プログラミング・動画編集 備忘録

プログラミングや動画編集についての備忘録です

Skyrim Mod 製作日記 - 19 - ダンジョンを自動生成する (4)

ウィザードリィ#1のマップを利用したダンジョン生成について、前回はテレポートの実現方法について記載しました。
このModで使用しているスクリプトはその辺りのものだけなので、後は基本的なことになるかもしれません。

敵の配置

まずは敵の内容について。
現在、このModはVersion 0.9.3として公開しています。
当初は的はドラウグルのレベルドリストのみでしたが、いくつかの敵パターンを用意するようにしました。

まず、レベルドリストですが、B1~B10までのレベルドリストを作成し、その中にそれっぽい敵配置となるようなレベルドリストを含めるようにしました。
次の内容はB1に配置する敵のレベルドリストです。
f:id:rrryutaro:20170408185711p:plain

リストの内容はざっくりと次の通りです。

  • 近接戦闘(片手・両手それぞれ)を行う山賊のレベルドリスト
  • 動物のレベルドリスト
  • ケルトンのレベルドリスト
  • ドラウグルのレベルドリスト

プレイヤーのレベルが高ければ相応に高いレベルの敵が出現します。
ただし、この内スケルトンは大して強い内容になりません。

レベルドリストだけでは配置できませんので、このレベルドリストをテンプレートとして使用するアクターを作成します。
テンプレートを使用する際、そのまま配置すると、関係性の無い敵は同士討ちをはじめてしまうため、Factionsを追加するようにしています。
f:id:rrryutaro:20170408190605p:plain

ただ、自分はまだこの辺の適切な設定をわかっていないため、敵の種別について一通り登録してあります。

ユニークな敵など、個別の設定を行う場合、テンプレートのチェックを外して任意の設定を行うようにします。
例えば、ラスボスのワードナは特別強くなるようにステータスなどを底上げしています。
f:id:rrryutaro:20170408190926p:plain

敵の配置は、マップ上で次のように配置する位置と向きを指定します。
f:id:rrryutaro:20170408191358p:plain

今のところただ配置しているだけのため、そのセルに侵入すると全員がアクティブ状態となります。
このため、レベルが高いと敵も強いのはいいのですが、ドラウグルはやたらとシャウトを使い、動物は熊がやたらと吼えてうるさいったらないです。
本来なら適切な位置などでアクティブになるようにしたいのですが、やり方をよくわかっていません。

以上

Skyrim Mod ファイルフォーマット解説 - 2

はじめに

この記事ではSkyrimのModのファイルフォーマットについて解説しています。
SkyrimのModのファイルフォーマットについてはTes5Mod:Mod File Format - The Unofficial Elder Scrolls Pages (UESP)が詳しいですが、ここでは、これまで自分なりに解析してきた内容や、必要な部分について解説していきます。
また、同時にプログラミングで利用する情報なども合わせて解説したいと思いますが、プログラミングについての主な情報は別サイトで記事にいていきます。

前回はModの基本構成や、ファイルの先頭部分のファイルヘッダーについて記載しました。
今回は主にグループについてです。

グループ

Modファイルの中身をみると、最初には必ずTES4からはじまるファイルヘッダーがあり、その後はグループの固まりの繰り返しが基本となります。
Skyrim.esmを見てみます。
f:id:rrryutaro:20170408174648p:plain
選択した範囲がファイルヘッダーです。その後に続くGRUPからが、グループのはじまりです。

グループの先頭24byteはグループヘッダーです。
f:id:rrryutaro:20170408181214p:plain

ここではとりあえず次の点を把握できればOKです。

名称 データ型(サイズ) 説明
Group string(4) GRUP固定グループの始まりを示す
DataSize uint(4) グループヘッダーを含むグループ全体のサイズ
Signature string(4) そのグループで扱う情報を識別する記号

実際のデータを見てみます。

名称 内容 バイナリ上での表示
Group GRUP f:id:rrryutaro:20170408181747p:plain
DataSize 96,862 f:id:rrryutaro:20170408181849p:plain
Signature GMST f:id:rrryutaro:20170408181923p:plain

前回特に言及しませんでしたが、DataSizeは内容の所には10進数で書いていますが、バイト上での表示は16進数で、バイトオーダーはリトルエンディアンです。
バイトオーダーなどについての詳細はGoogleなどで"バイトオーダー"で検索してみてください。
10進数と16進数の確認は例えば、Windows標準の計算機などで確認する方法があります。
qiita.com

