白銀のライねる

解析とかのメモとかをなんとか

【空の探検隊】技データ・技習得データの解析【waza_p.bin】

技データの解析について解説。

技データは「BALANCE/waza_p.bin」に格納されており、各ポケモンの技習得データも一緒にまとめられている。

SIR0形式のファイルで、どこからが技データか、技習得データであるかがポインターで示されている。
SIR0形式については以下の記事を参照。
lainel.hatenablog.com

なお、本記事ではロムハック等を行っていないバニラの状態であることを前提とする。


「waza_p.bin」の構造は以下の通り。

0x00~0x0F SIR0ヘッダー
0x10~(不定) 技習得データ
(技習得データ)~(不定) 技データ
(技データ)~ SIR0ポインターリスト

技習得データはSIR0ポインターの展開と同じ仕組みでデータが圧縮されているので、バイナリから値を読むには変換する必要がある。これについては先程のSIR0の記事に書かれているが、本記事でも解説していく。

データ取得

技習得データはフシギダネ(0x001)~闇のディアルガ(0x228)まで順番に格納されており、そこから更に「レベル習得技」、「技マシン習得技」、「タマゴ技」と3つのリストに分かれている。

そして、SIR0ポインターリストが指すポインターは"それぞれ3つの習得技リスト×全ポケモン分"となっている。
ここでは例としてフシギダネのデータを解析してみる。

まずポインターリストの位置を特定する必要がある。
SIR0ヘッダーの0x08を確認する。

ここの値を4バイト取ると「B0 33 01 00」。並べ替えると「000133B0」なので、ポインターリストは0x133B0が開始位置となる。


0x133B0にジャンプしてみると、やたらと0x4が並んでいるがこれはポインターの値が4バイトであるため、4バイト区切りでポインターが存在しているということになる。

このポインターリストは最初の値から順に足していくことでポインターポインターを把握することができる。ややこしいけど。

最初の0x4はSIR0ヘッダー内の0x4にあるコンテンツポインターを表す。
次は0x4なので先程の0x4に加算して0x8。これは先程確認したSIR0ヘッダーのポインターリストのポインター
その次の値がやたらとデカいが、これは値が複数のバイトで構成されており、0x80を下回るまで連続で取得する必要がある。

現在の値は0x84。これは0x80を超えている。
その次の値は0xB3。これも0x80を超えている。
更にその次の値は0x34。ここまででようやく0x80未満となるのでここで区切る。

次に以下の式で値を求める。0x80を下回るようにするため0x7FでAND演算を行い、「取得した値の数×7」の分だけ左へシフトした値を足していく。シフト数は値を足すにつれて7ずつ減らしていく。

# 取得した値が4つ
値 = ((1つ目の値 & 0x7F) << 21) + ((2つ目の値 & 0x7F) << 14) + ((3つ目の値 & 0x7F) << 7) + (4つ目の値 & 0x7F)

# 取得した値が3つ
値 = ((1つ目の値 & 0x7F) << 14) + ((2つ目の値 & 0x7F) << 7) + (3つ目の値 & 0x7F)

# 取得した値が2つ
値 = ((1つ目の値 & 0x7F) << 7) + (2つ目の値 & 0x7F)

# 取得した値が1つ
値 = 1つ目の値 & 0x7F

今回の値を当てはめると以下の通り。

値 = ((0x84 & 0x7F) << 14) + ((0xB3 & 0x7F) << 7) + (0x34 & 0x7F)

((0x84 & 0x7F) << 14) = 0x10000
((0xB3 & 0x7F) << 7) = 0x1980
(0x34 & 0x7F) = 0x34

これらを合計すると、0x10000 + 0x1980 + 0x34 = 0x119B4
そして以前までの値である0x8を足すと、0x119B4 + 0x8 = 0x119BC

よって、フシギダネのレベル習得技にあたるポインターリストのポインターは「0x119BC」となる。

以降は技データのポインターまですべて0x4なので、「0x119C0」「0x119C4」「0x119C8」といったように、4バイト区切りでポインターが並んでいることがわかる。


0x119BCにジャンプすると、ここでようやく「フシギダネのレベル習得技データ」そのものへのポインターに辿り着く。

