おばちゃんのスカイリムガイド

2016/02/29

スカイリムのUIの話

今日はスカイリムのUIについて、制作中につまづいたことや失敗したこと、基本的な作り方の手順についてなど、ささやかですが今まで試行錯誤したことを書きたいと思います。
スカイリムのUIはFlashという有料のソフトで作られているせいか、海外のサイトでも制作に関する情報がほとんどありません。SkyUIのHUDウィジェットみたいにメジャーなものですら、作り方については何の解説もなく、ソースを見て察しろ、みたいな状態です。(私の探し方が下手なだけかもしれませんが)
ゲーム中で使われているUIのFlashファイル自体はかなり昔から出回っていましたが、それをどのように改造したらよいのか、CK wikiのような公式の解説があるわけでもなく、またモーション制作のように有志のチュートリアルのようなものもついぞ見たことがありません。
ン十万もする3Dソフトのモーション作成講座はあるのに、なんでFlashのスカイリムUI作成講座はないんだろうかと思いますが……まあ、Flashなんて四年前から完全に終わってましたからね。
…というか今ではもう、Flashという製品の名称自体が終了してしまいました(合掌)
ところでFallout4も、HUDmenu.swfとかfont_en.swfなんていう馴染みのあるファイル名を見かけるってことは、やっぱりまたUI作成のミドルウェアはScaleformなんでしょうか。
だとしたらFallout4のUI制作もイバラの道になりそうですね。

スタート画面のFlashをセーブ名が見えるように改造してみました。
適当に作ったものですが使ってみたい方がいらっしゃいましたらどうぞ。(startmenu.swf)

セーブ名の表示ってFlashのスクリプトで20字以上(表示は17字)が切り捨てられているんです。
何を以って20字なのかは謎ですが……日本語だと全然読めないですよね。

ちなみにフリーソフトで作ったFlashファイルでも、ゲーム画面上に表示すること自体は、アドビの正規品のFlashと同様、問題なくできます。(↓これは「ParaFla」というフリーソフトで作りました)

ただ、このParaFlaというフリーソフトですと、インスタンスのフレームにスクリプトを直付けすることしかできませんので、ゲームのシステムとデータをやりとりするようなUIを作るのは無理っぽいです。
(フリーでもFlashDevelopなら作れそうですが、いまどきAS2.0の環境って構築できるのだろうか…)
でも、MCMメニューの表紙とか、SS撮影用のプリクラの枠とか、表示オンリーのものだったらこれでも充分作れますんで、ご興味のある方はぜひ試してみてください。
Flashのファイルをゲームの画面上に表示させること自体は、意外に簡単です。

ちなみにFlashファイルに画像ファイルを含める場合は「PNG」形式で(JPEGはダメっぽい)、画像は「圧縮しない」という設定にしておかないとスカイリムのゲーム画面上では表示されないです。
正規のAdobe Flashだったら、ライブラリの画像のプロパティの圧縮設定をロスレス(PNG/GIF)にしておく必要があります(最初はこれを知らんかったので、結構悩みました)。
「ParaFla」の画面。PNGファイルの透過の部分もちゃんとキリ抜いた状態で表示されます。

作成したFlashファイルをゲーム上に呼び出すには、SKSEの「UI」スクリプトを使います。
Flashファイルを表示するのに一番簡単な方法は、SKSEの「カスタムメニュー(CustomMenu)」としてFlashファイルをゲーム画面上に呼び出す方法です。
ただし「カスタムメニュー」としてFlashファイルを読み込むと、Flashファイルが表示されている間はゲーム中の動作は一時停止してしまい、操作入力系はFlash上に移ってしまいます。
(本や手紙を開いた時や、ロックピックの開錠中のような感じになります)

【Flashファイルをカスタムメニューとして表示するスクリプトの記述例】
たとえば作成したFlashファイルが「test.swf」という名前で、Dataフォルダ以下の「Interface/exported/obachan」というフォルダに置いてあった場合、そのFlashファイルを表示するスクリプトはこうなります。
UI.OpenCustomMenu("exported/obachan/test", 0)
パスはInterfaceフォルダをルートとして、Flashファイルの位置を指定します(拡張子のswfはいらない)
ちなみに「カスタムメニュー」を閉じる時は、
UI.CloseCustomMenu()
になります。(※カスタムメニューは同時に複数開けないものなので、閉じる時は引数は無いです)
ただし前述した通り、カスタムメニューを開いてる最中はプレイヤーの操作などはできなくなりますので、カスタムメニューを閉じるスクリプトは、プレイヤーの操作やゲームの進行に依存しないものに付けておかないと、カスタムメニューの画面から元のゲーム画面に戻れなくなってしまいます。
もっとも「カスタムメニュー」として使われるようなFlashは、Flashのコンテンツ内に「キャンセル」や「戻る」ボタンなどを用意してメニューから抜けるしくみを付けてあるのが一般的です。
ただ、それはFlash側にスクリプト(ActionScript)を付けないとできないことなので……スクリプト無しのPalaFlaで作ったFlashなどをカスタムメニューとして使う場合は、Papyrusスクリプト側で予めホットキーなどを用意しておいてメニューを閉じるようにするしかないと思います。

ところで私はこの「カスタムメニュー」の、ゲーム中の動作が止まってしまう仕様を、鍛冶や錬金のクラフト中やNPCとのダイアログ中などのように周囲の時間や動作を止めないで表示させる方法はないものかしら、と前々から思っているのですが、どうしたらよいのかさっぱりわかりません。
SkyUIのバージョン5でクラフト系のメニューが追加された際に、ソースをいろいろ見てみたのですが、Flash側の方にはそれらしき記述は見当たらないんですよね。
ゲーム中の動作を止めないで独自のカスタムメニューが作れたら、オブリビオンであったNPCの好感度を上げるミニゲームとか、マイクラみたいな釣りModとか、ゲーム内の動きとUIを連動させた面白いModがいろいろ作れるのになあ、と思うんですけど……私には手の届かない領域のようでとても残念です。


ちなみにゲーム中の進行を止めずにFlashファイルを画面上に表示させたい場合は、現状、私の知る限りでは、HUDメニューのFlashの中に読み込んでHUDの一部として表示させる方法しかありません。
HUDメニューはプレイヤーの状態や対象の情報などを視覚的に知らせるためのUI、いわゆるヘッドアップディスプレイ(HUD)のことですが、スカイリムでは体力やマジカのバーや、コンパス、クロスヘア(照準)のアイコン、クエスト開始の文字エリアなど、様々なパーツを含んだ一つのファイルになっています。
「HUDメニュー」のFlashソースファイル「hudmenu.fla」。
このHUDメニュー内にあるパーツ類は、他のUI画面が表示される時にも、一時的に見えなくなるだけで、ゲーム起動中はずっと画面上に存在し続けているようです。
このHUDメニューの中に自作のFlashファイルを読み込めば、ゲームの操作や進行を止めることなく、HUDの一部として好きな時に表示させられます。
ただしHUDメニュー内では、プレイヤーからの入力を受け付けるものは作れないようです。
試しに文字入力用のテキストフィールドを作って、SKSEの「AllowTextInput」という命令をFlash側につけてキー入力ができるようになるかどうか試してみたんですが、カスタムメニュー内では動くのに、HUDメニュー内ではうまく動きませんでした。
HUDメニュー上でも、カスタムメニューのようにマウスやキーボードの操作系をFlash上に持ってくることができれば、前述したような、「ゲームの動作を止めずにFlash側で操作系のあるメニューを開く」という状態が実現するのですが……私にはどうしたらいいのか、さっぱり見当もつかなくて、お手上げです。


