「逆引きリファレンス」の編集履歴(バックアップ)一覧に戻る
逆引きリファレンス」を以下のとおり復元します。
この項目ではやりたいことから調べられます。
やり方は一例であって必ずしもということはないので、他のパターンもあればぜひ記載してください。
 
#contents

*ゲーム開始時に魔法やアイテムを自動で追加したい(初期化クエスト)

MOD導入後に自動的にカスタマイズメニューの魔法やアイテムを追加するMODがあります。それのやり方です。
MOD導入後にセーブを読み込んだあとに一回しか動かないクエストです。
例としてカスタマイズメニューの魔法をプレイヤーに追加するクエストを作ります。

まず、Object WindowのCharacterツリーのQuestを選択します。
AchievementsQuestというのがあるので右クリック->Duplicateでコピー。
新規作成だとうまくいかない場合もあるので使えるクエストをコピーします。
コピーしたクエストを開いてIDと名前をつけます。(例:InitQuest)
Priorityは99など高い数値にしておきます。
Start Game EnabledとRun at Onceにチェック。
そのままScriptsのボタンに移動して、要らないスクリプトをすべてRemove。
Addボタン->[New Script]でスクリプト新規作成。
extendsはQuest。

 Spell property CustomMenuSpell(魔法名) auto
 Event oninit()
   Actor player = game.getplayer()
   if !(player.hasspell(CustomMenuSpell))
     player.addspell(CustomMenuSpell)
     self.stop()
  endif
 endEvent 

Oninitは初期化した時に駆動するイベントです。
Oninitは同タイミングで二回読むっぽいので、重複防止のためにCustomMenuSpellを持っていない場合でしかプレイヤーに魔法を追加しません。
Run at Onceのため一度しか起動しないですが、念のためself.Stop()でクエストを止めます。
oninitはActorにつけても動きませんクエストで駆動するようにしましょう。

**ゲームロード度に動くスクリプト
Oninitだと一回だけで、OnLoadは正しく動作しないのでOnPlayerLoadGameを使います(skyrim1.6以上必要)。
ただこれはActorのPlayerにしか返さないので、直接QuestにスクリプトをつけるのではなくAlias(エイリアス)を経由させて使います。

まず、Object WindowのCharacterツリーのQuestを選択します。
AchievementsQuestというのがあるので右クリック->Duplicateでコピー。
コピーしたクエストを開いてIDと名前をつけます。(例:LoadQuest)
Priorityは99など高い数値にしておきます。
Start Game Enabledにチェックが入ってるか確認。
そのままScriptsのボタンに移動して、スクリプトをすべてRemove。
Addボタン->[New Script]でスクリプト新規作成。
extendsはQuest。例ではTestLoadScriptと名前をつけました。

 Scriptname TestLoadScript extends Quest  
 Event OnInit()
 	; 自前の関数
 	LoadFunc()
 EndEvent
 
 ;実際の処理はここに書く
 Function LoadFunc()
 	debug.notification("Hello Work!")
 EndFunction

コンパイルしてスクリプトのウィンドウを閉じる。
Quest Aliasesボタン->右クリック->New Referense Alias
Aliasはplayerとでもしておく。
Unique ActorからPlayerを選ぶ。
ScriptのところをAddボタン->[New Script]でスクリプト新規作成。

 TestLoadScript Property QuestScript Auto
 ; ↑QuestScript名
 Event OnPlayerLoadGame()
 	QuestScript.LoadFunc()
 EndEvent

コンパイルしてスクリプトのウィンドウを閉じる。
Propertyで当クエストの指定も忘れずに。


*常時稼動させるスクリプト
&bold(){※できる限り使わないことを考えぬいてください。}
常時稼働する事自体スクリプト(Papyrus)かそうでないかにかかわらず負荷がかかるために避けたほうが良いです。
とくに&bold(){間隔の短い}OnUpdateによるスクリプト回しは、環境にもよりますがスタックエラーにつながりやすいです。

OnUpdateとRegisterForSingleUpdate()を使います。
RegisterForUpdate()はスタックエラーの原因になりやすいので使いません。
つけたり止めたりしやすいのでクエストかマジックエフェクトで回します。
クエストの作り方は上記2つに書いてあるので省略。
例はプレイヤーがスニーク中かつ灯火使用中の場合は灯火を消します。

 ;(マジックエフェクトの場合はEvent OnEffectStart)
 Event Oninit()
 	RegisterForSingleUpdate(10)
 EndEvent
 Event OnUpdate()
 	;実際の処理はここ
 	player = game.getplayer()
 	if (player.isSneaking()) && (player.HasSpell(Candlelight))
  		DispelSpell(Candlelight)
 	endif
 	;10秒後OnUpdate開始。つまり10秒単位で回る。
 	RegisterForSingleUpdate(10)
 EndEvent

に1秒など短い間隔でループさせると大量にスタックしてCTDの要因や他のスクリプトの遅延になります。
(OnUpdate内の記述によりますが)できれば2秒以上ゆとりを持って設定しましょう。
高速でループさせる必要があるかどうかをよく吟味して、何か単発のイベントで代替できるか探りましょう。


*DLCや特定のespが読み込まれてる場合に処理をする
GetFormFromFile()だと存在しない場合にログにエラーが出てしますのでGetModByName()を使います。
例ではドーンガード。

 if Game.GetModByName("Dawnguard.esm") < 255
    ; ドーンガードがある場合の処理。別のespのフォームIDからFormを取得するには Game.GetFormFromFile(0x00000000,"Dawnguard.esm")
 else ;GetModByNameが255を返した場合読み込まれていません 
    ;ドーンガードがない場合の処理
 endIf


*一度のみ実行
Oninit()などで絶対に一度のみしか走らないで欲しい処理などに

 Bool doOnce = False
 Event Oninit()
 	if (doOnce)
 		return
 	else
 		doOnce = True
 	endif
 	;実際の処理はここ
 EndEvent

*名前

**アクターの名前の取得
対象アクターの名前を取得して左上に表示させたい時に、
debug.notification("ActorName:" + Actor)
とやってもスクリプト名やActorと表示されるだけなので、以下のようにアクターベースから名前を取得します。
debug.notification("ActorName:"+ Actor.GetActorBase().GetName())

#highlight(linenumber,php){{
Actor  actTarget;
String szName;

; 現在のゲーム上で表示されている名前
szName = actTarget.GetDisplayName();

; 表示名の変更に影響されない元の設定名
; レベルドリストから生成されたアクターの場合、空白になる場合がある。
szName = actTarget.GetActorBase().GetName();

; 表示名の変更に影響されない元の設定名
; レベルドリストから生成されたアクターの場合でも、元になったActorBaseの名前が入る。
; 通常のアクターの場合でも使えるので、設定名を取得する場合はこの方が確実。
szName = actTarget.GetLeveledActorBase().GetName();
}}

**場所の名前の取得
場所の名前をセル→ロケーション→ワールドの順に取得する。
屋外などでは、セルやロケーションに名前が設定されていない場合がある為。
celPlaceで指定したセルか、objrefMarkerで指定したリファレンスの場所名を返す。
#highlight(linenumber,php){{
; ----------------------------------------------------------
; @name     getPlaceName
; @function
; @global
; @param    [celPlace=None]     {Cell}
; @param    [objrefMarker=None] {ObjectReference}
; @returns  {String}
; ----------------------------------------------------------
String Function getPlaceName(               \
    Cell            celPlace        = None, \
    ObjectReference objrefMarker    = None  \
) global
    ;-------------------------------------------------------
    ; Init Variables
    ;-------------------------------------------------------
    Location    locMarker;
    WorldSpace  wsMarker;
    String      szName  = "";

    ;-------------------------------------------------------
    ; Check Arguments
    ;-------------------------------------------------------
    If !celPlace && objrefMarker
        celPlace = objrefMarker.GetParentCell();
    Elseif celPlace && !objrefMarker
        objrefMarker = celPlace.GetNthRef(0);
    Endif; !celPlace && objrefMarker

    ;-------------------------------------------------------
    ; Get Cell Name
    ;-------------------------------------------------------
    If celPlace
        szName = celPlace.GetName();
    Endif; celPlace

    ;-------------------------------------------------------
    ; Get Location Name
    ;-------------------------------------------------------
    If (szName == "")
        If objrefMarker
            locMarker = objrefMarker.GetCurrentLocation();
        EndIf; objrefMarker

        If locMarker
            szName = locMarker.GetName();
        Endif; locMarker
    Endif; (szName == "")
    
    ;-------------------------------------------------------
    ; Get World Name
    ;-------------------------------------------------------
    If (szName == "")
        If objrefMarker
            wsMarker = objrefMarker.GetWorldSpace();
        EndIf; objrefMarker

        If wsMarker
            szName = wsMarker.GetName();
        Endif; wsMarker
    Endif; (szName == "")
    
    ;-------------------------------------------------------
    ; Return
    ;-------------------------------------------------------
    return szName;
EndFunction; getPlaceName()
}}

*espファイルのゴミを消す
一度設定してしまったプロパティはespに保存されます。
その後、不要になった場合にそのまま消してしまうとPapyrus.logに以下のようなwarningメッセージを吐くespが出来上がります。
 [12/24/2020 - 00:00:01PM] warning: Property <プロパティ名> on script <スクリプト名> attached to <オブジェクトのEDID> (オブジェクトのformID) cannot be initialized because the script no longer contains that property
espが自身に保存されたプロパティ情報を元に初期化しようとしたがスクリプトには存在しないために出る注意文で、新規ゲームでも関係なくメッセージを出します。
実害は無いですが邪魔な存在である事は確かなのでなるべくなら消しましょう。

-消し方
#ref(clear_value.jpg)
消したいプロパティを選択後clear valueを押し<<defalult>>にする事でespから情報を削除出来ます。
設定後、CKを保存してespを更新するのを忘れないでください。
更新を忘れて、スクリプトからプロパティを削除してしまうと注意文は消えません。
消してしまった場合、一度スクリプトにプロパティを加えてコンパイルし直してください。

なお、これはセーブデータに残ってしまった情報とは違います。
こういうの↓
 12/24/2020 - 01:00:00PM] warning: Could not find type <オブジェクトのEDIDやAlias> in the type table in save
これはセーブデータに残ってしまった情報で確実な方法は発見されていません(2013/07/04現在)

