DQ3 レベルに応じて経験値の配分を変える2

今回から実装に移ります。まず、前提として、オリジナルでも獲得経験値の最大値は3バイトMaxの#$FFFFFFです(平均前)。それ以上獲得しても#$FFFFFFでクリップされます。これを各自のレベルに応じて配分していくわけですが、分子の取り得る最大値は99、分母の取り得る最大値は298(レベル99が1人にレベル1が3人)となります。

誤差を極力抑えるため、分子*経験値をしてから分母で割るようにします(当たり前ですが)。獲得経験値が#$FFFFFFだった場合でも分子をかけた値の最大値は4バイトを超えません。従って分子*経験値の計算はSR: $001107 $00,X(4B)=A(1)*$00,X(3B)が使用できます。次にこれを分母(2バイト)で割るのですが、この除算を行うSRが存在しないので自作します。SR: $001295 $00,x(3B)=$00,X(3B)/A(2B?) 剰余=A,$30というSRが存在するので、基本このSRをパクって割られる数が4バイトに対応したものを作ればいい、ということになります。

というわけで、後は使用するRAM領域を決めて、条件に該当していれば傾斜配分計算を行い、各自への経験値の加算部分をいじれば終わり、ということになります。また、除算した余りを合計し、分母で割った数を余りの経験値として生存人数で割って加算する、ということも考えたのですが、理論的にこの値が各自に加算する際に1を超えないことがわかったのでその処理はスキップします*1。御託が長くなりましたが作業を開始します。まず、傾斜配分した経験値の保存先として、$7E2640-5Fを使用します。戦闘終了時のみ使用となるので、他の使用領域とかぶっていても問題ありません。

$7E2640-3 1人目の獲得経験値
$7E2644-7 2人目の獲得経験値
$7E2648-B 3人目の獲得経験値
$7E264C-F 4人目の獲得経験値
$7E2650-1 最大レベル+1-1人目のレベル(2Byte),0の場合は経験値はもらえない
$7E2652-3 最大レベル+1-2人目のレベル(2Byte),0の場合は経験値はもらえない
$7E2654-5 最大レベル+1-3人目のレベル(2Byte),0の場合は経験値はもらえない
$7E2656-7 最大レベル+1-4人目のレベル(2Byte),0の場合は経験値はもらえない
7E2658-9 生存者の中の最大レベル+1
7E265A-B 傾斜配分の分母
7E265C-D 傾斜によって発生した余りの合計値(分母は7E265A)
7E265E 0bit 経験値傾斜配分が発生した
1bit 獲得経験値ウィンドウを表示している
  • SR: $02A6AF 戦闘終了時処理SR_SR_0001(勝利時)
02A6ED JSR $EC75 SR: $02EC75 戦闘終了後経験値計算用RAM初期化
02A6F0 JSR $EE5C SR: $02EE5C 一人当たりの経験値計算
02A6F6 JSR $EE7C SR: $02EE7C 各自獲得経験値ウィンドウオープン

SR: $02EE7C 各自獲得経験値ウィンドウオープンについては次回にまわします。

  • SR: $02A7B3 経験値加算+レベルアップ処理
02A7CA JSR $EC83 SR: $02EC83 各自の経験値を$00-03にセット(インデックス:Y)
02A7CD-D3 NOP
  • SR: $02EC75 戦闘終了後経験値計算用RAM初期化(新SR)
02EC75 LDX #$001E X=#$001E
02EC78 LDA #$0000 A=#$0000
02EC7B STA $2640,X $7E2640+X=A
02EC7E DEX X–
02EC7F DEX X–
02EC80 BPL #$F9 if(n==off) goto $02EC7B
02EC82 RTS return
  • SR: $02EC83 各自の経験値を$00-03にセット(インデックス:Y)(新SR)
02EC83 PHX Push X
02EC84 TYA A=Y
02EC85 ASL A<<1
02EC86 ASL A<<1
02EC87 TAX X=A
02EC88 LDA $2640,X A=$7E2640+X 下位2バイト
02EC8B STA $00 $000000=A
02EC8D LDA $2642,X A=$7E2642+X 上位2バイト
02EC90 STA $02 $000002=A
02EC92 PLX Pull X
02EC93 RTS return
  • SR: $02EE5C 一人当たりの経験値計算(新SR)
02EE5C PHA Push A
02EE5D PHX Push X
02EE5E PHY Push Y
02EE5F JSR $ECC1 SR: $02ECC1 生存者の最大レベル+1を返す
02EE62 STA $2658 $7E2658=A
02EE65 JSR $ECC6 SR: $02ECC6 生存者中の最大レベル+1-レベル値をセット
02EE68 JSR $ED50 SR: $02ED50 経験値の傾斜配分をするか(該当c=on)
02EE6B BCS #$05 if(c==on) goto $02EE72
02EE6D JSR $ECF4 SR: $02ECF4 一人当たりの経験値計算(平等)
02EE70 BRA #$03 goto $02EE75
02EE72 JSR $ED8F SR: $02ED8F 一人当たりの経験値計算(傾斜)
02EE75 JSR $A746 SR: $02A746 一人当たりの獲得経験値計算処理
02EE78 PLY Pull Y
02EE79 PLX Pull X
02EE7A PLA Pull A
02EE7B RTS return
  • SR: $02ECC1 生存者の最大レベル+1を返す
02ECC1 JSR $EC94 SR: $02EC94
02ECC4 INC A++
02ECC5 RTS return
  • SR: $02EC94 生存者中の最大レベル取得(新SR)