ちなみにこのHUDメニュー上にFlashファイルを読み込む方法なんですが、SkyUIのHUDウィジェットとして表示させるのが一番てっとり早くて簡単です。
SkyUIに頼らずFlashファイルを自力でHUDに組み込むこともできますが、そうする場合は、HUDメニューのムービークリップの中にゲーム上で動的に空のムービークリップを作成して、そこに自分のFlashファイルをロードする、という力技な作業を行うことになります。
拙作の字幕Modなどはその力技なやり方でHUD上に読み込んでいるのですが、読み込む時の深度によってデフォルトのコンパスが消えたり、他のModのFlashのインスタンス名と競合して位置がめちゃくちゃになったり、トラブルが続出して、つくづくUI制作の道は難しいなあと思いました。
ですので、よっぽど特殊なことをしようというのでもない限り、SkyUIの機能を素直に利用してHUDウィジェットとして表示させるのが一番確実です。
改めて書くことでもありませんが、SkyUIはやっぱり偉大なModです。
SkyUIはもともと最初に導入すべきModとして真っ先に名前上がるくらいの神Modですが、UIの参考としてSkyUIのFlashのソースファイルを見るようになって、なおさらその凄さが身に沁みるようになりました。

そういえば…余談ですが、SkyUIのHUDウィジェットは何気にPapyrusスクリプトの配列の128の壁の制限を受けていますんで、ゲーム上では最大128個までしか読み込めない仕様なんですよね。
(SkyUI本体のウィジェットも含めて、です)
128個なんて、そんな大量のMod入れたりしないよ……と思うかもしれませんが、HUDウィジェットはアイコン一個でも一つのウィジェットとしてカウントされてたりするのもあるんで、意外と数を食います。
EFFやFrostfallやDefeatなど、いろんなModで見かける体力バーのようなメーターのウィジェットも、あれも1本のメーターにつき1つのウィジェット、という扱いですからね。
作る側も使う側も気をつけないと、あっさり上限に達してしまうのではないかと思います。
ちなみにMCMの登録Mod数もMAX128まで、っぽいですよね。
こっちの方が気をつけないとヤバイかな?

【FlashファイルをSkyUIのHUDウィジェットとして表示する方法】
さて、FlashファイルをSkyUIのHUDウィジェットとしてゲーム上に表示するのは、Flashファイルさえ用意できれば、ビックリするくらい簡単です。
CKで新規のクエストを一つ作って、それに以下のようなスクリプトを付けるだけ。
scriptname TestWidget extends SKI_WidgetBase

string function GetWidgetSource()
 return "../obachan/test.swf"
endFunction
最低限必要なのは、読み込むFlashファイル名の指定……これだけです。
その他はスクリプトの拡張元の「SKI_WidgetBase」がやってくれてるので、デフォルトの設定のままでよければ、何も追加する必要はありません。
もちろんスクリプトの名称は「TestWidget」じゃなくていいし、読み込むFlashファイルの名前も何でもOKです。SkyUIのHUDウィジェット場合は、ルートの場所が「Interface/exported/widgets」になりますので、「Interface/exported/obachan/test.swf」を読み込みたい場合は、上記のように「../obachan/test.swf」というパスになります。(HUDウィジェットの場合は拡張子が要ります)

ちなみにこのHUDウィジェットのスクリプトは、「SKI_WidgetBase.psc」というスクリプトを拡張したものになりますので、コンパイルの際にはSkyUIのスクリプトのソースファイル群が必要になります。
そういえばSkyUIの最新のv5.1には、何故かスクリプトのソースファイルが付いていませんね。
今まではbsaの中に必ず含まれてたのに……忘れちゃったのかな?
ちなみにv5.0にはちゃんと付属していますので、HUDウィジェットやMCMの機能を使ったModを作りたい方はOLD VERSUINSにある過去バージョンをダウンロードするか、あるいはSkyUIのGitHubから頂戴してくればよいです。


ところでSkyUIのHUDウィジェットとしてFlashファイルを表示するためには、Flashファイルの側でもやっておかなくてはならない設定があります。
最低限必要なのは、Flash内のコンテンツを一つのムービークリップにまとめて「widget」というインスタンス名をつけることです。
ちなみにこのインスタンス名は半角英数の小文字で「widget」です。先頭が大文字(Widget)になっているだけでアウトですので、要注意です。
私はそれでつまづいて何日も悩んだりしました。
FlashのActionScriptはPapyrusスクリプトと違って大文字小文字の区別があるんですよね。
PalaFlaの場合はムービークリップの代わりにスプライトを作って名前をつけます。
画像などのコンテンツはそのスプライトの中に作成します。
これで用意したFlashファイルはSkyUIのHUDウィジェットのローダーによって画面上に表示されるようになるのですが、正直、この状態ではHUDウィジェットと呼べる代物ではありません。
SkyUIのHUDウィジェットの真髄は、単にFlashファイルをHUD上に読み込むだけでなく、そのFlashコンテンツの表示上の操作をあらかじめプロパティや関数として組み込んであって、Papyrusスクリプトだけで簡単に調整できるようにしてくれているところにあります。
画面上のどこに表示するかという位置の設定や、透明度の設定、それにフェードイン・フェードアウトといった演出や、トゥイーン移動までデフォルトで用意されているのだから、驚きです。
その至れり尽くせりの恩恵にあずかるには、Flashのインスタンスに「widget」という名前をつけるだけでなく、そのベースになってるシンボル自体にSkyUIの「WidgetBase」クラスを拡張したスクリプト(ActionScript)をつける必要があります。

