データが読み込まれる仕組み
ゲームを起動すると、まずプラグインが読み込まれ、続いてセーブデータが読み込まれ、ゲームをプレイする準備が整います。
ここでもう一度セーブデータをロードすると、ゲームの進捗状況がセーブデータに保存されている状態に戻ります。セーブデータからデータを取り出して展開するので、そうなるわけです。
ところが、セーブデータに保存される内容はすべてではありません。一部の情報は保存されません。保存されないということは、プラグインの情報のままになります。
具体的な例で説明
SkyrimのYASHが実装している方法として、本の重さを例に説明します。
本の情報はプラグインにあります。本の名前や内容、価格、重さ、場所などがあります。プレイヤーが本を入手し、自宅の机の上に置いたとします。この机の上に置いたという位置情報はセーブデータに保存されます。ですので、本をどこかに持ち去っても、セーブデータをロードすると、本は机の上に戻るわけです。
本の重さが1になっているとします。初回ロード直後は1です。そのあと、スクリプトで重さを2に変更したとします。この重さの情報はセーブデータに保存されません。ですので、セーブデータをロードしても重さは2のままです。
これは、メモリ内に展開されている情報が、セーブデータをロードすることで上書きされて巻き戻るのですが、セーブデータにない情報はそのままになるからです。スクリプトで重さを変更したことはそのままになってしまうわけです。
Fallout 4を再起動すると、メモリが完全に初期化されますので、本の情報は再びプラグインから読み込まれてメモリに展開されます。重さは1です。そしてセーブデータの情報によって、机の上に置かれます。場所だけが復元されるわけです。
これをうまく利用すると、初回ロードを検知できます。
実装例
まずプラグインでダミーの本を用意します。重さを1にしておきます。
スクリプトでOnPlayerLoadGameイベントを捕捉するようにしておきます。
OnPlayerLoadGameイベントが発火したら、本の重さを調べます。重さが1なら初回ロードです。そして重さを2に変更します。
セーブデータをロードすると、再びOnPlayerLoadGameイベントが発火しますが、本の重さは2になっています。これで2回目以降のロードを検知できます。
活用例
活用例としては、Actorの顔が黒くなるバグを修正するRusty Face Fixがあります。初回ロードでは問題ないのに、2回目以降のロードで顔が黒くなることがあるので、周囲のActorに修正用スクリプトを配布して直します。この処理は初回ロードでは無駄なので、省略するようにするといいでしょう。
RustyFaceFixScript.psc (papyrus)
; ダミーの本を用意して紐づけしておく
; 重さは1にすること
Book Property DummyBook Auto Const
Function LoadGameEvent()
; 重さが1なら初回ロード
if DummyBook.GetWeight() == 1
; スクリプト配布処理を停止する
Player.RemoveSpell(RFFCloakSpell)
Self.ClearDistanceMarker()
; 2回目以降のロードに備えて重さを2にしておく
DummyBook.SetWeight(2)
return
endif
; (以下略)
EndFunction