• 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] How should I save the triggering unit from function to function?

Status
Not open for further replies.
Level 6
Joined
Mar 9, 2023
Messages
75
[SOLVED]

Hi! I dip my toes more in jass but I can't put all my thoughts into action. How can I save the triggering unit across all functions of the trigger? Hashtable? Save as a global? Take UnitId? What and how? It's triggered by an item (event is elsewhere). Local for the functions triggered by the timers obviously don't work.

JASS:
function Trig_Heartmender_Actions takes nothing returns nothing
    local unit u = GetTriggerUnit()
    call SetUnitLifePercentBJ( u, 30.00 )
    call AddSpecialEffectTargetUnitBJ( "origin", u, "Holy Light.mdx" )
    call SetUnitInvulnerable( u, true )
    call UnitAddAbility(u,'A09C')
    call UnitMakeAbilityPermanent(u, true, 'A09C')
set u = null
endfunction

function Invu takes nothing returns nothing ///It cant find trigger unit
    local unit u = GetTriggerUnit()
    call SetUnitInvulnerable(u, false )
    set u = null
endfunction

function CooldownOver takes nothing returns nothing ///It cant find trigger unit
    local unit u = GetTriggerUnit()
    call UnitMakeAbilityPermanent(u, false, 'A09C')
    call UnitRemoveAbility(u,'A09C')
    set u = null
endfunction

function Heartmender_Timer takes nothing returns nothing
    local timer a = CreateTimer()
    local timer b = CreateTimer()
    call TimerStart(a, 2.00, false, function Invu)
    call TimerStart(b, 180.00, false, function CooldownOver)
    set a = null
    set b = null
endfunction

//===========================================================================
function InitTrig_Heartmender takes nothing returns nothing
    set gg_trg_Heartmender = CreateTrigger(  )
    call TriggerAddAction( gg_trg_Heartmender, function Trig_Heartmender_Actions )
    call TriggerAddAction( gg_trg_Heartmender, function Heartmender_Timer )
endfunction

Edit: it's for an item in a hero-map, so each hero is able to buy this item. Each hero is saved in a unit array.
 
Last edited:

Uncle

Warcraft Moderator
Level 73
Joined
Aug 10, 2018
Messages
7,866
You need to link the Timers and the Unit together using a Hashtable:
vJASS:
local timer t = CreateTimer()
local unit u = GetTriggerUnit()
call SaveUnitHandle( MyHashtable, GetHandleId(t), 0, GetHandleId(u) )
Now when that Timer expires you can use the GetExpiredTimer() function to retrieve it and then use it to Load the Unit handle that you saved previously:
vJASS:
local timer t = GetExpiredTimer()
local unit u = LoadUnitHandle( MyHashtable, GetHandleId(t), 0 )
// You now have access to the unit again

There's a library called TimerUtils which makes this process easier.

Or make the switch to Lua and not have to deal with this crappy programming language :p
 
Level 6
Joined
Mar 9, 2023
Messages
75
You need to link the Timers and the Unit together using a Hashtable:
vJASS:
local timer t = CreateTimer()
local unit u = GetTriggerUnit()
call SaveUnitHandle( MyHashtable, GetHandleId(t), 0, GetHandleId(u) )
Now when that Timer expires you can use the GetExpiredTimer() function to retrieve it and then use it to Load the Unit handle that you saved previously:
vJASS:
local timer t = GetExpiredTimer()
local unit u = LoadUnitHandle( MyHashtable, GetHandleId(t), 0 )
// You now have access to the unit again

There's a library called TimerUtils which makes this process easier.

Or make the switch to Lua and not have to deal with this crappy programming language :p
Is it a good time mentioning I'm a complete rookie at hashtables? Are there a just a few lines I need to make it work, or are you gonna send me to school? 😵
 

Uncle

Warcraft Moderator
Level 73
Joined
Aug 10, 2018
Messages
7,866
I'd recommend learning and using Lua over Jass, especially if you're starting out fresh and your map isn't too far along. It's objectively better.

Anyway, a Hashtable is basically a more powerful Array, so if you understand those then it's not that difficult to learn.

You Save/Load data from it using the Save/Load functions like in my example. Here it is applied to your code:
vJASS:
globals
    HeartmenderHash = InitHashtable()
endglobals

function Heartmender_Actions takes nothing returns nothing
    local unit u = GetTriggerUnit()
    local timer a = CreateTimer()
    local timer b = CreateTimer()
    // Link the Unit to the Timers so that when you Get the Timer you can also Get the Unit
    call SaveUnitHandle( HeartmenderHash, GetHandleId(a), 0, GetHandleId(u) )
    call SaveUnitHandle( HeartmenderHash, GetHandleId(b), 0, GetHandleId(u) )
    call SetUnitLifePercentBJ( u, 30.00 )
    call AddSpecialEffectTargetUnitBJ( "origin", u, "Holy Light.mdx" )
    call SetUnitInvulnerable( u, true )
    call UnitAddAbility(u,'A09C')
    call UnitMakeAbilityPermanent(u, true, 'A09C')
    call TimerStart(a, 2.00, false, function Heartmender_Invu)
    call TimerStart(b, 180.00, false, function Heartmender_CooldownOver)
    set u = null
    set a = null
    set b = null
endfunction

function Heartmender_Invu takes nothing returns nothing
    local timer t = GetExpiredTimer()
    local unit u = LoadUnitHandle( HeartmenderHash, GetHandleId(t), 0 )
    call SetUnitInvulnerable(u, false)
    call DestroyTimer(t)
    set u = null
    set t = null
endfunction

function Heartmender_CooldownOver takes nothing returns nothing
    local timer t = GetExpiredTimer()
    local unit u = LoadUnitHandle( HeartmenderHash, GetHandleId(t), 0 )
    call UnitMakeAbilityPermanent(u, false, 'A09C')
    call UnitRemoveAbility(u,'A09C')
    call DestroyTimer(t)
    set u = null
    set t = null
endfunction

//===========================================================================
function InitTrig_Heartmender takes nothing returns nothing
    set gg_trg_Heartmender = CreateTrigger(  )
    call TriggerAddAction( gg_trg_Heartmender, function Heartmender_Actions )
endfunction
Linking data together using the Hashtable is useful since you're often limited in the Event Responses that you have available. When a Timer expires all you can really do is call GetExpiredTimer(), which gets you the Timer. This isn't that useful since we want the Unit and maybe some other data, but we can make it useful by Saving the Unit and the other data to the Timer itself inside of the Hashtable beforehand.

This linking of data is very powerful and is a common theme among programming. Take for instance the fact that all Units are linked to the Player that owns them which is handled using the GetOwningPlayer() function. Blizzard set this up so that when you have a Unit you will also have it's Owner. These are two different objects (Unit and Player) but they're linked together to form a relationship where the Unit can get you the Player. You can then use Hashtables and other methods to link Units to the Player so you can reverse the relationship (Get a Unit from a Player rather than a Player from a Unit). It's this Getting and Setting of data that once mastered will give you a lot of control over what can happen in your map.

Here's a GUI Array example that may help explain what the Hashtable is doing:
  • Set Variable MyTimer = (Last created timer)
  • Set Variable HeartmenderHash[MyTimer] = (Triggering unit)
If we plug that Timer into HeartmenderHash we will get the (Triggering unit) that we stored in it.

Also, note that I'm not cleaning up the memory leaks associated with Hashtable data. You can look into that once you're more comfortable with getting it working.
 
Last edited:
Status
Not open for further replies.
Top