しかしながら、このFlashのシンボル(ムービークリップ)にスクリプトをつけるという作業は、フリーソフトのPalaFlaでは行うことができません。
ここから先の作業はどうしてもAdobeのFlashが必要になってしまいます。
ちなみに現在、スカイリムのUIを唯一作成することのできるFlashのバージョンCS6は、体験版としてのダウンロードはできないようでして(試用できるのはシリーズの最新版のみ)、無料の試用期間を利用してためしにUIを作ってみる、ということができません。
なのでFlashでの作り方をいくら詳しく書いても、ぜひお試しくださいとは気軽には言えない現状でとてもせつないのですが……それでもあえて書こうと思います。
Flashのノウハウなんて誰も興味ないかもしれませんけど、このまま頭の中にあるだけでは絶対に忘れてしまいそうだし、それに作り方さえわかれば、アドビ税を払ってでも、いっちょUIを作ってみるか、と思う方がいらっしゃるかもしれないですしね。
FlashはWeb用のコンテンツとしては、皆からばい菌のように嫌われてましたけど、動きのあるビジュアルを作るソフトとしてはかなり使いやすいもので、個人的にはとても完成度の高い、よく出来た制作ツールだと思っています。(もっとも私はActionScript3.0になって挫折したクチでしたが)
扱い方もBlenderなんかよりずっと単純ですし、CKとも似てるところがあります。
まあ、今更Flashなんか習得したところで、何の足しにもならないですけどね……

まずは新規ファイルを作成。スカイリムのUIを作る場合は必ず「ActionScript2.0」を選択します。
ちなみに「ActionScript2.0」はFlashのバージョンCC以降は廃止になりました。

CS6であればMacで作っても全然問題ありません。
Webなどで使われるFlashの場合は、ステージの「幅」や「高さ」や「背景色」などがそのFlashの見かけに関係してきますが、スカイリムのUIではこれらは関係ないので設定は何でも構わないようです。
スカイリムの画面上ではFlash内で作ったコンテンツの大きさがUIのサイズとなります。
ただしスカイリムのUIのFlashは1280×720の画面サイズが基準になっているようでして、ゲーム画面を1920×1080でプレイする時は、1280×720内で作ったものがそのまま1920×1080に拡大されます。
つまり1280×720より大きい画面では、画像は拡大されて汚くなる、ということです。
スカイリムのデフォルトのUIではほとんど画像が使われておらず、ベクターの部品中心で構成されていますが、それはどんな画面サイズでも綺麗に表示させるための配慮かなと思います。

ちなみに1280×720が基準と書きましたが、ゲームをプレイする時の画面のアスペクト比は16:9ではないものもあるわけでして……たとえば800×600とか、画面の横幅が16:9より狭いものについてはどうなるかというと、無理やり4:3の比率に縮小されたりはせずに、途中で画面が千切れます。
つまり1280×720基準ですが、1280×720ギリギリまで中身を作ってしまうと、画面サイズによっては横が見切れてしまうという状態になるわけです。
私は日ごろ、1280×720か1920×1080でしかプレイしていなかったので、横幅の狭い画面で表示させたらどうなるか、ということに思い至らず、1280×720の画面をギリギリいっぱいまで使う大きなメニュー画面を作ってしまうという失敗を冒してしまいました。(SexLab Directorがそれです)
ですので、画面のサイズ自体は1280×720基準で作るのですが、ゲーム中では画面が4:3になることも考慮して、Flash内で作るものの横幅は960pxまでに収めなくてはならないかと思います。

ところで画面のギリギリいっぱいまでUIを表示させたい場合というのもあるわけでして……たとえばマジカのバーやロード画面のレベルのバーなどは、16:9でも4:3でも必ず画面の右端や左端にあって、画面の横幅が狭くなったからといって途中で千切れたりしてませんよね。
それらはどうやって画面にフィットさせているのかというと、Scaleformの機能でゲーム画面の大きさを取得して位置を固定できる関数があって、それを使ってパーツごとに画面の「左上端」「左上中央」「右上端」といった画面上の位置を指定して配置するようです。
※もう少し詳しく書くと「Common/Shared/GlobalFunc.as」でムービークリップ自体に「Lock」という関数が拡張されているので、それを使って各インスタンスの表示位置を固定します。
(たとえばマジカのバーだと「MagickaMeterAnim.Lock("BL");」という記述で、どんな画面サイズでも必ず画面左下のポジションに来るように固定されてます)

ちなみにSkyUIのHUDウィジェットとしてFlashを作る場合は、表示位置に関しては小難しいことを考える必要はありません。前述しましたが、SkyUIのHUDウィジェットはSkyUI側で既に表示位置を調整できる機能をつけてくれてますので、わざわざ自分でそういった機能を作る必要はないのです。
最低限気をつけなくてはならないのは、作るウィジェットの大きさを幅960px、高さ720px内に収めること、だけです。
HUDウィジェットにする場合はムービークリップに必ず「widget」というインスタンス名をつけます。

上記の画像の例では、100×100pxのグリーンの正方形を置いてるだけですが、Flashの中身は自由に何でも作れます。テキストフィールドを置くもよし、画像を使うもよし、ムービークリップの中にムービークリップを散りばめるもよし、アニメーションさせるもよし。
ただし動画やサウンドをライブラリに読み込んで使うことはできません。スカイリムのUI上で音を鳴らしたい場合はまた別途、スクリプトで記述する必要があります。
作ったFlash内のパーツは最後、全部選択状態にして1つのシンボル(ムービークリップ)にまとめます。
前にも書きましたが、SkyUIのHUDウィジェットの場合は、ルートにまとめたムービークリップに「widget」というインスタンス名をつける必要があります。

Flashにあまり馴染みの無い方に向けて補足しますと、「ムービークリップ」というのはスカイリムでいう「Form」のようなものといいますか、Flashにおける標準のベースオブジェクトみたいなもんです。
ちなみにFlashとCKは制作の概念やインターフェースがとてもよく似ているツールでして、ベースになるオブジェクト(Flashでは「シンボル」と呼びます)をステージ上に配置すると、ObjectReferenceのようなインスタンスとして配置される、というしくみになっております。
(つまりインスタンス名は、スカイリムでいう「RefID」みたいなものです)
ただCKのように、オブジェクトウィンドウ(Flashでは「ライブラリ」といいます)からあらかじめ登録されたオブジェクトを選んで配置する、というような方法だけでなく、ステージ上で作ったグラフィックやテキスト、アニメーションなどをグループ化して「ムービークリップ」という何でもありの形態にまとめて、新規のベースのオブジェクト(シンボル)としてライブラリに登録することができます。
そんな所はスカイリム限定の制作ツールであるCKよりもだいぶ自由度が高い、と言えますでしょうか。
ちなみに私はスカイリムをプレイするまでは、Modなんて作ったこともなければ、プログラムの素養もないただのおばちゃんだったのですが、唯一このFlashを触ったことがあったおかげで、CKやPapyrusスクリプトに慣れるのにさほど苦労しませんでした。
ですので、その逆も同様に、CKに親しまれている方ならば、Flashの使い方もすぐに習得できるのではないかと思います。
シンボル(ムービークリップ)のプロパティ画面。
ここでスクリプトをベースのオブジェクトに紐付けます(リンケージといいます)。

