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

氷の洞窟の実装を進めていて、マップのインポートはギミックも含めて終わったのですが、肝心のグランドラゴーンまわりのイベントの実装をすすめる気が起きず、よくよく考えてみると「使えるアイテム枠がない」ということが原因なのがわかりました。現在リリースしているver1.6.7ですでに255個(アイテムID:#$0はターミネーターとして使われているので使えません)全部使ってしまっているので枠がありません。このパッチを作る方針として極力「削る」ということはしたくなかったので(性格を変えるアイテムの整理は「必要である」と思って作業していたので例外)、削ることは最初に検討しましたが、もし増やしたいアイテムがさらに出てきた場合、ますます思考がみみっちくならざるをえないので非常に抵抗感がありました。ちなみに検討していた削除対象アイテムは以下の通り。

アイテム名削除理由
ルーズソックス今更「ルーズソックス」というのもアレな上に性格が変わるわけでもない
アープのかぎフラグで扉が開くようにすれば削れる
おうじゃのけん(2)名称が同じだからフラグで動作を変えれば可能?攻撃力も違うので面倒そう
へいしのふくフラグでON/OFFできないか
おなべのフタゴミ盾なので削除候補
ルーンスタッフ存在感が0なので削除候補

他にも真面目に検証したら削れるものはあるかもしれませんが、削るにしてもある程度の作業は避けられない上に、何より作業が後ろ向きなのが非常に不愉快です。同じ労力を使うなら増やす方に使いたい、というわけでアイテムIDの9ビット化について検討をし、可能であるという結論になったので作業した結果がこちら。

DQ3 K.Mixアイテム拡張01

9ビット化というとあと255種類アイテムを新規定義できそうですが、いろいろ制限があったために+44種類のトータル299種類までしか拡張できていません。とはいえ、オリジナルから言うと+72種類なのでそこそこ頑張ったほうだと思いますww。DQ3 K.Mixにおいてはこれだけ枠があれば十分という判断です。

まず注意点として、今回の拡張作業はDQ3 K.Mix専用の特殊仕様です。通常アイテムの最大数を9個に絞っていたので可能だったと言っても過言ではありません。アイテムIDを9ビットにするにあたって大きな障害は以下の3つです。

  1. 各PCの情報領域($7E3925-)
  2. セーブデータ中の袋のアイテム情報領域
  3. 袋のアイテム情報領域($7E3725-3924)

実際に作業するとなると、アイテムIDを指定している固定長データ(モンスター基本データ、ショップ、すごろく、アイテム拾得情報など)を軒並み変更する必要があるのですが、それはROMの領域(と根気)があればできる話なのでここでは触れません。

この中で比較的余裕なのが1です。アイテムIDを9ビット化するにあたり、ビット単位で詰めたとしてもさらに12ビットに必要になりますが、これは直前の装備数、所持アイテム数がそれぞれ1バイト割り当てられているのでここを流用し、装備数、所持アイテム数は最大HP、現在HPの上位4ビットを使えば事足ります。アイテムの9ビット化はDQ6 Extendedで既に実施済みだったのでこの部分については割とすぐ終わりました。理屈で言えばこの部分に関してはアイテムID:$511まで格納する余裕はあります。

問題は2と3です。オリジナルのセーブデータは8KB(=#$2000バイト)ですが、袋の中に入れられるアイテム種類を増やそうととしても空きがありません。以前調べましたが、冒険の書3個でトータル#$1FDDバイトを使用しているので普通に拡張するとなるとまるで足りなくなるのでストレートにやるならセーブデータの拡張は不可欠です。幸いにしてDQ3 K.Mixでは既に32KBにセーブデータファイルを拡張済みかつ、冒険の書1つに割り当てた領域に多少余裕を持たせていたのでまあなんとかなる、という状態でした(結果として拡張領域は使用しませんでしたが)。

次にメモリ中の袋の情報の領域をどこにするかということですが、これまた難しいです。オリジナルでは、アイテムID用に#$0100バイト、対応する個数用に#$0100バイトを$7E3725- $7E3825-にそれぞれ用意していました。個数用にも1バイトを割り当てているので理屈では255個まで持つことは可能です(99個でクリップする処理があるので最大は99個)。99個を最大とするなら1ビット余計なので、これをアイテムIDの方に割り振ると2バイト(アイテムID:9ビット+個数:7ビット)でアイテムID#$01FFまで表現できてしまいます。とは言えアイテムIDの種類分だけ余計に領域が必要になるので、+128種類(アイテムID:#$18Fまで)なら+#$0100バイト、+256種類(アイテムID:#$1FFまで)なら+#$0200バイトがさらに必要になることになります。もともとの袋領域が#$0200バイトなのでそれぞれ合計#$0300バイト、#$0400バイト連続した領域がゲーム開始から終了まで必要になります(幾つかの場所に分割して格納することも理論上可能ですが、正直実装が無駄に複雑になるのであまり現実的ではありません)。

すでにAIの学習情報として$7EFC00-FFFFの#$0400バイトを使ってしまっているので、別の場所を探さないといけないですが、結論から言ってこれだけの領域をゲーム開始時から終了まで使われていない場所は見つけることができませんでした。$7Fのバンクも探してみましたが駄目でした。1つ禁じ手としては拡張したセーブデータの領域が#$0E00バイト空いていたので使うことも考えましたが、セーブもしていないのにセーブデータが更新されていくというのもどうかと思い採用しませんでした。今回のケースに限っては追加するアイテム種類数はそれほど多くないため、+128種類でも十分ということで、当初トータル384種類、#$0300を確保して実装を行い、テストプレイをはじめましたが、アッサラーム、ポルトガのマップでNPC関連の情報でその領域が使用されていることがわかってしまい、NPC関連の情報を移動させたものの今度はこれらのマップに進入するとゲームが止まるという別の問題が起きてしまい、正直解決方法がさっぱり思いつかず、色々悩んだ結果「もっと情報を圧縮して元の場所($7E3725-3924)を使う」という結論にたどり着きました。袋の情報という極めてライフタイムの長い情報を格納する領域を「どこかで使われるのではないか」とビクつきながらテストプレイするのは正直気が重いので(駄目だったときの精神的ダメージが大きいwww)、元の場所なら確実に安全なのは保証済みです。セーブデータも拡張領域を使用する必要もありません。

というわけでデータの格納形式は「アイテムID:9ビット+個数情報:4ビット(最大15個まで)」を1つとしてビット単位で詰めていくことにしました。これは通常の所持数が9個だからできるフォーマットです。また、9個以上持てるアイテムの個数情報は専用の領域を用意して1アイテムにつき1バイトを割り当てる変則的なフォーマットです。この形式なら13ビット☓300種類+特殊アイテム個数8ビット☓24種類(現状使用しているのは10種類ですが、余裕を見ておきました)=4092ビットでギリギリ4096ビット(#$0200バイト)に収まります。結局追加できるのは44種類ですが、現状どう考えても全部使うことはないと思われるので(開発開始から追加したのは28種類、残りの変更量から考えても十分)問題なしと判断しました。なにより領域が確実に使われることがないのでこの点についての検証をする必要がありません。

じゃあ問題はないかというとまあそう簡単にも行かないのがこの話の難しいところで、長くなったのでまた次回。

スポンサーリンク

コメントを書く

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