02EC94 JSL $02B9A6 SR: $02B9A6 パーティ人数取得
02EC98 STA $02 $000002=A パーティ人数を$02にセット
02EC9A LDY #$0000 Y=#$0000
02EC9D LDA #$0001 A=#$0001 初期値としてレベル1をセット
02ECA0 PHA Push A
02ECA1 CPY $02 Y==$000002?
02ECA3 BEQ #$18 if(z==on) goto $02ECBD
02ECA5 JSL $043F87 SR: $043F87 引数:1#$01 引数:2#$FD 引数:3#$FF 生死判定(死亡c=on?)
02ECAC AND #$0010 A&=#$0010
02ECAF BNE #$09 if(z==off) goto $02ECBA 死人は飛ばす
02ECB1 JSR $ED35 SR: $02ED35 指定キャラクターのレベルを返す(ひとりじめベルト装備時は1)
02ECB4 CMP $01,S A>=Stack($01)? スタック中のレベル値と比較
02ECB6 BCC #$02 if(c==off) goto $02ECBA
02ECB8 STA $01,S Stack($01)=A 大きければ入れ替え
02ECBA INY Y++
02ECBB BRA #$E4 goto $02ECA1
02ECBD NOP
02ECBE NOP
02ECBF PLA Pull A
02ECC0 RTS return
  • SR: $02ED35 指定キャラクターのレベルを返す(ひとりじめベルト装備時は1)(新SR)
02ED35 STY $2428 $7E2428=Y
02ED38 LDA #$00F2 A=#$00F2 ひとりじめベルトのアイテムID
02ED3B STA $242C $7E242C=A
02ED3E JSL $02B87A SR: $02B87A アイテム装備チェック
02ED42 BVC #$04 if(v==off) goto $02ED48
02ED44 LDA #$0001 A=#$0001 レベル1
02ED47 RTS return
02ED48 JSL $042FEB SR: $042FEB 引数:1#$01 引数:2#$FD 引数:3#$FF レベル取得
02ED4F RTS return
  • SR: $02ECC6 生存者中の最大レベル+1-レベル値をセット(新SR)
02ECC6 JSL $02B9A6 SR: $02B9A6 パーティ人数取得
02ECCA STA $02 $000002=A
02ECCC LDY #$0000 Y=#$0000
02ECCF CPY $02 Y==$000002?
02ECD1 BEQ #$20 if(z==on) goto $02ECF3
02ECD3 JSL $043F87 SR: $043F87 引数:1#$01 引数:2#$FD 引数:3#$FF 生死判定(死亡c=on?)
02ECDA AND #$0010 A&=#$0010
02ECDD BNE #$11 if(z==off) goto $02ECF0 死人は飛ばす
02ECDF JSR $ED35 SR: $02ED35 指定キャラクターのレベルを返す(ひとりじめベルト装備時は1)
02ECE2 STA $00 $000000=A
02ECE4 TYA A=Y
02ECE5 ASL A<<1
02ECE6 TAX X=A
02ECE7 LDA $2658 A=$7E2658
02ECEA SEC c=on
02ECEB SBC $00 A-=$000000 差分を計算
02ECED STA $2650,X $7E2650+X=A
02ECF0 INY Y++
02ECF1 BRA #$DC goto $02ECCF
02ECF3 RTS return
  • SR: $02ED50 経験値の傾斜配分をするか(該当c=on)
02ED50 LDA #$FFFF A=#$FFFF
02ED53 CMP $06FFE2 A==$06FFE2? ROM中の傾斜配分フラグを調べる#$FFFF以外は傾斜配分しない
02ED57 BEQ #$02 if(z==on) goto $02ED5B
02ED59 CLC c=off
02ED5A RTS return
02ED5B JSR $A7A1 SR: $02A7A1 生存人数取得
02ED5E CMP #$0001 A==#$0001? 生存人数が1人なら傾斜配分しない
02ED61 BEQ #$F6 if(z==on) goto $02ED59
02ED63 JSR $EE03 SR: $02EE03 経験値を傾斜配分するレベル差数取得
02ED66 STA $00 $000000=A
02ED68 LDX #$0000 X=#$0000
02ED6B LDA $2650,X A=$7E2650+X
02ED6E CMP $00 A>=$000000?
02ED70 BCS #$09 if(c==on) goto $02ED7B
02ED72 INX X++
02ED73 INX X++
02ED74 CPX #$0008 X>=#$0008 ?
02ED77 BCC #$F2 if(c==off) goto $02ED6B
02ED79 CLC c=off
02ED7A RTS return
02ED7B SEC c=on
02ED7C RTS return
  • SR: $2EE03 経験値を傾斜配分するレベル差数取得(新SR)
02EE03 LDA $2658 A=$7E2658
02EE06 STA $00 $000000=A
02EE08 LDA #$000A A=#$000A
02EE0B LDX #$0000 X=#$0000
02EE0E JSL $00121C SR: $00121C $00,X(2B)=$00,X(2B)/A(1B) 剰余=A
02EE12 LDA $00 A=$000000
02EE14 CLC c=off
02EE15 ADC #$0002 A+=#$0002
02EE18 PHA Push A
02EE19 LDA #$0006 A=#$0006
02EE1C CMP $01,S A>=Stack($01)?
02EE1E BCS #$02 if(c==on) goto $02EE22
02EE20 BRA #$02 goto $02EE24
02EE22 STA $01,S Stack($01)=A
02EE24 PLA Pull A
02EE25 RTS return

思いのほか長くなってしまったのでこのへんで。次回は実際の経験値配分計算(平均・傾斜)を実装します。

*1:例:分母が100で、生存人数が4人の場合、余りの合計値の最大は396、分母の100で割ると整数部分は3となり、これを生存人数の4で割っても各自に加算する経験値は1を超えない。生存人数が2人、3人の場合も同様