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

Strangest hashtable screw-up yet

Status
Not open for further replies.
Level 9
Joined
Dec 6, 2007
Messages
233
So i have this trigger

  • ability fire
    • Events
      • Time - Every 0.05 seconds of game time
    • Conditions
    • Actions
      • Unit Group - Pick every unit in Flamethrower_Shooter_Group and do (Actions)
        • Loop - Actions
          • Set Temp_Loc = (Position of (Picked unit))
          • Set Temp_Real = (Facing of (Picked unit))
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • (Load Flamethrower_Timer_Tick of (Key (Picked unit)) from Flamethrower_Hash) Greater than 36
            • Then - Actions
              • Hashtable - Save 0 as Flamethrower_Timer_Tick of (Key (Picked unit)) in Flamethrower_Hash
              • Unit Group - Remove (Picked unit) from Flamethrower_Shooter_Group
            • Else - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • (Load Flamethrower_Timer_Tick of (Key (Picked unit)) from Flamethrower_Hash) Less than 18
            • Then - Actions
              • Set Temp_Real = (Temp_Real - 45.00)
              • Set Temp_Real = (Temp_Real + ((Real((Load Flamethrower_Timer_Tick of (Key (Picked unit)) from Flamethrower_Hash))) x 5.00))
              • Hashtable - Save ((Load Flamethrower_Timer_Tick of (Key (Picked unit)) from Flamethrower_Hash) + 1) as Flamethrower_Timer_Tick of (Key (Picked unit)) in Flamethrower_Hash
            • Else - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • (Load Flamethrower_Timer_Tick of (Key (Picked unit)) from Flamethrower_Hash) Greater than or equal to 18
              • (Load Flamethrower_Timer_Tick of (Key (Picked unit)) from Flamethrower_Hash) Less than or equal to 36
            • Then - Actions
              • Set Temp_Real = (Temp_Real + 45.00)
              • Set Temp_Real = (Temp_Real - (((Real((Load Flamethrower_Timer_Tick of (Key (Picked unit)) from Flamethrower_Hash))) - 18.00) x 5.00))
              • Hashtable - Save ((Load Flamethrower_Timer_Tick of (Key (Picked unit)) from Flamethrower_Hash) + 1) as Flamethrower_Timer_Tick of (Key (Picked unit)) in Flamethrower_Hash
            • Else - Actions
          • Game - Display to (All players) the text: (String((Load Flamethrower_Timer_Tick of (Key (Picked unit)) from Flamethrower_Hash)))
          • Unit - Create 1 Dummy Fireball for (Owner of (Picked unit)) at Temp_Loc facing Temp_Real degrees
          • Unit - Set the custom value of (Last created unit) to (Level of Flamethrower for (Picked unit))
          • Unit Group - Add (Last created unit) to Flamethrower_Shell
          • Unit - Add a 1.00 second Generic expiration timer to (Last created unit)
          • Trigger - Turn on flame travel <gen>
          • Custom script: call RemoveLocation(udg_Temp_Loc)
that makes a flamethrower effect. It sweeps back and forth a wave of flame in a 90 degree cone. However, when Flamethrower_Timer_Tick reaches 22, the next run it sets it to 1. Every time i run it after that, it never leaves 1, but it still fires for the correct amount of time.

Other related triggers:
  • ability set
    • Events
      • Unit - A unit Begins channeling an ability
    • Conditions
      • (Ability being cast) Equal to Flamethrower
    • Actions
      • Unit Group - Add (Triggering unit) to Flamethrower_Shooter_Group
      • Hashtable - Save 0 as Flamethrower_Timer_Tick of (Key (Triggering unit)) in Flamethrower_Hash
  • ability reset
    • Events
      • Unit - A unit Stops casting an ability
    • Conditions
      • (Ability being cast) Equal to Flamethrower
    • Actions
      • Unit Group - Remove (Triggering unit) from Flamethrower_Shooter_Group
      • Hashtable - Save 0 as Flamethrower_Timer_Tick of (Key (Triggering unit)) in Flamethrower_Hash