ステージ上のコンテンツを選択状態にして「シンボル」に変換すると、上記のようなプロパティの画面が開いて詳細を入力することができます。
(ライブラリにあるムービークリップのシンボルを選んで右クリックし「プロパティ」を選んでもOKです)
「ActionScriptのリンケージ」というのは、CKでベースのオブジェクトのエディット画面を開いて、Papyrusスクリプトを「Add」するのと同じような感覚です。
付けたいスクリプトの名前が「testWidget.as」だったら「クラス」の欄に「testWidget」と入力します。
(「as」というのはActionScriptの拡張子です)
一番上の欄のシンボルの「名前」や「識別子」は適当につけても大丈夫っぽいです。上記の画像ではインスタンス名の「widget」と同じにしちゃってますが、別に何でもかまいません。
一番上の欄の「名前」はBaseIDのようなもの、「識別子」というのは、スクリプトでこのオブジェクトのインスタンスを自動生成する時などに使われます。


ムービークリップにスクリプトを紐づけたら、今度はそのスクリプトファイル自体を用意します。
(上記の画像の例では、「testWidget.as」を用意します)
ActionScriptのソースファイルは、Papyrusスクリプトと同様、単なるテキストファイルですので、お好きなエディタを使って作成・編集できます。
上記の画像の例のように「testWidget」というスクリプトを付けるのだったら、「testWidget.as」というファイルを新規作成して、現在作成中のFlashファイルと同じところ(同じフォルダ内)に保存します。
※スクリプトをフォルダの中に入れて管理したい場合は、リンケージする「クラス」のスクリプト名の前に、そのフォルダ名をドットで繋いで付けます。たとえば「oba」というフォルダの中に「testWidget.as」を入れるのだったら、「クラス」の欄のところは「oba.testWidget」という風に記載します。

SkyUIのHUDウィジェットとして稼動させるために最低限必要なスクリプトは以下の記述です。
import skyui.widgets.WidgetBase;

class testWidget extends WidgetBase
{
 public function testWidget()
 {
  super();
 }
}
見慣れないと最初は「ゲッ」とか思うかもしれませんが、Papyrusスクリプトに慣れている方なら、やってることはさほど変わらないのですぐに理解できるのではないかと思います。
余談ですが、昔、スカイリムのPapyrusスクリプトは「Java」というプログラム言語に似ている、という話をどこかで目にしたことがあります。
でも私はずっとActionScriptに似てるよなー、って思っていました。
でもそれはActionScriptに「Java」と似ている部分があったから、だったのかもしれません。
ちなみに上記のActionScriptをPapyrusスクリプトで書いたら、こんな感じになるかと思います。
scriptname testWidget extends WidgetBase

event OnInit()
 parent.OnInit()
endEvent
上記のスクリプトを見ればわかると思いますが、「testWidget.as」は大したことはしてません。
SkyUIのHUDウィジェットのベースのクラスの「WidgetBase」を拡張して初期化してるだけです。
ActionScriptの方の「public function testWidget()...」のところの記述は、小難しい横文字でいうと「コンストラクタ」といって、このスクリプトが実体化(インスタンス化)した時に最初に行われる初期化の処理になります。
Papyrusスクリプトで言ったら、OnInitイベントのようなものです(たぶん)。
ちなみにPapyrusスクリプトの場合は、拡張元の親と同じことをするだけなら、わざわざ「parent.OnInit()」なんて書く必要はありませんが、ActionScript2.0の場合は自身の初期化の際に「拡張元の親も初期化処理を行いますよ」とちゃんと書いてやらないと自動では行ってくれないようです。
そんなわけで、testWidgetクラスのコンストラクタの中で、「super()」と書いております。
(super()は拡張元の親…スーパークラスのコンストラクタを呼び出す処理です)

スクリプトが完成したら、あとは「パブリッシュ」してFlashファイルを書き出すだけですが、その前にもう一つ、やっておかなければいけないことがあります。
さきほど作成したスクリプトはSkyUIの「WidgetBase.as」を拡張したわけなんですが、Papyrusスクリプトと同様、FlashのActionScriptも他のスクリプトの関数を使ったり拡張したりする場合は、その引用元のスクリプトをちゃんと用意しておかないとコンパイルできないのです。
なので、まずSkyUIのソースファイルをSkyUIのGitHubからダウンロードさせてもらいます。
「src」フォルダ内の「CLIK」「Common」「HUDWidgets」……この3つのフォルダに入っているのがHUDウィジェットをコンパイルするのに必要なスクリプト達です。
今回作成した「testWidget.as」で直接使ったのは、「HUDWidgets」というフォルダの中に入っている「skyui/widgets/WidgetBase.as」だけなんですが、この「WidgetBase.as」の中でさらに「CLIK」や「Common」といったフォルダ配下のスクリプトも使っていますので、この「CLIK」「Common」「HUDWidgets」の3つのフォルダ全部に「クラスパス」を通します。
「ファイル」>「パブリッシュ設定」でFlashファイルを書き出す際の様々な設定が行えます。
「スクリプト」の項目の隣にあるレンチのマークをクリックすると「クラスパス」の設定ができます。
「クラスパス」というのは、Papyrusの例でいったら、インポート用のフォルダの場所指定のことです。
Papyrusスクリプトをコンパイルする時、デフォルトでは「Data/Scripts/source」フォルダに関連するスクリプトのソースファイルを置きますよね。その他にも、Papyrusのコンパイラのオプションを設定すれば別のフォルダにあるスクリプトを参照することができるわけですが、同じようにFlashでもActionScriptをコンパイルする時に参照するフォルダを設定することができます。
「パブリッシュ設定」にある、ActionScript2.0の設定画面で、その参照するフォルダを設定することができますので、「+」アイコンを押して、前述した3つのフォルダの場所を追加します。
ちなみに上記の画像は、各ファイルやフォルダがこんな風↓に置かれている場合の一例です。
指定するパスは作業している環境に合わせて、適宜変更してください。
クラスパスが正しく通っていなかったり、必要なスクリプトが足りていなかったりすると、パブリッシュした時に「コンパイルエラー」のタブにエラーの詳細が出ます。
パブリッシュしてFlashファイル(swfファイル)を書き出した時に何もエラーが出なければ成功です。


さて、長くなって参りましたが、もう一息ですのでめげずにお付き合い下さい。
HUDウィジェットのFlashを作ったら、それをゲーム画面上に呼び出すためのMod(espファイル)を作成しなきゃなりませんが、その作成についても少々補足したいと思います。
ちなみにHUDウィジェットのようなUIを単に表示させるだけのModでしたら、CKでは「Skyrim.esm」などのマスターファイルを最初に読み込む必要はありません。
Skyrim本体のデータは何も参照しませんので。
マスターファイルを何も読み込まないとロードの時間がかかりませんので楽チンです。
まずは前述したように空のクエストを一個作って、そのクエストにFlashファイルをHUDウィジェットとしてゲーム上に読み込むスクリプトをつけます。
scriptname TestWidget extends SKI_WidgetBase

