FF3(FC) アイテム99個バグ


§0、アイテム99個バグとは

戦闘勝利時に、99個持っているアイテムを敵が落とすと、
アイテム変化などが起こる現象のこと。
発売当時から有名だが、なぜ起こるのかを解説し、
どのようなことが可能なのかを紹介していく。
ただし、実際のプログラムを見たわけではないので、
ここでの記述は正しいとは限らないので注意。



§1、基礎知識

§1−1、戦闘中のアイテムとキャラデータ構造

所持アイテムデータはアイテムの種類、アイテムの個数の順で32個分並んでいる。
アイテムデータ後にはキャラのデータが先頭から順に並んでいる。

以下は、アイテム欄の一番左上のアイテムの種類を記録したメモリを0番地とした場合の
データの内容である。

+ 0:アイテム1の種類ID
○ 1:アイテム1の数
 (中略)
+ 62:アイテム32の種類ID
○ 63:アイテム32の数
----以下キャラ1のデータ----
+ 64:ジョブ
○ 65:レベル(データ上は表示上の値よりも一つ小さい)
+ 66:戦闘開始時の状態
○ 67:経験値、1の位
+ 68:経験値、256の位
○ 69:経験値、65536の位
 70-75:名前
+ 76:戦闘開始時のHP、1の位
○ 77:戦闘開始時のHP、256の位
+ 78:最大HP、1の位
○ 79:最大HP、256の位
+ 80:熟練度(データ上は表示上の値よりも一つ小さい)
○ 81:熟練度経験値(100貯めると熟練度がアップする)
 82-91:力、素早さ、体力、知力、精神の元と修正後の値
+ 92:弱点属性
○ 93:魔法回避回数
+ 94:魔法回避率
○ 95:魔法防御
+ 96:右手攻撃属性
○ 97:右手攻撃回数
+ 98:右手命中率
○ 99:右手攻撃力
+100:右手追加効果
○101:左手攻撃属性
+102:左手攻撃回数
○103:左手命中率
+104:左手攻撃力
○105:左手追加効果
+106:防御属性
○107:回避回数
+108:回避率
○109:防御力
+110:ステータス異常耐性
○111:用途不明。基本的に0
+112:戦闘開始時のレベル1魔法のMP
○113:レベル1魔法の最大MP
 (中略)
+126:戦闘開始時のレベル8魔法のMP
○127:レベル8魔法の最大MP
---
 128-191:キャラ2のデータ
 192-255:キャラ3のデータ
...

○はアイテムIDを参照するところで、+は値が+1される可能性があるところ。


§1−2、敵が落とすアイテムの処理

敵がアイテムを落とすと、まず、アイテム欄に同種のアイテムがないかを探す。
具体的には、アイテム欄の0番地のデータから、
落としたアイテムIDと一致するかを調べ、
一致すれば、次の番地を調べ、98以下なら+1して終了する。
一致しなければ調べる場所を+2番地にして調べる、を繰り返す。
62番地を調べても一致しなかった場合は
アイテムIDが0(空欄)のデータを0番地からから探し、
0のデータがあれば、そこに落としたアイテムのIDを書き込み、
その次の番地データ(個数)を+1して終了する。
通常は空欄の個数は0なので、空欄が落としたアイテム1個に変わることになる。
62番地を調べても0でなかった場合、そのまま終了する。
つまり、空欄が無い場合はアイテムを落とさなかったことになる。


§2 アイテム99超えバグ

アイテムを落とす処理で問題となるのは、同種のアイテムがあるが99以上ある場合で、
なぜか終了せずに、調べるを番地そのままで空欄を探す作業に移行する。
最後に調べたのは同種アイテムの個数なので、
そこから2番地おき、つまり個数が0のデータを探すことになる。

例えばアイテム欄の先頭にポーション(ID:166)が99個だけ存在するときには
データ上は以下のようになっている。

0:166/ポーション
1: 99/個数
2:  0/空欄
3:  0/個数
4:  0/空欄
5:  0/個数
...

ここでポーションをドロップすると以下のように変わる。

0:166/ポーション
1: 99/個数
2:  0/空欄
3:166/個数(+166)
4:  1/カイザーナックル(+1)
5:  0/個数
...

複数個ある空欄や0個のカイザーナックルが出現するが、
このまま戦闘終了すると、空欄の個数や、0個のアイテムは消滅するので、特に問題は起きない。
例ではポーションと空欄を並べているが、間に他のアイテムがあっても同じである。(以後の例も同様)


§2−1、カイザーナックル生成

先の状況に対して、もうひとつポーションを落とすと以下のようになる。

0:166/ポーション
1: 99/個数
2:  0/空欄
3:166/個数
4:  1/カイザーナックル
5:166/個数(+166)
6:  1/カイザーナックル(+1)
7:  0/個数
...

これによってカイザーナックルが166個生成される。
100個以上のアイテムは戦闘終了時に99個にまとめられるので、
実際にはカイザーナックルが99個が出現する。
もしも、ポーションでなく、木の矢(ID:79)の場合は、79個出現することになる。
元々アイテム欄に別のカイザーナックルが大量に存在する場合、
個数がオーバーフローして少なくなることがあるので注意。


§2−2、99個ドロップ

ちょっと状況を変えて、ポーションの後にアイテム欄に存在しない、
ボムのかけら(ID:177)を落とした場合を考えてみる。
アイテム欄に無いアイテムは、アイテム欄の一番上の空欄(ID:0)に入り、個数を加算する。