any ideas?

EDIT: yes, i did change the initial values of the hastable integer variables
 
First off, you need to clear the values of your unit, after
  • If - Conditions
    • (Load Flamethrower_Timer_Tick of (Key (Picked unit)) from Flamethrower_Hash) Greater than 36
    • Then - Actions
    • Hashtable - Clear all child hashtables of (Key (Picked unit)) in Flamethrower_Hash
    • Unit Group - Remove (Picked unit) from Flamethrower_Shooter_Group
and

  • ability reset
  • Events
    • Unit - A unit Stops casting an ability
  • Conditions
    • (Ability being cast) Equal to Flamethrower
  • Actions
    • Unit Group - Remove (Triggering unit) from Flamethrower_Shooter_Group
    • Hashtable - Clear all child hashtables of (Key (Triggering unit)) in Flamethrower_Hash
This way, the next one will be normally set to 0 and the caster won't be affected by previous casts. Now tell me, does it happen always when the value hits 22?
 
Level 9
Joined
Dec 6, 2007
Messages
233
mmk, i'll clear those, but anywho, yes. It always breaks after 22, witch is absolutely strange because the number 22 doesn't appear anywhere else in my map
 
Level 10
Joined
Oct 31, 2009
Messages
352
Looking at what you've posted theres no reason this should cut off at 22. I would point out that if it is running for the correct amount of time as you suggest, it must be a display problem (though I see nothing wrong with that either).

The first time you cast it does it fire for the correct amount of time as well, or is that only after the first time?

______________________________________________________
First off, you need to clear the values of your unit, after

I learned something today
 
Level 9
Joined
Dec 6, 2007
Messages
233
i do not have newgen, but, erm, how to pm the map? pm doesn't have an attachments... I'd rather not post the map on the thread because it has a large number of things i've been working on.
 
For these triggers, convert your matching triggers to custom script, delete all your stuff, and put what I give you:

JASS:
function Trig_ability_fire_Func001B takes unit u,unit dum returns nothing
    local hashtable hash = udg_Flamethrower_Hash
    local integer id     = GetHandleId(u)
    local integer ref    = udg_Flamethrower_Timer_Tick
    local integer i      = LoadInteger(hash,id,ref)
    local real angle     = GetUnitFacing()
    if i > 36 then
        call GroupRemoveUnit(udg_Flamethrower_Shooter_Group,u)
        call FlushChildHashtable(hash,id)
    elseif i < 18 then
        set angle = angle - 45. + i *5.
        call SaveInteger(hash,id,ref,i + 1)
    elseif i >= 18 and i <= 36 then
        set angle = angle + 45. - ((i - 18.)*5.)
        call SaveInteger(hash,id,ref,i + 1)
    endif
    call DisplayTextToPlayer(GetLocalPlayer(),0.,0.,I2S(i))
    set dum = CreateUnit(GetOwningPlayer(u),'e002',GetUnitX(u),GetUnitY(u),angle)
    call SetUnitUserData(dum,GetUnitAbilityLevel(u,'A002'))
    call GroupAddUnit(udg_Flamethrower_Shell,dum)
    call UnitApplyTimedLife(dum,'BTLF',1.)
    call EnableTrigger(gg_trg_flame_travel)
endfunction
 
function Trig_ability_fire_Func001A takes nothing returns nothing
    call Trig_ability_fire_Func001B(GetEnumUnit(),null)
endfunction
 
function Trig_ability_fire_Actions takes nothing returns boolean
    call ForGroup(udg_Flamethrower_Shooter_Group,function Trig_ability_fire_Func001A)
    return false
endfunction
 
//===========================================================================
function InitTrig_ability_fire takes nothing returns nothing
    set gg_trg_ability_fire = CreateTrigger()
    call TriggerRegisterTimerEvent(gg_trg_ability_fire,0.05,true)
    call TriggerAddCondition(gg_trg_ability_fire,Condition(function Trig_ability_fire_Conditions))
