System GUI-Friendly Timer System

Weep

Godspeed to the sound of the pounding
Reaction score
400
GUI-Friendly Timer System
by Weep
Version 1.0.4​

-- General Information --
This system provides a leak-free, GUI-friendly implementation of a timer system. It requires no JASS knowledge to use, nor any other systems, nor any software other than the World Editor. It will not interfere with other systems, either.

Before you copy triggers that use GTS into a new map, you need to copy over GTS with its GTS Variable Creator trigger, or the pasted triggers will have some of their actions disabled.
If you pasted GTS-using triggers before pasting GTS, to fix it, go through all the pasted triggers and find any actions like "Run GTS Store <gen>" or "Run GTS Release <gen>", and re-enable them.

-- How To Implement --
  1. Be sure "Automatically create unknown variables while pasting trigger data" is enabled in the World Editor general preferences.
  2. Copy the trigger category "GTS" from the demo map and paste it into your map.

-- Example Usage --
Using GTS in your own triggers is a multi-step process, and will be a little unfamiliar to GUI users, although I've made it as easy as I know how.

I'll walk you through a simple example: creating a special effect, then destroying it after a short delay.

You will need:
  1. Arrays to store any data you want to be able to use when the timer expires. In this case, it's a Special Effect array named TestFX. Note: these arrays should only be used with GTS's indexing, or it might conflict! To save the same data using different indexing, eg. unit auto-indexing, use a separate array.
  2. A "callback" trigger that will be run when the timer expires. In this case, I'll name the trigger TestCallback.
  3. A trigger in which you'll start the timer. In this case, it'll be a trigger named Test that's set to run when the player hits "esc".

First, here's what the main trigger, Test, should look like:
Trigger:
  • Test
    • Events
      • Player - Player 1 (Red) skips a cinematic sequence
    • Conditions
    • Actions
      • -------- Yes, this leaks a point...it&#039;s just an example: --------
      • Special Effect - Create a special effect at (Center of (Playable map area)) using Abilities\Spells\Orc\LightningShield\LightningShieldTarget.mdl
      • Set TestFX[GTS_NewIndex] = (Last created special effect)
      • Set GTS_StoreTrigger = TestCallback &lt;gen&gt;
      • Countdown Timer - Start GTS_NewTimer as a One-shot timer that will expire in 4.00 seconds
      • Trigger - Run GTS Store &lt;gen&gt; (ignoring conditions)

  • For this example, we create a special effect, then store it in the array, using GTS_NewIndex as the index. GTS_NewIndex is a number that is matched with the timer GTS_NewTimer, which can be used to store data in an array so that we will be able to retrieve it later, when the timer expires. (FYI: this is similar to how "structs" work in vJASS, with a set of data all being saved at one particular array index in several arrays. It's a multi-instanceable way of working.)
  • We set GTS_StoreTrigger to be our "callback" trigger, the trigger we want to run when the timer expires - in this case, it's the trigger named TestCallback I listed above.
  • We start the timer however we like. It can be a repeating timer, but in this case, we just want it to run once.
  • Last, we run the trigger GTS Store <gen>, which finalizes the process - it saves the trigger we specified to run with the timer, and loads a new timer and its index to GTS_NewTimer and GTS_NewIndex, ready to be used next.

Next, here's what the "callback" trigger, TestCallback, should look like:
Trigger:
  • TestCallback
    • Events
    • Conditions
    • Actions
      • Special Effect - Destroy TestFX[GTS_GetIndex]
      • Trigger - Run GTS Release &lt;gen&gt; (ignoring conditions)

  • Because we saved the special effect in the array TestFX at the proper index, we can retrieve it at the index GTS_GetIndex. When the trigger expires, that variable is set to the same number as GTS_NewIndex was when we started the timer. Note: GTS_GetIndex only works in a "callback" trigger being run by GTS, only when the timer expires!
  • The last action is Run GTS Release <gen>, which stops the expiring timer and recycles it back into the system. If you don't release a timer when you're done with it, it will leak from the system. It's also possible to release a timer at any time by setting GTS_ReleaseTimer to whichever timer you want to stop, then running GTS Release <gen>, but if there is no timer set, it will release the expiring timer (which is what we're doing in this example).
