• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

Problem with timer

Status
Not open for further replies.
Level 22
Joined
Feb 3, 2009
Messages
3,292
So here's the problem, the trigger just doesn't wait for the timer at all... it just goes further. Any help?

JASS:
native UnitAlive takes unit u returns boolean

scope Mystic initializer InitTrig_Mystic_Wolf

private function Time takes nothing returns nothing
endfunction

private constant function Conditions takes nothing returns boolean
   return GetSpellAbilityId() == 'A000'   // ID of your spell
endfunction

private function Actions takes nothing returns nothing
// Don't change these
local unit x = GetTriggerUnit()
local location l = GetSpellTargetLoc()
local player xo = GetOwningPlayer(x)
local unit y
local integer lvl = GetUnitAbilityLevel(x, 'A000')
local real rnd = GetRandomReal(1 , 100)
local integer array d
local timer TheTimer = CreateTimer()
// End

// Config variables bellow.
local boolean txt = true  //displays debug messeges if set to true.
local boolean order = true // if the caster should get Ordered to stop after cast.
local boolean special = true  // if set to true, you will have a chance (set bellow) to summon a special wolf.
local real mps = 4. - lvl  // mana per second drained.
local real mps_rnd = 4. - lvl
local real t = 1.  // the delay in which the caster looses mana.
local real chance = 25.  // The chance to summon a special wolf.

// Dummy Units
set d[1]='n001'        // This one will be created if level==1 (as you see in [])
set d[2]='n000'        // This one will be created if level==2 (as you see in [])
set d[3]='n002'        // This one will be created if level==3 (as you see in [])
set d[4]='n003'        // This is the RawCode of special
// End of Dummy Units
// End of Config variables.

if GetUnitState(x , UNIT_STATE_MANA) < 1 then
call Error(GetOwningPlayer(x), "Not enough mana")
call RemoveLocation(l)
set x = null
set y = null
return
else
if rnd <= chance and special == true then
set mps = mps + mps_rnd
set y = CreateUnitAtLoc (xo, d[4], l, 0.)  // We have a chance of 25% to summon a special Wolf.
else
set y = CreateUnitAtLoc (xo, d[lvl], l, 0.)
endif
endif

if order == true then
call IssueImmediateOrder(x , "stop")  // if order is set to true, it will order the caster to stop.
endif

loop
exitwhen UnitAlive(y) == false or GetUnitState(x , UNIT_STATE_MANA) < 1 or UnitAlive(x) == false
call SetUnitState(x , UNIT_STATE_MANA , GetUnitState(x, UNIT_STATE_MANA) - mps)   // we set the mana of the caster to his mana - variable mps.
call TimerStart(TheTimer, t, false, function Time)
endloop

if txt == true then
if UnitAlive(y) == false then
call DisplayTimedTextToPlayer(Player(0), 0, 0, 2.5 , "Wolf has died.")
elseif UnitAlive(x) == false then
call DisplayTimedTextToPlayer(Player(0), 0, 0, 2.5 ,"The caster has died, therefore the wolf dies.")
elseif GetUnitState(x , UNIT_STATE_MANA) < 1 then
call DisplayTimedTextToPlayer(Player(0), 0, 0, 2.5 ,"The caster's mana has reached 0, the wolf dies.")
endif
endif
call KillUnit(y)  // we kill our unit.

// we remove leaks
call RemoveLocation(l)
set x = null
set y = null
endfunction

//===========================================================================
private function InitTrig_Mystic_Wolf takes nothing returns nothing
   local trigger t = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( t, EVENT_PLAYER_UNIT_SPELL_EFFECT )
    call TriggerAddCondition( t, Condition( function Conditions ) )
    call TriggerAddAction( t, function Actions )
endfunction
endscope
 
