Jump to content

Force a script to run only once


morrowind1979

Recommended Posts

Scriptname DagUrWelcome extends ObjectReference

 

Sound Property DagothUrWelcomeSpeech Auto

 

Event OnTriggerEnter(ObjectReference akActionRef)

DagothUrWelcomeSpeech.Play(self)

 

EndEvent

 

Ok this is a script I created for a trigger box in my quest. the trigger activates every time the player enters teh trigger box. I only want the trigger to run once then disable teh trigger box how would i do this???

Link to comment
Share on other sites

add a variable that is only true at the first instance

 

i.e.

Scriptname DagUrWelcome extends ObjectReference

Sound Property DagothUrWelcomeSpeech Auto
Int Property RunOnceVar = 0 Auto

Event OnTriggerEnter(ObjectReference akActionRef)

If RunOnceVar == 0
 DagothUrWelcomeSpeech.Play(self)
 RunOnceVar = 1
EndIf

EndEvent

If that variable doesn't stick, then use a global variable instead

 

EDIT: The above prevents the trigger from running again, but doesn't disable it.

 

To completely disable the trigger you'll need to add an xmarker, make the xmarker an enable parent of the trigger box, then in your script after the sound plays have the script disable the xmarker and it will cause the trigger to disable. you may have to play with timing etc...

 

so it would be more like

Scriptname DagUrWelcome extends ObjectReference

Sound Property DagothUrWelcomeSpeech Auto
ObjectReference Property EnableMarker Auto
{assign the xmarker to this property}

Event OnTriggerEnter(ObjectReference akActionRef)


DagothUrWelcomeSpeech.Play(self)
Utility.Wait(5)
EnableMarker.Disable()

EndEvent

 

either way may work for your purposes...

Edited by IsharaMeradin
Link to comment
Share on other sites

add a variable that is only true at the first instance

 

i.e.

Scriptname DagUrWelcome extends ObjectReference

Sound Property DagothUrWelcomeSpeech Auto
Int Property RunOnceVar = 0 Auto

Event OnTriggerEnter(ObjectReference akActionRef)

If RunOnceVar == 0
 DagothUrWelcomeSpeech.Play(self)
 RunOnceVar = 1
EndIf

EndEvent

If that variable doesn't stick, then use a global variable instead

 

EDIT: The above prevents the trigger from running again, but doesn't disable it.

 

To completely disable the trigger you'll need to add an xmarker, make the xmarker an enable parent of the trigger box, then in your script after the sound plays have the script disable the xmarker and it will cause the trigger to disable. you may have to play with timing etc...

 

so it would be more like

Scriptname DagUrWelcome extends ObjectReference

Sound Property DagothUrWelcomeSpeech Auto
ObjectReference Property EnableMarker Auto
{assign the xmarker to this property}

Event OnTriggerEnter(ObjectReference akActionRef)


DagothUrWelcomeSpeech.Play(self)
Utility.Wait(5)
EnableMarker.Disable()

EndEvent

 

either way may work for your purposes...

 

Thanks what value do i put Runonce to in properties??? Nevermind just set it to 0 as default going to test ingame seems to have done teh trick thanks a lot!!!

Edited by morrowind1979
Link to comment
Share on other sites

^^ why so complicated? If the script is put on the trigger, then all you need to do is call disable() (on self) No need for markers at all.

 

Also, as I mentioned in another topic, why use a property when a simple variable will suffice? In this case a boolean variable. And yes, it will save across savegames, no need for global variables. But if the object/script is disabled, then it is redundant anyway

 

Another important point is that you probably want to test that it was the Player that entered the trigger, otherwise a stray NPC might mess things up...

 

Also, you may want to use PlayAndWait in this case:

 

Scriptname DagUrWelcome extends ObjectReference

Sound Property DagothUrWelcomeSpeech Auto
bool RunOnce

Event OnTriggerEnter(ObjectReference ActionRef)
If !RunOnce && ActionRef == Game.GetPlayer()
	RunOnce = true
	DagothUrWelcomeSpeech.PlayAndWait(self)
	disable()
EndIf
EndEvent

 

Alternatively you could use States, but not really necessary:

 

Scriptname DagUrWelcome extends ObjectReference

Sound Property DagothUrWelcomeSpeech Auto

AUTO STATE WAITING

Event OnTriggerEnter(ObjectReference ActionRef)
If ActionRef == Game.GetPlayer()
	GotoState("DONE")
	DagothUrWelcomeSpeech.PlayAndWait(self)
	disable() ; this is now optional, as the "DONE" state will render the script inactive anyway
EndIf
EndEvent

END STATE

STATE DONE
END STATE

Edited by steve40
Link to comment
Share on other sites

