# ポケモンコロシアム ボルグのフロアにおける不定消費について
この記事は[Pokémon RNG Advent Calendar 2020](https://adventar.org/calendars/5311) 3日目の記事です。
この記事はコロシアムライコウ乱数実用化直前の段階で公開したページを加筆したものです.
ポケモンコロシアムの解析の基本的な情報は[こちら]( https://scrapbox.io/yatsuna827827-12010999/%E3%83%9D%E3%82%B1%E3%83%A2%E3%83%B3%E3%82%B3%E3%83%AD%E3%82%B7%E3%82%A2%E3%83%A0%E3%81%AE%E4%B9%B1%E6%95%B0%E8%A7%A3%E6%9E%90)にまとめてあるので, 解析してみたい方は参考にしてみてください.
## 0.0 はじめに
![](https://i.imgur.com/F1Lcn5o.jpg)
知らない人はびっくりするかもしれませんが, コロシアムのダークライコウは乱数調整可能です. 難易度は普通のGBA乱数くらいです.
今年の3月末に公開したCOSearchによってコロシアムライコウの乱数調整が可能となり, 某鳥アイコンの方の乱数調整成功を皮切りに, 4月頭には色理想ダークライコウが量産されました.
かけらさんによるスイクン乱数の開拓と合わせて, 長らく乱数調整不可能と言われていたスイクンとライコウが3世代実機対戦に放たれることとなり, キャラランクにも大きな変動を与えているみたいです(オフ会をまともに開けない情勢なので実際の使用感とかは未知数らしいですが).
12月ということでAdventCalenderのネタを探していた時, 「そういえばライコウの解析をしたのはまだ今年だった, 記事としてちゃんと公開してないや」と思い出し, あとあんまり放置しすぎるとどういう処理だったのか忘れそうなので, これまでライコウの乱数調整を困難なものにしていた泡マシーンの挙動について, 詳細に書き残しておくことにしました.
## 0.1 当時の序文
ダークポケモン研究所の最下層では不定消費(時間経過で乱数が消費され, その速度が一定でない)が存在する.
かけら(sina_poke)氏によるステータス画面でのポケモンの瞬きの観測を利用したseed特定法の開拓により, いくつかのダークポケモンの乱数調整が容易になったが, ダークライコウの乱数調整の難度は, この不定消費によっていまだ高いままである.
この不定消費の発生原理を解明し, 制御することを目的とし, 調査を行った.
## 1. 不定消費についての基本事項
## 1.0. 不定消費の仕様
- いくつかの例外を除き, 基本的には常に消費は発生している.
- メニューを開いている間やNPCとの会話, イベントの最中も例外ではない.
- 手持ち画面(ポケモン6匹が並ぶ画面)やP★DAを開いている間は消費が止まる.
- 手持ち画面やP★DAからメニュー画面に復帰する際には初期化処理が入る.
- 一般に「不定消費が存在する」と言われているエリアには, 単に不定移動NPCの移動を制御するために乱数が使われているものと, そうでないものがある.
前者は移動方向と待機時間を決定するのみであり, 消費の発生頻度は高くない(バトル山フロント等).
後者は観測した限りでは, マップに存在するオブジェクトの不定期な動作を制御するものと考えられる.
## 1.1. ボルグのフロアにおける不定消費の用途
- ボルグの部屋から壁を挟んだ南側にある部屋(エレベータが2つ並ぶ部屋の北の部屋)にある6つの機械内に発生する気泡の制御に用いられている.
![](https://i.imgur.com/LoArSjH.png)
## 2. ボルグのフロアにおける不定消費の詳細
## 2.0 処理の概要
- 6つ並ぶ機械のうち, 泡が発生するのは4つだけ(上の画像の通り).
- この4つの機械の泡の発生を管理するために, float値を取るカウンタが4つ存在する. 以下, これを<b>メインカウンタ1~4</b>と呼ぶ.
- 各メインカウンタには従属するカウンタが存在する. メインカウンタ$i$に従属するカウンタを<b>サブカウンタ$i$</b>と呼ぶ.
- サブカウンタは泡の発生の契機となるカウンタである. つまり, サブカウンタが溜まることで泡発生の処理が走る.
## 2.1 詳細な処理の記述
- 毎フレーム乱数を4つ発生させ, 4つのメインカウンタを順番に加算していく. この時の処理は$j$フレーム目のメインカウンタ$i$の値を$c_{ij}$で表せば, $$c_{i(j+1)} = c_{ij} + {\rm rand} * 0.003$$となる(ただし${\rm rand}$はLCGで得た16bit整数を65536で割ったfloat値である.以下同).
- メインカウンタが1以上になった場合(以下これを<b>繰り上げ</b>の発生と呼ぶ), メインカウンタの値が$-1.0$され, 直後に1消費が入り(用途不明), その後サブカウンタが初期化される.
- サブカウンタの値は0.9999999(0x3f7ffffe)で初期化される.
- 以後, 発生したすべての泡が消えるまでの間, サブカウンタの加算処理が追加される.サブカウンタの加算処理が走るタイミングは, 呼び出し元のメインカウンタの加算処理(及び繰り上げ時の1消費)の後である.
- 泡の発生から消失までは100Fである.
- サブカウンタの加算は$$d_{i(j+1)} = d_{ij} + rand * 0.5$$で行われる.
- ただし, サブカウンタ起動後100F目の加算後にrandの係数が0に変更される.すなわち泡の発生が起こり得るのは, サブカウンタ起動後100F目までである.
- サブカウンタの繰り上げが発生した場合, 直後に6消費が追加される.さらに, そのフレームにおけるすべてのカウンタの加算処理が終了した後に(次のフレームの頭に?)1消費が追加される.
- サブカウンタの繰り上げが発生してから30F後, メインカウンタ1の加算処理の前に3消費が入る.
- サブカウンタの繰り上げが発生してから40F後, メインカウンタ1の加算処理の前に1消費が入る.
- 手持ち画面からメニューに戻る際, メインカウンタは0.9999999f(0x3f7ffffe)で初期化される.
- この仕様のおかげで不定乱数の調整が現実的なものになってくれた.
## 2.2 よくある(?)疑問と回答
#### Q. サブカウンタ起動中にメインカウンタに繰り上げが発生した場合にサブカウンタが2つ従属するのか?
A. メインカウンタの係数を1桁間違えていた.最大でも1Fに0.003しか加算されないため, 100F間隔で繰り上げが発生することはあり得ない.
#### Q. サブカウンタの動作が終了する30F(もしくは40F)以内にサブカウンタの繰り上げが発生した場合, 遅れて発生する消費は発生するのか?
A. これも起こりえない.サブカウンタの動作停止は最後の泡の発生から100F後であるため.
## 2.3 いやわからんわ
と言われそうなので, シミュレートするプログラムの疑似コードを書いてみた.
https://gist.github.com/yatsuna827/bea34f19b48ca8aceabbf4696d13341f
適度にコメントしてありますが, わからないところがあればTwitterでご質問ください.
## 3. ハマったところ
ScrapBoxにも書いたことばかりですが, 一応, 改めて.
### 3.1 安定版(5.0)ではBreakPointがまともに使えない
そもそも機能として存在してないとかそういうレベル.メモリにBP仕掛けて読み込んでいる箇所の付近を調べるみたいな調査ができないのでもうお手上げ.開発版(5.0-11707を使った)には実装されていたので助かったが, 開発版ゆえに不安定な部分もあるっぽい.開発版のバージョンによってはBPが上手く機能しないものもあったので, いろいろ試してみないといけなさそう.
### 3.2 レジスタビュワーの小数型の表記が罠
![](https://i.imgur.com/RqsHHqC.png)
2列目の"f"が頭についているのが小数値を格納するレジスタ.f0からf31まである.Dolphinのビュワーでは64bitで表現されているのが, 実態はfloatらしい(命令で切り替えられるのかも?).気づくまで64bitのままで計算して合わねえな~ってずっと言ってた.
### 3.3 止めすぎると落ちる
仕方ない.XDはもっと不安定.普段以上にストレス耐性が要る.
## 4 最後に
~~実機対戦でライコウが暴れて環境を壊しても責めないでください.~~
ポケモンコロシアムはヌオーが大活躍する神ゲーなのでぜひプレイしましょう.
記事を書いている時点では次は7日まで埋まっていませんが, 誰か書きませんか?