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

hashtables (for jass)

Status
Not open for further replies.
Level 6
Joined
Sep 9, 2006
Messages
92
If i'm setting up a spell that has to use hashtables and timers, first, am i able to link the hashtables to a specific timer like how LHV was set up to do? or should i just run an index like i would in gui, a different number per instance?
and second, am i able to use an init function which starts a timer loop function, for, in my case, lifting a unit up into the air, then have that function start another timer loop function (after x height) which throws the unit? (im sure i am, but an example wouldnt hurt because currently mine isnt quite working; however i need to fix it up a bit so i won't post the code at this time)
 
If i'm setting up a spell that has to use hashtables and timers, first, am i able to link the hashtables to a specific timer like how LHV was set up to do? or should i just run an index like i would in gui, a different number per instance?
and second, am i able to use an init function which starts a timer loop function, for, in my case, lifting a unit up into the air, then have that function start another timer loop function (after x height) which throws the unit? (im sure i am, but an example wouldnt hurt because currently mine isnt quite working; however i need to fix it up a bit so i won't post the code at this time)

if you can use JASS hashtables then maybe it would be easy for you to use structs instead...

the first question... if you mean attach 1 hashtable to 1 timer, I don't think so..

the second question.. yes.
 
Level 6
Joined
Sep 9, 2006
Messages
92
if you can use JASS hashtables then maybe it would be easy for you to use structs instead...

the first question... if you mean attach 1 hashtable to 1 timer, I don't think so..

the second question.. yes.

ive looked at a tutorial for structs and read a little bit but i have no idea what it actually is, but thanks ill run an index; also, are structs faster than hash? or why use structs vs hashtables?
 
Level 6
Joined
Sep 9, 2006
Messages
92
ive looked at a tutorial for structs and read a little bit but i have no idea what it actually is

found a tutorial, but its a bit unclear; you have 1 struct that saves a specific type of data (unit/real/int/whatever) so you save say a unit to "structunit caster", so its like a mini hashtable? would this mean that (for a spell) if i needed to save the caster and the target i would save "unitstruct caster = GetTriggerUnit()" and then save "unitstruct target = GetSpellTargetUnit()" and then other variable types would need their own struct.... am i thinking correctly?

edit: err... i have it wrong, its pretty much exactly a hashtable but the syntax is a bit different...
 
Level 6
Joined
Sep 9, 2006
Messages
92
Here's my spell, using hashtables still; it almost works except for some stuff in the second loop (it does loop for a bit but doesnt move the unit like it should and stops prematurely)

JASS:
//==============================================================================//
//Death's Respite - JASS version                                                //
//                                                                              //
//Lifts the unit into the air and then throws it back, dealing damage.          //
//==============================================================================//
//Constants                                                                     //
//==============================================================================//

function Trig_DR_JASS_Conditions takes nothing returns boolean
    return GetSpellAbilityId() == 'A001' //Ability ID
endfunction

function DR_Max_Time_Lift takes nothing returns real
    return 1.00  //Max time to lift unit into air
endfunction

function DR_Dmg_Multiplier takes nothing returns real
    return 0.60  //Damage multiplier ( lvl x (str + int) x DmgConstant )
endfunction

function DR_Dmg_Init takes nothing returns real
    return 30.00  //Initial Damage ( ( DmgInit x lvl ) + ( lvl x (str + int) x DmgConstant ) )
endfunction

function DR_Lift_per_Tick takes nothing returns real
    return 2.00  //Height lifted per .02sec
endfunction

function DR_Throw_per_Tick takes nothing returns real
    return 20.00  //Distance thrown per .02sec
endfunction

function DR_Porab_Length takes nothing returns real
    return 1200.00  //Overall length of the porabolic shape multiplied by the time used to lift
endfunction

function DR_Porab_EndDist takes nothing returns real
    return 600.00  //End distance from initial point for parabola multiplied by the time used to lift
endfunction

function DR_Height takes real MaxHeight, real MaxDist, real CurDist returns real
    return (((4.00 * MaxHeight) / MaxDist) * (MaxDist - CurDist) * (CurDist / MaxDist))
endfunction

//==============================================================================//
//End Constants                                                                 //
//==============================================================================//


function DR_JASS_Throw takes nothing returns nothing
    local timer tt = GetExpiredTimer()
    local real maxdist = LoadReal( udg_DR_JASS_Hash, GetHandleId(tt), StringHash("MaxDist"))
    local real curdist = LoadReal( udg_DR_JASS_Hash, GetHandleId(tt), StringHash("CurDist"))
    local real maxheight = LoadReal( udg_DR_JASS_Hash, GetHandleId(tt), StringHash("MaxHeight"))
    local real targetptx = LoadReal( udg_DR_JASS_Hash, GetHandleId(tt), StringHash("TargetPtX"))
    local real targetpty = LoadReal( udg_DR_JASS_Hash, GetHandleId(tt), StringHash("TargetPtY"))
    local real endptx = LoadReal( udg_DR_JASS_Hash, GetHandleId(tt), StringHash("EndPtX"))
    local real endpty = LoadReal( udg_DR_JASS_Hash, GetHandleId(tt), StringHash("EndPtY"))
    local unit target = LoadUnitHandle( udg_DR_JASS_Hash, GetHandleId(tt), StringHash("Target") )
    local location temp
    call DisplayTextToForce( GetPlayersAll(), "test" )
    if maxdist > curdist then
        set temp = PolarProjectionBJ( Location( targetptx, targetpty ), DR_Throw_per_Tick(), AngleBetweenPoints(Location( targetptx, targetpty ), Location( endptx, endpty )) )
        call SaveReal(udg_DR_JASS_Hash, GetHandleId(tt), StringHash("TargetPtX"), GetLocationX(temp) )
        call SaveReal(udg_DR_JASS_Hash, GetHandleId(tt), StringHash("TargetPtY"), GetLocationY(temp) )
        call SaveReal(udg_DR_JASS_Hash, GetHandleId(tt), StringHash("CurDist"), (curdist + DR_Throw_per_Tick()) )
        set targetptx = LoadReal( udg_DR_JASS_Hash, GetHandleId(tt), StringHash("TargetPtX"))
        set targetpty = LoadReal( udg_DR_JASS_Hash, GetHandleId(tt), StringHash("TargetPtY"))
        call SetUnitPositionLoc(target, Location(targetptx, targetpty) )
        call SetUnitFlyHeight( target, DR_Height( maxheight, maxdist, curdist ), 0.00 )
    else
        call PauseTimer(tt)
        call DestroyTimer(tt)
        set tt = null
        set target = null
    endif

    call RemoveLocation(temp)
    set tt = null
    set target = null
endfunction

function DR_JASS_Lift takes nothing returns nothing
    local timer t = GetExpiredTimer()
    local timer tt = CreateTimer()
    local unit caster = LoadUnitHandle( udg_DR_JASS_Hash, GetHandleId(t), StringHash("Caster") )
    local unit target = LoadUnitHandle( udg_DR_JASS_Hash, GetHandleId(t), StringHash("Target") )
    local real time = LoadReal( udg_DR_JASS_Hash, GetHandleId(t), StringHash("Time") )
    local integer lvl = LoadInteger( udg_DR_JASS_Hash, GetHandleId(t), StringHash("Level") )
    local integer str = LoadInteger( udg_DR_JASS_Hash, GetHandleId(t), StringHash("Str") )
    local integer int = LoadInteger( udg_DR_JASS_Hash, GetHandleId(t), StringHash("Int") )
    local location temp

    if time <= DR_Max_Time_Lift() then

        call SaveReal( udg_DR_JASS_Hash, GetHandleId(t), StringHash("Time"), ( time + 0.02 ) )
        call SetUnitFlyHeight( target, ( GetUnitFlyHeight(target) + DR_Lift_per_Tick() ), 0.00 )
        call UnitDamageTarget( caster, target, (DR_Dmg_Init()*I2R(lvl)+((I2R(str)+I2R(int))*(I2R(lvl)*DR_Dmg_Multiplier()))*0.02), true, false, ATTACK_TYPE_MAGIC, DAMAGE_TYPE_NORMAL, WEAPON_TYPE_WHOKNOWS )
        call DestroyTimer(tt)
    else

        call TimerStart( tt, 0.02, true, function DR_JASS_Throw )
        call SaveBoolean( udg_DR_JASS_Hash, GetHandleId(tt), StringHash("Lifting"), false )
        call SaveBoolean( udg_DR_JASS_Hash, GetHandleId(tt), StringHash("Throw"), true )
        call PauseUnit( target, false )
        call SaveReal( udg_DR_JASS_Hash, GetHandleId(tt), StringHash("MaxDist"), ( DR_Porab_Length() * time ) )
        call SaveReal( udg_DR_JASS_Hash, GetHandleId(tt), StringHash("CurDist"), ( (DR_Porab_Length() * time)/2.00 ) )
        call SaveReal( udg_DR_JASS_Hash, GetHandleId(tt), StringHash("MaxHeight"), ( time * 100.00 ) )
        call SaveReal( udg_DR_JASS_Hash, GetHandleId(tt), StringHash("TargetPtX"), GetLocationX(GetUnitLoc(target)))
        call SaveReal( udg_DR_JASS_Hash, GetHandleId(tt), StringHash("TargetPtY"), GetLocationY(GetUnitLoc(target)))
        set temp = PolarProjectionBJ( Location(GetLocationX(GetUnitLoc(target)), GetLocationY(GetUnitLoc(target))), ((DR_Porab_Length() * time) / 2.00), AngleBetweenPoints(Location(GetLocationX(GetUnitLoc(caster)), GetLocationY(GetUnitLoc(caster))), Location(GetLocationX(GetUnitLoc(target)), GetLocationY(GetUnitLoc(target)))))
        call SaveReal( udg_DR_JASS_Hash, GetHandleId(tt), StringHash("EndPtX"), GetLocationX(temp))
        call SaveReal( udg_DR_JASS_Hash, GetHandleId(tt), StringHash("EndPtY"), GetLocationY(temp))
        call DestroyEffect(AddSpecialEffectTarget("Abilities\\Spells\\Undead\\DeathCoil\\DeathCoilSpecialArt.mdl", target, "origin"))

        call PauseTimer(t)
        call DestroyTimer(t)
        set t = null
        set caster = null
        set target = null
    endif

    call RemoveLocation(temp)
    set t = null
    set caster = null
    set target = null
endfunction

function Trig_DR_JASS_Actions takes nothing returns nothing
    local unit caster = GetTriggerUnit()
    local unit target = GetSpellTargetUnit()
    local timer t = CreateTimer()

    call PauseUnit( target, true )
    call SaveUnitHandle( udg_DR_JASS_Hash, GetHandleId(t), StringHash("Target"), target )
    call SaveUnitHandle( udg_DR_JASS_Hash, GetHandleId(t), StringHash("Caster"), caster )
    call SaveReal( udg_DR_JASS_Hash, GetHandleId(t), StringHash("Time"), 0.00 )
    call SaveBoolean( udg_DR_JASS_Hash, GetHandleId(t), StringHash("Throw"), false )
    call SaveBoolean( udg_DR_JASS_Hash, GetHandleId(t), StringHash("Lifting"), true )
    call SaveInteger( udg_DR_JASS_Hash, GetHandleId(t), StringHash("Str"), GetHeroStr( caster, true) )
    call SaveInteger( udg_DR_JASS_Hash, GetHandleId(t), StringHash("Int"), GetHeroInt( caster, true) )
    call SaveInteger( udg_DR_JASS_Hash, GetHandleId(t), StringHash("Level"), GetUnitAbilityLevel(caster, GetSpellAbilityId()) )

    call DestroyEffect(AddSpecialEffectTarget("Abilities\\Spells\\Undead\\DarkRitual\\DarkRitualTarget.mdl", target, "origin"))
    call UnitAddAbility(target, 'Arav')
    call UnitRemoveAbility(target, 'Arav')
    call TimerStart(t, 0.02, true, function DR_JASS_Lift)

    set caster = null
    set target = null
    set t = null
endfunction

//===========================================================================
function InitTrig_DR_JASS takes nothing returns nothing
    set gg_trg_DR_JASS = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( gg_trg_DR_JASS, EVENT_PLAYER_UNIT_SPELL_CAST )
    call TriggerAddCondition( gg_trg_DR_JASS, Condition( function Trig_DR_JASS_Conditions ) )
    call TriggerAddAction( gg_trg_DR_JASS, function Trig_DR_JASS_Actions )
endfunction
if i cant get it to work like this ill add in an index to keep track instead of using timers

edit: the spell is supposed to lift the target for 1 second then throw it back; this is a jass version of a gui spell i made and uploaded, the jass one not fully functional compared to the gui version yet... the gui had the caster channel for up to 1 second which determined distance/damage however this just is a cast
 
Last edited:
Level 6
Joined
Sep 9, 2006
Messages
92
I see no loops, also PolarProjectionBJ() and locations are bad (for leaking reasons) (use X and Y positions instead), also... my guess is: if it's not a flying unit, SetUnitFlyHeight() doesn't work, you may use an Impale spell without graphics cast by a dummy to achieve that effect, though.

by loop i refer to timer loop in a function, polar projection ya i dont know the other function to use besides this (or taking it apart using jass helper, which makes it very confusing) changing flying height works fine because of
JASS:
    call UnitAddAbility(target, 'Arav')
    call UnitRemoveAbility(target, 'Arav')
the only problem im having might b because of linking them to a timer; the second timer loop function (DR_JASS_Throw) doesnt seem to do anything besides run a loop a few times then stop
 
Level 13
Joined
Jun 23, 2009
Messages
299
by loop i refer to timer loop in a function, polar projection ya i dont know the other function to use besides this (or taking it apart using jass helper, which makes it very confusing) changing flying height works fine because of
JASS:
    call UnitAddAbility(target, 'Arav')
    call UnitRemoveAbility(target, 'Arav')
the only problem im having might b because of linking them to a timer; the second timer loop function (DR_JASS_Throw) doesnt seem to do anything besides run a loop a few times then stop
I guess I got that: if maxdist > curdist then is never true because the "time" value is 0.00 :wink:
 
Level 13
Joined
Jun 23, 2009
Messages
299
in DR_JASS_Lift function, every .02 seconds "time" is set to ((load "time" from hash) + .02) making it equal to 1 eventually, which is what starts the DR_JASS_Throw function
Yes, it changes the "Time" hash value, but it doesn't change the "time" variable accordingly, since it registers the "Time" value before it is changed this way. Anyway, that if check I said is pretty much useless, since it would always be true.
 
Level 6
Joined
Sep 9, 2006
Messages
92
Yes, it changes the "Time" hash value, but it doesn't change the "time" variable accordingly, since it registers the "Time" value before it is changed this way. Anyway, that if check I said is pretty much useless, since it would always be true.

ill check on that however it works as intended on that; raises the unit up over 1 second (however the damage is buggy, does too much)
 
Level 13
Joined
Jun 23, 2009
Messages
299
ill check on that however it works as intended on that; raises the unit up over 1 second (however the damage is buggy, does too much)
Sorry, you were right, I didn't read the code well...

So... according to the code, "tt" should run more or less 61 times, check that with a DebugMsg that displays an integer variable that increases everytime the timer fires.
 
Level 6
Joined
Sep 9, 2006
Messages
92
Sorry, you were right, I didn't read the code well...

So... according to the code, "tt" should run more or less 61 times, check that with a DebugMsg that displays an integer variable that increases everytime the timer fires.

will do, 61 depending on my actual triggering or because of a bug? (it should take the unit back to the ground from the top of the parabola, it just seems like thtats a small number however ive never calculated it like that)

edit: it seems that in practice the trigger loops 32 times so....

edit2 however i would think it should loop 30 times because the max distance is 600 (1200/2 to get middle of parabola) / 20 = 30
 
Level 13
Joined
Jun 23, 2009
Messages
299
will do, 61 depending on my actual triggering or because of a bug? (it should take the unit back to the ground from the top of the parabola, it just seems like thtats a small number however ive never calculated it like that)

edit: it seems that in practice the trigger loops 32 times so....

edit2 however i would think it should loop 30 times because the max distance is 600 (1200/2 to get middle of parabola) / 20 = 30
32 times without showing differences? It may run too fast to be stopped when it should. (And maybe the trigger doesn't end at the time another instance starts)
Try either making the timer fire every 0.10 seconds or removing 'Arav' at the end of the Throw trigger and not when the first timer starts.
 
Status
Not open for further replies.
Top