AIに新しい乱数調整ツールを作らせる①

言い出しっぺの法則

初期SEED検索のコードの9割AI (無料枠のChatGPT-5と無料のGemini Pro)を使って2日で完成させました。(流用したCUI版の5genSeedUntiもAIに作らせた)

つまり、AIにコードを書かせれば誰でも乱数ツールが作れるわけですね!こういうのに興味がある人はやってみましょう。

やれと言われた気がするので複数回に分けてやっていきます。

 

この記事は、AIを使って初めて乱数調整ツールを自作するガチ初心者向けです。

乱数調整ミリしら人「乱数調整入門」を見てからきてください。

www.mizdra.net

blastoise-x.hatenablog.com

⚠注意事項⚠

・少しずつ書きかけを更新していきます。

C#ミリしら人なので、詳しいことはAIに聞いてください。

・Cわかりません。C++わかりません。Python勉強中。

・AIはChat-GPTとGemini Proを使用しています。

・プロンプトの管理は面倒くさいのでやりません。

・乱数調整ツールのweb移植は試行錯誤を含めていつかやります。

はじめに

「乱数調整ツールをつくる」と言うと、なんか難しそうに聞こえますが、実際にやっていることはただの四則演算です。簡単ですね!

5世代以前のポケモンに限らず、Nintendo DSで発売されたゲームの大半は初期乱数の制御が簡単(一部を除く)で、乱数調整の開拓難易度は低めです。

つまり、ほとんどのゲームは開拓されていないブルーオーシャンというわけです。それだけの価値があるかは置いておいて。

 

この記事では、これの流れに沿って進めていきます。なに書いてるかわからないけど参考程度に。(以降、参考資料と呼びます)

乱数調整プログラムC#実装 Advent Calendar 2023 - Adventar

どの言語で作るかは自由ですが、C#だと気持ちよく書けるらしいです。知らんけど。

乱数列をつくる

参考資料の1日目2日目をやります。

乱数列を作るにはまず、線形合同法(LCG)のパラメータを知る必要があります。

DPtなら32bit LCG:R[n+1] = R[n] * 0x41C64E6D + 0x6073

BW/BW2なら64bit LCG:R[n+1] = R[n]  * 0x5D588B656C078965 + 0x269EC3

古いゲームでは32bit LCG、ある期間からは64bit LCGが使われてるらしいです。(開発元による)

ポケモン以外のゲームで乱数調整を開拓するなら各自で調べることになります。エミュレータかなんかで調べましょう。

エミュレータの導入】

qiita.com

【パラメータの調査】

note.com

(これ以外に参考になりそうなのが見つからない)

 

LCGのパラメータ調査が終わったらAIの出番です。

AIに渡すプロンプト(指示)には以下の要素を含ませます。

  • 乱数調整用のツールを作ること
  • 疑似乱数にはLCGを使用し、連続した乱数列を出力したい旨
  • LCGの各種パラメータ
  • その他、初期SEEDの入力や乱数列の長さなどの設定

「初期SEEDは16進数の32bit」、「乱数列の長さを入力したい」、「ファイル名を入力してテキストファイルとして出力したい」なども追加すると良いです。

プログラミングのやり方自体がわからないならAIに聞きましょう

 

LCGのパラメータがR[n+1] = R[n] * 0x41C64E6D + 0x3039、32bitの16進数の入力、乱数列の長さの入力、テキストファイルで出力する旨を伝えると、このようなコードが返ってくると思います。


class LCG
{
    static void Main()
    {
        Console.Write("Enter Initial SEED : 0x");   // 初期SEED入力
        if (uint.TryParse(Console.ReadLine(), System.Globalization.NumberStyles.HexNumber, null, out uint Seed))
        {
            Console.Write("Enter SEED Count :");
            if (int.TryParse(Console.ReadLine(), out int count) && count > 0)
            {
                Console.Write("Enter File Name :");
                string outputPath = Console.ReadLine();
                if (!outputPath.EndsWith(".txt", StringComparison.OrdinalIgnoreCase))
                {
                    outputPath += ".txt";
                }
                using (StreamWriter writer = new(outputPath))
                {
                    for (int i = 1; i < count; i++, Seed = NextSeed(Seed))
                    {                 
                        Console.WriteLine($"Count:{count}, Seed:{Seed:X8}");
                        writer.WriteLine($"Count:{count}, Seed:{Seed:X8}");
                    }
                    Console.WriteLine($"Generated {count} seeds. Output saved to {outputPath}");      
                }
            }
            else { Console.WriteLine("Invalid Input for SEED Count."); }
        }
        else { Console.WriteLine("Invalid Input for Initial SEED."); }
    }
    