ここの値は「13 00 00 00」なので、「0x13」がフシギダネのレベル習得技データのポインターとなる。
ついでに、次のポインターにあたる0x119C0の値は「0x3C」。これがフシギダネの技マシン習得技データにあたり、その次の0x119C4の値は「0x70」で、これがタマゴ技習得データとなる。

技習得データ

先程求めた0x13にジャンプすると、これまた不規則な数字がやたらと並んでいるように見えるが、これもSIR0のポインターと同じように変換する必要がある。

最初の値は「0x81」で、これは0x80を超えているので続けて値をチェックする。
次の値は「0x1A」で、0x80を下回るのでここで区切る。
今回は2つの値になるので、「((0x81 & 0x7F) << 7) + (0x1A & 0x7F)」で求める。
よって、0x80 + 0x1A = 0x9A

この値は一旦置いといて、次の値を取る。値は「0x1」で、0x80を下回るので区切る。

技取得データはこの2バイトで構成されている。
最初に取得した「0x9A」は技IDを表し、次に取得した「0x1」は習得レベルを表す。

0x0 技ID
0x1 習得レベル

0x9Aにあたる技は「たいあたり」なので、「フシギダネレベル1たいあたりを覚える」ということになる。

技IDに関しては、text_j.strに含まれる技名リストのインデックスとなっているのと同時に、後述の技データのインデックスにもなっている。

技マシン・タマゴ技習得データ

これら2つの習得データにはレベルが存在しないため、すべて技ID単一となる。
フシギダネの技マシンのポインターは0x3Cなので、そこにジャンプ。

0x12は「いあいぎり」、0x18は「いばる」・・・といったように、レベル技と同じように並んでいる。同様に、0x80以上の値は変換する必要がある。

フシギダネのタマゴ技のポインターは0x70。

0x0Bは「あまえる」、0x54は「くさぶえ」・・・といったようにこれも同じ構造。

ちなみに、技マシンの習得データには本来技マシンとして存在しない「あまごい」等の天候技や「かげぶんしん」「がんせきふうじ」「よこどり」が含まれていることがある。正真正銘の没データ

これらの技は技マシンではなくふしぎだまの効果(「あめだま」「ぶんしんだま」等)として存在している。技マシンとふしぎだまには技IDを設定できるパラメータが用意されており、この値が他の道具と被ると何らかの不都合があるため技マシンから削除されたと思われる。

習得データとして登録されているのはおそらく、本家ポケモンから習得データをツールか何かで一括変換した際の名残・・・だと思っている。


フシギダネの分が終わると次はフシギソウの習得データに移る。ポケモンIDと同じ順序で進んでいく。

技データ

SIR0ヘッダーの0x4であるコンテンツポインター(4バイト)を確認する。

値は「A0 33 01 00」で、アドレス0x133A0を指している。
ここへジャンプすると、2つのポインターが並んでいることが確認できる。

これは0xE0E0、0x119B0から始まるデータがこのファイルのコンテンツとして存在しているということになる。

0xE0E0にジャンプすると0x00が多いスカスカなデータ群が見つかる。これが技データである。


ちなみに0x119B0は先程の習得データのポインターリストのポインターを指している。この位置から数えると0x00のポインターが3つ取得できるが、これは無効な値となる。いわゆるnullである。



ポケモンデータの一番最初は「なにものか」というダミーのポケモンが設定されており、ゲーム内で表示させようとするとスプライトIDが0xFFFFである為フリーズ。更にあらゆる値が0x00である為、終端を0x00で判定している処理ではいろいろ不具合が起きてしまう。
おそらく習得データの個数をポケモンデータの個数と揃える為に入れられたダミーデータと思われる。


技データの構造は以下の通り。長さは26バイト。

