[vJASS] Hashtables Learning

Status
Not open for further replies.
If I make a nova that works like this
JASS:
            loop
                exitwhen i >= NOVA_SIZE
                set inst.Nova[i] = CreateUnit( inst.Player , UNIT_ID , inst.X , inst.Y , A )
                set A = A + dA
                set i = i + 1
            endloop
then later I move with this
JASS:
                loop
                    exitwhen j >= NOVA_SIZE
                    set x = inst.X + inst.expand * Cos( a * bj_DEGTORAD )
                    set y = inst.Y + inst.expand * Sin( a * bj_DEGTORAD )
                    call SetUnitX( inst.Nova[j] , x )
                    call SetUnitY( inst.Nova[j] , y )
                    set j = j + 1
                    set a = a + dA
                endloop
Which is better the previous or a hashtable. If hashtable how do I use it ?

Note:
I never used hashtables before, so I decided to learn how to use them but in JASS directly (I will not learn in GUI then JASS)
 
idk in vjass but i too work on nova but in jass, i do this way with hashtable

JASS:
function Trig_HolyNova_Conditions takes nothing returns boolean
    return GetSpellAbilityId() == 'A004'
endfunction

function HolyNovaTimer takes nothing returns nothing
    local timer t = GetExpiredTimer()
    local integer id = GetHandleId(t)
    local integer cv
    local unit pu
    local unit dummy
    local unit u = LoadUnitHandle(udg_Spell_Table, id, 1)
    local real x = GetUnitX(u)
    local real y = GetUnitY(u)
    local real nx 
    local real ny 
    local real distance = LoadReal(udg_Spell_Table, id, 3) - 35
    local real dmg = LoadReal(udg_Spell_Table, id, 2)
    local integer nr = LoadInteger(udg_Spell_Table, id, 4)
    local real g = 360/nr
    local integer a = 0

    if distance > 0 then
        call SaveReal(udg_Spell_Table, id, 3, distance)
    loop
    exitwhen a > nr
      set dummy = LoadUnitHandle(udg_Spell_Table, id, a+5)
      set nx = GetUnitX(dummy) + 35 * Cos(a*g)  
      set ny = GetUnitY(dummy) + 35 * Sin(a*g) 

      call SetUnitPosition(dummy, nx, ny)
    set a = a + 1
    endloop

    set dummy = null

        call TimerStart(t, 0.03, false, function HolyNovaTimer)
    else

    loop
    exitwhen a > nr
      set dummy = LoadUnitHandle(udg_Spell_Table, id, a+5)
      //call RemoveUnit(dummy)
      call KillUnit(dummy)
    set a = a + 1
    endloop

        call GroupEnumUnitsInRange(udg_UG, x, y, 550, null)
        loop
            set pu = FirstOfGroup(udg_UG)
            exitwhen (pu==null)
            if IsUnitEnemy(pu, GetOwningPlayer(u)) then
                set cv = GetUnitUserData(pu)
                if LoadInteger(udg_Misc_Table, id, cv) == 0 then
                    call UnitDamageTarget(u, pu, dmg, true, false, ATTACK_TYPE_HERO, DAMAGE_TYPE_NORMAL, WEAPON_TYPE_WHOKNOWS)
                endif
                call SaveInteger(udg_Misc_Table, id, cv, 1)
            endif
            call GroupRemoveUnit(udg_UG, pu)
        endloop

        call PauseTimer(t)
        call DestroyTimer(t)
        call FlushChildHashtable(udg_Spell_Table, id)
        call FlushChildHashtable(udg_Misc_Table, id)
    endif

    set t = null
    set u = null
endfunction


function Trig_HolyNova_Actions takes nothing returns nothing
    local unit u = GetTriggerUnit()
    local real x = GetUnitX(u)
    local real y = GetUnitY(u)
    local timer t = CreateTimer()
    local integer id = GetHandleId(t)
    local real d2 = 350.00
    local real dmg = 100
    local integer a = 0
    local integer d1 = 150
    local integer fnr = 48
    local real g = 360/fnr
    local real r
    local real x1
    local real y1
    local real xt
    local real yt
    local player p = GetTriggerPlayer()

    call SaveUnitHandle(udg_Spell_Table, id, 1, u)
    call SaveReal(udg_Spell_Table, id, 2, dmg)
    call SaveReal(udg_Spell_Table, id, 3, d2)
    call SaveInteger(udg_Spell_Table, id, 4, fnr)


        loop
           exitwhen a > fnr
            set x1 = x + 150 * Cos(a*g)  
            set y1 = y + 150 * Sin(a*g) 
            set xt = x + d2 * Cos(a*g)  
            set yt = y + d2 * Sin(a*g) 
            set r = bj_RADTODEG * Atan2(yt - y1, xt - x1)
            set u = CreateUnit (p, 'h004', x1 , y1, r)
            call SaveUnitHandle(udg_Spell_Table, id, a+5, u)
            call SetUnitPathing( u, false ) 
           set a = a + 1
        endloop

    call TimerStart(t, 0.05, false, function HolyNovaTimer)