    static uint NextSeed(uint Seed)
    {
        uint a = 1103515245;
        uint b = 12345;
        return (a * Seed + b);
    }
}

プログラムの流れとしては、

  • 初期SEEDを入力。16進数に変換し、無効な入力ならメッセージを返す。
  • 乱数列の長さを入力。無効な入力ならメッセージを返す。
  • ファイル名を入力。入力に".txt"がない場合追加する。
  • 乱数列を生成する。

といった感じです。

要所要所でわからない点は調べるか、部分的にAIに聞くようにしましょう。その行動がいずれ役に立つはずです。

乱数処理をつくる

 

 

 

 

 

 

 

 

Lua Scriptで64bit LCGを実装する

ちょっと思いついたので作ってみた

 

DeSmuMeのluaスクリプト浮動小数点数を使用しており、52bitまでの精度しか保証されていません。そのため、32bit * 32bitの計算をそのまま行うと、狂いが生じてしまいます。

そこで、Luaスクリプト上で32bit LCG / 64bit LCGの計算をするためには、少し工夫が必要です。(Google SpreadSheetで計算させるときも同じ)

 

そして、作った64bit LCGがこれです。

LCG_64 - Pastebin.com


local Rand_addr = 0x02235798 --B2/JP
function LCG_64(U32,L32)
 --64bit multiplication
 local l16, u16, Carry16
 local l24, u24, Carry24
 local Carry
 local x, y, z = {}, {}, {}

 x[0] = bit.band(L32, 255)
 x[1] = bit.band(bit.rshift(L32, 8), 255)
 x[2] = bit.band(bit.rshift(L32, 16), 255)
 x[3] = bit.band(bit.rshift(L32, 24), 255)

 y[0] = bit.band(x[0] * 1812433253, 4294967295)
 y[1] = bit.band(bit.lshift(x[1] * 1812433253, 8), 4294967295)
 y[2] = bit.band(bit.lshift(x[2] * 1812433253, 16), 4294967295)
 y[3] = bit.band(bit.lshift(x[3] * 1812433253, 24), 4294967295)

 l16 = bit.band(y[0], 0xFFFF) + bit.band(y[1], 0xFFFF) + bit.band(y[2], 0xFFFF) + bit.band(y[3], 0xFFFF)
 Carry16 = bit.rshift(l16, 16)
 u16 = bit.rshift(y[0], 16) + bit.rshift(y[1], 16) + bit.rshift(y[2], 16) + bit.rshift(y[3], 16) + Carry16

 z[0] = bit.rshift(u16, 16)
 z[1] = math.floor((x[0] * 1812433253) / 0x100000000)
 z[2] = math.floor((x[1] * 1812433253) / 0x1000000)
 z[3] = math.floor((x[2] * 1812433253) / 0x10000)
 z[4] = math.floor((x[3] * 1812433253) / 0x100)

 l32 = bit.band((y[0] + y[1] + y[2] + y[3]), 4294967295)

 u32 = z[0] + z[1] + z[2] + z[3] + z[4] 
 u32 = bit.band(LCG_32(L32, 1566083941, u32), 4294967295) 
 u32 = bit.band(LCG_32(U32, 1812433253, u32), 4294967295)

 l24 = bit.band(y[0], 0xFFFFFF) + bit.band(y[1], 0xFFFFFF) + bit.band(y[2], 0xFFFFFF) + bit.band(y[3], 0xFFFFFF) + 2531011
 Carry24 = bit.rshift(l24, 24)
 u24 = bit.rshift(y[0], 24) + bit.rshift(y[1], 24) + bit.rshift(y[2], 24) + bit.rshift(y[3], 24) + Carry24

 Carry = bit.rshift(u24, 24)
 l32 = bit.band((l32 + 2531011), 4294967295)
 u32 = u32 + Carry 

 return l32, u32
