SkyrimMOD作成wiki

逆引きリファレンス

最終更新:

匿名ユーザー

- view
だれでも歓迎! 編集
この項目ではやりたいことから調べられます。
やり方は一例であって必ずしもということはないので、他のパターンもあればぜひ記載してください。


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


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で当クエストの指定も忘れずに。


常時稼動させるスクリプト

※できる限り使わないことを考えぬいてください。
常時稼働する事自体スクリプト(Papyrus)かそうでないかにかかわらず負荷がかかるために避けたほうが良いです。
とくに間隔の短い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())

  1. Actor actTarget;
  2. String szName;
  3.  
  4. ; 現在のゲーム上で表示されている名前
  5. szName = actTarget.GetDisplayName();
  6.  
  7. ; 表示名の変更に影響されない元の設定名
  8. ; レベルドリストから生成されたアクターの場合、空白になる場合がある。
  9. szName = actTarget.GetActorBase().GetName();
  10.  
  11. ; 表示名の変更に影響されない元の設定名
  12. ; レベルドリストから生成されたアクターの場合でも、元になったActorBaseの名前が入る。
  13. ; 通常のアクターの場合でも使えるので、設定名を取得する場合はこの方が確実。
  14. szName = actTarget.GetLeveledActorBase().GetName();
  15.  

場所の名前の取得

場所の名前をセル→ロケーション→ワールドの順に取得する。
屋外などでは、セルやロケーションに名前が設定されていない場合がある為。
celPlaceで指定したセルか、objrefMarkerで指定したリファレンスの場所名を返す。
  1. ; ----------------------------------------------------------
  2. ; @name getPlaceName
  3. ; @function
  4. ; @global
  5. ; @param [celPlace=None] {Cell}
  6. ; @param [objrefMarker=None] {ObjectReference}
  7. ; @returns {String}
  8. ; ----------------------------------------------------------
  9. String Function getPlaceName( \
  10. Cell celPlace = None, \
  11. ObjectReference objrefMarker = None \
  12. ) global
  13. ;-------------------------------------------------------
  14. ; Init Variables
  15. ;-------------------------------------------------------
  16. Location locMarker;
  17. WorldSpace wsMarker;
  18. String szName = "";
  19.  
  20. ;-------------------------------------------------------
  21. ; Check Arguments
  22. ;-------------------------------------------------------
  23. If !celPlace && objrefMarker
  24. celPlace = objrefMarker.GetParentCell();
  25. Elseif celPlace && !objrefMarker
  26. objrefMarker = celPlace.GetNthRef(0);
  27. Endif; !celPlace && objrefMarker
  28.  
  29. ;-------------------------------------------------------
  30. ; Get Cell Name
  31. ;-------------------------------------------------------
  32. If celPlace
  33. szName = celPlace.GetName();
  34. Endif; celPlace
  35.  
  36. ;-------------------------------------------------------
  37. ; Get Location Name
  38. ;-------------------------------------------------------
  39. If (szName == "")
  40. If objrefMarker
  41. locMarker = objrefMarker.GetCurrentLocation();
  42. EndIf; objrefMarker
  43.  
  44. If locMarker
  45. szName = locMarker.GetName();
  46. Endif; locMarker
  47. Endif; (szName == "")
  48.  
  49. ;-------------------------------------------------------
  50. ; Get World Name
  51. ;-------------------------------------------------------
  52. If (szName == "")
  53. If objrefMarker
  54. wsMarker = objrefMarker.GetWorldSpace();
  55. EndIf; objrefMarker
  56.  
  57. If wsMarker
  58. szName = wsMarker.GetName();
  59. Endif; wsMarker
  60. Endif; (szName == "")
  61.  
  62. ;-------------------------------------------------------
  63. ; Return
  64. ;-------------------------------------------------------
  65. return szName;
  66. EndFunction; getPlaceName()
  67.  

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が自身に保存されたプロパティ情報を元に初期化しようとしたがスクリプトには存在しないために出る注意文で、新規ゲームでも関係なくメッセージを出します。
実害は無いですが邪魔な存在である事は確かなのでなるべくなら消しましょう。

  • 消し方
消したいプロパティを選択後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というツールで消せます。


扉の開錠/施錠



扉の施錠判断には ObjectReference.IsLocked を使います。扉の開錠/施錠には ObjectReference.Lock を使います。
以下は、アクティベートイベントを元に、対象の扉が開いている場合は施錠/閉じている場合は解錠するスクリプトの例です。

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 タブにある情報を設定します。
以下、スクリーンショットでは鍵を必要とする状態で扉を閉めています。
何らかのイベント等をトリガーに先に進めるようにする場合などに使えます。


オブジェクトの移動



設置済みのオブジェクトを移動させるには ObjectReference.SetPosition を使います。
以下はアクティベートした対象そのものを後ろへ移動させるスクリプトの例です。

Scriptname ExampleMoveObject extends ObjectReference  

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

ObjectReference.SetPosition で指定する座標は、セル内の絶対座標系の値です。
ObjectReference には現在位置を表す x, y, z プロパティがあるので、それを使って相対位置を指定するのが常套手段です。
向きも変えたい場合は ObjectReference.SetAngle を併用します。

※ポイント:この移動方法は、今の座標から徐々に指定の場所へ移動させるものではありません。ObjectReference.SetPosition は、瞬時の移動しかできません。徐々に移動させるには前提として対象が Actor である必要があります。

新しいオブジェクトの設置

簡単な例



オブジェクトを新しく設置するには ObjectReference.PlaceAtMe を使います。
第一引数に Form オブジェクトを指定します。
オブジェクト指向熟練者への補足ですが、以下の対比がちょうど当てはまると覚えておくと良いでしょう。
Form オブジェクト クラス
ObjectReference.PlaceAtMe new 演算子
ObjectReference オブジェクト インスタンス
以下(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 オブジェクトがあれば新しいオブジェクトを生成できます。

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



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

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」が設定してあります。何度もアクティベートすれば当然…。
囲まれます。

SpawnerTaskを使用して大量発生させる

SpawnerTaskを使えば、敵やオブジェクトを効率よくスポーンさせることが出来ます。
下記の例では、PCの周囲に一気に出現させています。
  1. Bool Function spawnAroundPlayer(Form frmTarget, Int nAddNum = 1)
  2. ;-------------------------------------------------------
  3. ; Init Variables
  4. ;-------------------------------------------------------
  5. Actor actPlayer = Game.GetPlayer();
  6. Float[] aPos = new Float[3];
  7. Float[] aRot = new Float[3];
  8. Int nTaskID;
  9.  
  10. ;-------------------------------------------------------
  11. ; Spawn
  12. ;-------------------------------------------------------
  13. If frmTarget && (nAddNum > 0)
  14. nTaskID = SpawnerTask.Create();
  15. SpawnerTask.AddSpawn( \
  16. nTaskID, frmTarget, actPlayer, aPos, aRot, nAddNum);
  17. SpawnerTask.Run(nTaskID);
  18. Endif; frmTarget && (nAddNum > 0)
  19.  
  20. ;-------------------------------------------------------
  21. ; Return
  22. ;-------------------------------------------------------
  23. return true;
  24. EndFunction; spawnAroundPlayer()
  25.  

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



アクティベートするたびに FormList の中にある何かが部屋のどこかに設置されるサンプルです。

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

アクターの移動


アクターの誘導



アクターとは動きまわるオブジェクトのことです。プレイヤーや敵やNPCなどが該当します。
「オブジェクトの移動」で紹介した ObjectReference.SetPosition は瞬時の移動です。誘導には Actor.PathToReference を使います。
誘導する際、移動先のオブジェクトを指定する必要があります。ObjectReference であれば何でも良いですが、もしも自由に誘導させたいならば 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()を使えば、対象のアクターを別のアクターの隣や背後といった定位置に移動させることが出来る。
隊列の形成などは、この手法が使われていることが多い。

  1. Actor actTarget;
  2. Actor actFollow;
  3.  
  4. actTarget.KeepOffsetFromActor( \
  5. actFollow, \
  6. 170.0, -170.0, 0.0, \
  7. afCatchUpRadius = 260.0, \
  8. afFollowRadius = 8.0 );
  9.  

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



敵を倒した際、コンテナーをドロップさせてアイテムをゲットできるようにしてみましょう。
方法は簡単です。Actor.OnDeath イベントで敵が倒されたタイミングを見計らい
  • コンテナーを設置
  • 敵を排除
するだけです。以下、事例です。

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以外を返します)

  1. ; ----------------------------------------------------------
  2. ; @name isInRagdollActor
  3. ; @desc 対象の人物がフロスダ等によるラグドール影響下にあるかを返す
  4. ; @function
  5. ; @global
  6. ; @param actTarget {Actor} 対象の人
  7. ; @param isDeadRagdollCheck {Bool} 死亡からラグドール状態に移行した場合を考慮するか
  8. ; @returns {Bool} 影響下にあればtrue
  9. ; ----------------------------------------------------------
  10. Bool Function isInRagdollActor(Actor actTarget, Bool isDeadRagdollCheck = true) global
  11. ;-------------------------------------------------------
  12. ; Init Variables
  13. ;-------------------------------------------------------
  14. Bool isInRagdoll = false;
  15.  
  16. ;-------------------------------------------------------
  17. ; Checking Ragdoll Status
  18. ;-------------------------------------------------------
  19. If actTarget
  20. ; 死亡時にラグドール状態に移行する場合はGetActorKnockStateは0を返すため
  21. ; 従来のGetMass関数による判定と同じ挙動を行いたい時はIsDeadのチェックを加える
  22. If (PO3_SKSEFunctions.GetActorKnockState(actTarget) != 0)
  23. isInRagdoll = true
  24. ElseIf isDeadRagdollCheck
  25. isInRagdoll = actTarget.IsDead()
  26. EndIf
  27. Endif; actTarget
  28.  
  29. ;-------------------------------------------------------
  30. ; Return
  31. ;-------------------------------------------------------
  32. return isInRagdoll;
  33. EndFunction; isInRagdollActor()
  34.  

GetMass関数を使う(従来のやり方、SE版ではアクターに対しては非推奨)

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

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

Precision環境下でなくても今後出てくるModによってはGetMass関数がアクターに対して通常時でも0以外を返すようになる可能性があるため前述のGetActorKnockState関数でラグドール判定を行う事を推奨します。

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

  1. ; ----------------------------------------------------------
  2. ; @name isInRagdoll
  3. ; @desc 対象の人や物がラグドール影響下にあるかを返す
  4. ; @function
  5. ; @global
  6. ; @param obrfThis {ObjectReference} 対象の人や物
  7. ; @returns {Bool} 影響下にあればtrue
  8. ; ----------------------------------------------------------
  9. Bool Function isInRagdoll(ObjectReference obrfThis) global
  10. ;-------------------------------------------------------
  11. ; Init Variables
  12. ;-------------------------------------------------------
  13. Bool isInRagdoll = false;
  14.  
  15. ;-------------------------------------------------------
  16. ; Checking Ragdoll Status
  17. ;-------------------------------------------------------
  18. If obrfThis && (obrfThis.GetMass() != 0)
  19. isInRagdoll = true;
  20. Endif; obrfThis && (obrfThis.GetMass() != 0)
  21.  
  22. ;-------------------------------------------------------
  23. ; Return
  24. ;-------------------------------------------------------
  25. return isInRagdoll;
  26. EndFunction; isInRagdoll()
  27.  

ラグドール中のモーション再生によるバグ

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

十進数と十六進数の変換

Papyrusには、こういった標準的な関数がないので不便する場合がある。

