Additional Random Enemies – 敵をランダムに配置するMOD

※2022/03/17 ; version 0.3 に更新。設置されるマーカー間の最低距離を1.5倍に延長しました。複数のマーカーから敵が集まって乱戦状態になるのを防ぐためです。また、設置場所のランダム性を上げました。


バニラだと平穏すぎるスカイリム。ダンジョン内はまだしも、フィールドでは黙々と目的地に向かって走ることも多いです。

そこで今回は、MCMで選択した敵をフィールド上へランダムに配置するMODを作ってみました。敵増加MOD作成の難しさについてもいろいろと書いています。


1. 最新版ダウンロード(uploader.jp)

※DLC Dawnguard、DLC Dragonborn、SKSE、SkyUI が必要です。


2. 使い方

2-1. MCMで設定を行う

「一般」タブ

「稼動」にチェックが入っている場合のみ機能します。

当MODは、屋外のランダムな座標にスポーンマーカーを設置し、そこに再度近づくと敵を生成するという仕組みになっています。稼動のチェックを外すと、設置済みのマーカーを残したまま新規設置や敵生成の機能のみが停止します。

マーカー設置数の確認やリセット、および各種確率の設定もできます。

  • 出現率 … マーカーに近づいたときに敵を出現させる割合です。
  • 戦闘遭遇率 … 人型とそれ以外の敵とがすでに戦っている場面に遭遇する割合です。
  • 人型率 … 人型の敵(ドラウグルや山賊など)が出現する割合です。
  • レベル同期 … 1/2の確率でプレイヤーレベルに同期した敵も出現するようになります。
「敵の出現数」タブ

クマや山賊などの種類ごとに、出現数する最大数を指定します。数値は 0 から 9 まで指定でき、0 だと出現しなくなります。

指定された数値をもとに「1/2 以上、指定値以下」の数の敵が出現します。例えば 9 を指定した場合は 5~9 体となります。

MCM自動保存機能

PapyrusUtil を導入している場合、MCM設定が自動で保存されます。ニューゲーム、および当MOD未導入のセーブデータをロードした際、その設定が反映されます。当MOD導入済みのセーブデータには反映されませんので、セーブデータごとに異なる設定を維持することは可能です。

この機能は全自動で行われます。ユーザーの作業は不要です。

2-2. フィールドを走り回る

導入直後はマーカーが設置されていないため、追加の敵は出現しません。フィールド移動中にランダムでマーカーを設置していきますから、まずは徒歩で各地を移動する必要があります。後述する理由により、馬に騎乗しているときは設置処理が行われません。

マーカーは、居住地区でないフィールド上に最大で128個まで設置されます。敵の生成に使われたマーカーは削除されます。

2-3. 敵を強くする

当MODの目標は、バニラよりはフィールド上に敵が出てくることと、その出現位置がランダムであることです。敵の強さには主眼を置いていませんので、ハードコアを求める場合には物足りないと思います。 もしも敵が弱いと感じたら、MCMで以下の2点を設定してみてください。

  • 「レベル同期」にチェックを入れる。
  • 「ウェアベア」の出現数を上げる。(デフォルトは0)

一応テストプレイでレベル同期ウェアベアを9体出してみましたが、強すぎて1体も倒せませんでした。お好みに合わせてやってください。

力は強いし足も速いし集団だと恐怖でしかない。

3. インストール / アンインストール

3-1. インストール

DLC Dawnguard、DLC Dragonborn、SKSE、SkyUI (LE/SE) が必要です。

MCM自動保存機能を使う場合には PapyrusUtil (LE/SE) も必要です。

MOD管理ツールでインストールしてください。ロードオーダーはどこでも構いません。

3-2. アンインストール

MCMで「稼動」のチェックを外した後、「マーカーリセット」を押してすべてのマーカーを削除してください。さらに屋内で30日待機を行うと、出現させた敵が消えるので安心です。

その後、MOD管理ツールでアンインストールしてください。