endfunction

JASS:
function Trig_ability_set_Conditions takes nothing returns boolean
    if GetSpellAbilityId() == 'A002' then
        call GroupAddUnit(udg_Flamethrower_Shooter_Group,GetTriggerUnit())
        call SaveInteger(udg_Flamethrower_Hash,GetHandleId(GetTriggerUnit()),udg_Flamethrower_Timer_Tick,0)
    endif
    return false
endfunction
 
//===========================================================================
function InitTrig_ability_set takes nothing returns nothing
    local trigger t = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ(t,EVENT_PLAYER_UNIT_SPELL_CHANNEL)
    call TriggerAddCondition(t,Condition(function Trig_ability_set_Conditions))
endfunction

JASS:
function Trig_ability_reset_Conditions takes nothing returns boolean
    if GetSpellAbilityId() == 'A002' then
        call GroupRemoveUnit(udg_Flamethrower_Shooter_Group,GetTriggerUnit())
        call FlushChildHashtable(udg_Flamethrower_Hash,GetHandleId(GetTriggerUnit()))
    endif
    return false
endfunction
 
//===========================================================================
function InitTrig_ability_reset takes nothing returns nothing
    local trigger t = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ(t,EVENT_PLAYER_UNIT_SPELL_ENDCAST)
    call TriggerAddCondition(t,Condition(function Trig_ability_reset_Conditions))
endfunction

JASS:
function Trig_flame_travel_Func001B takes unit dum returns unit
    call SetUnitUserData(dum,4)
    call GroupAddUnit(udg_Flamethrower_Shell,dum)
    call UnitApplyTimedLife(dum,'BTLF',2.)
    return dum
endfunction
 
function Trig_flame_travel_Func001A takes nothing returns nothing
    local unit    tar
    local unit    u       = GetEnumUnit()
    local player  p       = GetOwningPlayer(u)
    local integer id      = GetHandleId(u)
    local integer data    = GetUnitUserData(u)
    local integer delay   = LoadInteger(udg_Flamethrower_Hash,id,udg_Flaming_Ground_Delay)
    local integer strikes = LoadInteger(udg_Flamethrower_Hash,id,udg_Strikes_Left)
    local real    base    = LoadInteger(udg_Flamethrower_Hash,id,udg_Level_Of_Ability)*45.
    local real    damage
    local real    face    = GetUnitFacing(u)
    local real    x       = GetUnitX(u)
    local real    y       = GetUnitY(u)
    local boolean b       = false
    if data == 4 and delay == 0 then
        call SaveInteger(udg_Flamethrower_Hash,id,udg_Flaming_Ground_Delay,2)
        call UnitApplyTimedLife(CreateUnit(p,'h000',x,y,270.),'BTLF',7.)
    else
        call SaveInteger(udg_Flamethrower_Hash,id,udg_Flaming_Ground_Delay,delay - 1)
    endif
    set x = x + 25.*Cos(face*bj_DEGTORAD)
    set y = y + 25.*Sin(face*bj_DEGTORAD)
    call SetUnitPosition(u,x,y)
    call GroupEnumUnitsInRange(bj_lastCreatedGroup,x,y,75.,null)
    loop
        set tar = FirstOfGroup(bj_lastCreatedGroup)
        exitwhen tar == null
        call GroupRemoveUnit(bj_lastCreatedGroup,tar)
        if GetWidgetLife(tar) > 0. and not IsUnitType(tar,UNIT_TYPE_SAPPER) and IsUnitEnemy(tar,p) then
            if not b then
                set b = true
            endif
            if data == 0 then
                set damage = 5.
            elseif data == 4 and not IsUnitInGroup(tar,udg_Cant_Hit_Delay) then
                set damage = base
                set x = GetUnitX(tar)
                set y = GetUnitY(tar)
                if strikes > 0 then
                    call SaveInteger(udg_Flamethrower_Hash,GetHandleId(Trig_flame_travel_Func001B(CreateUnit(p,'e002',x,y,face + 45.))),udg_Strikes_Left,strikes - 1)
                    call SaveInteger(udg_Flamethrower_Hash,GetHandleId(Trig_flame_travel_Func001B(CreateUnit(p,'e002',x,y,face - 45.))),udg_Strikes_Left,strikes - 1)
                    set bj_groupCountUnits = bj_groupCountUnits + 2
                    set strikes = strikes - 1
                endif
                call DestroyEffect(AddSpecialEffect("Abilities\\Spells\\Items\\AIfb\\AIfbSpecialArt.mdl",x,y))
                call SaveInteger(udg_Flamethrower_Hash,GetHandleId(tar),udg_Cant_Hit_Delay_Timer,100)
                call GroupAddUnit(udg_Cant_Hit_Delay,tar)
            else
                set damage = data*15.
            endif

            call UnitDamageTarget(u,tar,damage,true,false,ATTACK_TYPE_NORMAL,DAMAGE_TYPE_NORMAL,WEAPON_TYPE_WHOKNOWS)
        endif
    endloop
    if b then
        call FlushChildHashtable(udg_Flamethrower_Hash,id)
        call GroupRemoveUnit(udg_Flamethrower_Shell,u)
        call RemoveUnit(u)
    else
        set bj_groupCountUnits = bj_groupCountUnits + 1
    endif
    set u = null
