Jump to content

Scripting a timer


Yulliah

Recommended Posts

Alright, so my custom NPC is a writer with an unfinished book who wants a safe place to finish her book.

You assign her to a settlement and then I would like there to be at least 5 in-game days before she offers you the finished book to read.

How am I going to do this?

Link to comment
Share on other sites

Alright, so my custom NPC is a writer with an unfinished book who wants a safe place to finish her book.

You assign her to a settlement and then I would like there to be at least 5 in-game days before she offers you the finished book to read.

How am I going to do this?

I did this in Wastelander's Rash by creating a 24 hour timer script and using on OnTimer Event to increment a day counter. When days = target, execute a function / trigger dialogue, etc...

 

Event OnTimerGameTime(int TID)

 

Int Days = WR_DaysPassed.getvalueint()

Int NotifyMe = WR_Notifications.getvalueint()

Int NoMoreTimer = 0

If TID == 0

If WR_CompGone.getvalueint() == 1

If WR_CureMe.getstage() >= 20 && WR_Cureme.getstage() <=40

WR_DaysPassed.setvalueint(Days); record every 24 hour cycle to reduce player wait times for quest to resume

If NotifyMe == 1

Debug.notification("Curie has been gone for "+Days+" days.")

Endif

Endif

 

;Add days passing script segment with stage 40 activator here

 

If Days >= 15

ComCurie.removefromfaction(DisallowedCompanionFaction)

WR_CureMe.SetObjectiveCompleted(30)

WR_CureMe.SetStage(40)

WR_CompGone.setvalueint(0)

NoMoreTimer = 1

Endif

Endif

Else

If WR_CureME.getstage() == 30 && WR_CompGone.getvalueint() == 0

WR_CompGone.setvalueint(1)

Endif

If NoMoreTimer == 0

StartTimerGameTime(24,0)

Days = Days +1

Endif

If NoMoreTimer == 1

WR_DaysPassed.setvalueint(0)

CancelTimer()

Endif

Endif

EndEvent

 

Link to comment
Share on other sites

Awesome! Thank you both!

 

So I can just put in the stage fragment:

 

Utility.WaitGameTime(120.0)

YM_SettlementDialogue.SetStage(20)

 

Like that and then it will run the wait game time before setting the stage? (of course with the YM_SettlementDialogue set in properties)

Link to comment
Share on other sites

I'll note that the Utility.Wait() and similar methods are generally not recommended unless there's a specific reason to use them. While it's a little bit more complicated, it's more recommended to use SetTimerGameTime() and to intercept that timer (using the ID you specify) with OnTimerGameTime(). This way, you're not forcing the game engine to keep a specific script running while that call to the Utility script completes. There are quite a few otherwise great mods floating around that make very bad use of timing-related features and it's best not to make your mod one of them.

Link to comment
Share on other sites

@joelflake that's useful, have any resource profiles been published for papyrus script calls ? Be good to know which calls are thread locked or unlocked and what the execution budget is.

 

Doing some multi-threading without F4SE I was lead to believe that a call to an external script function would be async and unlock the calling script (which is why you have to nail in your own spin locks):

 

"Any time a thread makes an external call (to a function on a different object, to a global function, or to a function in a script with a different self), its execution is suspended and will be resumed when the call is completed. Meanwhile the script instance it was working on will be "unlocked" so that other threads can potentially access and modify it."

Link to comment
Share on other sites

Whether or not someone has published some profiling is a good question. I can't find the "best practices" page on the FO4 Creation Kit website, but I do recall it having said something to the effect of "timer events are preferred." I suspect part of the preference may lie in the fact that timer events can be cancelled prior to termination.

 

And it may be true that the script calling the Wait() behavior is actually freed up (and I confess it's been a while since I've reviewed the threading details of FO4's Papyrus implementation,) but this brings up the issue of exactly how the Wait() behaviors operate. Do they stick around in the name of the calling script? I admit I don't know off the top of my head, but I probably ought to figure it out since I'm in the process of rewriting some scripts from a mod of mind and extracting them as a modder's resource Papyrus library and much of the point is to actually force certain behaviors to execute serially despite threading being available in order to avoid hogging resources for things that really don't need to be threaded.

In the mean time, I'll see if I can't tamp down exactly how the wait() behaviors work. Some mods have source code that frightens me - especially those dealing with timed workshop objects - because a single call to some wait() behavior can't really take in to account other events that may affect whether or not the timer should still process. It may be the best thing for the OP's mod that the wait() behavior is used if, at the time it is called, the next lines of could should absolutely always execute.

Link to comment
Share on other sites

I would expect wait() based functions set a todo pointer in a process list and then unlock and eventually unload the script state, but dont have the profiling or debug tools to watch what actually happens.

 

Get the principle that long running transactions should be async and timers are more flexible, but, code simplicity can also be a virtue.

Link to comment
Share on other sites

  • Recently Browsing   0 members

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