HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

More Trigger Bugs

08-20-2007, 11:36 PM#1
Dil999
I'm working on a spell (My first using Handles). This one is meant to have 5 rotating wisps of light, which rotate outwards like a nova, and then back in. All of this works, except for the actual effects. Allied units inside the area should have a divine shield effect attached to them and become invulnerable. The problem is that they arent becoming vulnerable when they leave the radius, or when the spell ends, and they arent getting the divine shield effect.
I believe there could be something wrong with lastgroup.

Collapse JASS:
function Spiral_Filter takes nothing returns boolean
    return GetWidgetLife(GetFilterUnit()) > 0 and IsUnitAlly(GetFilterUnit(),GetOwningPlayer(bj_ghoul[111]))
endfunction

function Spiral_Move takes nothing returns nothing
    local timer t = GetExpiredTimer()
    local unit u = GetHandleUnit(t,"TriggerUnit")
    local unit u2 = GetHandleUnit(t,"DummyUnit")
    local real Distance = (GetHandleReal(t,"Distance"))
    local real x = GetUnitX(u)
    local real y = GetUnitY(u)
    local real Dur = (GetHandleReal(t,"Dur") + 0.04)
    local real Angle = (GetHandleReal(t,"Angle") + 7.1)
    local real x2
    local real y2
    local unit u3
    
    local group lastgroup = CreateGroup()
    local group currentgroup = CreateGroup()
    local group currentgroup2 = CreateGroup()
    set bj_ghoul[111] = u

//==================================
//=====PART THAT ISNT WORKING=======
//==================================
    call GroupAddGroup(GetHandleGroup(t,"lastgroup"),lastgroup)
    call GroupEnumUnitsInRange(currentgroup,x,y,Distance,Filter(function Spiral_Filter))
    call SetHandleHandle(t,"lastgroup",currentgroup)
    call GroupAddGroup(currentgroup,currentgroup2)
    
        loop
            set u3 = FirstOfGroup(currentgroup)
            exitwhen u3 == null
                if (IsUnitInGroup(u3,lastgroup) == false) then
                
                    if GetHandleEffect(FirstOfGroup(currentgroup),"SpiralEffect") == null then
                        call SetHandleHandle(FirstOfGroup(currentgroup),"SpiralEffect",AddSpecialEffectTarget("Abilities\\Spells\\Human\\DivineShield\\DivineShieldTarget.mdl",u3,"origin"))
                    endif
                    
                    call SetUnitInvulnerable(u3,true)
                    call GroupRemoveUnit(currentgroup,u3)
                endif                                            
        endloop


                        
        loop
            set u3 = FirstOfGroup(lastgroup)
            exitwhen u3 == null 
                if (IsUnitInGroup(u3,currentgroup2) == false) then
                    call DestroyEffect(GetHandleEffect(FirstOfGroup(lastgroup),"SpiralEffect"))
                    call SetUnitInvulnerable(u3,false)
                    call GroupRemoveUnit(lastgroup,u3)
                endif
        endloop
        
    call DestroyGroup(currentgroup)
    call DestroyGroup(currentgroup2)
    call DestroyGroup(lastgroup)
    set u3 = null

//==================================
//==================================
//==================================
                
    
    
    if Distance < 400 and Dur < 4.00 then
        set Distance = Distance + 4.571
    endif
    
    if Dur > 4.00 then
        set Distance = Distance - 4.571
    endif
    
    
    set x2 = x + Distance * Cos(Angle * bj_DEGTORAD)
    set y2 = y + Distance * Sin(Angle * bj_DEGTORAD)
    
    call SetUnitX(u2,x2)
    call SetUnitY(u2,y2)
    
    call SetHandleReal(t,"Angle",Angle)
    call SetHandleReal(t,"Distance",Distance)
    call SetHandleReal(t,"Dur",Dur)
    
        if Dur >= 10.00 then
            call PauseTimer(t)
            call DestroyTimer(t)
            call KillUnit(u2)
            call FlushHandleLocals(t)
        endif
        
        
    set t = null
    set u = null
    set u2 = null
         
endfunction