end

function LCG_32(rand, a, b)
 --32bit multiplication
 local x, y = {}, {}

 x[0] = bit.band(rand, 255)
 x[1] = bit.band(bit.rshift(rand, 8), 255)
 x[2] = bit.band(bit.rshift(rand, 16), 255)
 x[3] = bit.band(bit.rshift(rand, 24), 255)

 y[0] = bit.band(x[0] * a, 4294967295)
 y[1] = bit.band(bit.lshift(x[1] * a, 8), 4294967295)
 y[2] = bit.band(bit.lshift(x[2] * a, 16), 4294967295)
 y[3] = bit.band(bit.lshift(x[3] * a, 24), 4294967295)

 return bit.band((y[0] + y[1] + y[2] + y[3] + b), 4294967295)
end

function Fn()
 L32 = memory.readdword(Rand_addr)
 U32 = memory.readdword(Rand_addr + 4)
 for i = 0, 16 do
    gui.text(0,10 * i, string.format("%08X%08X", U32, L32))
    L32, U32 = LCG_64(U32,L32)
 end
end
gui.register(Fn)
  

※32bit multiplicationはマジあり(@maziari1105)さんのものをお借りしました。

16bitで分割して短くしてもいいです。

B2-JPNで使用するとこうなります。

Q. 何につかうの?

A. 知らん

 

おわり。

【ポケモンBW2】イッシュの難関を破壊するお話

はじめまして。こんにちは。こんばんは。

ジラーテです。(ジラー"チ"ではない)

 

前回のPokémon Past Generation Advent Calendar 2024 の参加をきっかけに、乱数処理の解析を始めて1年ほどが経過しました。

この1年間で、乱数処理アセンブリの解析手法など、様々な知識を得ることができました。(プログラミング技術は向上していません)

今回、Pokémon Past Generation Advent Calendar 2025 では、第5世代の長年の謎とされてきたイッシュの難関の生成処理の解析まとめ + 乱数調整で黒の摩天楼/白の樹洞を破壊していきます。

 

今回の乱数処理の解析にあたって、乱数ツール完成までの約4ヶ月分の解析メモを残しています。乱数処理の解析の流れなどが気になる方は、是非覗いてみてください。リンクはTwitterのbioに載せてあります。

https://x.com/namofure

(ここだけの話、DQ9のACEを開拓した ニート 凄い人のメモも残ってます)

 

この記事はPokémon Past Generation Advent Calendar 2025 2日目の記事です。

adventar.org

はじめに

イッシュの難関乱数の話をする前に、なぜイッシュの難関生成処理が長年の謎とされてきたかを解説します。(持論)

【ここらへん長いので飛ばしてもいいです】

基本的に、第5世代の乱数処理の解析は、発売から数年以内、かつ殆どが実機を用いて行われてきました。

この時点である程度、実用的な乱数処理の解析は完了していたのですが、イッシュの難関に限ると、生成処理のあまりの複雑さから断念されたようです。

ちなみに、数ヶ月前に開拓したPWT乱数、実は発売後数年でdorara32さんが実機で解析されていました。(やばすぎる)

当時の乱数解析勢の熱狂具合は恐ろしいですね。

話を戻しまして、イッシュの難関生成処理のどこが複雑であったのかを話していきます。

イッシュの難関生成処理には、"Unova乱数列生成"、"通路生成"、"フロア生成"、"トレーナー生成"の4段階に別れています。(どれも問題ではある)

前提知識として、第5世代では個体値乱数列・性格値乱数列以外に、一時的に使用に使用される乱数があります。

64bitの孵化乱数列・PWT乱数列がそれに該当し、イッシュの難関にも32bitのUnova乱数列が存在しています。

