• 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.

[JASS] Trigger help (timer carry-through)

Status
Not open for further replies.
Level 5
Joined
Sep 19, 2006
Messages
152
I've gotten a great deal of outdated or even conflicting information regarding timers. To date I've been using the PolledWait function, but am trying to correct my work-in-progress to the timer function instead. Even my JassCraft program allows commands that the World Editor refuses to recognize.

Basically, I'm looking for a working example of a way to carry either the triggering unit (or even just the player number of the triggering unit) from the base trigger to the function activated by the expiring trigger. I've been flooded with links to various tutorials; I really think I could learn the most effectively from an actual example of what the working trigger should look like. In other words, I'd like someone to write in the few lines needed to transfer the pertinent information from Action01 of the trigger to Action02. Thanks!

JASS:
function SorceressAbilities_Action02 takes nothing returns nothing
    local timer T                = GetExpiredTimer ()
    local unit caster  //  <---- this is the unit I need to define
//
    if GetUnitAbilityLevel (caster, 'BEfn') == 0 then
        call DestroyTimer (T)
        call SetUnitAbilityLevel (caster, 'A08C', 1)
    endif    
    set T = null
endfunction

function SorceressAbilities_Action01 takes nothing returns nothing
    local integer abil           = GetSpellAbilityId ()
    local unit caster
    local timer T
//
    if abil == 'A08D' or abil == 'A0A3' then
        set caster = GetSpellAbilityUnit ()
    else
        return
    endif
    call SetUnitAbilityLevel (caster, 'A08C', 2)
    set T = CreateTimer ()
    call TimerStart (T, 0.50, true, function SorceressAbilities_Action02)
    set T = null
    set caster = null
endfunction

function InitTrig_SorceressAbilities takes nothing returns nothing
    set gg_trg_SorceressAbilities = CreateTrigger ()
    call TriggerRegisterPlayerUnitEvent (gg_trg_SorceressAbilities, Player (1), EVENT_PLAYER_UNIT_SPELL_FINISH, null)
    call TriggerRegisterPlayerUnitEvent (gg_trg_SorceressAbilities, Player (2), EVENT_PLAYER_UNIT_SPELL_FINISH, null)
    call TriggerRegisterPlayerUnitEvent (gg_trg_SorceressAbilities, Player (3), EVENT_PLAYER_UNIT_SPELL_FINISH, null)
    call TriggerAddAction (gg_trg_SorceressAbilities, function SorceressAbilities_Action01)
endfunction
 
The easiest way is with a hashtable.

This post might help:
http://www.hiveworkshop.com/forums/1597351-post5.html

First, make a hashtable named "udg_SorceressHash", or whatever you want. It doesn't matter. I'm just using udg_SorceressHash in my example.

So first, you must create the hashtable. So in your init function:
JASS:
function InitTrig_SorceressAbilities takes nothing returns nothing
    set gg_trg_SorceressAbilities = CreateTrigger ()
    set udg_SorceressHash = InitHashtable()
    call TriggerRegisterPlayerUnitEvent (gg_trg_SorceressAbilities, Player (1), EVENT_PLAYER_UNIT_SPELL_FINISH, null)
    call TriggerRegisterPlayerUnitEvent (gg_trg_SorceressAbilities, Player (2), EVENT_PLAYER_UNIT_SPELL_FINISH, null)
    call TriggerRegisterPlayerUnitEvent (gg_trg_SorceressAbilities, Player (3), EVENT_PLAYER_UNIT_SPELL_FINISH, null)
    call TriggerAddAction (gg_trg_SorceressAbilities, function SorceressAbilities_Action01)
endfunction

Now you must attach data:
JASS:
function SorceressAbilities_Action01 takes nothing returns nothing
    local integer abil           = GetSpellAbilityId ()
    local unit caster
    local timer T
//
    if abil == 'A08D' or abil == 'A0A3' then
        set caster = GetSpellAbilityUnit ()
    else
        return
    endif
    call SetUnitAbilityLevel (caster, 'A08C', 2)
    set T = CreateTimer ()
    call SaveUnitHandle(udg_SorceressHash,GetHandleId(T),0,caster)
    //Store the caster under "0" of the handle ID of the timer. 
    call TimerStart (T, 0.50, true, function SorceressAbilities_Action02)
    set T = null
    set caster = null
endfunction

