Local Countdown Timers

Genyuumaru

New Member
Reaction score
15
I have been a GUI triggerer for a very long time now. I pretty much knew what Jass realy is and the only benefit I see from jumping GUI to Jass is the ability to use local variables.

It took me 30 minutes to learn how Jass works (I know a couple of programming languages) and the use of local variables realy helped me in some triggers.

People say that Jass makes your triggers cleaner and run more smoothly. Well I think that's trashtalk. The triggers will run more "smoothly" by some 1 or 2%. I also heard a statement in a tutorial like: "A lot of people say that GUI is faster, because it is easier, but no. Jass is faster, because you write on the keyboard faster than you click the mouse." Umm... Is this guy serious? Well, who's faster in remembering all the fucking functions?

So far everything is working, except for the topic name.

From what I understand, local variables can be used in that same function where you created them. What's the point of local countdown timers? Most likely you can't add "local timer expires" as an event. So what are they for?

Creating a trigger like:

Code:
loop
  exitwhen Remaining time of "timer" == 0 seconds
endloop
will not make your triggers run smoothly! It will cause unnecessary lag.

So... How do you do it? Like for example I want to make a MUI push trigger with the use of timers (local ones). And I don't realy think that the use of the code I gave will be very great...
 

cleeezzz

The Undead Ranger.
Reaction score
268
its better if you used GetExpiredTimer()

i dont think that loop would work very well.
 

Genyuumaru

New Member
Reaction score
15
Could you be more specific?

Okay I have a function asd.
In it I start a repeating timer that will expire in 0.05 seconds.

Now where do I put the GetExpiredTimer?
 

cleeezzz

The Undead Ranger.
Reaction score
268
JASS:
private function CB takes nothing returns nothing //you dont really need GetExpiredTimer() unless its for structs or something
     blah.(put looping actions here)
endfunction

private function asd takes nothing returns nothing
     call TimerStart( timer, 0.05, true, function CB)
endfunction
 

Expelliarmus

Where to change the sig?
Reaction score
48
So far, the ways are:
- Gamecache
- Struct Attachments (vJASS required)
- ...Adding Further Methods

Gamecache:
- Local Handle Variable Functions

Kattana's Handle Vars System

JASS:
function H2I takes handle h returns integer
    return h
    return 0
endfunction

function LocalVars takes nothing returns gamecache
    if udg_GameCache == null then
        set udg_GameCache = InitGameCache("jasslocalvars.w3v")
    endif
    return udg_GameCache
endfunction

function SetHandleHandle takes handle subject, string name, handle value returns nothing
    if value==null then
        call FlushStoredInteger(LocalVars(),I2S(H2I(subject)),name)
    else
        call StoreInteger(LocalVars(),I2S(H2I(subject)), name, H2I(value))
    endif
endfunction

function SetHandleInt takes handle subject, string name, integer value returns nothing
    if value==0 then
        call FlushStoredInteger(LocalVars(), I2S(H2I(subject)), name)
    else
        call StoreInteger(LocalVars(), I2S(H2I(subject)), name, value)
    endif
endfunction

function SetHandleBoolean takes handle subject, string name, boolean value returns nothing
    if value==false then
        call FlushStoredBoolean(LocalVars(), I2S(H2I(subject)), name)
    else
        call StoreBoolean(LocalVars(), I2S(H2I(subject)), name, value)
    endif
endfunction

function SetHandleReal takes handle subject, string name, real value returns nothing
    if value==0 then
        call FlushStoredReal(LocalVars(), I2S(H2I(subject)), name)
    else
        call StoreReal(LocalVars(), I2S(H2I(subject)), name, value)
    endif
endfunction

function SetHandleString takes handle subject, string name, string value returns nothing
    if value==null then
        call FlushStoredString(LocalVars(), I2S(H2I(subject)), name)
    else
        call StoreString(LocalVars(), I2S(H2I(subject)), name, value)
    endif
endfunction

function GetHandleHandle takes handle subject, string name returns handle
    return GetStoredInteger(LocalVars(), I2S(H2I(subject)), name)
    return null
endfunction

function GetHandleInt takes handle subject, string name returns integer
    return GetStoredInteger(LocalVars(), I2S(H2I(subject)), name)