string function GetWidgetSource()
 return "../obachan/testWidget.swf"
endFunction
この最低限のスクリプトで表示させると、こんな風に画面の一番左上端に表示されるかと思います。
これはSkyUIのHUDウィジェットのデフォルトの設定が、ウィジェットの基準点(アンカー)「左上」、ウィジェットの座標「X:0、Y:0」になっているからです。
たとえばゲーム画面の中央にウィジェットを表示させたい場合は、スクリプトにこう追加します。
event OnWidgetInit()
 HAnchor = "center"
 VAnchor = "center"
 X = 640
 Y = 360
endEvent
「OnWidgetInit」というのは、拡張元の「SKI_WidgetBase」で定義されているイベントで、その名の通り、このウィジェットが最初にゲーム画面上にロードされる時に実行されます。
ですので、このウィジェットの初期状態を設定する処理などを書くとよいです。
「X」や「Y」といった値は、ウィジェットの画面上の座標の指定に使うプロパティで、画面の一番左上が「X=0, Y=0」、一番右下が「X=1280, Y=720」になります。
ちなみに画面サイズが「1280×720」ではない場合はどうなるかというと、1280×720基準で配置した時の比率をその画面サイズ上で再現して表示されます。
つまり「X=640、Y=360」という指定だと、画面が1920×1080だろうが800×600だろうが、画面中央に表示され、さらにその半分の「X=320、Y=180」だと、ウィジェットは必ず画面の1/4の位置に、正方形の比率はそのままの状態で配置されるのです。(意味わかりますでしょうか?)
この機能、自分で搭載しようと思ったら、結構ややこしくて面倒な作業だと思います。
本当にSkyUIの作者さまさまです。

「HAnchor」「VAnchor」はウィジェットの基準点……つまり座標を指定する時に、ウィジェットのどの部分をその座標に持ってくるかという、アンカーとなる部分を指定するためのプロパティです。
「HAnchor」は水平方向の基準で、"left"、"center"、"right"の3つです(デフォルトはleft)。
「VAnchor」は垂直方向の基準で、"top"、"center"、"bottom"の3つです(デフォルトはtop)。
つまり画面中央に表示させたい時は、ウィジェットの中心に基準点があった方が指定しやすいので、両方とも「center」にすると良いです。
下の画像のように画面の一番右下にぴったり表示させたい場合は「right」「bottom」が最適ですね。
event OnWidgetInit()
 HAnchor = "right"
 VAnchor = "bottom"
 X = 1280
 Y = 720
endEvent
ちなみにこれらの設定を途中で動的に変えたい場合……たとえばMCMの設定からウィジェットの表示位置などを動かしたい場合は、拡張元のスクリプトの「OnWidgetReset」というイベントを呼び出してやればウィジェットの表示の更新ができます。
Function moveWidget()
  HAnchor = "right"
  VAnchor = "bottom"
  X = 1280
  Y = 720
  parent.OnWidgetReset()
EndFunction
上記の例では「moveWidget()」という関数にしちゃってますが、別に関数にしなくてもかまいません。
ウィジェットを変化させたいタイミングで、関数内の処理をかけばOKです。
ちなみに「parent」というのはスクリプトの拡張元の「SKI_WidgetBase」のことです。
「SKI_WidgetBase.psc」のソースを見れば、他にもどんなイベントやプロパティがあるか一目瞭然ですので、HUDウィジェットを作成する際には一度目を通しておくことをお勧めします。

SkyUIのHUDウィジェットには他にも、フェードイン・フェードアウトさせたり、表示するモードを設定したりする便利機能があるのですが、長くなって参りましたので、割愛します。
ゲーム側からデータを送って、ウィジェットに反映させる方法なども書きたいのですが、いざ説明しようとするととても難しいですね。無駄に長くなってしまうし。途中で飽きてしまう(私が)


ちなみにこれ↓は先日作ったModなんですが、実際に自分でプレイ中に使ってみたら、あんまり使い勝手が良くないことがわかって、つくづくUIってのは難しいなあと思いました。
UIは、ただ作ればいいってもんじゃないですね。
どんなに素晴らしい機能があっても、操作性が悪いと結局、使わなくなっちゃいますから。


昨今のModを見ていると、高性能でいろんな機能があるModほどUIの不自由さがネックになって、使いづらいというか、設定が面倒くさくてわかりづらい、楽しめない、ということが多い気がします。
UIがもっと簡単に自由に作れるといいんですけどねえ……

2016/01/11

SM様が見てる~ストーリーマネージャーの「神の目」

私がスカイリムを初めてプレイしたのは、もう四年も前のことになりますが、その時の興奮と衝撃は今でも昨日のことのように覚えています。
まるで映画を見てるみたいだったド迫力のアルドゥインの襲撃シーン、蝶やトンボやサケが採り放題の夢みたいな美しい自然……私が感激したものを挙げたらきりが無いのですが、その中でも一番「このゲーム凄い!面白い!」と衝撃的だったのは、NPCの心無い一言でした。
一番最初に辿りついた村~リバーウッドで、ふと目についた道端の樽を漁ったら、「あの女を見てごらん、ゴミを漁ってるよ」って、これみよがしに言う声が聞こえてきたんですよね(笑)
「あの女って、もしかして私のこと?」と思って顔を上げたら、近くの家の縁側にいたおばあさん(スヴェン母のヒルデさん)が不審者を見るみたいな目でこっちを見てて。

ええ~!まさか私がアイテム漁ってるとこ見てそんなこと言ったの!?
…ってか、この樽ってゴミ箱だったんだ……!!(私が拾ったキャベツは生ゴミか)

前作オブリビオンでも、お店の人が万引きを警戒してプレイヤーの後をついて来る事はあったけれど、まさかNPCにイヤミまで言われるなんて……本当に驚きました。
凄い、このゲームはNPCがこっちの行動を見て生身の人間みたいに反応するんだ……オブリビオンからもっともっとNPCのAIが進化したんだ、って感動しましたね。
とりわけ私はどんなゴミみたいなアイテムでも残さず拾ってしまう、TES初心者あるある…みたいなタイプでしたから、ヒルデさんのイヤミは心にぐさっときて、以後のプレイではヒルデさんの前では絶対に樽を漁らないように気をつけました。

でもあの時、私のがめつい行動を見ていたのは、本当はヒルデさんではなかったのです。
私の一挙一足をストーカーのようにチェックしていたのは、「ストーリーマネージャー」というスカイリムの因果を司る神。

このゴミ漁りの一件の他にも、私がスカイリムで面白いと思った事件の多くは、この神の何でも見通す目が少なからず関与していました。
今日はそんなストーリーマネージャーこと、SM様のことについて、書きたいと思います。

この手紙……私はフォントを可愛い書体に変えていたせいで、最初はファンレターかと思いました。


さて、まずは「ストーリーマネージャー」とは何ぞや…ということなんですが。