TIP: Move the "callback" trigger above the main trigger in the World Editor's trigger list. This will make it easier to copy and paste your triggers as a whole trigger category, into a new map. Or, be sure you paste the "callback" trigger into a new map before pasting the main trigger, if you're copying them one at a time.


Here's a more complex example, which can be used as a basis for any "over time" type of effect. This example produces one of two types of explosion effects, chosen randomly but always the same for the whole duration, on every unit on the map, every 0.5 seconds for 6 seconds. This demonstrates releasing a timer from outside its callback.

Trigger:
  • TimerTest
    • Events
      • Player - Player 1 (Red) skips a cinematic sequence
    • Conditions
    • Actions
      • Custom script: set bj_wantDestroyGroup = true
      • Unit Group - Pick every unit in (Units in (Playable map area)) and do (Actions)
        • Loop - Actions
          • -------- For a short-duration timer to create effects: --------
          • -------- Save the picked unit at the index of the timer we will be using. --------
          • Set ExampleUnit[GTS_NewIndex] = (Picked unit)
          • -------- Randomly save one out of two possible paths for the effect. --------
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • (Random integer number between 0 and 1) Equal to 0
            • Then - Actions
              • Set ExampleString[GTS_NewIndex] = Abilities\Weapons\Bolt\BoltImpact.mdl
            • Else - Actions
              • Set ExampleString[GTS_NewIndex] = Abilities\Spells\Other\Incinerate\FireLordDeathExplode.mdl
          • -------- Set which trigger to run with the timer. --------
          • Set GTS_StoreTrigger = TimerCallback1 &lt;gen&gt;
          • -------- Start the timer. --------
          • Countdown Timer - Start GTS_NewTimer as a Repeating timer that will expire in 0.50 seconds
          • -------- Save the data. --------
          • Trigger - Run GTS Store &lt;gen&gt; (ignoring conditions)
          • -------- -------------------- --------
          • -------- For a long-duration timer to stop the periodic creation of effects: --------
          • -------- Store the previously-started timer so we can stop it. --------
          • Set ExampleTimers[GTS_NewIndex] = (Last started timer)
          • -------- Set which trigger to run with the timer. --------
          • Set GTS_StoreTrigger = TimerCallback2 &lt;gen&gt;
          • -------- Start the timer. --------
          • Countdown Timer - Start GTS_NewTimer as a One-shot timer that will expire in 3.00 seconds
          • -------- Save the data. --------
          • Trigger - Run GTS Store &lt;gen&gt; (ignoring conditions)

Trigger:
  • TimerCallback1
    • Events
    • Conditions
    • Actions
      • -------- In this action, we get the data we previously &quot;attached&quot; to the timer, because GTS_GetIndex is the index of the expiring timer. --------
      • Special Effect - Create a special effect attached to the overhead of ExampleUnit[GTS_GetIndex] using ExampleString[GTS_GetIndex]
      • Special Effect - Destroy (Last created special effect)

Trigger:
  • TimerCallback2
    • Events
    • Conditions
    • Actions
      • -------- Set the short-period timer as the timer to release. --------
      • Set GTS_ReleaseTimer = ExampleTimers[GTS_GetIndex]
      • -------- Release it. --------
      • Trigger - Run GTS Release &lt;gen&gt; (ignoring conditions)
      • -------- Now, release the long-duration timer, which is the expiring timer. --------
      • -------- (Since the timer we set to GTS_ReleaseTimer was already released, by default it will release the expiring timer.) --------
      • Trigger - Run GTS Release &lt;gen&gt; (ignoring conditions)

