Jump to content

Moving objects via script (TranslateTo)


FuryoftheStars

Recommended Posts

Could I still have this main quest with the confirmation dialog and use it to populate a global var with the playerâs response, and then use a reference alias quest for the individual objects whoâs scripts check this var? In this way I can still move the objects (including the ones that arenât firing any of the normal objectreference events) and only have it done if the player confirms this is what they want.

 

Iâm also wondering if thereâs any way to differentiate between a player adding this mod mid play through vs starting a new game?

Link to comment
Share on other sites

Is there a trigger condition for quests for when you enter certain cells?

 

A bit of experimentation reveals that if I wait until I'm inside of the hearthfire home before popping my message (for now, I'm just setting a 30 sec delay to give me time to get inside with the current save I have), then enable the object, TranslateTo will work. I can also check the object's enable condition and save this to a bool prior to enabling it for the move, that way once I'm done moving it, I can re-disable it (and actually, I'm noticing I need to disable/re-enable anyway to update the collision box, so really, I'm disabling regardless, then checking the bool to see if I should re-enable).

 

MoveToMyEditorLocation still does not work and in fact I just noticed it's throwing an error of "cannot be moved" into the papyrus log for that method. I did notice in SSEEdit that the chandeliers and horker head are flagged as persistent, which lead me to googling around and finding some posts by Arthmoor on the AFK Mods forums talking about different levels of persistence and that in some cases of "fully" persistent objects, even script methods of moving objects wouldn't work. *shrug*

https://www.afkmods.com/index.php?/topic/3669-overhauling-the-weapon-rack-scripts/page/21/&tab=comments#comment-148158

 

If a reference is selected as a Papyrus script property, everything changes. Now you're back to the classic definition of persistence. These references are maintained in memory at all times, and cannot be moved. Sometimes even scripts are incapable of repositioning them. With a new twist too. The positioning data is baked into the save game from the moment the game starts and therefore no such object can ever be relocated. It makes no difference what type of script it is either.