スカイリムの発売十ヶ月前(2011/1/17)に書かれた、開発中のスカイリムを紹介する「gameinfomer」の記事(The Technology Behind The Elder Scrolls V: Skyrim)によると、ストーリーマネージャー、もとい「Radiant Story」というシステムはベセスダ様入魂の目玉の新機能のひとつであったことが窺えます。
ちなみに上記の「gameinfomer」の記事は英語なんですが、この記事を翻訳して紹介している「doope!」というゲームサイト様の特集記事があります。
↓こちらがその記事のリンクです。よろしければこちらをご覧ください。
「The Elder Scrolls V: Skyrim」の新エンジンは”Creation Engine”、その概要が遂に明らかに


上記の記事後半にある「Skyrimの物語は”Radiant Story”システムにより拡張される)」…のくだりが、「ストーリーマネージャー」によって、どんな進化がゲームにもたらされるのかを紹介している部分です。
これをざっくり読めば、どういった類のイベントがストーリーマネージャーによって引き起こされたものなのか、スカイリムを既にある程度プレイされている方であれば、「ああ、あの時のアレか…」と思い当たるフシが少しはあるのではないかと思います。

「プレイヤーが未探索の場所や調査して欲しい場所へと自然に案内できる様」にと作られたこのシステムおかげで、未上陸のソルスセイムのダンジョンをいきなりクエストの目的地に指定されて「どこ?」と探しまくったり、スイートロールを落としただけで殺し合いの喧嘩が始まるNPC達の「より複雑で現実的な反応」を拝ませてもらったりしたわけですね(笑)
なんだかこう皮肉いっぱいに書くと、このシステムは「微妙」な機能だった感じがしなくもないのですが、しかしこの新システムは実際のところ、使い方によっては結構あなどれない性能をもっていまして、ベセスダ様がドヤ顔するのもさもありなん…という感じなのでありました。


ストーリーマネージャーというのは、ざっくり簡単に言ってしまうと、プレイヤーの挙動によって動く、クエストの着火装置……みたいなもんです。
プレイヤーが誰かを攻撃したり、魔法を使ったり、アイテムを拾ったり、レベルUPしたり、誰かと仲良くなったり、罪を犯したり……プレイヤーが何かするたびどこかに行くたびにチェックが走って、条件に合うものがあればクエストを発動させます。

たとえばヒルデさんが「ゴミを漁っている!」とイヤミを言ってきたのは、「WIAddItem02(ごみあさり)」というクエストが発動したからなんですが、このクエストが発動したのはストーリーマネージャーの「Player Add Item」というSMイベントで「プレイヤーがゴミを漁っている!」と判定されたのが原因です。
「Player Add Item」というSMイベントは、文字通り、プレイヤーが何かアイテムを取得したのを察知して起こるイベントでして、プレイヤーが何かしらのアイテム…たとえ矢一本でも…を取得するたびにイベントが走ります。
しかもこのイベントでSM(ストーリーマネージャー)様が察知するのは、プレイヤーが単に何かアイテムをゲットした、という情報だけではないんです。
そのアイテムは元々どこにあったものだったのか、誰の所有物だったか、どこでプレイヤーが手に入れたか、そのアイテムは盗んだのか、買ったのか、スリとったのか…などなど、入手経路についてもSM様は全部チェックしているんです。
このSM様の何でも見通す「神の目」だけは、たとえ隠密100、スリ100のドヴァキンさんでも、絶対にごまかすことはできません。誰にも目撃されなかった筈の盗みなのに、あとで「雇いの悪漢」が送られてくるのも、買い物して店を出た瞬間に、カルセルモの手紙を持った配達人が駆け寄ってくるのも全部、このSM様が見ていたから、なんですね。

ごみあさりクエストを走らせるかどうかを決める、SMイベントのノードの条件設定

上記の画像は、プレイヤーがアイテムを取得したことを察知したSM様が「WIAddItem02(ごみあさり)」クエストにGOサインを出す場合の条件設定です。
まず一つ目……AquireTypeが「5」という条件がありますが、これはコンテナタイプの収納からアイテムを入手したかどうかをチェックしています。
条件二つ目の 「WIAddite02RubbishContainerList」というのは「Rubbish(がらくた)」という名前の通り、
たいした物の入っていない樽や袋といったコンテナが登録されているフォームリストです。
そして三つ目は、プレイヤーが室内(インテリア)にはいないことをチェックするもの。
つまり、野外で樽や袋のような基本リスポンする保管に向かない収納庫からアイテムを入手すると、SM様は「プレイヤーはゴミを漁った!」と判定するわけなんですね。
そして「WIAddItem02(ごみあさり)」クエストに通知がいき、クエストの配役が決まると、NPCがプレイヤーにイヤミを言ったり嘲笑したりという場面が発生するのです。
だからヒルデさんのAIが進化して、プレイヤーの行動に超反応したわけじゃあないんです。
ヒルデさんはたまたま、私が樽を漁った時にすぐ近くに居ただけ。
私がゴミ箱同然の道端の樽から何かを入手したのを察知したSM様が、「今プレイヤーがゴミを漁ったよ!」と「WIAddItem02(ごみあさり)」クエストにチクって、そしてそのごみあさりクエストの配役(エイリアス)に条件の範囲内にいたヒルデさんが選ばれただけだったんです。
このように登場人物や舞台を、その場にいるものの中から見繕ってクエストを臨機応変に組み立てて実行させるからこそ、SM様は「ストーリーマネージャー」と呼ばれるわけなんですね。
スカイリムで「へえ、こんなイベントあったんだ…」と思う場面の多くは、ただそこにいたから、という理由でSM様に選ばれて参加したNPC達の一期一会のシーンであることが多いです。


たとえば……女性NPCが集まって談笑してるところに、「やあ、ご婦人方!この素晴らしい日に、大きくて強い男がお手伝いできることはありますかな?」と、男NPCが意味深なセリフでナンパしてくるという変なシーンを見たことがあるでしょうか。
これもSM様から通知を受け取って始まるクエスト(DialogueGenericScene04)のシーンで、スカイリム本体で用意されている汎用の会話シーンの一つなんですが、バニラの状態だとお目にかかるのはちょっと珍しいかもしれません。
ちなみにこのナンパシーンを拝むには、まず、サーディアちゃんタイプのお色気担当の女性ボイスタイプ(FemaleSulty)のNPCがいることが必須条件です。
それから「FemaleCommoner」「FemaleEvenToned」「FemaleNord」のいずれかのボイスタイプの女性NPCがサーディアちゃんのボイスタイプのキャラと会話できる範囲内にいること。
この女性キャラ陣が揃い、かつサーディアちゃんタイプの半径500以内に「MaleNord」の男性がいると、この会話シーンのクエストが発動する条件が揃います。
つまり年頃のイケてるおねーちゃん達が集まってキャッキャしてるところを見て、ノルド男がスケベ心(?)を出して声をかけてくる、という筋書きなんですね。
ちなみにこのテの汎用クエストは、メインクエストなど主要なクエストに登場する予定の予約済みのNPCは基本的には参加しません。(サーディアちゃんなども予約済みNPCの一人です)
なので他のクエストに登場する予定がないModで追加されたフォロワーなどの方が、このシーンの出演者に選ばれる可能性が高いかもしれないですね。
このナンパシーンのやりとりはちょっとイミフっぽい感じではあるのですが、配役がハマると結構面白いので、まだ見たことがないという方はぜひ一度ご覧になってみてください。