セーブデータに残ったスクリプト情報の残骸は[[Save game script cleaner>http://www.nexusmods.com/skyrim/mods/52363/]]というツールで消せます。


*扉の開錠/施錠

-サンプル: &ref(ExampleUnlockDoor.zip)(動かし方は中にある readme.txt を参照のこと)

扉の施錠判断には [[ObjectReference.IsLocked>http://www.creationkit.com/index.php?title=IsLocked_-_ObjectReference]] を使います。扉の開錠/施錠には [[ObjectReference.Lock>http://www.creationkit.com/index.php?title=Lock_-_ObjectReference]] を使います。
以下は、アクティベートイベントを元に、対象の扉が開いている場合は施錠/閉じている場合は解錠するスクリプトの例です。

 Scriptname ExampleUnlockDoor extends ObjectReference
 
 ObjectReference Property targetDoor Auto
 
 Event OnActivate(ObjectReference akActionRef)
 	if (targetDoor.IsLocked())
 		Debug.Notification("Unlock")
 		targetDoor.Lock(false)
 	else
 		Debug.Notification("Lock")
 		targetDoor.Lock(true)
 	endIf
 endEvent

targetDoor プロパティに事前に対象となる扉を指定する必要があります。
また、Creation Kit にて事前に扉の状態を決めるには Lock タブにある情報を設定します。
以下、スクリーンショットでは鍵を必要とする状態で扉を閉めています。
#ref(set_lock.png)
何らかのイベント等をトリガーに先に進めるようにする場合などに使えます。


*オブジェクトの移動

-サンプル: &ref(ExampleMoveObject.zip)(動かし方は中にある readme.txt を参照のこと)

設置済みのオブジェクトを移動させるには [[ObjectReference.SetPosition>http://www.creationkit.com/index.php?title=SetPosition_-_ObjectReference]] を使います。
以下はアクティベートした対象そのものを後ろへ移動させるスクリプトの例です。

 Scriptname ExampleMoveObject extends ObjectReference  
 
 Event OnActivate(ObjectReference akActionRef)
 	SetPosition(x, y - 128, z)
 endEvent

[[ObjectReference.SetPosition>http://www.creationkit.com/index.php?title=SetPosition_-_ObjectReference]] で指定する座標は、セル内の絶対座標系の値です。
[[ObjectReference>http://www.creationkit.com/index.php?title=ObjectReference_Script]] には現在位置を表す x, y, z プロパティがあるので、それを使って相対位置を指定するのが常套手段です。
向きも変えたい場合は [[ObjectReference.SetAngle>http://www.creationkit.com/index.php?title=SetAngle_-_ObjectReference]] を併用します。

''※ポイント'':この移動方法は、今の座標から徐々に指定の場所へ移動させるものではありません。[[ObjectReference.SetPosition>http://www.creationkit.com/index.php?title=SetPosition_-_ObjectReference]] は、瞬時の移動しかできません。徐々に移動させるには前提として対象が [[Actor>http://www.creationkit.com/index.php?title=Actor_Script]] である必要があります。

*新しいオブジェクトの設置
**簡単な例

-サンプル: &ref(ExampleSetObject.zip)(動かし方は中にある readme.txt を参照のこと)

オブジェクトを新しく設置するには [[ObjectReference.PlaceAtMe>http://www.creationkit.com/index.php?title=PlaceAtMe_-_ObjectReference]] を使います。
第一引数に [[Form>http://www.creationkit.com/index.php?title=Form_Script]] オブジェクトを指定します。
オブジェクト指向熟練者への補足ですが、以下の対比がちょうど当てはまると覚えておくと良いでしょう。
|[[Form>http://www.creationkit.com/index.php?title=Form_Script]] オブジェクト|クラス|
|[[ObjectReference.PlaceAtMe>http://www.creationkit.com/index.php?title=PlaceAtMe_-_ObjectReference]]|new 演算子|
|[[ObjectReference>http://www.creationkit.com/index.php?title=ObjectReference_Script]] オブジェクト|インスタンス|
以下(ExampleSetObject サンプル)はアクティベートする度に WETempActivator が後ろに増えていくスクリプトの例です。

 Scriptname ExampleSetObject extends ObjectReference
 
 Activator Property setObject Auto  
 
 int count = 0
 
 Event OnActivate(ObjectReference akActionRef)
 	count = count + 1
 	ObjectReference newObject = PlaceAtMe(setObject, 1)
 	newObject.SetPosition(x, y -  count * 128, z)
 endEvent

サンプルは WETempActivator を新しく設置するものですが、他のものでも Form オブジェクトがあれば新しいオブジェクトを生成できます。

**スキーヴァーを大量発生させる例

-サンプル: &ref(ExampleSetSkeever.zip)(動かし方は中にある readme.txt を参照のこと)

アクティベートするたびにスキーヴァーが部屋のどこかに設置されるサンプルです。

 Scriptname ExampleSetSkeever extends ObjectReference
 
 ActorBase Property skeever Auto
 
 Event OnActivate(ObjectReference akActionRef)
 	float newx = -1000 + 2000 * Utility.RandomFloat()
 	float newy = -1000 + 2000 * Utility.RandomFloat()
 
 	Actor newActor = PlaceAtMe(skeever, 1) as Actor
 	newActor.SetPosition(newx, newy, z)
 	newActor.StopCombat()
 endEvent

skeever プロパティには「EncSkeever」が設定してあります。何度もアクティベートすれば当然…。
#ref(skeevers.jpg)
囲まれます。

**SpawnerTaskを使用して大量発生させる
SpawnerTaskを使えば、敵やオブジェクトを効率よくスポーンさせることが出来ます。
下記の例では、PCの周囲に一気に出現させています。
#highlight(linenumber,php){{
Bool Function spawnAroundPlayer(Form frmTarget, Int nAddNum = 1)
    ;-------------------------------------------------------
    ; Init Variables
    ;-------------------------------------------------------
    Actor       actPlayer   = Game.GetPlayer();
    Float[]     aPos        = new Float[3];
    Float[]     aRot        = new Float[3];
    Int         nTaskID;
    
    ;-------------------------------------------------------
    ; Spawn
    ;-------------------------------------------------------
    If frmTarget && (nAddNum > 0)
        nTaskID = SpawnerTask.Create();
        SpawnerTask.AddSpawn( \
            nTaskID, frmTarget, actPlayer, aPos, aRot, nAddNum);
        SpawnerTask.Run(nTaskID);
    Endif; frmTarget && (nAddNum > 0)
    
    ;-------------------------------------------------------
    ; Return
    ;-------------------------------------------------------
    return true;
EndFunction; spawnAroundPlayer()
}}

**FormList を使ったランダム設置の例

-サンプル: &ref(ExampleSetRandomObject.zip)(動かし方は中にある readme.txt を参照のこと)

アクティベートするたびに [[FormList>http://www.creationkit.com/index.php?title=FormList_Script]] の中にある何かが部屋のどこかに設置されるサンプルです。

FormList には ObjectWindow の「WorldObjects/Tree/Plants」カテゴリにある植物群が入っており、設置後、素材を採集できます。

 Scriptname ExampleSetRandomObject extends ObjectReference  
 
 FormList Property flowers Auto
 
 Event OnActivate(ObjectReference akActionRef)
 	float newx = -1000 + 2000 * Utility.RandomFloat()
 	float newy = -1000 + 2000 * Utility.RandomFloat()
 
 	Debug.Notification("Activate ... new object (" + newx + ", " + newy + ")")
 
 	ObjectReference newObject = PlaceAtMe(flowers.GetAt(Utility.RandomInt(0, flowers.GetSize() - 1)), 1)
 	newObject.SetPosition(newx, newy, z)
 endEvent

*アクターの移動

**アクターの誘導

-サンプル: &ref(ExampleSkeeverAroundStone.zip)(動かし方は中にある readme.txt を参照のこと)

アクターとは動きまわるオブジェクトのことです。プレイヤーや敵やNPCなどが該当します。
「オブジェクトの移動」で紹介した [[ObjectReference.SetPosition>http://www.creationkit.com/index.php?title=SetPosition_-_ObjectReference]] は瞬時の移動です。誘導には [[Actor.PathToReference>http://www.creationkit.com/index.php?title=PathToReference_-_Actor]] を使います。
誘導する際、移動先のオブジェクトを指定する必要があります。[[ObjectReference>http://www.creationkit.com/index.php?title=ObjectReference_Script]] であれば何でも良いですが、もしも自由に誘導させたいならば XMarker を使うのがお勧めです。

 Scriptname ExampleSkeeverAroundStone extends ObjectReference  
 
 Actor Property skeever Auto
 ObjectReference Property destination Auto
 int angle = 0
 
 Event OnCellLoad()
 	RegisterForSingleUpdate(1)
 endEvent
 
 Event OnUpdate()
 	float distance = skeever.GetDistance(destination)
 	if (distance < 64)
 		angle = angle + 45
 		destination.SetPosition(x + 256 * Math.cos(angle), y + 256 * Math.sin(angle), z)
 	endIf
 	skeever.PathToReference(destination, 0.5)
 
 	RegisterForSingleUpdate(1)
 endEvent

以上のサンプルはスキーヴァーが石碑の周りをぐるぐると回らせるものです。
destination に XMarker をセットし、スキーヴァーの到着を判断して位置を変えていきます。
また、本サンプルは「常時稼動させるスクリプト」のサンプルにもなっています。


**隊列の形成
KeepOffsetFromActor()を使えば、対象のアクターを別のアクターの隣や背後といった定位置に移動させることが出来る。
隊列の形成などは、この手法が使われていることが多い。

#highlight(linenumber,php){{
Actor actTarget;
Actor actFollow;

actTarget.KeepOffsetFromActor(  \
    actFollow,                  \
    170.0, -170.0, 0.0,         \
    afCatchUpRadius = 260.0,    \
    afFollowRadius  = 8.0       );
}}

*倒した敵からコンテナードロップ

-サンプル: &ref(ExampleDropChest.zip)(動かし方は中にある readme.txt を参照のこと)

敵を倒した際、コンテナーをドロップさせてアイテムをゲットできるようにしてみましょう。
方法は簡単です。[[Actor.OnDeath>http://www.creationkit.com/index.php?title=OnDeath_-_Actor]] イベントで敵が倒されたタイミングを見計らい
-コンテナーを設置
-敵を排除
するだけです。以下、事例です。

 Scriptname ExampleDropChest extends ObjectReference  
 
 Container Property BaseChest Auto
 
 Event OnDeath(Actor akKiller)
 	ObjectReference chest = PlaceAtMe(BaseChest, 1)
 	Disable(false)
 	Delete()
 	chest.SetAngle(0, 0, chest.z)
 EndEvent

BaseChest に事前にドロップさせるコンテナーをセットしておく必要があります。
コンテナーを設置したら、敵本体を即時に無効にして削除します。
サンプルではスキーヴァー(EncSkeever)がフィールドにいます。倒すと空の宝箱(TreasDraugrChestEMPTYSmall)がドロップします。
最後にアングルを変えているのは、敵が死亡時、横たわるのでそれに合わせて宝箱も傾いてしまうのを補正するためです。

*キルムーブ時のイベントの取得
要:SKSE

 Event Init()
 	RegisterForCameraState();まず別のイベントで登録する
 EndEvent
 
 Event OnPlayerCameraState()
 	if newState == 2 ;キルムーブのカメラ切り替え
 		
 	EndIf
 EndEvent

*NPCのインベントリから見えない装備を外す方法
単に今着ている装備を外すだけだと、ロードを挟んだ際に元々着ていた服に戻ります。
これを防ぐためには透明な装備を登録したOutfitをSetすればよいです。
価値を0にしておけば別の装備を渡したときにそちらを優先してきてくれます。
なおOutfitをSetすると元の服装に戻らなくなるため、予め回収しておくのもよいでしょう。

 Outfit Property NakedOutfit Auto ; AAの無い装備を一つ登録したOutfit
 
 Function ExampleFunction(Actor akNPC)
 	; 単に今着ている装備を外したい場合
 	akNPC.UnequipAll()
 	akNPC.RemoveAllItems()
 	; アイテムを回収したい場合は自分を指定
 	; akNPC.RemoveAllItems(Game.GetPlayer())
 
 	; 恒久的に装備を外してしまいたい場合
 	akNPC.SetOutfit(NakedOutfit)
 EndFunction

*ラグドール状態の取得
ラグドールはフスロダなどで吹っ飛んでいるとき、または死亡時の手足がブラブラした状態のことです。
判定方法は二通りありますが片方はアクターが『フロスダやマヒ等で倒れているか』を判定する時に使い、
もう片方はオブジェクトが重力の影響下や固定されてるオブジェであるかの判定に使う事を推奨します。(理由は後述)

**powerofthree's Papyrus ExtenderのGetActorKnockState関数を使う

こちらは対象がアクターでより正確にラグドール状態を取得したい場合に有効となります。
GetActorKnockState関数はアクターがフロスダやマヒ(あるいはPushActorAway)等で倒れてラグドール状態になり、起き上がりが終わるまでは0以外を返します。
ただし、あくまで死亡以外の要因でラグドール状態になった時に判定するためのもので、死亡が原因でラグドールになった場合はGetActorKnockStateは0を返すためIsDeadによるチェックも必要です。
(マヒ状態や吹っ飛んでる途中で死亡した場合はGetActorKnockStateは0以外を返します)

#highlight(linenumber,php){{
; ----------------------------------------------------------
; @name     isInRagdollActor
; @desc     対象の人物がフロスダ等によるラグドール影響下にあるかを返す
; @function
; @global
; @param    actTarget           {Actor} 対象の人
; @param    isDeadRagdollCheck  {Bool}  死亡からラグドール状態に移行した場合を考慮するか
; @returns  {Bool}               影響下にあればtrue
; ----------------------------------------------------------
Bool Function isInRagdollActor(Actor actTarget, Bool isDeadRagdollCheck = true) global
    ;-------------------------------------------------------
    ; Init Variables
    ;-------------------------------------------------------
    Bool isInRagdoll = false;
    
    ;-------------------------------------------------------
    ; Checking Ragdoll Status
    ;-------------------------------------------------------
    If actTarget 
        ; 死亡時にラグドール状態に移行する場合はGetActorKnockStateは0を返すため
        ; 従来のGetMass関数による判定と同じ挙動を行いたい時はIsDeadのチェックを加える
        If (PO3_SKSEFunctions.GetActorKnockState(actTarget) != 0)
            isInRagdoll = true
        ElseIf isDeadRagdollCheck
            isInRagdoll = actTarget.IsDead()
        EndIf
    Endif; actTarget

    ;-------------------------------------------------------
    ; Return
    ;-------------------------------------------------------
    return isInRagdoll;
EndFunction; isInRagdollActor()
}}

**GetMass関数を使う(従来のやり方、SE版ではアクターに対しては非推奨)
アクターが吹っ飛んでいるかの判定では最もメジャーな方法でしたが、[[Precision>https://www.nexusmods.com/skyrimspecialedition/mods/72347]]の登場により事情が変わりました。
このMod環境下では武器攻撃の判定をより正確な判定にするのにHavok衝突判定を使うため、アクターに対してアクティブラグドールというものを付与されるようになります。
その影響でこのModの環境下の場合はアクターがラグドール状態でなくてもGetMassが0以外を返すようになります。
そのため、Precision環境下でアクターがふっ飛ばされてラグドールになってるかをGetMass関数で判定すると問題が発生する可能性があるため注意が必要です。

Precision環境でない場合はアクターに対するGetMass関数は通常時は常に0を返しますが、ラグドール中だけは設定されているラグドールの計算に使う重量(Mass)を返します。
※フロスダなどで吹っ飛んでから静止すると起き上がりモーションが発生しますが、このモーション中もラグドール扱いとして0以外を返します。

例:
 if Game.GetPlayer().GetMass() == 0 ;ラグドール中じゃないとき
 	debug.SendAnimationEvent(Game.GetPlayer(),"staggerStart")
 endif

#highlight(linenumber,php){{
; ----------------------------------------------------------
; @name     isInRagdoll
; @desc     対象の人や物がラグドール影響下にあるかを返す
; @function
; @global
; @param    obrfThis  {ObjectReference} 対象の人や物
; @returns  {Bool}                      影響下にあればtrue
; ----------------------------------------------------------
Bool Function isInRagdoll(ObjectReference obrfThis) global
    ;-------------------------------------------------------
    ; Init Variables
    ;-------------------------------------------------------
    Bool isInRagdoll = false;

    ;-------------------------------------------------------
    ; Checking Ragdoll Status
    ;-------------------------------------------------------
    If obrfThis && (obrfThis.GetMass() != 0)
        isInRagdoll = true;
    Endif; obrfThis && (obrfThis.GetMass() != 0)

    ;-------------------------------------------------------
    ; Return
    ;-------------------------------------------------------
    return isInRagdoll;
EndFunction; isInRagdoll()
}}

**ラグドール中のモーション再生によるバグ
ラグドール中あるいは起き上がってる途中に別のモーションを再生すると、その場で固定されて行動不能になるバグがあります。ラグドール中は基本的に別のモーションでは割り込めないですが、ドラウグルはよろめき(StaggerStart)が割り込めてしまうので、上記の条件で除外しましょう。

*十進数と十六進数の変換
Papyrusには、こういった標準的な関数がないので不便する場合がある。

**十進数→十六進数
#highlight(linenumber,php){{
; ----------------------------------------------------------
; @name     convDecToHex
; @desc     整数値を十六進数表記の文字列に変換
; @function
; @global
; @param    nNum    {Int}   変換したい整数値
; @returns  {String}        十六進数表記の文字列
; ----------------------------------------------------------
String Function convDecToHex(Int nNum) global
    ;-------------------------------------------------------
    ; Init Variables
    ;-------------------------------------------------------
    String   szHex;
    Bool     isNegative;
    Int[]    aNums = new Int[8];
    String[] aHex  = new String[8];
    Int      nIdx  = 0;
    Int      nLen  = aNums.Length;

    ;-------------------------------------------------------
    ; Checking over 0x80000000
    ;-------------------------------------------------------
    If (nNum < 0)
        isNegative = True;

        nNum += 0x80000000;
    Endif

    ;-------------------------------------------------------
    ; Parse integer
    ;-------------------------------------------------------
    aNums[0] = (nNum / 0x10000000);
    nNum    -= (aNums[0] * 0x10000000);
    aNums[1] = (nNum / 0x01000000);
    nNum    -= (aNums[1] * 0x01000000);
    aNums[2] = (nNum / 0x00100000);
    nNum    -= (aNums[2] * 0x00100000);
    aNums[3] = (nNum / 0x00010000);
    nNum    -= (aNums[3] * 0x00010000);
    aNums[4] = (nNum / 0x00001000);
    nNum    -= (aNums[4] * 0x00001000);
    aNums[5] = (nNum / 0x00000100);
    nNum    -= (aNums[5] * 0x00000100);
    aNums[6] = (nNum / 0x00000010);
    nNum    -= (aNums[6] * 0x00000010);
    aNums[7] = nNum;

    ;-------------------------------------------------------
    ; Convert to HEX
    ;-------------------------------------------------------
    If isNegative
        aNums[0] = aNums[0] + 8;
    Endif

    While (nIdx < nLen)
        If (aNums[nIdx] == 10)
            aHex[nIdx] = "A";
        Elseif (aNums[nIdx] == 11)
            aHex[nIdx] = "B";
        Elseif (aNums[nIdx] == 12)
            aHex[nIdx] = "C";
        Elseif (aNums[nIdx] == 13)
            aHex[nIdx] = "D";
        Elseif (aNums[nIdx] == 14)
            aHex[nIdx] = "E";
        Elseif (aNums[nIdx] == 15)
            aHex[nIdx] = "F";
        Else
            aHex[nIdx] = (aNums[nIdx] as String);
        Endif

        nIdx += 1;
    EndWhile

    ;-------------------------------------------------------
    ; Join characters
    ;-------------------------------------------------------
    szHex   = aHex[0] + aHex[1] + aHex[2] + aHex[3] \
            + aHex[4] + aHex[5] + aHex[6] + aHex[7];
    
    ;-------------------------------------------------------
    ; Return
    ;-------------------------------------------------------
    return szHex;
EndFunction; convDecToHex()
}}

**十六進数→十進数
#highlight(linenumber,php){{
; ----------------------------------------------------------
; @name     convHexToDec
; @desc     十六進数表記の文字列を整数値で応答
; @function
; @global
; @param    szHex   {String}    十六進数表記の文字列
; @returns  {Int}               変換した整数値
; ----------------------------------------------------------
Int Function convHexToDec(String szHex) global
    ;-------------------------------------------------------
    ; Init Variables
    ;-------------------------------------------------------
    Int     nIdx = 0;
    Int     nLen = StringUtil.GetLength(szHex);
    String  cChar;
    Int     nNum;
    Int     nRet;
    
    ;-------------------------------------------------------
    ; Parse Hex-String
    ;-------------------------------------------------------
    While (nIdx < nLen)
        cChar = StringUtil.GetNthChar(szHex, nIdx);
        
        If StringUtil.IsDigit(cChar)
            nNum = cChar as Int;
        Elseif (cChar == "A") || (cChar == "a")
            nNum = 10;
        Elseif (cChar == "B") || (cChar == "b")
            nNum = 11;
        Elseif (cChar == "C") || (cChar == "c")
            nNum = 12;
        Elseif (cChar == "D") || (cChar == "d")
            nNum = 13;
        Elseif (cChar == "E") || (cChar == "e")
            nNum = 14;
        Elseif (cChar == "F") || (cChar == "f")
            nNum = 15;
        Else
            nNum= 0;
        Endif

        nNum = (nNum * Math.pow(16, (nLen - (nIdx + 1)))) as Int;

        nRet += nNum;
        nIdx += 1
    EndWhile

    ;-------------------------------------------------------
    ; Return
    ;-------------------------------------------------------
    return nRet;
EndFunction; convHexToDec()
}}

*攻撃側と防御側の位置と角度判定
バックスタブなどのMODで使われる手法。二者の相対的な距離と角度から判定している。
#highlight(linenumber,php){{
; ----------------------------------------------------------
; @name     getAttackAngle
; @desc     攻撃側と防御側の向きと距離のタイプを返す
; @function
; @global
; @param    actAtk              {Actor} 攻撃側の人
; @param    actDef              {Actor} 防御側の人
; @param    [nCloseRange=170.0] {Float} 近接と判断する距離限界
; @param    [nFrontAngle=44.0]  {Float} 正面と判断する角度限界
; @param    [nRearAngle=125.0]  {Float} 背面と判断する角度限界
; @returns  {Int}
;           距離のタイプとして、以下を返す
;           -1 : 以下のどれでもない、または処理エラー
;           11 : 正面近距離
;           12 : 背面近距離
;           21 : 正面遠距離
;           22 : 背面遠距離
; ----------------------------------------------------------
Int Function getAttackAngle(        \
    Actor actAtk,                   \
    Actor actDef,                   \
    Float nCloseRange   = 170.0,    \
    Float nFrontAngle   = 44.0,     \
    Float nRearAngle    = 125.0     \
) global
    ;-------------------------------------------------------
    ; Init Variables
    ;-------------------------------------------------------
    Int     nRet = -1;
    Float   nFaceMin;
    Float   nFaceMax;
    Float   nRearMin;
    Float   nRearMax;
    Float   nDist;
    Float   nAngleAtk;
    Float   nAngleDef;

    ;-------------------------------------------------------
    ; Check Arguments
    ;-------------------------------------------------------
    If !actAtk || !actDef || (actAtk == actDef)
        return nRet;
    Endif; !actAtk || !actDef || (actAtk == actDef)

    If (nCloseRange < 0.0)
        nCloseRange *= -1.0;
    Endif; (nCloseRange < 0.0)

    If (nFrontAngle < 0.0)
        nFrontAngle *= -1.0;
    Endif; (nFrontAngle < 0.0)

    If (nFrontAngle > 90.0)
        nFrontAngle = 90.0;
    Endif; (nFrontAngle > 90.0)

    If (nRearAngle < 0.0)
        nRearAngle *= -1.0;
    Endif; (nRearAngle < 0.0)

    If (nRearAngle < 90.0)
        nRearAngle = 90.0;
    Elseif (nRearAngle > 180.0)
        nRearAngle = 180.0;
    Endif; (nRearAngle < 90.0)

    ;-------------------------------------------------------
    ; Init Range Values
    ;-------------------------------------------------------
    nFaceMin = nFrontAngle * -1.0;
    nFaceMax = nFrontAngle;
    nRearMin = nRearAngle * -1.0;
    nRearMax = nRearAngle;

    ;-------------------------------------------------------
    ; Get Distance and Angles
    ;-------------------------------------------------------
    nDist       = actAtk.GetDistance(actDef);
    nAngleAtk   = actAtk.GetHeadingAngle(actDef);
    nAngleDef   = actDef.GetHeadingAngle(actAtk);

    ;-------------------------------------------------------
    ; Check Distance
    ;-------------------------------------------------------
    If (nDist <= nCloseRange)
        nRet = 10;
    Else
        nRet = 20;
    Endif; (nDist <= nCloseRange)

    ;-------------------------------------------------------
    ; Check Defender Angle
    ;-------------------------------------------------------
    If (nAngleAtk >= nFaceMin) && (nAngleAtk <= nFaceMax)
        If (nAngleDef >= nFaceMin)  \
        && (nAngleDef <= nFaceMax)
            nRet += 1;
        Elseif (nAngleDef <= nRearMin) \
        ||     (nAngleDef >= nRearMax)
            nRet += 2;
        Else
            nRet = -1;
        Endif; (nDist <= nCloseRange) && ...
    Else
        nRet = -1;
    Endif; (nAngleAtk >= nFaceMin) && ...

    ;-------------------------------------------------------
    ; Return
    ;-------------------------------------------------------
    return nRet;
EndFunction; getAttackAngle()
}}

*コンソールやクロスヘアで選択した対象を取得
コンソールやクロスヘアで選択中のオブジェクトのリファレンスを取得したい場合の処理。
Game.GetCurrentConsoleRef()は昔のSKSEではサポートしていなかった関数なので、念の為にバージョンをチェックしている。
#highlight(linenumber,php){{
; ----------------------------------------------------------
; @name     getObjectSelected
; @desc     選択中のオブジェクトを取得する
; @function
; @global
; @param    [enableCrosshair=True]  {Bool}
;           クロスヘア選択を有効にする
; @param    [enableConsole=True]    {Bool}
;           コンソール選択を有効にする
; @returns  {ObjectReference}
;           取得した収納オブジェクト
; ----------------------------------------------------------
ObjectReference Function getObjectSelected( \
    Bool enableCrosshair  = True,           \
    Bool enableConsole    = True            \
) global
    ;-------------------------------------------------------
    ; Init Variables
    ;-------------------------------------------------------
    ObjectReference obrfFind;
    Int             nSkseVer = SKSE.GetScriptVersionRelease();
    
    ;-------------------------------------------------------
    ; Console selected
    ;-------------------------------------------------------
    If !obrfFind && enableConsole && (nSkseVer > 47)
        obrfFind = \
            Game.GetCurrentConsoleRef() as ObjectReference;
    Endif
    
    ;-------------------------------------------------------
    ; Crosshair
    ;-------------------------------------------------------
    If !obrfFind && enableCrosshair
        obrfFind = \
            Game.GetCurrentCrosshairRef() as ObjectReference;
    Endif
    
    ;-------------------------------------------------------
    ; Return
    ;-------------------------------------------------------
    Return obrfFind;
EndFunction; getObjectSelected()
}}

*ゲーム内の時間取得
Utility.GetCurrentGameTime()でゲーム内の経過日数を取得してから計算する。

**ゲーム内時間の週を数値で返す
#highlight(linenumber,php){{
; ----------------------------------------------------------
; @name     getCurrentWeekIdx
; @desc     ゲーム内時間の週を数値で返す
; @function
; @global
; @returns  {Int}   週を示す整数値(0 - 6)
; ----------------------------------------------------------
Int Function getCurrentWeekIdx() global
    ;-------------------------------------------------------
    ; Init Variables
    ;-------------------------------------------------------
    Float   nGameTime   = Utility.GetCurrentGameTime();
    Int     nDays       = Math.Floor(nGameTime);
    Int     nWeeks      = Math.Floor(nDays / 7);
    Int     nWeekIdx    = nDays - (nWeeks * 7);

    ;-------------------------------------------------------
    ; Return
    ;-------------------------------------------------------
    return nWeekIdx;
EndFunction; getCurrentWeekIdx()
}}

**ゲーム内時間の時間を数値で返す
#highlight(linenumber,php){{
; ----------------------------------------------------------
; @name     getCurrentHour
; @desc     ゲーム内時間の時間を数値で返す
; @function
; @global
; @returns  {Int}   時間を示す整数値(0 - 23)
; ----------------------------------------------------------
Int Function getCurrentHour() global
    ;-------------------------------------------------------
    ; Init Variables
    ;-------------------------------------------------------
    Float   nGameTime   = Utility.GetCurrentGameTime();
    Int     nDays       = Math.Floor(nGameTime);
    Int     nHours      = Math.Floor((nGameTime - nDays) * 24);

    ;-------------------------------------------------------
    ; Return
    ;-------------------------------------------------------
    return nHours;
EndFunction; getCurrentHour()
}}

*判定処理
様々な判定を行う処理の例。

**対象の人が敵性であるかを返す
この例では、敵と判定する為の3つの条件を組み合わせている。
#highlight(linenumber,php){{
; ----------------------------------------------------------
; @name     isEnemy
; @desc     対象の人が敵性であるかを返す
; @function
; @global
; @param    actEnemy            {Actor} 対象の人
; @param    [actTarget=None]    {Actor}
;           誰に対する敵かを指定(None時はプレイヤーに対する敵)
; @returns  {Bool}                      敵性であればtrue
; ----------------------------------------------------------
Bool function isEnemy(Actor actEnemy, Actor actTarget = None) global
    ;-------------------------------------------------------
    ; Init Variables
    ;-------------------------------------------------------
    Bool    isEnemy = false;
    Int     nReaction;
    Int     nRank;

    ;-------------------------------------------------------
    ; Check Argument
    ;-------------------------------------------------------
    If !actEnemy
        return isEnemy;
    Elseif !actTarget
        actTarget = Game.GetPlayer();
    Endif; !actEnemy

    ;-------------------------------------------------------
    ; Check Actor
    ;-------------------------------------------------------
    If (actEnemy == actTarget)
        return isEnemy;
    Endif; (actEnemy == actTarget)

    ;-------------------------------------------------------
    ; Check Hostile
    ;-------------------------------------------------------
    If !isEnemy
        isEnemy = actEnemy.IsHostileToActor(actTarget);
    Endif; !isEnemy

    ;-------------------------------------------------------
    ; Check Reaction
    ;-------------------------------------------------------
    If !isEnemy
        ; Obtains this actors faction-based reaction 
        ; to the other actor
        ; 0 - Neutral
        ; 1 - Enemy
        ; 2 - Ally
        ; 3 - Friend
        nReaction   = actEnemy.getFactionReaction(actTarget);
        isEnemy     = (nReaction == 1);
    Endif; !isEnemy

    ;-------------------------------------------------------
    ; Check Relationship
    ;-------------------------------------------------------
    If !isEnemy
        ; Relationship functions use the following values:
        ; 4 - Lover
        ; 3 - Ally
        ; 2 - Confidant
        ; 1 - Friend
        ; 0 - Acquaintance
        ; -1 - Rival
        ; -2 - Foe
        ; -3 - Enemy
        ; -4 - Archnemesis
        nRank   = actEnemy.GetRelationshipRank(actTarget);
        isEnemy = (nRank <= -2);
    Endif; !isEnemy

    ;-------------------------------------------------------
    ; Return
    ;-------------------------------------------------------
    return isEnemy;
EndFunction; isEnemy()
}}

**対象の人がフォロワーであるかを返す
フォロワーMODを使用している場合では、判定条件が異なるかも知れない。
#highlight(linenumber,php){{
; ----------------------------------------------------------
; @name     isFollower
; @desc     対象の人がフォロワーであるかを返す
; @function
; @global
; @param    actTarget   {Actor} 対象の人
; @returns  {Bool}              フォロワーであればtrue
; ----------------------------------------------------------
Bool Function isFollower(Actor actTarget) global
    ;-------------------------------------------------------
    ; Init Variables
    ;-------------------------------------------------------
    Faction[]   aFollower;
    Bool        isFollower = false;

    ;-------------------------------------------------------
    ; Get Factions
    ;-------------------------------------------------------
    ; CurrentFollowerFaction    0x5C84E
    ; CurrentHireling           0xBD738
    aFollower       = new Faction[2];
    aFollower[0]    = Game.GetForm(0x5C84E) As Faction;
    aFollower[1]    = Game.GetForm(0xBD738) As Faction;

    ;-------------------------------------------------------
    ; Check Factions
    ;-------------------------------------------------------
    If actTarget.IsInFaction(aFollower[0]) \
    || actTarget.IsInFaction(aFollower[1])
        isFollower = true;
    Endif; actTarget.IsInFaction(aFollower[0]) || ...

    ;-------------------------------------------------------
    ; Return
    ;-------------------------------------------------------
    return isFollower;
EndFunction; isFollower()
}}

**対象の人が魔法使いであるかを返す
この例では、戦闘スタイルで魔法使いかを判定している。
この判定条件が有効かどうかは、使う場面による。
#highlight(linenumber,php){{
; ----------------------------------------------------------
; @name     isMagicUser
; @desc     対象の人が魔法使いであるかを返す
; @function
; @global
; @param    actTarget   {Actor} 対象の人
; @returns  {Bool}              魔法使いであればtrue
; ----------------------------------------------------------
Bool Function isMagicUser(Actor actTarget) global
    ;-------------------------------------------------------
    ; Init Variables
    ;-------------------------------------------------------
    ActorBase   abTarget    = actTarget.GetLeveledActorBase();
    CombatStyle csTarget    = abTarget.GetCombatStyle();
    Float       nMeleeMult  = csTarget.GetMeleeMult();
    Float       nMagicMult  = csTarget.GetMagicMult();
    Float       nRangedMult = csTarget.GetRangedMult();
    Bool        isMagicUser = false;
    
    ;-------------------------------------------------------
    ; Check
    ;-------------------------------------------------------
    If (nMagicMult > nMeleeMult) || (nMagicMult > nRangedMult)
        isMagicUser = true;
    Endif; (nMagicMult > nMeleeMult) || (nMagicMult > nRangedMult)
    
    ;-------------------------------------------------------
    ; Return
    ;-------------------------------------------------------
    return isMagicUser;
EndFunction; isMagicUser()
}}

**対象の人がクリーチャーであるかを返す
この例では、人間タイプでないことをクリーチャーの条件としている。
MODで、ActorTypeCreatureのキーワードがないクリーチャーが多い為。
良し悪しあるので、ケェス・バイ・ケェスではある。
#highlight(linenumber,php){{
; ----------------------------------------------------------
; @name     isCreature
; @desc     対象の人がクリーチャーであるかを返す
; @function
; @global
; @param    actTarget   {Actor} 対象の人
; @returns  {Bool}              クリーチャーであればtrue
; ----------------------------------------------------------
Bool Function isCreature(Actor actTarget) global
    ;-------------------------------------------------------
    ; Init Variables
    ;-------------------------------------------------------
    ActorBase   abTarget    = actTarget.GetLeveledActorBase();
    Int         nSex        = abTarget.GetSex();
    Bool        isCreature  = false;
    
    ;-------------------------------------------------------
    ; Check Keyword
    ;-------------------------------------------------------
    If !actTarget.HasKeywordString("ActorTypeNPC")
        isCreature = true;
    Elseif (nSex == -1)
        isCreature = true;
    Endif; !actTarget.HasKeywordString("ActorTypeNPC")
    
    ;-------------------------------------------------------
    ; Return
    ;-------------------------------------------------------
    return isCreature;
EndFunction; isCreature()
}}

**対象の人が人間男性であるかを返す
#highlight(linenumber,php){{
; ----------------------------------------------------------
; @name     isMale
; @desc     対象の人が人間男性であるかを返す
; @function
; @global
; @param    actTarget   {Actor} 対象の人
; @returns  {Bool}              人間男性であればtrue
; ----------------------------------------------------------
Bool Function isMale(Actor actTarget) global
    ;-------------------------------------------------------
    ; Init Variables
    ;-------------------------------------------------------
    ActorBase   abTarget    = actTarget.GetLeveledActorBase();
    Int         nSex        = abTarget.GetSex();
    Bool        isMale      = false;
    
    ;-------------------------------------------------------
    ; Check Keyword
    ;-------------------------------------------------------
    If !actTarget.HasKeywordString("ActorTypeNPC")
        isMale = false;
    Elseif (nSex == 0)
        isMale = true;
    Endif; !actTarget.HasKeywordString("ActorTypeNPC")
    
    ;-------------------------------------------------------
    ; Return
    ;-------------------------------------------------------
    return isMale;
EndFunction; isMale()
}}

**対象の人が人間女性であるかを返す
#highlight(linenumber,php){{
; ----------------------------------------------------------
; @name     isFemale
; @desc     対象の人が人間女性であるかを返す
; @function
; @global
; @param    actTarget   {Actor} 対象の人
; @returns  {Bool}              人間女性であればtrue
; ----------------------------------------------------------
Bool Function isFemale(Actor actTarget) global
    ;-------------------------------------------------------
    ; Init Variables
    ;-------------------------------------------------------
    ActorBase   abTarget    = actTarget.GetLeveledActorBase();
    Int         nSex        = abTarget.GetSex();
    Bool        isFemale    = false;
    
    ;-------------------------------------------------------
    ; Check Keyword
    ;-------------------------------------------------------
    If !actTarget.HasKeywordString("ActorTypeNPC")
        isFemale = false;
    Elseif (nSex == 1)
        isFemale = true;
    Endif; !actTarget.HasKeywordString("ActorTypeNPC")
    
    ;-------------------------------------------------------
    ; Return
    ;-------------------------------------------------------
    return isFemale;
EndFunction; isFemale()
}}

**対象の人が戦闘継続可能であるかを返す
その瞬間に継続可能かどうかの判定。GetMass()はラグドール状態かの判定。
#highlight(linenumber,php){{
; ----------------------------------------------------------
; @name     canCombat
; @desc     対象の人が戦闘継続可能であるかを返す
; @function
; @global
; @param    [actTarget=None]    {Actor}
;           対象の人 (None時はプレイヤーが対象)
; @returns  {Bool}                      
;           戦闘継続可能であればtrue
; ----------------------------------------------------------
Bool Function canCombat(Actor actTarget = None) global
    ;-------------------------------------------------------
    ; Init Variables
    ;-------------------------------------------------------
    Bool canCombat = true;

    ;-------------------------------------------------------
    ; Checking Actor
    ;-------------------------------------------------------
    If !actTarget
        actTarget = Game.GetPlayer();
    Endif; !actTarget

    ;-------------------------------------------------------
    ; Checking Keywords
    ;-------------------------------------------------------
    If !actTarget.Is3DLoaded()      \
    || actTarget.IsDisabled()       \
    || actTarget.IsDead()           \
    || actTarget.IsUnconscious()    \
    || actTarget.IsBleedingOut()    \
    || (actTarget.GetMass() != 0)
        canCombat = false;
    Endif; !actTarget.Is3DLoaded() || ...

    ;-------------------------------------------------------
    ; Return
    ;-------------------------------------------------------
    return canCombat;
EndFunction; canCombat()
}}