SignatureGMSTとあります。UESPによるとGame Settingとのこと。
Game Settingということでしょうか。
とりあえず、ここでは詳細は気にしません。

ここまでわかれば、知りたい情報のSignatureのある位置まで、DataSize分読み飛ばしていけばよいことになります。

プログラミングでグループのデータを扱う方法は次の記事にまとめました。
qiita.com

はてな記法一覧とマークダウンでの対応

とりあえず、自分用の備忘録です。
ここでは、自分がよく使うもので、間違いがち、忘れがちなものを随時更新します。

なお基本的に、はてな記法一覧で見当たらない方法はHTMLの記述で行うだけのことです。

記法 はてな記法 マークダウン
見出し *見出し #見出し
リンク [URL:title=タイトル] [タイトル](URL)
インラインコード <code>コード</code> `コード`

以上

ブログのテーマを変更しました

これまで、次のテーマを使っていました。
クリスタブルー~CrystalBlue~ - テーマ ストア


直前の記事がこんな感じの表示ですね。
f:id:rrryutaro:20170408170830p:plain

自分でテーマを作ってみようと思いましたが、中々手がつかず、次のような表示にもなってしまうため、変更しました。
f:id:rrryutaro:20170408170946p:plain

現在使用中のテーマは次のテーマです。

Wideboard - テーマ ストア

このテーマだと、画面いっぱいに広げれば、その分広がるので見やすくなったと思います。
f:id:rrryutaro:20170408171338p:plain

なお、実際にテーマを知りたい場合は、画面最上部のHatena Blogのメニューである、そのブログタイトルのドロップダウンリストをクリックして、「このブログのテーマを見る」をクリックすればわかります。
f:id:rrryutaro:20170408172327p:plain

Skyrim Mod 製作日記 - 18 - ダンジョンを自動生成する (3)

ウィザードリィ#1のマップを利用したダンジョン生成ですが、一応一通りの内容が出来たので、以前に公開したバージョンを更新し、日本語版も用意し、Nexusの方へも登録してみました。

ただ、PS4版でフォロワーの追従がうまくいかず、その点は不完全なままです。
また、出現する敵と敵の強さなどの調整が不十分なので、今後修正していきたいと思っています。

以下、このModでのポイントなど。特にPS4基準で作成している点について。

テレポートについて

※書いてみたものの、わかりづらい内容ですみません

ウィザードリィでは元々トラップの一種としてテレポートがありますが、それとは別にSkyrimウィザードリィのダンジョンを再現するのに次の手段をとっています。

  1. ダークゾーンはLightの設定を真っ暗にして、別セルとして用意し、その場所へMoveTo(テレポート)させる
  2. マップの端から端へのループはダミーの見た目を用意して、端から端の場所へMoveTo(テレポート)させる
  3. 各階への移動は、各階は別セルとして、通常のDoorでのTeleportで移動させる
  4. エレベータでの移動は、エレベータ用の部屋を用意してDoorでつないで、Teleportで移動させる

まず、ダークゾーンについてです。
通常のダンジョンは次のように設定して、ライトを設置せずに明るくさせています。
f:id:rrryutaro:20170405222430p:plain

一方ダークゾーンは次のように設定して、ライトがないと真っ暗になります。
f:id:rrryutaro:20170405222507p:plain

"Directional Ambient Lighting"とは日本語で、指向性周囲照明となるようです。
壁などを設置した際にその向きの周辺の照明ということなのでしょう。
例えば、色を赤に設定すれば赤色の照明になります。

セルへの移動は、アクティベーターを次のように作成しています。
f:id:rrryutaro:20170405222948p:plain

ここで重要なのは次の2つのスクリプトです。

まず1つ目。プレイヤーを移動させるのに使用します。

Scriptname DA16DreamwarpTriggerScript extends ObjectReference  Conditional

ObjectReference Property pDA16DreamwarpReturnMarker  Auto
Message Property pDA16DreamwarpMessage Auto

Event OnTriggerEnter(ObjectReference akActionRef)

	if akActionRef == Game.GetPlayer()
		Game.GetPlayer().MoveTo(pDA16DreamwarpReturnMarker)
		pDA16DreamwarpMessage.Show()
	endif

endEvent

続いて、2つ目はフォロワーを移動させるのに使用しています。

Scriptname C06TombEntranceCheatScript extends ObjectReference  

Location Property TombLoc auto

