Jump to content

Using OnDistanceGreaterThan to get an actor to say a line when x distance away from other actor?


NikaCola

Recommended Posts

Like the title says, I'm having a little trouble using the event ondistancegreaterthan, because I need to nest it inside another event (in this instance onquestinit)

 

What I'm trying to accomplish is that the follower I'm creating will speak a certain line once a given quest has advanced to a certain stage...but only after we're a certain distance away from the quest giver. The code I have so far looks like this...but please remember I am definitely not an expert in papyrus or any scripting so...please be gentle! =)

Event OnQuestInit()
RegisterForRemoteEvent(MQXXX, "OnStageSet")
RegisterForDistanceGreaterThanEvent(myref1, myref2, 200.00)
endevent


Event Quest.OnStageSet(Quest akSender, int auiStageID, int auiItemID)


if aksender == MQXXX
            if auistageid == XXX
            if MQ1 == 0
	     if ismyactornearPC() == true && (myref1.getreference()).getdistance(game.getplayer())>400
     myactor.saycustom(xxxcustomtopic, game.getplayer())
	     debug.messagebox("actor should say the line")
MQ1 = 1
endif 
endif
 endif
endif
endevent


bool Function ismyactorNearPC()
       bool returnVal = Game.GetPlayer().GetDistance(myfollower) <= 2500      
       RETURN returnVal
EndFunction

Right now the script works as I'd like once the stage is set, but ONLY if my follower is already over the specified distance away. The problem is that there's nowhere in that block of code to put the event ondistancegreaterthan, because as near as I can tell you can only run one event at a time? I'd like for the line of dialogue to be said after the stage is set, and after the follower walks away and is a set distance away.

 

Is there any way to make that happen that I'm missing? I'm sorry the code is so sloppy, LOL, and thank you so much for any help! <3

Link to comment
Share on other sites

Try an event logic structure something like this (not exact code) ...

Bool bActorIsOverDistance = False

Event OnDistanceGreaterThan(ObjectReference akObj1, ObjectReference akObj2, float afDistance)
If akObj1 == MyActorref && mqxxx.GetCurrentStageID() >= 20
	; do stuff
ElseIf akObj1 == MyActorref
	; set a flag for onstageset event
	bActorIsOverDistance = True
Endif
EndEvent

Event Quest.OnStageSet(Quest akSender, int auiStageID, int auiItemID)
If akSender == MQXXX && auiStageID >= XX && bActorIsOverDistance == True
	; do stuff
Endif
EndEvent
Edited by SKK50
Link to comment
Share on other sites

Use 'STATES'. By using states you can have multiple EVENTS of the same type in a single script.

 

I will refer you to the script attached to the water fountain "Vault_WaterFountain01" - script name: drinkfromfountainscript.

 

You can see below how they are nested within OnBeginState events:

 

State waiting
;turn off fountain (slow) when entering the waiting state
Event OnBeginState(string asOldState)
debug.trace(self + " OnBeginState waiting, from " + asOldState)
BeginDrinking()
EndEvent
;On activate start drinking
Event OnActivate(ObjectReference akActionRef)
debug.trace(self + " OnActivate: WAITING")
If akActionRef == Game.GetPlayer()
myPlayer = game.getPlayer()
drinkTime = 1
amountDrunk = 1
GotoState("drinking")
EndIf
EndEvent
endState

State drinking
Event OnBeginState(string asOldState)
debug.trace(self + " OnBeginState drinking, from " + asOldState)
;turn on fountain (fast)
SetAnimationVariableFloat("fDampRate", 0.08)
SetAnimationVariableFloat("fToggleBlend", 1.0)
;wait for water flow
FountainStart.play(self)
utility.wait(0.25)
;drink for 1 sec (1 drinktime)
;drinkingSound.play(self)
while drinkTime > 0
utility.wait(1.0)
;add spell fx for each drink
spellOnDrink.Cast(myPlayer)
;play drinking sound
drinkingSound.play(self)
;decrement drinktime
drinkTime = drinkTime-1
endWhile
utility.wait(0.5)
Tutorial.SetStage(500)

; if this is furniture, loop while in it
if GetBaseObject() is furniture && IsFurnitureInUse()
GotoState("looping")
else
GotoState("waiting")
endif
EndEvent
;if you spam the button while drinking...
Event OnActivate(ObjectReference akActionRef)
debug.trace(self + " OnActivate: DRINKING")
If akActionRef == Game.Getplayer()
DrinkAgain()
EndIf
EndEvent
endState