function Spiral_Actions takes nothing returns nothing
    local timer array t
    local unit u = GetTriggerUnit()
    local unit array u2
    local real x = GetUnitX(u)
    local real y = GetUnitY(u)
    local integer i = 0
    local player p = GetOwningPlayer(u)
    local integer i2 = 5
    local real dur = 0.0
    local real array anglegetter
    
        loop
            set t[i] = CreateTimer()
            call SetHandleReal(t[i],"Dur",dur)
            call SetHandleInt(t[i],"Level",GetUnitAbilityLevel(u,'A000'))
            set anglegetter[i] = (360 / i2) * i
            call SetHandleReal(t[i],"Angle",anglegetter[i])
            call SetHandleReal(t[i],"Distance",0) 
            call SetHandleHandle(t[i],"TriggerUnit",u)
            call SetHandleHandle(t[i],"DummyUnit",(CreateUnit(p,'h000',x,y,GetRandomReal(1,360))))
            call TimerStart(t[i],0.04,true,function Spiral_Move)                        
            set t[i] = null
            set u2[i] = null
            set i = i + 1
        exitwhen i >= i2
        endloop
        
    set u = null
    set p = null       
    
endfunction

function SpiralConds takes nothing returns boolean
    return GetSpellAbilityId() == 'A000'
endfunction

function InitTrig_HolySpiral takes nothing returns nothing
    local trigger t = gg_trg_HolySpiral
    set t = CreateTrigger()
    call TriggerAddAction(t,function Spiral_Actions)
    call TriggerAddCondition(t,Condition(function SpiralConds))
    call TriggerRegisterAnyUnitEventBJ(t,EVENT_PLAYER_UNIT_SPELL_EFFECT)
    set t = null
endfunction
08-21-2007, 12:47 AM#2
botanic
i dont know a lotta jass but i didnt see any leaves area stuff so that could be the problem ;P
08-21-2007, 01:24 AM#3
Dil999
Instead of using leaving area stuff, I'm using 2 unit groups. The units which were within range the last time, and this time. First i check if any units are in now and werent before. That part works. Second, I check if there are any units which were in before and arent now. That doesnt.
08-21-2007, 02:23 AM#4
Hydrolisk
Collapse JASS:
    call GroupAddGroup(GetHandleGroup(t,"lastgroup"),lastgroup)
    call GroupEnumUnitsInRange(currentgroup,x,y,Distance,Filter(function Spiral_Filter))
    call SetHandle*Handle*(t,"lastgroup",currentgroup)
    call GroupAddGroup(currentgroup,currentgroup2)
    
        loop
            set u3 = FirstOfGroup(currentgroup)
            exitwhen u3 == null
                if (IsUnitInGroup(u3,lastgroup) == false) then
                
                    if GetHandleEffect(FirstOfGroup(currentgroup),"SpiralEffect") == null then
                        call SetHandle*Handle**(FirstOfGroup(currentgroup)*,"SpiralEffect",AddSpecialEffectTarget("Abilities\\Spells\\Human\\DivineShield\\DivineShieldTarget.mdl",u3,"origin"))
                    endif
                    
                    call SetUnitInvulnerable(u3,true)
                    call GroupRemoveUnit(currentgroup,u3)
                endif                                            
        endloop


                        
        loop
            set u3 = FirstOfGroup(lastgroup)
            exitwhen u3 == null 
                if (IsUnitInGroup(u3,currentgroup2) == false) then
                    call DestroyEffect(GetHandleEffect(FirstOfGroup(lastgroup),"SpiralEffect"))
                    call SetUnitInvulnerable(u3,false)
                    call GroupRemoveUnit(lastgroup,u3)
                endif
        endloop
        
    call DestroyGroup(currentgroup)
    call DestroyGroup(currentgroup2)
    call DestroyGroup(lastgroup)
    set u3 = null

*Don't mock my limited programming knowledge.*

Possible errors are caught between "*"

Is the second "handle" required?

The "(FirstofGroup(currentgroup)" might not be working because there isn't a second ")" to cover the not-covered "(". Possibly small errors like this with the others?
Perhaps coding errors or logical errors?

