HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

Periodic Spell Help in JASS

12-17-2009, 01:40 AM#1
SmileyJeff
Hi all, i am recently learning JASS, and i wanted to create DOT spells in my map that is MUI. But i can't find any good tutorial with timers to make these type of spells.

I follow the timer tutorial, and to try out how to do a periodic timer. Below is my code where when the caster cast thunderclap, it will display interger i which will increament whenenever the timer expire.

I set the timer to true, because i want it to repeat itself. But it is not repeating. I only get a "1" on screen after the 1st expire and then nothing else. Please help! Or please explain how should i make periodic timer work?

Collapse JASS:
function Trig_Periodic_Conditions takes nothing returns boolean
    if ( not ( GetSpellAbilityId() == 'AHtc' ) ) then
        return false
    endif
    return true
endfunction

function DisplayText takes nothing returns nothing
    //Doing this so that i can destroy it later    
    local timer t = GetExpiredTimer()
    //My Codes Here
    set udg_i = ( udg_i + 1 )
    call DisplayTextToForce( GetPlayersAll(), I2S(udg_i) )

    //Destroy Timer and clearing it
    call DestroyTimer(t)
    set t = null
endfunction

function Trig_Periodic_Actions takes nothing returns nothing
    local timer t = CreateTimer()
    call TimerStart(     t     ,      1.00     ,     true    ,     function DisplayText        )
    set t = null
    
endfunction

//===========================================================================
function InitTrig_Periodic takes nothing returns nothing
    set gg_trg_Periodic = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( gg_trg_Periodic, EVENT_PLAYER_UNIT_SPELL_EFFECT )
    call TriggerAddCondition( gg_trg_Periodic, Condition( function Trig_Periodic_Conditions ) )
    call TriggerAddAction( gg_trg_Periodic, function Trig_Periodic_Actions )
endfunction


Thanks in advance!
12-17-2009, 01:46 AM#2
Deaod
First of all, use TimerUtils (can be found in the scripts section).
Secondly, youre destroying the Expiring timer (which is the one you set up to run periodically).
12-17-2009, 01:50 AM#3
Kueken
You destroy the timer in the first callback.

Quote:
Originally Posted by SmileyJeff
Collapse JASS:
function DisplayText takes nothing returns nothing
    //Doing this so that i can destroy it later    
    local timer t = GetExpiredTimer()
    //My Codes Here
    set udg_i = ( udg_i + 1 )
    call DisplayTextToForce( GetPlayersAll(), I2S(udg_i) )
   
    //Destroy Timer and clearing it
    call DestroyTimer(t)   //you want pobably some condition when to destroy the timer
                           //in this case you should pause the timer before destroying it
    set t = null           //nulling a timer variable might be a bad idea, it can cause a handle stack corruption bug
                         //which can possibly crash your map
endfunction


I recommend switching to vJass and using TimerUtils for Mui spells; you can also use hashtables to store values using the handle id of the timer.

Regarding the nulling of timer variables: link
12-17-2009, 02:00 AM#4
SmileyJeff
I've tried fixed it. But now it is not working and won't display "i" anymore.

Collapse JASS:
function Trig_Periodic_Conditions takes nothing returns boolean
    if ( not ( GetSpellAbilityId() == 'AHtc' ) ) then
        return false
    endif
    return true
endfunction

function DisplayText takes nothing returns nothing
    //My Codes Here
    call DisplayTextToForce( GetPlayersAll(), I2S(udg_i) )
endfunction

function Trig_Periodic_Actions takes nothing returns nothing
    local timer t = CreateTimer()
    if(udg_i < 10) then
        call DisplayTextToForce( GetPlayersAll(), "Less Than 10" )
        call TimerStart(     t     ,      1.00     ,     true    ,     function DisplayText        )
        set udg_i = ( udg_i + 1 )
    endif

    //Destroy Timer and clearing it
    call DestroyTimer(t)
    set t = null
    
endfunction

//===========================================================================
function InitTrig_Periodic takes nothing returns nothing
    set gg_trg_Periodic = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( gg_trg_Periodic, EVENT_PLAYER_UNIT_SPELL_EFFECT )
    call TriggerAddCondition( gg_trg_Periodic, Condition( function Trig_Periodic_Conditions ) )
    call TriggerAddAction( gg_trg_Periodic, function Trig_Periodic_Actions )
endfunction