しかし、その実態は64bit LCGを164回回し、その一部を32bit * 84個として格納・使用するというものでした。(こんなの実機でわかるわけないだろ!)

次に、通路生成のお話です。

簡単に言うと、エレベーターフロア(0,0)を原点に一巡で各フロアを回り、通路を1本作ります。これを2回。

一巡かつ行き止まりの処理も考えないといけないので、実機の調査は不可能ですね。おわり。

お次にフロア生成。

これも、テーブルを覗かないと無理ですね。おわり。

最後にトレーナー生成。

これも(ry

とまぁ、こんな感じです。

概要はMugenRNGのソースコードだったり、調査隊の中間報告でも見てください。

バトルサブウェイ乱数を開拓したさきさんであったり、dorara32さんであったり、当時の開拓者が最新のエミュレータを使えばあっさりと解析できそうですけどね。

技術的補足

【ここは乱数調整有識者向けです】

前述のUnova乱数列生成にあたり、大きな問題となる処理がありました。

それは、Unova乱数列の初項を64bit LCGでSeedを更新する際、種となる32bitで算術右シフトが発生しているという点です。

夜綱さんのコードを借りてC#で書くとこうなります。

    uint Seed32bit = 0xBEEFCAFE;
    ulong Seed64bit = (ulong)((int)Seed32bit);
    Seed32bit → 0xBEEFCAFE
    Seed64bit → 0xFFFFFFFFBEEFCAFE

要するに、64bit LCGの種が32bit かつ 最上位bitが1(intで負の数)とのき上位32bitが0xFFFFFFFFで埋められます。

この処理を数日前に発見してから、ツール完成を間に合わせるため、睡眠時間削ってPCとにらめっこしてました。;;

第5世代ではイッシュの難関の他に、起動時の乱数処理として発生しているようですがよくわかりません。

サイファーさんによると、BDSPでも一部この処理が行われているそうです。

イッシュの難関乱数ってなにするの?

導入がクソ長くなりましたが、本題に入っていきたいと思います。

 

まずは、「イッシュの難関乱数調整ってなにやるのー?」という話ですね。

今回のイッシュの難関乱数では、ほぼ全ての事象の予測初期SEEDの検索を行います。

イッシュの難関の生成処理は個体値乱数列の32bitひとつから生成されているため、性格値乱数列の初期SEEDがわかれば、全ての予測が可能という訳です。

 

ドクターと手持ちの生成処理に限り、調査が終わっていないため実装していません。悪しからず。

使用ツール

・MugenRNG v1.1.0

github.com

動作には.NET 8.0が必要です。

MugenRNG v1.0.0は動作しない欠陥なので捨ててください。

 

・5genSearch

レポ針から初期SEEDを特定するのに使います。

実践

個体値乱数列の消費ズレを防ぐため、

・バトルボックスを空にする。

・徘徊等の個体値乱数消費を発生させない。

以上の条件を前提とします。

 

例によって実機での環境が整っていないため、DeSmuMe 0.9.13を使用。

初期SEEDの設定には Seed_Injection_J.lua を使用します。

MugenRNG

調べた初期SEEDを入力し[GO!!]すると、

・各フロアの種類と通路の有無

・ボス部屋の場所

・ゲートトレーナーの場所

・出現トレーナー

がわかります。各層1人だけドクターに上書きされます。(未実装)

ハピラキ爆弾

ポケモンブリーダーをハイライト]にチェックを入れながら[GO!!]すると、ポケモンブリーダーの手持ちを別ウィンドウに表示す...

る予定だったんですけど、間に合わなくて実装できませんでした。

↓こんな感じで手持ちが確認できる予定だった。

(後ろの子はアシマ先生のシーンちゃんです)

高速金策

[マダム/ジェントルマンをハイライト]にチェックを入れながら[GO!!]すると、マダム/ジェントルマンのいる部屋をハイライトす...

る予定だったんですけど、なんか実装してません。やろうと思えばすぐできます。

最速クリア用SEED検索

今回の乱数調整の本マルです。

各種設定を行い[検索]を押すと、最速クリアが可能な初期SEEDを返します。

