DQ3 K.Mix アイテムID9ビット拡張作業2

前回のエントリで領域の問題はクリアしたところまで説明しました。あとはPCのアイテム領域の操作、袋の中身の操作のプログラムを書くだけ、という話になりそうなのですが、以下の2点が問題となります。

  1. 対象範囲がかなり広いため、十分なテストが必要
  2. ビット単位でデータを詰めてセットしているので、アイテムの操作にまつわる処理量が10倍~に膨れ上がり、人が操作していて違和感を覚えるくらいに遅くなりかねない

1に関しては十分にテストをすればいいだけという話ではありますが、対象範囲を把握するのがかなり大変です。先日もテストプレイ中に間違った場所に情報をセットしてしまう箇所が残っていていつの間にかPCの最大MPが999になっていたりしました。一応そこそこテストをしてからテストプレイを開始したわけですが、ポロポロと問題が見つかるという始末です。PCのデータというかなりデリケートな箇所の操作なので、対処漏れがあると非常にまずいです。一通りテストしてOKだと思って別の方にテストプレイをしてもらったら対処漏れが見つかったりしたので(DQ3のアイテム操作のバリエーションは意外と多い)、rcまで出せたとしても正式版までは2ヶ月位置きたいと思っています。

2はデータ形式をこねくっている以上避けられません。各キャラクターのアイテム操作は最大12個なのであまり表面化しませんが、袋のアイテム操作は種類数が最大255(かそれ以上)になるので実装によっては処理に時間がかかり、突っかかるような感覚を覚えるケースがあります。オリジナルでは1バイトにアイテムID、個数を格納しているので、アイテムを並べ替えたり順番を1つずらしたりという操作は極めてシンプルに記述されています。以下一例。

  • SR:$045418 袋からアイテムを減らす
$04542CDEC $3825,X$3825+X–個数を減らす
$04542FBNE #$1Aif(z==off) goto $04544B袋の対象のアイテム個数が0個になったら1個ずつ前にずらさないといけない
$045431INXX++
$045432CPX #$0100X>=#$0100?255種類最後までずらす
$045435BCS #$0Eif(c==on) goto $045445
$045437LDA $3825,XA=$3825+X
$04543ASTA $3824,X$3824+X=A個数情報をずらす
$04543DLDA $3725,XA=$3725+X
$045440STA $3724,X$3724+X=AアイテムID情報をずらす
$045443BRA #$ECgoto $045431
$045445STZ $3824,X$3824+X=#$00一番最後を#$00でうめる
$045448STZ $3724,X$3724+X=#$00
$04544BREP #$30m=off(A/M:16b) x=off(X/Y:16b)

アイテムIDを9ビット化した場合、アイテムID,個数情報が0ビットから始まるわけではなくなってしまうので単純にずらせばいいというわけにはいきません。アイテムID+個数情報をまとめて2バイトに固められたら楽ですが、その分領域を食うのでそれもできないというのが悩ましいところ。かくして空きを作らずビットの途中からアイテムIDを格納するような形態しかできないという結論に落ち着きました。次に問題となるのが「どうやってアクセスするか」です。ビットの途中から始まる情報にアクセスするためのSRはオリジナルの時点で存在しています。

  • SR:$025CC0 ターン開始時処理
$025CFDPEA #$23ACPush #$23AC
$025D00PEA #$0018Push #$0018
$025D03PEA #$7E00Push #$7E00
$025D06JSL $C9029ESR: $09029E

なんとなく前後を見ていれば想像がつきますが、「$7E23ACの3-4ビットの値を取ってくる」のがSR: $09029Eらしいということがわかります。反対に値をセットするのがSR: $0902E9です。自分で0から実装するとなると結構面倒ですが、なかなか便利なSRです。次に中身を見てみます。

  • SR:$09029E RAM上情報取得