ReferenceAlias Property Aela auto
ReferenceAlias Property Farkas auto
ReferenceAlias Property Vilkas auto

ObjectReference Property AelaSpot auto
ObjectReference Property FarkasSpot auto
ObjectReference Property VilkasSpot auto

Quest Property C06 auto

Event OnTriggerEnter(ObjectReference akActivator)
	if (akActivator == Game.GetPlayer())
		if (C06.GetStage() >= 30 && C06.GetStage() < 40)
			; if (Aela.GetReference().GetCurrentLocation() != TombLoc)
				Aela.GetReference().MoveTo(AelaSpot)
			; endif
			; if (Farkas.GetReference().GetCurrentLocation() != TombLoc)
				Farkas.GetReference().MoveTo(FarkasSpot)
			; endif
			; if (Vilkas.GetReference().GetCurrentLocation() != TombLoc)
				Vilkas.GetReference().MoveTo(VilkasSpot)
			; endif
		endif
	endif
EndEvent

よくよく見ると、2つ目のスクリプトでプレイヤーもフォロワーも移動できますが、当初は1つ目のスクリプトのみ利用していたのと、メッセージ表示に利用していたためです。
今後修正してもよいかもしれません。

プレイヤー用のスクリプトは、プログラムで生成する際に移動先のマーカーを設定するようにしています。
フォロワー用のスクリプトは次のようにプロパティ設定をしてあります。
f:id:rrryutaro:20170405223505p:plain

クエストと、クエストステージが条件として必要となるため、次のようにクエストを作ってあります。
f:id:rrryutaro:20170405223627p:plain

クエストはゲーム開始時にクエストが開始されるようにしているので、スクリプトの条件が成立します。

フォロワーはクエストの"DialogueFollower"にあるエイリアス"Follower"を参照すればよいようで、プロパティに設定しています。(※しかしながら、PS4版ではコレが有効でない?のか、フォロワーが移動しません、この辺はまだ自分が知識不足で原因がわかっていません)

このアクティベーターをセルへトリガーとして次のように配置します。
f:id:rrryutaro:20170405224526p:plain
※XMarkerHeadingに重なっている四角のトリガーはメッセージ表示に使用しているもので、別途説明します

ダークゾーン側には次のように配置します。
f:id:rrryutaro:20170405224614p:plain

トリガーに触れると、矢印の先のXMarkerHeadingへ移動します。
f:id:rrryutaro:20170405225422p:plain

マップで見ると次の部分です。
f:id:rrryutaro:20170405225909p:plain
セルを赤色で塗っている部分がダークゾーンです。それぞれの入り口にトリガーを置き、出口にマーカーを配置して、スクリプトのMoveToで移動しています。

マップの端から端への移動もこのトリガーとマーカーを配置させて移動させます。
ただし、表示領域を作らないと真っ暗な表示になるため、ダミー用の領域を作成します。
次のマップはB3階のマップです。
f:id:rrryutaro:20170405230436p:plain
セルを黄色で塗っている部分がダミー用の表示領域で、その他前の位置で、逆方向へテレポートさせます。
ただ、ドアの開閉などの状態はリンクしないため、見た目が異なるなどの難点がありますが、まぁしょうがないでしょう。
DoorをActivateした際に、別のドアを開閉するスクリプトがあれば、見た目をリンクさせることができるかもしれません。ありそうな気はしますが、今のところ探していません。

各階やエレベータについては、DoorのTeleportをそのまま利用します。
f:id:rrryutaro:20170405230850p:plain

※こちらも、PS4版だとナビメッシュでフォロワーの配置場所を作っていても、移動してこない場合があります。基本的には別のセル間への移動はできて、同一セル間の移動は出来ないようですが、別のセル間でも移動しない場合もあり、いまひとつ原因がわかっていません


とりあえず、今回はこの辺で。

Skyrim Mod ファイルフォーマット解説 - 1

はじめに

SkyrimのModファイルフォーマットについて解説?していきたいと思います。
Modのファイルフォーマットを知れば、プログラムを組んでデータを自動生成したり、Mod上の欲しい情報を取り出したりなどが行え、Mod製作にかかる時間を短縮できます。
また、プログラムを組まないにしても、バイナリエディタなどで直接情報を確認することも出来ます。

なお、Mod製作をはじめて4ヶ月ほどで、主にプログラムでModを生成することを進めていたので、逆に基本的なことを知らない部分もありますので、ご了承ください。
また、PS4で動作することを基本条件としていますので、PC版でなら簡単に出来ることを難しくやっている場合もあるかと思います。