4. 更新履歴

  • 2022/03/17 (version 0.3) ; 設置されるマーカー間の最低距離を1.5倍に延長。設置場所のランダム性上昇。
  • 2021/12/01 (version 0.2) ; MCM自動保存機能を実装。
  • 2021/10/20 (version 0.1) ; 公開。


5. 作成秘話

5-1. 出現位置を決める

MODで敵を出現させるとなると、バニラのようにあらかじめ特定の座標に配置しておく方法と、ゲーム内で動的に配置する方法とが考えられます。

あらかじめ配置しておく方法は、スポーンポイントを適切な場所に配置できるのが強みです。遺跡前だったり水辺だったり、それらしい場所にそれらしい敵を出現させることができます。ただし、他MODとの競合には注意が必要で、スポーンポイントがMOD家の中に埋まってしまうこともあり得るし、地形が変更されれば地中や空中に敵を出現させてしまうこともあり得ます。

一方、ゲーム内で配置する方法は出現ポイントのランダム性が強みになります。どこで敵と遭遇するかわからないので、より新鮮な感覚を味わえるでしょう。

中立NPCのことを考えると、出現させる場所は居住地区でない場所が望ましいです。居住地区かどうかは、スクリプトの HasKeyword() 関数を使って Location に LocTypeHabitation という Keyword が付けられているかどうかを見れば判定できます。この Keyword は主に屋外用で、ホワイトラン郊外のような都市周辺や街道の脇に直接作られた町などに付けられています。屋内の場合は LocTypeDwelling という Keyword が使われています。

居住地区を除外できたら、次にどの座標に置くかということが悩みの種になります。特にZ座標(高さ)を決めるのが非常に難しく、適当にやると地中や空中に出現させてしまう可能性があります。

当MODではプレイヤーが通った座標を使っています。これなら、敵が出現してもおかしくない場所と高さであることが保証されるからです。騎乗中にマーカーが配置されないようにしているのは、空中に配置してしまう可能性があるからでした。この方法のデメリットとして、MOD導入直後はマーカーがないため、しばらく歩き回らないと敵が出てこない点が挙げられます。一定数を初期配置することも考えましたが、やはり他MODとの競合の懸念があるのでやめました。

座標を決める別の手段としては、周辺の岩や木を検索して使うことも考えられます。この手段は一度検討してみたものの、それらが地中に埋めて配置されていないかどうかを判定することができずに断念しました。また、プレイヤーから一定の距離以上離れている岩や木を検索するのも難しかったです。目の前に敵が突然出現したらおかしいですからね。FindRandomReferenceOfAnyTypeInListFromRef() を何度も繰り返せば離れているものでも取得できますけど、シンプルとはとても言い難い処理になってしまいます。

5-2. プレイヤーレベルに応じて変化する敵を作る

バニラのモブ敵は、LeveledCharacter というものを使ってプレイヤーレベルに応じた敵が出てくるようになっています。アイテムでよく聞くレベルドリストのNPC版です。

この LeveledCharacter は設定がちょっと複雑で、大まかな作り方は次のような感じです。

  1. 実際に出現する個々の敵を Actor として作る。
  2. LeveledCharacter に、レベルごとの敵 Actor を複数登録する。
  3. 新規 Actor のテンプレートに、作成した LeveledCharacter を指定する。

3番で作る Actor をフィールド上に配置すれば、レベルに応じて LeveledCharacter に登録された1番の Actor のうちのどれかが出現することになります。どのレベルでどの敵が出るかについては細かく設定することができます。

LeveledCharacter への登録とレベル設定
新規 Actor のテンプレートに、作成した LeveledCharacter を指定

この LeveledCharacter の面白いところは、Actor だけでなく別の LeveledCharacter も登録できるところです。例えば、複数のレベル帯の魔術師を登録したものと山賊を登録したものを別々に用意しておき、それらを新規の LeveledCharacter に登録すると、魔術師または山賊がランダムに出現する Actor となります。この方法を応用すると、様々なバリエーションのスポーンポイントを簡単に作成することができます。