(Note that in that quote snippet, it's movement via the CK and mods Arthmoor is talking about except where specifically mentioning scripts.)

 

Anyway, if quests can trigger by the player entering a certain cell, then I can just split this into 3 quests, 1 for each home, then run down the list of objects using the technique I detailed above. I'd considered looking into arrays and papyrus's equivalent to for loops so I could cut down on the number of property vars I need to write into the script (and hopefully avoid having to edit the script any time a change is made where another object's location needs to be updated or one no longer needs it), but in order to do that, I'd also need to create a matrix array for the xyz coords (to feed into TranslateTo) and I'm not sure if I want to go down that road, yet (assuming papyrus can even do that)....

Edited by FuryoftheStars
Link to comment
Share on other sites

Instead of using a quest then, I would suggest using a triggerbox placed at the in door of the interior cell, and using OnTriggerEnter. Since you are editing the cell anyway by moving the items, I would suggest putting X-Markers or duplicated HF objects that are Initially disabled and using MoveTo, to move the vanilla objects to their markers.

 

Something like this:

 

 

 

Message Property HFModInstallMsg Auto
ObjectReference Property HorkerHead Auto 
ObjectReference Property HorkerHeadMarker Auto 

ObjectReference Property AnotherHFRef Auto 
ObjectReference Property AnotherHFRefMarker Auto 

Actor Property PlayerRef Auto
Bool Property Done = False Auto Hidden

Auto State Waiting
    Event OnTriggerEnter(ObjectReference akActionRef)
        If akActionRef == PlayerRef && Done == False
            Done = True
            GoToState("Done")
            Utility.Wait(1)
            If HFModInstallMsg.Show() == 1
                If HorkerHead != None && HorkerHead.IsDeleted() == False
                    HorkerHead.Moveto(HorkerHeadMarker)
                Endif 
                
                If AnotherHFRef != None && AnotherHFRef.IsDeleted() == False
                    AnotherHFRef.Moveto(AnotherHFRefMarker)
                Endif 
            Endif
            
            Utility.Wait(1)
            Self.Disable() ;Disable this triggerbox so OnTriggerEnter won't fire any more.
        Endif
    EndEvent
EndState 

State Done 
    Event OnTriggerEnter(ObjectReference akActionRef)
        ;do nothing 
    EndEvent
EndState

 

 

Link to comment
Share on other sites

Thanks!

 

(EDIT: Bleh, nevermind on the below. I suppose it'd still be good info to know, but I'm realizing at the moment that the usage of the array where I'm trying to use it is actually over complicating things, so I'm switching methods.)

 

So I'm working through this and went ahead and bit the bullet to learn arrays and looping with papyrus (I still need the xyz coords as I want to do a quick check to see if the objects are already in their correct positions. If they are, there's no sense in popping the message to the player or doing anything else). One question I have on them: can you assign the full array of values to the variable in one go?

 

Rather than writing out individual If checks on each object's xyz coords, I'm popping them into an array defined in script during runtime and then looping on it real quick with a bool to break early if need. This is what I have at the moment that'll compile (this is just a snippet):

float[] xyzCoords = new float[3]
xyzCoords[0] = ObjectArray[i].GetPositionX()
xyzCoords[1] = ObjectArray[i].GetPositionY()
xyzCoords[2] = ObjectArray[i].GetPositionZ()

In other languages, this is doable in one line, though I suppose due to the nature of just declaring the array I can't do that in papyrus. But can I combine the 3 assignments into one line? Again, in other languages, I could do something like this:

float[] xyzCoords = new float[3]
xyzCoords = {ObjectArray[i].GetPositionX(), ObjectArray[i].GetPositionY(), ObjectArray[i].GetPositionZ()}

However, this won't compile for papyrus. I've tried wrapping the values in {}, [], and (). Do I need to use something other than a comma? Or am I stuck with having to assign each element on their own line?

Edited by FuryoftheStars
Link to comment
Share on other sites

I'm pretty sure in papyrus you have to do it in multiple lines. If your markers are in the same positions as the vanilla items should be, then you don't need to use an array, you can just compare the positions of the marker and vanilla object.

 

 

 

Scriptname TM_ObjectRefScript extends ObjectReference

Message Property HFModInstallMsg Auto
ObjectReference Property HorkerHead Auto 
ObjectReference Property HorkerHeadMarker Auto 

ObjectReference Property AnotherHFRef Auto 
ObjectReference Property AnotherHFRefMarker Auto 

Actor Property PlayerRef Auto
Bool Property Done = False Auto Hidden

Auto State Waiting
    Event OnTriggerEnter(ObjectReference akActionRef)
        If akActionRef == PlayerRef && Done == False
            Done = True
            GoToState("Done")
            Utility.Wait(1)
            If HorkerHead.GetPositionX() != HorkerHeadMarker.GetPositionX() || HorkerHead.GetPositionY() != HorkerHeadMarker.GetPositionY() \ 
            || HorkerHead.GetPositionZ() != HorkerHeadMarker.GetPositionZ()
                If HFModInstallMsg.Show() == 1
                    If HorkerHead != None && HorkerHead.IsDeleted() == False
                        HorkerHead.Moveto(HorkerHeadMarker)
                    Endif 
                    
                    If AnotherHFRef != None && AnotherHFRef.IsDeleted() == False
                        AnotherHFRef.Moveto(AnotherHFRefMarker)
                    Endif 
                Endif
            Endif
            
            Utility.Wait(1)
            Self.Disable() ;Disable this triggerbox so OnTriggerEnter won't fire any more.
        Endif
    EndEvent
EndState 

State Done 
    Event OnTriggerEnter(ObjectReference akActionRef)
        ;do nothing 
    EndEvent
EndState

 

 

Link to comment
Share on other sites

Thanks. Yeah, I realized the mistake I was making and ended up doing this (by the way, how do you do spoiler tags in these forums?):

bool NeedsUpdating = False
int i = 0
While i < ObjectArray.Length && !NeedsUpdating
    If ObjectArray[i].GetPositionX() != XCoordArray[i] || ObjectArray[i].GetPositionY() != YCoordArray[i] || ObjectArray[i].GetPositionZ() != ZCoordArray[i]
        NeedsUpdating = True
    EndIf
EndWhile

Oh, one more question. If statements with multiple conditions. Does papyrus evaluate all of the conditions regardless, or will it shortcut out if the first condition it evaluates false? IE:

If NeedsUpdating && ConfirmationMessage.Show() == 1

If "NeedsUpdating" is False, will it still attempt to evaluate the next condition (causing the message box to show), or will it shortcut out and skip the message box? I've seen both ways between the languages I've used.

Link to comment
Share on other sites

You know, I'm actually not sure about that, it'd be easy enough to test though. The spoiler tags are [spoiler*] and [/spoiler*] without the *. If it turns out it still shows the message, you can always put them on separate lines.

 

If needsUpdating

If ConfirmationMessage.Show() == 1

Link to comment
Share on other sites

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...