十進数→十六進数

  1. ; ----------------------------------------------------------
  2. ; @name convDecToHex
  3. ; @desc 整数値を十六進数表記の文字列に変換
  4. ; @function
  5. ; @global
  6. ; @param nNum {Int} 変換したい整数値
  7. ; @returns {String} 十六進数表記の文字列
  8. ; ----------------------------------------------------------
  9. String Function convDecToHex(Int nNum) global
  10. ;-------------------------------------------------------
  11. ; Init Variables
  12. ;-------------------------------------------------------
  13. String szHex;
  14. Bool isNegative;
  15. Int[] aNums = new Int[8];
  16. String[] aHex = new String[8];
  17. Int nIdx = 0;
  18. Int nLen = aNums.Length;
  19.  
  20. ;-------------------------------------------------------
  21. ; Checking over 0x80000000
  22. ;-------------------------------------------------------
  23. If (nNum < 0)
  24. isNegative = True;
  25.  
  26. nNum += 0x80000000;
  27. Endif
  28.  
  29. ;-------------------------------------------------------
  30. ; Parse integer
  31. ;-------------------------------------------------------
  32. aNums[0] = (nNum / 0x10000000);
  33. nNum -= (aNums[0] * 0x10000000);
  34. aNums[1] = (nNum / 0x01000000);
  35. nNum -= (aNums[1] * 0x01000000);
  36. aNums[2] = (nNum / 0x00100000);
  37. nNum -= (aNums[2] * 0x00100000);
  38. aNums[3] = (nNum / 0x00010000);
  39. nNum -= (aNums[3] * 0x00010000);
  40. aNums[4] = (nNum / 0x00001000);
  41. nNum -= (aNums[4] * 0x00001000);
  42. aNums[5] = (nNum / 0x00000100);
  43. nNum -= (aNums[5] * 0x00000100);
  44. aNums[6] = (nNum / 0x00000010);
  45. nNum -= (aNums[6] * 0x00000010);
  46. aNums[7] = nNum;
  47.  
  48. ;-------------------------------------------------------
  49. ; Convert to HEX
  50. ;-------------------------------------------------------
  51. If isNegative
  52. aNums[0] = aNums[0] + 8;
  53. Endif
  54.  
  55. While (nIdx < nLen)
  56. If (aNums[nIdx] == 10)
  57. aHex[nIdx] = "A";
  58. Elseif (aNums[nIdx] == 11)
  59. aHex[nIdx] = "B";
  60. Elseif (aNums[nIdx] == 12)
  61. aHex[nIdx] = "C";
  62. Elseif (aNums[nIdx] == 13)
  63. aHex[nIdx] = "D";
  64. Elseif (aNums[nIdx] == 14)
  65. aHex[nIdx] = "E";
  66. Elseif (aNums[nIdx] == 15)
  67. aHex[nIdx] = "F";
  68. Else
  69. aHex[nIdx] = (aNums[nIdx] as String);
  70. Endif
  71.  
  72. nIdx += 1;
  73. EndWhile
  74.  
  75. ;-------------------------------------------------------
  76. ; Join characters
  77. ;-------------------------------------------------------
  78. szHex = aHex[0] + aHex[1] + aHex[2] + aHex[3] \
  79. + aHex[4] + aHex[5] + aHex[6] + aHex[7];
  80.  
  81. ;-------------------------------------------------------
  82. ; Return
  83. ;-------------------------------------------------------
  84. return szHex;
  85. EndFunction; convDecToHex()
  86.  

十六進数→十進数

  1. ; ----------------------------------------------------------
  2. ; @name convHexToDec
  3. ; @desc 十六進数表記の文字列を整数値で応答
  4. ; @function
  5. ; @global
  6. ; @param szHex {String} 十六進数表記の文字列
  7. ; @returns {Int} 変換した整数値
  8. ; ----------------------------------------------------------
  9. Int Function convHexToDec(String szHex) global
  10. ;-------------------------------------------------------
  11. ; Init Variables
  12. ;-------------------------------------------------------
  13. Int nIdx = 0;
  14. Int nLen = StringUtil.GetLength(szHex);
  15. String cChar;
  16. Int nNum;
  17. Int nRet;
  18.  
  19. ;-------------------------------------------------------
  20. ; Parse Hex-String
  21. ;-------------------------------------------------------
  22. While (nIdx < nLen)
  23. cChar = StringUtil.GetNthChar(szHex, nIdx);
  24.  
  25. If StringUtil.IsDigit(cChar)
  26. nNum = cChar as Int;
  27. Elseif (cChar == "A") || (cChar == "a")
  28. nNum = 10;
  29. Elseif (cChar == "B") || (cChar == "b")
  30. nNum = 11;
  31. Elseif (cChar == "C") || (cChar == "c")
  32. nNum = 12;
  33. Elseif (cChar == "D") || (cChar == "d")
  34. nNum = 13;
  35. Elseif (cChar == "E") || (cChar == "e")
  36. nNum = 14;
  37. Elseif (cChar == "F") || (cChar == "f")
  38. nNum = 15;
  39. Else
  40. nNum= 0;
  41. Endif
  42.  
  43. nNum = (nNum * Math.pow(16, (nLen - (nIdx + 1)))) as Int;
  44.  
  45. nRet += nNum;
  46. nIdx += 1
  47. EndWhile
  48.  
  49. ;-------------------------------------------------------
  50. ; Return
  51. ;-------------------------------------------------------
  52. return nRet;
  53. EndFunction; convHexToDec()
  54.  

攻撃側と防御側の位置と角度判定

バックスタブなどのMODで使われる手法。二者の相対的な距離と角度から判定している。
  1. ; ----------------------------------------------------------
  2. ; @name getAttackAngle
  3. ; @desc 攻撃側と防御側の向きと距離のタイプを返す
  4. ; @function
  5. ; @global
  6. ; @param actAtk {Actor} 攻撃側の人
  7. ; @param actDef {Actor} 防御側の人
  8. ; @param [nCloseRange=170.0] {Float} 近接と判断する距離限界
  9. ; @param [nFrontAngle=44.0] {Float} 正面と判断する角度限界
  10. ; @param [nRearAngle=125.0] {Float} 背面と判断する角度限界
  11. ; @returns {Int}
  12. ; 距離のタイプとして、以下を返す
  13. ; -1 : 以下のどれでもない、または処理エラー
  14. ; 11 : 正面近距離
  15. ; 12 : 背面近距離
  16. ; 21 : 正面遠距離
  17. ; 22 : 背面遠距離
  18. ; ----------------------------------------------------------
  19. Int Function getAttackAngle( \
  20. Actor actAtk, \
  21. Actor actDef, \
  22. Float nCloseRange = 170.0, \
  23. Float nFrontAngle = 44.0, \
  24. Float nRearAngle = 125.0 \
  25. ) global
  26. ;-------------------------------------------------------
  27. ; Init Variables
  28. ;-------------------------------------------------------
  29. Int nRet = -1;
  30. Float nFaceMin;
  31. Float nFaceMax;
  32. Float nRearMin;
  33. Float nRearMax;
  34. Float nDist;
  35. Float nAngleAtk;
  36. Float nAngleDef;
  37.  
  38. ;-------------------------------------------------------
  39. ; Check Arguments
  40. ;-------------------------------------------------------
  41. If !actAtk || !actDef || (actAtk == actDef)
  42. return nRet;
  43. Endif; !actAtk || !actDef || (actAtk == actDef)
  44.  
  45. If (nCloseRange < 0.0)
  46. nCloseRange *= -1.0;
  47. Endif; (nCloseRange < 0.0)
  48.  
  49. If (nFrontAngle < 0.0)
  50. nFrontAngle *= -1.0;
  51. Endif; (nFrontAngle < 0.0)
  52.  
  53. If (nFrontAngle > 90.0)
  54. nFrontAngle = 90.0;
  55. Endif; (nFrontAngle > 90.0)
  56.  
  57. If (nRearAngle < 0.0)
  58. nRearAngle *= -1.0;
  59. Endif; (nRearAngle < 0.0)
  60.  
  61. If (nRearAngle < 90.0)
  62. nRearAngle = 90.0;
  63. Elseif (nRearAngle > 180.0)
  64. nRearAngle = 180.0;
  65. Endif; (nRearAngle < 90.0)
  66.  
  67. ;-------------------------------------------------------
  68. ; Init Range Values
  69. ;-------------------------------------------------------
  70. nFaceMin = nFrontAngle * -1.0;
  71. nFaceMax = nFrontAngle;
  72. nRearMin = nRearAngle * -1.0;
  73. nRearMax = nRearAngle;
  74.  
  75. ;-------------------------------------------------------
  76. ; Get Distance and Angles
  77. ;-------------------------------------------------------
  78. nDist = actAtk.GetDistance(actDef);
  79. nAngleAtk = actAtk.GetHeadingAngle(actDef);
  80. nAngleDef = actDef.GetHeadingAngle(actAtk);
  81.  
  82. ;-------------------------------------------------------
  83. ; Check Distance
  84. ;-------------------------------------------------------
  85. If (nDist <= nCloseRange)
  86. nRet = 10;
  87. Else
  88. nRet = 20;
  89. Endif; (nDist <= nCloseRange)
  90.  
  91. ;-------------------------------------------------------
  92. ; Check Defender Angle
  93. ;-------------------------------------------------------
  94. If (nAngleAtk >= nFaceMin) && (nAngleAtk <= nFaceMax)
  95. If (nAngleDef >= nFaceMin) \
  96. && (nAngleDef <= nFaceMax)
  97. nRet += 1;
  98. Elseif (nAngleDef <= nRearMin) \
  99. || (nAngleDef >= nRearMax)
  100. nRet += 2;
  101. Else
  102. nRet = -1;
  103. Endif; (nDist <= nCloseRange) && ...
  104. Else
  105. nRet = -1;
  106. Endif; (nAngleAtk >= nFaceMin) && ...
  107.  
  108. ;-------------------------------------------------------
  109. ; Return
  110. ;-------------------------------------------------------
  111. return nRet;
  112. EndFunction; getAttackAngle()
  113.  

コンソールやクロスヘアで選択した対象を取得

コンソールやクロスヘアで選択中のオブジェクトのリファレンスを取得したい場合の処理。
Game.GetCurrentConsoleRef()は昔のSKSEではサポートしていなかった関数なので、念の為にバージョンをチェックしている。
  1. ; ----------------------------------------------------------
  2. ; @name getObjectSelected
  3. ; @desc 選択中のオブジェクトを取得する
  4. ; @function
  5. ; @global
  6. ; @param [enableCrosshair=True] {Bool}
  7. ; クロスヘア選択を有効にする
  8. ; @param [enableConsole=True] {Bool}
  9. ; コンソール選択を有効にする
  10. ; @returns {ObjectReference}
  11. ; 取得した収納オブジェクト
  12. ; ----------------------------------------------------------
  13. ObjectReference Function getObjectSelected( \
  14. Bool enableCrosshair = True, \
  15. Bool enableConsole = True \
  16. ) global
  17. ;-------------------------------------------------------
  18. ; Init Variables
  19. ;-------------------------------------------------------
  20. ObjectReference obrfFind;
  21. Int nSkseVer = SKSE.GetScriptVersionRelease();
  22.  
  23. ;-------------------------------------------------------
  24. ; Console selected
  25. ;-------------------------------------------------------
  26. If !obrfFind && enableConsole && (nSkseVer > 47)
  27. obrfFind = \
  28. Game.GetCurrentConsoleRef() as ObjectReference;
  29. Endif
  30.  
  31. ;-------------------------------------------------------
  32. ; Crosshair
  33. ;-------------------------------------------------------
  34. If !obrfFind && enableCrosshair
  35. obrfFind = \
  36. Game.GetCurrentCrosshairRef() as ObjectReference;
  37. Endif
  38.  
  39. ;-------------------------------------------------------
  40. ; Return
  41. ;-------------------------------------------------------
  42. Return obrfFind;
  43. EndFunction; getObjectSelected()
  44.  

ゲーム内の時間取得

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