Level 11
Joined
Sep 30, 2009
Messages
697
man your coding hurts my eyes Q_Q maybe try to use tab sometimes to make it more readable :p
Also your starting the same timer again and again o_O
I do not really understand what you want to do :(
Waiting for a timer? Wc3 never does that ^^

Other tips:
- use coordinates instead of locations (faster)
 
Level 14
Joined
Nov 18, 2007
Messages
1,084
First: You posted this in the wrong place. :p
Second: You're misunderstanding the use of a timer. To do this correctly, you'll need to use TimerUtils.
Third: I would help you right now, but I don't have time at the moment. Instead, I'll post the indented code so other people will have an easier time helping you.
JASS:
native UnitAlive takes unit u returns boolean

scope Mystic initializer InitTrig_Mystic_Wolf

    private function Time takes nothing returns nothing
    endfunction

    private constant function Conditions takes nothing returns boolean
       return GetSpellAbilityId() == 'A000'   // ID of your spell
    endfunction

    private function Actions takes nothing returns nothing
        // Don't change these
        local unit x = GetTriggerUnit()
        local location l = GetSpellTargetLoc()
        local player xo = GetOwningPlayer(x)
        local unit y
        local integer lvl = GetUnitAbilityLevel(x, 'A000')
        local real rnd = GetRandomReal(1 , 100)
        local integer array d
        local timer TheTimer = CreateTimer()
        // End

        // Config variables bellow.
        local boolean txt = true  //displays debug messeges if set to true.
        local boolean order = true // if the caster should get Ordered to stop after cast.
        local boolean special = true  // if set to true, you will have a chance (set bellow) to summon a special wolf.
        local real mps = 4. - lvl  // mana per second drained.
        local real mps_rnd = 4. - lvl
        local real t = 1.  // the delay in which the caster looses mana.
        local real chance = 25.  // The chance to summon a special wolf.

        // Dummy Units
        set d[1]='n001'        // This one will be created if level==1 (as you see in [])
        set d[2]='n000'        // This one will be created if level==2 (as you see in [])
        set d[3]='n002'        // This one will be created if level==3 (as you see in [])
        set d[4]='n003'        // This is the RawCode of special
        // End of Dummy Units
        // End of Config variables.

        if GetUnitState(x , UNIT_STATE_MANA) < 1 then
            call Error(GetOwningPlayer(x), "Not enough mana")
            call RemoveLocation(l)
            set x = null
            set y = null
            return
        else
            if rnd <= chance and special == true then
                set mps = mps + mps_rnd
                set y = CreateUnitAtLoc (xo, d[4], l, 0.)  // We have a chance of 25% to summon a special Wolf.
            else
                set y = CreateUnitAtLoc (xo, d[lvl], l, 0.)
            endif
        endif

        if order == true then
            call IssueImmediateOrder(x , "stop")  // if order is set to true, it will order the caster to stop.
        endif

        loop
            exitwhen UnitAlive(y) == false or GetUnitState(x , UNIT_STATE_MANA) < 1 or UnitAlive(x) == false
            call SetUnitState(x , UNIT_STATE_MANA , GetUnitState(x, UNIT_STATE_MANA) - mps)   // we set the mana of the caster to his mana - variable mps.
            call TimerStart(TheTimer, t, false, function Time)
        endloop

        if txt == true then
            if UnitAlive(y) == false then
                call DisplayTimedTextToPlayer(Player(0), 0, 0, 2.5 , "Wolf has died.")
            elseif UnitAlive(x) == false then
                call DisplayTimedTextToPlayer(Player(0), 0, 0, 2.5 ,"The caster has died, therefore the wolf dies.")
            elseif GetUnitState(x , UNIT_STATE_MANA) < 1 then
                call DisplayTimedTextToPlayer(Player(0), 0, 0, 2.5 ,"The caster's mana has reached 0, the wolf dies.")
            endif
        endif
        call KillUnit(y)  // we kill our unit.

        // we remove leaks
        call RemoveLocation(l)
        set x = null
        set y = null
    endfunction

    //===========================================================================
    private function InitTrig_Mystic_Wolf takes nothing returns nothing
       local trigger t = CreateTrigger(  )
        call TriggerRegisterAnyUnitEventBJ( t, EVENT_PLAYER_UNIT_SPELL_EFFECT )
        call TriggerAddCondition( t, Condition( function Conditions ) )
        call TriggerAddAction( t, function Actions )
    endfunction
endscope
 
Level 11
Joined
Sep 30, 2009
Messages
697
JASS:
library TimerUtils initializer init
//*********************************************************************
//* TimerUtils (red+blue+orange flavors for 1.24b+)
//* ----------
//*
//*  To implement it , create a custom text trigger called TimerUtils
//* and paste the contents of this script there.
//*
//*  To copy from a map to another, copy the trigger holding this
//* library to your map.
//*
//* (requires vJass)   More scripts: htt://www.wc3c.net
//*
//* For your timer needs:
//*  * Attaching
//*  * Recycling (with double-free protection)
//*
//* set t=NewTimer()      : Get a timer (alternative to CreateTimer)
//* ReleaseTimer(t)       : Relese a timer (alt to DestroyTimer)
//* SetTimerData(t,2)     : Attach value 2 to timer
//* GetTimerData(t)       : Get the timer's value.
//*                         You can assume a timer's value is 0
//*                         after NewTimer.
//*
//* Multi-flavor:
//*    Set USE_HASH_TABLE to true if you don't want to complicate your life.
//*
//* If you like speed and giberish try learning about the other flavors.
//*
//********************************************************************

//================================================================
    globals
        //How to tweak timer utils:
        // USE_HASH_TABLE = true  (new blue)
        //  * SAFEST
        //  * SLOWEST (though hash tables are kind of fast)
        //
        // USE_HASH_TABLE = false, USE_FLEXIBLE_OFFSET = true  (orange)
        //  * kinda safe (except there is a limit in the number of timers)
        //  * ALMOST FAST
        //
        // USE_HASH_TABLE = false, USE_FLEXIBLE_OFFSET = false (red)
        //  * THE FASTEST (though is only  faster than the previous method
        //                  after using the optimizer on the map)
        //  * THE LEAST SAFE ( you may have to tweak OFSSET manually for it to
        //                     work)
        //
        private constant boolean USE_HASH_TABLE      = true
        private constant boolean USE_FLEXIBLE_OFFSET = false

        private constant integer OFFSET     = 0x100000
        private          integer VOFFSET    = OFFSET
              
        //Timers to preload at map init:
        private constant integer QUANTITY   = 256
        
        //Changing this  to something big will allow you to keep recycling
        // timers even when there are already AN INCREDIBLE AMOUNT of timers in
        // the stack. But it will make things far slower so that's probably a bad idea...
        private constant integer ARRAY_SIZE = 8190

    endglobals

    //==================================================================================================
    globals
        private integer array data[ARRAY_SIZE]
        private hashtable     ht
    endglobals

    //It is dependent on jasshelper's recent inlining optimization in order to perform correctly.
    function SetTimerData takes timer t, integer value returns nothing
        static if(USE_HASH_TABLE) then
            // new blue
            call SaveInteger(ht,0,GetHandleId(t), value)
            
        elseif (USE_FLEXIBLE_OFFSET) then
            // orange
            static if (DEBUG_MODE) then
                if(GetHandleId(t)-VOFFSET<0) then
                    call BJDebugMsg("SetTimerData: Wrong handle id, only use SetTimerData on timers created by NewTimer")
                endif
            endif
            set data[GetHandleId(t)-VOFFSET]=value
        else
            // new red
            static if (DEBUG_MODE) then
                if(GetHandleId(t)-OFFSET<0) then
                    call BJDebugMsg("SetTimerData: Wrong handle id, only use SetTimerData on timers created by NewTimer")
                endif
            endif
            set data[GetHandleId(t)-OFFSET]=value
        endif        
    endfunction

    function GetTimerData takes timer t returns integer
        static if(USE_HASH_TABLE) then
            // new blue
            return LoadInteger(ht,0,GetHandleId(t) )
            
        elseif (USE_FLEXIBLE_OFFSET) then
            // orange
            static if (DEBUG_MODE) then
                if(GetHandleId(t)-VOFFSET<0) then
                    call BJDebugMsg("SetTimerData: Wrong handle id, only use SetTimerData on timers created by NewTimer")
                endif
            endif
            return data[GetHandleId(t)-VOFFSET]
        else
            // new red
            static if (DEBUG_MODE) then
                if(GetHandleId(t)-OFFSET<0) then
                    call BJDebugMsg("SetTimerData: Wrong handle id, only use SetTimerData on timers created by NewTimer")
                endif
            endif
            return data[GetHandleId(t)-OFFSET]
        endif        
    endfunction

    //==========================================================================================
    globals
        private timer array tT[ARRAY_SIZE]
        private integer tN = 0
        private constant integer HELD=0x28829022
        //use a totally random number here, the more improbable someone uses it, the better.
    endglobals

    //==========================================================================================
    function NewTimer takes nothing returns timer
        if (tN==0) then
            //If this happens then the QUANTITY rule has already been broken, try to fix the
            // issue, else fail.
            debug call BJDebugMsg("NewTimer: Warning, Exceeding TimerUtils_QUANTITY, make sure all timers are getting recycled correctly")
            static if( not USE_HASH_TABLE) then
                debug call BJDebugMsg("In case of errors, please increase it accordingly, or set TimerUtils_USE_HASH_TABLE to true")
                set tT[0]=CreateTimer()
                static if( USE_FLEXIBLE_OFFSET) then
                    if (GetHandleId(tT[0])-VOFFSET<0) or (GetHandleId(tT[0])-VOFFSET>=ARRAY_SIZE) then
                        //all right, couldn't fix it
                        call BJDebugMsg("NewTimer: Unable to allocate a timer, you should probably set TimerUtils_USE_HASH_TABLE to true or fix timer leaks.")
                        return null
                    endif
                else
                    if (GetHandleId(tT[0])-OFFSET<0) or (GetHandleId(tT[0])-OFFSET>=ARRAY_SIZE) then
                        //all right, couldn't fix it
                        call BJDebugMsg("NewTimer: Unable to allocate a timer, you should probably set TimerUtils_USE_HASH_TABLE to true or fix timer leaks.")
                        return null
                    endif
                endif
            endif
        else
            set tN=tN-1
        endif
        call SetTimerData(tT[tN],0)
     return tT[tN]
    endfunction

    //==========================================================================================
    function ReleaseTimer takes timer t returns nothing
        if(t==null) then
            debug call BJDebugMsg("Warning: attempt to release a null timer")
            return
        endif
        if (tN==ARRAY_SIZE) then
            debug call BJDebugMsg("Warning: Timer stack is full, destroying timer!!")

            //stack is full, the map already has much more troubles than the chance of bug
            call DestroyTimer(t)
        else
            call PauseTimer(t)
            if(GetTimerData(t)==HELD) then
                debug call BJDebugMsg("Warning: ReleaseTimer: Double free!")
                return
            endif
            call SetTimerData(t,HELD)
            set tT[tN]=t
            set tN=tN+1
        endif    
    endfunction

    private function init takes nothing returns nothing
     local integer i=0
     local integer o=-1
     local boolean oops = false
     
        static if( USE_HASH_TABLE ) then
            set ht = InitHashtable()
            loop
                exitwhen(i==QUANTITY)
                set tT[i]=CreateTimer()
                call SetTimerData(tT[i], HELD)
                set i=i+1
            endloop
            set tN = QUANTITY
        else
            loop
                set i=0
                loop
                    exitwhen (i==QUANTITY)
                    set tT[i] = CreateTimer()
                    if(i==0) then
                        set VOFFSET = GetHandleId(tT[i])
                        static if(USE_FLEXIBLE_OFFSET) then
                            set o=VOFFSET
                        else
                            set o=OFFSET
                        endif
                    endif
                    if (GetHandleId(tT[i])-o>=ARRAY_SIZE) then
                        exitwhen true
                    endif
                    if (GetHandleId(tT[i])-o>=0)  then
                        set i=i+1
                    endif
                endloop
                set tN = i
                exitwhen(tN == QUANTITY)
                set oops = true
                exitwhen not USE_FLEXIBLE_OFFSET
                debug call BJDebugMsg("TimerUtils_init: Failed a initialization attempt, will try again")               
            endloop
            
            if(oops) then
                static if ( USE_FLEXIBLE_OFFSET) then
                    debug call BJDebugMsg("The problem has been fixed.")
                    //If this message doesn't appear then there is so much
                    //handle id fragmentation that it was impossible to preload
                    //so many timers and the thread crashed! Therefore this
                    //debug message is useful.
                elseif(DEBUG_MODE) then
                    call BJDebugMsg("There were problems and the new timer limit is "+I2S(i))
                    call BJDebugMsg("This is a rare ocurrence, if the timer limit is too low:")
                    call BJDebugMsg("a) Change USE_FLEXIBLE_OFFSET to true (reduces performance a little)")
                    call BJDebugMsg("b) or try changing OFFSET to "+I2S(VOFFSET) )
                endif
            endif
        endif

    endfunction

endlibrary

Timerutils allows you to attach an integer to a timer, also it allows timer recycling. Everything else explains the well done documentation ;)
 
Status
Not open for further replies.
Top