Am I right?
08-21-2007, 02:34 AM#5
Dil999
It all checks out in JassCraft, so I know theres no simple errors. SetHandleHandle means your creating a handle which is a handle. Another example is SetHandleInteger- makes a handle which is an integer.
08-21-2007, 12:31 PM#6
Pyrogasm
Use. CSCache.

—

This is all wrong:
Collapse JASS:
function InitTrig_HolySpiral takes nothing returns nothing
    local trigger t = gg_trg_HolySpiral
    set t = CreateTrigger()
    call TriggerAddAction(t,function Spiral_Actions)
    call TriggerAddCondition(t,Condition(function SpiralConds))
    call TriggerRegisterAnyUnitEventBJ(t,EVENT_PLAYER_UNIT_SPELL_EFFECT)
    set t = null
endfunction
That is all completely pointless. You're making a local that equals the global and then setting it equal to a new trigger when it already is. Just do this:
Collapse JASS:
function InitTrig_HolySpiral takes nothing returns nothing
    call TriggerAddAction(gg_trg_HolySpiral,function Spiral_Actions)
    call TriggerAddCondition(gg_trg_HolySpiral,Condition(function SpiralConds))
    call TriggerRegisterAnyUnitEventBJ(gg_trg_HolySpiral,EVENT_PLAYER_UNIT_SPELL_EFFECT)
endfunction

If you try to get a real/int that hasn't actually been stored (Using [ljass]SetHandleReal/Int[/ljas] it will return 0 anyway. It's pointless to store it as 0.00 when you know it hasn't already got a value as you've done:
Collapse JASS:
local real dur = 0.0
//...
call SetHandleReal(t[i],"Dur",dur)
//...
call SetHandleReal(t[i],"Distance",0)

set anglegetter[i] = (360 / i2) * i is a problem because the loop runs 6 times, but you're only using 5 increments for the angles (initializing i as 1 will fix this).

When you do call SetHandleInt(t[i],"Level",GetUnitAbilityLevel(u,'A000')), you should store the level to a variable outside of the loop such that it doesn't need to get the level multiple times:
Collapse JASS:
local integer level = GetUnitAbilityLevel(u, 'A000')
//...
call SetHandleInt(t[i],"Level",level)

I personally dislike starting at 0 when looping through things; I find it easier to start at 1 and then make my exitwhens at the top of the loop so that I can easily divide by the number of times the loop will run and stuff. Thus, I'd do this:

Collapse JASS:
local integer i = 0
//...
local integer i2 = 5 //It will create 5 units; you were creating 6
//...
loop
    set i = i+1
    exitwhen i > i2
    set t[i] = CreateTimer()
    call SetHandleReal(t[i],"Dur",dur)
    call SetHandleInt(t[i],"Level",GetUnitAbilityLevel(u,'A000'))
    set anglegetter[i] = (360 / i2) * i
    call SetHandleReal(t[i],"Angle",anglegetter[i])
    call SetHandleReal(t[i],"Distance",0) 
    call SetHandleHandle(t[i],"TriggerUnit",u)
    call SetHandleHandle(t[i],"DummyUnit",(CreateUnit(p,'h000',x,y,GetRandomReal(1,360))))
    call TimerStart(t[i],0.04,true,function Spiral_Move)                        
    set t[i] = null
    set u2[i] = null
endloop

The way you do everything with arrays is both pointless and unnecessary. You can simply remove the arrays:
Collapse JASS:
loop
    set i = i+1
    exitwhen i > i2

    set t = CreateTimer()
    call SetHandleInt(t,"Level",level)
    call SetHandleReal(t,"Angle",(360 / i2) * i) //Note how this is inlined
    call SetHandleHandle(t,"TriggerUnit",u)
    call SetHandleHandle(t,"DummyUnit",(CreateUnit(p,'h000',x,y,GetRandomReal(1,360))))
    call TimerStart(t,0.04,true,function Spiral_Move)                        
endloop //I also removed the u2 array, as you never used it

set t = null

