Jump to content

Scripting time events


A.J.

Recommended Posts

Hello, I have some questions about Scripting time events.

 

Until now, I did them with workarounds. For example, if you need to reach a certain location in 3 days after you take the quest, I was setting a "quest.startingtime" variable as gamedayspassed, then in front of the door of the location I was placing a trigger box with a script attached, where it was a ending time set as gamedayspassed, then a simple endingtime - startingtime comparison to 3 would make the trick.

 

Ok I don't know if I explained well but it was quite a simple script and it was working in these kinds of situations.

 

But now I really would like to introduce a REALTIME event.

 

A NPC enters in a place and he must go out after some time, I would say 1 minute.

 

Since I use staged timers to make things happen after some time, I did a staged timer to make these 60 seconds pass.

scn aaPSourisIsAwayScript

begin gamemode

if aaPinkyAptSet.aaPSourisAway == 1 ;this is a global quest.variable that says when he must be away, it avoids 
				    ;the timer to start until it is setted to 1 from the rest of the quest)

	if aaPinkyAptSet.aaPSourisStart > 0    ;The timer itself, in the shape of a quest.variable, I
					       ; tried with a local one, the classic ftimer and istage, 
					       ;and it wasn't working. Since I change cells and do 
					       ;things while the time passes, I supposed I had to place a
					       ;global quest.variable)

		set aaPinkyAptSet.aaPSourisStart to GetSecondsPassed

	elseif aaPinkyAptSet.aaPSourisStage == 0    ;The stage of the timer, quest.variable as over here
		set aaPinkyAptSet.aaPSourisStart to 60
		set aaPinkyAptSet.aaPSourisStage to 1

	elseif aaPinkyAptSet.aaPSourisStage == 1
		set aaPinkyAptSet.aaPSourisStart to 0
		set aaPinkyAptSet.aaPSourisStage to 2

                ;etc.etc. do the other things that must happen when the time finishes

	endif

endif

end

Can you notice something wrong in the script itself?

 

.

.

.

 

Now what I can't understand is WHERE I should attach my script.

 

- I can't attach it to the NPCREF because it's disabled (ok... too long to explain why, but simply when he goes over the door he will be disabled), and I already have seen that disabled things make troubles with scripts that refer to themselves (crash too).

- I attached it to the Dialogue quest of this NPC. Doesn't work.

- I attached it to the main quest (it is and it will be running for a long time). Still doesn't work.

- Should I make a fake quest to attach it? I can't see how this could be different on attaching it on the main quest or the dialogue quest.

 

I'm also using my little debug item that shows ingame the values of the variables. Two variables (the stage and the aaPSourisIsAway, the one that makes the timer start) are set in the right way; the only one that shows weird values is the timer itself. But since I'm not sure my little debug tool can correctly handle a float value, I don't feel in the mood to blame it.

 

Oooh... my script formatted in very bad colours because of the comments I've placed, sorry. Anyway, if someone needs some more informations, I'll provide everything you need.

 

Thank you very much

Link to comment

Based on what I see, the above code does the following:

 

When aaPinkyAptSet.aaPSourisAway == 1, enter inner block.

 

Since aaPinkyAptSet.aaPSourisStart == 0  first if is skipped.

 

Since aaPinkyAptSet.aaPSourisStage == 0 second if does get processed.

        aaPinkyAptSet.aaPSourisStage set to 1

        aaPinkyAptSet.aaPSourisStart set to 60

 

Script proceeds to next frame.

 

At this point, unless aaPinkyAptSet.aaPSourisAway == 1 is changed, the script will never do ANYTHING but the first

if aaPinkyAptSet.aaPSourisStart > 0  block since it will always be > 0. The other elseif's will simply get skipped.

 

It's very important that aaPinkyAptSet.aaPSourisStart is a float and NOT an integer. For example:

 

Let's say that GetSecondsPassed returns .002456 seconds. Assigning that value to a float results in the variable being

equal to .002456. Assigning it to an integer results in a variable being equal to 0 since it rounds the float to integer

using normal rounding rules for a typecast.

 

You are replacing aaPinkyAptSet.aaPSourisStart with GetSecondsPassed each frame so it's never going to actually vary much.

It will simply end up being a tiny number and never incrementally increase (or, in this case, since you started it at 60, you want it

to decrease).

 

Try something like this:

scn aaPSourisIsAwayScript

begin gamemode

    if aaPinkyAptSet.aaPSourisAway == 1

        if aaPinkyAptSet.aaPSourisStage == 0
            set aaPinkyAptSet.aaPSourisStart to 60
            set aaPinkyAptSet.aaPSourisStage to 1
            return
        endif
 
        if aaPinkyAptSet.aaPSourisStage == 1
            if aaPinkyAptSet.aaPSourisStart > 0
                set aaPinkyAptSet.aaPSourisStart to aaPinkyAptSet.aaPSourisStart - GetSecondsPassed
            else
                set aaPinkyAptSet.aaPSourisStage to 2
            endif
            return
        endif

        if aaPinkyAptSet.aaPSourisStage == 2
            set aaPinkyAptSet.aaPSourisStart to 0
            set aaPinkyAptSet.aaPSourisStage to 3
            return
        endif

    endif

end
Link to comment