09029EPHPPush P Flag
09029FSEIi=on
0902A0REP #$30m=off(A/M:16b) x=off(X/Y:16b)
0902A2PHAPush A
0902A3PHBPush DB
0902A4PHYPush Y
0902A5PHXPush X
0902A6SEP #$10x=on(X/Y:8b)
0902A8LDA $0D,SA=Stack($0D)
0902AATAXX=A
0902ABPHXPush X
0902ACPLBPull DB
0902ADLDY #$00Y=#$00
0902AFLDA $0E,SA=Stack($0E)
0902B1AND ($10,S),YA&=Stack($10+Y)
0902B3STA $40DP($40)=A
0902B5LDA $0E,SA=Stack($0E)
0902B7BEQ #$14if(z==on) goto $0902CD
0902B9LSRA>>1
0902BABCS #$11if(c==on) goto $0902CD
0902BCTAXX=A
0902BDLDA $0C,SA=Stack($0C)
0902BFLDY #$02Y=#$02
0902C1AND ($10,S),YA&=Stack($10+Y)
0902C3LSRA>>1
0902C4ROR $40DP($40)>>1
0902C6TAYY=A
0902C7TXAA=X
0902C8LSRA>>1
0902C9TAXX=A
0902CATYAA=Y
0902CBBCC #$F6if(c==off) goto $0902C3
0902CDREP #$30m=off(A/M:16b) x=off(X/Y:16b)
0902CFPLXPull X
0902D0PLYPull Y
0902D1PLBPull DB
0902D2LDA $05,SA=Stack($05)
0902D4STA $0B,SStack($0B)=A
0902D6LDA $03,SA=Stack($03)
0902D8STA $09,SStack($09)=A
0902DALDA $40A=DP($40)
0902DCSTA $07,SStack($07)=A
0902DETSCA=S
0902DFCLCc=off
0902E0ADC #$0006A+=(#$0006+c)
0902E3TCSS=A
0902E4PLAPull A
0902E5PLPPull P Flag
0902E6LDA $40A=DP($40)
0902E8RTLreturn

何をやっているかはともかく、ぱっと見て「クソ長い」というのはわかると思います。ちなみに値をセットするSRはこれより長いです。アイテムIDを取ってくるだけの「A=$3725+X」の1命令と同じことをするだけでもこの処理量に膨れ上がるわけです。DQ3は幸いにしてターン制RPGなのでリアルタイム性を求められるアクションゲームやATBを採用しているFF4-6と違い、複雑な処理を実装しても実害が出るケースはほとんど存在しないため、トータルのCPUのサイクル数(=処理量)というのには今まであまり気を配らずに作業をしてきましたが、流石に上記のような変更が更に256倍以上(アイテム種類分)になると目に見えて支障が出ます。当初はこのSRを使っていましたが、特定のケースで突っかかるような感じを覚えることがあったので(アイテムの種類をほぼ最大にして先頭付近にある1個しかないアイテムを袋から出すなど)、アイテム操作という移動中ユーザーが行う作業の半分以上を占めるであろう部分が快適にできないというのはよろしくないので結局専用のアクセスSRを作ることにしました。

長くなったのでまた次回。

スポンサーリンク

コメント

  1. 匿名 より:

    初めまして、いつも楽しみにしています。暇つぶしに遊んでいたのが、いつしか次のバージョンをワクワクしながら待つようになりました。緻密な作業の中、大変だと思いますが心の底から応援しています。DQ3に着目してくださって本当にありがとうございます。素晴らしい!

    管理者より返信:

    プレイしていただきありがとうございます。暇な時にたまーにやり返してもらえると嬉しいです。アイテム数追加も含め今やってる作業が恐らく最後のメジャーアップデートになると思います(流石にもうネタがない)。いくつかの追加要素のうちまだ手が全くついていないものが多いのでいつリリースになるかわかりませんが、気長に待っていてください。

コメントを書く

メールアドレスが公開されることはありません。コメントは管理者の承認後表示されます。