**パワーアタック判定
スプリント攻撃以外はアニメーション変数「bAllowRotation」で判定できる。
#highlight(linenumber,php){{
; Animation event, sent when an object we are listening 
; to hits one of the events we are listening for 
Event OnAnimationEvent(ObjectReference akSource, string asEventName)
    ;-------------------------------------------------------
    ; Init Variables
    ;-------------------------------------------------------
    Actor   actTarget   = akSource as Actor;
    Bool    isPowerAtk  = true;

    ;-------------------------------------------------------
    ; Check Power Attack
    ;-------------------------------------------------------
    If (asEventName == "weaponSwing") \
    || (asEventName == "weaponLeftSwing")
        isPowerAtk =                            \
            actTarget.GetAnimationVariableBool( \
                "bAllowRotation"                );
    Endif; (szEvent == "weaponSwing") || ...
EndEvent; OnAnimationEvent()
}}

***The Ultimate Dodge Mod か Nemesis使用環境の場合
The Ultimate Dodge Modを使用している場合か、
アニメーション管理ツールのNemesis実行時に「The Ultimate Dodge Mod」にチェックを入れて処理した場合、人間NPCのアニメーションから受信できるAnimationEventが増える。
通常攻撃時は"NextAttackInitiate"、パワーアタック時は"NextPowerAttackInitiate"が発生する。
(スプリントのパワーアタック時も"NextPowerAttackInitiate"が発生する)