Then you load it:
JASS:
function SorceressAbilities_Action02 takes nothing returns nothing
    local timer T                = GetExpiredTimer ()
    local unit caster           = LoadUnitHandle(udg_SorceressHash,GetHandleId(T),0)
 //load the info

    if GetUnitAbilityLevel (caster, 'BEfn') == 0 then
        call PauseTimer(T) //pause the timer first before destroying it
        call DestroyTimer (T)
        call SetUnitAbilityLevel (caster, 'A08C', 1)
        call FlushChildHashtable(udg_SorceressHash,GetHandleId(T))
        //clear the data under the id of the timer
    endif    
    set T = null
    set caster = null
endfunction
 
Last edited:
Level 5
Joined
Sep 19, 2006
Messages
152
Thank you for your very thorough response, PurgeandFire111: your simple example was much more beneficial to me than were any of the tutorials I checked out.

I did have a few questions regarding your sample trigger, however.

First, in the SorceressAbilities_Action02 function, it is unnecessary to null the caster?

Second, can integers be saved in the same "slot" as was allocated to a unit, or must it be saved to another? For example:
set n = GetHandleId (T)
call SaveUnitHandle (udg_SorceressHash, n, 0, caster)
call SaveIntegerHandle (udg_SorceressHash, n, 0, 5)
...or must the previous line read (udg_SorceressHash, n, 1, 5)?

Last, is it necessary to put the line set udg_SorceressHash = InitHashtable() in the trigger initialization, or can it be used in an if/then command such as
if x == 1 then
set udg_SorceressHash = InitHashtable()
else
set x = x - 1
endif
 
First, in the SorceressAbilities_Action02 function, it is unnecessary to null the caster?

My bad. Fixed.

Second, can integers be saved in the same "slot" as was allocated to a unit, or must it be saved to another? For example:
set n = GetHandleId (T)
call SaveUnitHandle (udg_SorceressHash, n, 0, caster)
call SaveIntegerHandle (udg_SorceressHash, n, 0, 5)
...or must the previous line read (udg_SorceressHash, n, 1, 5)?

The latter (second one). You must save it to a different one:
call SaveInteger(udg_SorceressHash, n, 1, 5)

Last, is it necessary to put the line set udg_SorceressHash = InitHashtable() in the trigger initialization, or can it be used in an if/then command such as
if x == 1 then
set udg_SorceressHash = InitHashtable()
else
set x = x - 1
endif

No, it isn't necessary. However, you only need to create the hash once, so it is fine to put it in the initialization. That way, you are sure that it has been created already. ;) [In fact, it'd be better to use only one hash the entire game (to avoid the 256 hashtable limit, and to save handles), don't worry about overwriting. As long as you save into different parentKeys {and flush when finished using it}, it will work fine.]
 
Level 5
Joined
Sep 19, 2006
Messages
152
Hmmm. The reply I wrote last night didn't post....

Anyway, I had a few more (and final) questions regarding your responses.

First, as you wrote in your last post, do most people use a "master hashtable" (something like udg_MasterHashtable) for use throughout all triggers used in their maps?

Last, can an integer be written over another integer, or must the entire "pool" be flushed before new integers are added? For instance:

call SaveIntegerHandle (udg_MasterHash, n, 0, 5)
call SaveIntegerHandle (udg_MasterHash, n, 0, 8) <---will this overwrite the "5" from the previous line?

Thanks again for all your easy-to-understand help, PurgeandFire111. I promise -- no more questions! ;)
 
No problem, feel free to ask any questions. That is what this forum is for. :)

First, as you wrote in your last post, do most people use a "master hashtable" (something like udg_MasterHashtable) for use throughout all triggers used in their maps?

It is generally advised to do so, as that is the most efficient way. However, it isn't terrible to use more than one. Usually, you won't really run into the 256 hashtable limit anyway.

Last, can an integer be written over another integer, or must the entire "pool" be flushed before new integers are added? For instance:

call SaveIntegerHandle (udg_MasterHash, n, 0, 5)
call SaveIntegerHandle (udg_MasterHash, n, 0, 8) <---will this overwrite the "5" from the previous line?

It will simply replace it. No need to flush it first as far as I know. =) Only flush it once you know you aren't going to store anything under "n" again. (or if you know you aren't going to store under the same childKey under a certain parentKey, then you can just remove it using RemoveSavedHandle() or RemoveSavedInteger/Real/Boolean/String().)
 
Status
Not open for further replies.
Top