-- System Code --
JASS:
// GUI-Friendly Timer System -- v1.0.4 -- by Weep
//    http://www.thehelper.net/forums/showthread.php?t=151051
//
//    Requires: only this trigger and its variables.
//
// -- What? --
//    This system provides a leak-free, GUI-friendly implementation of a timer system.
//    It requires no JASS knowledge to use.
//
// -- Why? --
//    The World Editor GUI provides no ability to create or easily manage timers without
//    custom script.  This system is easy to implement and, as a bonus, takes care of
//    indexing, as well.
//
// -- How To Implement --
//    0. Before you copy triggers that use GTS into a new map, you need to copy over GTS
//       with its GTS Variable Creator trigger, or there will be a problem: actions in the
//       pasted triggers will be disabled.
//
//    1. Be sure &quot;Automatically create unknown variables while pasting trigger data&quot; is
//       enabled in the World Editor general preferences.
//    2. Copy this trigger category (&quot;GTS&quot;) and paste it into your map.
//    3. For more thorough instructions on how to craft triggers using GTS, see its thread at
//       http://www.thehelper.net/forums/showthread.php?t=151051
//
//       Here are the basics, though:
//         a. Create arrays for whatever information you want to be able to retrieve when the
//            timer expires.
//         b. Create a trigger that you want to run when a timer expires.  In that trigger,
//            you&#039;ll be able to retrieve the relevant information from those arrays, using
//            GTS_GetIndex as the array index.  That number is matched to the expiring timer,
//            allowing it to be &quot;MUI&quot;, or multi-instanceable in general.
//         c. When you want to start a timer, save the information you want to be able to
//            recall into your arrays, using GTS_NewIndex as the array index.  GTS_NewIndex
//            is the index of the timer that is available to start.
//         d. Set GTS_StoreTrigger to the trigger you just created - the one you want to run
//            when the timer expires.
//         e. Start the &quot;countdown timer&quot; GTS_NewTimer with whatever settings you please.
//         f. Then, run the trigger GTS Store &lt;gen&gt;.
//         g. You will need to release the timer when you&#039;re done with it, or it will leak from
//            the system.  Typically, this is done at the end of the &quot;callback&quot; trigger.
//            Releasing a timer stops the timer and recycles it back into the system.
//            To release the expiring timer from a &quot;callback&quot; trigger, just run the trigger
//            GTS Release &lt;gen&gt;.  To release any other timer, at any time, set GTS_ReleaseTimer
//            to the timer you want to release, and run GTS Release &lt;gen&gt;.
//
// -- Notes --
//    GTS&#039;s GTS_GetIndex is not wait-safe; you can&#039;t use it after a wait in a trigger that&#039;s
//    run by GTS (but you&#039;re using a timer system, so why would you want to use waits anyway?)
//
//    Don&#039;t write any values to GTS_GetIndex, or it will mess up any other triggers run by GTS.
//
//    This system has two possible modes of operation: &quot;blue&quot; which uses hashtables and has
//    no limit on the number of timers that can be running at once, and &quot;orange&quot;, which uses
//    less computing power, but has a pre-defined limit on the number of timers.
//    To set which mode, change the function GTS_UseHashtable at the top of the code, below.
//    By default, it is set to &quot;orange&quot; mode.
//    To set the number of timers, change the function GTS_TimerAmount.
//    By default, it is set to 1000 timers.
//
// -- Credits --
//    Vexorian on wc3c.net for TimerUtils, which helped me learn about basic timer systems.
//
//    Credit in your map not needed, but please include this README.
//
// -- Version History --
//    1.0.4: First release.


//===================================================================
// Configurables.
function GTS_UseHashtable takes nothing returns boolean //If set to true, the system will use a hashtable to store data, which is slower but allows for unlimited timers.
    return false
endfunction

function GTS_TimerAmount takes nothing returns integer  //If not using hashtables, this value sets how many timers it will generate for use.
                                                    //No more than this number of timers will be able to be in use at the same time from this system.
    return 1000 //Must be no higher than 8190.
endfunction


