2018年6月14日

【Papyrus.psc】自動脱衣スクリプト統合版アップデート

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

前回の 自動脱衣・着衣機能をつけよう のスクリプトをアップデートします。
NPCおよびプレイヤーの自動脱衣・着衣スクリプト統合版(要SKSE)の修正です。

※2020/07/14 新サイトでアップデート記事を書きました。→ 自動脱衣スクリプト2020 | 今もSkyrim


目次

  1. 変更点
  2. UnEquipAll
  3. 完全版

1. 変更点

今回のスクリプトはNPCもプレイヤーも自動脱衣・着衣するものです。UnEquipAll というコードを使うかどうかで2つのバリエーションを用意しました。UnEquipAll 版はCTDに注意する必要がありますので後述してあります。
変更点は主として以下の2点です。トリガーボックスへのスクリプトの付け方等については前回を参照してください。

1-1. たいまつへの対応

たいまつは武器扱いではないため、前回のスクリプトでは対応できていませんでした。プレイヤーの装備情報を「Weapon」ではなく「Form」タイプのプロパティに保存することで、たいまつも着脱できるように対応しました。
NPCは暗い場所で自動的にたいまつを使うので対応不要ですが、記述の統一性を持たせるために一部変更しています。

1-2. 両手武器を外した際、前の片手武器が装備される仕様への対策

UnEquipAll を使わない完全版でのみ必要な対策です。
両手武器を装備中、左手に巻物やたいまつを持ったりすると、右手にはその前に装備していた片手武器が自動的に装備されます。これはバニラの仕様で、スクリプトから両手武器を外しても同じことが起こります。
UnEquipAll を使わない場合、この自動装備される片手武器も外す必要があり、対策しました。

目次に戻る


2. UnEquipAll

まず簡単な、UnEquipAll を使う方法から載せておきます。
前回も説明しましたが、脱衣する actPasser.UnEquipAll() のところでCTDすることがありますが、それで良ければこちらの方が記述も短くて理解しやすいです。
CTDは、セーブデータロード直後、一度もセルロードを挟まずにNPC(フォロワー)がトリガーボックスに入った時に起こります。

使う場合は以下のスクリプトをトリガーボックスに付けて、armRing および folArmor の2つのプロパティだけ指定してください。

Scriptname EkaUndressScript05 extends ObjectReference
{ NPC、プレイヤー脱衣統合版(要SKSE)。トリガーボックスに適用。}

;下記2つのプロパティを指定---
Armor Property armRing Auto ; JewelryRingGold を指定
FormList Property folArmor Auto ; 作成した空の FormList を指定
;-------------------------------

Form Property fomWepL Auto
Form Property fomWepR Auto

Actor actPasser
Form fomTemp
Int i

;--------------------------------------------------入る時
Event OnTriggerEnter(ObjectReference akTriggerRef)
    actPasser = akTriggerRef as Actor

    If actPasser == None
        Return
    ElseIf actPasser == Game.GetPlayer() ; プレイヤー
        If folArmor.GetSize() > 0
            folArmor.Revert()
        EndIf

        i = 0
        While i < 31 ; 防具
            fomTemp = actPasser.GetWornForm(Math.LeftShift(1, i))
            If fomTemp != None
                folArmor.AddForm(fomTemp)
                fomTemp = None
            EndIf
            i += 1
        EndWhile

        fomWepR = actPasser.GetEquippedObject(1) ; 右手武器
        fomWepL = actPasser.GetEquippedObject(0) ; 左手武器
    EndIf

    actPasser.UnEquipAll()
    actPasser = None
EndEvent

;--------------------------------------------------出る時
Event OnTriggerLeave(ObjectReference akTriggerRef)
    actPasser = akTriggerRef as Actor

    If actPasser == None
        Return
    ElseIf actPasser != Game.GetPlayer() ; NPC着衣
        actPasser.AddItem(armRing, 1, true)
        actPasser.EquipItem(armRing, false, true)
        actPasser.RemoveItem(armRing, 1, true)
    Else ; プレイヤー着衣
        Int intNum = folArmor.GetSize()
        If intNum > 0
            i = 0
            While i < intNum && i < 31
                fomTemp = folArmor.GetAt(i)
                If fomTemp != None && actPasser.GetItemCount(fomTemp) > 0
                    actPasser.EquipItemEx(fomTemp, 0, false, true)
                EndIf
                fomTemp = None
                i += 1
            EndWhile
            folArmor.Revert()
        EndIf

        If fomWepR != None && actPasser.GetItemCount(fomWepR) > 0
            actPasser.EquipItemEx(fomWepR, 1)
        EndIf
        fomWepR = None

        If fomWepL != None && actPasser.GetItemCount(fomWepL) > 0
            actPasser.EquipItemEx(fomWepL, 2)
        EndIf
        fomWepL = None
    EndIf

    actPasser = None