1つだけ気になった制限事項として、スクリプトがついた Actor は LeveledCharacter に登録できないという点があります。これはドラゴンが好例なんですけど、ドラゴンは普通にスクリプトがついた Actor と、それが外された NoScript 版 Actor とが用意されているんです。以前からこの NoScript 版は何だろう?と思っていましたが、 LeveledCharacter で使われていたんですね。スクリプトを付けたいときは、LeveledCharacter をテンプレートにした Actor(上述の3番)になら付与することができます。

この制限の影響で、DLCドラゴンボーンで出てくる爆発系のクモは、当MODで敵として出現させることはできますけど爆発しません。あれは各クモごとにスクリプトの設定が異なるため、一括してスクリプトを付与するわけにはいかないからです。専用のスクリプトを用意すればいけるんですが、クモのためにそれをやるのは気乗りしませんでした。色のバリエーションを楽しむ敵として使ってください。

5-3. 出現時の負荷を軽減したい

経験上、大量の Actor を同時に出現させるとCTDすることがあります。何が負荷になっているのかはっきりとは分かりませんが、今のところ私が考えているのは、装備品等の高解像度テクスチャを一気に読み込むことによる過負荷なのではないかということです。単体の Actor で見れば大したことがなさそうでも、大概のNPCはセルをロードするときに一気に読み込まれますから、これが要因になる可能性はあると思っています。

対策としては敵を出現させるタイミングをずらすことが考えられますが、あんまり遅らせるとプレイヤーの視界で突然出現することになりかねませんから、可能な限りセルをロードするタイミングに近いほうが望ましいのは確かです。というわけで、当MODではそのタイミングに OnCellLoad() を使うことにしました。これはセル内のオブジェクトをすべてロードし終わったときに発動するイベントでして、これを使うことで他のオブジェクトの OnLoad() と処理が重なってしまうことを回避したつもりです。

それに加えて、そもそもスポーンマーカーを設置する際にも、セル内にいるNPC数が16を超えている場所には設置しないようにする条件を加えています。この判定にはSKSEの GetNumRefs(43) という関数を使っていて、43というNPCを表す数値でフィルタリングしてオブジェクトの数を取得することができます。テストしたところフォロワーもその人数に含まれるようなので設定値に悩んだのですが、まぁ常時10人以上連れて歩くプレイヤーはそんなにいないだろうと考えて16にしてみました。

5-4. 出現させた敵を消す

ランダム配置する場合の最大の難関です。バニラのモブ敵 Actor は原則としてリスポーン属性がついていますので、そのまま出現させるとリスポーンしちゃいます。敵を固定配置しておくならそれでもいいんですが、ランダム配置の場合は消しておかないと敵だらけになる可能性があるし負荷も増えます。

方法としては、出現させた段階で何らかの変数にその敵情報を保持しておいてセルを離れるときに消す、というのがまず思い付きます。が、これはスクリプトとしてはやや煩雑で、当MODのように出現数もランダムにする場合は結構冗長なコードになります。できなくはないですけれど。

そこで考えた挙句、リスポーンを外した Actor を新たに作る方法を取りました。これは作るまでがかなり大変なんですが、出現させた後に放っておけるので楽です。リスポーンしないので後処理をシステムに依存することができます。

リスポーンを外した Actor というのは1から作る必要はなくて、テンプレートに参照する Actor を指定し、Use Base Data のチェックだけ外したあと Respawn のチェックを外すと良いです。そうすれば、左上のIDや名前、フラグ以外はすべてテンプレートが参照されます。

バニラの敵バリエーションはものすごく多いので当MODで参照する際にかなり選別をしていて、特に山賊や魔術師、フォースウォーンはバニラよりもバリエーションに欠けます。「敵を消す」という条件がなければバニラの多彩な Actor と LeveledCharacter を使うことができたんですけど、ランダム配置してスクリプトをシンプルに保つために以上のようなことをしてました。