//===================================================================
// This is just for reference.
// If you use JassHelper, you could uncomment this section instead of creating the variables in the trigger editor.

// globals
//  hashtable udg_GTS__Hashtable
//  integer array udg_GTS__Integers
//  timer array udg_GTS__TimerSpares
//  trigger array udg_GTS__TriggerList
//  boolean array udg_GTS__TimerStatus
//  timer udg_GTS_NewTimer
//  integer udg_GTS_NewIndex = 0
//  integer udg_GTS_GetIndex = 0
//  trigger udg_GTS_StoreTrigger
//  timer udg_GTS_ReleaseTimer
// endglobals

//===================================================================
// System code follows.  Don&#039;t touch!
//===================================================================
// &quot;Blue&quot; edition with hashtables, used if GTS_UseHashtable returns true.
function GTS_RunTriggerBlue takes nothing returns boolean
    local integer timerid = GetHandleId(GetExpiredTimer())

    set udg_GTS_GetIndex = LoadInteger(udg_GTS__Hashtable, 1, timerid)                      //Load the timer&#039;s index
    call ConditionalTriggerExecute(LoadTriggerHandle(udg_GTS__Hashtable, 0, timerid))       //Conditional, because it&#039;s meant for use with GUI

    return false
endfunction

function GTS_StoreActionsBlue takes nothing returns nothing
    local integer timerid = GetHandleId(udg_GTS_NewTimer)

    call SaveBoolean(udg_GTS__Hashtable, 2, timerid, true)                                  //Safety for the timer being in-use

    call SaveTriggerHandle(udg_GTS__Hashtable, 0, timerid, udg_GTS_StoreTrigger)                //Attach a trigger to the timer
    set udg_GTS_StoreTrigger = null

    if(udg_GTS__Integers[2] &gt; 0) then                                                       //If there are pre-generated timers available
        set udg_GTS_NewTimer = LoadTimerHandle(udg_GTS__Hashtable, 3, udg_GTS__Integers[2]) //...load it
        set timerid = GetHandleId(udg_GTS_NewTimer)
        set udg_GTS_NewIndex = LoadInteger(udg_GTS__Hashtable, 1, timerid)                  //Get its index
        set udg_GTS__Integers[2] = udg_GTS__Integers[2]-1                                   //Decrement the timer stack count
    else
        set udg_GTS_NewTimer = CreateTimer()                                                //Make a new timer
        set timerid = GetHandleId(udg_GTS_NewTimer)
        call TriggerRegisterTimerExpireEvent(gg_trg_GTS_Setup, udg_GTS_NewTimer)            //Add it to the system
        call SaveInteger(udg_GTS__Hashtable, 1, timerid, udg_GTS__Integers[0])              //Give it an index
        set udg_GTS_NewIndex = udg_GTS__Integers[0]                                         //...and make that the current index
        set udg_GTS__Integers[0] = udg_GTS__Integers[0]+1                                   //Increment the timer count
    endif
endfunction

function GTS_ReleaseTimerBlue takes timer t returns nothing
    local integer timerid = GetHandleId(t)

    if(LoadBoolean(udg_GTS__Hashtable, 2, timerid)) then                                    //Safety: only release a timer that has been started by GTS
        call PauseTimer(t)                                                                  //Stop the timer
        call RemoveSavedHandle(udg_GTS__Hashtable, 0, timerid)                              //Clear the attached trigger
        call SaveBoolean(udg_GTS__Hashtable, 2, timerid, false)                             //Save that the timer has been stopped
        set udg_GTS__Integers[2] = udg_GTS__Integers[2]+1                                   //Increment the timer stack count
        call SaveTimerHandle(udg_GTS__Hashtable, 3, udg_GTS__Integers[2], t)                //Add it to the stack
    endif
endfunction

