• Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
  • Read Evilhog's interview with Gregory Alper, the original composer of the music for WarCraft: Orcs & Humans 🔗Click here to read the full interview.

How to avoid waiting

Status
Not open for further replies.
Level 14
Joined
May 22, 2010
Messages
362
I understand that using wait is buggy and inefficient, and read that timers are much better, but I did not find how to use them.
So how can I avoid using the wait function in the following trigger.

  • Trig2
    • Events
      • Unit - A unit Finishes casting an ability
    • Conditions
    • Actions
      • Custom script: local unit VV = GetTriggerUnit()
      • Wait 8.00 seconds
      • Custom script: call SetUnitManaPercentBJ( VV, 100 )
      • Custom script: set VV = null
 
Level 14
Joined
May 22, 2010
Messages
362
So from what I understand I have to create a trigger with two functions one(the one that starts the timer) that is executed when the event occurs and a second that is executed by when the timer runs out.
JASS:
function fnca takes nothing returns nothing
    call SetUnitManaPercentBJ( VV, 100 )
    set VV = null
endfunction

function fnc takes nothing returns nothing
local unit VV = GetTriggerUnit()
    call TimerStart(CreateTimer(), 5, false, function fnca)
endfunction

//===========================================================================
function InitTrig_Fnk takes nothing returns nothing
    set gg_trg_Fnk = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( gg_trg_Fnk, EVENT_PLAYER_UNIT_SPELL_FINISH )
    call TriggerAddAction( gg_trg_Fnk, function fnc )
endfunction
Why doesnt it work?
 
Last edited:
Level 33
Joined
Mar 27, 2008
Messages
8,035
If you're using GUI, you can use either Indexing / Hashtable to replace Waits.
The usage of Wait in your trigger post #1, is just fine as it is because the Wait is not so complex.

As said by Mag, if you're using vJASS, you should use Timers, but if you're using GUI, just resort to Hashtable / Indexing, it should be efficient enough.
 
Level 33
Joined
Mar 27, 2008
Messages
8,035
I tested the wait and it is not fine as it does not wait 8 seconds it waits some random amount of time of about 6 seconds.
What method did you used to count the seconds ?

This is how to test the effectiveness of Waits;
  • Wait Test Local Variable
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
    • Actions
      • Custom script: local unit u = GetTriggerUnit()
      • Custom script: local unit dummy = CreateUnit(Player (0), 'hfoo', GetUnitX(u), GetUnitY(u), 0.00)
      • Custom script: call UnitApplyTimedLife(dummy, 'BTLF', 8.00)
      • Custom script: call TriggerSleepAction(8.00)
      • Custom script: call KillUnit(u)
      • Custom script: call KillUnit(dummy)
      • Custom script: set u = null
      • Custom script: set dummy = null
If the Footman dies at the same time as the Caster (u), the Wait has successfully wait for 8 seconds.
 
Level 23
Joined
Apr 16, 2012
Messages
4,041
So from what I understand I have to create a trigger with two functions one(the one that starts the timer) that is executed when the event occurs and a second that is executed by when the timer runs out.
JASS:
function fnca takes nothing returns nothing
    call SetUnitManaPercentBJ( VV, 100 )
    set VV = null
endfunction

function fnc takes nothing returns nothing
local unit VV = GetTriggerUnit()
    call TimerStart(CreateTimer(), 5, false, function fnca)
endfunction

//===========================================================================
function InitTrig_Fnk takes nothing returns nothing
    set gg_trg_Fnk = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( gg_trg_Fnk, EVENT_PLAYER_UNIT_SPELL_FINISH )
    call TriggerAddAction( gg_trg_Fnk, function fnc )
endfunction
Why doesnt it work?

the reason why it doesnt work is because VV is local, it can only be used within function fnc and if you try to use it outside of function fnc it will return null.
You have to do something like this
JASS:
function B takes nothing returns nothing
    local timer t = GetExpiredTimer()
    local unit u = LoadUnitHandle(some global hashtable, GetHandleId(t), 1)
    call FlushChildHashtable(which hashtable, GetHandleId(t))
    call SetUnitManaPercentBJ(u, 100)
    call DestroyTimer(t)
    set t = null
    set u = null
endfunction

function A takes nothing returns nothing
    local unit u = GetTriggerUnit()
    local timer t = CreateTimer()
    call SaveUnitHandle(which hashtable, GetHandleId(t), 1, u)
    call TimerStart(t, 8., false, function B)
    set t = null
    set u = null
