• 🏆 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!

MUI Timers

Status
Not open for further replies.
Level 5
Joined
Mar 6, 2015
Messages
130
hello
Kinda Weird but still i`m using a Loop Trigger and a Counter to Ensure that I have a MUI timed Spell , i was wondering is there any way to make a MUI timer ,i`m afraid using them and i couldn`t find anything useful in tutorials
what method do you use for Defining a timer for every spell Instances?
and how can access the Cast Datas in other trigger when a timer expires?
 
Level 12
Joined
Jan 2, 2016
Messages
973
JASS:
function DelayedDeath takes nothing returns nothing
    local timer t = GetExpiredTimer()
    local unit u = LoadUnitHandle(udg_Table, GetHandleId(t), 'unit')
    call UnitApplyTimedLife(u, 'BTLF', 0.01)
    call DestroyEffect(AddSpecialEffect(EFFECT_2_STRING, GetUnitX(u), GetUnitY(u))
    call FlushChildHashtable(udg_Table, GetHandleId(t)) // or in this case you could use RemoveSavedHandle(udg_Table, GetHandleId(t), 'unit')
    call DestroyTimer(t)
    set t = null
endfunction

function DeathCaller takes nothing returns boolean
    local timer t = CreateTimer()
    call SaveUnitHandle(udg_Table, GetHandleId(t), 'unit', GetSpellTargetUnit())
    call TimerStart(t, 5.00, false, function DelayedDeath)
    call PauseUnit(GetSpellTargetUnit(), true)
    call DestroyEffect(AddSpecialEffectTarget(EFFECT_1_STRING, GetSpellTargetUnit(), "chest")
    set t = null
endfunction
Just an example :p
The basic points of what needs to be done to get it working are:
0) You need a hashtable.
1) Create 2 functions - initiation, and "action" function.
2) in the initiation function create a timer, and save all the variables you need for the actions function into a the hashtable, with key = the timer's id (you can simply make a struct with all the variables needed, and just save the struct)
3) load the variables in the action func, and do the thing you want.
4) don't forget to destroy (or recycle) the timer.

Here is one more-realistic trigger (from my map):
JASS:
function StormEffect takes nothing returns nothing
    local timer t = GetExpiredTimer()
    local integer id = GetHandleId(t)
    local integer max = LoadInteger(udg_Table, id, 'maxh')
    local integer already_ran = LoadInteger(udg_Table, id, 'used')
    local real x = LoadReal(udg_Table, id, 'tarx')
    local real y = LoadReal(udg_Table, id, 'tary')
    local unit d = LoadUnitHandle(udg_Table, id, 'dumy')
    local real radius = LoadReal(udg_Table, id, 'rang')
    local integer lvl = LoadInteger(udg_Table, id, 'levl')
    local group g = CreateGroup()
    local unit FoG
    call GroupEnumUnitsInRange(g,x,y,radius,null)
    loop
        set FoG = FirstOfGroup(g)
        exitwhen FoG == null
        if IsUnitEnemy(FoG, GetOwningPlayer(d)) and not IsUnitType(FoG, UNIT_TYPE_MAGIC_IMMUNE) and IsUnitAliveBJ(FoG) then
            call ChangeUnitSpeed2( FoG, 0.4, 1.5, false, 'A01A', false )
            call DestroyEffect(AddSpecialEffectTarget("Abilities\\Spells\\Other\\Monsoon\\MonsoonBoltTarget.mdl", FoG, "origin"))
            call UnitDamageTargetBJ( d , FoG, (40.00+(10.00*I2R(lvl))), ATTACK_TYPE_NORMAL, DAMAGE_TYPE_LIGHTNING )
        endif
        call GroupRemoveUnit(g, FoG)
    endloop
    call DestroyGroup(g)
    if already_ran == max then
        call RecTimer(t)
    else
        call SaveInteger(udg_Table, id, 'used', already_ran+1)
    endif
    set t = null
    set d = null
    set g = null
endfunction

function Trig_Call_Storm takes nothing returns nothing
    local unit c = GetTriggerUnit()
    local real x = GetSpellTargetX()
    local real y = GetSpellTargetY()
    local weathereffect rain
    local weathereffect wind

/////////////////////////////////////////////
    local timer t = GetFreeTimer()    
    local integer id = GetHandleId(t)
/////////////////////////////////////////////

    local unit d = CreateUnit(GetOwningPlayer(c),'h00C',x,y,0.00)
    local integer lvl = GetUnitAbilityLevel(c,'A019')
    local real spell_radius = 325.00+(25.00*I2R(lvl))
    local rect r = Rect(x-spell_radius, y-spell_radius, x+spell_radius, y+spell_radius)
    set rain = AddWeatherEffect( r , 'RAhr' )
    set wind = AddWeatherEffect( r , 'WNcw' )
    call EnableWeatherEffect( rain , true )
    call EnableWeatherEffect( wind , true )

/////////////////////////////////////////////////////////////
    call SaveInteger(udg_Table, id, 'maxh' , 6+lvl)  
    call SaveInteger(udg_Table, id, 'used' , 1)         
    call SaveReal(udg_Table, id, 'tarx' , x)              
    call SaveReal(udg_Table, id, 'tary' , y)           
    call SaveUnitHandle(udg_Table, id, 'dumy' , d) 
    call SaveReal(udg_Table, id, 'rang' , spell_radius)
    call SaveInteger(udg_Table, id, 'levl' , lvl)       
    call TimerStart( t, 1.10 - (lvl*0.1), true, function StormEffect)
    set t = null
////////////////////////////////////////////////////////////

    call TriggerSleepAction((1.10 - (lvl*0.10))*(7+lvl))
    call UnitApplyTimedLife(d, 'BTLF', 0.01)
    call EnableWeatherEffect( rain , false )
    call EnableWeatherEffect( wind , false )
    call RemoveWeatherEffect( rain )
    call RemoveWeatherEffect( wind )
    call RemoveRect(r)
    set d = null
    set r = null
endfunction

function Trig_Call_Storm_Conditions takes nothing returns boolean
    if GetSpellAbilityId() == 'A019' then
        return true
    endif
    return false
endfunction

//===========================================================================
function InitTrig_Call_Storm takes nothing returns nothing
    set gg_trg_Call_Storm = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( gg_trg_Call_Storm, EVENT_PLAYER_UNIT_SPELL_EFFECT )
    call TriggerAddCondition( gg_trg_Call_Storm, Condition( function Trig_Call_Storm_Conditions ) )
    call TriggerAddAction( gg_trg_Call_Storm, function Trig_Call_Storm )
endfunction
 
Last edited:
Level 5
Joined
Mar 6, 2015
Messages
130
In GUI, you should stick to your 0.03 interval trigger.
When you are using JASS or vJASS, I can recommend TimerUtils and structs.

With those, you can easily allocate unique instances and set their id to the timer.

is the 0.03 interval Efficient? even if I use this method for all of my Spells?
the Method works fine and its dynamically configurable every time that you want to stop the loop you can save counter as total duration into hashtable but is this really Efficient ? will the Game work smoothly with hundred of these spells?
 
Level 5
Joined
Mar 6, 2015
Messages
130
It also depends on what is done inside the callbacks.
But ensure that the timer does not run if there is no active instance and you will be fine, also with a lot of spells.
so it should be fine if you turn off the trigger while there is no stance ,isn`t it?


  • Nourish Loop
    • Events
      • Time - Every 0.03 seconds of game time
    • Conditions
    • Actions
      • Unit Group - Pick every unit in Nrsh_G and do (Actions)
        • Loop - Actions
          • Set Nrsh_Unit = (Load (Key Unit) of (Key (Picked unit)) in Hero_Hashtable)
          • Set Nrsh_T = (Load (Key T) of (Key (Picked unit)) from Hero_Hashtable)
          • Set Nrsh_T = (Nrsh_T + 0.03)
          • Set Nrsh_Duration = (Load (Key Duration) of (Key (Picked unit)) from Hero_Hashtable)
          • Set Nrsh_Heal = (Load (Key Heal) of (Key (Picked unit)) from Hero_Hashtable)
          • Hashtable - Save Nrsh_T as (Key T) of (Key (Picked unit)) in Hero_Hashtable
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • Nrsh_T Greater than or equal to Nrsh_Duration
            • Then - Actions
              • Set Nrsh_Effect = (Load (Key effect) of (Key (Picked unit)) in Hero_Hashtable)
              • Special Effect - Destroy Nrsh_Effect
              • Unit - Set life of Nrsh_Unit to ((Life of Nrsh_Unit) + Nrsh_Heal)
              • Floating Text - Create floating text that reads (String(Nrsh_Heal)) above Nrsh_Unit with Z offset 0.00, using font size 10.00, color (10.00%, 100.00%, 30.00%), and 80.00% transparency
              • Floating Text - Show (Last created floating text) for (All allies of (Owner of Nrsh_Unit))
              • Floating Text - Set the velocity of (Last created floating text) to 64.00 towards 90.00 degrees
              • Floating Text - Change (Last created floating text): Disable permanence
              • Floating Text - Change the lifespan of (Last created floating text) to 2.00 seconds
              • Hashtable - Clear all child hashtables of child (Key (Picked unit)) in Hero_Hashtable
              • Unit Group - Remove (Picked unit) from Nrsh_G
              • Unit - Remove (Picked unit) from the game
            • Else - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • (Number of units in Nrsh_G) Equal to 0
            • Then - Actions
              • Trigger - Turn off (This trigger)
            • Else - Actions
 
Level 24
Joined
Aug 1, 2013
Messages
4,657
In GUI, you cant really get top performing spells.
There is little you can do to make a proper handler function for a timer in GUI so a trigger that runs every 0.03 seconds is the best you can get.

If you want performance, you should learn JASS and how to use timers.
 
Status
Not open for further replies.
Top