Finally, everything can be attached to 1 timer instead of using 5 different timers. Here's that function done correctly :D
Collapse JASS:
function Spiral_Actions takes nothing returns nothing
    local timer t = CreateTimer()
    local unit u = GetTriggerUnit()
    local real x = GetUnitX(u)
    local real y = GetUnitY(u)
    local integer i = 0
    local player p = GetOwningPlayer(u)
    local integer i2 = 5
    local integer level = GetUnitAbilityLevel(u, 'A000')

        loop
            set i = i+1
            exitwhen i > i2
            call SetHandleReal(t,"Angle "+I2S(i),(360 / i2) * i)
            call SetHandleHandle(t,"DummyUnit "+I2S(i),(CreateUnit(p,'h000',x,y,GetRandomReal(0,360))))
        endloop

        call SetHandleInt(t,"Level",level)    
        call SetHandleHandle(t,"TriggerUnit",u)
        call TimerStart(t,0.04,true,function Spiral_Move)

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


As for the callback function, now you're going to have to modify everything to work with arrays... but let's assume that you're not going to do it for 5 units at once in the callback first. Here's how you'd go about fixin' it up:

Pointless:
Collapse JASS:
    local group lastgroup = CreateGroup()
 //...
    call GroupAddGroup(GetHandleGroup(t,"lastgroup"),lastgroup)
The fix: local group lastgroup = GetHandleGroup(t,"lastgroup") and remove the aforementioned line. This also fixes a group leak as you were overwriting lastgroup a few lines below.

You're attaching a special effect to a unit and then attaching it with handlevars. Bad idea. The best solution is to make an ability based off of the "life regeneration aura" ability that does nothing but add the Divine Shield SFX to the unit that has the ability. Then you'll simply remove it when the effect needs to go away:
Collapse JASS:
if GetHandleEffect(FirstOfGroup(currentgroup),"SpiralEffect") == null then
    call SetHandleHandle(FirstOfGroup(currentgroup),"SpiralEffect",AddSpecialEffectTarget("Abilities\\Spells\\Human\\DivineShield\\DivineShieldTarget.mdl",u3,"origin"))
endif

//Becomes this:
if GetUnitAbilityLevel(u3, 'A001') == 0 then
    call UnitAddAbility(u3, 'A001')
endif

//And change this:
call DestroyEffect(GetHandleEffect(FirstOfGroup(lastgroup),"SpiralEffect"))
//To this:
call UnitRemoveAbility(u3, 'A001')

All of this:
Collapse JASS:
loop
    set u3 = FirstOfGroup(currentgroup)
    exitwhen u3 == null
    if (IsUnitInGroup(u3,lastgroup) == false) then
        if GetUnitAbilityLevel(u3, 'A001') == 0 then
            call UnitAddAbility(u3, 'A001')
        endif
                    
        call SetUnitInvulnerable(u3,true)
        call GroupRemoveUnit(currentgroup,u3)
    endif                                            
endloop


                        
loop
    set u3 = FirstOfGroup(lastgroup)
    exitwhen u3 == null 
    if (IsUnitInGroup(u3,currentgroup2) == false) then
        call UnitRemoveAbility(u3, 'A001')
        call SetUnitInvulnerable(u3,false)
        call GroupRemoveUnit(lastgroup,u3)
    endif
endloop
Can be condensed to this:
Collapse JASS:
loop
    set u3 = FirstOfGroup(lastgroup)
    exitwhen u3 == null 
    if not(IsUnitInGroup(u3,currentgroup2)) then //The "not" operator is useful
        call UnitRemoveAbility(u3, 'A001')  //'A001' being the rawcode of the new spell
        call SetUnitInvulnerable(u3,false)
    endif
    call GroupRemoveUnit(currentgroup,u3) //Removing it from the other group so we don't have to check to see if the unit isn't in this one in the other loop
    call GroupRemoveUnit(lastgroup,u3) //Taking it out of the If/Then/Else prevents a possible thread crash with an infinite loop
endloop                                //I think that was your problem

loop
    set u3 = FirstOfGroup(currentgroup)
    exitwhen u3 == null
    if GetUnitAbilityLevel(u3, 'A001') == 0 then
        call UnitAddAbility(u3, 'A001')
        call SetUnitInvulnerable(u3,true) //You don't need to make it invulnerable every time if it already is
    endif                                            
    call GroupRemoveUnit(currentgroup,u3) //Again, fixing the infinite loop problems
endloop