function GTS_ReleaseActionsBlue takes nothing returns nothing
    if(udg_GTS_ReleaseTimer != null) then                                                   //Release udg_GTS_ReleaseTimer if a timer is specified
        call GTS_ReleaseTimerBlue(udg_GTS_ReleaseTimer)
        set udg_GTS_ReleaseTimer = null
    elseif(GetTriggerEventId() == EVENT_GAME_TIMER_EXPIRED) then                            //Otherwise, release the expiring timer if valid
        call GTS_ReleaseTimerBlue(GetExpiredTimer())                                        //No, don&#039;t release the Kraken.
    endif
endfunction

//===================================================================
// &quot;Orange&quot; edition with HandleId-Offset, used if GTS_UseHashtable returns false.
function GTS_RunTriggerOrange takes nothing returns boolean
    set udg_GTS_GetIndex = GetHandleId(GetExpiredTimer()) - udg_GTS__Integers[0]            //Load the timer&#039;s index
    call ConditionalTriggerExecute(udg_GTS__TriggerList[udg_GTS_GetIndex])                  //Conditional, because it&#039;s meant for use with GUI

    return false
endfunction

function GTS_StoreActionsOrange takes nothing returns nothing
    set udg_GTS__TimerStatus[udg_GTS_NewIndex] = true                                       //Safety for the timer being in-use

    set udg_GTS__TriggerList[udg_GTS_NewIndex] = udg_GTS_StoreTrigger                       //Attach a trigger to the timer
    set udg_GTS_StoreTrigger = null

    if(udg_GTS__Integers[2] &gt; 0) then                                                       //If there are pre-generated timers available
        set udg_GTS_NewTimer = udg_GTS__TimerSpares[0]                                      //...load it
        set udg_GTS_NewIndex = GetHandleId(udg_GTS_NewTimer) - udg_GTS__Integers[0]         //Get its index
        set udg_GTS__Integers[2] = udg_GTS__Integers[2]-1                                   //Decrement the timer stack count
        set udg_GTS__TimerSpares[0] = udg_GTS__TimerSpares[udg_GTS__Integers[2]]
//  else                                                                                    //If there are no available timers, fail.
//      call BJDebugMsg(&quot;GTS: Too many timers are in use!  Check for timer leaks, or increase the timer amount.&quot;)
    endif
endfunction

function GTS_ReleaseTimerOrange takes timer t returns nothing
    local integer timerindex = GetHandleId(t) - udg_GTS__Integers[0]

    if(udg_GTS__TimerStatus[timerindex]) then                                               //Safety: only release a timer that has been started by GTS
        call PauseTimer(t)                                                                  //Stop the timer
        set udg_GTS__TriggerList[timerindex] = null                                         //Clear the attached trigger
        set udg_GTS__TimerStatus[timerindex] = false                                        //Save that the timer has been stopped
        set udg_GTS__TimerSpares[udg_GTS__Integers[2]] = t                                  //Increment the timer stack count
        set udg_GTS__Integers[2] = udg_GTS__Integers[2]+1                                   //Add it to the stack
    endif
endfunction

function GTS_ReleaseActionsOrange takes nothing returns nothing
    if(udg_GTS_ReleaseTimer != null) then                                                   //Release udg_GTS_ReleaseTimer if a timer is specified
        call GTS_ReleaseTimerOrange(udg_GTS_ReleaseTimer)
        set udg_GTS_ReleaseTimer = null
    elseif(GetTriggerEventId() == EVENT_GAME_TIMER_EXPIRED) then                            //Otherwise, release the expiring timer if valid
        call GTS_ReleaseTimerOrange(GetExpiredTimer())
    endif
endfunction

function GTS_RegisterTimersOrange takes nothing returns nothing
    local integer i = IMinBJ(udg_GTS__Integers[2]+250, udg_GTS__Integers[1])                //Add up to 250 timers at a time, up to the intented timer count

    loop
        exitwhen udg_GTS__Integers[2] == i
        call TriggerRegisterTimerExpireEvent(gg_trg_GTS_Setup, udg_GTS__TimerSpares[udg_GTS__Integers[2]])
        set udg_GTS__Integers[2] = udg_GTS__Integers[2]+1
    endloop