Please help, why is it not calling my DisplayText function anymore after it has expire?
Regarding vJass and TimerUtils, i will give it a check [:
12-17-2009, 02:14 AM#5
DioD
do not destroy timer ffs
12-17-2009, 02:19 AM#6
JeffreyQ
But i only destroy it after i want it to stop which is after 10seconds. >< This is confusing.

Anyway, what is the tool that highlights my JASS script like those i paste in JASS tag? Can't remember anymore.
12-17-2009, 02:25 AM#7
Kueken
You still destroy the timer every callback, but now you only display i when your variable is > 10.
12-17-2009, 02:38 AM#8
DioD
IF statement DO NOT stop execution.
12-17-2009, 06:19 AM#9
TheWye
Hi, let me explain to you how you are doing it wrong. This below is the modified code that you posted:

Collapse JASS:
function Trig_Periodic_Actions takes nothing returns nothing
    local timer t = CreateTimer()
    if(udg_i < 10) then
        call DisplayTextToForce( GetPlayersAll(), "Less Than 10" )
        call TimerStart(     t     ,      1.00     ,     true    ,     function DisplayText        )
        set udg_i = ( udg_i + 1 )
    endif

    //Destroy Timer and clearing it
    call DestroyTimer(t)
    set t = null
    
endfunction

The problem with this is that the call DestroyTimer(t) will always run if the spell is cast. The timer that was created at the beginning of this function will always get destroyed before it can even expire. Thats why it never displays the "i" anymore.

The code that you posted first was actually more correct:
Collapse JASS:
function DisplayText takes nothing returns nothing
    //Doing this so that i can destroy it later    
    local timer t = GetExpiredTimer()
    //My Codes Here
    set udg_i = ( udg_i + 1 )
    call DisplayTextToForce( GetPlayersAll(), I2S(udg_i) )

    //Destroy Timer and clearing it
    call DestroyTimer(t)
    set t = null
endfunction

function Trig_Periodic_Actions takes nothing returns nothing
    local timer t = CreateTimer()
    call TimerStart(     t     ,      1.00     ,     true    ,     function DisplayText        )
    set t = null
    
endfunction

But the problem with this is that the call DestroyTimer(t) will be called without any condition at all. This means, everytime the timer expires, it WILL be destroyed. So now the thing that you need to do is to add a condition for the destruction of the timer. You have done this on your modified code by doing the if-udg_i comparison but you are doing it a little wrong since you still put outside the if comparison. Try understanding this code:

Collapse JASS:
function DisplayText takes nothing returns nothing
    //Doing this so that i can destroy it later    
    local timer t = GetExpiredTimer()
    //My Codes Here
    if(udg_i < 10)then
        set udg_i = ( udg_i + 1 )
        call DisplayTextToForce( GetPlayersAll(), I2S(udg_i) )
    else //the use of "else" allows you to do alternative action when the if condition is not satisfied (this case udg_i >= 10)
       
        //Destroy Timer and clearing it
        call DestroyTimer(t)
        set t = null

        //don't forget to reset udg_i so it would work correctly if the spell is cast again
        set udg_i = 0
    endif
    set t = null
endfunction

function Trig_Periodic_Actions takes nothing returns nothing
    local timer t = CreateTimer()
    call TimerStart(     t     ,      1.00     ,     true    ,     function DisplayText        )
    set t = null
    
endfunction

hope that helps :)
12-17-2009, 10:36 AM#10
SmileyJeff
@TheWye

Thanks for the detail explanation and clarification and fixing my code. I understand it fully [: +rep!

Thanks to the others for hinting me what i did wrong [:
12-17-2009, 12:58 PM#11
Themerion
Once you make the transition to vJASS, you can use TimerUtils (and seeing as you seem to be somewhat competent, you eventually will switch to vJASS). Then you don't need a global variable, and can let more than 1 hero use this spell at once (if you do that now, bad things will happen, since there is only 1 global variable).

Just a short comment on the order of things in TheWye's code. Logically, you want udg_i to be 0 before you start running it. Therefore, you should set it to 0 when you begin, not when you're finished. It will make more sense.

Collapse JASS:
function Trig_Periodic_Actions takes nothing returns nothing
    local timer t = CreateTimer()

// Put it here instead of in the other function
        set udg_i = 0

    call TimerStart(     t     ,      1.00     ,     true    ,     function DisplayText        )
    set t = null
    
endfunction
12-17-2009, 07:09 PM#12
TheWye
@Themerion

Well.. must have missed that one :S. Thats actually what I usually do too.