endfunction
 
function GetHandleBoolean takes handle subject, string name returns boolean
    return GetStoredBoolean(LocalVars(), I2S(H2I(subject)), name)
endfunction

function GetHandleReal takes handle subject, string name returns real
    return GetStoredReal(LocalVars(), I2S(H2I(subject)), name)
endfunction

function GetHandleString takes handle subject, string name returns string
    return GetStoredString(LocalVars(), I2S(H2I(subject)), name)
endfunction

function GetHandleUnit takes handle subject, string name returns unit
    return GetStoredInteger(LocalVars(), I2S(H2I(subject)), name)
    return null
endfunction

function GetHandleTimer takes handle subject, string name returns timer
    return GetStoredInteger(LocalVars(), I2S(H2I(subject)), name)
    return null
endfunction

function GetHandleTrigger takes handle subject, string name returns trigger
    return GetStoredInteger(LocalVars(), I2S(H2I(subject)), name)
    return null
endfunction

function GetHandleEffect takes handle subject, string name returns effect
    return GetStoredInteger(LocalVars(), I2S(H2I(subject)), name)
    return null
endfunction

function GetHandleGroup takes handle subject, string name returns group
    return GetStoredInteger(LocalVars(), I2S(H2I(subject)), name)
    return null
endfunction

function GetHandleLightning takes handle subject, string name returns lightning
    return GetStoredInteger(LocalVars(), I2S(H2I(subject)), name)
    return null
endfunction

function GetHandleWidget takes handle subject, string name returns widget
    return GetStoredInteger(LocalVars(), I2S(H2I(subject)), name)
    return null
endfunction

function FlushHandleLocals takes handle subject returns nothing
    call FlushStoredMission(LocalVars(), I2S(H2I(subject)) )
endfunction
JASS:
function Callback takes nothing returns nothing
    local timer t = GetExpiredTimer()
    local unit dummy = GetHandleUnit(t, "dummy") //retrieve attached Data
    local real angle = GetHandleReal(t, "angle") //retrieve attached Data
    // ...Some Actions
   
    call PauseTimer(t)
    call DestroyTimer(t)
    call FlushHandleLocals(t)
    call RemoveUnit(dummy)
    set dummy = null
endfunction

function Actions takes nothing returns nothing
    // ... Some Actions
    local timer t = CreateTimer()
    local unit dummy = CreateUnit(GetOwningPlayer(u),'H001', 0, 0, bj_RADTODEG * angle) 
    call SetHandleHandle(t, "dummy", dummy) //Attach Data
    call SetHandleReal(t, "angle", angle) //Attach Data
    call TimerStart(t, 0.0375 , true, function Callback)
    call FlushHandleLocals(t)
    set t = null
    
endfunction

function InitTrig takes nothing returns nothing
    local trigger t = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ(t,EVENT_PLAYER_UNIT_SPELL_EFFECT )
    call TriggerAddAction(t,function Actions)
endfunction

Editting...

Struct Attachment
- ABC (requires vJASS)