アドレス データ型 名称 備考
0x00 int16 威力 技の威力。内部の値であり、ゲーム上では確認できない。主にダメージ計算に使用される。
0x02 int8 タイプ 技のタイプ。ポケモンデータと同様。
0x03 int8 分類 0…物理、1…特殊、2…変化
0x04 int16 ビット1 近距離攻撃に関連するビットフラグ。詳細は不明。
0x06 int16 ビット2 遠距離攻撃に関連するビットフラグ。詳細は不明。
0x08 int8 PP 技のPP。
0x09 int8 不明。0、8、10、15、20、25、30、70の値。
0x0A int8 不明。0、15、20、65、70、75、80、85、88、95、100、125の値。
0x0B int8 命中率 技の命中率。値が125の技は必中。
0x0C int8 不明。0、20、50、75の値。
0x0D int8 最大連続攻撃数? 連続で攻撃する技の最大攻撃回数?
複数回攻撃する技のみ2~5の値が設定されているが、0に設定されている技もある為詳細不明。
0x0E int8 カテキン使用上限 カテキンで技を強化できる回数。攻撃技はすべて99、変化技はすべて0。
通常攻撃にあたる「こうげき(0x168)」のみ値が1。
0x0F int8 急所率 急所に当たる確率。何故か変化技にも設定されているが、殆どの技は8である為これが開発中のデフォルト値だったと思われる。
他にも、連続攻撃技は1~3、「きりさく」等の急所に当たりやすい技は30、ふしぎだまの効果にあたる技や未使用($$$)の技はすべて0、「がまん」「リベンジ」「ゆきなだれ」が解かれた時に出る攻撃技は2に設定されている。
0x10 int8 不明。0~1の値。相手に効果がある技のフラグ?
0x11 int8 不明。0~1の値。自身に効果がある技のフラグ?
0x12 int8 不明。0~1の値。何らかのフラグ?
0x13 int8 やけど関連の値? 相手をやけど状態にする技やそれを回復する技のみ0に設定されている。それ以外は1。詳細不明。
0x14 int8 攻撃技を示すフラグ? 攻撃技は1、それ以外は0。
0x15 int8 不明。0~31の値。
0x16 int16 技ID 内部で明示的に設定された技のID。
有効な技である0x21Fの技までは連番が振られているが、無効な技となるその次の技からは何故か0x19Eから順に割り当てられる。
0x18 int8 不明。0~1の値。何らかのフラグ?

これを元に技データを構成していく。
先頭である0xE0E0から技データ1つ分である26バイトを取る。

技データの一番最初(ID=0x00)はダミーデータとなっており、技名は「なし」。一応技ではあるのでこれも技データとして取得する必要がある。

この値を上記表に当てはめると、各パラメータが何を表しているかがわかる。ただ、ダミーデータだとわかりづらいのでその次のデータ(ID=0x01)を例とする。
最初の位置から26バイト進んだ0xE0EAから26バイト取得する。

この技は「アイアンテール」。これを表に当てはめていくと以下のようになる。

0x00 威力 40 (0x0028)
0x02 タイプ はがね (0x11)
0x03 分類 物理 (0x00)
0x04 ビット1 00000000 00000000 (0x00)
0x06 ビット2 00000000 00000000 (0x00)
0x08 PP 10 (0x0A)
0x09 15 (0x0F)
0x0A 125 (0x7D)
0x0B 命中率 78 (0x4E)
0x0C 75 (0x4B)
0x0D 最大連続攻撃数? 1 (0x01)
0x0E カテキン使用上限 99 (0x63)
0x0F 急所率 8 (0x08)
0x10 0 (0x00)
0x11 0 (0x00)
0x12 0 (0x00)
0x13 やけど関連の値? 1 (0x01)
0x14 攻撃技を示すフラグ? 1 (0x01)
0x15 11 (0x0B)
0x16 技ID 1 (0x0001)
0x18 0 (0x00)


尚、データ終端はポインターリストまで「0xAA」で埋められているため、プログラムを書く場合はここの値でループを抜ける条件にすると良い。

技名について (text_j.str)

技名はwaza_p.binには含まれておらず、文字列がまとめられた「text_j.str」に格納されている。「MESSAGE」というディレクトリに含まれている。
このファイルの0x2F4A2以降が技名となっている為、ここの文字列を0x00で区切って各技に割り当てることで対応した技名になる。

その他

waza_p.binの他にも、「waza_p2.bin」というファイルが存在している。空のみに存在し、時闇には無い。
構造は全く同じでバイナリの値こそ異なるものの、値を展開するとwaza_p.binと同じ値になる為用途は不明。psy_command氏によるとROMから削除しても一応問題なく動くとのこと。