set u = null
set t = null
set p = null
endfunction

//===========================================================================
function InitTrig_Explosive_nova takes nothing returns nothing
    set gg_trg_Explosive_nova = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( gg_trg_Explosive_nova, EVENT_PLAYER_UNIT_SPELL_EFFECT )
    call TriggerAddCondition( gg_trg_Explosive_nova, Condition( function Trig_HolyNova_Conditions ) )
    call TriggerAddAction( gg_trg_Explosive_nova, function Trig_HolyNova_Actions )
endfunction
 
What is this line, why do we need to get the ID of Handle (t) ?

local
integer id = GetHandleId(t)

t = timer
every timer got a unque integer id (so even running more timer same time but each timer got different id)

why usefull this ?

because unique its mean and be overwrited like when u use custom value or avility id etc etc, so unique for identify for 1st key.
when i create a timer and get the created timer id then i save every data like this

key1:timerid,key2:asuwant,value:asuwant

when i make single shot timer then i can get the timerid again (with GetHandleId(GetExpiredTimer())) so i call directly that data where this handle id is the key1 and when spell is over then i flush everything where is the primary key this timer id
 
u cant, i use this for fast spells, for longer spell linked list is good

for fast spell u get the id via restart the timer and get again the expired timer id so its mean for each cast u need 1 timer, but since we can use for fast thing like knockback, fireout a missile unit etc this dont matter because dont run a ton timer in same time
 
.. , fireout a missile unit etc this dont matter because dont run a ton timer in same time

Yes, that's exactly my point. I use one timer, how can I get the ID of this unit to load it from the hashtable. That's what confuses me so I use array unit variable but when it come to 2D array that's where the problem may occur.
 
Are those changes right ?

from
call SetUnitX( Nova[(dat-1)*NOVA_SIZE + j] , x )
to
call SetUnitX(LoadUnitHandle( NovaU , dat , j),x)

and also this,

set Nova[(dat-1)*NOVA_SIZE + i] = CreateUnit( dat.Owner , N_UNIT_ID , dat.Cx , dat.Cy , A ) became
JASS:
set u = CreateUnit( dat.Owner , N_UNIT_ID , dat.Cx , dat.Cy , A )
call SaveUnitHandle( NovaU , dat , i , u )
and for the destroy part,
JASS:
loop
exitwhen j >= NOVA_SIZE
   call KillUnit(LoadUnitHandle( NovaU , dat , j))
   @set Nova[(dat-1)*NOVA_SIZE + j] = null@    // this was the previous code I used
   set dat.expand = 0
set j = j + 1
endloop

call FlushChildHashtable( NovaU , dat )
 
Last edited:
i will show tommorow how i made 1 timer for buffs but each unit in unit array can get more buff (so attached more special effect & number)

i remade my buff system, now it is linked list inside linked list with hashtable

header functions
JASS:
function RemoveUnitBuff takes integer id, integer index returns nothing
    local integer cv = GetUnitUserData( udg_Buff_Unit[id] )
    local integer buffid = LoadInteger( udg_Buff_Index_Table, cv, index )
    local real spd
    local integer amount = LoadInteger( udg_Buff_Amount, cv, buffid ) * -1
    local integer t =  LoadInteger( udg_Buff_Index_Table, cv, buffid )
    local unit u = udg_Buff_Unit[id]

	if index != udg_Buff_Unit_Index[cv] then
	   call SaveInteger( udg_Buff_Index_Table, cv, index, LoadInteger( udg_Buff_Index_Table, cv, udg_Buff_Unit_Index[cv] ) )
	endif
	
	set udg_Buff_Unit_Index[cv] = udg_Buff_Unit_Index[cv] - 1
	call DestroyEffect ( LoadEffectHandle(udg_Buff_EffectTable, cv, buffid))	

    call SaveInteger( udg_Buff_Timer, cv, buffid, 0 )
    call SaveInteger( udg_Buff_Amount, cv, buffid, 0 )
    if buffid==1 then
        set udg_B_Crit[cv] = udg_B_Crit[cv] + amount
    elseif buffid==2 then
        set udg_B_CritDmg[cv] = udg_B_CritDmg[cv] + amount
    elseif buffid == 3 then
        set udg_B_Eva[cv] = udg_B_Eva[cv] + amount
     endif


    if udg_Buff_Unit_Index[cv] == 0 then
          set udg_Buff_Unit_Id[cv] = 0
       if id != udg_Buff_Index then
          set udg_Buff_Unit[id] = udg_Buff_Unit[udg_Buff_Index]
          set udg_Buff_Unit_Id[GetUnitUserData(udg_Buff_Unit[id])] = id
       else

       endif
        set udg_Buff_Index = udg_Buff_Index - 1
        call FlushChildHashtable(udg_Buff_Index_Table, cv)
        call FlushChildHashtable(udg_Buff_EffectTable, cv)
        call FlushChildHashtable(udg_Buff_Timer, cv)
        call FlushChildHashtable(udg_Buff_Amount, cv)
    endif