ファイルフォーマットの情報は次のサイトで詳しく解説されていますので、自分なりに解析してきたことなどを書いてきたいと思います。
Tes5Mod:Mod File Format - The Unofficial Elder Scrolls Pages (UESP)
(※以降この際とのことはUESPと略します)

項目名の名称などは主にSSEEditでの名称を使っていきます。

使うツールなど

  • Skyrim Special Edition Creation Kit Version 1.3.9.0
  • SSEEdit 3.2
  • Microsoft Visual Studio Community 2017 ( C# )
  • BinaryEditor Stirling Version 1.31
  • Binary Editor BZ Version 1.9.8.5

最小限の状態

Skyrim Special Edition Creation Kit(以降 CK)を起動し、Skyrim.esmにのみチェックを入れて読込み、ファイル保存したespファイルをバイナリエディタで表示すると次のようになっています。
f:id:rrryutaro:20170403220210p:plain

ファイルの先頭4文字が"TES4"となっています。(その後の"I"はたまたま文字コードで"I"に一致しているだけです)
全てのModファイルはこの情報からはじまります。(※SkyrimはTES=The Elder Scrolls シリーズの5作目なのでTES5なのですが、ファイルフォーマットはTES4(Oblivion)の頃から変わらないということでしょうか。この辺はよくわかりません)

このModファイルは一切のデータがないため、"TES4"からファイルの終わりまで、Modファイルの基本情報のみが記載されています。この"TES4"からファイルの終わりまでの情報をファイッルヘッダーと呼ぶことにします。

では、これをSSEEditで読込んでみます。
f:id:rrryutaro:20170403221222p:plain

SSEEditのウィンドウの右側に情報が表示されています。
まずは、Record Headerと書かれていて、その下にぶら下がっている項目を見てきます。

表示名 内容 バリナリ上での表示
Signature TES4 f:id:rrryutaro:20170403221809p:plain
DataSize 73 f:id:rrryutaro:20170403221848p:plain
Record Flags f:id:rrryutaro:20170403222015p:plain
FormID 0 f:id:rrryutaro:20170403222124p:plain
Version Control Info 1 0 f:id:rrryutaro:20170403222300p:plain
Form Version 44 f:id:rrryutaro:20170403222344p:plain
Version Control Info 2 0 f:id:rrryutaro:20170403222621p:plain

このレコードヘッダーはModのファイルフォーマットを理解する上で重要な要素です。
一部例外がありますが、Modのファイルフォーマットの構造は次のようになっています。

Modファイル
 + ファイルヘッダー (レコード形式)
 + グループ
   - グループヘッダー
   + レコード
     - レコードヘッダー
     + フィールド
       - フィールドヘッダー
       - フィールドデータ 

今解説している部分がファイルヘッダーで、これはレコード形式となっています。
レコードとは武器であれば1つ分の武器情報を扱う情報の固まりです。
グループとはレコードを包括した情報の固まりです。

レコードはレコードヘッダーから始まり、その後に続く情報がフィールドとなります。
フィールドは武器であれば、ダメージの値など、レコードで扱われる各種の情報の固まりです。

SSEEditで続きの情報を見て行きます。
Record Header の後に、 HEDR - Header とあります。これがフィールドです。

SSEEdit上では一部わかりませんが、フィールドはまず、次のフィールドヘッダーがあります。

名称 データ型(サイズ) 説明
Signature char[4] フィールドがどのようなデータであるかを示す4文字の名称。フィールド名が同じでもレコードが異なれば扱う情報は異なる可能性があるので注意
Data Size ushor フィールドデータのサイズフィールドヘッダーのサイズは含まないので注意

※ushorのサイズは2byte、(別名uint16など)

実際のデータを見てみます。

表示名 内容 バリナリ上での表示
Signature HEDR f:id:rrryutaro:20170403223820p:plain
DataSize 12 f:id:rrryutaro:20170403223843p:plain

"TES4"レコードの"HEDR"フィールドの型情報など

名称 データ型(サイズ) 説明
Version float UESPでの説明では「ほとんどのファイルで0.94; Update.esmの最近のバージョンでは1.7です。」とのこと
Number of Records uint 全レコード数。(解析しきれていませんが、単純にカウントしても数が合いません・・・)
Next Object ID uint 次のオブジェクトID(FormID)、CK上で何かを追加した際に使われるかと思われます。

実際のデータです。

表示名 内容 バリナリ上での表示
Version float f:id:rrryutaro:20170403223952p:plain
Number of Records uint f:id:rrryutaro:20170403224104p:plain
Next Object ID uint f:id:rrryutaro:20170403224144p:plain

UESPでは、Number of Records(UESPでの表記はnumRecords)はint32、Next Object ID(UESPでの表記はnextObjectId)はulongとなっていますが、ここではC#を中心として扱うので、C#での表現とします。また、C#でのlong, ulongは8byte、C++は4byteのようなので、混乱なきよう。なお、レコードカウントについてはマイナスにはならないはずなので、一応uintとしています)

では、SSEEditで以降の項目を見て行きますが、次の"OFST"と"DELE"は灰色になっています。
これは、"TES4"レコードで扱われるフィールドで、かつファイル上での順番的にはこの順番になっているであろうフィールドですが、ファイル上ではデータが無いため、表示されていません。必須項目ではないということですね。どの項目が必須かなどはUESPのサイトで確認するのがいいかと思われます。

次のデータです。

表示名 内容 バリナリ上での表示
Signature CNAM f:id:rrryutaro:20170403225742p:plain
DataSize 8 f:id:rrryutaro:20170403225819p:plain
CNAM - Autohr DEFAULT f:id:rrryutaro:20170403225853p:plain

※フィールドで扱う文字列は終端がNULLになるものと、そうでないものがあるため注意が必要です。基本的にはDataSizeを参照すれば大丈夫ですが、プログラムで扱う際には、終端がNULLかそうでないかのチェックが必要になります。

Master Files - MAST

表示名 内容 バリナリ上での表示
Signature MAST f:id:rrryutaro:20170403230120p:plain
DataSize 11 f:id:rrryutaro:20170403230140p:plain
MAST - Filename DEFAULT f:id:rrryutaro:20170403230206p:plain

Master Files - DATA

表示名 内容 バリナリ上での表示
Signature DATA f:id:rrryutaro:20170403231026p:plain
DataSize 8 f:id:rrryutaro:20170403231051p:plain
DATA - Unknown 0 f:id:rrryutaro:20170403231113p:plain

※マスターファイルはそのModでの前提ファイルです。フィールドはHEDRのように、フィールドデータ内で複数の情報を扱っているケースと、このMaster Filesのように、複数のフィールドが連続してある固まりとしていることもあります。例えば、マスターファイルが複数ある場合には次のようになっています。

f:id:rrryutaro:20170403231321p:plain
f:id:rrryutaro:20170403231355p:plain
※このような形式は多数あるため、プログラムでデータを取り込んで書きかえたい場合、並び順に注意する必要があります。例えば、コンテナなどは、コンテナ何に格納されているアイテムを示すのに、コンテナ内のアイテム数を示すフィールドがあり、それに続いて、コンテナのアイテムを示すフィールドがアイテム数分続きます。

INTV - Unknwon

表示名 内容 バリナリ上での表示
Signature INTV f:id:rrryutaro:20170403231707p:plain
DataSize 4 f:id:rrryutaro:20170403231725p:plain
DATA - Unknown 1 f:id:rrryutaro:20170403231746p:plain

と、このように管理されています。
通常はこの後に"GRUP"の4文字があり、その後4byteにグループのデータサイズがあり、データサイズ分読み飛ばすと、また次の"GRUP"の4文字があります。
それについては次回解説していきたいと思います。以上。

Visual Studio 2017 Community の導入

SkyrimのMod製作を補助するプログラムを作っていますが、作り直すことにしたので、ついでにVisual Studioの最新版を入れてそちらで行うことにします。

www.visualstudio.com
www.visualstudio.com

インストーラーを実行すると次の画面が表示されます。
f:id:rrryutaro:20170401205809p:plain

各タブの内容はこんな感じになっていました。
f:id:rrryutaro:20170401220144p:plainf:id:rrryutaro:20170401220153p:plainf:id:rrryutaro:20170401220203p:plain

[ワークロード]で好みの開発形態にチェックを入れれば、[個別のコンポーネント]には必要な項目が自動でチェックされます。
さらに必要ならチェックを付ければよいでしょう。

今回必要なのは.NETデスクトップ開発ですが、ついでなので、ユニバーサルWindowsプラットフォーム開発にもチェックを付けてインストールしたところ、およそ1時間ほどかかりましたが、特につまづくことも無くインストールが行えました。


以上