読者です 読者をやめる 読者になる 読者になる

FF4DS のお客様にご迷惑をおかけする「現象」

DS 版の Final Fantasy IV で2件の「現象」が見つかっているという案内が出ています

一件目は、2週目以降においてイベント回想モードで「未来へのプロローグ」(エンディングの一場面)を観てしまうと、その後、本物のエンディングの途中で先に進まなくなるというもの。閲覧状態でセーブしてしまうと回避方法がなくなります。

二件目は、途中までゲームを進め、飛空挺を地底に置いた状態で、メニューからタイトルに戻る or 戦闘で全滅してタイトルに戻り、ニューゲームを選んでプレイを開始すると、飛空挺入手時におかしなことが起こり、ゲームが進行できなくなるというもの。

アナウンスに「不具合」という単語が全く出てこないのが微笑ましいというか、そんなところで小手先にサポートの対応コストを削ろうとするよりも、評判へのダメージのほうに気を遣った方がいいんじゃないかと他人事ながら心配になったりするわけですが、まぁ、それはそれとして現象だけから原因を探ってみようかな、と。

不具合内容の推測

完全に現象からの推測でしかないのですが、どうみても2件ともフラグ管理の不具合ですよね。

一件目は、イベント回想モードの実装時に、本当のイベントと回想モードでスクリプトを共有するように実装した場合にありがちなやつです。回想モードの場合のみ特別なフラグを立てておいて、回想終了でフラグを見てシーン選択に戻るように分岐させる、という実装で起こる典型的な不具合かと。本来ならば、回想終了時に回想フラグを寝かせないといけないはずが、寝かせ忘れてしまい、本物のエンディングの最中に回想フラグが立っているので途中で中断してしまった、というパターンだと思われます。

(追記)不具合の再現動画を見てみましたが、エンディングの該当シーンから出るところではなくて、入るところで不具合が発生するんですね。うーん。もっと何か人知を越えるミラクルな不具合な気もします……。間違えて、隣のシーンの回想フラグも一緒に立ててしまっていたとか。万が一、メモリ破壊系の不具合だと、モデル検査じゃ見つけられないんですよね……。

二件目は、これは典型的な初期化忘れの不具合でしょう。おそらく、飛空挺の場所は、地上か地底かというフラグと、座標値の組み合わせで管理されていたんでしょうね。で、地上か地底かというフラグが、ニューゲームの開始時にも、最初に飛空挺を入手する時にも、明示的に地上で初期化をすることを忘れていた、と。普段はたまたま電源投入時の0クリアでうまく動いていたものの、フラグが地底になっていた状態でニューゲームをした際におかしなことになったのでしょう。

何が問題だったのか

両者ともに、よほど嗅覚が優れたデバッグスタッフに当たらない限りは、ブラックボックステストで見つけるのは困難でしょう。スクリプトの内部実装をわかっていないと、外から見ただけでは事象の因果関係がわかりませんので。これをデバッグ工程で見つけられなかったのは仕方がなかったことかと思います。

一方、実装者の観点から見ると、突っ込みどころは多いわけですが……。まず、セーブデータに保存するべきグローバルなフラグと、電源断で消えるローカルなフラグの区別がきちんとされていなかったと思われる点。どう考えても、回想モードのフラグはローカルなフラグとして管理されるはずのもの*1です。できるだけセーブデータに保存されてしまうフラグの数を減らして、今回のような妙な状態が発生するリスクを低減するのは、わりと基本だと思っておりました。

また、ニューゲームでの開始時にフラグをまとめてクリアするのではなく、個別にクリアしていたと思われる点も突っ込みどころでしょう。普通は、今回のような初期化忘れで妙な状態が発生しないように、まとめてクリアするように実装しておくものだと思うのですが……。今回のように引継ぎ要素があったりするとややこしいんですが、そういう時は引継ぎ要素の領域だけを特別扱いするのが本筋かと。そもそも、飛空挺入手時のスクリプトで、飛空挺の新しい座標を指定しているのに、地上か地底かを明示的に設定するのを忘れているのが不自然なんですよね……。よっぽど、ケイオティックなフラグ管理になっていたんでしょうか。

デバッグコストを考えた際に、できるだけ妙なステートを永続化させない、というのはプログラミングの基本です。グローバル変数よりもローカル変数を使うべきですし、1ステージが終わればその間に動的に確保したメモリは一括して開放すべきです。スクリプトを組む際にも同じ原則を普通は適用するはずなのですが、どうも今回はそれがうまく行っていなかったことが伺われますね。

そこでモデル検査!(笑)

こんなとき、もしもデバッグの一環として、シナリオスクリプトに対してモデル検査を適用していれば、今回の不具合は(うまくモデル化できていれば)2件とも事前に見つかっていたことでしょう。人間が見落としたグローバルフラグの寝かし忘れの検出なんて、モデル検査がもっとも得意とするところです。今回の件は、モデル検査で検出可能な不具合の良い事例かもしれませんね(^^;

というわけで、ゲームシナリオにモデル検査を適用する研究をされている皆さま*2、がんばりましょう!

*1:シーンをまたいだフラグの保持は、グローバルなものでしかできなかった、という可能性はありますが……。それはそれでありがちな仕様。

*2:といっても、自分を除くと2名しか存じないわけですが(笑)