dq9 解析メモ(daisukedaisukeのブログ)

2023年10月から2024年6月まで、約9カ月間のdq9解析結果を投稿します。エンカ調査がメインです。

dq9 2G/3Gエンカウント時の特殊処理について

記事まとめ daisukedaisuke.hatenablog.com

daisukedaisuke.hatenablog.com

daisukedaisuke.hatenablog.com

dq9において、コミュニティの報告により、3Gまで生成されたうえで、3Gが消える現象が報告されたので、詳しく調べました。
コミュニティと協力の上調査した結果、「メモリ不足」のため、削除されると結論付けました。

0x54テーブル、初期乱数0x8306C29B91CD5A41の場合を考えます。

daisukedaisuke.github.io

通常のエンカウントについてはここを見てください
qiita.com

F % 備考
0F 92.556 タイガーランス1体
1F 92.2741 90以上なので3G
2F 48.4155 リカントマムル
3F 87.9463 2体
4F 60.0000 バブーン
5F 19.9015 1体
6F 31.9196 謎消費

タイガーランス1体、リカントマムル2体、バブーン1体で、通常の削除処理(調査メモ2枠目で解説)が実行され、タイガーランス1体、リカントマムル1体、バブーン1体になります。

ソート編

今まで未知の処理として解説しなかったソート処理を、コミュニティの協力もあり理解することができたので解説します。

3Gエンカウントでは、謎消費(6=5パターン)が順番の(ランダム)入れ替えを担っており、次のテーブルで入れ替えされます。
1Gエンカウントでは謎消費は発生しない。2Gエンカウントの入れ替えは後述する1Gを先頭にする処理にて元に戻され、無意味なので触れません。

RandInt関数内で次の計算を行います

|31.9196 * 0.01 * 6|=1

計算結果をもとに、次のテーブルを参考にしてで入れ替えを行います。
今回の場合は1です
これはFUN_0209cd4c内(GenerateCompanionByBT関数)の0209d0ecで行われています。

[
 0 => [1, 2, 3],
 1 => [1, 3, 2],
 2 => [2, 1, 3],
 3 => [2, 3, 1],
 4 => [3, 1, 2],
 5 => [3, 2, 1],
]

1、3、2なので、この通りに入れ替えされ、タイガーランス1体、バブーン1体、リカントマムル1体になります。
次に、1Gが先頭になるように入れ替えます。
これは、FUN_021676cc(LR: 0x02166fa0)の先頭で行われています。
今回はエンカウントしたタイガーランスが先頭なので行われません。
先ほどのテーブルを最適化すると、こうなります。

local swapTable = {
    [0] = {1, 2, 3},
    [1] = {1, 3, 2},
    [2] = {1, 2, 3},
    [3] = {1, 3, 2},
    [4] = {1, 3, 2},
    [5] = {1, 2, 3}
}

コスト条件編

dq9のエンカウントにはいままで誰も気付かなかったであろうメモリ制限があり、解析によってゲームから取り出した以下の数値の合計が、 157232-157450を超えると、超えたモンスターが全て削除されます。
この制限はモンスター事ではなく、重複を削除したグループ事に適応されます。
エンカウント生成で既に0体になっている場合は、そのモンスターのコスト計算は発生しません。
これらの制限の計算は0x02167364から0x021673a4付近で行われており、 削除は0x2167494FUN_020019c8によって行われています。

docs.google.com

タイガーランス1体、バブーン1体、リカントマムル1体です。
まず一時的に重複グループを削除します。今回は重複がないので、そのままです。
次に、スプレッドシートからコストを取得して、全て足し算します。

モンスター コスト 合計
タイガーランス 72704 72704
バブーン 47104 119808
リカントマムル 72704 192512

となり、157000を超える(157KB?)ため、一番後ろにいるリカントマムルが削除されます。 削除された場合は、hp計算は行われません。

そのため、3Gエンカウントなのに、タイガーランス1体、バブーン1体という奇妙なエンカウントが発生します。
乱数消費は、7(3Gエンカウント)+2(体)で「9」(モーションあり: 13)消費になります。

制限の理由はコミュニティの人たちによって意見が分かれていますが、「コスト」の値は、ポリゴン、テクスチャ、アニメーションを読み込むために必要なメモリ(Byte?)であるという説が有力です。

制限が発生する組み合わせをプログラムで全て出力しました。4シート、7000件以上あります。 docs.google.com

Q&A

Q: コストの高いモンスターが複数スポーンした記憶があるけどなんで
A:
(コミュニティからの質問)
コストは、重複を削除したモンスターに適応されます。
遺跡S(EFテーブル)のエンカで、プラチナキング(17408)+ゴールドマジンガ(104448)+ゴールドマジンガ(104448)=226304では、そのまま計算するとコストオーバーになりますが、内部的には重複が削除され、プラチナキング(17408)+ゴールドマジンガ(104448)=121856として計算されているので、削除が発生しません。
逆にいえば、プラチナキング(17408)+ゴールドマジンガ(104448)+ファイナルウェポン(95232)=217088であれば、コストオーバーするため、削除が発生します。

↓該当するエンカウントを発生させた場合

下記のようなエンカウントは、同じモンスターでコストをオーバーしないため、削除が発生することなくスポーンすることができます

Q: 通常のエンカウント処理の文献はどこにありますか?
A:

springwilddance.hatenablog.com

qiita.com

Q: 複数モンスターが削除された場合実装的にバグるよね?
A: 2Gの時点で削除が発生する可能性のある場所は全て3Gエンカウントが設定されていません。

Q: なぜメモリ不足だと結論付けたのですか?
A: 「157232-157450を超えると」と書いたように、コスト制限にはエンカウントしたグループ数によって変わるブレがあります。
また、上限を計算する処理を要約すると、実質上2ポインターアドレスの引き算であり、これが現在利用可能なメモリの範囲ではないかと推測したためです。

Q: スプレッドシートにあるE列の数値は何ですか?
A: オリジナルのデータです。コミュニティによると、それはKB単位での数値ではないかという憶測があります。
オリジナルの数値を、10(10進数)左シフトすると(AB << 10)コストの数値になります(AIも左シフト10は1024倍をするのと同等と言っています)

Q: モンスターが削除される条件は何?
A: モンスターの合計コストが157232-157450を超えると、超えたモンスターが削除されます。この制限は重複を削除したグループに適応されます。他にも、フィードのモンスター数制限を超えると、削除されます。

権利表示

このページで利用している株式会社スクウェア・エニックスを代表とする共同著作者が権利を所有する著作物の転載・配布は禁止いたします。 © 2009 ARMOR PROJECT/BIRD STUDIO/LEVEL-5/SQUARE ENIX All Rights Reserved.