物を拾わせたい

Modを作ろう

フォロワーに物を拾わせて楽しよう

2019/7/26 追記

どうやらフォロワーはプレイヤーが直に置いた矢しか認識できないようです。戦闘で落っこちた矢は認識できず、矢はPapyrusを貼り付けることもできないのでお手上げです。


戦闘が終わるたびに矢を拾うのが面倒なので、フォロワーに拾わせたくなりました。

PackageのAcquireを使うと手っ取り早いです。必要なものは以下の通りです。

  • Quest
  • 拾うアイテムを入れるReferenceAlias
  • 拾うActorを入れるReferenceAlias
  • 拾うためのScene
  • 拾うためのPackage

PackageはQuest Ownerに作ったQuestを指定します。これでPackage内でReferenceAliasを使えるようになります。アイテムのところまでTravelさせてからAcquireで拾わせます。拾うアニメーションもしてくれます。

お手軽ですが、問題がいくつかあります。まず、コンテナからアイテムを選別して拾わせることができません。それから、アイテムの位置情報が更新されないようです。

Skyrimは、どうやらその付近に何があるかをキャッシュで持っているようです。PapyrusのFind系関数は、このキャッシュを使うようです。

まず、Acquireで矢を拾わせるサンプルコードです。

782 (papyrus)

Scene Property MyScene Auto
ReferenceAlias Property MyLootActor Auto
ReferenceAlias Property MyLootTarget Auto
FormList Property MyAmmoList Auto

Function LootAmmoStart(Actor akLootActor)
    ; 対象の周囲1000units以内にある矢を探す
    ObjectReference kLootTarget = Game.FindClosestReferenceOfAnyTypeInList(MyAmmoList, akLootActor.X, akLootActor.Y, akLootActor.Z, 1000)

    ; 矢が見つかったら拾わせる
    if kLootTarget
        MyLootActor.ForceRefTo(akLootActor)
        MyLootTarget.ForceRefTo(kLootTarget)
        MyScene.Start()
    endif
EndFunction

このコードは、1本目の矢は問題なく拾ってくれます。ところが2本目は拾ってくれません。FindClosestReferenceOfAnyTypeInListが1本目の矢を返し続けるからです。

ObjectReferenceはMoveTo関数で動かすと、位置情報が更新されるようです。そこで、PackageはTravelだけにしてAcquireを使わずに、Scene終了時にPapyrus Fragmentで関数を呼ぶようにします。

Acquireを使わないサンプルコードです。

786 (papyrus)

ScriptName MyScript Extends Quest

Scene Property MyScene Auto
ReferenceAlias Property MyLootActor Auto
ReferenceAlias Property MyLootTarget Auto
FormList Property MyAmmoList Auto

Function LootAmmoStart(Actor akLootActor)
    ; 対象の周囲1000units以内にある矢を探す
    ObjectReference kLootTarget = Game.FindClosestReferenceOfAnyTypeInList(MyAmmoList, akLootActor.X, akLootActor.Y, akLootActor.Z, 1000)

    ; 矢が見つかったら拾わせる
    if kLootTarget
        MyLootActor.ForceRefTo(akLootActor)
        MyLootTarget.ForceRefTo(kLootTarget)
        MyScene.Start()
    endif
EndFunction

Function LootAmmoFinish()
    Actor kLootActor = MyLootActor.GetReference()

    ; 拾うアニメーションを開始
    Debug.SendAnimationEvent(kLootActor, "IdleKneeling")
    Utility.Wait(0.8)

    ; はるか上空に飛ばすことで位置情報を更新する
    ObjectReference kLootTarget = MyLootTarget.GetReference()
    kLootTarget.MoveTo(kLootTarget, afZOffset = 10000.0)

    ; 拾ってアニメーションを止める
    kLootActor.AddItem(kLootTarget, abSilent = true)
    Debug.SendAnimationEvent(kLootActor, "IdleStop")
EndFunction

SceneのPapyrus Fragmentに記述するコードです。

793 (papyrus)

(GetOwningQuest() as MyScript).LootAmmoFinish()

これで何本でも拾ってくれます。

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