endfunction

function GTS_CreateTimersOrange takes nothing returns nothing
    local integer i = IMinBJ(udg_GTS__Integers[2]+250, udg_GTS__Integers[1])                //Pre-generate up to 250 timers at a time, up to the intented timer count

    loop
        exitwhen udg_GTS__Integers[2] == i
        set udg_GTS__TimerSpares[udg_GTS__Integers[2]] = CreateTimer()
        set udg_GTS__Integers[2] = udg_GTS__Integers[2]+1
    endloop
endfunction

function GTS_PreloadTimersOrange takes nothing returns nothing                              //This pre-generates timers in a row, so their handle IDs will be sequential
    local trigger t = CreateTrigger()
    local triggeraction a = TriggerAddAction(t, function GTS_CreateTimersOrange)

    set udg_GTS_NewTimer = CreateTimer()
    set udg_GTS__Integers[0] = GetHandleId(udg_GTS_NewTimer)                                //Save the first timer&#039;s handle as the offset value

    loop
        exitwhen udg_GTS__Integers[2] &gt;= udg_GTS__Integers[1]
        call TriggerExecute(t)                                                              //Generate the timers using TriggerExecute to avoid the thread operation limit
    endloop

    call TriggerRemoveAction(t, a)
    set a = TriggerAddAction(t, function GTS_RegisterTimersOrange)
    set udg_GTS__Integers[2] = 0
    call TriggerRegisterTimerExpireEvent(gg_trg_GTS_Setup, udg_GTS_NewTimer)                //Add the first timer to the system

    loop
        exitwhen udg_GTS__Integers[2] &gt;= udg_GTS__Integers[1]
        call TriggerExecute(t)                                                              //Set up the rest of the timers using TriggerExecute
    endloop

    call TriggerRemoveAction(t, a)
    call DestroyTrigger(t)
    set t = null
    set a = null
endfunction

// ===========================================================================
function InitTrig_GTS_Setup takes nothing returns nothing
    set udg_GTS_ReleaseTimer = null

    if(GTS_UseHashtable()) then
        set udg_GTS__Hashtable = InitHashtable()

        set gg_trg_GTS_Setup = CreateTrigger()
        call TriggerAddCondition(gg_trg_GTS_Setup, Condition(function GTS_RunTriggerBlue))
        call TriggerRegisterTimerExpireEvent(gg_trg_GTS_Setup, udg_GTS_NewTimer)
        call SaveInteger(udg_GTS__Hashtable, 1, GetHandleId(udg_GTS_NewTimer), 0)
        set udg_GTS__Integers[0] = 1

        set gg_trg_GTS_Store = CreateTrigger()
        call TriggerAddAction(gg_trg_GTS_Store, function GTS_StoreActionsBlue)

        set gg_trg_GTS_Release = CreateTrigger()
        call TriggerAddAction(gg_trg_GTS_Release, function GTS_ReleaseActionsBlue)
    else
        set gg_trg_GTS_Setup = CreateTrigger()
        call TriggerAddCondition(gg_trg_GTS_Setup, Condition(function GTS_RunTriggerOrange))
        set udg_GTS__Integers[1] = GTS_TimerAmount()
        call GTS_PreloadTimersOrange()

        set gg_trg_GTS_Store = CreateTrigger()
        call TriggerAddAction(gg_trg_GTS_Store, function GTS_StoreActionsOrange)

        set gg_trg_GTS_Release = CreateTrigger()
        call TriggerAddAction(gg_trg_GTS_Release, function GTS_ReleaseActionsOrange)
    endif
endfunction

-- Notes --
GTS's GTS_GetIndex is not wait-safe; you can't use it after a wait in a trigger that's run by GTS (but you're using a timer system, so why would you want to use waits anyway?)

Don't write any values to GTS_GetIndex, or it will mess up any other triggers run by GTS.