JASS:
//==============================================================================
//  DOCUMENTATION:
//==============================================================================
//
//  PURPOUSE OF ABC:
//       * Attaching multiple structs to a <handle>
//       * Not using stupid game cache.
//      
//       * Currently supported <handle> types are timer, trigger, dialog and region
//         ABC can NOT be used to attach things to units,
//         Systems that can attach stuff to units require a mission key
//         ABC does not have mission keys, witch is one of the reasons it is so fast.
//
//       * These are the only 4 handle types I found that need attaching (except units)
//         If you have the need for some other handle types please let me know
//
//
//  HOW TO USE:
//       * Lets assume you want to attach some spell data to a timer.
//         You would do the following:
//
//         1. Create struct that will contain all your data.
//         2. call SetTimerStructA(myTimer, myStruct) 
//
//         and then you decide you need one more struct on that timer...
// 
//         call SetTimerStructB(myTimer, myStruct2) 
//
//         Then in a periodic timer you just get the stored value
//         set myStruct = GetTimerStructA(myTimer)
//     
//         In your final itearation of periodic timer
//         you need to clear stored values
//         ClearTimerStructA(myTimer)
//         ClearTimerStructB(myTimer)
//         If you don't system will start to overflow
//
//  DIFFERENCE FROM v5.1:
//       * Added support for regions
//
//  DIFFERENCE FROM v5.0:
//       * You cannot use SetStructA two times on the same <handle>
//         without clearing the previous value. 
//
//       * ABC v5.0 used to overwrite the old values when you did that.
//         This caused errors when collisions get over 3
//         Since collisions almost never happen in real maps noone noticed this before
//         Only some hardcore tests will detect this
//         
//       * New version of ABC treats overwrite as an error.
//         BAD:  SetStructA(X, value1); SetStructA(X, value2) 
//         GOOD: SetStructA(X, value1); ClearStructA(X); SetStructA(X, value2)
//
//       * HASH_COLLISION_LIMIT is reduced from 8 to 7 to simplyfy algorithms
//         (using null borders at modulo 8)
//         This effectively means that you can store around 6000 attachments per hash
//         before you get an overflow. (used to be 7000)
//         
//       * This simplyfication increased ABC speed a little.
//
//  PROS: 
//       * ABC is faster than any gamecache based system.
//
//       * you can attach any struct to any supported <handle> type
//
//       * you CAN attach up to 3 structs on the same <handle>
//         but only if you use different functions, for example
//         SetTriggerStructA(), SetTriggerStructB(), SetTriggerStructC()
//         
//       * get and set functions are extremelly fast (using hash algorithm)
//
//       * System reports collision, overwrite and overflow.
//         Basically if you do anything stupid system will tell you.
//
//       * This system will work even if your map leaks
//         and will NOT slow down because of it.
//
//       * This is the system that spits torment test in the eye.
//
//       * For compatibility with ABC v4.6 look at ABCC library
//         
//
//  CONS:
//       * you must manually clean the stored value - REMEMBER THIS RULE!!!
//         Don't forget to use ClearStruct() functions
//
//       * you should NOT use Get without a Set - REMEMBER THIS RULE!!!  
//         It will simply return a zero and nothing bad will happen,
//         but it will lag really really bad
//         (system will report this as an error)
//
//       * System starts to collide if you have more than 1024 structs in one hash.
//         (you can see this very obviosly with -overload test)
//         If that happens it can mean one of 2 things:
//           1. you are using more than 1024 timers, triggers or dialogs - !?
//           2. you forgot to use ClearStruct and you are leaking handles somewhere
//             if this is the case simply do a search on your code and find
//             what trigger uses ABC but has no ClearStruct calls.
//
//  DETAILS:
//       * when struct is detached from <handle> it is not destroyed
//         you still have to do that manually if necessary
//
//       * ABC will not interfere with other attachemt systems
//         You can freely use any other system alongside ABC
//
//       * For unit attaching I recommend using PUI
//
//
//  SPECIAL THANKS TO: 
//       * NagelBagel - for finding errors in versions 4.3 and 4.4
//       * Here-b-Trollz - for testing ABC and for making cool spells with it.
//       * Toadcop - for being pain in the ass and for pushing me to improve ABC.
//       * emjlr3 - for pointing out the need for non-generic trigger attachments
//       * PandaMine - I found a bug in ABC by examining his HSAS vs ABC test
//       * All those people out there who use and support my systems
//         Thank you guys.
//
//  HOW TO IMPORT:
//       * Just create a trigger named ABC
//       * convert it to text and replace the whole trigger text with this one
//
//==============================================================================


//------------------------------------------------------------------------------
//  We will use textmacros to create multiple instances of system
//------------------------------------------------------------------------------
//! textmacro ABC takes X, NAME, TYPE

//------------------------------------------------------------------------------
// Global arrays represent our hash tables.
// System is currently using 3 hash tables per handle type. (A, B, C)
//------------------------------------------------------------------------------
globals
    private $TYPE$    array $TYPE$Key$X$
    private integer  array $TYPE$Value$X$
        private integer  $TYPE$maxCollision$X$ = 0
endglobals

//------------------------------------------------------------------------------
// returns the maximum collision so far
//------------------------------------------------------------------------------
function Get$NAME$Collision$X$ takes nothing returns integer
    return $TYPE$maxCollision$X$
endfunction