//    call DisplayTextToPlayer( Player(0), 0, 0, "|cffffff00Remove buff a="+I2S(amount)+" array index" + I2S(udg_Buff_Index+1)+" C.Index" + I2S(id) +" buff index"+I2S(udg_Buff_Unit_Index[cv]) + " time" +I2S(t)+GetUnitName(u)+"|r")
set u = null
endfunction

function AddUnitBuff takes unit u, integer buffid, integer amount, integer dur, integer effectid, string apoint returns nothing
    local integer cv = GetUnitUserData(u)
    local integer times = LoadInteger( udg_Buff_Timer, cv, buffid )
    local integer oldv = LoadInteger( udg_Buff_Amount, cv, buffid )
    local integer diff = amount - oldv
    local integer pl = GetPlayerId(GetOwningPlayer(u)) + 1
    local real spd

    if udg_Buff_Unit_Id[cv] == 0 then
	set udg_Buff_Index = udg_Buff_Index + 1
        set udg_Buff_Unit[udg_Buff_Index] = u
        set udg_Buff_Unit_Id[cv] = udg_Buff_Index
    
    endif

    if times == 0 then
	    set udg_Buff_Unit_Index[cv] = udg_Buff_Unit_Index[cv] + 1
		call SaveInteger( udg_Buff_Index_Table, cv, udg_Buff_Unit_Index[cv], buffid )
		
       if effectid > - 1 then
	    call SaveEffectHandle(udg_Buff_EffectTable, cv, buffid, AddSpecialEffectTarget( udg_Effects[effectid], u, apoint ))
        endif
    endif
	
    call SaveInteger( udg_Buff_Amount, cv, buffid, amount )
    call SaveInteger( udg_Buff_Timer, cv, buffid, dur )

//    call DisplayTextToPlayer( Player(0), 0, 0, "dur=" + I2S(dur) + " amount="+I2S(amount)+" unit index in unit array" + I2S(udg_Buff_Index) +" unit buff index"+I2S(udg_Buff_Unit_Index[cv]))

    if buffid == 1 and oldv == 0 then
        set udg_B_CritDmg[cv] = udg_B_CritDmg[cv] + diff
    elseif buffid == 2 and oldv == 0  then
       set udg_B_Crit[cv] = udg_B_Crit[cv] + diff
    elseif buffid == 3 then
        set udg_B_Eva[cv] = udg_B_Eva[cv] + diff
    endif
    call DisplayTextToPlayer( Player(0), 0, 0, "|cffff0000b.id=" + I2S(buffid) + " diff="+I2S(diff)+" array index"+I2S(udg_Buff_Index)+" b amount"+I2S(udg_Buff_Unit_Id[cv])+"|r")

endfunction

timer trigger action
JASS:
    local integer i = 1
    local integer ii = 1
    local integer pv = 0
    local integer cc
    local integer po = 0
    local integer cv
    local integer buffid = 0
    local integer times = 0
    local integer vigor = 0
    loop
        exitwhen i > udg_Buff_Index
        set cv = GetUnitUserData(udg_Buff_Unit[i])
        if IsUnitType(udg_Buff_Unit[i], UNIT_TYPE_DEAD) or udg_Buff_Purge[cv] then
            //call ClearUnitBuff (i) not done but easy to do it with loop
        else
            loop
                exitwhen ii > udg_Buff_Unit_Index[cv]
                set buffid = LoadInteger(udg_Buff_Index_Table, cv, ii)
                set times = LoadInteger(udg_Buff_Timer, cv, buffid)
                 if times == 0 then
                     call RemoveUnitBuff (i, ii)
                else
                    call SaveInteger(udg_Buff_Timer, cv, buffid, times - 1)
                endif
                set ii = ii + 1
            endloop
            set ii = 1
            set udg_Buff_Purge[cv] = false
        endif
        set i = i + 1
    endloop
 
Status
Not open for further replies.
Back
Top