Jump to content

Help creating a timed for loop


Noggog

Recommended Posts

So, I have a custom Turn Undead script that lowers the stats of the undead victim, as well as some other things. I wanted to make it so that the stats wouldn't come back at the snap of a finger once the spell ended, but rather slowly creep back throughout the spell duration.

 

I started using this (messy and unpolished) script in the scriptEffectFinish area of my spell effect:

 

             ;loop is my loop timer, initially 0

Label 0 
		set loop to (loop + getSecondsPassed)
	printc "timer is %.2f", loop
 if ( loop < 5 )
 	 GoTo 0
	 endif

 

When I run this beast, it goes through and finishes the loop in a fraction of a second. I'm guessing it's because this loop is running every frame it can, and even if the getSecondsPassed is only .01, it'll keep adding .01 to the loop until it reaches 5.

 

So I decided to do this script instead:

 

             ;loop is my loop timer, initially 0

Label 0 
		set loop getSecondsPassed
	printc "timer is %.2f", loop
                           
 if ( loop < 5 )
 	 GoTo 0
	 endif

 

It seemed to work in my head, because getSecondsPassed would initially be 0, and then when one second had passed, getSecondsPassed would be 1, and then loop would be set to 1. This would continue until 5 seconds had passed.

Instead, my game freezes, probably because of an infinite loop.

 

What am I fundamentally getting wrong here? How do I just get a loop that lasts X seconds long?

Edited by Leviathan1753
Link to comment
Share on other sites

What am I fundamentally getting wrong here? How do I just get a loop that lasts X seconds long?

 

What you're missing is that GetSecondsPassed represents the time elapsed since the last frame your script ran in and the beginning of the current frame. It does not change within a frame. The other thing to keep in mind, is that your entire script is run in one frame, regardless of how long it takes. If you were to make a script that really took 5 seconds to run, then the game would freeze for 5 seconds.

 

Label 0 
		set loop to (loop + getSecondsPassed)
	printc "timer is %.2f", loop
 if ( loop < 5 )
 	 GoTo 0
	 endif

 

What's happening in the above snippet is that this entire loop is running in one frame. If your game is running at 60fps, then getSecondsPassed is about 0.17, and your loop is being run 294 times. Of course it runs very quickly since it's not doing anything within the loop.

 

        	Label 0 
		set loop getSecondsPassed
	printc "timer is %.2f", loop
                           
 if ( loop < 5 )
 	 GoTo 0
	 endif

 

In the above code, you have created an infinite loop. GetSecondsPassed does not change within a frame, no matter how long that frame takes to process. And since it will not increment inside your script, loop will never increment either. So your loop will never end.

 

The proper way to do this is not to do it in the ScriptEffectFinish block at all. ScriptEffectFinish runs only once, at the very end of the spell duration. The better way to do it is to set the spell's duration to however long you want the effect to last, and use the ScriptEffectUpdate block to make whatever you want happen after X number of seconds. ScriptEffectUpdate runs every frame that the spell is active. The timer then looks like this:

 

float timer

begin ScriptEffectUpdate
    if ( timer < 5 )
        set timer to timer + getSecondsPassed
    else         
        ; insert block of code that has to run after 5 seconds
    endif
end

 

The above will increment timer every frame until 5 seconds has passed, after which your block of code will run. If you want the loop to run every 5 seconds while the spell is running, rather than just once, set timer = 0 in that block of code.

 

As far as what you are trying to do, I guess my take on it would be something like this:

 

float timer
float timelimit

begin ScriptEffectStart
     set timelimit to 25
     ; other stuff
end

begin ScriptEffectUpdate
    if ( timer < timelimit )
        set timer to timer + getSecondsPassed
    else
        if (timelimit == 25)
             ; insert block of code that has to run after the first 25 seconds
             set timelimit to 5
             set timer to 0
        else
             ; insert block of code that runs every 5 seconds until the end of the spell duration
             set timer to 0
        endif
    endif
end

 

The above will do nothing for the first 25 seconds of the spell duration. After that, it will do the first block of code, and then the second block of code every 5 seconds until the end of the spell.

Edited by InAComaDial999
Link to comment
Share on other sites

There aren't commands to get those in the vanilla CS. You can do it with OBSE functions though. I believe it would go like this:

 

int spellindex
int spellduration
int spellmagnitude

begin ScriptEffectStart
   set spellindex to GetScriptActiveEffectIndex
   set spellduration to (GetNthActiveEffectDuration spellindex)
   set spellmagnitude to (GetNthActiveEffectMagnitude spellindex)
...
end

Edited by InAComaDial999
Link to comment
Share on other sites

  • 9 years later...

just what i am also looking for .... i use this code as u say and work great

 

float timer

begin ScriptEffectUpdate

if ( timer < 5 )

set timer to timer + getSecondsPassed

else

; insert block of code that has to run after 5 seconds

endif

end

now is it possible to add a key to stop the whole script ... i try to use ( getbuttonpressed ) but no success
Edited by mma75online
Link to comment
Share on other sites

GetButtonPressed is only for use with message boxes. It's not for detecting the pressing of keyboard keys.

I'm afraid this will require OBSE instead. Either OnKeyDown or IsKeyPressed, 2, 3 could be used. I personally prefer IsKeyPressed2 for things like this.

But now we need to know what kind of spell this is. If it's of only temporary effect, like an actual Spell or Power or Potion, and has to be re-cast every time, the loop could be broken via a stop flag variable perhaps. Though if it's more like an Ability and endlessly running, it cannot be stopped unless forever, and then it can't be made working again, unless by another trigger somehow.

Provided it is a Spell and will cease running after a time, the stop flag will also be cleared the next time it's casted. Then a script like this could do:


float timer
short stopTimer
 
Begin ScriptEffectUpdate
    if IsKeyPressed2 <yourKeyCode>
        set stopTimer to 1
    endif
    if stopTimer
        return ; abort script run here
    endif
    if ( timer < 5 )
        set timer to timer + getSecondsPassed
    else
        ; insert block of code that has to run after 5 seconds
    endif
End
Link to comment
Share on other sites

thank u for fast replay & thank u more for this information it will great help me for some mod i wanna improve

 

the script i was work in it is a spell that trigger several random animation in certain condition ... I try IsKeyPressed2 as u instruct but not break the loop the animation stay repeated until the end of the spell duration ..

Link to comment
Share on other sites

Hmm, can I see the whole script here, so everything's in context, check the order in which things happen and where stuff can go wrong?

sorry to bother U .. it work the error was mine i set a key used by other mod ... when i change it script work fine .. thank u very much

Link to comment
Share on other sites

  • Recently Browsing   0 members

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