This is a mighty severe problem:
Collapse JASS:
call SetHandleHandle(t,"lastgroup",currentgroup)
//...
call DestroyGroup(currentgroup)
You're storing it and then destroying it. Not gonna work. Simply store a clone of the group as you've already done with currentgroup2. Change the first line to call SetHandleHandle(t,"lastgroup",currentgroup2) and remove the line call DestroyGroup(currentgroup2)
set u3 = null is redundant because you're exiting the loop when the variable is null.

Collapse JASS:
if Distance < 400 and Dur < 4.00 then
    set Distance = Distance + 4.571
endif
    
if Dur > 4.00 then
    set Distance = Distance - 4.571
endif
Should be changed to this:
Collapse JASS:
if Distance < 400 and Dur < 4.00 then
    set Distance = Distance + 4.571
elseif Dur > 4.00 then
    set Distance = Distance - 4.571
endif

Collapse JASS:
call SetHandleReal(t,"Angle",Angle)
call SetHandleReal(t,"Distance",Distance)
call SetHandleReal(t,"Dur",Dur)
    
if Dur >= 10.00 then
    call PauseTimer(t)
    call DestroyTimer(t)
    call KillUnit(u2)
    call FlushHandleLocals(t)
endif
Would be more efficiently written as this:
Collapse JASS:
if Dur >= 10.00 then
    call KillUnit(u2)

    call PauseTimer(t)
    call FlushHandleLocals(t) //You must do this before destroying the timer, else it's flushing a null category
    call DestroyTimer(t)
else
    call SetHandleReal(t,"Angle",Angle)
    call SetHandleReal(t,"Distance",Distance)
    call SetHandleReal(t,"Dur",Dur)
endif

So, all put together it would be this:
Collapse JASS:
function Spiral_Move takes nothing returns nothing
    local timer t = GetExpiredTimer()
    local unit u = GetHandleUnit(t,"TriggerUnit")
    local unit u2 = GetHandleUnit(t,"DummyUnit")
    local real Distance = (GetHandleReal(t,"Distance"))
    local real x = GetUnitX(u)
    local real y = GetUnitY(u)
    local real Dur = (GetHandleReal(t,"Dur") + 0.04)
    local real Angle = (GetHandleReal(t,"Angle") + 7.1)
    local real x2
    local real y2
    local unit u3
    
    local group lastgroup = local group lastgroup = GetHandleGroup(t,"lastgroup")
    local group currentgroup = CreateGroup()
    local group currentgroup2 = CreateGroup()
    set bj_ghoul[111] = u

    call GroupEnumUnitsInRange(currentgroup,x,y,Distance,Filter(function Spiral_Filter))
    call SetHandleHandle(t,"lastgroup",currentgroup2)
    call GroupAddGroup(currentgroup,currentgroup2)
    
        loop
            set u3 = FirstOfGroup(lastgroup)
            exitwhen u3 == null 
                if not(IsUnitInGroup(u3,currentgroup2)) then
                    call UnitRemoveAbility(u3, 'A001') //'A001' being the rawcode of the new spell
                    call SetUnitInvulnerable(u3,false)
                endif
            call GroupRemoveUnit(currentgroup,u3)
            call GroupRemoveUnit(lastgroup,u3)
        endloop

        loop
            set u3 = FirstOfGroup(currentgroup)
            exitwhen u3 == null
                if GetUnitAbilityLevel(u3, 'A001') == 0 then
                        call UnitAddAbility(u3, 'A001')
                        call SetUnitInvulnerable(u3,true)
                endif                                            
                call GroupRemoveUnit(currentgroup,u3)
        endloop
        
    call DestroyGroup(currentgroup)
    call DestroyGroup(lastgroup)
    
    if Distance < 400 and Dur < 4.00 then
        set Distance = Distance + 4.571
    elseif Dur > 4.00 then
        set Distance = Distance - 4.571
    endif    
    
    set x2 = x + Distance * Cos(Angle * bj_DEGTORAD)
    set y2 = y + Distance * Sin(Angle * bj_DEGTORAD)
    
    call SetUnitX(u2,x2)
    call SetUnitY(u2,y2)
    
    if Dur >= 10.00 then
        call KillUnit(u2)

        call PauseTimer(t)
        call FlushHandleLocals(t)
        call DestroyTimer(t)
    else
        call SetHandleReal(t,"Angle",Angle)
        call SetHandleReal(t,"Distance",Distance)
        call SetHandleReal(t,"Dur",Dur)
    endif        
        
    set t = null
    set u = null
    set u2 = null