Edited by joerqc
Link to comment
Share on other sites

Thank you for the help, and the example! I tried it out but the saycustom line fires EVERY time, no matter how close I get my follower to the objectreference (just another actor in the game.) I even tried with a ridiculous distance like 5000 but the line is immediately said once I set that quest stage.

 

I think this is because the event is registered and fires when this particular quest starts. So the script runs and detects that my follower is far enough away from the NPC to say this line (because they haven't even met yet and are def. far away from each other at that moment) so it sets the flag to True and this doesn't really work the way I'm hoping. =(

 

I feel like there's something so obvious I'm missing, ahh! Is there a better way to control when the event actually fires?

 

edit: Sorry! This was a reply to SKK50. I'm looking at your example, joerqc, but for the life of me I'm really having trouble getting my head around it. =( Does using States mean I can just nest every event together, like a giant function? I've read through the CK pages on states a few times and the examples are...somewhat hard for me to follow. (again I am very very new to scripting)

Link to comment
Share on other sites

Okaaay....I seemed to have gotten it working, but I think it's maybe a stupid way of doing it? The problem definitely was that the ondistancegreaterthan event was firing as soon as the quest started, and I couldn't figure out a better way to start it at the right time (on a certain quest and stage, while at the same time being able to use ondistancegreaterthan since both of these are events)

 

So I did kind of like what SKK50 suggested, but also used another event (on scene end) to set another variable, then I waited to actually register the ondistancegreaterthan event until OnSceneEnd was done. Is that a super dumb way of doing this? I mean...it works. =D I just don't want to cause problems for the game or any one playing this mod.

 

Here's the script as working:

Event OnQuestInit()
RegisterForRemoteEvent(MQXXX, "OnStageSet")
RegisterForRemoteEvent(dumbprestonscene, "OnEnd")
endevent

Event OnDistanceGreaterThan(ObjectReference akObj1, ObjectReference akObj2, float afDistance)
if akobj1 == game.getplayer()
if akobj2 == dumbfacepreston
if afdistance >= 500.00
if prestonscenedone == 1
if correctstage == 1
debug.messagebox ("no way this will work")
            myactor.saycustom(topic, game.getplayer())
               

Event Quest.OnStageSet(Quest akSender, int auiStageID, int auiItemID)
if aksender == MQxxx
if ismyactornearPC() == true
    if auistageid == 123
correctstage = 1

endif 
endif
 endif
endif
endevent

event Scene.OnEnd(Scene SceneToCheck)
	if scenetocheck == dumbprestonscene
	if ismyactornearPC == true
	prestonscenedone = 1
    debug.messagebox("stupid scene over")
RegisterForDistanceGreaterThanEvent(game.getplayer(), dumbfacepreston, 500.00)

endif
endif
endevent

bool Function ismyactorNearPC()
       bool returnVal = Game.GetPlayer().GetDistance(myfollower) <= 2500      
       RETURN returnVal
EndFunction
Link to comment
Share on other sites

Considering the high level states and flow BEFORE getting stuck into the detail code is best, and from your code I infer the conditions you are working with are:

 

Actor is close at stage start - OK 1 wait for far then 2 do stuff

Actor is far at stage start - NOTOK 1 wait for close then 2 wait for far then 3 do stuff

 

There are several ways to approach this, here is a possible function flow (this is logic not code !):

 

OnStageSet
If stage i am interested in
Is distance less than ?
Yes = Set hasbeencloseflag, RegisterForDistanceGreaterThanEvent

No = RegisterForDistanceLessThanEvent

OnDistanceGreaterThan
hasbeencloseflag set ?

No = RegisterForDistanceLessThanEvent

Yes = Unregister and do stuff

 

OnDistanceLessThan

Set hasbeencloseflag

RegisterForDistanceGreaterThanEvent

Edited by SKK50
Link to comment
Share on other sites

How did that even compile? The first event is not probably closed. EndEvent is missing, and those nested if statements also don't close properly.

 

I cleaned up the syntax:

 

 

 

 

Event OnQuestInit()
RegisterForRemoteEvent(MQXXX, "OnStageSet")
RegisterForRemoteEvent(dumbprestonscene, "OnEnd")
endevent

Event OnDistanceGreaterThan(ObjectReference akObj1, ObjectReference akObj2, float afDistance)
if akobj1 == game.getplayer()
    if akobj2 == dumbfacepreston
        if afdistance >= 500.00
            if prestonscenedone == 1
                if correctstage == 1
                    debug.messagebox ("no way this will work")
                    myactor.saycustom(topic, game.getplayer())
                endif
            endif
        endif
    endif
endif
EndEvent
               

Event Quest.OnStageSet(Quest akSender, int auiStageID, int auiItemID)
if aksender == MQxxx
    if ismyactornearPC() == true
        if auistageid == 123
            correctstage = 1

        endif
    endif
endif
endevent

event Scene.OnEnd(Scene SceneToCheck)
    if scenetocheck == dumbprestonscene
        if ismyactornearPC == true
            prestonscenedone = 1
            debug.messagebox("stupid scene over")
            RegisterForDistanceGreaterThanEvent(game.getplayer(), dumbfacepreston, 500.00)

        endif
    endif
endevent

bool Function ismyactorNearPC()
       bool returnVal = Game.GetPlayer().GetDistance(myfollower) <= 2500      
       RETURN returnVal
EndFunction

 

 

 

500 units is fairly short. That's like a few feet from an object and your logic is checking for distance greater than 500 units. What this means is anything within 500 units will fire. So you might want to try something higher. A Cell is 4096 units in width and length. So I think the following distances to try should be 1024, and 2048.

Link to comment
Share on other sites

 

So I did kind of like what SKK50 suggested, but also used another event (on scene end) to set another variable, then I waited to actually register the ondistancegreaterthan event until OnSceneEnd was done. Is that a super dumb way of doing this? I mean...it works. =D I just don't want to cause problems for the game or any one playing this mod.

 

No, it's not a dumb way to do it. After I read your first comment I was going to suggest you register for the distance event in the onstageset event rather than onquestinit.

Link to comment
Share on other sites

How did that even compile? The first event is not probably closed. EndEvent is missing, and those nested if statements also don't close properly.

 

I cleaned up the syntax:

 

 

 

Event OnQuestInit()
RegisterForRemoteEvent(MQXXX, "OnStageSet")
RegisterForRemoteEvent(dumbprestonscene, "OnEnd")
endevent

Event OnDistanceGreaterThan(ObjectReference akObj1, ObjectReference akObj2, float afDistance)
if akobj1 == game.getplayer()
    if akobj2 == dumbfacepreston
        if afdistance >= 500.00
            if prestonscenedone == 1
                if correctstage == 1
                    debug.messagebox ("no way this will work")
                    myactor.saycustom(topic, game.getplayer())
                endif
            endif
        endif
    endif
endif
EndEvent
               

Event Quest.OnStageSet(Quest akSender, int auiStageID, int auiItemID)
if aksender == MQxxx
    if ismyactornearPC() == true
        if auistageid == 123
            correctstage = 1

        endif
    endif
endif
endevent

event Scene.OnEnd(Scene SceneToCheck)
    if scenetocheck == dumbprestonscene
        if ismyactornearPC == true
            prestonscenedone = 1
            debug.messagebox("stupid scene over")
            RegisterForDistanceGreaterThanEvent(game.getplayer(), dumbfacepreston, 500.00)

        endif
    endif
endevent

bool Function ismyactorNearPC()
       bool returnVal = Game.GetPlayer().GetDistance(myfollower) <= 2500      
       RETURN returnVal
EndFunction

 

 

 

500 units is fairly short. That's like a few feet from an object and your logic is checking for distance greater than 500 units. What this means is anything within 500 units will fire. So you might want to try something higher. A Cell is 4096 units in width and length. So I think the following distances to try should be 1024, and 2048.

 

I re-wrote the script in a hurry to post it here (or at least changed the property names around a little bit) and I probably missed a few things. Thank you for cleaning it up though! I probably should get into the habit of making my stuff look like that. As for the unit distance, I was going based off this page... https://www.creationkit.com/index.php?title=Unit

 

Is it different for fallout vs. skyrim, or have I just misunderstood how units work in general?

 

 

So I did kind of like what SKK50 suggested, but also used another event (on scene end) to set another variable, then I waited to actually register the ondistancegreaterthan event until OnSceneEnd was done. Is that a super dumb way of doing this? I mean...it works. =D I just don't want to cause problems for the game or any one playing this mod.

 

No, it's not a dumb way to do it. After I read your first comment I was going to suggest you register for the distance event in the onstageset event rather than onquestinit.

 

 

That makes me feel at least somewhat less stupid, thank you! =D

 

Link to comment
Share on other sites

  • Recently Browsing   0 members

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