#highlight(linenumber,php){{
Event OnAnimationEvent(ObjectReference akSource, string asEventName)
    ;-------------------------------------------------------
    ; Init Variables
    ;-------------------------------------------------------
    Bool    isPowerAtk  = false;

    ;-------------------------------------------------------
    ; Check Power Attack
    ;-------------------------------------------------------
    If (asEventName == "NextAttackInitiate")
        isPowerAtk = false
    ElseIf (asEventName == "NextPowerAttackInitiate")
        isPowerAtk = true
    Endif; (asEventName == "NextAttackInitiate") ElseIf ...
EndEvent; OnAnimationEvent()
}}

**設備や器具の判定
設備や器具であるかを判定する為の処理例。
基本的には、キーワードで判定することが可能。
椅子などは、キーワードで判定できない場合もあるので注意。
#highlight(linenumber,php){{
; ----------------------------------------------------------
; @name     isSittingObject
; @desc     対象のオブジェクトが座るタイプの家具かどうか
; @function
; @global
; @param    obrfTarget  {ObjectReference}   対象のオブジェクト
; @returns  {Bool}
;           座るタイプの家具の場合はtrue
; ----------------------------------------------------------
Bool Function isSittingObject(ObjectReference obrfTarget) global
    ;-------------------------------------------------------
    ; Init Variables
    ;-------------------------------------------------------
    Bool isObject   = false;
    Form frmTarget  = obrfTarget.GetBaseObject();

    ;-------------------------------------------------------
    ; Check the name in the name list
    ;-------------------------------------------------------
    ; IsTable [KYWD:0009B9A9]
    ; isBarStool [KYWD:00074EC7]
    If frmTarget.HasKeywordString("IsTable") \
    || frmTarget.HasKeywordString("isBarStool")
        isObject = true;
    Endif; frmTarget.HasKeywordString("IsTable") || ...

    ;-------------------------------------------------------
    ; Return
    ;-------------------------------------------------------
    return isObject;