I prefer the sates method because I think it the fastest and has the least amount of overhead during and after the script has run.

 

Same thing from slowest with most overhead to fastest with least overhead:

 

Sound Property DagothUrWelcomeSpeech Auto
bool RunOnce

Event OnTriggerEnter(ObjectReference akActionRef)
If (!RunOnce && akActionRef == Game.GetPlayer()) ; full blown check every trigger
	RunOnce = true
	DagothUrWelcomeSpeech.PlayAndWait(Self)
	Disable()
EndIf
EndEvent

(same speed as above:)

Sound Property DagothUrWelcomeSpeech Auto
bool RunOnce

Event OnTriggerEnter(ObjectReference akActionRef)
If (RunOnce) ; light check every trigger
Else If (akActionRef == Game.GetPlayer()) ; med check until player trigger
	RunOnce = true
	DagothUrWelcomeSpeech.PlayAndWait(Self)
	Disable()
EndIf
EndEvent

Sound Property DagothUrWelcomeSpeech Auto

Auto State Waiting
Event OnTriggerEnter(ObjectReference akActionRef)
	If (akActionRef == Game.GetPlayer()) ; med check until player trigger
		GoToState("Done");
		DagothUrWelcomeSpeech.PlayAndWait(Self)
		Disable()
	EndIf
EndEvent
EndState

State Done
EndState

Throw in the player ref instead of Game.GetPlayer(), and it is blazing :)

Sound Property DagothUrWelcomeSpeech Auto
Actor Property PlayerRef Auto ; edit, should be Actor, not ObjectReference

Auto State Waiting
Event OnTriggerEnter(ObjectReference akActionRef)
	If (akActionRef == PlayerRef) ; light check until player trigger
		GoToState("Done");
		DagothUrWelcomeSpeech.PlayAndWait(Self)
		Disable()
	EndIf
EndEvent
EndState

State Done
EndState

If you factor in speed and overhead, states take it imo.

Edited by Ez0n3
Link to comment
Share on other sites

@EzOn3: usually when IF statements are evaluated, as soon as part of an AND expression condition is false, the rest of the expression gets ignored because the whole condition will be false anyway. That's how I understand such statements are typically evaluated in programming languages in general. So I don't think there would be any notable performance gain in the second script (relative to the first one), unless Papyrus goes against the grain for some reason. But anyway, I agree that States are generally better, and they have the advantage of shutting off event blocks in the above examples. Edited by steve40
Link to comment
Share on other sites

I was under the impression that "&&" (and) has to check both even if the first doesn't qualify. I don't think "||" (or) suffers from that though. I have to double check, but that's how it works the last time I checked. Been wrong many times before though ;)

 

Edit:

I think I was thinking of FO3. I just noticed on the wiki:

The AND operator (&&) will be true if both of the expressions to its left and right are true, and will short-circuit if the left expression is false (it will not evaluate the right expression at all).

So ya, you're correct. One of the many improvements I'm still catching on to :)

 

Should be no difference between the 1st and 2nd.

Edited by Ez0n3
Link to comment
Share on other sites

^^ why so complicated?

Complicated? sometimes the "easy" way is more complicated because that requires having actual programing knowledge. For someone like me who has to self teach themselves in the stuff that they use, complicated can be the easy way because when something does work you tend to stick with that.

 

My scripting background comes from Baldur's Gate series where the game scripts were a series of IF THEN blocks evaluated from the top down. It makes it easier for me to see what is going on if I use IF statements. As long as the script functions, whether or not parts of it are unnecessary, I'm happy.

Link to comment
Share on other sites

As long as the script functions, whether or not parts of it are unnecessary, I'm happy.

 

I'll respectfully disagree - when we face a public running tens or hundreds of mods with any number of scripts, we should optimize our code as much as possible to reduce load on people's games. This helps both users and fellow modders.

 

I do agree that with this whole "self-taught" thing (and who isn't when it comes to Papyrus?) it's easy to fall back to the "this works so okay" mode - but if you have the capacity to learn a new and better way, that same self-taught skill should update itself and learn a new and better trick :)

 

I'm always a little intimidated when someone asks how to do something in papyrus and I have a suggestion which I'd like to share (helping people is cool) but I suspect it'll be an awkward way of doing things and I just know someone like Steve or Ez0n3 will come along sooner or later and bust out an awesome way of doing it and make me feel like a total hack - but at the same time that's how both I and the asker learn something new. So I just suck it up and post anyway.

 

I'm still fuzzy on the whole states thing (gotostate does not mean leave the current state immediately? WTF) and the CK wiki isn't the most helpful on the subject of states (which is why I initially avoided them), but these examples have helped a lot.

Edited by acidzebra
Link to comment
Share on other sites

  • Recently Browsing   0 members

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