Mmmh... reading your answer I suppose I found the problem.

 

set aaPinkyAptSet.aaPSourisStart to GetSecondsPassed  in the first block IS WRONG

It should be:

set aaPinkyAptSet.aaPSourisStart to aaPinkyAptSet.aaPSourisStart - GetSecondsPassed

 

Thank you Astymma to show me the right way :)

 

Still, where do I should attach a script like that? I mean, can I attach it to a random dialogue quest, for example? or should I create a new fake empty quest? or... any other place, maybe? I can't attach it to the NPC involved because he's going to be disabled sometimes.

 

--------------

 

By the way, this is out of topic but maybe you could be interested of it. I'm aware that script is a little tricky, but after I got the sense of it I found a nice way to make a timer.

 

When the script starts, timer is 0, so the first if timer > 0 is skipped and goes to the elseif where the stage is 0. Here the timer is set to 60 and stage is set to 1. Then it jumps the other elseif. It comes back at the start of the script, now timer is > 0 so the timer starts counting from 60 to 0. When it finishes, it goes to the elseif where the stage is 1. Here it sets stage 2 and does the rest of the things.

 

He explains definetely better what I mean

http://www.cipscis.com/fallout/tutorials/staged_timers.aspx

Link to comment

Well I suppose I would need an entire thread for that, Halstrom. I mean, I'm quite new on modding and even if at this point I start to understand the sense of things most of the time, there are many times where I could apply different solutions to a common problem. Fact is, I'm sure there are solutions better than others, concerning stability. So a staged timer script could be replaced with a timed effect, but what is the better solution between the two of them? Now for the reason you said the effect disappear when I change cell, I couldn't use it. Also I couldn't use it because that NPC is going to be disabled and re-enabled, sometimes. But the concept at the bottom still remains. What's better? What potentially less breaks the player's game? This is the main question that haunts my mind several times, while developing my little mod, because my last though is releasing it, not only learning about modding, and I wouldn't want to break anyone else's game. In my past experience as Fallout and mainly Skyrim gamer, when installing a mod we all (the gamers, the mod users) knew  that a scripted mod could be potentially more dangerous than a plain one. But I really can't live without scripting in a quest mod, it's definetely impossible when the quest is something different from "go there and kill everyone".

 

Here's a little example of a script stability doubt. I made a valve activator, that regulates the water in a room. I linked the Z position of the water with a timer (Z = Z - getsecondspassed), so when you activate the valve the water goes down slowly inside a grate and empties the room. Nice, it's working. But even without the water, when you go in the room your visual will change with a blurry one like if the water was still there. There are no swim animations, or radiations from the water, just the visual effect. So I though ok let's disable the water when it reaches the bottom. This leads to a crash, probably because I'm disabling an item with a script running on it, inside the script itself (!!!). So I kept it in this way, with the blurry visual effect, and it's quite bad for realism. But, worst than ever, if I see a blurry visual effect where there's no water, it means something is not working properly, generally speaking, I think this could lead to some break at some point in the future.

 

I can understand that modding will imply experience, and probably at the end it also means "you can't do whatever you have in mind, just stick with safe solutions". Fact is I still don't know which they are (the safe solutions), but I know that after all this work, after the hundred hours spent in this mod, if one day I'll find I did deep mistakes in concept I'll start crying like a sulky brahmin. I doubt I'll do everything from scratch.

 

On a side note, for Astymma:

I see redundancy in variables in my script, I could simply use the aaPSourisIsAway as stage for the timer itself, applied to your script. Your script is definetely better and better written. Thank you very much!

And my script with that corrected mistake worked too. But still I prefer yours.

Link to comment

No Problems, I just thought I'd throw it out there, I have zero experience with activators myself, you also may find Prideslayers NX_Variable system very handy for dealing with flags on actors too or telling your quest script which actor it is dealing with, have a look at my SexoutDrugging beta OP for more info on how NX works, it's really very simple just Set & Get functions :)

Link to comment

Your script was fine to be honest AJ... it comes down to experience specifically with scripting these engines.

When I construct a "staged" script I prefer if-endifs with returns over a long series of if-elseif....endif  chunks without needing returns.

 

A few reasons:

 

  • The number of elseifs in one if-endif block is limited before the engine barfs.
  • Returning at the earliest logical moment conserves script time so other scripts get more time.
  • A large elseif construction evaluates every single condition all the way to the end, taking the maximum time each frame to execute.
  • if-endifs with returns are more easily read and debugged than large elseif constructions.
Link to comment

Astymma

 

I understand and perfectly agree with your points.

 

And I would like to underline one of these:

 

"The number of elseifs in one if-endif block is limited before the engine barfs."

 

This kind of things is what I would really need to know right now. I suppose this is a "trick" not easily documented around, on my side this is the first time I read about it, and believe me if I tell you I like reading things around to learn something more. I figure this is one of those things that could lend to an infinite frustration while looking for a mistake in a script, if people like me never heard about it.

 

Wouldn't be nice if scraps of wisdom like this one would be written and pinned all together in a thread? like for example in the 101 help script thread? This is just a suggestion.

Link to comment

Archived

This topic is now archived and is closed to further replies.

  • Recently Browsing   0 members

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

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue. For more information, see our Privacy Policy & Terms of Use