EndFunction; isSittingObject()

; ----------------------------------------------------------
; @name     isSleepingObject
; @desc     対象のオブジェクトが寝るタイプの家具かどうか
; @function
; @global
; @param    obrfTarget  {ObjectReference}   対象のオブジェクト
; @returns  {Bool}
;           寝るタイプの家具の場合はtrue
; ----------------------------------------------------------
Bool Function isSleepingObject(ObjectReference obrfTarget) global
    ;-------------------------------------------------------
    ; Init Variables
    ;-------------------------------------------------------
    Bool isObject  = false;
    Form frmTarget = obrfTarget.GetBaseObject();

    ;-------------------------------------------------------
    ; Check the name in the name list
    ;-------------------------------------------------------
    ; FurnitureBedRoll [KYWD:000E4AD6]
    If frmTarget.HasKeywordString("FurnitureBedRoll")
        isObject = true;
    Endif; frmTarget.HasKeywordString("FurnitureBedRoll")

    ;-------------------------------------------------------
    ; Return
    ;-------------------------------------------------------
    return isObject;
EndFunction; isSleepingObject()

; ----------------------------------------------------------
; @name     isAlchemyLab
; @desc     対象のオブジェクトが錬金器具かどうか
; @function
; @global
; @param    obrfTarget  {ObjectReference}   対象のオブジェクト
; @returns  {Bool}
;           錬金器具の場合はtrue
; ----------------------------------------------------------
Bool Function isAlchemyLab(ObjectReference obrfTarget) global
    ;-------------------------------------------------------
    ; Init Variables
    ;-------------------------------------------------------
    Bool isObject   = false;
    Form frmTarget  = obrfTarget.GetBaseObject();

    ;-------------------------------------------------------
    ; Check the name in the name list
    ;-------------------------------------------------------
    ; isAlchemy [KYWD:0002A40B]
    ; WICraftingAlchemy [KYWD:0004F6E6]
    If frmTarget.HasKeywordString("isAlchemy") \
    || frmTarget.HasKeywordString("WICraftingAlchemy")
        isObject = true;
    Endif; frmTarget.HasKeywordString("isAlchemy") || ...

    ;-------------------------------------------------------
    ; Return
    ;-------------------------------------------------------
    return isObject;
EndFunction; isAlchemyLab()

; ----------------------------------------------------------
; @name     isCookingObject
; @desc     対象のオブジェクトが調理器具かどうか
; @function
; @global
; @param    obrfTarget  {ObjectReference}   対象のオブジェクト
; @returns  {Bool}
;           調理器具の場合はtrue
; ----------------------------------------------------------
Bool Function isCookingObject(ObjectReference obrfTarget) global
    ;-------------------------------------------------------
    ; Init Variables
    ;-------------------------------------------------------
    Bool isObject   = false;
    Form frmTarget  = obrfTarget.GetBaseObject();

    ;-------------------------------------------------------
    ; Check the name in the name list
    ;-------------------------------------------------------
    ; isCookingSpit [KYWD:00068ADA]
    ; CraftingCookpot [KYWD:000A5CB3]
    ; isSmallCookingPot [KYWD:001010B2]
    ; isSmallCookingPotDBPoison [KYWD:001010B5]
    ; isCraftingOven [KYWD:01002840]
    If frmTarget.HasKeywordString("isCookingSpit")      \
    || frmTarget.HasKeywordString("isCraftingOven")     \
    || frmTarget.HasKeywordString("CraftingCookpot")    \
    || frmTarget.HasKeywordString("isSmallCookingPot")  \
    || frmTarget.HasKeywordString("isSmallCookingPotDBPoison")
        isObject = true;
    Endif; frmTarget.HasKeywordString("isCookingSpit") || ...

    ;-------------------------------------------------------
    ; Return
    ;-------------------------------------------------------
    return isObject;
EndFunction; isCookingObject()

; ----------------------------------------------------------
; @name     isEnchanter
; @desc     対象のオブジェクトが通常の付呪器具かどうか
; @function
; @global
; @param    obrfTarget  {ObjectReference}   対象のオブジェクト
; @returns  {Bool}
;           通常の付呪器具の場合はtrue
; ----------------------------------------------------------
Bool Function isEnchanter(ObjectReference obrfTarget) global
    ;-------------------------------------------------------
    ; Init Variables
    ;-------------------------------------------------------
    Bool isObject   = false;
    Form frmTarget  = obrfTarget.GetBaseObject();

    ;-------------------------------------------------------
    ; Check the name in the name list
    ;-------------------------------------------------------
    ; isEnchanting [KYWD:0006E2A3]
    ; WICraftingEnchanting [KYWD:0004F6DD]
    ; DLC2StaffEnchanter [KYWD:02017738]
    If frmTarget.HasKeywordString("DLC2StaffEnchanter")
        isObject = false;
    Elseif frmTarget.HasKeywordString("isEnchanting") \
    ||     frmTarget.HasKeywordString("WICraftingEnchanting")
        isObject = true;
    Endif; frmTarget.HasKeywordString("DLC2StaffEnchanter")

    ;-------------------------------------------------------
    ; Return
    ;-------------------------------------------------------
    return isObject;
EndFunction; isEnchanter()

; ----------------------------------------------------------
; @name     isStaffEnchanter
; @desc     対象のオブジェクトが杖の付呪器具かどうか
; @function
; @global
; @param    obrfTarget  {ObjectReference}   対象のオブジェクト
; @returns  {Bool}
;           杖の付呪器具の場合はtrue
; ----------------------------------------------------------
Bool Function isStaffEnchanter(ObjectReference obrfTarget) global
    ;-------------------------------------------------------
    ; Init Variables
    ;-------------------------------------------------------
    Bool isObject   = false;
    Form frmTarget  = obrfTarget.GetBaseObject();

    ;-------------------------------------------------------
    ; Check the name in the name list
    ;-------------------------------------------------------
    ; DLC2StaffEnchanter [KYWD:02017738]
    If frmTarget.HasKeywordString("DLC2StaffEnchanter")
        isObject = true;
    Endif; frmTarget.HasKeywordString("DLC2StaffEnchanter")

    ;-------------------------------------------------------
    ; Return
    ;-------------------------------------------------------
    return isObject;
EndFunction; isStaffEnchanter()

