霧イベントにおけるキンシャケのドロップ数

Hack

霧イベント

サーモンランにおいて霧イベントではキンシャケが「オオモノ五匹出現後に一匹」というサイクルで出現する。

このキンシャケは他のオオモノと違い、金イクラを1、5、10のいずれかドロップすることが知られている。シードを固定するとこのドロップ数が同じ(オオモノが詰まったりしない限りは)になるケースが多いので、ドロップ数は初期シードから計算可能と思われていた。

また、経験則からこのドロップ数がランダムであり、ほぼ等確率(それぞれ1/3ずつ)であることはわかっていました。

しかし、そこまでわかっていながら何故か今までドロップ数を決定するアルゴリズムは特定されずにいました。なぜか?

ドロップ数変更は3.2.0から

というのも、霧イベントにおいてキンシャケがランダムドロップをするようになったのが3.2.0からであるためだ。Starlightは3.1.0までしか動作しないし、解析するにおいでもデバッグシンボルがなくなってしまったため、3.1.0と3.1.0以降では大きく解析の難易度が異なる。

が、ドロップ数変更を突き止めないことには霧イベント100納品という大記録をLanPlayであっても達成することができないのだ。どうしても100納品チャレンジをしたいので調べることにした。

解析手法

幸運だったのはたまたま3.2.0のバイナリを保存していたこと、そして3.1.0の次のアップデートであるために差分が少なく、デバッグシンボルがなくても調べやすいことでした。

ドロップ数がランダム化というのは「機能の更新」ではなく「機能の追加」であるので、3.1.0に比べて新たに「ドロップ数を決定する」ためのサブルーチンが追加されている可能性が高いのです。

問題はそのサブルーチンがどこに追加されているかということなのですが「霧イベントを管轄するクラス」または「キンシャケを管轄するクラス」のどちらかにありそうなのはなんとなくわかりますね。

今回はこの二つのどちらかに「ドロップ数を決定するサブルーチン」があると信じて解析を進めました。

霧イベントを管轄するクラス

霧イベントはGame::Coop::EventFogというクラスで制御されており、3.1.0の時点で全部で100ほどのサブルーチンがあります。

これを3.2.0のものと比べて、新たなサブルーチンが追加されていないかを調べます。二時間ほどかかったのですが、大きな変更点は見つかりませんでした。

キンシャケを管轄するクラス

キンシャケはGame::Coop::EnemySakelienGoldenというクラスで制御されており、3.1.0の時点で30ほどのサブルーチンがありました。

霧イベントに比べれば少ないので良心的ですよね。そして3.1.0のコードを見ながら一致するものを探してシンボル名をつけていたときにその事件は発生しました。

このサブルーチン、3.1.0にないね???

3.2.0にしか存在しないサブルーチンが二つあり、そのうち一方がものすごく怪しい感じがしました。それがsub_4A7BD0であり、以下のような擬似コードをもっていました。

__int64 __fastcall sub_4A7BD0(__int64 this, __int64 a2)
{
  *(this + 2640) = sead::Random::getU32((this + 0x724)) / 0x55555556;
  return sub_4643F4(this, a2);
}

これはもうちょっとわかりやすく書き直すことができるのですが、sead::Random::getU32()で乱数を生成しているのがまず怪しいですよね。そしてその数を謎の定数0x55555556で割っているのも気になります。

しかしよく考えてみてください。この0x55555556というのは決してマジックナンバーではないのです。というのも、32ビットの整数が取りうる範囲が0x00000000 - 0xFFFFFFFFなのでこの値はほとんどこの範囲の1/3なんです。

あれ、1/3ってどこかで見ましたよね?そう、キンイクラのドロップ数のそれぞれの確率です。

つまり、先程のコードをわかりやすく書くと以下のようになります。3で割ったあまりを計算してthis[0xA50]に代入してから別の関数に飛ばしているのです。

__int64 __fastcall sub_4A7BD0(__int64 this, __int64 a2)
{
  this[0xA50] = sead::Random::getU32() % 3;
  return sub_4643F4(this, a2);
}

この時点で、このサブルーチンの計算結果が以下のような影響をもたらすのではないかと考えました。

意味場合の数確率
01個ドロップ?1431655767通り0.33333333372
15個ドロップ?1431655767通り0.33333333372
210個ドロップ?1431655762通り0.33333333255

なんと僅かに10個ドロップの確率が低いことがわかりました!!(無視できるレベルだが

IPSwitchによる検証

推測ができたからには、実際にプレイしてチェックする必要があります。

以下は5.3.0で動作するキンシャケのドロップ数を常に10個にするコードです。

// Goldie in Fog always drop 10 eggs [tkgling]
@enabled
006A0ECC 52008052
006A0EE0 92420AB9

今後の展望

キンシャケのドロップ数を決定するための乱数を生成する乱数生成器の初期化シードを調べる必要があります。

乱数生成器自体はthis[0x724]にあるのがわかっているのですが、問題はこれが「いつ」「どこで」「何によって」初期化されたかということですね。

まだまだ調べがいがあるのですが、キンシャケ完全解析はそう遠くないと思います。

記事は以上。

コメント

タイトルとURLをコピーしました