それから、しばらく前に「今頃になってこんな没クエストが見つかるなんて!」と話題になってたようなんですけども、死んだNPCが幽霊となって配偶者や子供、兄弟といった家族の側をうろつくというクエスト(WiKill02)…なんてのもSM様経由で始まる汎用クエストのひとつです。
スカイリムにはNPCが死んだ時の演出として用意されているクエストが結構ありますね。
以前、消えない死体について調べていた時に悩まされたWIKill05(関係者が死んだNPCに駆け寄り、家に引きこもるクエスト)だとか、誰かを殺した後に、そのNPCと仲の悪かったキャラからお礼を貰うクエスト(WiKill04)など……死が身近なスカイリムだからこそ、いろんな演出が用意されているんでしょうか。
ただ、上記の幽霊クエストがずっとゲーム中では発生せず、誰にも知られず埋もれていたことからもわかるように、SM様によるクエスト関係者抽出のしくみは実際のところ、セリフが用意されているボイスタイプであるかどうかという大きな壁に阻まれて、100%稼動しているとは言えません。
ボイスタイプの問題をクリアし、さらに他の主要クエストで予約されておらず、しかも故人の家族や恋人であるという関係性をもっているNPCの組み合わせなんて……狙って用意しないと難しいです。
CKでQuestの「Event」のところをソートすると、SMイベント経由で稼動するクエストが一目瞭然です。

「ごみあさり」とか「うっかり落としてしまいました」とか「何かいい物でも見つけたんですか?」とか
クエスト名の日本語訳って、なんかいい味出してるなあと思います。


さてそれでは、CKとか弄らない方にとってはクソ眠い話になるでしょうけども、せっかくなんで、このストーリーマネージャーの機能がどんな風に搭載されているのかを見てみたいと思います。
ストーリーマネージャーのイベントの詳細は、CKのオブジェクトウィンドウの「Character」カテゴリの中にある「SM Event Node」という項目で見ることができます。
SMイベントは前述した「Player Add Item」のように、プレイヤーの行動や周囲の状況に対応したさまざまな種類のものがあります。
たとえば「Craft Item」というのは、プレイヤーが錬金台や鍛冶屋の鋳造器具などでアイテムを制作した時に起こるイベントです。チュートリアルで武器や防具を作った時にすかさず鍛冶屋さんが「悪くない」とか褒めてくれますよね。ああいうNPCのリアクションの出所になっているのがこの「Craft Item」です。
「Kill Actor Event」とか、「Increase Level」とか、大抵は名前のまんま、という感じのイベントなんですが、中にはゲーム中では一度も使用されておらず、具体的にどういう場面で発生するのか、私にはよくわからないイベントもあります。

ちなみに上の画像は、スカイリム本体+DLC3種を読み込んだ時のもので、Usersの一番多いもの(つまりゲーム中で一番よく使われているもの)から順に並んでおります。
これを見ると、一番ゲーム中で多く使われているのは「Script Event」ですね。
この「Script Event」というのは、ちょっと特殊なタイプのイベントでして、これはプレイヤーの直接行動からではなく、スクリプトからキーワード経由で発動します。
こちらはプレイヤーの動作と関係なく任意のタイミングで手動で発動させることができるのが便利で、だからこそゲーム内で一番多く使われていると思うんですが、スクリプトを知らない方には説明がちょっと難しいので割愛させていただきますね。

「Change Location Event」のSM Event Node 編集画面
各SMイベントの項目をダブルクリックすると、上画像のような「SM Event Node」の画面が開きます。
ここにそれぞれのSMイベントから通知を受けたいクエストを登録するわけです。
クエストを登録する場所は、SMイベントノード(節)と言うようにツリー構造になっていて、第一層のノードには大抵ざっくりとした条件が設定されています。(何も条件がないのもあります)
たとえば「DungeonNode」というブランチでしたら、移動先のロケーションのキーワードが「LocTypeDungeon」になっているかどうか、つまりダンジョンかどうか……という条件です。
それでその条件をパスしたら、その配下のクエストノードのチェックが始まって、そこでもっと細かい条件判定をし、条件が合えばクエスト開始のGOサインが出る、というしくみです。
実行されるクエストは一回のイベントにつき一個、と決まっているわけでなくて、イベントをシェアしてクエストを同時多発的に実行したり、配下のノードからランダムで実行されるものを選んだり、実行されるクエスト数に制限を設けたりなどできます。


上の画像の「Change Location Event」というSMイベントは、ゲーム中では二番目によく使われているイベントで、文字通り、プレイヤーがロケーションを移動した時に起こるイベントです。
「Change Location Event」によって発動するクエストは沢山あって、例をあげるとキリがないのですが、個人的に苦笑を禁じえないのはDA09、デイドラ・メリディア様の「夜明け」関連のクエストです。
上画像で赤線を引いた部分……「Stacked Branch Node: QuestNode」の下に「DA09ChangeLocation」というクエストが登録されているんですが、このクエストは何をしているのかというと、プレイヤーが移動した先のダンジョンの宝箱に例のアノ珠を仕込んでおくという裏工作を行っているんですね。
SM様はプレイヤーが訪れた場所の詳細……ボスキャラやボス用宝箱の所在、ロケーションの中心地といった「Location Ref」の情報もしっかり押さえてますので、それを毎回教えてもらって、例の珠をポスティングしているというわけです。
だからあの珠は節操無く、どこにでも入っていたんですね(笑)


使用頻度が三番目に多い「Actor Dialogue Event」というイベントは、さきほどご紹介したナンパシーンのようなNPC同士の会話イベントの着火によく使われるSMイベントです。
もっともボイスタイプさえ合えば誰でも会話シーンが始まるというような汎用会話のクエストはスカイリムではほとんど無くて、登録されているのは固定のNPC同士による会話シーンばかりです。
ちなみに私が以前試しに作ってみたNPC同士の汎用会話シーンModも、この「Actor Dialogue Event」のSMイベントを利用して作ったものでした。
このイベントはロードされている範囲内にいる、会話が可能なシチュエーションにいるNPCを察知すると発生するのですが、前提としてNPCのAIパッケージに「Random Conversations」のチェックが入っていないと会話可能とは見なされないようです。
また会話の起こる頻度や距離感などはゲームセッティングの値で決まっているようでして、詳しくはCK Wikiのこのあたりに詳細が書かれています。
自分でModを作ってみて思ったんですが、このイベントで検出するNPCの範囲というのは予想以上に広くて、しかも会話が始まる前に自動で相手に近寄ってきてくれたりはしないので、軽く通りすがりに挨拶する程度なら、「Actor Hello Event」の方がより自然な感じになるのではないかと思いました。


