• 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.
  • It's time for the first HD Modeling Contest of 2025. Join the theme discussion for Hive's HD Modeling Contest #7! Click here to post your idea!

[JASS] Indexing

Status
Not open for further replies.

Oli

Oli

Level 3
Joined
Aug 9, 2015
Messages
31
Hello,
The problem comes from my lack of knowledge regarding working with indexing, that is specifically, how to get a unit's index within an array(unit array) after setting it and clenase it, or if it is even necessary, as for my way of thinking, it is, because there is no other way to get a reference to it (in this particular situation)?

I want to create a script which would include these steps:
1. A unit is spawned from a dummy spell, it is set in an array
2. In another function(which triggers after a specific timer expires) the unit is removed.
JASS:
function explosion takes nothing returns nothing
[S]    local unit rocket = LoadUnitHandle(Rockets, p, 1)[/S]
    local timer RocketTimer = GetExpiredTimer()
    call UnitDamagePointLoc(rocket, 0, 100, GetUnitLoc(rocket), 20, ATTACK_TYPE_PIERCE,WEAPON_TYPE_AXE_MEDIUM_CHOP)
    call CreateUnitAtLoc(GetOwningPlayer(rocket), 'hpea', GetUnitLoc(rocket), 270)
    call RemoveUnit(rocket)
///Variable cleansing
[S]    call FlushChildHandle(Rockets, GetHandleId(rocket))[/S]
    call PauseTimer(RocketTimer)
    call DestroyTimer(RocketTimer)
    set RocketTimer = null
    set rocket = null
endfunction

Events
A unit Begins channeling an ability

Conditions
Ability Being Cast Equal to Dommy

    local unit rocket = CreateUnitAtLoc(GetOwningPlayer(GetTriggerUnit()), 'hpea', OffsetLocation(GetUnitLoc(GetTriggerUnit()), 500.00, 0), GetUnitFacing(GetTriggerUnit()))
    local timer RocketTimer = CreateTimer()
    call TimerStart(RocketTimer, 1.5, false, function explosion)
    call IssuePointOrderLoc(rocket, "move", PolarProjectionBJ(GetUnitLoc(rocket), 100.00, GetUnitFacing(rocket)))
    call SetUnitFlyHeight(rocket, GetUnitFlyHeight(GetTriggerUnit()), 0)
    call SetUnitFlyHeight(rocket, 0 , 1.5 / GetUnitFlyHeight(rocket))
    [S]set Rockets[i] = rocket[/S]

The question is simple and perhaps be stupid, but for the weak scripter i am, this problem is truly a challange for me to solve, because the index is set during the game, not pre-emptively(since the start).
  • There are other errors but these are suprisingly fixable for me.
 
Last edited:

Chaosy

Tutorial Reviewer
Level 40
Joined
Jun 9, 2011
Messages
13,220
I suggest you use TimerUtils, it abuses a timer bug which allows you to attach data to a timer.
A unit indexer might also be required, I do not remember if a handle id is too big for a standard integer.

So all you'd do is:
CreateTimer
StartTimer
AttachDataToTimer(unitqueId)

and in the function callback for the timer:
id = getAttachedDataofTimer(getExpiredTimer())
do stuff with the unit
destroy expired timer

As a bit of Wurst propaganda, you could use an anonymous function as timer callback.
 

Uncle

Warcraft Moderator
Level 71
Joined
Aug 10, 2018
Messages
7,537
To add onto what Chaosy said.

There's no reason to use a Unit array here. Understand that in a Callback function like explosion you only have access to a single thing, the timer that expired. Luckily, that's all you really need since you can use that along with a Hashtable to track all of your data for you. You do this by using the timer as the Parent key and the saved data as the Children keys in your Hashtable.

For example, when you cast the ability you create the rocket unit and the timer and then save the rocket unit to the timer in your hashtable:
vJASS:
function cast takes nothing returns nothing
    local unit u = CreateUnit()
    local timer t = CreateTimer()
    call SaveUnitHandle(rocketHash, GetHandleId(t), 0, GetHandleId(u))
    call TimerStart(t, 1.5, false, function explosion)
    // clean up
    set t = null
    set u = null
endfunction

Now when the timer expires you can get access to the rocket unit by loading it from the hashtable:
vJASS:
function explosion takes nothing returns nothing
    local timer t = GetExpiredTimer()
    local unit u = LoadUnitHandle(rocketHash, GetHandleId(t), 0)
    // do stuff referencing the loaded rocket unit
    // then clean up
    call FlushChildHashtable(rocketHash, GetHandleId(t))
    call PauseTimer(t)
    call DestroyTimer(t)
    set t = null
    set u = null
endfunction

It's that simple. TimerUtils, which Chaosy mentioned, is meant to make this process even easier for you.

Hashtables aside, when people hear Unit Indexing they think of this: GUI Unit Indexer 1.4.0.0
This is a system that takes advantage of Custom value (called User data in Jass) to assign each unit a unique integer id. You can then use this Custom value as the [Index] in your Arrays to assign data to units on an individual basis. It's like a lightweight version of a Hashtable, it offers less flexibility but it's easier to work with and could possibly help solve some other issues.

An example of tracking AbilityPower, a custom stat for each unit, using Unit Indexing:
  • Unit - Create 1 unit...
  • Set Variable CV = Custom value of (Last created unit)
  • Set Variable AbilityPower[CV] = 100
  • Unit - Create 1 unit...
  • Set Variable CV = Custom value of (Last created unit)
  • Set Variable AbilityPower[CV] = 200
The first unit will have 100 AbilityPower and the second unit will have 200 AbilityPower. This is because each unit was assigned a unique Custom Value (CV) upon creation by the Unit Indexer system. So both units are using their own [Index] in the AbilityPower array.

In Jass you would do it like this:
vJASS:
// 1st unit
local unit u = CreateUnit()
local integer cv = GetUnitUserData(u)
set udg_AbilityPower[cv] = 100
// 2nd unit
set u = CreateUnit()
set cv = GetUnitUserData(u)
set udg_AbilityPower[cv] = 200
 
Last edited:
Status
Not open for further replies.
Top