使い方は5genSearchの初期SEED検索とほぼ同じです。(というかほぼパクり

初期SEEDは無限に出てくるので、いいカンジのところで[中止]するか検索範囲を狭めましょう。リスト上の右クリックが機能しないので、Seed欄で[Ctrl + C]でコピー、MugenRNGの入力フォームで[Ctrl + V]でペーストして検索してください。

キーリンクはどちらでも結果は変わらないと思います。

youtu.be

あとがき

いかがでしたか?

今回は、令和最新版の乱数調整「イッシュの難関乱数」について解説しました。

導入と乱数調整部分の比率がおかしいのは気のせいです。

 

元々は、MugenRNGだけ実装する予定だったのですが、GUIの初期SEED検索を自作したいと思ったので急遽追加することにしました。(速度は出ないし最適化されてないけど)

初期SEED検索のコードの9割AI (無料枠のChatGPT-5と無料のGemini Pro)を使って2日で完成させました。(流用したCUI版の5genSeedUntiもAIに作らせた)

つまり、AIにコードを書かせれば誰でも乱数ツールが作れるわけですね!こういうのに興味がある人はやってみましょう。

...

あと、イッシュの難関の生成処理はどの階層も基本的に同じです。今回はエリア10のみ対応したツールを作りましたが、やろうと思えばエリア1~10すべてに対応させることもできます。

 

あとあと、今後の進展について。今回実装した初期SEED検索を元に、GUI版BW2のパラメータ高速検索プラズマスキップツールを作ろうと思ってます。やる気が出れば。

 

あとあとあと、MugenRNGのアイコンを募集しています。デフォルトだと味気ないので誰か作ってください。

 

そして最後に、

乱数ツールの9割はAIが書いてるので誰でも乱数ツールを作ることができます!!!

 

以上。

 

3日目の記事は空さんの「ポケモン最新作の乱数について」です。

CFWでゴニョニョするのかな?(Φ+Д+Φ 

 

 

 

 

 

 

 

【DQMJ2P】タイトル画面から初期SEEDを復元する

珍しく、DQMJ2Pの乱数調整です。

はじめに

本作、DQMJ2P/DQMJ2はタイトル画面で様々なフィールドが表示される。この画面でLCG 1消費が発生するのだが、これを利用して初期SEEDを復元できると思いついた。

概要

DQMJ2P/DQMJ2の乱数生成は基本的な32bit LCG(線形合同法)で、

r[n+1] = (0x41C64E6D * r[n] + 0x3039) mod 0x100000000

乱数処理は全て、上位16bitのモジュロ演算(mod)で行われる。

内容

タイトル画面生成時には、上位16bit mod 1~7で乱数をとる。この1~7の値は本編の進行状況により異なる。そのため、密林クリア前に初期SEEDの復元はできない。

乱数の値は0~6の範囲で、

0:密林 1:平原 2:雪山 3:断崖 4:海岸 5:遺跡 6:ピピッ島

のいずれかのフィールドが表示されるようになっている。

フィールド表示による乱数消費はタイトル画面に戻るたびに発生するため、ワイヤレス通信から戻る等で連続した乱数の取得を行うことができる。

この連続した乱数から初期SEEDの総当たり/現在SEEDの特定を行う。

総当たりの場合は、連続した15程度の乱数。起動時間を指定すれば5つの乱数から初期SEEDの特定が可能と思われる。また、32bit LCGの初期SEEDはJST依存であり、32bitからの起動時間の逆算は容易である。

用途

特にない。強いて言えば、RTA用に空白時間の計測が行える程度だろうか。

本作は某ポケモンとは異なり、不定消費が大量に発生するため乱数調整の余地はない。

また前作、DQMJでもタイトル画面での初期SEEDの復元が可能と思われるが、こちらも用途はない。

【ポケモンDPt】スロットマシーン設計書

詳しい内部処理は過去記事、pastebinのソースコードを参照。

スロット配置

DPt Slot RNG - Pastebin.com

スロットの配置は日替わりSEEDから決定される。

・12byteの規定配列(0-5-1-1-4-4-2-2-2-3-3-3)を取得。

・日替わりSEEDをLCGで更新、上位16bit %12の乱数値を取得。

・乱数値を参照して規定配列の入れ替えを計66回行う。

配列1byte目と乱数値byte目を入れ替え、これを11回繰り返す。

配列2byte目と乱数値byte目を入れ替え、これを10回繰り返す。

配列3byte目と乱数値byte目を入れ替え、これを9回繰り返す。

配列4byte目と乱数値byte目を入れ替え、これを8回繰り返す。

配列5byte目と乱数値byte目を入れ替え、これを7回繰り返す。

配列6byte目と乱数値byte目を入れ替え、これを6回繰り返す。

配列7byte目と乱数値byte目を入れ替え、これを5回繰り返す。

配列8byte目と乱数値byte目を入れ替え、これを4回繰り返す。

配列9byte目と乱数値byte目を入れ替え、これを3回繰り返す。

配列10byte目と乱数値byte目を入れ替え、これを2回繰り返す。

配列11byte目と乱数値byte目を入れ替える。

・最終的な12byteを特定の位置に配置する。

現在SEEDの特定

トバリゲームコーナー入り口で初期SEEDの特定。

スロットの出目を参照して、対応したSEEDを総当たりする。

出目の抽選

トバリスロット乱数調整 - Pastebin.com

基本的な出目の抽選はLCG3消費で行われる。

0x6185ADDCを現在SEEDとするとき

・0x6185ADDC:現在SEED

・0x950C6F1F:ボール出現抽選

・0x112122A6:ボール種類抽選

・0x560EB521:プレミアボール抽選

ボール抽選判定が不の場合は以降の処理は行われない。

ボール種類抽選でピッピ入りが選ばれた場合、追加で2消費が発生する。(後述)

・ボール出現判定(設定5)

上位16bit %100の値が

・35未満のとき、ボールが出現する。

・ボール抽選判定(設定5)

上位16bit %100の値が

・4のとき、モンスターボール(ヒメリの実)

・11~19のとき、サファリボール(つきのいし)

・23~59のとき、ハイパーボール(ピカチュウ)

・63~99のとき、スーパーボール(リプレイ)

が出現する。

それ以外のときはピッピ入りのボールになる。

・プレミアボール判定

省略

・追加判定(設定5)

ボール判定抽選時にピッピ入りのボールが選ばれた場合、追加で2消費が発生する。

0x6185ADDCを現在SEEDとするとき

・0x6185ADDC:現在SEED

・0x950C6F1F:ボール出現抽選

・0x112122A6:ボール種類抽選

・0x560EB521:プレミアボール抽選

・0x97F98D80:ピッピテーブル抽選

・0xAF5E9FF3:ピッピ抽選

・ピッピテーブル抽選

ピッピ抽選テーブル(A、B、Cテーブル)の抽選を行う。

上位16bit %100の値が

・0~4、70~99のとき、Aテーブル

・5~24、60~69のとき、Bテーブル

・25~59のとき、Cテーブル

・ピッピ抽選

Aテーブル

上位16bit %100の値が

・0~4のとき、色違い

・5~24のとき、通常色

・25~99のとき、メタモン

Bテーブル

・0~19のとき、色違い

・20~79のとき、通常色

・80~99のとき、メタモン

Cテーブル

・0~74のとき、色違い

・75~94のとき、通常色

・95~99のとき、メタモン

 

【ポケモンBW2】PWTを利用して高速でパラメータを特定する

既存の方法として、「はじめから」からトレーナーIDでパラメータを特定する方法がありますが、今回はPWTを利用してパラメータを特定していきます。

3DSや海外ROMにも対応していますが、PWTを利用するパラメータ特定はBW2専用であることに注意してください。

[トレーナーIDから特定する方法]

ポケモン BW2 パラメータ特定 乱数調整 - ミルクの日記

使用ツール

・BW2PrmSearcher

github.com

技術的解説

PWTレンタルトーナメント/レンタルマスターは、性格値乱数を消費してレンタルポケモン6匹を決定しています。

このランダム性を利用することで、レンタルポケモンに対応した性格値乱数初期SEEDを総当たりしています。

レンタルマスターは乱数値%350とランダム性がより強くなり検索しやすくなりますが、ホドモエジム攻略後に利用できる点を考慮して、レンタルトーナメントを使用しています。

実践

例によって実機環境が整っていないため、エミュを使用して実践します。

[年, 月, 秒, 時, 分, 秒, VCount, Timer0, 初期SEED]
0, 11, 22, 11, 22, 33, 0x82, 0x1105, 0x7F23F41FDD333BC9

使用エミュレータ:DeSmuME 0.9.11

Seed_injection_J.lua を使用して初期SEEDを設定する。

Config.txtの設定

Nazo値、Timer0ほかバージョンに対応した値を設定します。

国内・海外問わず使用できるはずです。(知らんけど)

【BW/BW2】全28バージョンパラメータ纏め - なるほどえたきちのブログじゃねーの

Macアドレスは[00-11-22-88-22-77](某極悪違法ツールのデフォルト)

DateTimeは現在時刻周辺を設定します。今回は11:00:00 ~ 11:59:59の範囲とします。

パラメータの特定

「つづきから」までの流れは同じ。

PWT、左の受付からレンタルトーナメント/みぎのクジを選択します。

選ばれた6匹を上から順番にツールに入力するとパラメータが出力されます。

指定するDateTimeの範囲によりますが、4~5匹入力すれば検索できます。
たまに検索できないことがあるので、全角スペースを押して別の条件で再検索しましょう。

【ポケモンBW2】イッシュの難関調査隊 中間報告

かつての調査隊が失踪したので引き継ぎます。

↓失踪した調査隊の中間報告 ( ・‿‿・ )

要約すると、

( ・‿‿・ )

「なんの成果も!! 得られませんでした!!」

イッシュの難関を破壊するツール↓

調査結果(固有SEED編)

イッシュの難関で使われる固有SEEDの話。

個体値乱数列から一つ取得し、個体値生成処理をする。これを r[0]とする。この32bitをLCGで更新し、上位32bitを3つ取得する。

その後、LCGを160回更新して、上位32bitのうち下位16bitを160個取得する。

これらの計84個の32bitがイッシュの難関の乱数列となる。

個体値乱数列オフセット+2(0xDAFD0012)のとき、

CC0A3CB0 C5904B6E 009DA10C 4723EBB6
6AD36824 5F960BD0 3F6A356D B57D5C7C
1B4819F7 AB0025DD 8AD3E265 EC20370A
09EC19DE 5B719D97 E9D9EEEA 2292BE8A
8744496A 1237E791 9AD6B85A 9D02F7B5
624A6736 3CBD101F 7D8CC56D 72D572AD
E8E6A89D B22712B5 E4597BF7 BD925C3B
26D99DE8 0BF1C467 63B75081 3AB5F3D7
3F291B71 F4445CFC CDF60699 E2239F2A
020194EA 84BBEEB7 F3069F7B 569F4CB8
2E9C72D1 77C389C2 ADBA835C C188F7DA
269F6CC2 5EC75CE3 41E4487A 9EC0E928
3607DE1F 46E4E1F0 103139D3 3976BF19
F8905D4F 35C80914 2E996609 1E466359
D327988C AFF962F1 85DB8DE2 92DDD22B
EDE49DF4 09B77E22 AE49C072 371601DD
988C3F5F 9B2209AD E7F0D1C8 4F414911
89A23534 1058D273 33C91FC0 DB045B74
F58BFE28 F5CC5E94 C58B4751 880E551C
11343CBD 50ECBE70 BF548369 C38355A5
315A7DDC 8CE927B0 6A296D3C A8E4DCCE

こうなる。

調査結果(エリア生成編)

各エリア生成処理は、ボス部屋生成→通路生成→部屋生成の順番で行われる。

Unova乱数列オフセット+2(0x009DA10C)を種にした64bit LCGで、

消費数 上位32bit 補正 乱数値 備考
0 00000000 0 0
1 8D049251 4 2 ボス部屋階層
2 CBF453BB 11 8 ボス配置
3 8111724E 2 1 (1,1)下
4 F41B5713 2 1 (2,1)下
5 FC2F5426 2 1 (3,1)下
6 F896C23D 1 0 (4,1)右
7 C4CF4064 2 1 (4,2)上
8 4DA301C0 2 0 (3,2)右
9 A1EC3B32 3 1 (3,3)下
10 C97B6889 1 0 (4,3)右
11 8DFE5002 1 0 (4,4)上
12 7EBB979E 1 0 (3,4)上
13 4E8A3FFF 2 0 (2,4)左
14 07BE5E0C 2 0 (2,3)左
15 478AB142 1 0 (2,2)上
16 C757C199 1 0 (1,2)右
17 AEB76CE7 1 0 (1,3)右
18 078E94E8      
19 A63F4C3E      
20 F2C5AF67      
21 AC330FEC      
22 CFBE5DF3      
23 F532C2F8      
24 8597D754      
25 D193CCD5      
26 8DE855D0      
27 2155410A      
28 882247E8      
29 39567D08      
30 BE23E12F      
31 F6DAF489      
32 11F021EE      

最初の2消費でボス部屋の階層・配置を決定する。

その後の15消費(ボス階層は14)で通路を生成、追加の15消費で補正を行う。

通路生成はエレベーター室から一巡に行い、通路のない部屋が生成されることはない。

詳細はMugenRNGMugenFloor.csを参照。

通路生成後にはフロア配列を決める。

黒の摩天楼のフロア配列の初期値は以下の通り.

エリア10 - 16
02 02 09 09 09 0A 0A 0A 0D 0D 0F 0F 10 13 13
エリア10 - 17
00 00 00 02 02 0B 0B 0B 0E 0E 0F 0F 10 13 13
エリア10 - 18
02 02 06 06 06 09 09 09 0E 0E 0F 0F 10 13 13
エリア10 - 19
02 02 07 07 07  0A 0A 0A 0C 0C 0F 0F 10 13 13

この15byteを入れ替えた後、エレベーター室・ボス部屋を除いて順番に配置される。また、ボス部屋直下の部屋は一定範囲で固定されている模様。

エリア配列関連はMugenRoomB/W.csを参照。

調査結果(トレーナー生成編)

トレーナー生成では、Unova乱数列オフセット+1(0xC5904B6E)を種にした64bit LCGを使用する。

出現するトレーナーの種類と数は決まっており、

サイキッカー3人、研究員5人、塾帰り3人、ウェイター4人、短パン小僧3人、ミニスカート2人、バックパッカー5人、マダム1人、ジェントルマン1人が選ばれる。

各層ごとのトレーナー生成処理は同じなため、別の層に同一トレーナーが出現する場合がある。

また、フロア配置処理の過程で、トレーナーの配置数が減少する場合がある。その時はトレーナーごと消滅する。

トレーナー生成後はゲートトレーナーを決定する。

2消費で階層と該当トレーナーを決定する。ゲートトレーナーが消滅することはない。

トレーナー関連処理はTrainerB/W.csを参照。

ゲートトレーナー決定後にドクターの生成を行う。

ドクターのテーブルは
0285 0286 0287 0289 028A

これを5回入れ替え処理を行い、前から4つを27のTIDに上書きする。

なんかよくわからん。別に実装しなくてもいいけど

調査結果(ポケモン生成編)

手持ちポケモンの生成には160個の16bit群を使用する。

格納されたTIDテーブルを参照して、若い順に上から16bitを種とした64bit LCGで手持ちを生成する。

各階層に格納されているTIDは27+5。27のうち後ろの0~6は使用されない場合があり、+5は0xFFFFで埋められている。

(27 + 5) * 5層分で計160のTIDが格納される。(5層目はリザーブらしい)

生成処理は(上位32bit * 手持ち数) >> 32だと思う。重複には補正値を掛けそう。

一般トレーナーの手持ちを知る必要はないので、ポケモンブリーダー(3匹)だけ調べればいいかな。

まとめ

現時点で判明したUnova SEEDのうち、r[0]とr[3]だけ用途がわかっていない。