endfunction
If there are grammar errors sorry writing from mobile

so you have to save the unit to hashtable and start timer and in the another function you have to load the unit from hashtable.
This above is Mui and Leakless(I believe :D)
 
Level 14
Joined
May 22, 2010
Messages
362
re to defskull
1.I created a trigger that waits 1 second than adds 1 to a variable(it has a default value of 1) and than runs itself again.
2.I created a peasant that has 1hp regen.
3.I created a trigger that on map initialization sets the peasant's hp to 1 and runs the trigger above.
4.I created a trigger that when I press the left arrow key it displays the current value of the variable and the peasant's hp.
If wait was accurate the values displayed should mach, but they dont when the peasant's hp gets to 9(that is to say 8 seconds have elapsed) the variable's value is at about 7. With time the inaccuracy grows even greater.

re to edo949
I wanted to use local variables so that I can avoid using hashtables, since I dont understand how to use them and it seems to be pretty complicated.
 
Level 23
Joined
Apr 16, 2012
Messages
4,041
Its 494 not 949 :D
Its not that complicated but the local means you can only work with it in function in which it is declared
for instance:
JASS:
function B takes nothing returns nothing
    call BJDebugMsg(GetUnitName(u))
endfunction

function A takes nothing return nothing
    local unit u = GetTriggerUnit()
    local timer t = CreateTimer(ň
    call TimerStart(t, 1., false(if periodic), function B)
endfunction
this will most likely pop up error - undefined variable u in function B.
Its because local unit u from function A is only declared for function A.
You can only have unit u in function A and f. B if it is global.
The defskulls method is better then yours.

I have tested
JASS:
function Trig_Untitled_Trigger_001_Actions takes nothing returns nothing
	local unit u = gg_unit_hpea_0000
    call BJDebugMsg("start")
	call UnitApplyTimedLife(u, 'BTLF', 8.)
	call TriggerSleepAction(8.)
	call BJDebugMsg("8 seconds passed")
	set u = null
endfunction

//===========================================================================
function InitTrig_Untitled_Trigger_001 takes nothing returns nothing
    set gg_trg_Untitled_Trigger_001 = CreateTrigger(  )
    call TriggerAddAction( gg_trg_Untitled_Trigger_001, function Trig_Untitled_Trigger_001_Actions )
endfunction
and it is quite accurate actually. The 8 seconds passed is right when the units expiration timer ends(the unit dies.) so you should be fine with the wait(TriggerSleepAction).
 
Level 33
Joined
Mar 27, 2008
Messages
8,035
Local variable value only works within their functions only, you cannot jump from Trigger A to Trigger B by referring to the same local variable, it won't work.
That way, you're gonna need a Global Variable, this when Hashtable or Indexing comes in handy as they allow you to process data globally, sharing data between triggers, enabling you to perform a trigger that is saved over time, or simply a periodic timer.

It's not that hard using a Hashtable, reading tutorials maybe hard, but you gotta do the tutorials by actually doing it, not just read.

That way, you will feel the experience and will improve over time.
 
If the timer period is constant, use a buffer.

JASS:
// You need a unit array, and 2 integers:
// unitBuffer -> unit array
// unitBufferR -> integer
// unitBufferW -> integer

function B takes nothing returns nothing
    set udg_unitBufferR = udg_unitBufferR + 1
    call SetUnitManaPercentBJ(udg_unitBuffer[udg_unitBufferR], 100)

    // Check if we can empty the buffer
    if udg_unitBufferW == udg_unitBufferR then
        set udg_unitBufferW = 0
        set udg_unitBufferR = 0
        // You should never actually do this though
        // It's better to use resources like TimerUtils 
        // so you could recycle the timers instead.
        // Destroying timers can sometimes cause
        // handle stack corruptions.
        call DestroyTimer(GetExpiredTimer())
    endif
endfunction

function A takes nothing returns nothing
    set udg_unitBufferW = udg_unitBufferW + 1
    set udg_unitBuffer[udg_unitBufferW] = GetTriggerUnit()
    
    if udg_unitBufferW == 1 then
        call TimerStart(CreateTimer(), 8, false, function B)
    endif
endfunction

function InitTrig_Spell takes nothing returns nothing
    local trigger t = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
    call TriggerAddAction(t, function A) // It would be much better to add a condition and just return false at the end though.
    set t = null
endfunction
 
Status
Not open for further replies.
Top