ドラゴンクエストIVの「8逃げバグ」の話題が掘り返される 119
ストーリー by nagazou
なんと 部門より
なんと 部門より
ファミコン版のドラクエIVで「にげる」コマンドを8回選択すると、以後の攻撃が「かいしんのいちげき」になる「8逃げ」と呼ばれるバグ技が存在するが、元クライマックス代表の内藤寬氏が、自身のYouTubeチャンネル上でその理由を公開したそうだ。同氏はドラクエIVでチーフプログラマーを務めていた(内藤かんチャン[動画]、ファミ通.com、Togetter)。
同氏は動画中で同じくドラクエのプログラムを手掛けた山名学氏に電話を掛けて直接質問。ドラクエIVでは4回目の「にげる」で必ず逃げられることから、「それ以上逃げられることを想定していなかった」という。当時のドラクエでは専用カウンターがなく、2進数で選択回数をカウントしていたのだが、2進数で3桁であれば最大「111」までカウントできるようになっていたそうだ。
しかし、ボス戦で逃げられない戦闘の時に「にげる」を8回行うとと、カウンターが「1000」に達して4桁目になり、その位置にはパルプンテ用の「かいしんのいちげき」カウンターが設定されていたことから、必ず「かいしんのいちげき」が出てしまっていたそうだ。
あるAnonymous Coward 曰く、
同氏は動画中で同じくドラクエのプログラムを手掛けた山名学氏に電話を掛けて直接質問。ドラクエIVでは4回目の「にげる」で必ず逃げられることから、「それ以上逃げられることを想定していなかった」という。当時のドラクエでは専用カウンターがなく、2進数で選択回数をカウントしていたのだが、2進数で3桁であれば最大「111」までカウントできるようになっていたそうだ。
しかし、ボス戦で逃げられない戦闘の時に「にげる」を8回行うとと、カウンターが「1000」に達して4桁目になり、その位置にはパルプンテ用の「かいしんのいちげき」カウンターが設定されていたことから、必ず「かいしんのいちげき」が出てしまっていたそうだ。
あるAnonymous Coward 曰く、
DQ4にげ8バグについて、あの人を直撃! — YouTube
https://www.youtube.com/watch?v=N1HYWuOewjI
ドラクエ4で「にげる」8回でずっと会心の一撃になるバグ、こういう仕組みで起こってたらしい「そうだったのか!」「これは有益」 — Togetter
https://togetter.com/li/1715732
8逃げとは (ハチニゲとは) [単語記事] — ニコニコ大百科
https://dic.nicovideo.jp/a/8%E9%80%83%E3%81%92
ガッキーの結婚の話かと (スコア:3, おもしろおかしい)
それは逃げ8
Re: (スコア:0)
ガッキーどころか、一般人女性との結婚フラグすら立たない致命的なバグが…
Re:ガッキーの結婚の話かと (スコア:1)
会心フラグはたまたま8回で立てられる位置にあったけど
ふしぎなきりがあたりをつつむフラグを立てようと思ったら128回逃げる必要がある
Re:ガッキーの結婚の話かと (スコア:1)
8回逃げられたら、以後の相手の攻撃が「つうこんのいちげき」になるバグが存在しています。
Re:ガッキーの結婚の話かと (スコア:1)
Re: (スコア:0)
# それはDQ4じゃなくてDQ5
バーン「知らなかったのか…? 大魔王からは逃げられない…」 (スコア:2, おもしろおかしい)
Re:バーン「知らなかったのか…? 大魔王からは逃げられない…」 (スコア:1)
ポップも8回逃げたら会心の一撃連発になったんだろうか
×バグ → 〇裏技 (スコア:1)
「バグ」と呼ぶとマイナスイメージですが、「裏技」と呼ぶことでご褒美要素のように言い換えてプラスイメージに転換するというファミコン時代の大人の知恵です
エンドレスエイト (スコア:0)
同じストーリーも8回繰り返すと、カウンターの桁が上がって別のフラグが立つということですね
ノリが組み込みソフトウェア (スコア:0)
昔は大変だったんだなあとしみじみおもう。
Re:ノリが組み込みソフトウェア (スコア:1)
最近だったら、逃走回数カウントするのに、
特に気にせずにint変数とか使っちゃいそうだよねぇ……
FC時代のバグや裏技には、
こういうギリギリの節約のせいで生まれたものも多いはず。
Re:ノリが組み込みソフトウェア (スコア:1)
マイナスはあり得ないとか言ってunsigned intか、微妙にケチってunsigned charとかにしそう。
がっつりけちると共用体でビットフィールドかなぁ。
値範囲チェックを入れたクラスにしてSet/Getで使うのが今時流か?
Re: (スコア:0)
ただのフラグなのにintとかも。
Re: (スコア:0)
最近は8bit型ですね。
さすがに32bit型はやりすぎでした。
Re: (スコア:0)
当時のファミマガには具体的な枚数が伏せられてましたけど、
1回の購入枚数を上げていくと計算合わなくなるのでピンとくるんですよね。
[]_g@
Re: (スコア:0)
あのバグのせいでカジノは楽しめなかったような
Re: (スコア:0)
当時はオーバーフロー防止のための条件文すらメモリの無駄だったのですね
if (cnt!= max) cnt++;
Re: (スコア:0)
>ドラクエIVでは4回目の「にげる」で必ず逃げられる
むしろ疑うべきはこちらでは?
プログラミングの初歩で学んでおきたいバグ (スコア:0)
でも最近の環境でこのようなバグが発生することは少ないのかしら?
# FORTRANでメモリの利用領域を適当に拡縮させてフラグ調整してた程度の経験しかないのでAC
Re:プログラミングの初歩で学んでおきたいバグ (スコア:2)
逆に8ビット時代はスタックで引数送ったり、ましてや変数を置くなんてできなかったけど(再帰なんかまたのまた夢)、今はローカルのバッファを行きすぎてスタック飛ばすのがよくあったりするわけで。
Re:プログラミングの初歩で学んでおきたいバグ (スコア:1)
// とかいいつつバッファオーバーランでいろいろやらかすのもまた乙
Re: (スコア:0)
32-bitや64-bitのカウンタでオーバーフロー起こすことはあまりないけど(と油断するからバグるのだが)
ビットシフトだとやりがち。
厄介なのは、意図的にオーバーフローさせて上位ビットを0や1に固定するイディオムもあるので、
意図的なのかバグなのか見た目では判断しづらいところ。
Re: (スコア:0)
32bitカウンタなんて100Mhzクロックで回したら
1分しないでオーバーフローを起こすけどね。
Re:プログラミングの初歩で学んでおきたいバグ (スコア:1)
この前、株価が32bitの最大値を超えて問題になった記事がありましたね。
Re: (スコア:0)
メモリがとにかく無かった時代のプログラム手法で、8ビットのカウンター用ワークで使わないビットをフラグビットとして使うなんて今はしないよね。
それと今は変にフラグ管理するとデータベースとの相性が悪いっていうのもあるので、昔ほど必須のテクニックでは無いような気がする。
まあそうだろうなと (スコア:0)
30年の時を経て当事者が直接語るというのは感慨深いが、
話の中身自体は特に何か当事者にしか知り得ない興味深い事情とか裏話があるわけではなく、
現象(8回なにかすると別のフラグが立つ)から容易に想像がつく、フットプリントできるだけ小さくするための
実装上の制約以上のものではなかったですね。
しかし逃げるコマンドの回数をカウントしなきゃいけない理由がわからない。
雑魚敵に対して
>>ドラクエIVでは4回目の「にげる」で必ず逃げられる
という仕様は限られたメモリ空間を3bitも消費する価値があるほど重要だったのだろうか。
一回あたりの逃げ成功確立を適当に設定しておけば十分な気が。
あと「4回試行でかならず成功」を実装するだけならカウンタは2bitで十分な気が。
Re: (スコア:0)
> あと「4回試行でかならず成功」を実装するだけならカウンタは2bitで十分な気が。
ニコニコ大百科の記事によると、逃げる回数のカウンタは下位2ビットで、下から3ビット目は「時の砂を使用したかどうか」のフラグのようですね。
Re: (スコア:0)
単純に加算で実装していたから逃げ続けると2ビットをオーバーして3ビット目4ビット目までどんどん立っちゃうって話じゃないの?
Re: (スコア:0)
2bitの逃げるカウンタと会心フラグの間に他のフラグがある事も容易に想像がつくはずですが?
Re: (スコア:0)
>2bitの逃げるカウンタと会心フラグの間に他のフラグがある事も容易に想像がつくはずですが?
ああそのとおりですね、4回目以降8回目までにも別フラグが立つことによる副作用がありえたわけですね、
会心の一撃フラグがあまりに強烈なので8回という数字が際立っただけで。
逃げ続けると他のフラグもたって何かべつのことが起きてるのだろうか。
Re:まあそうだろうなと (スコア:1)
まあ、ストーリーの元になった記事からして「逃げるカウンタが3bit」って間違えちゃってますので、しかたないですけど、
下位から順番に
1~2: 逃げ回数(通常の戦闘は 11 = 3回逃げた時は確実に逃げられるはずなので、2bitで十分)
3: 時の砂使用済(戦闘状態の保存処理を0の場合のみ行うことで、使った時の状態に差し戻せるようにする)
4: パルプンテの結果が「ちからがみなぎってきた」だった(すべての攻撃が会心の一撃になる)
5: 敵を倒した(1体でも倒したら戦闘終了時のメッセージが「○○をやっつけた」になり、1体も倒せなかった時は「○○はいなくなった」に)
6: 不明
7: 敵が複数種類かどうか(戦闘終了時の「○○(モンスター名)をやっつけた」が、「まもののむれ」表記になる)
8: 不思議な霧状態かどうか(該当時は敵味方全員呪文の効果がなくなる)
と、戦闘中の状態をbitフラグで管理しています。
たくさん逃げ続ければ他の状態も変更可能ですが、戦闘中に使って意味ありそうなのはあとは8bit目ぐらいでしょうか。
また、3bit目は時の砂フラグなので「時の砂を使う+4回逃げる」でも8逃げ可能。
Re:まあそうだろうなと (スコア:1)
すみません、なんか勘違いしてました。
戦闘中に2回以上時の砂が使われることはないので、
時の砂を使って巻き戻した後は、もう巻き戻すことはないから状態保存は不要
ってことで負荷軽減のためらしいですね。
涙ぐましすぎる…
Re: (スコア:0)
6502の命令調べてみないとだけど、bit testでjnzするほうが命令数少なそう。
Re: (スコア:0)
するためには回数をカウントする必要がある
成功率そのものが逃げるたびにだんんだん上がっていって4回目で100%に到達という仕様
Re: (スコア:0)
0回、1回、2回、
3回目のインクリメントで4以下の数字をランダムで求める。
4の場合は逃げられる。それ以外は2以下の数を書き込む。
必ず成功しなくなる。
ビット制約があり正しい作りなならこういう作りかな?
Re: (スコア:0)
ファミコンではその「ランダム」も曲者っていう印象だけど
一つの乱数を共用している場合「4」までしか発生しない(乱数に制限を設ける)ということができないように思う
「逃げている」とかをフラグ管理しようと思ったら、メモリ等の制約上それはそれで難しそうだし
Re: (スコア:0)
あのあたりの実装だと、1バイトの乱数を線形合同法で回してるぐらいじゃないかな。
4まで欲しければ2bit取ればいい。
綺麗な乱数ではないから、使い方を誤ると悲劇が起こる [srad.jp]
Re:まあそうだろうなと (スコア:2)
メモリをケチった状況での乱数といえばドルアーガの塔。
全60面ありますが、面番号を種とした8bit乱数を使ってアルゴリズム生成した迷路なので、マップデータはゼロ。
FLOOR 60 だけは面番号ではなく255を種にしていて、その結果乱数が「オール1になる」という偏りが発生し、
「生成した壁が必ず左方向に伸びていく」ので、横線だけという最終面にふさわしい乱数感のないマップのできあがり。
乱数の偏りを逆手に取った面白いアイデアと思いました。
それならば (スコア:0)
32回とか512回とか逃げるを選べば別のフラグが立つ?
Re: (スコア:0)
togetterの方ではそう解説されてる。
というか4逃げの段階でも既に時の砂フラグが立ってるそうな。
時の砂併用すれば8回以下ん9逃走で会心の一撃出せる、とも。
ビットパッキングの順番って重要ですね (スコア:0)
これが「痛恨の一撃」になるバグだったら誰も取り上げなかったのに。
ちょっと疑問なんだが (スコア:0)
会心の一撃フラグが立つ理由は判ったけど、戦闘1ターン毎にフラグって
初期化してないのかね。
なんでず~っと会心になるんだろ?
Re:ちょっと疑問なんだが (スコア:1)
その戦闘中ずっと会心の一撃が出るようになるというパルプンテの効果だから、としか言えません。
にげるに失敗しているので戦闘も終わっておらず、初期化する理由がありません。
Re: (スコア:0)
パルプンテ用のフラグなわけだから、パルプンテ唱えたときだけ初期化するんじゃないの
パルプンテ唱えてないときにもいちいち初期化するのは無駄だろう
Re: (スコア:0)
みなぎってきたら1ターンでは治まらないでしょう?
「話題が掘り返される(拡散する)」 (スコア:0)
何か新事実があったわけでもなく、まんまだったと。
Re: (スコア:0)
昔からだけど、早まった最適化をする人が多すぎる印象。
最適化沼にハマっていくための通過儀礼なのかもしれない。
# とりあえずベンチマークを取れ、プロファイリングをしろ
Re: (スコア:0)
昔のゲームを今のハードで実行するなら、そりゃ楽だろうけど。
今のゲームも、要求が高いだけに高速化とか通信とか、結構大変かと思うよ。
黎明期は何をしても新しいとなるけどある程度成熟してくるとその中から
新たなものを発見するのは難易度が高いよ、これは愚痴ですが。
Re: (スコア:0)
時代は移り変わり、メモリアクセスを減らすのが高速化のための工夫の時代