2017年12月20日

【Papyrus.psc】初回/毎回ロード時に実行する

- Papyrusスクリプトの記憶を記録に残すシリーズその6 -

MOD導入後、初回だけ実行して魔法を覚えさせたいときなどの方法です。関連して、毎回ロード時に実行する方法もご紹介します。


目次

  1. 初回ロード時だけ実行する
  2. 毎回ロード時に実行する

1. 初回ロード時だけ実行する

1-1. クエストの作成

ロード時にスクリプトを発動させるためには、クエストを新規で作成して使います。
Object Window の Character > Quest を開き、右クリックして「New」を選択すると新規クエストを作成できます。

IDを入力し、「Start Game Enabled」と「Run Once」をチェックします。Typeには「Miscellaneous」を指定します。
そして一旦「OK」を押して確定します。これをしないとクエストの大枠がきちんと作成されないようで、そのままスクリプトを付けようとするとCKが落ちます。
クエストを開きなおすと、次のようにタブがいくつか追加されているはずです。

1-2. クエストにスクリプトを付ける

作成したクエストの Scripts タブを開きます。「Add」ボタンを押して新しくスクリプトを作成するのですが、Extends のところを「Quest」にします。もし空欄になっていたら書き込んでから「OK」してください。

スクリプトのコードは以下のようにします。

Scriptname EkaFirstTimeScript extends Quest

Bool booInit

Event OnInit()
    Utility.Wait(0.1)
    If booInit == true
        Return
    Else
        booInit = true
        Debug.MessageBox("初回用スクリプトを実行しました。")
    EndIf
EndEvent

Scripts タブに下図のようにスクリプトを付けられたら完成です。

これで初回ロードのときだけメッセージボックスを出すようになりました。必要に応じてその部分を改変してお使いください。

1-3. 分岐の補足説明

上記スクリプトでは、OnInit イベントの仕様への対策としてBool変数を使った分岐をしています。OnInit イベントは何故か同時に2回イベントを発動させることがあります。もしかしたら確実に実行させるための仕様なのかもしれませんが、メッセージボックスのように2回出て欲しくないこともあるので対策が必要です。

ポイントは「Utility.Wait」です。Papyrusに限らず、スクリプトのウェイトコマンドというのはわずかに誤差が生じます。OnInit イベントで同時に2つ発動した処理のタイミングを、ウェイトの部分でずらしているのです。
Bool変数は初期値が false ですから、先に If の Else 分岐に入った方がBool変数を true に書き換え、後から If に到達した方は Return の分岐に入って何も実行されません。

ちなみにこの2回同時発動は、スカイリムを起動して最初にセーブデータをロードしたときに良く起こります。2回発動する条件について確実な再現性が得られていないのですが、Bool変数を使って分岐していれば今のところ正常な動きをしてくれているので上記の方法をとっています。

目次に戻る


2. 毎回ロード時に実行する

2-1. クエストの作成

セーブデータをロードするたびに毎回実行される方法です。先ほどと同様にクエストを新規で作成します。

IDにクエスト名「EkaEveryTime」を入れ、「Start Game Enabled」をチェックします。Typeには「Miscellaneous」を指定します。そして一旦「OK」して確定します。

2-2. クエストにスクリプトを付ける

作成したクエストの Scripts タブを開き、「Add」ボタンを押して新しくスクリプトを作成します。スクリプト名は「EkaEveryTimeScript」にしました。Extends のところは「Quest」にします。

スクリプトのコードは以下のようにします。

Scriptname EkaEveryTimeScript extends Quest

Bool booInit

;--------------------------------------------------初回ロード用
Event OnInit()
    Utility.Wait(0.1)
    If booInit == true
        Return
    Else
        booInit = true
        Load()
    EndIf
EndEvent

;--------------------------------------------------実行する内容
Function Load()
    Debug.MessageBox("毎回用スクリプトを実行しました。")
EndFunction

ここでは初回ロード用の OnInit を記述し、実行する内容を Function という関数部分に書いています。
Function ~ EndFunction の外から Load() と記述することで、その内容が実行されます。「Load」が関数の名前で、既存の関数名でなければ自由に付けられます。

Scripts タブはこれでOKです。さらに追加設定をしていきます。

2-3. クエストのエイリアスの設定

クエストにスクリプトを付けただけでは、毎回ロード時にそのスクリプトを実行することができません。
Quest Aliases タブに移動し、右クリックして「New Reference Alias」を選択します。

Reference Alias ダイアログが開きますので、次のように設定します。

Alias には適当に名前を付けます。Fill Type は「Unique Actor」から「Player」を選択します。
そして Scripts の「Add」ボタンを押して新しくスクリプトを付けます。スクリプト名は「EkaEveryAliasScript」にしました。Extends は「Alias」にしてください。

コードは以下のようにします。

Scriptname EkaEveryAliasScript extends Alias

EkaEveryTimeScript Property QuestScript Auto

Event OnPlayerLoadGame()
    QuestScript.Load()
EndEvent

スクリプト名やプロパティ名がいくつか出てきて混乱しそうになりますが、間違えないようにしましょう。
プロパティにはクエスト本体を指定しますが、上記の通りにしていれば「EkaEveryTime」しか選択できませんので大丈夫でしょう。

スクリプトが設定できれば次のようになっているはずです。

確定して「Quest Aliases」が設定できていれば完成です。

あとはクエストに付けたスクリプト「EkaEveryTimeScript」の Function Load() 内にやりたい事を書き込めばOKです。

毎回ロード時に実行する方法は設定がやや複雑ですね。ほぼコピペで作成したほうが楽かもしれません。

目次に戻る


【Papyrus.psc】シリーズリスト

補足:私はスクリプトを書くのは好きですが、専門家ではありません。内容は creationkit.com の情報と個人的な経験を基にして書いています。どうかご参考程度にご覧ください。


0 件のコメント:

コメントを投稿

注: コメントを投稿できるのは、このブログのメンバーだけです。