It's not currently possible to get the index of any timer but the expiring timer. I might add this function later, but I haven't run into a situation where I needed or couldn't work around it.

This system has two possible modes of operation: "blue" which uses hashtables and has no limit on the number of timers that can be running at once, and "orange", which uses less computing power, but has a pre-defined limit on the number of timers.
To set which mode, change the function GTS_UseHashtable at the top of the code, below. By default, it is set to "orange" mode.
To set the number of timers, change the function GTS_TimerAmount. By default, it is set to 1000 timers.

-- Credits --
Vexorian on wc3c.net for TimerUtils, which helped me learn about basic timer systems.

Credit in your map not needed, but please include the README.

-- Version History --
1.0.4: First release.

--------------------------------------​

All comments welcome.
 

Attachments

  • GTS 1.0.4 Demo.w3x
    27.9 KB · Views: 421

tooltiperror

Super Moderator
Reaction score
231
[LJASS]GTS_UseHashtable[/LJASS] and [LJASS]GTS_TimerAmount[/LJASS] should be constant functions.

[LJASS]IMinBJ[/LJASS] can be replaced with a custom function to be faster, I think, because the else can be inlined to endif?

JASS:

// Will it make a difference?
 function IMin takes integer a, integer b returns integer
     if a &lt; b then
       return a
     endif
       return b
 endfunction


You should probably mention to GUI-Users that this could allow them to make arrays and save integers like their making their own structs.
 

Weep

Godspeed to the sound of the pounding
Reaction score
400
[LJASS]GTS_UseHashtable[/LJASS] and [LJASS]GTS_TimerAmount[/LJASS] should be constant functions.
I suppose so. Without JassHelper, it doesn't make any difference, though. I don't think I'll bother reuploading it until something else warrants an update.

[LJASS]IMinBJ[/LJASS] can be replaced with a custom function to be faster, I think, because the else can be inlined to endif?
It's run a handful of times at map init; in such cases, I prefer cleaner code.

You should probably mention to GUI-Users that this could allow them to make arrays and save integers like their making their own structs.
I did. :p
 

tooltiperror

Super Moderator
Reaction score
231
But why would it make it cleaner? It doesn't add a line to the working code.

Also, I'm far too lazy to read all of your documentation! But now I know I can make a blank trigger to set variables to be the 'creator', I never thought about that.

I should probably get started on that GUI-Friendly spell event system.

Edit: better.

JASS:
//Weep:
  ___ _   _ ___    ___    _             _ _        _____ _               
 / __| | | |_ _|__| __| _(_)___ _ _  __| | |_  _  |_   _(_)_ __  ___ _ _ 
| (_ | |_| || |___| _| &#039;_| / -_) &#039; \/ _` | | || |   | | | | &#039;  \/ -_) &#039;_|
 \___|\___/|___|  |_||_| |_\___|_||_\__,_|_|\_, |   |_| |_|_|_|_\___|_|  
                                            |__/                         
 ___         _             
/ __|_  _ __| |_ ___ _ __  
\__ \ || (_-&lt;  _/ -_) &#039;  \ 
|___/\_, /__/\__\___|_|_|_|
     |__/
 

polo2005

Wana start playing LoL? http://tinyurl.com/369as27
Reaction score
97
hmmm... whati f i change the timer to ongonig instand of one shot for looping purpose as making a unit slide?

or should i run the system again in the callback trigger?
 

Weep

Godspeed to the sound of the pounding
Reaction score
400
hmmm... whati f i change the timer to ongonig instand of one shot for looping purpose as making a unit slide?
That's fine, as long as you have some way of determining when the slide is over, and releasing the timer then.
 

PurgeandFire

zxcvmkgdfg
Reaction score
509
It looks awesome. :)