endfunction
 
function Trig_flame_travel_Conditions takes nothing returns boolean
    set bj_groupCountUnits = 0
    call ForGroup(udg_Flamethrower_Shell,function Trig_flame_travel_Func001A)
    if bj_groupCountUnits == 0 then
        call DisableTrigger(gg_trg_flame_travel)
    endif
    return false
endfunction
 
//===========================================================================
function InitTrig_flame_travel takes nothing returns nothing
    local trigger t = CreateTrigger()
    call DisableTrigger(t)
    call TriggerRegisterTimerEvent(t,0.05,true)
    call TriggerAddCondition(t,Condition(function Trig_flame_travel_Conditions))
    set gg_trg_flame_travel = t
endfunction
 
Last edited:
Level 9
Joined
Dec 6, 2007
Messages
233
I thank you for putting the time and effort to make that, and i did learn some things about jass because of it, but i have to decline the code. I am not a sufficient jass programmer, and therefore cannot troubleshoot or modify this code (I already am planning on placing extra bits into the code about timed removal instead of expiration timers). Also, there are multiple systems connected to many of those triggers. Changing those to jass would mean I would also have to modify another large portion of the map, making me unable to troubleshoot or modify that either. A GUI answer to this issue would give me knowledge of what to do if another situation like this were to occur, rather than posting another frantic help thread. I will learn jass eventually, just not now. +rep anyways, i don't want to have wasted your time for naught.

If anyone has good knowledge of hashes and wants to take a crack at this, post about it, and i will pm you the map

(By the way, bribe, do you have any comments about the spells and systems in the map? i'm thinking of making a spellpack)
 
Here's one thing you're doing weirdly: saving integers into the hashtable right before you flush it (waste). Another thing is that you're trying to reference hashtable values even after you flushed it (returns null, that will give errors).

As for the spell pack, as long as your GUI code doesn't have bad FPS (which, from looking at it, it will) it's fine.

Another problem is that GUI hashtables have a lot of glitches. If you do not use JASS hashtables instead of them, you are liable to run into unprecedented weirdness.
 
Level 9
Joined
Dec 6, 2007
Messages
233
oh yeah, i added the flushes after a previous suggestion on this thread, but forgot to delete the old code there. It's now fixed. About gui hashes: odd, i guess i'll just play around with it until i can fix it. thanks
 
Status
Not open for further replies.
Top