; ----------------------------------------------------------
; @name     isSharpeningWheel
; @desc     対象のオブジェクトが研ぎ石かどうか
; @function
; @global
; @param    obrfTarget  {ObjectReference}   対象のオブジェクト
; @returns  {Bool}
;           研ぎ石の場合はtrue
; ----------------------------------------------------------
Bool Function isSharpeningWheel(ObjectReference obrfTarget) global
    ;-------------------------------------------------------
    ; Init Variables
    ;-------------------------------------------------------
    Bool isObject   = false;
    Form frmTarget  = obrfTarget.GetBaseObject();

    ;-------------------------------------------------------
    ; Check the name in the name list
    ;-------------------------------------------------------
    ; WICraftingSmithingTempering [KYWD:0004F6FD]
    ; CraftingSmithingSharpeningWheel [KYWD:00088108]
    If frmTarget.HasKeywordString("WICraftingSmithingTempering") \
    || frmTarget.HasKeywordString("CraftingSmithingSharpeningWheel")
        isObject = true;
    Endif; frmTarget.HasKeywordString("WICraftingSmithingTempering") || ...

    ;-------------------------------------------------------
    ; Return
    ;-------------------------------------------------------
    return isObject;
EndFunction; isSharpeningWheel()

; ----------------------------------------------------------
; @name     isArmorTable
; @desc     対象のオブジェクトが作業机かどうか
; @function
; @global
; @param    obrfTarget  {ObjectReference}   対象のオブジェクト
; @returns  {Bool}
;           作業机の場合はtrue
; ----------------------------------------------------------
Bool Function isArmorTable(ObjectReference obrfTarget) global
    ;-------------------------------------------------------
    ; Init Variables
    ;-------------------------------------------------------
    Bool isObject   = false;
    Form frmTarget  = obrfTarget.GetBaseObject();

    ;-------------------------------------------------------
    ; Check the name in the name list
    ;-------------------------------------------------------
    ; isBlacksmithWorkbench [KYWD:000D932E]
    ; CraftingSmithingArmorTable [KYWD:000ADB78]
    If frmTarget.HasKeywordString("isBlacksmithWorkbench") \
    || frmTarget.HasKeywordString("CraftingSmithingArmorTable")
        isObject = true;
    Endif; frmTarget.HasKeywordString("isBlacksmithWorkbench") || ...

    ;-------------------------------------------------------
    ; Return
    ;-------------------------------------------------------
    return isObject;
EndFunction; isArmorTable()

; ----------------------------------------------------------
; @name     isForge
; @desc     対象のオブジェクトが鍛造器具かどうか
; @function
; @global
; @param    obrfTarget  {ObjectReference}   対象のオブジェクト
; @returns  {Bool}
;           鍛造器具の場合はtrue
; ----------------------------------------------------------
Bool Function isForge(ObjectReference obrfTarget) global
    ;-------------------------------------------------------
    ; Init Variables
    ;-------------------------------------------------------
    Bool isObject   = false;
    Form frmTarget  = obrfTarget.GetBaseObject();

    ;-------------------------------------------------------
    ; Check the name in the name list
    ;-------------------------------------------------------
    ; isBlacksmithForge [KYWD:000CAE0A]
    ; CraftingSmithingForge [KYWD:00088105]
    ; isBlacksmithAnvil [KYWD:000EB60B]
    If frmTarget.HasKeywordString("isBlacksmithForge") \
    || frmTarget.HasKeywordString("isBlacksmithAnvil") \
    || frmTarget.HasKeywordString("CraftingSmithingForge")
        isObject = true;
    Endif; frmTarget.HasKeywordString("isBlacksmithForge") || ...

    ;-------------------------------------------------------
    ; Return
    ;-------------------------------------------------------
    return isObject;
EndFunction; isForge()

; ----------------------------------------------------------
; @name     isTanningRack
; @desc     対象のオブジェクトが皮なめしかどうか
; @function
; @global
; @param    obrfTarget  {ObjectReference}   対象のオブジェクト
; @returns  {Bool}
;           皮なめしの場合はtrue
; ----------------------------------------------------------
Bool Function isTanningRack(ObjectReference obrfTarget) global
    ;-------------------------------------------------------
    ; Init Variables
    ;-------------------------------------------------------
    Bool isObject   = false;
    Form frmTarget  = obrfTarget.GetBaseObject();

    ;-------------------------------------------------------
    ; Check the name in the name list
    ;-------------------------------------------------------
    ; isTanning [KYWD:000727A0]
    ; CraftingTanningRack [KYWD:0007866A]
    If frmTarget.HasKeywordString("isTanning") \
    || frmTarget.HasKeywordString("CraftingTanningRack")
        isObject = true;
    Endif; frmTarget.HasKeywordString("isTanning") || ...

    ;-------------------------------------------------------
    ; Return
    ;-------------------------------------------------------
    return isObject;
EndFunction; isTanningRack()

; ----------------------------------------------------------
; @name     isSmelter
; @desc     対象のオブジェクトが溶鉱炉かどうか
; @function
; @global
; @param    obrfTarget  {ObjectReference}   対象のオブジェクト
; @returns  {Bool}
;           溶鉱炉の場合はtrue
; ----------------------------------------------------------
Bool Function isSmelter(ObjectReference obrfTarget) global
    ;-------------------------------------------------------
    ; Init Variables
    ;-------------------------------------------------------
    Bool isObject   = false;
    Form frmTarget  = obrfTarget.GetBaseObject();

    ;-------------------------------------------------------
    ; Check the name in the name list
    ;-------------------------------------------------------
    ; isSmelter [KYWD:0009C6C3]
    ; CraftingSmelter [KYWD:000A5CCE]
    If frmTarget.HasKeywordString("isSmelter") \
    || frmTarget.HasKeywordString("CraftingSmelter")
        isObject = true;
    Endif; frmTarget.HasKeywordString("isSmelter") || ...

    ;-------------------------------------------------------
    ; Return
    ;-------------------------------------------------------
    return isObject;
EndFunction; isSmelter()

; ----------------------------------------------------------
; @name     isWoodChoppingBlock
; @desc     対象のオブジェクトが薪割りかどうか
; @function
; @global
; @param    obrfTarget  {ObjectReference}   対象のオブジェクト
; @returns  {Bool}
;           薪割りの場合はtrue
; ----------------------------------------------------------
Bool Function isWoodChoppingBlock(ObjectReference obrfTarget) global
    ;-------------------------------------------------------
    ; Init Variables
    ;-------------------------------------------------------
    Bool isObject   = false;
    Form frmTarget  = obrfTarget.GetBaseObject();

    ;-------------------------------------------------------
    ; Check the name in the name list
    ;-------------------------------------------------------
    ; FurnitureWoodChoppingBlock / 0x00072dfb (KYWD)
    If frmTarget.HasKeywordString("FurnitureWoodChoppingBlock")
        isObject = true;
    Endif; frmTarget.HasKeywordString("FurnitureWoodChoppingBlock")

    ;-------------------------------------------------------
    ; Return
    ;-------------------------------------------------------
    return isObject;
EndFunction; isWoodChoppingBlock()

; ----------------------------------------------------------
; @name     isOreVein
; @desc     対象のオブジェクトが鉱脈かどうか
; @function
; @global
; @param    obrfTarget  {ObjectReference}   対象のオブジェクト
; @returns  {Bool}
;           鉱脈の場合はtrue
; ----------------------------------------------------------
Bool Function isOreVein(ObjectReference obrfTarget) global
    ;-------------------------------------------------------
    ; Init Variables
    ;-------------------------------------------------------
    Bool isObject   = false;
    Form frmTarget  = obrfTarget.GetBaseObject();

    ;-------------------------------------------------------
    ; Check the name in the name list
    ;-------------------------------------------------------
    ; isPickaxeFloor [KYWD:000613A8]
    ; isPickaxeTable [KYWD:000613A9]
    ; isPickaxeWall [KYWD:000A82C3]
    If frmTarget.HasKeywordString("isPickaxeFloor") \
    || frmTarget.HasKeywordString("isPickaxeTable") \
    || frmTarget.HasKeywordString("isPickaxeWall")
        isObject = true;
    Endif; frmTarget.HasKeywordString("isPickaxeFloor") || ...

    ;-------------------------------------------------------
    ; Return
    ;-------------------------------------------------------
    return isObject;
EndFunction; isOreVein()
}}

**盗み判定
盗みかどうかを判定する関数はない為、不法侵入と所有権で判定している。
#highlight(linenumber,php){{
Bool Function isStealing(ObjectReference obrfTarget, Actor actTarget)
    ;-------------------------------------------------------
    ; Declare Variables
    ;-------------------------------------------------------
    Bool        isStealing;
    ActorBase   abTarget;
    Cell        celThis;
    ActorBase   abOwnThis;
    Faction     fctOwnThis;
    ActorBase   abOwnHere;
    Faction     fctOwnHere;

    ;-------------------------------------------------------
    ; Init Variables
    ;-------------------------------------------------------
    isStealing  = actTarget.IsTrespassing();
    abTarget    = actTarget.GetActorBase();
    celThis     = obrfTarget.GetParentCell();
    abOwnThis   = obrfTarget.GetActorOwner();
    fctOwnThis  = obrfTarget.GetFactionOwner();
    abOwnHere   = celThis.GetActorOwner();
    fctOwnHere  = celThis.GetFactionOwner();

    ;-------------------------------------------------------
    ; Check Stealing
    ;-------------------------------------------------------
    If abOwnThis && (abOwnThis != abTarget)
        isStealing = true;
    Elseif abOwnHere && (abOwnHere != abTarget)
        isStealing = true;
    Elseif fctOwnThis && !actTarget.IsInFaction(fctOwnThis)
        isStealing = true;
    Elseif fctOwnHere && !actTarget.IsInFaction(fctOwnHere)
        isStealing = true;
    Endif; abOwnThis && (abOwnThis != abTarget)

    ;-------------------------------------------------------
    ; Return
    ;-------------------------------------------------------
    return true;
EndFunction; isStealing()
}}

*配置オブジェクトの操作
セル内に配置されたオブジェクトを操作する処理。

**配置オブジェクトを一括で初期位置に戻す
MoveToMyEditorLocation()が初期位置に戻す処理。
この例では、nObjectTypeでオブジェクトの種類を指定して、セル内のオブジェクトを一括で元の位置に戻している。
#highlight(linenumber,php){{
; ----------------------------------------------------------
; @name     resetPositionsByObjectTypeIn
; @function
; @global
; @param    [celTarget=None]    {Cell}
; @param    [nObjectType=0]     {Int}
; @returns  {Int}
; ----------------------------------------------------------
Int Function resetPositionsByObjectTypeIn(  \
    Cell    celTarget   = None,             \
    Int     nObjectType = 0                 \
) global
    ;-------------------------------------------------------
    ; Init Variables
    ;-------------------------------------------------------
    ObjectReference obrfEach;
    Int             nIdx;
    Int             nCnt;
    Int             nReset = 0;
    
    ;-------------------------------------------------------
    ; Check the target cell
    ;-------------------------------------------------------
    If !celTarget
        celTarget = Game.GetPlayer().GetParentCell();
    Endif; !celTarget
    
    ;-------------------------------------------------------
    ; Loop of objects
    ;-------------------------------------------------------
    nIdx = 0;
    nCnt = celTarget.GetNumRefs(nObjectType);

    While (nIdx < nCnt)
        obrfEach = celTarget.GetNthRef(nIdx, nObjectType);

        If obrfEach
            obrfEach.MoveToMyEditorLocation();
            nReset += 1;
        Endif; obrfEach

        nIdx += 1;
    EndWhile; (nIdx < nCnt)
    
    ;-------------------------------------------------------
    ; Return
    ;-------------------------------------------------------
    return nReset;
EndFunction; resetPositionsByObjectTypeIn()
}}