Is this better than the usual Dynamic Indexing? (well, I know the hash version isn't but what about the orange version?) Just out of curiosity. But very nice to GUIers regardless.
 

Weep

Godspeed to the sound of the pounding
Reaction score
400
Is this better than the usual Dynamic Indexing?
"Dynamic Indexing" ought to be better for frequent loops on many instances (eg. sliding projectiles). This system is better suited for longer periods that need precision (eg. matching an ability cooldown or a buff duration) or medium-length periods that ought to start exactly at a certain time (eg. an over-time effect that should happen every 0.25 seconds starting exactly at a spell cast).

For short periods for a few instances at a time, eg. for knockback, the difference in performance (if there even is any - I haven't tested) is probably negligible, and I'd say this is more convenient.
 

tooltiperror

Super Moderator
Reaction score
231
It would be nice if you created a sort of wrapper for JASSing Maccies, so we could just do [LJASS]call GTS_TImerStart(real timeout, boolean periodic, code callback)[/LJASS] instead of doing all the running timers and storing and all that jazz.
 

Weep

Godspeed to the sound of the pounding
Reaction score
400
Here you go.

JASS:
//GTS JASS Wrapper - v1.0.0 - by Weep
//Requires GUI-Friendly Timer System: http:// <a href="http://www.thehelper.net/forums/showthread.php?t=151051" class="link link--internal">www.thehelper.net/forums/showthread.php?t=151051</a>
//Paste into your map header to use.

//Call this AFTER saving all your data into arrays at index udg_GTS_NewIndex.
//This will save the timer being started as bj_lastStartedTimer, and will load a new timer as udg_GTS_NewTimer.
function GTS_TimerStart takes real timeout, boolean periodic, code handlerFunc returns nothing
	set bj_lastStartedTimer = udg_GTS_NewTimer
	call TimerStart(udg_GTS_NewTimer, timeout, periodic, handlerFunc)
	call TriggerExecute(gg_trg_GTS_Store)
endfunction

//Call this when done using a timer.  If you had saved the timer in a variable, you should null it so you don&#039;t accidentally release the timer again, later.
function GTS_ReleaseTimer takes timer t returns nothing
	set udg_GTS_ReleaseTimer = t
	call TriggerExecute(gg_trg_GTS_Release)
endfunction
JASS:
function Callback1 takes nothing returns nothing
    call DestroyEffect(AddSpecialEffectTarget(udg_ExampleString[udg_GTS_GetIndex], udg_ExampleUnit[udg_GTS_GetIndex], &quot;overhead&quot;))
endfunction

function Callback2 takes nothing returns nothing
    call GTS_ReleaseTimer(udg_ExampleTimers[udg_GTS_GetIndex])
    call GTS_ReleaseTimer(GetExpiredTimer())
endfunction

function TestEnum takes nothing returns nothing
    set udg_ExampleUnit[udg_GTS_NewIndex] = GetEnumUnit()
    if (GetRandomInt(0, 1) == 0) then
        set udg_ExampleString[udg_GTS_NewIndex] = &quot;Abilities\\Weapons\\Bolt\\BoltImpact.mdl&quot;
    else
        set udg_ExampleString[udg_GTS_NewIndex] = &quot;Abilities\\Spells\\Other\\Incinerate\\FireLordDeathExplode.mdl&quot;
    endif
    call GTS_TimerStart(0.5, true, function Callback1)
    set udg_ExampleTimers[udg_GTS_NewIndex] = bj_lastStartedTimer
    call GTS_TimerStart(3.00, false, function Callback2)
endfunction

function TestActions takes nothing returns nothing
    set bj_wantDestroyGroup = true
    call ForGroupBJ(GetUnitsInRectAll(GetPlayableMapRect()), function TestEnum)
endfunction

//===========================================================================
function InitTrig_TimerTest takes nothing returns nothing
    set gg_trg_TimerTest = CreateTrigger()
    call TriggerRegisterPlayerEventEndCinematic(gg_trg_TimerTest, Player(0))
    call TriggerAddAction(gg_trg_TimerTest, function TestActions)
endfunction
 
General chit-chat
Help Users
  • No one is chatting at the moment.

      The Helper Discord

      Staff online

      Members online

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top