EndEvent

目次に戻る


3. 完全版

本命です。UnEquipAll 版と異なるのは「入る時」の脱衣スクリプトの部分で、「出る時」はまったく同じ記述です。

以下のスクリプトをトリガーボックスに付けて、armRing および folArmor の2つのプロパティだけ指定してください。

Scriptname EkaUndressScript06 extends ObjectReference
{ NPC、プレイヤー脱衣統合版(要SKSE)。トリガーボックスに適用。UnEquipAll 未使用完全版。}

;下記2つのプロパティを指定---
Armor Property armRing Auto ; JewelryRingGold を指定
FormList Property folArmor Auto ; 作成した空の FormList を指定
;-------------------------------

Form Property fomWepL Auto
Form Property fomWepR Auto

Actor actPasser
Form fomTemp
Int i

;--------------------------------------------------入る時
Event OnTriggerEnter(ObjectReference akTriggerRef)
    i = 0
    actPasser = akTriggerRef as Actor

    If actPasser == None
        Return
    ElseIf actPasser != Game.GetPlayer() ; NPC脱衣
        While i < 31
            actPasser.UnequipItemSlot(30 + i)
            i += 1
        EndWhile

        fomTemp = actPasser.GetEquippedObject(1) ; 右手
        If fomTemp != None
            actPasser.UnequipItemEx(fomTemp, 1)
            fomTemp = None
            Utility.Wait(0.01)
        EndIf
        fomTemp = actPasser.GetEquippedObject(0) ; 左手
        If fomTemp != None
            actPasser.UnequipItemEx(fomTemp, 2)
            fomTemp = None
        EndIf
    Else ; プレイヤー脱衣
        If folArmor.GetSize() > 0
            folArmor.Revert()
        EndIf

        While i < 31
            fomTemp = actPasser.GetWornForm(Math.LeftShift(1, i))
            If fomTemp != None
                folArmor.AddForm(fomTemp)
                actPasser.UnequipItemSlot(30 + i)
                fomTemp = None
            EndIf
            i += 1
        EndWhile

        Int intWepTypeR = actPasser.GetEquippedItemType(1) ; 右手武器タイプ
        If intWepTypeR != 0
            fomWepR = actPasser.GetEquippedObject(1) ; 右手武器
            If fomWepR != None
                actPasser.UnequipItemEx(fomWepR, 1) ; 両手武器の時、ここで直前の片手武器が装備される
            EndIf
        EndIf

        Int intWepTypeL = actPasser.GetEquippedItemType(0) ; 左手武器タイプ
        If intWepTypeR == 5 || intWepTypeR == 6 || intWepTypeR == 7 || intWepTypeR == 12 ; 両手装備の時
            fomTemp = actPasser.GetEquippedObject(1) ; 両手装備前の右手装備を外す
            If fomTemp != None
                If actPasser.GetEquippedItemType(1) == 9 ; 魔法
                    actPasser.UnequipSpell(fomTemp as Spell, 1)
                Else
                    actPasser.UnequipItemEx(fomTemp, 1)
                EndIf
                fomTemp = None
                Utility.Wait(0.01)
            EndIf

            fomTemp = actPasser.GetEquippedObject(0) ; 両手装備前の左手装備を外す
            If fomTemp != None
                If intWepTypeL == 9 ; 魔法
                    actPasser.UnequipSpell(fomTemp as Spell, 0)
                ElseIf intWepTypeL == 10 ; 盾が上手く外れないので指定
                    actPasser.UnequipItemSlot(39)
                Else
                    actPasser.UnequipItemEx(fomTemp, 2)
                EndIf
                fomTemp = None
            EndIf
        ElseIf intWepTypeL != 0 && intWepTypeL != 9 && intWepTypeL != 10 ; 魔法は外さない,盾は外し済み
            fomWepL = actPasser.GetEquippedObject(0) ; 左手武器
            If fomWepL != None
                actPasser.UnequipItemEx(fomWepL, 2)
            EndIf
        EndIf
    EndIf

    actPasser = None
