自動脱衣スクリプトのアップデート版です。自作MODに自動脱衣機能を付けたり、プレイヤー用の脱衣かごを用意したりする際、ご参考になる部分があれば嬉しいです。
※2022/03/12 スクリプトの2行目に著作権表記を入れるようにしました。今まで通り表記なしで使っていただいても大丈夫です。
※2022/09/15 スクリプトを少し書き換えて効率を良くしました。スクリプトソースの導入について追記しました。
1. 特定ゾーンに自動脱衣機能を付ける方法(プレイヤーもNPCも脱衣)
1-1. トリガーボックスで囲む
特定ゾーンに自動脱衣機能を付けるには、その範囲をトリガーボックスという見えないボックスで囲み、スクリプトを設定することになります。
まずは Creation Kit (CK) で対象のセルを表示し、何でも良いのでオブジェクトを選択してください。今回は、キナレス聖堂で中央の床を選択してみます。
この状態でツールボタンの「T」を押し、出てくるダイアログで「TriggerBox」を選択します。
薄い色のボックスが出現したら、下図のように適切な大きさに変更します。この中に入ると脱衣し、出ると着衣することになります。
微調整したいときは、トリガーボックスをダブルクリックして Reference を開き、「Position」で位置を、「Bounds」で大きさを指定します。
1-2. ボックスに新規スクリプトを設定する
Reference の Scripts タブで「Add」ボタンを押します。出てきたダイアログで [New Script] を選択して、新規スクリプトを追加します。
「Name」がスクリプト名になりますので、他のMODと被らないような名称を付けてください。
スクリプトが追加されたら、右クリックして「Edit Source」を選択し、編集画面を開きます。外部エディタを設定済みの場合は「Open in External Editor」です。
1-3. 自動脱衣スクリプト(プレイヤーもNPCも脱衣・着衣)
編集画面を開くと、1行目はすでに入力されています。2行目以降を以下のようにしてください。このスクリプトにはSKSEが必要です。
Scriptname AutoUnequip_scrTrigger extends ObjectReference
{Copyright (C) 2020,2022 eka. (https://ekagames.lifecycle.jp/creation-kit/unequip-all/)}
Import Math
Armor Property armRing Auto ; NPC用リング
FormList Property folArmor Auto ; プレイヤー防具
Form Property fomL Auto Hidden ; プレイヤー左手
Weapon Property wepR Auto Hidden ; プレイヤー右手
;------------------------------ ボックスに入るとき
Event OnTriggerEnter(ObjectReference akActionRef)
Actor actRef = akActionRef as Actor
If actRef == None
Return
ElseIf actRef == Game.GetPlayer() ; プレイヤー
wepR = actRef.GetEquippedWeapon() ; 右手武器取得
fomL = actRef.GetEquippedObject(0) ; 左手アイテム取得
folArmor.Revert()
Armor armWorn
Int i = 0
While i < 31 ; 装備スロット順に防具取得
armWorn = actRef.GetWornForm(LeftShift(1, i)) as Armor
If armWorn
folArmor.AddForm(armWorn)
EndIf
i += 1
EndWhile
armWorn = None
Else ; NPC
actRef.AddItem(armRing, 1, true)
actRef.EquipItem(armRing, false, true)
actRef.RemoveItem(armRing, 9, true) ; Outfit 装備
Utility.Wait(0.05)
EndIf
actRef.UnequipAll() ; 脱衣
actRef = None
EndEvent
;------------------------------ ボックスから出るとき
Event OnTriggerLeave(ObjectReference akActionRef)
Actor actRef = akActionRef as Actor
If actRef == None
Return
ElseIf actRef == Game.GetPlayer() ; プレイヤー
If wepR && actRef.GetItemCount(wepR) > 0
actRef.EquipItemEx(wepR, 1) ; 右手装備
EndIf
wepR = None
If fomL && actRef.GetItemCount(fomL) > 0
actRef.EquipItemEx(fomL, 2) ; 左手装備
EndIf
fomL = None
Armor armWorn
Int i = folArmor.GetSize()
While i > 0
i -= 1
armWorn = folArmor.GetAt(i) as Armor
If armWorn && actRef.GetItemCount(armWorn) > 0
actRef.EquipItemEx(armWorn) ; 防具装備
EndIf
EndWhile
armWorn = None
folArmor.Revert()
Else ; NPC
actRef.AddItem(armRing, 1, true)
actRef.EquipItem(armRing, false, true)
actRef.RemoveItem(armRing, 9, true) ; Outfit 装備
EndIf
actRef = None
EndEvent
ツールバーの File > Save を選択し、スクリプトをセーブ(コンパイル)します。
コンパイルに成功すると「Compilation succeeded.」の文字が出ます。ここで失敗する場合は、次項を見てスクリプトソースの導入を行ってください。
1-4. スクリプトソースを導入する
CKでスクリプトを扱うには、あらかじめバニラのスクリプトソースをゲームフォルダに解凍しておく必要があります。さらに、SKSEを利用するスクリプトをコンパイルするには、SKSEのスクリプトソースも必要です。
バニラのスクリプトソースは以下のように導入します。LEとSEで解凍先のフォルダが異なるので注意します。圧縮ファイルの解凍には 7-Zip を使ってください。
- LE: “Data/Scripts.rar” 内にあるすべての .psc を “Data/Scripts/Source” フォルダに入れる。
- SE: “Data/Scripts.zip” 内にあるすべての .psc を “Data/Source/Scripts” フォルダに入れる。
SKSEのスクリプトソースは、SKSEのウェブサイトから対応するエディション(LE/SE/AE)の .7z ファイルをダウンロードして解凍し、抜き出します。SKSEの “Data/Scripts/Source” 内にあるすべての .psc を、上記のフォルダに上書きしてください。バニラのスクリプトを上書きすることになりますが、SKSEのスクリプトでもバニラの関数はそのまま使えますので問題ありません。
1-5. プロパティに用いるオブジェクトを作成する
プロパティとは、スクリプトに付けられた変数の一種です。ゲームデータとスクリプトとの橋渡しをするのが主な目的で、プロパティを指定することによって、スクリプトからゲームデータにアクセスしたり操作したりすることができます。
今回必要なオブジェクトは次の2つで、これらを作成してプロパティに指定します。
- Armor armRing … NPCの装備をコントロールするための指輪。
- FormList folArmor … プレイヤーの防具情報を保持するためのリスト。
指輪は何でも良いのですが、今回は金の指輪をコピーし、MOD専用として使いたいと思います。
Object Window で Items > Armor から「JewelryRingGold」を開きます。
ID と Name を任意の名称に変更します。ゲーム内では表示しないので、分かりやすいもので構いません。
「Playable」のチェックを外し、プレイヤーが扱うことのできない、非表示アイテムとします。
編集してOKボタンを押すと、新しいオブジェクトとして作成するかどうかのダイアログが出ますので、「はい」を選択します。これで金の指輪のコピー品が作成されます。
次に、防具情報を保持するための FormList を用意します。
Miscellaneous > FormList を開き、どこでも良いので右クリックして「New」を選択します。
ここでは ID に任意の名称を付けるだけでOKです。
1-6. プロパティに指定する
作成したオブジェクトをプロパティに指定していきます。トリガーボックスの Reference を開き、スクリプトを選択状態にして「Properties」ボタンを押します。
ダイアログが開いたら、「armRing」を選択して右側の「Edit Value」ボタンを押してください。
Pick Object 欄で、作成した「armRing」を選択します。同様にして「folArmor」も指定してください。
以上で完成です。トリガーボックスの範囲が自動脱衣仕様になりました。esp を保存してロードオーダーに加えてから、ゲーム内で確認してみましょう。
2. 脱衣かごを配置する方法(プレイヤーまたはNPCのみ脱衣)
2-1. かごを作成する
脱衣かごは、セルのどこかに配置してプレイヤーがアクティベートするものとします。見た目だけバニラのかごを流用し、家具のようにアクティベートできるようにしましょう。
Object Window で Items > MiscItem から Basket06 を開きます。Model 欄の「Edit」ボタンを押して、見た目を確認します。
見た目が確認できたら、nif ファイルのパスをドラッグ選択して「Ctrl+C」でコピーします。
WorldObjects > Activator を開き、どこでも良いので右クリックして「New」を選択します。
ID と Name に任意の名称を入力します。Name はゲーム内でクロスヘアを合わせたときに表示されるテキストです。
そして、Model の右側の「Edit」ボタンを押します。
モデルが入っていない空の画面が開くので、「Edit」を押します。
ファイル名のところに、先ほどコピーした nif ファイルのパスをそのまま貼り付けます。
元の画面に戻ってモデルが表示されればOKです。このとき、うまく表示されず赤い三角形になってしまうことがあります。そのときは、nif ファイルのパスをもう一度貼り付け直してみてください。それでうまくいくと思います。
Model 欄にパスが入ったことを確認したら、「OK」ボタンを押して確定させます。新規のオブジェクトは、一度確定させないとスクリプトを設定することができません。
2-2. かごに新規スクリプトを設定する
作成した Activator を再度開いて、Scripts の「Add」ボタンを押します。スクリプトの追加方法はトリガーボックスの場合と同様です。
トリガーボックスのときは配置したボックスの方にスクリプトを設定しましたが、今度は配置する前のベースアイテムに設定することになります。こうすることで、この脱衣かごを複数配置しても、個別にスクリプトを設定する必要がなくなります。
2-3. 脱衣かごスクリプト(プレイヤーのみ脱衣・着衣)
脱衣かごはプレイヤー専用としました。体 (Body) の部位に何か装備していれば脱衣し、そうでなければ脱衣時の装備を着衣するというシンプルな仕様です。
脱衣と着衣の切り替えをフラグ管理仕様にすることもできますが、プレイヤーが自分で着衣を済ませた場合などの処理が複雑になるため、お勧めしません。
Scriptname AutoUnequip_scrBasket extends ObjectReference
{Copyright (C) 2020,2022 eka. (https://ekagames.lifecycle.jp/creation-kit/unequip-all/)}
Import Math
FormList Property folArmor Auto ; プレイヤー防具
Form Property fomL Auto Hidden ; プレイヤー左手
Weapon Property wepR Auto Hidden ; プレイヤー右手
;------------------------------ アクティベート
Event OnActivate(ObjectReference akActionRef)
Actor actRef = akActionRef as Actor
If actRef == None || actRef != Game.GetPlayer()
actRef = None
Return
EndIf
Armor armWorn
Int i
If actRef.GetWornForm(4) ; 脱衣
wepR = actRef.GetEquippedWeapon() ; 右手武器取得
fomL = actRef.GetEquippedObject(0) ; 左手アイテム取得
folArmor.Revert()
i = 0
While i < 31 ; 装備スロット順に防具取得
armWorn = actRef.GetWornForm(LeftShift(1, i)) as Armor
If armWorn
folArmor.AddForm(armWorn)
EndIf
i += 1
EndWhile
actRef.UnequipAll() ; 脱衣
Else ; 着衣
If wepR && actRef.GetItemCount(wepR) > 0
actRef.EquipItemEx(wepR, 1) ; 右手装備
EndIf
wepR = None
If fomL && actRef.GetItemCount(fomL) > 0
actRef.EquipItemEx(fomL, 2) ; 左手装備
EndIf
fomL = None
i = folArmor.GetSize()
While i > 0
i -= 1
armWorn = folArmor.GetAt(i) as Armor
If armWorn && actRef.GetItemCount(armWorn) > 0
actRef.EquipItemEx(armWorn) ; 防具装備
EndIf
EndWhile
folArmor.Revert()
EndIf
actRef = None
armWorn = None
EndEvent
自動脱衣の場合と処理は似ています。プロパティは folArmor のみ作成して設定すればOKです。
2-4. 脱衣かごを配置する
配置したい場所を Render Window に表示し、Object Window から脱衣かごをドラッグ&ドロップします。スクリプトをベースアイテムに設定したため、これだけで脱衣かごとして機能します。
そのままでは触れたときに動いてしまうので、Reference を開いて次の2か所の設定で固定します。
- 「Don’t Havok Settle」にチェックを入れる。
- 固定用スクリプト「defaultDisableHavokOnLoad」を追加する。
固定用スクリプトはバニラで使われているものです。Add ボタンで出るダイアログから検索して追加してください。プロパティを4つ持っていますので、「havokOnHit」を選択して「Edit Value」を押し、下図の状態にしてください。
2-5. トリガーボックスを併用する(NPCのみ脱衣・着衣)
もし、トリガーボックスの自動脱衣と脱衣かごとを併用する場合は、トリガーボックス側のプレイヤー脱衣を無効にする必要があります。脱衣かごでプレイヤーを管理し、トリガーボックスでNPCを管理することになります。
トリガーボックスのスクリプトは、以下のように変更します。
Scriptname AutoUnequip_scrTrigger extends ObjectReference
{Copyright (C) 2020,2022 eka. (https://ekagames.lifecycle.jp/creation-kit/unequip-all/)}
Armor Property armRing Auto ; NPC用リング
;------------------------------ ボックスに入るとき
Event OnTriggerEnter(ObjectReference akActionRef)
Actor actRef = akActionRef as Actor
If actRef == None || actRef == Game.GetPlayer()
actRef = None
Return
EndIf
actRef.AddItem(armRing, 1, true)
actRef.EquipItem(armRing, false, true)
actRef.RemoveItem(armRing, 9, true) ; Outfit 装備
Utility.Wait(0.05)
actRef.UnequipAll() ; 脱衣
actRef = None
EndEvent
;------------------------------ ボックスから出るとき
Event OnTriggerLeave(ObjectReference akActionRef)
Actor actRef = akActionRef as Actor
If actRef == None || actRef == Game.GetPlayer()
actRef = None
Return
EndIf
actRef.AddItem(armRing, 1, true)
actRef.EquipItem(armRing, false, true)
actRef.RemoveItem(armRing, 9, true) ; Outfit 装備
actRef = None
EndEvent
3. スクリプト解説
3-1. NPCを脱衣させる
NPCを脱衣させているのは、以下の1行です。これだけで、すべての装備品を外すことができます。
actRef.UnequipAll()
ただし、この UnequipAll() という関数は使い方に注意する必要があります。というのも、特定の場面で高確率のCTDを引き起こすからです。
それは、「セーブデータをロードした直後で、一度もセル移動をせず、NPCに対して関数を発動させた場合」です。
この原因は未だに解明できていません。体型MODを入れていない環境でも起こり、それが起こる状況のセーブデータでは再現率100%のように感じます。
対策として、脱衣の前に Outfit を着用させ直すことで、CTDをほぼ防ぐことができます。それが以下の処理です。
actRef.AddItem(armRing, 1, true)
actRef.EquipItem(armRing, false, true)
actRef.RemoveItem(armRing, 9, true)
Utility.Wait(0.05)
NPCに対して AddItem() や RemoveItem() 関数でアイテムの出し入れをすると、自動的に Outfit を着用し直します。これはデフォルトの仕様ですが、動作がやや不確実なため、間に EquipItem() を挟むと安定します。この処理を UnequipAll() の前に入れることで、CTDを防いでいます。
3-2. NPCを着衣させる
NPCを着衣させるには、たった今出てきた Outfit の着用し直しを行うだけで良いです。
フォロワーでないNPCなら Outfit に設定された防具のみを装備しますし、フォロワーとして雇用中であれば、さらに最適装備に切り替わります。
3-3. プレイヤーを脱衣させる
プレイヤーの脱衣も UnequipAll() で行います。プレイヤーの場合、この関数でCTDを引き起こすことはありません。
ただ、脱衣前の装備情報を保持しておかないといけませんので、以下の3つのプロパティを使っています。
FormList Property folArmor Auto ; プレイヤー防具
Form Property fomL Auto Hidden ; プレイヤー左手
Weapon Property wepR Auto Hidden ; プレイヤー右手
右手武器は以下のように取得できます。
wepR = actRef.GetEquippedWeapon() ; 右手武器取得
左手はたいまつの可能性があるので、Weapon でなく Form で取得します。
fomL = actRef.GetEquippedObject(0) ; 左手アイテム取得
防具は複数ありますので、FormList にリストとして保持します。それが以下の部分です。
i = 0
While i < 31 ; 装備スロット順に防具取得
armWorn = actRef.GetWornForm(LeftShift(1, i)) as Armor
If armWorn
folArmor.AddForm(armWorn)
EndIf
i += 1
EndWhile
GetWornForm() を使い、30番から60番までの装備スロットをチェックしています。装備スロットは他にもあるのですが、一般にはこれでほぼ取得できると思います。
この関数は Form を返してきますので、最後に as Armor を付けて変換し、None でなければリストに加えるようにしています。
3-4. プレイヤーを着衣させる
プレイヤーの着衣は、保持していた情報をチェックし、そのアイテムを所持していれば装備するという方法で行います。
If wepR && actRef.GetItemCount(wepR) > 0
actRef.EquipItemEx(wepR, 1) ; 右手装備
EndIf
wepR = None
If fomL && actRef.GetItemCount(fomL) > 0
actRef.EquipItemEx(fomL, 2) ; 左手装備
EndIf
fomL = None
i = folArmor.GetSize()
While i > 0
i -= 1
armWorn = folArmor.GetAt(i) as Armor
If armWorn && actRef.GetItemCount(armWorn) > 0
actRef.EquipItemEx(armWorn) ; 防具装備
EndIf
EndWhile
武器も防具もSKSEの EquipItemEx() という関数で装備させます。特に防具については、バニラの EquipItem() 関数を使ってはいけません。プレイヤーが独自に付呪した装備品の場合、EquipItem() 関数では付呪効果が適用されないからです。そこだけ気をつければ、問題なく元の姿に戻れると思います。
常に EquipItemEx() を使えば良さそうに思えるかもしれませんが、バニラの EquipItem() にも使い道はあります。例えば上述したNPCの Outfit を着用させるスクリプトでは、EquipItem() の方でないと逆に安定しません。
プレイヤーの着衣で一つ問題点を挙げるとすれば、「矢」を指定できない点です。Papyrus には、装備中の矢の情報を取得する関数はありません。UnequipAll() で外すことはできても、複数の矢を所持している場合に、元の矢を装備させるのが難しいのです。
矢を管理するには、インベントリに入った時点でその矢の情報を保持し、かつ装備したかどうかを専用クエストで監視することになると思います。脱衣機能のためだけにそのようなシステムを組むのは少しやりすぎな感じがしますので、これは仕様ということにして良いでしょう。
4. 著作権表記について
当ページで公開している Papyrus のスクリプトは、配布MODにおける利用、および個人利用問わず自由にご利用ください。スクリプトの2行目に著作権表記をしていますので、スクリプトをコピー&ペーストあるいは改変して使っていただいて構いません。必要であればご自身の著作権も併記してください。著作権は放棄しませんが、著作権表記そのものを省略することも許可します。
あまり難しいことは考えず、スクリプトについては自由に一部または全部をコピー・改変して使ってくださいということです。ただし、スクリプトの内容によって生じた不具合・損害等については、一切の責任を負いかねますのでご了承ください。
ご厚意により配布場所等で著作権表記、あるいはリンクをしていただける場合には、以下の文字列をお使いください。
Copyright © 2020,2022 eka.
https://ekagames.lifecycle.jp/creation-kit/unequip-all/
10 thoughts on “自動脱衣スクリプト2022”
こんなMODないかな?でもニッチだし無いだろうな、CKでアレをやりたいけど方法が分からない、あの手のスクリプトってどうなってるんだろう?
などで検索すると必ずここにたどり着きます。
有用なMOD、情報をいつもありがとうございます。
いつか誰か一人くらいの役には立つかもしれないと思って書いていますので、レスポンスをもらえるのはとても嬉しいです。
優しいお言葉、ありがとうございます。
こんちには。上の匿名でのコメントを送信した者です。
実は今、初めてMODを制作しておりまして、NexusModsとcreation clubでの配布を予定しております。
MODの中でeka.さんの自動脱衣と自動ドアのスクリプトを利用させていただいておりまして許可をいただきたくコメントしております。
記事の中でご自由にお使いくださいとの記載がありますが、MOD配布にあたりきちんと筋を通したほうが得策と思い至りまして。
配布する際には何らかの形でクレジットを記載しようと思います。
NexusModsはともかくcreation clubは私にとって未知の場所なのでどうなるか分からないのですが自動脱衣はSKSEが必要となっていることから恐らくCS版では使えないですよね?
自動ドアのスクリプトはCS版でも使えるかもしれませんがその場合でもやはりcreation clubでリリースする際にも何らかの形でクレジットを記載しようと思います(実際にCCでリリースできるか分かりませんが)。
以上用件のみですが失礼いたします。よろしくお願いいたします。
dgz400 さん、こんにちは。
これはご丁寧にありがとうございます。公開しているスクリプトは、どうぞご自由にご利用ください。配布される場所に関わらず、自作MOD内における複製および改変、再配布を許可します。
SKSEが必要になるのは、プレイヤーの着衣が含まれる次の2つのスクリプトです。これらはCS版では使えません。関数としては GetWornForm と EquipItemEx がSKSEのものです。
1-3. 自動脱衣スクリプト(プレイヤーもNPCも脱衣・着衣)
2-3. 脱衣かごスクリプト(プレイヤーのみ脱衣・着衣)
NPCのみとなる次のスクリプトは、CS版でも使えます。
2-5. トリガーボックスを併用する(NPCのみ脱衣・着衣)
2-5. のスクリプトは、10-13行目を下記のように書き換えることで「NPCは脱衣・着衣、プレイヤーは脱衣のみ」のスクリプトとすることもできます。プレイヤーの着衣だけは、SKSEがないと難しいです。
If actRef == None
Return
EndIf
自動ドアのスクリプトはSKSEを使わないので、おっしゃる通りCS版でも使えます。以上ご参考までに。
利用の許可だけでなくアドバイスも頂戴いたしましてありがとうございます。
初心者なりに目に見える部分はどうにか作ったのですがスクリプトとなると一朝一夕でどうこうできる問題ではないので大変参考になります。
今までずっとMODを利用する立場で、もちろん製作者に対して感謝の念を忘れたことは無いのですが、いざ自分で作るとものすごい労力が必要と痛感させられました。
元よりeka.さんのMODは愛用させていただいておりますし記事も拝見してるのですが、またご助言を仰ぐことがあるかもしれません。
その際は恐れ入りますがご教示いただければ幸いと存じます。
MODを使っていただいてありがとうございます。自分で作るのもまた達成感があって楽しいですよね。
スクリプトは汎用的に使えそうなパターンで書いてあります。使い方によっては変えたほうが良い部分もあるでしょうから、気にせず色々と書き換えてください。
今まで投稿したことのある内容ならお力になれることもあるかもしれませんので、いつでもどうぞ☆
作成したModのスクリプトでこちらの自動脱衣の記述を参考にさせていただきました
ところで、Additemで渡す数が1なのに対してRemoveitemで削除する数が9なのは何か意図してのことでしょうか?
またそれによるエラーなどは発生しないのでしょうか?
sinzzzz さん、嬉しいご報告ありがとうございます。
削除する数が9なのは、エラー処理を目的としています。万が一インベントリに2個以上のアイテムが残ってしまうエラーが起きたとしても、自動的に取り除けるようにするためです。
所持数より多い数を指定する安全性については、私も気になって調べたことがあります。
Creation Kit Wiki の RemoveItem – ObjectReference ページ、Notes の2個目に、これは FormList での例となりますが、aiCount 引数に満たない場合にはすべて取り除かれる旨の記載があります。
https://www.creationkit.com/index.php?title=RemoveItem_-_ObjectReference
私はこれを根拠に安全と判断しています。実際に aiCount に9や999を入れたMODをいくつか公開してきていますが、自身の環境でも不具合は経験していませんし、エラー報告を受けたこともありません。おそらく大丈夫ではないかと思います。細かくてすみません。ご参考まで。
eka. さんこんにちは。
おかげさまで上のコメントを投稿したあとMODをリリースすることができました。
PS版はスクリプトも含めバニラに存在しないものは一切MODに入れることができないと知り驚きましたが(えっ…そこまで厳しいの?っていう)。
ところでまたMODを制作しましてeka.さんの記事を参考にさせていただきましたので配布ページにその旨を記載させていただきたいと思います。
具体的には今からsktrimにあるバルグルーフの椅子をレバーで出したり消したりする記事です。
creation kit wikiや海外のチュートリアルなんかも見てますが私にとって一番参考になるのがeka,さんの記事です。
これはもうお世辞抜きで。
MODのリリースおめでとうございます&お疲れ様です。
PS4のMODは外部ファイルを入れられないので、使えそうなバニラのスクリプトを探して流用するみたいです。一方Xboxでは入れられるので、コンソール版まできちんと対応するのは結構大変なはず。
椅子の記事、もはや化石レベルですけど懐かしいですね。ご参考にしていただけるのはとても嬉しいです。どんどん使ってください。
ご報告ありがとうございます☆