エリア移動を検出しよう・プレイヤー編

Modを作ろう

プレイヤーがエリア移動したタイミングで何かしたい時に、エリア移動を検出する方法の解説です。

先に結論を書くと、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の方はこんな感じです。

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の方は切れるという概念がないので、安定しています。

タイトルとURLをコピーしました