//------------------------------------------------------------------------------
// initializes hash arrays to prevent lag when ABC is used for the first time
//------------------------------------------------------------------------------
private function Init$NAME$Hash$X$ takes nothing returns nothing
    set $TYPE$Key$X$[HASH_INDEX_LIMIT]   = null
        set $TYPE$Value$X$[HASH_INDEX_LIMIT] = 0
endfunction

//------------------------------------------------------------------------------
// attaches struct to a handle by using hash table
//------------------------------------------------------------------------------
function Set$NAME$Struct$X$ takes $TYPE$ t, integer s returns nothing
        debug local integer collision
        
        // hash using 32-bit integer overflow
    local integer i = (H2I(t) * HASH_UP) / HASH_DOWN + HASH_BIAS

        if $TYPE$Key$X$<i> == null then
            set $TYPE$Value$X$<i> = s
                set $TYPE$Key$X$<i> = t
                return
        endif

    debug if $TYPE$Key$X$<i> == t then
        debug call BJDebugMsg(&quot;|cFFFF0000ERROR: Hash[$X$] attachment overwrite on $TYPE$ #&quot; +I2S(H2I(t)))
        debug return
    debug endif        
    
        // if function gets below this line we have a collision
    debug set collision = 1
    loop
                debug if collision &gt;= HASH_COLLISION_LIMIT then
            debug call BJDebugMsg(&quot;|cFFFF0000ERROR: Hash[$X$] overflow&quot;)
            debug return
                debug endif    
        debug set collision = collision + 1
    
        set i = i + 1    
            exitwhen $TYPE$Key$X$<i> == null

        debug if $TYPE$Key$X$<i> == t then
            debug call BJDebugMsg(&quot;|cFFFF0000ERROR: Hash[$X$] attachment overwrite on $TYPE$ #&quot; +I2S(H2I(t)))
            debug return
        debug endif    
        endloop

        debug if collision &gt; $TYPE$maxCollision$X$ then
        debug   call BJDebugMsg(&quot;|cFFFF4444Warning: Hash[$X$] maximum collision is now: &quot; + I2S(collision))
        debug   set $TYPE$maxCollision$X$ = collision
        debug endif
        
    set $TYPE$Value$X$<i> = s
    set $TYPE$Key$X$<i> = t

    return
endfunction

//------------------------------------------------------------------------------
// gets stored struct from a handle 
//------------------------------------------------------------------------------
function Get$NAME$Struct$X$ takes $TYPE$ t returns integer
        debug local integer collision
        
        // hash using 32-bit integer overflow
    local integer i = (H2I(t) * HASH_UP) / HASH_DOWN + HASH_BIAS
        
        if $TYPE$Key$X$<i> == t then
                return $TYPE$Value$X$<i>
        endif
        
        // if function gets below this line we have a collision
    debug set collision = 1
    loop
                debug if collision &gt;= HASH_COLLISION_LIMIT then
                debug   call BJDebugMsg(&quot;|cFFFF0000ERROR: Hash[$X$] : get request on unknown handle&quot;)
                debug   return 0
                debug endif             
        debug set collision = collision + 1      
    
        set i = i + 1
            exitwhen $TYPE$Key$X$<i> == t
        endloop 
        
    return $TYPE$Value$X$<i>
endfunction


//------------------------------------------------------------------------------
// clears stored struct from a handle, also returns cleared value
//------------------------------------------------------------------------------
function Clear$NAME$Struct$X$ takes $TYPE$ t returns integer
        debug local integer collision
    local integer ik
    local integer ret
        
        // hash using 32-bit integer overflow
    local integer i = (H2I(t) * HASH_UP) / HASH_DOWN + HASH_BIAS
        
    // first find the index on witch key is stored
    debug set collision = 0
    loop
                debug if collision &gt;= HASH_COLLISION_LIMIT then
                debug   call BJDebugMsg(&quot;|cFFFF0000ERROR: Hash[$X$] : clear request on unknown handle&quot;)
                debug   return 0
                debug endif        
        debug set collision = collision + 1       
    
        exitwhen $TYPE$Key$X$<i> == t
        set i = i + 1
    endloop
    
    set ik = i
    set ret = $TYPE$Value$X$[ik]
    
    // then find last used key index in bucket
    loop
        set i = i + 1
        // we use the fact bucket borders (mod 8 indexes) are always null
        exitwhen $TYPE$Key$X$<i> == null  
    endloop
    
    // shift last bucket entry to the place of removed one
    set $TYPE$Key$X$[ik] = $TYPE$Key$X$[i-1]
    set $TYPE$Value$X$[ik] = $TYPE$Value$X$[i-1]
    // clear the previous last bucket entry
    set $TYPE$Key$X$[i-1] = null
    
    return ret
endfunction

//! endtextmacro

//==============================================================================
//  Macro execution -- this is where real functions get created
//==============================================================================
library ABC initializer Init

globals
        public constant integer HASH_SIZE = 8192
        public constant integer HASH_INDEX_LIMIT = 8190
        public constant integer HASH_DOWN = 524288     // 2^19  
        public constant integer HASH_UP   = 2134900736 // 2^22 * 509
        public constant integer HASH_BIAS = 4096       // HASH_SIZE / 2
        public constant integer HASH_COLLISION_LIMIT = 7 // ABC v5.0 had limit 8
        // 509 is the prime closest to 512
endglobals


//------------------------------------------------------------------------------
// conversion function used by the system internally
// you will not need to use it directly
//------------------------------------------------------------------------------
public function H2I takes handle h returns integer
    return h
    return 0
endfunction

//! runtextmacro ABC(&quot;A&quot;,&quot;Timer&quot;,&quot;timer&quot;)
//! runtextmacro ABC(&quot;B&quot;,&quot;Timer&quot;,&quot;timer&quot;)
//! runtextmacro ABC(&quot;C&quot;,&quot;Timer&quot;,&quot;timer&quot;)

//! runtextmacro ABC(&quot;A&quot;,&quot;Trigger&quot;,&quot;trigger&quot;)
//! runtextmacro ABC(&quot;B&quot;,&quot;Trigger&quot;,&quot;trigger&quot;)
//! runtextmacro ABC(&quot;C&quot;,&quot;Trigger&quot;,&quot;trigger&quot;)

//! runtextmacro ABC(&quot;A&quot;,&quot;Dialog&quot;,&quot;dialog&quot;)
//! runtextmacro ABC(&quot;B&quot;,&quot;Dialog&quot;,&quot;dialog&quot;)
//! runtextmacro ABC(&quot;C&quot;,&quot;Dialog&quot;,&quot;dialog&quot;)

//! runtextmacro ABC(&quot;A&quot;,&quot;Region&quot;,&quot;region&quot;)
//! runtextmacro ABC(&quot;B&quot;,&quot;Region&quot;,&quot;region&quot;)
//! runtextmacro ABC(&quot;C&quot;,&quot;Region&quot;,&quot;region&quot;)

private function Init takes nothing returns nothing
        call InitTimerHashA()
        call InitTimerHashB()
        call InitTimerHashC()

        call InitTriggerHashA()
        call InitTriggerHashB()
        call InitTriggerHashC()       
    
        call InitDialogHashA()
        call InitDialogHashB()
        call InitDialogHashC()
    
        call InitRegionHashA()
        call InitRegionHashB()
        call InitRegionHashC()    
endfunction


endlibrary
//==============================================================================
//  END OF ABC STRUCT ATTACHMENT SYSTEM
//==============================================================================</i></i></i></i></i></i></i></i></i></i></i></i></i></i>



JASS:
scope TimerAttachment

struct IO
    timer timer    
    unit dummy
    unit caster

 private method onDestroy takes nothing returns nothing
        call DestroTimer(.Timer)
        call RemoveUnit(.dummy)
        call ClearTimerStructA(.IOtimer)
endmethod                      
endstruct

private function Timeout takes nothing returns nothing
      local IO io = GetTimerStructA(GetExpiredTimer()) // retrieve Data
      // ..some action
      
        if Condition then //some condition
            call io.destroy() // call method onDestroy()
        endif
endfunction

private function Actions takes nothing returns nothing
    local IO io = IO.create()
    
    set io.Timer = CreateTimer()
    set io.caster = GetTriggerUnit()
    set io.dummy = CreateUnit(GetOwningPlayer(io.caster), DummyID, x, iy, angle)
    
    call SetTimerStructA(io.IOtimer, io) // attach struct to timer
    call TimerStart(io.Timer, 0.0375 true, function Timeout) // start timer
endfunction

public function InitTrig takes nothing returns nothing
    local trigger trig = CreateTrigger(  )
        call TriggerRegisterAnyUnitEventBJ( trig, EVENT_PLAYER_UNIT_SPELL_EFFECT )
        call TriggerAddAction( trig, function Actions )
endfunction
endscope


Struct Integer Arrays (Attaching via arrays)
JASS:
scope Timer

private struct IO 
    unit dummy
    unit caster

    static method create takes nothing returns IO
     local IO io = IO.allocate() 
    
        set io.caster = GetTriggerUnit()
        
        set io.dummy = CreateUnit(GetOwningPlayer(io.caster), Dummy, 0, 0, 360.0) 
       
        return io
    endmethod

    private method onDestroy takes nothing returns nothing
            call KillUnit(.dummy)
            call DestroyGroup( .damaged)
    endmethod                      
endstruct

globals
   
    private timer Timer    = null  

    private integer array Datas    
    private integer Total = 0   
endglobals

private function IOTimeout takes nothing returns nothing
 local IO d      
 local integer i = TopIndex
 
    loop
        exitwhen TopIndex &lt; 0
        set d = Datas<i>  // Get our struct.
        // ... some action
        
        if condition then //some condition
            call d.destroy()
            set TopIndex = TopIndex - 1
            if (TopIndex &lt;= 0) then
                set TopIndex = 0
                call PauseTimer(Timer)
            else
                set Datas<i> = Datas[TopIndex] 
            endif
        endif
    
        set i = i + 1 // next index
    endloop
endfunction


private function Actions takes nothing returns nothing
 local IO io = IO.create()

    set Datas[TopIndex] = io
    set TopIndex = TopIndex + 1
    
    if (TopIndex - 1 == 0) then
        call TimerStart(Timer, IOInterval, true, function IOTimeout)
    endif
endfunction


public function InitTrig takes nothing returns nothing 
 local trigger trig = CreateTrigger(  )
 
    set Timer = CreateTimer() /
    call TriggerRegisterAnyUnitEventBJ( trig, EVENT_PLAYER_UNIT_SPELL_EFFECT )
    call TriggerAddAction( trig, function Actions )
endfunction
endscope</i></i>
 

Genyuumaru

New Member
Reaction score
15
Need more info -_-

First of all - what means "private functions".

Second - If I transfer a unit variable to the loop function, will it be lost after the timer runs a couple of times? Like sometimes the Target Unit of Ability beeing cast gets lost.

Edit: What's Avada? And why use local triggers? It will save space when the spell is not used, but it will require additional space when the spell is used multiple times.
 

Expelliarmus

Where to change the sig?
Reaction score
48
First of all - what means "private functions".
It is part of the JASS extension (Read This)
When adding 'Private' in front of something (e.g functions, global variables), the preprocessor changes the function name to <scope name>__<function name>, which help prevent conflict between 2 or more functions with the same name.

Second - If I transfer a unit variable to the loop function, will it be lost after the timer runs a couple of times? Like sometimes the Target Unit of Ability beeing cast gets lost.
It will not be lost. 'transfer a unit variable' how?

Edit: What's Avada? And why use local triggers? It will save space when the spell is not used, but it will require additional space when the spell is used multiple times.
LOL Editted it. I edited one of my earlier spells and cropped bits that are irrelevant
 

Genyuumaru

New Member
Reaction score
15
Transfer - make a function take unit return nothing.

Okay I have a new question. Why can't jass triggers be turned off/on?
 

Genyuumaru

New Member
Reaction score
15
Create a trigger - edit - convert to custom text. Instead of "Initialy On" it will say "Run on Map Initialization".
 

Artificial

Without Intelligence
Reaction score
326
> Why can't jass triggers be turned off/on?
Why couldn't they..?
JASS:
call DisableTrigger(the trigger)
//and
call EnableTrigger(the trigger)


> Instead of "Initialy On" it will say "Run on Map Initialization".
Try making some GUI trigger initially disabled, and you'll see it calls DisableTrigger in the initialization function.

> And why use local triggers? It will save space when the spell is not used, but it will require additional space when the spell is used multiple times.
Whether you use a local or a global trigger has nothing to do with memory usage when the spell is cast. The InitTrig function doesn't run every time the spell is cast, it only runs once at map init.
 

Flare

Stops copies me!
Reaction score
662
loop
exitwhen Remaining time of "timer" == 0 seconds
endloop
Well, duh :p Loops carry out their actions (as good as) instantaneously so the timer won't have the chance to expire, meaning the exitwhen isn't going to be met and then you hit the op limit which is bad and causes lag

Umm... Is this guy serious? Well, who's faster in remembering all the fucking functions?
One word - AutoComplete


As regards how to use them, here's something I made with Vexorian's TimerUtils (which also has timer recycling)
JASS:
private function TimerCallback takes nothing returns nothing
    local timer t = GetExpiredTimer ()
    local FONData a = GetTimerData (t) //retrieving the struct instance from the timer
    local real x = GetUnitX (a.dummy)
    local real y = GetUnitY (a.dummy)
    local real endradius
    local rect r
    local rect r2
    local integer i = 0
    local real angle = GetRandomReal (0, bj_PI * 2)
    local real nx
    local real ny
    set x = x + a.cos * MOVEDIST
    set y = y + a.sin * MOVEDIST
    call SetUnitXY (a.dummy, x, y)
    set a.ticks = a.ticks - MOVEDIST
    set r = Rect(x - COLLRAD, y - COLLRAD, x + COLLRAD, y + COLLRAD)
    set z = a
    call EnumDestructablesInRect (r, Condition (function DestructFilter), function DestructActions)
    call RemoveRect (r)
    if a.ticks &lt;= 0 then
        set endradius = GetRadius (a.caster)
        set r = Rect (x - endradius, y - endradius, x + endradius, y + endradius)
        call EnumDestructablesInRect (r, Condition (function DestructFilter), function DestructActions)
        call RemoveRect (r)
        call ReleaseTimer (t)
        call KillUnit (a.dummy)
        call ShowUnit (a.dummy, false)
        if a.treants &lt; a.maxtreants and SPAWNREM then
            loop
            exitwhen i &gt;= a.maxtreants - a.treants
                set nx = x + Cos (angle) * OFFSET
                set ny = y + Sin (angle) * OFFSET
                call GAC_Start (TREESPAWNID, SPAWNS[GetUnitAbilityLevel (a.caster, SID) - 1], BIRTHTIME, GetOwningPlayer (a.caster), nx, ny, REMOVESPAWNED, FXSTRING, GetDuration (a.caster))
                set angle = angle + ((bj_PI*2)/(a.maxtreants - a.treants))
                set i = i + 1
            endloop
        endif
        call a.destroy ()
    endif
    set r = null
    set t = null
endfunction

private function Conditions takes nothing returns boolean
    return GetSpellAbilityId () == SID
endfunction

private function Actions takes nothing returns nothing
    local FONData a = FONData.create ()
    local timer t = NewTimer () //getting a new timer
    local location l = GetSpellTargetLoc ()
    local real cx = GetUnitX (GetTriggerUnit ())
    local real cy = GetUnitY (GetTriggerUnit ())
    local real tx = GetLocationX (l)
    local real ty = GetLocationY (l)
    local real x = tx-cx
    local real y = ty-cy
    local real angle = Atan2 (y, x)
    call RemoveLocation (l)
    set a.ticks = SquareRoot ((x*x) + (y*y))
    set a.caster = GetTriggerUnit ()
    set a.dummy = CreateUnit (GetOwningPlayer (a.caster), DID, cx, cy, angle * bj_RADTODEG)
    set a.cos = Cos (angle)
    set a.sin = Sin (angle)
    set a.maxtreants = GetTotalTreants (a.caster)
    call SetTimerData (t, a) //attaching struct instance to timer
    call TimerStart (t, INTERVAL, true, function TimerCallback) //starting the timer, executing TimerCallback when the timer expires
    set t = null
    set l = null
endfunction
 
General chit-chat
Help Users
  • No one is chatting at the moment.

      The Helper Discord

      Members online

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top