ところで話はちょっと脱線してしまうのですが、このNPCの汎用会話Modを作った2014年の初め頃から私は「Papyrus.0.log」などのログを見るのに、「SnakeTail」というログ監視ツールを使っております。
私にとっては「Mod Organizer」「Sublime Text2」とならぶ、スカイリムで遊ぶためになくてはならない三種の神器のツールのひとつで、このストーリーマネージャーの機能をよく知るためにも欠かせないものでしたので、ここでちょろっとご紹介させていただきます。
これは汎用会話Modを作ってた頃のSSなんですが……右端の赤枠の部分が「SnakeTail」です。

このツールの何がそんなに便利なのかと言いますと、これを使うとなんと、スカイリムのゲームをプレイしながら「Papyrus.0.log」などのログの進行をリアルタイムで見ることができるのです。
つまり横目でログが流れていくのを確認しながらゲームを操作するという感じでして……いちいちゲームを終了させずともログがチェックできるというだけでなく、プレイ中のどのタイミングで、どういったスクリプト処理が走っているのか、ということをその場で即チェックできるんですね。
もちろんこのツールを使う前に、動作を確認したいと思ってるスクリプトにデバッグ用のコメントを仕込んでおかないと意味がないですけれども……しかし準備さえすれば、その効果は抜群です。
少なくとも私にとっては、今までパンくずを撒きながら手探り状態で歩いていた暗いスクリプトの闇の中を、カーナビ付きの車で走り回れるようになった、と感じるくらい役に立った神ツールでした。


んで、この「SnakeTail」を使って、ストーリーマネージャーのログをプレイ中に観測すると、どのようなタイミングでイベントが起こり、どんなクエストが着火したか…というのが一目瞭然で面白いんです。
ちなみにストーリーマネージャーのログというのは、「StoryManager.0.log」というPapyrusスクリプトのログにも似たSM様の挙動が記録されるログのことです。
このログを出力するためには、Papyrusのログと同じようにiniファイルを編集する必要があります。
[General]
iStoryManagerLoggingEvent=-1
bEnableStoryManagerLogging=0 → bEnableStoryManagerLogging=1 に変更
セーブデータが保存される方のSkyrimフォルダの「skyrimprefs.ini」、この中の[General]にある「bEnableStoryManagerLogging」の設定を「1」に変更してやると、Papyrusのログが出力される「Logs」フォルダの中に「StoryManager」というフォルダが出来て、そこに「StoryManager.0.log」という名前でログが保存されるようになります。

また、同じ[General]の中の「iStoryManagerLoggingEvent」という項目は、このストーリーマネージャーのログ出力のオプション設定になってるようです。
ちなみにデフォルトの「-1」ですと、すべてのSMイベントがログに出力されます。
このオプションについてはCK Wikiを見ても説明がどこにも書いていないようなのですが、おばちゃんが自前でテストして調べてみたところ、こんな感じでログが切り替わるようになっておりました。
「0」……「Kill Actor Event」
「1」……「Assualt Actor Event」
「2」……「Change Location Event」
「3」……「Script Event」
「4」……「Actor Dialogue Event」
「5」……「Actor Hello Event」
「7」……「Player Add Item」
「8」……「Player Remove Item」
「9」……「Craft Item」
SMイベントのログは場所によっては物凄い量になりますから、自作Modの動作確認でログを見る場合などには、トレースするイベントの種類を限定できるこのオプションは非常に有用です。
もっとも私が確認できたのはこの9種だけで、他のイベントについてはわからなかったんですが。
他のイベントについて、何かご存知の方がいらっしゃいましたらぜひとも教えてください。


とまあ、そんなわけで、話がかなり専門的(?)になってきて読む気が失せたでしょうけども、もうこんな話をする機会も二度と無いでしょうから、もうちょっとだけご紹介させてください。

まずは「StoryManager.0.log」とはどんな感じのものなのか、一部ですがスクリーンショットを撮りましたので参考までにご覧ください。
ちなみに下の画像は、前述の「SnakeTail」でログを開いたところなので、文字色が変わったりなどしていますが、「StoryManager.0.log」自体は単なるテキストファイルです。
(クリックすると別ウィンドウで拡大します)
ストーリーマネージャーのログは、SMイベントが起きるたびに詳細情報が記録され、そのイベントに登録されたノードの判定がどうなったか、という結果が出力されます。
上の画像のログですと、まず一番最初に発生したのは「Player Add Item」イベントです。
二行目の「Started processing event 000014FE: Player Add Item ...」というところを見ると、プレイヤーがその時入手したアイテムの所有者は特に無く(OwnerRef: NULL)、またコンテナタイプの収納庫から入手(AquireType: 5)したことがわかります。
続けて三~五行目の記述は、その後、配下のノードの判定がどうなったかという結果を示す部分です。
まず「Player Add Item」のSMイベントノードの基点のノードを通って、それから二つ、「Node '' failed conditions」と出てますんで、直下にあったノードが二つとも条件外ということで、そこでチェックは終わり、その下層にあるノードのチェックはスルーされたことがわかります。
「Player Add Item」のSMイベントノード
「Player Add Item」のSMイベントノードには、第一層に二つのノードがあるだけですので、これでチェックはすべて完了となり、六行目で「Finished process event.」(イベントプロセス終了)となったわけです。
ざっとですが、ストーリーマネージャーのログの見方はこんな感じです。
まあ、これはチェックするノードが少ない時の例なので非常にわかりやすいんですが、いろんなイベントが立て込んできてタイムアウトが発生したりするようになると、ログの順番もめちゃめちゃになってきて、どれがどれなのかわけわかんなくなってきます。
ですが、条件をパスしてクエストの着火までたどり着いたものは名前がわかりますし、さらにそのクエストの必須項目が揃わなくてクエストが不発に終わっても、その結果がわかるようになっています。



長々と書きましたが、私がストーリーマネージャーについて書けることは以上です。
スカイリムにはいろんな仕掛けがいたるところに散りばめられているのに、目に見えるのはほんの一部です。ストーリーマネージャーのログを見ながらプレイしていると、特にそう感じます。
たわいもないNPCの一言の後ろに、こんな途方も無いしくみが隠されていたということが驚きで、そして知れば知るほど面白くて、それをずっと書きたいと思っていたんですが、うまくまとめられず、結局こんなとりとめもない内容になってしまいました。
更新するのをためらう出来ですが、少しでもスカイリムって凄いな、こんなしくみがあったんだ…と思っていただけたら嬉しいです。