endfunction

Now, if you were controlling the movement of all projectiles from 1 single timer, you'd do this:
Collapse JASS:
function Spiral_Move takes nothing returns nothing
    local timer t = GetExpiredTimer()
    local unit u = GetHandleUnit(t,"TriggerUnit")
    local unit array u2 // = GetHandleUnit(t,"DummyUnit")
    local real Distance = (GetHandleReal(t,"Distance"))
    local real x = GetUnitX(u)
    local real y = GetUnitY(u)
    local real Dur = (GetHandleReal(t,"Dur") + 0.04)
    local real array Angle // = (GetHandleReal(t,"Angle") + 7.1)
    local real x2
    local real y2
    local unit u3
    local integer i = 0
    local integer i2 = 5
    
    local group lastgroup = GetHandleGroup(t,"lastgroup")
    local group currentgroup = CreateGroup()
    local group currentgroup2 = CreateGroup()

    set bj_ghoul[111] = u

    call GroupEnumUnitsInRange(currentgroup,x,y,Distance,Filter(function Spiral_Filter))
    call SetHandleHandle(t,"lastgroup",currentgroup2)
    call GroupAddGroup(currentgroup,currentgroup2)
    
        loop
            set u3 = FirstOfGroup(lastgroup)
            exitwhen u3 == null 
                if not(IsUnitInGroup(u3,currentgroup2)) then
                    call UnitRemoveAbility(u3, 'A001')
                    call SetUnitInvulnerable(u3,false)
                endif
            call GroupRemoveUnit(currentgroup,u3)
            call GroupRemoveUnit(lastgroup,u3)
        endloop

        loop
            set u3 = FirstOfGroup(currentgroup)
            exitwhen u3 == null
                if GetUnitAbilityLevel(u3, 'A001') == 0 then
                    call UnitAddAbility(u3, 'A001')
                    call SetUnitInvulnerable(u3,true)
                endif                                            
                call GroupRemoveUnit(currentgroup,u3)
        endloop
        
    call DestroyGroup(currentgroup)
    call DestroyGroup(lastgroup)
    
    if Distance < 400 and Dur < 4.00 then
        set Distance = Distance + 4.571
    elseif Dur > 4.00 then
        set Distance = Distance - 4.571
    endif    

    loop
        set i = i+1
        exitwhen i > i2

        set u2[i] = GetHandleUnit(t, "DummyUnit "+I2S(i))
        set Angle[i] = GetHandleReal(t, "Angle "+I2S(i))+7.1
        set x2 = x + Distance * Cos(Angle[i] * bj_DEGTORAD)
        set y2 = y + Distance * Sin(Angle[i] * bj_DEGTORAD)

        call SetUnitX(u2[i],x2)
        call SetUnitY(u2[i],y2)
    endloop

    if Dur >= 10.00 then
        set i = 0
        loop
            set i = i+1
            exitwhen i > i2
            call KillUnit(u2[i])
        endloop

        call PauseTimer(t)
        call FlushHandleLocals(t)
        call DestroyTimer(t)
    else
        set i = 0
        loop
            set i = i+1
            exitwhen i > i2
            call SetHandleReal(t,"Angle "+I2S(i),Angle[i])
        endloop

        call SetHandleReal(t,"Distance",Distance)
        call SetHandleReal(t,"Dur",Dur)
    endif        
        
    set t = null
    set u = null
    set i = 0
    loop
        set i = i+1
        exitwhen i > i2
        set u2[i] = null
    endloop
endfunction




I apologize for any compile errors or typos there might be; I didn't thoroughly check this code. I hope it clears something up for you.
08-21-2007, 03:46 PM#7
Dil999
Ooh, thanks. Ill work on implementing all these immediately. This should also help me get to start coding alot better (my first jass spell with handles and 2nd with timers).