0:166/ポーション
1: 99/個数
2:177/ボムのかけら(+177)
3:167/個数(+1)
4:  1/カイザーナックル
5:  0/個数
...

これによって、ボムのかけらをいきなり99個手に入れることができる。
先に99個あるアイテムのほうを落とす必要があるので運が絡むが、
デスクローを大量に倒すことでブラックホールやリリスのくちづけを大量に入手することが可能。


§2−3、アイテム変化

ポーション99個、空欄、カイザーナックルとアイテムが並んだ状況を考える。

0:166/ポーション
1: 99/個数
2:  0/空欄
3:  0/個数
4:  1/カイザーナックル
5:  1/個数
...

この状態でポーションを落とした場合は以下のようになる。

0:166/ポーション
1: 99/個数
2:  0/空欄
3:166/個数(+166)
4:  2/猫の爪(+1)
5:  1/個数
...

このようにカイザーナックルが猫の爪に変化する。
ちょっと応用して以下のように並べれば、ポーションを2個落とした時に、
2種類のアイテムを変化させることができる。

0:166/ポーション
1: 99/個数
2:  0/空欄
3:  0/個数
4:  1/カイザーナックル
5:  1/個数
6:  0/空欄
7:  0/個数
8: 56/ラグナロク
9:  1/個数
...

§2−4 ジョブ変化

ポーション99個をアイテム欄の31番目に配置した場合を考える

...
60:166/ポーション
61: 99/個数
62:  0/空欄
63:  0/個数
---以下キャラ1のデータ---
64:  0/玉葱剣士
65:  0/レベル1
...

この状態でポーションを落とすと以下のようになる

...
60:166/ポーション
61: 99/個数
62:  0/空欄
63:166/個数(+166)
-------
64:  1/戦士(+1)
65:  0/レベル1
...

アイテム欄の次のデータである先頭キャラのジョブも影響を受ける。
ジョブIDが255の時は0の玉ねぎ剣士に戻る。
255に+1すると0にループするのは以下の処理でも同様。


§2−5 その他のキャラデータ変化

ポーション99個をアイテム欄の32番目に配置した場合を考える
ここでポーションを落とすと、65番地から検索が開始される。

...
62:166/ポーション
63: 99/個数
-------
64:  0/玉ねぎ剣士
65:  0/レベル1
66:  0/戦闘開始時ステータス異常:なし
...

上記例の場合は65番地が0(レベルが1)なので、以下のようにレベルが変化する。

...
62:166/ポーション
63: 99/個数
-------
64:  0/玉ねぎ剣士
65:166/レベル167(+166)
66:  1/戦闘開始時ステータス異常(+1)
...

戦闘開始時ステータス異常も変化するが、戦闘終了時に書き換えられるので影響はない。
元々のレベルが1(65番地が0)でない場合は次の67番地(経験値の1の位)が0か調べ、
そこが0でない(具体的には、経験値が256の倍数でない)場合は、69番地(経験値の65536の位)
を調べる。

...
62:166/ポーション
63: 99/個数
-------
64:  0/玉ねぎ剣士
65:  1/レベル2
66:  0/戦闘開始時ステータス異常なし
67: 16/経験値 16+166*65536
68:  0/
69:166/(+166)
70:203/名前1文字目「イ」(+1)
...

上のように大量の経験値が入り、名前の一文字目が変化する。
ただし、経験値が256の倍数の時は、以下のように変化する。

...
63:166/ポーション
64: 99/個数
-------
 1:  1/戦士
 2:  3/レベル4
 3:  0/戦闘開始時ステータス異常なし
 4:166/経験値 166+256*2 (+166)
 5:  2/(+1)
 6:  0/
...

元々の経験値が256の倍数でもなく、かつ65536以上の場合は、
次は戦闘開始時のHPの256の位が0ならば、そこにアイテムIDが入り、最大HPが1増える。
戦闘開始時のHPのデータそのものは戦闘終了後に残らない。

このように、データの奇数番目が0となる最初データにアイテムIDが入り、
次の偶数番地の値が+1されることになる。


§2−6 ループとフリーズ

1番目のキャラの奇数番地に0が無ければ、2番目のキャラから、そこにも無ければ3番目になる。
もしも255番地(3番目の最大MP)が0の場合、+1されるのは、256番地(4番目のジョブ)
ではなく、頭に戻って0番地(アイテム1の種類)になる。
3番目のキャラの奇数番地も0が無ければ、アイテム欄の頭から個数が0のものを探すことになる。
そしてアイテム欄にも0が無ければ処理が延々とループしてフリーズしてしまう。


§3 まとめ

アイテム99個バグで可能なことは以下の通り。

・アイテム変化(ID+1)
・大量のカイザーナックル生成(空欄→アイテムID個)
・99個ドロップ
・ジョブ変化(+1)
・レベル大アップ(1→アイテムID+1)
・経験値中アップ(+256+アイテムID)
・経験値大アップ(+65536*アイテムID)&名前変化(+1)
・最大HPアップ(+1)
・最大HP大アップ(+256*アイテムID) & 熟練度アップ(+1)
・熟練度経験値大アップ(0→アイテムID)& 力アップ(+1)
・最大MP大アップ(0→アイテムID)

+1の部分は256になると0に戻る。
キャラデータで変更できるのは3人目まで。

ドロップアイテムで一番IDが大きいのはリリスの口づけ(ID:190)なので、
この方法で可能なのは最大HPは48895(255+190*256)、最大MPは190になる。

あと、アイテムを沢山落とした時にフリーズすることがあるので注意。