**配置オブジェクトを一括で固定化する
SetMotionType()でMotion_Keyframedを指定すると、オブジェクトが固定化されて動かなくなる。
つまり、体当たりしても動かないオブジェクトになる。
この例では、nObjectTypeでオブジェクトの種類を指定して、セル内のオブジェクトを一括で固定化したり、固定化を解除したりしている。
#highlight(linenumber,php){{
; ----------------------------------------------------------
; @name     setMotionTypeByObjectTypeIn
; @function
; @global
; @param    [celTarget=None]    {Cell}
; @param    [enableLock=true]   {Bool}
; @param    [nObjectType=0]     {Int}
; @returns  {Int}
; ----------------------------------------------------------
Int Function setMotionTypeByObjectTypeIn(   \
    Cell    celTarget   = None,             \
    Bool    enableLock  = true,             \
    Int     nObjectType = 0                 \
) global
    ;-------------------------------------------------------
    ; Init Variables
    ;-------------------------------------------------------
    ObjectReference obrfEach;
    Int             nIdx;
    Int             nCnt;
    Int             nLockCnt = 0;
    
    ;-------------------------------------------------------
    ; Check the target cell
    ;-------------------------------------------------------
    If !celTarget
        celTarget = Game.GetPlayer().GetParentCell();
    Endif
    
    ;-------------------------------------------------------
    ; Loop of objects
    ;-------------------------------------------------------
    nIdx = 0;
    nCnt = celTarget.GetNumRefs(nObjectType);

    While (nIdx < nCnt)
        obrfEach = celTarget.GetNthRef(nIdx, nObjectType);

        ; Motion_Dynamic            = 1
        ; Motion_SphereIntertia     = 2
        ; Motion_BoxIntertia        = 3
        ; Motion_Keyframed          = 4
        ; Motion_Fixed              = 5
        ; Motion_ThinBoxIntertia    = 6
        ; Motion_Character          = 7
        If obrfEach.GetMass() && enableLock
            obrfEach.SetMotionType(obrfEach.Motion_Keyframed);
            nLockCnt += 1;
        Elseif !enableLock
            obrfEach.SetMotionType(obrfEach.Motion_Dynamic);
            nLockCnt += 1;
        Endif

        nIdx += 1;
    EndWhile
    
    ;-------------------------------------------------------
    ; Return
    ;-------------------------------------------------------
    return nLockCnt;
EndFunction; setMotionTypeByObjectTypeIn()
}}

**配置オブジェクトを一括で収集する
死体は単純にMoveTo()では移動できないので、Disable()してMoveTo()してEnable()している。
#highlight(linenumber,php){{
; ----------------------------------------------------------
; @name     gatherObjectsIn
; @function
; @global
; @param    [celTarget=None]    {Cell}
; @param    [obrfMoveTo=None]   {ObjectReference}
; @param    [nType=0]           {Int}
;           Form-Type
; @param    [nIsDeadAlive=0]    {Int}
;           0 = both, 1 = lives only, -1 = deads only
; @returns  {Bool}
; ----------------------------------------------------------
Bool Function gatherObjectsIn(              \
    Cell            celTarget       = None, \
    ObjectReference obrfMoveTo      = None, \
    Int             nType           = 0,    \
    Int             nIsDeadAlive    = 0     \
) global
    ;-------------------------------------------------------
    ; Init Variables
    ;-------------------------------------------------------
    Int             nIdx;
    Int             nCnt;
    ObjectReference obrfEach;
    Actor           actEach;
    
    ;-------------------------------------------------------
    ; Check arguments
    ;-------------------------------------------------------
    If !obrfMoveTo
        obrfMoveTo = Game.GetPlayer() as ObjectReference;
    Endif
    
    If !celTarget
        celTarget = obrfMoveTo.GetParentCell();
    Endif
    
    ;-------------------------------------------------------
    ; Scan chests
    ;-------------------------------------------------------
    nIdx = 0;
    nCnt = celTarget.GetNumRefs(nType);

    While (nIdx < nCnt)
        obrfEach = celTarget.GetNthRef(nIdx, nType);

        If !obrfEach.IsEnabled() || obrfEach.IsDeleted()
            obrfEach = None;
        Endif

        If obrfEach && (nType == 43)
            actEach = obrfEach as Actor;
        Else
            actEach = None;
        Endif

        If actEach
            If (nIsDeadAlive > 0) && actEach.IsDead()
                obrfEach    = None;
                actEach     = None;
            Elseif (nIsDeadAlive < 0) && !actEach.IsDead()
                obrfEach    = None;
                actEach     = None;
            Endif
        Endif
        
        If actEach && (nType == 43)
            If actEach.IsDead()
                actEach.Disable();
            Endif; actEach.IsDead()

            actEach.MoveTo(obrfMoveTo);

            If actEach.IsDead()
                actEach.Enable();
            Endif; actEach.IsDead()
        Elseif !actEach && obrfEach
            obrfEach.MoveTo(obrfMoveTo);
        Endif

        nIdx += 1;
    EndWhile
    
    ;-------------------------------------------------------
    ; Return
    ;-------------------------------------------------------
    return true;
EndFunction; gatherObjectsIn()
}}

**配置オブジェクトを一括で検知する
変性呪文の検知魔法のようなもの。スクリプトで実装すれば、好きなエフェクトを設定できる。
#highlight(linenumber,php){{
; ----------------------------------------------------------
; @name     detectObjectsIn
; @function
; @global
; @param    [celTarget=None]        {Cell}
; @param    [nType=0]               {Int}
;           Form-Type
; @param    [isLootableOnly=false]  {Bool}
; @param    [nIsDeadAlive=0]        {Int}
;           0 = both, 1 = lives only, -1 = deads only
; @returns  {Bool}
; ----------------------------------------------------------
Bool Function detectObjectsIn(          \
    Cell    celTarget       = None,     \
    Int     nType           = 0,        \
    Bool    isLootableOnly  = false,    \
    Int     nIsDeadAlive    = 0         \
) global
    ;-------------------------------------------------------
    ; Init Variables
    ;-------------------------------------------------------
    Int             nIdx;
    Int             nCnt;
    ObjectReference obrfEach;
    Actor           actEach;
    Actor           actPlayer   = Game.GetPlayer();
    EffectShader    efsEnemy;
    EffectShader    efsAlly;
    Hazard          hzdDetect;
    Bool            isLootable;
    
    ;-------------------------------------------------------
    ; Get Effect
    ;-------------------------------------------------------
    ; LifeDetected              [EFSH:0x000146]
    ; LifeDetectedEnemy         [EFSH:0x0DC209]
    ; LifeDetectedUndead        [EFSH:0x0AAEB3]
    ; LifeDetectedUndeadEnemy   [EFSH:0x016439]
    ; KynesPeaceFXS             [EFSH:0x084B39]
    ; HealCircleFXS             [EFSH:0x10CDC9]
    ; WerewolfTransFXS          [EFSH:0x0EBEC5]
    ; WerewolfTrans02FXS        [EFSH:0x0EBECD]
    ; DragonPowerAbsorbFXS      [EFSH:0x0280C0]
    ; AbsorbBlueFXS             [EFSH:0x0ABF08]
    ; AbsorbGreenFXS            [EFSH:0x0ABF07]
    ; AbsorbHealthFXS           [EFSH:0x0ABEFF]
    efsAlly     = Game.GetForm(0x000146) as EffectShader;
    efsEnemy    = Game.GetForm(0x0DC209) as EffectShader;
    ; CircleOfProtectionHazard  [HAZD:0x04E80C]
    ; CircleVitalityHazard      [HAZD:0x0B62EA]
    ; GuardianCircleHazard      [HAZD:0x0E0CD3]
    ; GuardianCircleTurnHazard  [HAZD:0x0FEAD3]
    hzdDetect   = Game.GetForm(0x04E80C) as Hazard;
    
    ;-------------------------------------------------------
    ; Check the target cell
    ;-------------------------------------------------------
    If !celTarget
        celTarget = Game.GetPlayer().GetParentCell();
    Endif
    
    ;-------------------------------------------------------
    ; Scan chests
    ;-------------------------------------------------------
    nIdx = 0;
    nCnt = celTarget.GetNumRefs(nType);

    While (nIdx < nCnt)
        obrfEach = celTarget.GetNthRef(nIdx, nType);

        If !obrfEach.IsEnabled() || obrfEach.IsDeleted()
            obrfEach = None;
        Endif

        If obrfEach && (nType == 43)
            actEach = obrfEach as Actor;
        Else
            actEach = None;
        Endif

        If actEach
            If (nIsDeadAlive > 0) && actEach.IsDead()
                obrfEach    = None;
                actEach     = None;
            Elseif (nIsDeadAlive < 0) && !actEach.IsDead()
                obrfEach    = None;
                actEach     = None;
            Endif
        Endif
        
        If !isLootableOnly
            isLootable = false;
        Elseif actEach
            isLootable = (actEach.GetNumItems() > 1);
        Elseif obrfEach && (nType == 28)
            isLootable = (obrfEach.GetNumItems() > 0);
        Else
            isLootable = false;
        Endif

        If isLootableOnly && !isLootable
            obrfEach    = None;
            actEach     = None;
        Endif

        If actEach && (nType == 43)
            If isEnemy(actEach)
                efsEnemy.Play(actEach, 26.0);
            Else
                efsAlly.Play(actEach, 26.0);
            Endif; isEnemy(actEach)
        Elseif !actEach && obrfEach
            obrfEach.placeAtMe(hzdDetect);
        Endif

        nIdx += 1;
    EndWhile
    
    ;-------------------------------------------------------
    ; Return
    ;-------------------------------------------------------
    return true;
EndFunction; detectObjectsIn()
}}

*NPCを操作する
NPCをPCのように操作する為に必要な一連の処理。
PCの操作停止、NPCの操作、カメラの切替、など。
#highlight(linenumber,php){{
Bool Function startNpcControl(Actor actTarget)
    ;-------------------------------------------------------
    ; Init Variables
    ;-------------------------------------------------------

    ;-------------------------------------------------------
    ; Start controlling
    ;-------------------------------------------------------
    Game.DisablePlayerControls(         \
        abMovement          = false,    \
        abFighting          = true,     \
        abCamSwitch         = false,    \
        abLooking           = false,    \
        abSneaking          = false,    \
        abMenu              = true,     \
        abActivate          = false,    \
        abJournalTabs       = false,    \
        aiDisablePOVType    = 0         );
    actTarget.SetPlayerControls(true);
    Game.SetPlayerAIDriven(true);
    actTarget.EnableAI();
    Game.SetCameraTarget(actTarget);
    Game.ForceThirdPerson();

    ;-------------------------------------------------------
    ; Return
    ;-------------------------------------------------------
    Return true;
EndFunction; startNpcControl()

Bool Function stopNpcControl(Actor actTarget)
    ;-------------------------------------------------------
    ; Init Variables
    ;-------------------------------------------------------
    Actor actPlayer = Game.GetPlayer();

    ;-------------------------------------------------------
    ; Switch the controlling
    ;-------------------------------------------------------
    actTarget.SetPlayerControls(false);
    Game.SetPlayerAIDriven(false);
    Game.EnablePlayerControls();
    actTarget.EnableAI();
    Game.SetCameraTarget(actPlayer);

    ;-------------------------------------------------------
    ; Return
    ;-------------------------------------------------------
    Return true;
EndFunction; stopNpcControl()
}}