ゲーム内時間の週を数値で返す

  1. ; ----------------------------------------------------------
  2. ; @name getCurrentWeekIdx
  3. ; @desc ゲーム内時間の週を数値で返す
  4. ; @function
  5. ; @global
  6. ; @returns {Int} 週を示す整数値(0 - 6
  7. ; ----------------------------------------------------------
  8. Int Function getCurrentWeekIdx() global
  9. ;-------------------------------------------------------
  10. ; Init Variables
  11. ;-------------------------------------------------------
  12. Float nGameTime = Utility.GetCurrentGameTime();
  13. Int nDays = Math.Floor(nGameTime);
  14. Int nWeeks = Math.Floor(nDays / 7);
  15. Int nWeekIdx = nDays - (nWeeks * 7);
  16.  
  17. ;-------------------------------------------------------
  18. ; Return
  19. ;-------------------------------------------------------
  20. return nWeekIdx;
  21. EndFunction; getCurrentWeekIdx()
  22.  

ゲーム内時間の時間を数値で返す

  1. ; ----------------------------------------------------------
  2. ; @name getCurrentHour
  3. ; @desc ゲーム内時間の時間を数値で返す
  4. ; @function
  5. ; @global
  6. ; @returns {Int} 時間を示す整数値(0 - 23
  7. ; ----------------------------------------------------------
  8. Int Function getCurrentHour() global
  9. ;-------------------------------------------------------
  10. ; Init Variables
  11. ;-------------------------------------------------------
  12. Float nGameTime = Utility.GetCurrentGameTime();
  13. Int nDays = Math.Floor(nGameTime);
  14. Int nHours = Math.Floor((nGameTime - nDays) * 24);
  15.  
  16. ;-------------------------------------------------------
  17. ; Return
  18. ;-------------------------------------------------------
  19. return nHours;
  20. EndFunction; getCurrentHour()
  21.  

判定処理

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

対象の人が敵性であるかを返す

この例では、敵と判定する為の3つの条件を組み合わせている。
  1. ; ----------------------------------------------------------
  2. ; @name isEnemy
  3. ; @desc 対象の人が敵性であるかを返す
  4. ; @function
  5. ; @global
  6. ; @param actEnemy {Actor} 対象の人
  7. ; @param [actTarget=None] {Actor}
  8. ; 誰に対する敵かを指定(None時はプレイヤーに対する敵)
  9. ; @returns {Bool} 敵性であればtrue
  10. ; ----------------------------------------------------------
  11. Bool function isEnemy(Actor actEnemy, Actor actTarget = None) global
  12. ;-------------------------------------------------------
  13. ; Init Variables
  14. ;-------------------------------------------------------
  15. Bool isEnemy = false;
  16. Int nReaction;
  17. Int nRank;
  18.  
  19. ;-------------------------------------------------------
  20. ; Check Argument
  21. ;-------------------------------------------------------
  22. If !actEnemy
  23. return isEnemy;
  24. Elseif !actTarget
  25. actTarget = Game.GetPlayer();
  26. Endif; !actEnemy
  27.  
  28. ;-------------------------------------------------------
  29. ; Check Actor
  30. ;-------------------------------------------------------
  31. If (actEnemy == actTarget)
  32. return isEnemy;
  33. Endif; (actEnemy == actTarget)
  34.  
  35. ;-------------------------------------------------------
  36. ; Check Hostile
  37. ;-------------------------------------------------------
  38. If !isEnemy
  39. isEnemy = actEnemy.IsHostileToActor(actTarget);
  40. Endif; !isEnemy
  41.  
  42. ;-------------------------------------------------------
  43. ; Check Reaction
  44. ;-------------------------------------------------------
  45. If !isEnemy
  46. ; Obtains this actors faction-based reaction
  47. ; to the other actor
  48. ; 0 - Neutral
  49. ; 1 - Enemy
  50. ; 2 - Ally
  51. ; 3 - Friend
  52. nReaction = actEnemy.getFactionReaction(actTarget);
  53. isEnemy = (nReaction == 1);
  54. Endif; !isEnemy
  55.  
  56. ;-------------------------------------------------------
  57. ; Check Relationship
  58. ;-------------------------------------------------------
  59. If !isEnemy
  60. ; Relationship functions use the following values:
  61. ; 4 - Lover
  62. ; 3 - Ally
  63. ; 2 - Confidant
  64. ; 1 - Friend
  65. ; 0 - Acquaintance
  66. ; -1 - Rival
  67. ; -2 - Foe
  68. ; -3 - Enemy
  69. ; -4 - Archnemesis
  70. nRank = actEnemy.GetRelationshipRank(actTarget);
  71. isEnemy = (nRank <= -2);
  72. Endif; !isEnemy
  73.  
  74. ;-------------------------------------------------------
  75. ; Return
  76. ;-------------------------------------------------------
  77. return isEnemy;
  78. EndFunction; isEnemy()
  79.  

対象の人がフォロワーであるかを返す

フォロワーMODを使用している場合では、判定条件が異なるかも知れない。
  1. ; ----------------------------------------------------------
  2. ; @name isFollower
  3. ; @desc 対象の人がフォロワーであるかを返す
  4. ; @function
  5. ; @global
  6. ; @param actTarget {Actor} 対象の人
  7. ; @returns {Bool} フォロワーであればtrue
  8. ; ----------------------------------------------------------
  9. Bool Function isFollower(Actor actTarget) global
  10. ;-------------------------------------------------------
  11. ; Init Variables
  12. ;-------------------------------------------------------
  13. Faction[] aFollower;
  14. Bool isFollower = false;
  15.  
  16. ;-------------------------------------------------------
  17. ; Get Factions
  18. ;-------------------------------------------------------
  19. ; CurrentFollowerFaction 0x5C84E
  20. ; CurrentHireling 0xBD738
  21. aFollower = new Faction[2];
  22. aFollower[0] = Game.GetForm(0x5C84E) As Faction;
  23. aFollower[1] = Game.GetForm(0xBD738) As Faction;
  24.  
  25. ;-------------------------------------------------------
  26. ; Check Factions
  27. ;-------------------------------------------------------
  28. If actTarget.IsInFaction(aFollower[0]) \
  29. || actTarget.IsInFaction(aFollower[1])
  30. isFollower = true;
  31. Endif; actTarget.IsInFaction(aFollower[0]) || ...
  32.  
  33. ;-------------------------------------------------------
  34. ; Return
  35. ;-------------------------------------------------------
  36. return isFollower;
  37. EndFunction; isFollower()
  38.  

対象の人が魔法使いであるかを返す

この例では、戦闘スタイルで魔法使いかを判定している。
この判定条件が有効かどうかは、使う場面による。
  1. ; ----------------------------------------------------------
  2. ; @name isMagicUser
  3. ; @desc 対象の人が魔法使いであるかを返す
  4. ; @function
  5. ; @global
  6. ; @param actTarget {Actor} 対象の人
  7. ; @returns {Bool} 魔法使いであればtrue
  8. ; ----------------------------------------------------------
  9. Bool Function isMagicUser(Actor actTarget) global
  10. ;-------------------------------------------------------
  11. ; Init Variables
  12. ;-------------------------------------------------------
  13. ActorBase abTarget = actTarget.GetLeveledActorBase();
  14. CombatStyle csTarget = abTarget.GetCombatStyle();
  15. Float nMeleeMult = csTarget.GetMeleeMult();
  16. Float nMagicMult = csTarget.GetMagicMult();
  17. Float nRangedMult = csTarget.GetRangedMult();
  18. Bool isMagicUser = false;
  19.  
  20. ;-------------------------------------------------------
  21. ; Check
  22. ;-------------------------------------------------------
  23. If (nMagicMult > nMeleeMult) || (nMagicMult > nRangedMult)
  24. isMagicUser = true;
  25. Endif; (nMagicMult > nMeleeMult) || (nMagicMult > nRangedMult)
  26.  
  27. ;-------------------------------------------------------
  28. ; Return
  29. ;-------------------------------------------------------
  30. return isMagicUser;
  31. EndFunction; isMagicUser()
  32.  

対象の人がクリーチャーであるかを返す

この例では、人間タイプでないことをクリーチャーの条件としている。
MODで、ActorTypeCreatureのキーワードがないクリーチャーが多い為。
良し悪しあるので、ケェス・バイ・ケェスではある。
  1. ; ----------------------------------------------------------
  2. ; @name isCreature
  3. ; @desc 対象の人がクリーチャーであるかを返す
  4. ; @function
  5. ; @global
  6. ; @param actTarget {Actor} 対象の人
  7. ; @returns {Bool} クリーチャーであればtrue
  8. ; ----------------------------------------------------------
  9. Bool Function isCreature(Actor actTarget) global
  10. ;-------------------------------------------------------
  11. ; Init Variables
  12. ;-------------------------------------------------------
  13. ActorBase abTarget = actTarget.GetLeveledActorBase();
  14. Int nSex = abTarget.GetSex();
  15. Bool isCreature = false;
  16.  
  17. ;-------------------------------------------------------
  18. ; Check Keyword
  19. ;-------------------------------------------------------
  20. If !actTarget.HasKeywordString("ActorTypeNPC")
  21. isCreature = true;
  22. Elseif (nSex == -1)
  23. isCreature = true;
  24. Endif; !actTarget.HasKeywordString("ActorTypeNPC")
  25.  
  26. ;-------------------------------------------------------
  27. ; Return
  28. ;-------------------------------------------------------
  29. return isCreature;
  30. EndFunction; isCreature()
  31.  

対象の人が人間男性であるかを返す

  1. ; ----------------------------------------------------------
  2. ; @name isMale
  3. ; @desc 対象の人が人間男性であるかを返す
  4. ; @function
  5. ; @global
  6. ; @param actTarget {Actor} 対象の人
  7. ; @returns {Bool} 人間男性であればtrue
  8. ; ----------------------------------------------------------
  9. Bool Function isMale(Actor actTarget) global
  10. ;-------------------------------------------------------
  11. ; Init Variables
  12. ;-------------------------------------------------------
  13. ActorBase abTarget = actTarget.GetLeveledActorBase();
  14. Int nSex = abTarget.GetSex();
  15. Bool isMale = false;
  16.  
  17. ;-------------------------------------------------------
  18. ; Check Keyword
  19. ;-------------------------------------------------------
  20. If !actTarget.HasKeywordString("ActorTypeNPC")
  21. isMale = false;
  22. Elseif (nSex == 0)
  23. isMale = true;
  24. Endif; !actTarget.HasKeywordString("ActorTypeNPC")
  25.  
  26. ;-------------------------------------------------------
  27. ; Return
  28. ;-------------------------------------------------------
  29. return isMale;
  30. EndFunction; isMale()
  31.  

対象の人が人間女性であるかを返す

  1. ; ----------------------------------------------------------
  2. ; @name isFemale
  3. ; @desc 対象の人が人間女性であるかを返す
  4. ; @function
  5. ; @global
  6. ; @param actTarget {Actor} 対象の人
  7. ; @returns {Bool} 人間女性であればtrue
  8. ; ----------------------------------------------------------
  9. Bool Function isFemale(Actor actTarget) global
  10. ;-------------------------------------------------------
  11. ; Init Variables
  12. ;-------------------------------------------------------
  13. ActorBase abTarget = actTarget.GetLeveledActorBase();
  14. Int nSex = abTarget.GetSex();
  15. Bool isFemale = false;
  16.  
  17. ;-------------------------------------------------------
  18. ; Check Keyword
  19. ;-------------------------------------------------------
  20. If !actTarget.HasKeywordString("ActorTypeNPC")
  21. isFemale = false;
  22. Elseif (nSex == 1)
  23. isFemale = true;
  24. Endif; !actTarget.HasKeywordString("ActorTypeNPC")
  25.  
  26. ;-------------------------------------------------------
  27. ; Return
  28. ;-------------------------------------------------------
  29. return isFemale;
  30. EndFunction; isFemale()
  31.  

対象の人が戦闘継続可能であるかを返す

その瞬間に継続可能かどうかの判定。GetMass()はラグドール状態かの判定。
  1. ; ----------------------------------------------------------
  2. ; @name canCombat
  3. ; @desc 対象の人が戦闘継続可能であるかを返す
  4. ; @function
  5. ; @global
  6. ; @param [actTarget=None] {Actor}
  7. ; 対象の人 (None時はプレイヤーが対象)
  8. ; @returns {Bool}
  9. ; 戦闘継続可能であればtrue
  10. ; ----------------------------------------------------------
  11. Bool Function canCombat(Actor actTarget = None) global
  12. ;-------------------------------------------------------
  13. ; Init Variables
  14. ;-------------------------------------------------------
  15. Bool canCombat = true;
  16.  
  17. ;-------------------------------------------------------
  18. ; Checking Actor
  19. ;-------------------------------------------------------
  20. If !actTarget
  21. actTarget = Game.GetPlayer();
  22. Endif; !actTarget
  23.  
  24. ;-------------------------------------------------------
  25. ; Checking Keywords
  26. ;-------------------------------------------------------
  27. If !actTarget.Is3DLoaded() \
  28. || actTarget.IsDisabled() \
  29. || actTarget.IsDead() \
  30. || actTarget.IsUnconscious() \
  31. || actTarget.IsBleedingOut() \
  32. || (actTarget.GetMass() != 0)
  33. canCombat = false;
  34. Endif; !actTarget.Is3DLoaded() || ...
  35.  
  36. ;-------------------------------------------------------
  37. ; Return
  38. ;-------------------------------------------------------
  39. return canCombat;
  40. EndFunction; canCombat()
  41.  

パワーアタック判定

スプリント攻撃以外はアニメーション変数「bAllowRotation」で判定できる。
  1. ; Animation event, sent when an object we are listening
  2. ; to hits one of the events we are listening for
  3. Event OnAnimationEvent(ObjectReference akSource, string asEventName)
  4. ;-------------------------------------------------------
  5. ; Init Variables
  6. ;-------------------------------------------------------
  7. Actor actTarget = akSource as Actor;
  8. Bool isPowerAtk = true;
  9.  
  10. ;-------------------------------------------------------
  11. ; Check Power Attack
  12. ;-------------------------------------------------------
  13. If (asEventName == "weaponSwing") \
  14. || (asEventName == "weaponLeftSwing")
  15. isPowerAtk = \
  16. actTarget.GetAnimationVariableBool( \
  17. "bAllowRotation" );
  18. Endif; (szEvent == "weaponSwing") || ...
  19. EndEvent; OnAnimationEvent()
  20.  

The Ultimate Dodge Mod か Nemesis使用環境の場合

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

  1. Event OnAnimationEvent(ObjectReference akSource, string asEventName)
  2. ;-------------------------------------------------------
  3. ; Init Variables
  4. ;-------------------------------------------------------
  5. Bool isPowerAtk = false;
  6.  
  7. ;-------------------------------------------------------
  8. ; Check Power Attack
  9. ;-------------------------------------------------------
  10. If (asEventName == "NextAttackInitiate")
  11. isPowerAtk = false
  12. ElseIf (asEventName == "NextPowerAttackInitiate")
  13. isPowerAtk = true
  14. Endif; (asEventName == "NextAttackInitiate") ElseIf ...
  15. EndEvent; OnAnimationEvent()
  16.  

設備や器具の判定

設備や器具であるかを判定する為の処理例。
基本的には、キーワードで判定することが可能。
椅子などは、キーワードで判定できない場合もあるので注意。
  1. ; ----------------------------------------------------------
  2. ; @name isSittingObject
  3. ; @desc 対象のオブジェクトが座るタイプの家具かどうか
  4. ; @function
  5. ; @global
  6. ; @param obrfTarget {ObjectReference} 対象のオブジェクト
  7. ; @returns {Bool}
  8. ; 座るタイプの家具の場合はtrue
  9. ; ----------------------------------------------------------
  10. Bool Function isSittingObject(ObjectReference obrfTarget) global
  11. ;-------------------------------------------------------
  12. ; Init Variables
  13. ;-------------------------------------------------------
  14. Bool isObject = false;
  15. Form frmTarget = obrfTarget.GetBaseObject();
  16.  
  17. ;-------------------------------------------------------
  18. ; Check the name in the name list
  19. ;-------------------------------------------------------
  20. ; IsTable [KYWD:0009B9A9]
  21. ; isBarStool [KYWD:00074EC7]
  22. If frmTarget.HasKeywordString("IsTable") \
  23. || frmTarget.HasKeywordString("isBarStool")
  24. isObject = true;
  25. Endif; frmTarget.HasKeywordString("IsTable") || ...
  26.  
  27. ;-------------------------------------------------------
  28. ; Return
  29. ;-------------------------------------------------------
  30. return isObject;
  31. EndFunction; isSittingObject()
  32.  
  33. ; ----------------------------------------------------------
  34. ; @name isSleepingObject
  35. ; @desc 対象のオブジェクトが寝るタイプの家具かどうか
  36. ; @function
  37. ; @global
  38. ; @param obrfTarget {ObjectReference} 対象のオブジェクト
  39. ; @returns {Bool}
  40. ; 寝るタイプの家具の場合はtrue
  41. ; ----------------------------------------------------------
  42. Bool Function isSleepingObject(ObjectReference obrfTarget) global
  43. ;-------------------------------------------------------
  44. ; Init Variables
  45. ;-------------------------------------------------------
  46. Bool isObject = false;
  47. Form frmTarget = obrfTarget.GetBaseObject();
  48.  
  49. ;-------------------------------------------------------
  50. ; Check the name in the name list
  51. ;-------------------------------------------------------
  52. ; FurnitureBedRoll [KYWD:000E4AD6]
  53. If frmTarget.HasKeywordString("FurnitureBedRoll")
  54. isObject = true;
  55. Endif; frmTarget.HasKeywordString("FurnitureBedRoll")
  56.  
  57. ;-------------------------------------------------------
  58. ; Return
  59. ;-------------------------------------------------------
  60. return isObject;
  61. EndFunction; isSleepingObject()
  62.  
  63. ; ----------------------------------------------------------
  64. ; @name isAlchemyLab
  65. ; @desc 対象のオブジェクトが錬金器具かどうか
  66. ; @function
  67. ; @global
  68. ; @param obrfTarget {ObjectReference} 対象のオブジェクト
  69. ; @returns {Bool}
  70. ; 錬金器具の場合はtrue
  71. ; ----------------------------------------------------------
  72. Bool Function isAlchemyLab(ObjectReference obrfTarget) global
  73. ;-------------------------------------------------------
  74. ; Init Variables
  75. ;-------------------------------------------------------
  76. Bool isObject = false;
  77. Form frmTarget = obrfTarget.GetBaseObject();
  78.  
  79. ;-------------------------------------------------------
  80. ; Check the name in the name list
  81. ;-------------------------------------------------------
  82. ; isAlchemy [KYWD:0002A40B]
  83. ; WICraftingAlchemy [KYWD:0004F6E6]
  84. If frmTarget.HasKeywordString("isAlchemy") \
  85. || frmTarget.HasKeywordString("WICraftingAlchemy")
  86. isObject = true;
  87. Endif; frmTarget.HasKeywordString("isAlchemy") || ...
  88.  
  89. ;-------------------------------------------------------
  90. ; Return
  91. ;-------------------------------------------------------
  92. return isObject;
  93. EndFunction; isAlchemyLab()
  94.  
  95. ; ----------------------------------------------------------
  96. ; @name isCookingObject
  97. ; @desc 対象のオブジェクトが調理器具かどうか
  98. ; @function
  99. ; @global
  100. ; @param obrfTarget {ObjectReference} 対象のオブジェクト
  101. ; @returns {Bool}
  102. ; 調理器具の場合はtrue
  103. ; ----------------------------------------------------------
  104. Bool Function isCookingObject(ObjectReference obrfTarget) global
  105. ;-------------------------------------------------------
  106. ; Init Variables
  107. ;-------------------------------------------------------
  108. Bool isObject = false;
  109. Form frmTarget = obrfTarget.GetBaseObject();
  110.  
  111. ;-------------------------------------------------------
  112. ; Check the name in the name list
  113. ;-------------------------------------------------------
  114. ; isCookingSpit [KYWD:00068ADA]
  115. ; CraftingCookpot [KYWD:000A5CB3]
  116. ; isSmallCookingPot [KYWD:001010B2]
  117. ; isSmallCookingPotDBPoison [KYWD:001010B5]
  118. ; isCraftingOven [KYWD:01002840]
  119. If frmTarget.HasKeywordString("isCookingSpit") \
  120. || frmTarget.HasKeywordString("isCraftingOven") \
  121. || frmTarget.HasKeywordString("CraftingCookpot") \
  122. || frmTarget.HasKeywordString("isSmallCookingPot") \
  123. || frmTarget.HasKeywordString("isSmallCookingPotDBPoison")
  124. isObject = true;
  125. Endif; frmTarget.HasKeywordString("isCookingSpit") || ...
  126.  
  127. ;-------------------------------------------------------
  128. ; Return
  129. ;-------------------------------------------------------
  130. return isObject;
  131. EndFunction; isCookingObject()
  132.  
  133. ; ----------------------------------------------------------
  134. ; @name isEnchanter
  135. ; @desc 対象のオブジェクトが通常の付呪器具かどうか
  136. ; @function
  137. ; @global
  138. ; @param obrfTarget {ObjectReference} 対象のオブジェクト
  139. ; @returns {Bool}
  140. ; 通常の付呪器具の場合はtrue
  141. ; ----------------------------------------------------------
  142. Bool Function isEnchanter(ObjectReference obrfTarget) global
  143. ;-------------------------------------------------------
  144. ; Init Variables
  145. ;-------------------------------------------------------
  146. Bool isObject = false;
  147. Form frmTarget = obrfTarget.GetBaseObject();
  148.  
  149. ;-------------------------------------------------------
  150. ; Check the name in the name list
  151. ;-------------------------------------------------------
  152. ; isEnchanting [KYWD:0006E2A3]
  153. ; WICraftingEnchanting [KYWD:0004F6DD]
  154. ; DLC2StaffEnchanter [KYWD:02017738]
  155. If frmTarget.HasKeywordString("DLC2StaffEnchanter")
  156. isObject = false;
  157. Elseif frmTarget.HasKeywordString("isEnchanting") \
  158. || frmTarget.HasKeywordString("WICraftingEnchanting")
  159. isObject = true;
  160. Endif; frmTarget.HasKeywordString("DLC2StaffEnchanter")
  161.  
  162. ;-------------------------------------------------------
  163. ; Return
  164. ;-------------------------------------------------------
  165. return isObject;
  166. EndFunction; isEnchanter()
  167.  
  168. ; ----------------------------------------------------------
  169. ; @name isStaffEnchanter
  170. ; @desc 対象のオブジェクトが杖の付呪器具かどうか
  171. ; @function
  172. ; @global
  173. ; @param obrfTarget {ObjectReference} 対象のオブジェクト
  174. ; @returns {Bool}
  175. ; 杖の付呪器具の場合はtrue
  176. ; ----------------------------------------------------------
  177. Bool Function isStaffEnchanter(ObjectReference obrfTarget) global
  178. ;-------------------------------------------------------
  179. ; Init Variables
  180. ;-------------------------------------------------------
  181. Bool isObject = false;
  182. Form frmTarget = obrfTarget.GetBaseObject();
  183.  
  184. ;-------------------------------------------------------
  185. ; Check the name in the name list
  186. ;-------------------------------------------------------
  187. ; DLC2StaffEnchanter [KYWD:02017738]
  188. If frmTarget.HasKeywordString("DLC2StaffEnchanter")
  189. isObject = true;
  190. Endif; frmTarget.HasKeywordString("DLC2StaffEnchanter")
  191.  
  192. ;-------------------------------------------------------
  193. ; Return
  194. ;-------------------------------------------------------
  195. return isObject;
  196. EndFunction; isStaffEnchanter()
  197.  
  198. ; ----------------------------------------------------------
  199. ; @name isSharpeningWheel
  200. ; @desc 対象のオブジェクトが研ぎ石かどうか
  201. ; @function
  202. ; @global
  203. ; @param obrfTarget {ObjectReference} 対象のオブジェクト
  204. ; @returns {Bool}
  205. ; 研ぎ石の場合はtrue
  206. ; ----------------------------------------------------------
  207. Bool Function isSharpeningWheel(ObjectReference obrfTarget) global
  208. ;-------------------------------------------------------
  209. ; Init Variables
  210. ;-------------------------------------------------------
  211. Bool isObject = false;
  212. Form frmTarget = obrfTarget.GetBaseObject();
  213.  
  214. ;-------------------------------------------------------
  215. ; Check the name in the name list
  216. ;-------------------------------------------------------
  217. ; WICraftingSmithingTempering [KYWD:0004F6FD]
  218. ; CraftingSmithingSharpeningWheel [KYWD:00088108]
  219. If frmTarget.HasKeywordString("WICraftingSmithingTempering") \
  220. || frmTarget.HasKeywordString("CraftingSmithingSharpeningWheel")
  221. isObject = true;
  222. Endif; frmTarget.HasKeywordString("WICraftingSmithingTempering") || ...
  223.  
  224. ;-------------------------------------------------------
  225. ; Return
  226. ;-------------------------------------------------------
  227. return isObject;
  228. EndFunction; isSharpeningWheel()
  229.  
  230. ; ----------------------------------------------------------
  231. ; @name isArmorTable
  232. ; @desc 対象のオブジェクトが作業机かどうか
  233. ; @function
  234. ; @global
  235. ; @param obrfTarget {ObjectReference} 対象のオブジェクト
  236. ; @returns {Bool}
  237. ; 作業机の場合はtrue
  238. ; ----------------------------------------------------------
  239. Bool Function isArmorTable(ObjectReference obrfTarget) global
  240. ;-------------------------------------------------------
  241. ; Init Variables
  242. ;-------------------------------------------------------
  243. Bool isObject = false;
  244. Form frmTarget = obrfTarget.GetBaseObject();
  245.  
  246. ;-------------------------------------------------------
  247. ; Check the name in the name list
  248. ;-------------------------------------------------------
  249. ; isBlacksmithWorkbench [KYWD:000D932E]
  250. ; CraftingSmithingArmorTable [KYWD:000ADB78]
  251. If frmTarget.HasKeywordString("isBlacksmithWorkbench") \
  252. || frmTarget.HasKeywordString("CraftingSmithingArmorTable")
  253. isObject = true;
  254. Endif; frmTarget.HasKeywordString("isBlacksmithWorkbench") || ...
  255.  
  256. ;-------------------------------------------------------
  257. ; Return
  258. ;-------------------------------------------------------
  259. return isObject;
  260. EndFunction; isArmorTable()
  261.  
  262. ; ----------------------------------------------------------
  263. ; @name isForge
  264. ; @desc 対象のオブジェクトが鍛造器具かどうか
  265. ; @function
  266. ; @global
  267. ; @param obrfTarget {ObjectReference} 対象のオブジェクト
  268. ; @returns {Bool}
  269. ; 鍛造器具の場合はtrue
  270. ; ----------------------------------------------------------
  271. Bool Function isForge(ObjectReference obrfTarget) global
  272. ;-------------------------------------------------------
  273. ; Init Variables
  274. ;-------------------------------------------------------
  275. Bool isObject = false;
  276. Form frmTarget = obrfTarget.GetBaseObject();
  277.  
  278. ;-------------------------------------------------------
  279. ; Check the name in the name list
  280. ;-------------------------------------------------------
  281. ; isBlacksmithForge [KYWD:000CAE0A]
  282. ; CraftingSmithingForge [KYWD:00088105]
  283. ; isBlacksmithAnvil [KYWD:000EB60B]
  284. If frmTarget.HasKeywordString("isBlacksmithForge") \
  285. || frmTarget.HasKeywordString("isBlacksmithAnvil") \
  286. || frmTarget.HasKeywordString("CraftingSmithingForge")
  287. isObject = true;
  288. Endif; frmTarget.HasKeywordString("isBlacksmithForge") || ...
  289.  
  290. ;-------------------------------------------------------
  291. ; Return
  292. ;-------------------------------------------------------
  293. return isObject;
  294. EndFunction; isForge()
  295.  
  296. ; ----------------------------------------------------------
  297. ; @name isTanningRack
  298. ; @desc 対象のオブジェクトが皮なめしかどうか
  299. ; @function
  300. ; @global
  301. ; @param obrfTarget {ObjectReference} 対象のオブジェクト
  302. ; @returns {Bool}
  303. ; 皮なめしの場合はtrue
  304. ; ----------------------------------------------------------
  305. Bool Function isTanningRack(ObjectReference obrfTarget) global
  306. ;-------------------------------------------------------
  307. ; Init Variables
  308. ;-------------------------------------------------------
  309. Bool isObject = false;
  310. Form frmTarget = obrfTarget.GetBaseObject();
  311.  
  312. ;-------------------------------------------------------
  313. ; Check the name in the name list
  314. ;-------------------------------------------------------
  315. ; isTanning [KYWD:000727A0]
  316. ; CraftingTanningRack [KYWD:0007866A]
  317. If frmTarget.HasKeywordString("isTanning") \
  318. || frmTarget.HasKeywordString("CraftingTanningRack")
  319. isObject = true;
  320. Endif; frmTarget.HasKeywordString("isTanning") || ...
  321.  
  322. ;-------------------------------------------------------
  323. ; Return
  324. ;-------------------------------------------------------
  325. return isObject;
  326. EndFunction; isTanningRack()
  327.  
  328. ; ----------------------------------------------------------
  329. ; @name isSmelter
  330. ; @desc 対象のオブジェクトが溶鉱炉かどうか
  331. ; @function
  332. ; @global
  333. ; @param obrfTarget {ObjectReference} 対象のオブジェクト
  334. ; @returns {Bool}
  335. ; 溶鉱炉の場合はtrue
  336. ; ----------------------------------------------------------
  337. Bool Function isSmelter(ObjectReference obrfTarget) global
  338. ;-------------------------------------------------------
  339. ; Init Variables
  340. ;-------------------------------------------------------
  341. Bool isObject = false;
  342. Form frmTarget = obrfTarget.GetBaseObject();
  343.  
  344. ;-------------------------------------------------------
  345. ; Check the name in the name list
  346. ;-------------------------------------------------------
  347. ; isSmelter [KYWD:0009C6C3]
  348. ; CraftingSmelter [KYWD:000A5CCE]
  349. If frmTarget.HasKeywordString("isSmelter") \
  350. || frmTarget.HasKeywordString("CraftingSmelter")
  351. isObject = true;
  352. Endif; frmTarget.HasKeywordString("isSmelter") || ...
  353.  
  354. ;-------------------------------------------------------
  355. ; Return
  356. ;-------------------------------------------------------
  357. return isObject;
  358. EndFunction; isSmelter()
  359.  
  360. ; ----------------------------------------------------------
  361. ; @name isWoodChoppingBlock
  362. ; @desc 対象のオブジェクトが薪割りかどうか
  363. ; @function
  364. ; @global
  365. ; @param obrfTarget {ObjectReference} 対象のオブジェクト
  366. ; @returns {Bool}
  367. ; 薪割りの場合はtrue
  368. ; ----------------------------------------------------------
  369. Bool Function isWoodChoppingBlock(ObjectReference obrfTarget) global
  370. ;-------------------------------------------------------
  371. ; Init Variables
  372. ;-------------------------------------------------------
  373. Bool isObject = false;
  374. Form frmTarget = obrfTarget.GetBaseObject();
  375.  
  376. ;-------------------------------------------------------
  377. ; Check the name in the name list
  378. ;-------------------------------------------------------
  379. ; FurnitureWoodChoppingBlock / 0x00072dfb (KYWD)
  380. If frmTarget.HasKeywordString("FurnitureWoodChoppingBlock")
  381. isObject = true;
  382. Endif; frmTarget.HasKeywordString("FurnitureWoodChoppingBlock")
  383.  
  384. ;-------------------------------------------------------
  385. ; Return
  386. ;-------------------------------------------------------
  387. return isObject;
  388. EndFunction; isWoodChoppingBlock()
  389.  
  390. ; ----------------------------------------------------------
  391. ; @name isOreVein
  392. ; @desc 対象のオブジェクトが鉱脈かどうか
  393. ; @function
  394. ; @global
  395. ; @param obrfTarget {ObjectReference} 対象のオブジェクト
  396. ; @returns {Bool}
  397. ; 鉱脈の場合はtrue
  398. ; ----------------------------------------------------------
  399. Bool Function isOreVein(ObjectReference obrfTarget) global
  400. ;-------------------------------------------------------
  401. ; Init Variables
  402. ;-------------------------------------------------------
  403. Bool isObject = false;
  404. Form frmTarget = obrfTarget.GetBaseObject();
  405.  
  406. ;-------------------------------------------------------
  407. ; Check the name in the name list
  408. ;-------------------------------------------------------
  409. ; isPickaxeFloor [KYWD:000613A8]
  410. ; isPickaxeTable [KYWD:000613A9]
  411. ; isPickaxeWall [KYWD:000A82C3]
  412. If frmTarget.HasKeywordString("isPickaxeFloor") \
  413. || frmTarget.HasKeywordString("isPickaxeTable") \
  414. || frmTarget.HasKeywordString("isPickaxeWall")
  415. isObject = true;
  416. Endif; frmTarget.HasKeywordString("isPickaxeFloor") || ...
  417.  
  418. ;-------------------------------------------------------
  419. ; Return
  420. ;-------------------------------------------------------
  421. return isObject;
  422. EndFunction; isOreVein()
  423.  

盗み判定

盗みかどうかを判定する関数はない為、不法侵入と所有権で判定している。
  1. Bool Function isStealing(ObjectReference obrfTarget, Actor actTarget)
  2. ;-------------------------------------------------------
  3. ; Declare Variables
  4. ;-------------------------------------------------------
  5. Bool isStealing;
  6. ActorBase abTarget;
  7. Cell celThis;
  8. ActorBase abOwnThis;
  9. Faction fctOwnThis;
  10. ActorBase abOwnHere;
  11. Faction fctOwnHere;
  12.  
  13. ;-------------------------------------------------------
  14. ; Init Variables
  15. ;-------------------------------------------------------
  16. isStealing = actTarget.IsTrespassing();
  17. abTarget = actTarget.GetActorBase();
  18. celThis = obrfTarget.GetParentCell();
  19. abOwnThis = obrfTarget.GetActorOwner();
  20. fctOwnThis = obrfTarget.GetFactionOwner();
  21. abOwnHere = celThis.GetActorOwner();
  22. fctOwnHere = celThis.GetFactionOwner();
  23.  
  24. ;-------------------------------------------------------
  25. ; Check Stealing
  26. ;-------------------------------------------------------
  27. If abOwnThis && (abOwnThis != abTarget)
  28. isStealing = true;
  29. Elseif abOwnHere && (abOwnHere != abTarget)
  30. isStealing = true;
  31. Elseif fctOwnThis && !actTarget.IsInFaction(fctOwnThis)
  32. isStealing = true;
  33. Elseif fctOwnHere && !actTarget.IsInFaction(fctOwnHere)
  34. isStealing = true;
  35. Endif; abOwnThis && (abOwnThis != abTarget)
  36.  
  37. ;-------------------------------------------------------
  38. ; Return
  39. ;-------------------------------------------------------
  40. return true;
  41. EndFunction; isStealing()
  42.  

配置オブジェクトの操作

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

配置オブジェクトを一括で初期位置に戻す

MoveToMyEditorLocation()が初期位置に戻す処理。
この例では、nObjectTypeでオブジェクトの種類を指定して、セル内のオブジェクトを一括で元の位置に戻している。
  1. ; ----------------------------------------------------------
  2. ; @name resetPositionsByObjectTypeIn
  3. ; @function
  4. ; @global
  5. ; @param [celTarget=None] {Cell}
  6. ; @param [nObjectType=0] {Int}
  7. ; @returns {Int}
  8. ; ----------------------------------------------------------
  9. Int Function resetPositionsByObjectTypeIn( \
  10. Cell celTarget = None, \
  11. Int nObjectType = 0 \
  12. ) global
  13. ;-------------------------------------------------------
  14. ; Init Variables
  15. ;-------------------------------------------------------
  16. ObjectReference obrfEach;
  17. Int nIdx;
  18. Int nCnt;
  19. Int nReset = 0;
  20.  
  21. ;-------------------------------------------------------
  22. ; Check the target cell
  23. ;-------------------------------------------------------
  24. If !celTarget
  25. celTarget = Game.GetPlayer().GetParentCell();
  26. Endif; !celTarget
  27.  
  28. ;-------------------------------------------------------
  29. ; Loop of objects
  30. ;-------------------------------------------------------
  31. nIdx = 0;
  32. nCnt = celTarget.GetNumRefs(nObjectType);
  33.  
  34. While (nIdx < nCnt)
  35. obrfEach = celTarget.GetNthRef(nIdx, nObjectType);
  36.  
  37. If obrfEach
  38. obrfEach.MoveToMyEditorLocation();
  39. nReset += 1;
  40. Endif; obrfEach
  41.  
  42. nIdx += 1;
  43. EndWhile; (nIdx < nCnt)
  44.  
  45. ;-------------------------------------------------------
  46. ; Return
  47. ;-------------------------------------------------------
  48. return nReset;
  49. EndFunction; resetPositionsByObjectTypeIn()
  50.  

配置オブジェクトを一括で固定化する

SetMotionType()でMotion_Keyframedを指定すると、オブジェクトが固定化されて動かなくなる。
つまり、体当たりしても動かないオブジェクトになる。
この例では、nObjectTypeでオブジェクトの種類を指定して、セル内のオブジェクトを一括で固定化したり、固定化を解除したりしている。
  1. ; ----------------------------------------------------------
  2. ; @name setMotionTypeByObjectTypeIn
  3. ; @function
  4. ; @global
  5. ; @param [celTarget=None] {Cell}
  6. ; @param [enableLock=true] {Bool}
  7. ; @param [nObjectType=0] {Int}
  8. ; @returns {Int}
  9. ; ----------------------------------------------------------
  10. Int Function setMotionTypeByObjectTypeIn( \
  11. Cell celTarget = None, \
  12. Bool enableLock = true, \
  13. Int nObjectType = 0 \
  14. ) global
  15. ;-------------------------------------------------------
  16. ; Init Variables
  17. ;-------------------------------------------------------
  18. ObjectReference obrfEach;
  19. Int nIdx;
  20. Int nCnt;
  21. Int nLockCnt = 0;
  22.  
  23. ;-------------------------------------------------------
  24. ; Check the target cell
  25. ;-------------------------------------------------------
  26. If !celTarget
  27. celTarget = Game.GetPlayer().GetParentCell();
  28. Endif
  29.  
  30. ;-------------------------------------------------------
  31. ; Loop of objects
  32. ;-------------------------------------------------------
  33. nIdx = 0;
  34. nCnt = celTarget.GetNumRefs(nObjectType);
  35.  
  36. While (nIdx < nCnt)
  37. obrfEach = celTarget.GetNthRef(nIdx, nObjectType);
  38.  
  39. ; Motion_Dynamic = 1
  40. ; Motion_SphereIntertia = 2
  41. ; Motion_BoxIntertia = 3
  42. ; Motion_Keyframed = 4
  43. ; Motion_Fixed = 5
  44. ; Motion_ThinBoxIntertia = 6
  45. ; Motion_Character = 7
  46. If obrfEach.GetMass() && enableLock
  47. obrfEach.SetMotionType(obrfEach.Motion_Keyframed);
  48. nLockCnt += 1;
  49. Elseif !enableLock
  50. obrfEach.SetMotionType(obrfEach.Motion_Dynamic);
  51. nLockCnt += 1;
  52. Endif
  53.  
  54. nIdx += 1;
  55. EndWhile
  56.  
  57. ;-------------------------------------------------------
  58. ; Return
  59. ;-------------------------------------------------------
  60. return nLockCnt;
  61. EndFunction; setMotionTypeByObjectTypeIn()
  62.  

配置オブジェクトを一括で収集する

死体は単純にMoveTo()では移動できないので、Disable()してMoveTo()してEnable()している。
  1. ; ----------------------------------------------------------
  2. ; @name gatherObjectsIn
  3. ; @function
  4. ; @global
  5. ; @param [celTarget=None] {Cell}
  6. ; @param [obrfMoveTo=None] {ObjectReference}
  7. ; @param [nType=0] {Int}
  8. ; Form-Type
  9. ; @param [nIsDeadAlive=0] {Int}
  10. ; 0 = both, 1 = lives only, -1 = deads only
  11. ; @returns {Bool}
  12. ; ----------------------------------------------------------
  13. Bool Function gatherObjectsIn( \
  14. Cell celTarget = None, \
  15. ObjectReference obrfMoveTo = None, \
  16. Int nType = 0, \
  17. Int nIsDeadAlive = 0 \
  18. ) global
  19. ;-------------------------------------------------------
  20. ; Init Variables
  21. ;-------------------------------------------------------
  22. Int nIdx;
  23. Int nCnt;
  24. ObjectReference obrfEach;
  25. Actor actEach;
  26.  
  27. ;-------------------------------------------------------
  28. ; Check arguments
  29. ;-------------------------------------------------------
  30. If !obrfMoveTo
  31. obrfMoveTo = Game.GetPlayer() as ObjectReference;
  32. Endif
  33.  
  34. If !celTarget
  35. celTarget = obrfMoveTo.GetParentCell();
  36. Endif
  37.  
  38. ;-------------------------------------------------------
  39. ; Scan chests
  40. ;-------------------------------------------------------
  41. nIdx = 0;
  42. nCnt = celTarget.GetNumRefs(nType);
  43.  
  44. While (nIdx < nCnt)
  45. obrfEach = celTarget.GetNthRef(nIdx, nType);
  46.  
  47. If !obrfEach.IsEnabled() || obrfEach.IsDeleted()
  48. obrfEach = None;
  49. Endif
  50.  
  51. If obrfEach && (nType == 43)
  52. actEach = obrfEach as Actor;
  53. Else
  54. actEach = None;
  55. Endif
  56.  
  57. If actEach
  58. If (nIsDeadAlive > 0) && actEach.IsDead()
  59. obrfEach = None;
  60. actEach = None;
  61. Elseif (nIsDeadAlive < 0) && !actEach.IsDead()
  62. obrfEach = None;
  63. actEach = None;
  64. Endif
  65. Endif
  66.  
  67. If actEach && (nType == 43)
  68. If actEach.IsDead()
  69. actEach.Disable();
  70. Endif; actEach.IsDead()
  71.  
  72. actEach.MoveTo(obrfMoveTo);
  73.  
  74. If actEach.IsDead()
  75. actEach.Enable();
  76. Endif; actEach.IsDead()
  77. Elseif !actEach && obrfEach
  78. obrfEach.MoveTo(obrfMoveTo);
  79. Endif
  80.  
  81. nIdx += 1;
  82. EndWhile
  83.  
  84. ;-------------------------------------------------------
  85. ; Return
  86. ;-------------------------------------------------------
  87. return true;
  88. EndFunction; gatherObjectsIn()
  89.  

配置オブジェクトを一括で検知する

変性呪文の検知魔法のようなもの。スクリプトで実装すれば、好きなエフェクトを設定できる。
  1. ; ----------------------------------------------------------
  2. ; @name detectObjectsIn
  3. ; @function
  4. ; @global
  5. ; @param [celTarget=None] {Cell}
  6. ; @param [nType=0] {Int}
  7. ; Form-Type
  8. ; @param [isLootableOnly=false] {Bool}
  9. ; @param [nIsDeadAlive=0] {Int}
  10. ; 0 = both, 1 = lives only, -1 = deads only
  11. ; @returns {Bool}
  12. ; ----------------------------------------------------------
  13. Bool Function detectObjectsIn( \
  14. Cell celTarget = None, \
  15. Int nType = 0, \
  16. Bool isLootableOnly = false, \
  17. Int nIsDeadAlive = 0 \
  18. ) global
  19. ;-------------------------------------------------------
  20. ; Init Variables
  21. ;-------------------------------------------------------
  22. Int nIdx;
  23. Int nCnt;
  24. ObjectReference obrfEach;
  25. Actor actEach;
  26. Actor actPlayer = Game.GetPlayer();
  27. EffectShader efsEnemy;
  28. EffectShader efsAlly;
  29. Hazard hzdDetect;
  30. Bool isLootable;
  31.  
  32. ;-------------------------------------------------------
  33. ; Get Effect
  34. ;-------------------------------------------------------
  35. ; LifeDetected [EFSH:0x000146]
  36. ; LifeDetectedEnemy [EFSH:0x0DC209]
  37. ; LifeDetectedUndead [EFSH:0x0AAEB3]
  38. ; LifeDetectedUndeadEnemy [EFSH:0x016439]
  39. ; KynesPeaceFXS [EFSH:0x084B39]
  40. ; HealCircleFXS [EFSH:0x10CDC9]
  41. ; WerewolfTransFXS [EFSH:0x0EBEC5]
  42. ; WerewolfTrans02FXS [EFSH:0x0EBECD]
  43. ; DragonPowerAbsorbFXS [EFSH:0x0280C0]
  44. ; AbsorbBlueFXS [EFSH:0x0ABF08]
  45. ; AbsorbGreenFXS [EFSH:0x0ABF07]
  46. ; AbsorbHealthFXS [EFSH:0x0ABEFF]
  47. efsAlly = Game.GetForm(0x000146) as EffectShader;
  48. efsEnemy = Game.GetForm(0x0DC209) as EffectShader;
  49. ; CircleOfProtectionHazard [HAZD:0x04E80C]
  50. ; CircleVitalityHazard [HAZD:0x0B62EA]
  51. ; GuardianCircleHazard [HAZD:0x0E0CD3]
  52. ; GuardianCircleTurnHazard [HAZD:0x0FEAD3]
  53. hzdDetect = Game.GetForm(0x04E80C) as Hazard;
  54.  
  55. ;-------------------------------------------------------
  56. ; Check the target cell
  57. ;-------------------------------------------------------
  58. If !celTarget
  59. celTarget = Game.GetPlayer().GetParentCell();
  60. Endif
  61.  
  62. ;-------------------------------------------------------
  63. ; Scan chests
  64. ;-------------------------------------------------------
  65. nIdx = 0;
  66. nCnt = celTarget.GetNumRefs(nType);
  67.  
  68. While (nIdx < nCnt)
  69. obrfEach = celTarget.GetNthRef(nIdx, nType);
  70.  
  71. If !obrfEach.IsEnabled() || obrfEach.IsDeleted()
  72. obrfEach = None;
  73. Endif
  74.  
  75. If obrfEach && (nType == 43)
  76. actEach = obrfEach as Actor;
  77. Else
  78. actEach = None;
  79. Endif
  80.  
  81. If actEach
  82. If (nIsDeadAlive > 0) && actEach.IsDead()
  83. obrfEach = None;
  84. actEach = None;
  85. Elseif (nIsDeadAlive < 0) && !actEach.IsDead()
  86. obrfEach = None;
  87. actEach = None;
  88. Endif
  89. Endif
  90.  
  91. If !isLootableOnly
  92. isLootable = false;
  93. Elseif actEach
  94. isLootable = (actEach.GetNumItems() > 1);
  95. Elseif obrfEach && (nType == 28)
  96. isLootable = (obrfEach.GetNumItems() > 0);
  97. Else
  98. isLootable = false;
  99. Endif
  100.  
  101. If isLootableOnly && !isLootable
  102. obrfEach = None;
  103. actEach = None;
  104. Endif
  105.  
  106. If actEach && (nType == 43)
  107. If isEnemy(actEach)
  108. efsEnemy.Play(actEach, 26.0);
  109. Else
  110. efsAlly.Play(actEach, 26.0);
  111. Endif; isEnemy(actEach)
  112. Elseif !actEach && obrfEach
  113. obrfEach.placeAtMe(hzdDetect);
  114. Endif
  115.  
  116. nIdx += 1;
  117. EndWhile
  118.  
  119. ;-------------------------------------------------------
  120. ; Return
  121. ;-------------------------------------------------------
  122. return true;
  123. EndFunction; detectObjectsIn()
  124.  

NPCを操作する

NPCをPCのように操作する為に必要な一連の処理。
PCの操作停止、NPCの操作、カメラの切替、など。
  1. Bool Function startNpcControl(Actor actTarget)
  2. ;-------------------------------------------------------
  3. ; Init Variables
  4. ;-------------------------------------------------------
  5.  
  6. ;-------------------------------------------------------
  7. ; Start controlling
  8. ;-------------------------------------------------------
  9. Game.DisablePlayerControls( \
  10. abMovement = false, \
  11. abFighting = true, \
  12. abCamSwitch = false, \
  13. abLooking = false, \
  14. abSneaking = false, \
  15. abMenu = true, \
  16. abActivate = false, \
  17. abJournalTabs = false, \
  18. aiDisablePOVType = 0 );
  19. actTarget.SetPlayerControls(true);
  20. Game.SetPlayerAIDriven(true);
  21. actTarget.EnableAI();
  22. Game.SetCameraTarget(actTarget);
  23. Game.ForceThirdPerson();
  24.  
  25. ;-------------------------------------------------------
  26. ; Return
  27. ;-------------------------------------------------------
  28. Return true;
  29. EndFunction; startNpcControl()
  30.  
  31. Bool Function stopNpcControl(Actor actTarget)
  32. ;-------------------------------------------------------
  33. ; Init Variables
  34. ;-------------------------------------------------------
  35. Actor actPlayer = Game.GetPlayer();
  36.  
  37. ;-------------------------------------------------------
  38. ; Switch the controlling
  39. ;-------------------------------------------------------
  40. actTarget.SetPlayerControls(false);
  41. Game.SetPlayerAIDriven(false);
  42. Game.EnablePlayerControls();
  43. actTarget.EnableAI();
  44. Game.SetCameraTarget(actPlayer);
  45.  
  46. ;-------------------------------------------------------
  47. ; Return
  48. ;-------------------------------------------------------
  49. Return true;
  50. EndFunction; stopNpcControl()
  51.  

マップ・マーカーを表示する

指定したクエストのエイリアスに任意のリファレンスをマーカーとして表示する。
クエストは名前でも指定可能。エイリアスは名前やIDや番号でも指定可能。
例では、isActiveで表示と非表示を切り替える。
  1. ; ----------------------------------------------------------
  2. ; @name showMapMarker
  3. ; @function
  4. ; @global
  5. ; @param obrfTarget {ObjectReference}
  6. ; @param [isActive=true] {Bool}
  7. ; @param [szQuestName=] {String}
  8. ; @param [nObjective=1] {Int}
  9. ; @param [szAliasName=RefAlias001] {String}
  10. ; @param [qstMarker=None] {Quest}
  11. ; @param [ralsMarker=None] {ReferenceAlias}
  12. ; @param [nAliasIdx=-1] {Int}
  13. ; @param [nAliasID=-1] {Int}
  14. ; @returns {Bool}
  15. ; ----------------------------------------------------------
  16. Bool Function showMapMarker( \
  17. ObjectReference obrfTarget, \
  18. Bool isActive = true, \
  19. String szQuestName = "", \
  20. Int nObjective = 1, \
  21. String szAliasName = "RefAlias001", \
  22. Quest qstMarker = None, \
  23. ReferenceAlias ralsMarker = None, \
  24. Int nAliasIdx = -1, \
  25. Int nAliasID = -1 \
  26. ) global
  27. ;-------------------------------------------------------
  28. ; Init Variables
  29. ;-------------------------------------------------------
  30. Bool isOK = false;
  31.  
  32. ;-------------------------------------------------------
  33. ; Check Arguments
  34. ;-------------------------------------------------------
  35. If !obrfTarget
  36. return isOK;
  37. Endif
  38.  
  39. ;-------------------------------------------------------
  40. ; Get Marker Quest
  41. ;-------------------------------------------------------
  42. If !qstMarker
  43. qstMarker = Quest.GetQuest(szQuestName);
  44. Endif
  45.  
  46. If !qstMarker
  47. return isOK;
  48. Endif
  49.  
  50. ;-------------------------------------------------------
  51. ; Get Reference Alias
  52. ;-------------------------------------------------------
  53. If !ralsMarker && (nAliasIdx >= 0)
  54. ralsMarker = \
  55. qstMarker.GetNthAlias( \
  56. nAliasIdx ) as ReferenceAlias;
  57. Elseif !ralsMarker && (nAliasID >= 0)
  58. ralsMarker = \
  59. qstMarker.GetAliasById( \
  60. nAliasID ) as ReferenceAlias;
  61. Elseif !ralsMarker && (szAliasName != "")
  62. ralsMarker = \
  63. qstMarker.GetAliasByName( \
  64. szAliasName ) as ReferenceAlias;
  65. Endif
  66.  
  67. If !ralsMarker
  68. return isOK;
  69. Endif
  70.  
  71. ;-------------------------------------------------------
  72. ; Show Marker
  73. ;-------------------------------------------------------
  74. If isActive
  75. ralsMarker.ForceRefTo(obrfTarget);
  76. qstMarker.SetObjectiveDisplayed( \
  77. nObjective, true, false );
  78. isOK = true;
  79. Else
  80. ralsMarker.Clear();
  81. qstMarker.SetObjectiveDisplayed( \
  82. nObjective, false, false );
  83. isOK = true;
  84. Endif
  85.  
  86. ;-------------------------------------------------------
  87. ; Return
  88. ;-------------------------------------------------------
  89. return isOK;
  90. EndFunction; showMapMarker()
  91.  

対象の人の戦闘を強制停止させる

戦闘を停止させる処理の詰め合わせ。
StopCombat()は対象のアクターの戦闘状態を停止させることしか出来ない。
本格的に戦闘停止させるには、警戒状態も解除し、相手方の戦闘状態も解除する必要がある。
disableRecoverのオプションは、戦闘停止時に全回復するようなMOD対策。
戦闘停止後に、停止前の体力に強制的に戻す為のオプション。
  1. ; ----------------------------------------------------------
  2. ; @name stopCombatEx
  3. ; @function
  4. ; @global
  5. ; @param actTarget {Actor}
  6. ; @param [disableRecover=true] {Bool}
  7. ; @param [enableStopAlarm=false] {Bool}
  8. ; @param [enableStopTarget=false] {Bool}
  9. ; @returns {Bool}
  10. ; ----------------------------------------------------------
  11. Bool Function stopCombatEx( \
  12. Actor actTarget, \
  13. Bool disableRecover = true, \
  14. Bool enableStopAlarm = false, \
  15. Bool enableStopTarget = false \
  16. ) global
  17. ;-------------------------------------------------------
  18. ; Init Variables
  19. ;-------------------------------------------------------
  20. Float nHealth;
  21. Float nDamage;
  22. Actor actEnemy;
  23.  
  24. ;-------------------------------------------------------
  25. ; Check Arguments
  26. ;-------------------------------------------------------
  27. If !actTarget || !actTarget.IsInCombat()
  28. return false;
  29. Endif; !actTarget || !actTarget.IsInCombat()
  30.  
  31. ;-------------------------------------------------------
  32. ; Get Current Health
  33. ;-------------------------------------------------------
  34. If disableRecover
  35. nHealth = actTarget.GetActorValue("Health");
  36. Endif; disableRecover
  37.  
  38. ;-------------------------------------------------------
  39. ; Stop Combat (Self)
  40. ;-------------------------------------------------------
  41. actTarget.StopCombat();
  42.  
  43. ;-------------------------------------------------------
  44. ; Stop Alarm
  45. ;-------------------------------------------------------
  46. If enableStopAlarm
  47. actTarget.StopCombatAlarm();
  48. Endif; enableStopAlarm
  49.  
  50. ;-------------------------------------------------------
  51. ; Stop Combat (Enemy)
  52. ;-------------------------------------------------------
  53. If enableStopTarget
  54. actEnemy = actTarget.GetCombatTarget();
  55.  
  56. If actEnemy
  57. stopCombatEx(actEnemy, disableRecover, false, false);
  58. Endif
  59. Endif; enableStopTarget
  60.  
  61. ;-------------------------------------------------------
  62. ; Damage Health
  63. ;-------------------------------------------------------
  64. If disableRecover
  65. nDamage = actTarget.GetActorValue("Health") - nHealth;
  66.  
  67. If (nDamage > 0.0)
  68. actTarget.DamageActorValue("Health", nDamage);
  69. Endif; (nDamage > 0.0)
  70. Endif; disableRecover
  71.  
  72. ;-------------------------------------------------------
  73. ; Return
  74. ;-------------------------------------------------------
  75. return true;
  76. EndFunction; stopCombatEx()
  77.  

外見変更

顔テキスチャの変更

NetImmerse Overrideが必要。
アクターの顔テキスチャを変更する処理。顔用のTextureSetを指定する。
  1. ; ----------------------------------------------------------
  2. ; @name changeFace
  3. ; @function
  4. ; @global
  5. ; @param actTarget {Actor}
  6. ; @param txtSkin {TextureSet}
  7. ; @returns {Bool}
  8. ; ----------------------------------------------------------
  9. Bool Function changeFace(Actor actTarget, TextureSet txtSkin) global
  10. ;-------------------------------------------------------
  11. ; Init Variables
  12. ;-------------------------------------------------------
  13. ActorBase abTarget;
  14. Int nHeadIdx = -1;
  15. String szNode = "";
  16.  
  17. ;-------------------------------------------------------
  18. ; Check Arguments
  19. ;-------------------------------------------------------
  20. If !actTarget || !txtSkin
  21. return false;
  22. Else
  23. abTarget = actTarget.GetLeveledActorBase();
  24. Endif; !actTarget || !txtSkin
  25.  
  26. ;-------------------------------------------------------
  27. ; Get Head Index
  28. ;-------------------------------------------------------
  29. If abTarget
  30. nHeadIdx = abTarget.GetIndexOfHeadPartByType(1);
  31. Endif; abTarget
  32.  
  33. ;-------------------------------------------------------
  34. ; Get Node Name
  35. ;-------------------------------------------------------
  36. If (nHeadIdx >= 0)
  37. szNode = abTarget.GetNthHeadPart(nHeadIdx).GetName();
  38. Endif; (nHeadIdx >= 0)
  39.  
  40. ;-------------------------------------------------------
  41. ; Apply Face Texture
  42. ;-------------------------------------------------------
  43. If (nHeadIdx >= 0)
  44. abTarget.SetFaceTextureSet(txtSkin);
  45. NetImmerse.SetNodeTextureSet( \
  46. actTarget, szNode, txtSkin, false);
  47. Endif; (nHeadIdx >= 0)
  48.  
  49. ;-------------------------------------------------------
  50. ; Return
  51. ;-------------------------------------------------------
  52. return true;
  53. EndFunction; changeFace()
  54.  

髪パーツの変更

  1. ; ----------------------------------------------------------
  2. ; @name changeHair
  3. ; @function
  4. ; @global
  5. ; @param actTarget {Actor}
  6. ; @param hpNewHair {HeadPart}
  7. ; @returns {Bool}
  8. ; ----------------------------------------------------------
  9. Bool Function changeHair(Actor actTarget, HeadPart hpNewHair)
  10. ;-------------------------------------------------------
  11. ; Init Variables
  12. ;-------------------------------------------------------
  13. ActorBase abTarget = actTarget.GetLeveledActorBase();
  14. Bool isPlayer = (Game.GetPlayer() == actTarget);
  15. Int nHeadIdx;
  16. HeadPart hpCurHair;
  17.  
  18. ;-------------------------------------------------------
  19. ; Get Hair Headparts
  20. ;-------------------------------------------------------
  21. nHeadIdx = abTarget.GetIndexOfHeadPartByType(3);
  22. hpCurHair = abTarget.GetNthHeadPart(nHeadIdx);
  23.  
  24. ;-------------------------------------------------------
  25. ; Reset Hair Part
  26. ;-------------------------------------------------------
  27. If !isPlayer && hpNewHair
  28. actTarget.ReplaceHeadPart(hpCurHair, hpNewHair);
  29. Elseif isPlayer && hpNewHair
  30. actTarget.ChangeHeadPart(hpNewHair);
  31. Endif; !isPlayer && hpNewHair
  32.  
  33. ;-------------------------------------------------------
  34. ; Return
  35. ;-------------------------------------------------------
  36. return true;
  37. EndFunction; changeHair()
  38.  

プレイヤーのヘッド・トラッキング

指定したオブジェクトに対して、プレイヤーにヘッド・トラッキングさせる処理。
自分自身を対象に指定すると、ゆっくり正面を向く。(ヘッド・トラッキングは継続)
ヘッド・トラッキングそのものを停止すると、急に正面を向く。
  1. Bool Function startPlayerHeadTracking(ObjectReference obrfTarget)
  2. ;-------------------------------------------------------
  3. ; Declare Variables
  4. ;-------------------------------------------------------
  5. Actor actPlayer = Game.GetPlayer();
  6.  
  7. ;-------------------------------------------------------
  8. ; Player Head Tracking
  9. ;-------------------------------------------------------
  10. If obrfTarget
  11. actPlayer.SetHeadTracking(true);
  12. actPlayer.SetLookAt(obrfTarget, false);
  13. actPlayer.SetAnimationVariableBool("bHeadTrackSpine", false);
  14. actPlayer.SetAnimationVariableInt("IsNPC", 1);
  15. Endif; obrfTarget
  16.  
  17. ;-------------------------------------------------------
  18. ; Return
  19. ;-------------------------------------------------------
  20. return true;
  21. EndFunction; startPlayerHeadTracking()
  22.  
  23. Bool Function stopPlayerLooking()
  24. ;-------------------------------------------------------
  25. ; Declare Variables
  26. ;-------------------------------------------------------
  27. Actor actPlayer = Game.GetPlayer();
  28.  
  29. ;-------------------------------------------------------
  30. ; Player Head Tracking
  31. ;-------------------------------------------------------
  32. actPlayer.SetLookAt(actPlayer, false);
  33.  
  34. ;-------------------------------------------------------
  35. ; Return
  36. ;-------------------------------------------------------
  37. return true;
  38. EndFunction; stopPlayerLooking()
  39.  
  40. Bool Function stopPlayerHeadTracking()
  41. ;-------------------------------------------------------
  42. ; Declare Variables
  43. ;-------------------------------------------------------
  44. Actor actPlayer = Game.GetPlayer();
  45.  
  46. ;-------------------------------------------------------
  47. ; Player Head Tracking
  48. ;-------------------------------------------------------
  49. actPlayer.ClearLookAt();
  50. actPlayer.SetAnimationVariableBool( \
  51. "bHeadTrackSpine", false );
  52. actPlayer.SetAnimationVariableInt("IsNPC", 0);
  53. actPlayer.SetHeadTracking(false);
  54.  
  55. ;-------------------------------------------------------
  56. ; Return
  57. ;-------------------------------------------------------
  58. return true;
  59. EndFunction; stopPlayerHeadTracking()
  60.  

配列の要素数を128を超えたものを扱いたい、または動的に配列を宣言したい

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

NGパターン

  1. Actor[] NPCArray
  2. int[] ValArray
  3. Function Test()
  4. int num = 0
  5. NPCArray = new Actor[200] ;1128までの範囲で宣言しろとエラーが出る
  6.  
  7. ; 変数の値分の配列を宣言したいが
  8. ; 配列数の指定に変数を指定するなとエラーが出る
  9. num = 200
  10. ValArray = new int[num]
  11. EndFunction; Test()
  12.  

配列数が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引数に値を指定する事で宣言と同時に各要素の値を指定値で初期化する事ができます。

実装例

  1. Actor[] NPCArray
  2. int[] ValArray
  3. Function Test()
  4. int num = 200 ;
  5. NPCArray = PapyrusUtil.ActorArray(num, None)
  6. ValArray = Utility.CreateIntArray(num, 10) ; 配列の各要素の値を10で初期化
  7. EndFunction; Test()
  8.  

装備してる武器や防具に付いているエンチャントを取得する(自分で付呪したものも取得する方法)

装備してる武器、防具のエンチャントを取得する処理。
WeaponとArmorのGetEnchantment関数は自分から付呪を施したエンチャントを取得できないため、
WornObject.GetEnchantment関数でのチェックも行う。

  1. ; 装備してる武器のエンチャントを取得
  2. ; iRightHandに0を渡せば左手武器のエンチャントを取得
  3. Enchantment Function GetWeaponEnchantment(Actor akTarget, int iRightHand = 1)
  4. Weapon w = akTarget.GetEquippedObject(iRightHand) as Weapon
  5. if !w
  6. return None
  7. endif
  8.  
  9. Enchantment ench = w.GetEnchantment()
  10. if ench
  11. return ench
  12. endif
  13.  
  14. return WornObject.GetEnchantment(akTarget, iRightHand, 0)
  15. EndFunction
  16.  
  17. ; 装備してる防具のエンチャントを取得
  18. Enchantment Function GetArmorEnchantment(Actor akTarget, int iSlotMask)
  19. Armor arm = akTarget.GetWornForm(iSlotMask) as Armor
  20. if !arm
  21. return None
  22. endif
  23.  
  24. Enchantment ench = arm.GetEnchantment()
  25. if ench
  26. return ench
  27. endif
  28.  
  29. return WornObject.GetEnchantment(akTarget, 0, iSlotMask)
  30. EndFunction
  31.  
上記サンプルのGetArmorEnchantment関数で第ニ引数に渡す値はスロットマスクとなります。
スロットマスクの値はこちらのページを参照してください。

最初からエンチャントが付いてる装備については上記のようにGetEquippedObjectやGetWornForm等でアイテムを取得し
それに対してGetEnchantment関数を使用すれば取得可能です。
ただし、GetEquippedObject等で取得できる武器と防具のデータはベースフォームであり、
自分から付呪を行った武器や防具に対してGetEnchantment関数を使用した場合はNoneを返します。

自分から付呪を行った武器や防具のエンチャントを取得したい場合は
WornObjectオブジェクトのGetEnchantment関数を使用すれば取得できます。
ただし、WornObjectオブジェクトのGetEnchantment関数は
対象の装備に自分で付呪したエンチャントがある場合のみ、エンチャントを返すという仕様のため
逆に最初からエンチャントが付いてる装備の場合はNoneを返します。

そのため、現在装備しているアイテムのエンチャントを取得する場合は
サンプルのように最初から付呪がされてるアイテムであるか確認し、
そうでない場合、WornObjectオブジェクトのGetEnchantment関数で自前で作成した付呪を取得するようにしましょう。

MCMの設定を保存、ゲーム開始時や再開時に設定を自動読込する

外部ファイルにMCMの設定を保存する事でニューゲーム時や違うセーブデータでゲームを再開した時に
一々MCMの再設定をする手間を省かせるようにする。

現状でメジャーなのはPapyrusUtilのJsonUtilオブジェクトを使用する方法か
MCMHelper(SEのみ)を使用する方法だが、
PapyrusUtilによる方法を記載する。
注:FISSでの自動読込は禁止。仕組み上の問題で複数のスクリプトが同時にFISSを使用するとCTDとなるため。

  1. Scriptname [スクリプト名] extends ski_configbase
  2.  
  3. GlobalVariable Property SampleGV auto
  4.  
  5. ~省略~
  6.  
  7. String settings_path = "..\\[Mod名]\\UserSettings"
  8.  
  9. ; MCMはセーブからのロード時にOnGameReloadイベントが発生するため
  10. ; この時に設定の読み込みを行う
  11. Event OnGameReload()
  12. parent.OnGameReload()
  13. LoadUserSettingsPapyrus()
  14. endEvent
  15.  
  16. ; MCMを閉じた時に実行
  17. ; 設定を自動保存
  18. Event OnConfigClose()
  19. parent.OnConfigClose()
  20. SaveUserSettingsPapyrus()
  21. EndEvent
  22.  
  23. ; MCMの初期化
  24. ; ニューゲーム時に設定の自動読込が実行される
  25. event OnConfigInit()
  26. ;MCMの初期設定を記述
  27. ~省略~
  28.  
  29. LoadUserSettingsPapyrus()
  30. endEvent
  31.  
  32. Bool function SaveUserSettingsPapyrus()
  33. JsonUtil.SetPathIntValue(settings_path, "Sample", SampleGV.GetValueInt())
  34.  
  35. if !JsonUtil.Save(settings_path, false)
  36. debug.Trace(ModName + ": Error saving user settings.", 0)
  37. return false
  38. endIf
  39. return true
  40. endFunction
  41.  
  42. Bool function LoadUserSettingsPapyrus()
  43. if !JsonUtil.IsGood(settings_path)
  44. ShowMessage(ModName + ": Can't load User Settings. Errors: {" + JsonUtil.getErrors(settings_path) + "}")
  45. return false
  46. endIf
  47.  
  48. SampleGV.SetValueInt(JsonUtil.GetPathIntValue(settings_path, "Sample", SampleGV.GetValueInt()))
  49. return true
  50. endFunction
  51.  
  52. ~OnConfigOpen等のMCMの各イベントの処理の記述は省略~
  53.  

MCMを開いて後に閉じた後に
(ルートディレクトリ)\SKSE\Plugins\[Mod名]ディレクトリにUserSettings.jsonが生成されている事、
セーブからのロードやニューゲーム時にMCMの設定が引き継がれている事を確認できたら、
MCMの自動保存と自動読込の作成は完了となります。
(MO2の場合は\overwrite\SKSE\Plugins\[Mod名]ディレクトリにUserSettings.jsonが生成されます。)

  • 上記サンプルでUserSettings.jsonに記載される内容
  1. {
  2. Sample:[設定値(整数)]
  3. }
ゲーム開始時にModの設定を一つ一つ手動でロードするのはユーザー側にとってかなり手間となるため
基本的には自動読込は実装するようにしましょう。
保存に関しては設定の切り替えが簡単だったり項目数が少なければ自動保存で問題ありませんが、
設定項目がかなりの数がある場合は自動保存はMCM側の設定で実行するか制御できるようにし、
手動保存と手動読込の手段も一緒に追加すると良いです。

余裕があれば自動保存、自動読込は設定で制御できるようにすると良いでしょう。

タグ:

+ タグ編集
  • タグ:

このサイトはreCAPTCHAによって保護されており、Googleの プライバシーポリシー利用規約 が適用されます。

目安箱バナー