プレイヤーがエリア移動したタイミングで何かしたい時に、エリア移動を検出する方法の解説です。
先に結論を書くと、Reference Aliasでループを回すのが確実です。
エリアの定義
Worldspace | おおまかなエリアの範囲。領域。屋外ならTamriel、ホワイトランならWhiterunworld。つまり屋外領域、ホワイトラン領域といった感じ。Worldspaceがなしになることもあり、この場合は屋内という扱い。 |
Cell | エリアの最小単位。区画。Worldspaceは小さなCellの集まりでできている。屋内は1つのCellでできている。Cellは必ず存在する。 |
Location | エリアのグループ。地域。複数のCellをグループ名をつけてまとめるようなもの。Locationがなしになることもあり、この場合は地域名なし。 |
Actorがいるエリアのそれぞれを取得するコードは次のようになります。
476 (papyrus)
Debug.Trace("worldspace = " + PlayerRef.GetWorldSpace())
Debug.Trace("cell = " + PlayerRef.GetParentCell())
Debug.Trace("location = " + PlayerRef.GetCurrentLocation())
エリア移動を検知するイベント
Actorがエリアを移動した時に発生するイベントがいくつかあります。
- OnLoad
- OnLocationChange
- OnAttachedToCell
- OnCellLoad
名前の通りですが、プレイヤー限定だったり、逆にプレイヤーには使えなかったり、ロードを挟まないと発生しなかったりします。
ロードを挟むというのは、Skyrimのゲームエンジンはゲームを起動してから初めて行く場所はロードしますが、キャッシュとしてデータをメモリにしばらく置いておくので、さっきまでいた場所に戻るようなケースではロードが発生しないことがあります。ロードが発生しなければイベントも発生しません。
そこで、SpellのConditionを使ってエリア移動を検出するようにします。
何でもよいのでObjectReferenceを作ります。とりあえずMiscItemからGold001をコピーして、どこでもいいのでCellに配置します。これを目印と呼びます。
Magic EffectとSpellを作ります。
Spellに設定するEffect ItemのConditionsは、こうします。
GetInSameCell関数を使い、目印を指定します。条件は== 0とします。これで、Actorが目印と違うCellにいる時にだけMagic Effectが発動するスペルになります。
Magic Effectに割り当てるPapyrusスクリプトは以下のようにします。
483 (papyrus)
Scriptname eqEffectSandboxLocationScript Extends ActiveMagicEffect
ObjectReference Property eqObjectSandboxLocationREF auto
Actor Property PlayerRef Auto
Event OnEffectStart(Actor akTarget, Actor akCaster)
Debug.Trace("eqEffectSandboxLocationScript.OnEffectStart")
RegisterForSingleUpdate(0.1)
Debug.Trace("cell = " + PlayerRef.GetParentCell())
Debug.Trace("worldspace = " + PlayerRef.GetWorldSpace())
Debug.Trace("location = " + PlayerRef.GetCurrentLocation())
EndEvent
Event OnUpdate()
eqObjectSandboxLocationREF.MoveTo(PlayerRef, afZOffset = 20)
if Self
RegisterForSingleUpdate(1.0)
endif
EndEvent
あとは、Questを作り、ReferenceAliasを作り、Playerを割り当て、Alias Spellsにいま作ったスぺルを指定します。
ゲームを起動して動作を確認します。Alternate Startの女神像の前です。足元に目印のコインがやってくるはずです。動作確認のためにコインをそのまま使いましたので、移動時に音がしますし、少し転がって動きます。これはmeshを削除するとなくなるので問題ありません。
Paryrusのログはこうなりました。屋内なのでWorldspaceはなしです。
[05/08/2019 - 11:02:10PM] location = [Location < (000ECF4C)>]
[05/08/2019 - 11:02:10PM] cell = [Cell <AbandonedPrison01 (00021594)>]
[05/08/2019 - 11:02:10PM] worldspace = None
移動してみます。選択肢の一番上を選んだのでソリチュードの近くの埠頭に移動します。
ログはこうなりました。屋外なのでWorldspaceがTamrielになりました。
[05/08/2019 - 11:03:31PM] location = [Location < (000358B9)>]
[05/08/2019 - 11:03:31PM] cell = [Cell <SolitudeDocks01 (000092BC)>]
[05/08/2019 - 11:03:31PM] worldspace = [WorldSpace <Tamriel (0000003C)>]
移動すると目印が定期的にワープしてくると思います。うまく動作することを確認したら、目印に指定されているmeshを削除すると目に見えなくなり、Playableフラグをオフにすると拾われることもなくなります。
たまにおかしくなる
しばらく検証を続けた結果、Magic Effectだとたまに動作しなくなりました。原因は不明です。SpellのMagic EffectではなくQuestのReference Aliasで回すようにした方が確実と思います。
SpellのConditionsはおそらく毎秒条件判定を行い、条件を満たしたらMagic Effectが付与されるという仕組みなので、Reference Aliasで回すのと負荷的には大差ないように思います。むしろ判定の頻度を調整できる分、Reference Aliasの方が有利かもしれません。
Magic Effectは何かの拍子に切れてしまい、切れたあと元に戻すのが面倒です。一方、Reference Aliasの方は切れるという概念がないので、安定しています。