EndEvent

;--------------------------------------------------出る時
Event OnTriggerLeave(ObjectReference akTriggerRef)
    actPasser = akTriggerRef as Actor

    If actPasser == None
        Return
    ElseIf actPasser != Game.GetPlayer() ; NPC着衣
        actPasser.AddItem(armRing, 1, true)
        actPasser.EquipItem(armRing, false, true)
        actPasser.RemoveItem(armRing, 1, true)
    Else ; プレイヤー着衣
        Int intNum = folArmor.GetSize()
        If intNum > 0
            i = 0
            While i < intNum && i < 31
                fomTemp = folArmor.GetAt(i)
                If fomTemp != None && actPasser.GetItemCount(fomTemp) > 0
                    actPasser.EquipItemEx(fomTemp, 0, false, true)
                EndIf
                fomTemp = None
                i += 1
            EndWhile
            folArmor.Revert()
        EndIf

        If fomWepR != None && actPasser.GetItemCount(fomWepR) > 0
            actPasser.EquipItemEx(fomWepR, 1)
        EndIf
        fomWepR = None

        If fomWepL != None && actPasser.GetItemCount(fomWepL) > 0
            actPasser.EquipItemEx(fomWepL, 2)
        EndIf
        fomWepL = None
    EndIf

    actPasser = None
EndEvent

ある程度はコメントとして説明を入れておきました。GetEquippedItemType を使って武器のタイプを数字で取得し、条件分岐しています。
処理が重い武器だと両手武器を外した時にほんの一瞬だけ片手武器が表示されてしまいますが、これは防げませんでした。普段は両手武器をメインで使わないので、前回のときは気付きませんでしたよ。

---2018/07/05 追記---
前回の記事と同様、プレイヤー付呪品の装備について修正を行いました。
actPasser.EquipItem(fomTemp, false, true) の部分を
actPasser.EquipItemEx(fomTemp, 0, false, true) に書き換えたものです。
これにより、プレイヤーが付呪した装備品でも、装備の際に付呪効果が適用されるようになっています。
---追記以上---

目次に戻る


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

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


4 件のコメント:

  1. はじめまして 最近SkyrimSEをはじめた者です。
    他の人が公開している家MODを使用していたのですが、着衣すると付呪の効果が反映されないので、CKの使い方を調べながらこちらのスクリプトを使用させていただきました。
    コメントなどが詳しく書いていてくださるのでスクリプトがわからない自分でもどういうことをしているのか理解しやすかったです。

    家のMODを改造して自分好みにしていこうと思っているのですが、オートソート、オートストレージをつけようと"General Stores - Auto Sorting Cloud Storage Resource"を入れてみたのですが、分類が大雑把で、もっと細かく仕分けできればとスクリプトを見たのですが、自分には何をやっているのかわからず。

    本当にあつかましいのですが、もし時間がありオートストレージのMOD等も作れるようでしたら、
    ”General Stores - Auto Sorting Cloud Storage Resource for packrats”見たいなもので分類がもっと細かい物を考えていただけないでしょうか?

    返信削除
    返信
    1. はじめまして!ようこそお越しくださいました。
      付呪効果の件、少しでもヒントになったのなら嬉しいです。長いスクリプトを読んでいただいてありがとうございます。

      オートストレージMODは面白そうですね。今までその系統のMODを使ったことがありませんが、スクリプトは書けそうな気がします。ご紹介いただいたMODのDescriptionを読んでみたところ、12種類のストレージに分類される感じでしょうか。
      自由に配置できるクラウド型オートストレージMODを考想してみます。プロトタイプができるまでしばらくお待ちください!

      削除
  2. こんばんは
    こんな無茶なお願い聞いていただけるとは本当にありがとうございます。
    プロトタイプできるのお待ちします。あまり無理せずに自分のペースでお願いします。

    返信削除
    返信
    1. こんばんは
      色々とバリエーションが思いついて逆に迷っていますが、とりあえずクラウド型を作ってみようと思っています。自由なペースでやりますので、期待しすぎず気長にお待ちを!

      削除

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