ActorでPapyrusスクリプトを動かすにはいくつか方法があります。
- ActorにScriptを直接持たせる
- ActorをQuestのReferenceAliasに入れて、ReferenceAlias経由でScriptを動かす
- ActorにSpellをかけるか持たせるかして、Magic Effect経由でScriptを動かす
他にもあるかもしれませんが、大体これのどれかになると思います。
Active Magic Effectとは
Actorにスペルの効果が発動すると、Magic Effectが動き出します。現在動いているMagic EffectのことをActive Magic Effectといいます。
スペルには効果時間という概念があります。つまり、Active Magic Effectには寿命があるのです。
- 効果が始まるときにOnEffectStartイベントが発生
- 効果が終わるときにOnEffectFinishイベントが発生
効果が終わるのは以下のどれかです。
- Magic Effectに設定された効果時間が経過した時
- ActorがUnloadされた時
- Dispel関数で意図的に終わらせた時
Active Magic Effectは永続に設定できる
通常、Magic Effectの種類はFire and ForgetかConcentrationです。Fire and Forgetはスペルをかけると発動し、効果時間が切れると終了します。Concentrationはスペルを詠唱している間だけずっと効果が続き、詠唱を止めると終わります。
種類をConstant Effectにすると、効果時間が無期限となります。Constant Effectはかけることはできず、スペルを持っている間はずっと効果が発動するようになります。
Constant Effectにしてあると、効果時間という概念がなくなるので、時間経過では切れません。また、Dispel関数で終わらせることもできません。ですが、ActorがUnloadされると終わります。つまり、Actorがエリア移動でプレイヤーと異なるセルに移動すると、Active Magic Effectが切れてしまいます。
永続にしたActive Magic Effectが切れたあとは
ActorにConstant Effectのスペルを持たせると、Active Magic Effectが切れるとスペルだけが残った状態になります。プレイヤーと同じセルに来たら再びMagic Effectが動いてほしいのですが、どうやら動かないようです。
そこで、Actorがプレイヤーと同じセルに来たらMagic Effectが発動し、その効果は永続で、セルから出たらActive Magic Effectが終了、再び同じセルに来たらMagic Effectが再発動する仕組みを考えました。
- Actorに持たせるMySpellとMyEffectを作る(Magic EffectはConstant Effectで永続とする)
- ActorにMySpellを持たせるMyDeliverSpellとMyDeliverEffectを作る
- ActorにMyDeliverSpellをばらまくMyCloakSpellとMyCloakEffectを作る
- 再発動させるためのRestartDeliverSpellとRestartDeliverEffectを作る
- ActorにRestartDeliverSpellをばらまくRestartCloakSpellとRestartCloakEffectを作る
MySpellはActorに持たせたいスペルです。効果はMyEffectです。Magic EffectはConstant Effectで永続とします。MyEffectにスクリプトを設定し、対象にThisActorNeedRestartSpellを持たせるようにします。
MyDeliverSpellはMySpellをActorに持たせるスペルです。効果はMyDeliverEffectです。Magic EffectはConcentrationとAimedです。Conditionに「MySpellを持ってない」を設定します。MyDeliverEffectにスクリプトを設定し、AddSpell関数を使って対象にMySpellを持たせます。
MyCloakSpellはMyDeliverSpellを周囲のActorにばらまくスペルです。効果はMyCloakEffectです。Magic EffectはConstant Effectで永続とします。Arch TypeにCloakを選びます。Assoc ItemにMyDeliverSpellを指定します。
RestartDeliverSpellはMySpellを再発動させるスペルです。効果はRestartDeliverEffectです。Magic EffectはConcentrationとAimedです。Conditionに「MySpellを持っている」「MyEffectを持っていない」を設定します。RestartDeliverEffectにスクリプトを設定し、RemoveSpell関数を使って対象からMySpellを取り除きます。
RestartCloakSpellはRestartDeliverSpellを周囲のActorにばらまくスペルです。効果はRestartCloakEffectです。Magic EffectはConstant Effectで永続とします。Arch TypeにCloakを選びます。Assoc ItemにRestartDeliverSpellを指定します。
Active Magic Effectの注意事項
通常、Active Magic EffectはOnEffectStartイベントで始まり、OnEffectFinishイベントで終わります。プレイヤーがスペルを手動で唱えると相手に効果が発生し、しばらくしたら効果が切れて終わるのであれば、あまり問題にはなりません。
ところが、Cloakでばらまいている時に対象が一瞬だけ現れて消えたり、長い処理時間の最中にスペルが切れるようなことがあると、すこし困った状況になります。
Active Magic Effectが切れてもスクリプトは動き続けます。ただし、Active Magic Effect自体が消滅しているため、スクリプトは自分自身がいないという状態になります。Papyrusでいうと、SelfがNoneになります。こうなると、Selfが必要な関数は一切動かなくなります。RegisterSingleUpdate、GoToState、Dispelなどが該当します。これらの関数を実行すると、Traceログにエラーが出力され、関数呼び出しは失敗に終わります。
[02/01/2020 – 09:20:45PM] Error: Unable to call RegisterForSingleUpdate – no native object bound to the script object, or object is of incorrect type
stack:
[None].eqEffectMovementScript.RegisterForSingleUpdate() – “<native>” Line ?
[None].eqEffectMovementScript.onBeginState() – “eqEffectMovementScript.psc” Line 90
[None].eqEffectMovementScript.GotoState() – “ActiveMagicEffect.psc” Line ?
[None].eqEffectMovementScript.OnUpdate() – “eqEffectMovementScript.psc” Line 82
この手のエラーは大抵は害がなく無視できるものです。ですが、無駄な処理を中断したり、エラーそのものを抑制したい場合は、書き方に工夫が必要です。
Magic Effectが切れることに対処 (papyrus)
Scriptname SampleScript Extends ActiveMagicEffect
Bool IsFinished
; スペルがかかると呼ばれる
Event OnEffectStart(Actor akTarget, Actor akCaster)
; 速攻でスペルが切れることがあるので、少し待ってから次の処理に移る
Utility.Wait(0.5)
; スペルが切れているなら何もしないで終わる
if IsFinished
return
endif
; 1秒後になにかする
RegisterForSingleUpdate(1.0)
EndEvent
; スペルが切れると呼ばれる
; 既にActiveMagicEffectは消えており、ActiveMagicEffectに対する操作は一切無効
Event OnEffectFinish(Actor akTarget, Actor akCaster)
IsFinished = true
EndEvent
Event OnUpdate()
; スペルが切れているなら何もしないで終わる
if IsFinished
return
endif
; ここでやりたことをする
; 再び1秒後になにかする
if !IsFinished
RegisterForSingleUpdate(1.0)
endif
EndEvent