*マップ・マーカーを表示する
指定したクエストのエイリアスに任意のリファレンスをマーカーとして表示する。
クエストは名前でも指定可能。エイリアスは名前やIDや番号でも指定可能。
例では、isActiveで表示と非表示を切り替える。
#highlight(linenumber,php){{
; ----------------------------------------------------------
; @name     showMapMarker
; @function
; @global
; @param    obrfTarget                  {ObjectReference}
; @param    [isActive=true]             {Bool}
; @param    [szQuestName=]              {String}
; @param    [nObjective=1]              {Int}
; @param    [szAliasName=RefAlias001]   {String}
; @param    [qstMarker=None]            {Quest}
; @param    [ralsMarker=None]           {ReferenceAlias}
; @param    [nAliasIdx=-1]              {Int}
; @param    [nAliasID=-1]               {Int}
; @returns  {Bool}
; ----------------------------------------------------------
Bool Function showMapMarker(                        \
    ObjectReference obrfTarget,                     \
    Bool            isActive    = true,             \
    String          szQuestName = "",               \
    Int             nObjective  = 1,                \
    String          szAliasName = "RefAlias001",    \
    Quest           qstMarker   = None,             \
    ReferenceAlias  ralsMarker  = None,             \
    Int             nAliasIdx   = -1,               \
    Int             nAliasID    = -1                \
) global
    ;-------------------------------------------------------
    ; Init Variables
    ;-------------------------------------------------------
    Bool isOK = false;
    
    ;-------------------------------------------------------
    ; Check Arguments
    ;-------------------------------------------------------
    If !obrfTarget
        return isOK;
    Endif
    
    ;-------------------------------------------------------
    ; Get Marker Quest
    ;-------------------------------------------------------
    If !qstMarker
        qstMarker = Quest.GetQuest(szQuestName);
    Endif
    
    If !qstMarker
        return isOK;
    Endif
    
    ;-------------------------------------------------------
    ; Get Reference Alias
    ;-------------------------------------------------------
    If !ralsMarker && (nAliasIdx >= 0)
        ralsMarker =                    \
            qstMarker.GetNthAlias(      \
                nAliasIdx               ) as ReferenceAlias;
    Elseif !ralsMarker && (nAliasID >= 0)
        ralsMarker =                    \
            qstMarker.GetAliasById(     \
                nAliasID                ) as ReferenceAlias;
    Elseif !ralsMarker && (szAliasName != "")
        ralsMarker =                    \
            qstMarker.GetAliasByName(   \
                szAliasName             ) as ReferenceAlias;
    Endif

    If !ralsMarker
        return isOK;
    Endif
    
    ;-------------------------------------------------------
    ; Show Marker
    ;-------------------------------------------------------
    If isActive
        ralsMarker.ForceRefTo(obrfTarget);
        qstMarker.SetObjectiveDisplayed(    \
            nObjective, true, false         );
        isOK = true;
    Else
        ralsMarker.Clear();
        qstMarker.SetObjectiveDisplayed(    \
            nObjective, false, false        );
        isOK = true;
    Endif
    
    ;-------------------------------------------------------
    ; Return
    ;-------------------------------------------------------
    return isOK;
EndFunction; showMapMarker()
}}

*対象の人の戦闘を強制停止させる
戦闘を停止させる処理の詰め合わせ。
StopCombat()は対象のアクターの戦闘状態を停止させることしか出来ない。
本格的に戦闘停止させるには、警戒状態も解除し、相手方の戦闘状態も解除する必要がある。
disableRecoverのオプションは、戦闘停止時に全回復するようなMOD対策。
戦闘停止後に、停止前の体力に強制的に戻す為のオプション。
#highlight(linenumber,php){{
; ----------------------------------------------------------
; @name     stopCombatEx
; @function
; @global
; @param    actTarget                   {Actor}
; @param    [disableRecover=true]       {Bool}
; @param    [enableStopAlarm=false]     {Bool}
; @param    [enableStopTarget=false]    {Bool}
; @returns  {Bool}
; ----------------------------------------------------------
Bool Function stopCombatEx(                 \
    Actor   actTarget,                      \
    Bool    disableRecover      = true,     \
    Bool    enableStopAlarm     = false,    \
    Bool    enableStopTarget    = false     \
) global
    ;-------------------------------------------------------
    ; Init Variables
    ;-------------------------------------------------------
    Float nHealth;
    Float nDamage;
    Actor actEnemy;

    ;-------------------------------------------------------
    ; Check Arguments
    ;-------------------------------------------------------
    If !actTarget || !actTarget.IsInCombat()
        return false;
    Endif; !actTarget || !actTarget.IsInCombat()

    ;-------------------------------------------------------
    ; Get Current Health
    ;-------------------------------------------------------
    If disableRecover
        nHealth = actTarget.GetActorValue("Health");
    Endif; disableRecover

    ;-------------------------------------------------------
    ; Stop Combat (Self)
    ;-------------------------------------------------------
    actTarget.StopCombat();

    ;-------------------------------------------------------
    ; Stop Alarm
    ;-------------------------------------------------------
    If enableStopAlarm
        actTarget.StopCombatAlarm();
    Endif; enableStopAlarm

    ;-------------------------------------------------------
    ; Stop Combat (Enemy)
    ;-------------------------------------------------------
    If enableStopTarget
        actEnemy = actTarget.GetCombatTarget();

        If actEnemy
            stopCombatEx(actEnemy, disableRecover, false, false);
        Endif
    Endif; enableStopTarget

    ;-------------------------------------------------------
    ; Damage Health
    ;-------------------------------------------------------
    If disableRecover
        nDamage = actTarget.GetActorValue("Health") - nHealth;

        If (nDamage > 0.0)
            actTarget.DamageActorValue("Health", nDamage);
        Endif; (nDamage > 0.0)
    Endif; disableRecover
    
    ;-------------------------------------------------------
    ; Return
    ;-------------------------------------------------------
    return true;
EndFunction; stopCombatEx()
}}

*外見変更
**顔テキスチャの変更
NetImmerse Overrideが必要。
アクターの顔テキスチャを変更する処理。顔用のTextureSetを指定する。
#highlight(linenumber,php){{
; ----------------------------------------------------------
; @name     changeFace
; @function
; @global
; @param    actTarget   {Actor}
; @param    txtSkin     {TextureSet}
; @returns  {Bool}
; ----------------------------------------------------------
Bool Function changeFace(Actor actTarget, TextureSet txtSkin) global
    ;-------------------------------------------------------
    ; Init Variables
    ;-------------------------------------------------------
    ActorBase   abTarget;
    Int         nHeadIdx    = -1;
    String      szNode      = "";

    ;-------------------------------------------------------
    ; Check Arguments
    ;-------------------------------------------------------
    If !actTarget || !txtSkin
        return false;
    Else
        abTarget = actTarget.GetLeveledActorBase();
    Endif; !actTarget || !txtSkin

    ;-------------------------------------------------------
    ; Get Head Index
    ;-------------------------------------------------------
    If abTarget
        nHeadIdx = abTarget.GetIndexOfHeadPartByType(1);
    Endif; abTarget

    ;-------------------------------------------------------
    ; Get Node Name
    ;-------------------------------------------------------
    If (nHeadIdx >= 0)
        szNode = abTarget.GetNthHeadPart(nHeadIdx).GetName();
    Endif; (nHeadIdx >= 0)

    ;-------------------------------------------------------
    ; Apply Face Texture
    ;-------------------------------------------------------
    If (nHeadIdx >= 0)
        abTarget.SetFaceTextureSet(txtSkin);
        NetImmerse.SetNodeTextureSet( \
            actTarget, szNode, txtSkin, false);
    Endif; (nHeadIdx >= 0)

    ;-------------------------------------------------------
    ; Return
    ;-------------------------------------------------------
    return true;
EndFunction; changeFace()
}}

**髪パーツの変更
#highlight(linenumber,php){{
; ----------------------------------------------------------
; @name     changeHair
; @function
; @global
; @param    actTarget   {Actor}
; @param    hpNewHair   {HeadPart}
; @returns  {Bool}
; ----------------------------------------------------------
Bool Function changeHair(Actor actTarget, HeadPart hpNewHair)
    ;-------------------------------------------------------
    ; Init Variables
    ;-------------------------------------------------------
    ActorBase   abTarget    = actTarget.GetLeveledActorBase();
    Bool        isPlayer    = (Game.GetPlayer() == actTarget);
    Int         nHeadIdx;
    HeadPart    hpCurHair;
    
    ;-------------------------------------------------------
    ; Get Hair Headparts
    ;-------------------------------------------------------
    nHeadIdx    = abTarget.GetIndexOfHeadPartByType(3);
    hpCurHair   = abTarget.GetNthHeadPart(nHeadIdx);

    ;-------------------------------------------------------
    ; Reset Hair Part
    ;-------------------------------------------------------
    If !isPlayer && hpNewHair
        actTarget.ReplaceHeadPart(hpCurHair, hpNewHair);
    Elseif isPlayer && hpNewHair
        actTarget.ChangeHeadPart(hpNewHair);
    Endif; !isPlayer && hpNewHair

    ;-------------------------------------------------------
    ; Return
    ;-------------------------------------------------------
    return true;
EndFunction; changeHair()
}}

*プレイヤーのヘッド・トラッキング
指定したオブジェクトに対して、プレイヤーにヘッド・トラッキングさせる処理。
自分自身を対象に指定すると、ゆっくり正面を向く。(ヘッド・トラッキングは継続)
ヘッド・トラッキングそのものを停止すると、急に正面を向く。
#highlight(linenumber,php){{
Bool Function startPlayerHeadTracking(ObjectReference obrfTarget)
    ;-------------------------------------------------------
    ; Declare Variables
    ;-------------------------------------------------------
    Actor actPlayer = Game.GetPlayer();

    ;-------------------------------------------------------
    ; Player Head Tracking
    ;-------------------------------------------------------
    If obrfTarget
        actPlayer.SetHeadTracking(true);
        actPlayer.SetLookAt(obrfTarget, false);
        actPlayer.SetAnimationVariableBool("bHeadTrackSpine", false);
        actPlayer.SetAnimationVariableInt("IsNPC", 1);
    Endif; obrfTarget
    
    ;-------------------------------------------------------
    ; Return
    ;-------------------------------------------------------
    return true;
EndFunction; startPlayerHeadTracking()

Bool Function stopPlayerLooking()
    ;-------------------------------------------------------
    ; Declare Variables
    ;-------------------------------------------------------
    Actor actPlayer = Game.GetPlayer();

    ;-------------------------------------------------------
    ; Player Head Tracking
    ;-------------------------------------------------------
    actPlayer.SetLookAt(actPlayer, false);
    
    ;-------------------------------------------------------
    ; Return
    ;-------------------------------------------------------
    return true;
EndFunction; stopPlayerLooking()

Bool Function stopPlayerHeadTracking()
    ;-------------------------------------------------------
    ; Declare Variables
    ;-------------------------------------------------------
    Actor actPlayer = Game.GetPlayer();

    ;-------------------------------------------------------
    ; Player Head Tracking
    ;-------------------------------------------------------
    actPlayer.ClearLookAt();
    actPlayer.SetAnimationVariableBool( \
        "bHeadTrackSpine", false        );
    actPlayer.SetAnimationVariableInt("IsNPC", 0);
    actPlayer.SetHeadTracking(false);
    
    ;-------------------------------------------------------
    ; Return
    ;-------------------------------------------------------
    return true;
EndFunction; stopPlayerHeadTracking()
}}

*配列の要素数を128を超えたものを扱いたい、または動的に配列を宣言したい
Papyrusの配列は通常は1~128までの範囲しか扱う事ができず、
それ以上の配列数を宣言しようと128を超える数値を指定するとエラーが発生します。
また、配列宣言時に配列数の部分を変数で指定した場合もエラーが発生します。

**NGパターン
#highlight(linenumber,php){{
Actor[] NPCArray
int[] ValArray
Function Test()
    int num = 0
    NPCArray = new Actor[200] ;1~128までの範囲で宣言しろとエラーが出る

    ; 変数の値分の配列を宣言したいが
    ; 配列数の指定に変数を指定するなとエラーが出る
    num = 200
    ValArray = new int[num]
EndFunction; Test()
}}

配列数が128を超える配列を作成したい場合、
Float、Int、String、Form、Alias型の場合は
SKSEのPapyrus拡張関数である
Utility.Create~Arrayを
用いる事で配列数が128を超える配列を作成することができます。(~の部分は型によって異なりますのでスクリプトリファレンスを確認してください。)
https://www.creationkit.com/index.php?title=Utility_Script

Actor型の場合は標準のSKSEの拡張関数には存在しないため
Papyrus拡張SKSEプラグインであるPapyrusUtilが必要となります。

この方法で配列の宣言をする場合、処理に必要な配列数を動的に宣言できるようになる他に第2引数に値を指定する事で宣言と同時に各要素の値を指定値で初期化する事ができます。

**実装例
#highlight(linenumber,php){{
Actor[] NPCArray
int[] ValArray
Function Test()
    int num = 200 ;
    NPCArray = PapyrusUtil.ActorArray(num, None)
    ValArray = Utility.CreateIntArray(num, 10) ; 配列の各要素の値を10で初期化
EndFunction; Test()
}}

復元してよろしいですか?

目安箱バナー