5-5. MCM設定の保存はやめたこともあった

version 0.1

ニューゲームの際にMCM設定を引き継ぐことができるMODがあります。FileAccess Interface for Skyrim Script – FISSPapyrusUtil – Modders Scripting Utility Functions などがそうで、これらのMODを使うと外部ファイルへの保存や読み込みが可能となります。

実を言うとこれらに対応したバージョンまで作ったんです。導入コードが簡単でとても扱いやすかったです。本当にすごく良かった。

しかし、なんと他MODとの相性問題が出てしまって泣く泣くカットすることに。問題が出てしまうのは自分で作った他の未公開MODで、それもMCMつけて設定保存ができるようにしていたんですよ。これら2つのMODは単独で導入する場合には何ら問題ないのに、同時に導入するとロードCTDしてしまうという謎現象が起きました。

その後なんとか起動はできるようになったんですが、今度はMCMに登録されない現象に見舞われました。ログで見ると片方のMODのスクリプトプロパティがなぜか軒並み読み込めてないエラーが出ていて、原因がわかりませんでした。単独使用ならエラーにならないのに。いろいろと試したところ、スクリプトをBSAに入れると確実にエラーとなりました。このあたりでこういうのは私のMODらしくないと思ってMCM保存機能はばっさりカットすることにしました。

以前から、スクリプトをBSAに入れると正常に動作しないことがあるなぁとは思っていたんですが、もしかしたら、LEでコンパイルしたpexをSEのBSAに入れたり、SEでコンパイルしたpexをLEのBSAに入れたりするのが良くないかもしれません。検証するのがあまりに面倒でやめちゃったんですけど、この先スクリプトをBSAに入れるときはLEとSEを混同しないようにしようと思いました。ちなみにルーズファイルであれば全くもって大丈夫ですし、混同していてもそれぞれ単独で導入しているときは正しく動作します。

version 0.2

MCM自動保存機能を実装しました。AEが出てからアップデートのあった PapyrusUtil だけを使うようにしたらうまくいきました。

この PapyrusUtil も含め、いろいろなSKSEプラグインMODのAE対応が思ってたよりも早くてびっくりしています。スカイリム愛されてるなぁと実感。

FISSの方は、調べたら排他制御ができないとのことでした。それでなぜCTDするのかは私にはわからないんですけど、ニューゲームの際に同時に呼び出すとだめみたいです。


(余談ですが Loose file の読みってルーズファイルでいいんですかね? 発音としてはルースだけど。ルースファイルよりルーズファイルの方がなんかしっくりくる感じはする。loose をルーズと読むこと自体が日本読みだから、カタカナではルーズファイルでいいのかなぁ。)

(そうそう発音で思い出したんですが、私中学のときに英語の授業で apple をエポゥと発音して先生に笑われたことがあります。がんばって発音したんだしアップルよりマシでしょと今なら思えますけど、当時すでにコミュ障をこじらせてた私は恥ずかしくてそれ以降わざと日本式発音で通してました。アイライクアップル。でも個人的には発音にすごく興味があって、受験期には発音とアクセントだけの教本を毎朝読んでたりしたからそこだけ得意でした。CD付きの本で発音練習とかもしてた。ネイティブ発音ができる人って羨ましいよね。)


これでだいたい書きたいことは書いたよ。秘話が長すぎたかもしんない。敵のランダム配置とMCMでの選択をしたい方はどうぞお試しください。導入直後は敵が出ませんが、しばらく使っていくとその効果を実感できるスルメのようなMODになっています。

いやしかしかなりの時間をCKに費やしてきたのに、いまだ知らないことが山のようにありますね。Anniversary Edition がどんなMOD事情になるかが気になる今日この頃、まだまだスカイリム遊べるなぁと嬉しく思うのでした。LEがメイン環境の私はアップデートについての不安もなく傍観してます。…LEは大丈夫だよね?

Leave a comment

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

14 − 4 =

4 thoughts on “Additional Random Enemies – 敵をランダムに配置するMOD”