Retrieving a struct using PUI outside scope?

Builder Bob

Live free or don't
Reaction score
249
is it possible its trying to destroy the wrong instance of the struct? this wasn't a problem before adding pui

seeing as you don't even use PUI to retrieve the struct instance in your Execute function, I don't see how that can be the case.
Are you saying that if you use the same code without setting Arrow[d.d] = d, that you don't get the double free errors?

What did your debug messages show by the way?
 

Builder Bob

Live free or don't
Reaction score
249
Try pausing the timer before you release it. There's a bug that can cause a repeating timer to do another run after it's destroyed.
 

cleeezzz

The Undead Ranger.
Reaction score
268
well its not just one more. its infinite rofl. the timer never stops. the screen is flooded with trying to destroy null struct or double free
 

Builder Bob

Live free or don't
Reaction score
249
Unless you give more information, I can't help you I'm afraid.

Do things step by step.
Use debug messages to figure out what is working and what is not in your system. From start to finish.
By that I mean that you need to figure out
  • When each function is being used.
  • When the struct instance is created
  • When the different if then blocks are being entered
  • When the timer is started
  • When the timer is stopped
  • When the struct is destroyed
  • What the different variables are at all these stages -check everything
  • etc...
Don't check everything at once. Begin with the the first code that is being run, and move on from there.

I would also comment out code that is non-essential for the first functions to run at first. Slowly uncomment more and more until you find your problem.

Be thorough
 

cleeezzz

The Undead Ranger.
Reaction score
268
JASS:
library CAS requires CSData,CSSafety,HandyFunctions

globals
    private constant real Start = 50.00   
    private constant real Scale = 1.00            
    private constant real Fly_height = 60.00   
    private constant attacktype A = ATTACK_TYPE_CHAOS
    private constant damagetype D = DAMAGE_TYPE_UNIVERSAL
    private unit Caster = null
endglobals

private function FilterIsEnemyAlive takes nothing returns boolean
    return IsUnitEnemy(GetFilterUnit(), GetOwningPlayer(Caster)) and GetWidgetLife(GetFilterUnit())>0.405
endfunction  

               
//=======================================================================
struct Arrow
    //! runtextmacro PUI()
    unit u
    unit d
    unit a
    real moved
    real cd
    real maxd
    real dmg
    real angle
    real r
    real plx
    real ply
    real bases
    group g = CreateGroup()
    timer t
    integer aid
    integer lvl
    real int
    real next
    boolean spell
    string sfx
    string as
    integer func
    real csd
       
    static method create takes integer ut, unit u, real cx, real cy, real tx, real ty, real period, real r, real moved, real maxd, real dmg, integer aid, string as, integer lvl, real int, string sfx, integer func returns Arrow
        local integer index
        local item    indexItem
        local integer i
        local real angle = AngleXY(cx,cy,tx,ty)
        local unit arrow = CreateUnit(GetOwningPlayer(u),ut, PolarProjectionX (cx, Start, angle), PolarProjectionY (cy, Start, angle) , Rad2Deg(angle))
        local Arrow d = Arrow.allocate()
        set Arrow[arrow] = d  // THIS LINE
        set d.t = NewTimer()
        set d.u = u
        set d.cd = Start
        set d.csd = 0
        set d.maxd = maxd
        set d.angle = angle
        set d.dmg = dmg
        set d.r = r
        set d.d = arrow
        set d.plx = GetUnitX(d.d)
        set d.ply = GetUnitY(d.d)
        call GroupAddUnit(Arrows,d.d)
        call SetUnitMoveSpeed(d.d, moved)
        set d.bases = moved
        set index = 0
            loop
                exitwhen index > 5
                set indexItem = UnitItemInSlot(u, index)
                    if indexItem != null then
                        if GetItemTypeId(indexItem) == 'I00G' or GetItemTypeId(indexItem) == 'I00M' then
                            set i = GetRandomInt(1, 100)
                                if i <= 15 then
                                    call UnitAddItemById(d.d,'I00V')
                                endif
                        endif
                        if GetItemTypeId(indexItem) == 'I00J' or GetItemTypeId(indexItem) == 'I00M' then
                            set i = GetRandomInt(1 , 100)
                                if i <= 15 then
                                    call UnitAddItemById(d.d,'I00X')
                                endif
                        endif
                        if GetItemTypeId(indexItem) == 'I00F' or GetItemTypeId(indexItem) == 'I00M' then
                            set i = GetRandomInt(1 , 100)
                                if i <= 17 then
                                    call UnitAddItemById(d.d, 'I00W')
                                endif
                        endif
                        if GetItemTypeId(indexItem) == 'I007' then
                            set i = GetRandomInt(1 , 100)
                                if i <= 10 then
                                    call UnitAddItemById(d.d, 'I007')
                                endif
                        endif
                        if GetItemTypeId(indexItem) == 'I006' then
                            set i = GetRandomInt(1 , 100)
                                if i <= 15 then
                                    call UnitAddItemById(d.d, 'I006')
                                endif
                        endif
                        if GetItemTypeId(indexItem) == 'I008' then
                            set i = GetRandomInt(1 , 100)
                                if i <= 20 then
                                    call UnitAddItemById(d.d, 'I008')
                                endif
                        endif
                    endif
                set index = index + 1
            endloop
        set indexItem = null
        set d.moved = moved
        set Caster = u
            if aid != 0 and sfx != null then
                set d.spell = true
                    if aid != 0 then
                        set d.aid = aid
                        set d.as = as
                        set d.int = int
                        set d.next = int
                        set d.a = CreateUnit(GetOwningPlayer(u),'h000',cx,cy,0)
                        call UnitAddAbility(d.a,aid)
                        call SetUnitAbilityLevel(d.a,aid,lvl)
                        call UnitApplyTimedLife(d.a,'BTLF',60)
                    else
                        set d.aid = 0
                    endif
                    if sfx != null then
                        set d.sfx = sfx
                    else
                        set d.sfx = null
                    endif
            else
                set d.spell = false
            endif
                if func == 1 then
                    if GetUnitState( u, UNIT_STATE_MANA) >= 1 then
                        call SetUnitState( u, UNIT_STATE_MANA, GetUnitState( u, UNIT_STATE_MANA) - 1)
                        call SetUnitMoveSpeed(d.d, moved - 7)
                        set d.bases = moved - 7
                        set d.func = func
                    else
                        set d.func = 0
                    endif
                else 
                    set d.func = 0
                endif
        call SetUnitPathing(d.d,false)
        call SetUnitScale(d.d,Scale,Scale,Scale)
        call SetUnitFlyHeight(d.d,Fly_height,0.00)
                
        call TimerStart(d.t,period,true,function Arrow.Execute)
        call SetCSData(d.t,d)
        
        return Arrow[d.d]
    endmethod
    
    static method Execute takes nothing returns nothing
        local real x
        local real y
        local real x2
        local real y2
        local real a
        local unit u
        local group g = CreateGroup()
        local real dist
        local real rdist
        local Arrow d = GetCSData(GetExpiredTimer())
        
        set x = GetUnitX(d.d)
        set y = GetUnitY(d.d)
        
        set rdist = DistanceXY( x, y, d.plx, d.ply)
            if d.moved < d.bases then
                call SetUnitMoveSpeed(d.d, GetUnitMoveSpeed(d.d) + 0.3)
            endif
        set d.cd = d.cd + rdist
        set d.plx = x
        set d.ply = y
        
            if d.cd >= d.maxd or d.d == null then
                set u = null
                call DestroyGroup(g)
                set g = null
                call d.destroy()
                return
            endif

  
        
        set d.angle =  Deg2Rad(GetUnitFacing(d.d))
        set x = PolarProjectionX(x, d.moved, d.angle)
        set y = PolarProjectionY(y, d.moved, d.angle)
        
            if x > GMaxX or x < GMinX or y > GMaxY or y < GMinY then
                call RemoveUnit(d.d)
                set d.d = null
                set u = null
                call DestroyGroup(g)
                set g = null
                call d.destroy()
                return
            endif
            
        call SetUnitX(d.d, x)
        call SetUnitY(d.d, y)
        call GroupEnumUnitsInRange(g,x,y,d.r,Condition(function FilterIsEnemyAlive))
            
            loop
                set u = FirstOfGroup(g)
                exitwhen u == null
                    if not(IsUnitInGroup(u,d.g)) then
                        call GroupAddUnit(d.g,u)
                        call UnitDamageTarget(d.d,u,d.dmg,false,false,A,D,null)
                        
                    endif 
                call GroupRemoveUnit(g,u)                
            endloop
        call DestroyGroup(g)
        set g = null

            if GetUnitState(d.d, UNIT_STATE_LIFE) > .405 then
                if d.spell == true then
                    set d.csd = d.csd + rdist
                        if d.csd >= d.int then
                            set d.csd = 0
                                if d.aid != 0 then
                                    call IssuePointOrder(d.a, d.as, x, y)
                                endif
                                if d.sfx != null then
                                    call DestroyEffect(AddSpecialEffect( d.sfx, x, y ))
                                endif
                        endif
                endif
            endif
            if d.func == 1 then
                set g = CreateGroup()
                call GroupEnumUnitsInRange(g,x,y,600,Condition(function FilterIsEnemyAlive))
                call GroupAddGroupAdv(Arrows, g)
                loop
                    set u = FirstOfGroup(g)
                    if u == d.d then
                        call GroupRemoveUnit(g,u)
                        set u = FirstOfGroup(g)
                    endif
                    exitwhen u == null
                    set x2 = GetUnitX(u)
                    set y2 = GetUnitY(u)
                    set dist = DistanceXY(x,y,x2,y2)
                        if dist <= 600 then
                            set a = AngleXY(x2,y2,x,y)
                                if 400/dist <= dist then
                                    set x2 = SafeX(PolarProjectionX(x2,(13200/dist*d.moved),a))
                                    set y2 = SafeY(PolarProjectionY(y2,(13200/dist*d.moved),a))
                                endif
                            call SetUnitX(u,x2)
                            call SetUnitY(u,y2)
                        endif
                    call GroupRemoveUnit(g,u)
                endloop
                call DestroyGroup(g)
                set g = null
            endif                                   
    endmethod
    
    method onDestroy takes nothing returns nothing
        call RemoveUnit(.d)
        call RemoveUnit(.a)
        set .u = null
        set .d = null
        set .a = null
        call GroupRemoveUnit(Arrows,.d)
        call GroupClear(.g)
        call DestroyGroup(.g)
        set .g = null
        call ReleaseTimer(.t)
        set .spell = false
        set .func = 0

    endmethod
endstruct

public function SA takes integer ut, unit u, real cx, real cy, real tx, real ty, real period, real r, real moved, real maxd, real dmg, integer aid, string as, integer lvl, real int, string sfx, integer func returns nothing    
    call Arrow.create(ut,u,cx,cy,tx,ty,period,r,moved,maxd,dmg,aid,as,lvl,int,sfx,func)
endfunction  

endlibrary


done. theres one comment in the code, adding that pui function messes it up, if that line is removed, it works 100%
 

Builder Bob

Live free or don't
Reaction score
249
Great, then I know what's wrong. I forgot about it since I have never used PUI, but PUI actually recycles the structs automatically when the unit handle is recycled.

What you have to do is call .release() instead of .destroy() for the struct instances you want to destroy. This way PUI will know it doesn't have to destroy the instances. I guess that's what caused the double free errors.
 

cleeezzz

The Undead Ranger.
Reaction score
268
thanks that did the trick...damn i should have known, my other pui struct used release -.-

ill rep you as soon as i can.
 

Builder Bob

Live free or don't
Reaction score
249
I'm glad we managed to solve this. I was as blind as you, so don't worry.

Great debugging on your part. Knowing which line did the difference between no errors and errors was what lead me to the answer. I would have never thought of it otherwise.

Look at the bright side. If this ever happens to you again, you'll be sure to recognize what's really going on.
 

cleeezzz

The Undead Ranger.
Reaction score
268
haha.. came across another problem..also related to PUI usage. but this one has REALLY stumped me.

using the CAS library posted before(with the pui fix in it)

i found it easy to implement the struct into other codes so i can tell how far, how much dmg the arrow does and stuff like. so i made a clone skill, it splits the arrow into 3, the middle one does regular dmg, the other 2 do a factor of the dmg. not hard. code first, then ill explain what happens.

JASS:
scope Image initializer Init

//=======================================================================
private function Actions takes nothing returns nothing
    local unit u = GetTriggerUnit()
    local group g = CreateGroup()
    local unit tu
    local integer i
    local real x
    local real y
    local real tx
    local real ty
    local real txol
    local real tyol
    local real txor
    local real tyor
    local real end
    local real Angle
    local real damage
    local Arrow e
    set i = GetUnitAbilityLevel(u,GetSpellAbilityId())

    call GroupAddGroupAdv(Arrows,g)
        loop
            set tu = FirstOfGroup(g)
            exitwhen tu == null
                if GetOwningPlayer(tu) == GetOwningPlayer(u) then
                    set e = Arrow[tu]
                    set x = GetUnitX(tu)
                    set y = GetUnitY(tu)
                    set end = e.maxd - e.cd
                    set tx = PolarProjectionX(x,end,Deg2Rad(GetUnitFacing(tu)))
                    set ty = PolarProjectionY(y,end,Deg2Rad(GetUnitFacing(tu)))
                    set Angle = AngleXY(x,y,tx,ty)
                    set txol = PolarProjectionX(tx,350,(Angle + 0.34906))
                    set tyol = PolarProjectionY(ty,350,(Angle + 0.34906))
                    set txor = PolarProjectionX(tx,350,(Angle - 0.34906))
                    set tyor = PolarProjectionY(ty,350,(Angle - 0.34906))
                    set damage = e.dmg * (i * .20)
                    call CAS_SA(GetUnitTypeId(tu),u,x,y,txol,tyol,0.03,e.r,e.moved,end,damage,e.aid,e.as,e.aidlevel,e.int,e.sfx,e.func)
                    call CAS_SA(GetUnitTypeId(tu),u,x,y,txor,tyor,0.03,e.r,e.moved,end,damage,e.aid,e.as,e.aidlevel,e.int,e.sfx,e.func)                
                    
                    set e = 0
                endif
            call GroupRemoveUnit(g,tu)
        endloop
    set u = null
    call DestroyGroup(g)
    set g = null
endfunction


//=======================================================================
private function Conditions takes nothing returns boolean
    return GetSpellAbilityId() == 'A024'
endfunction


//=======================================================================
private function Init takes nothing returns nothing
    local trigger trig = CreateTrigger()   
    call TriggerRegisterAnyUnitEventBJ(trig,EVENT_PLAYER_UNIT_SPELL_EFFECT)
    call TriggerAddCondition(trig,Condition(function Conditions))
    call TriggerAddAction(trig,function Actions)
endfunction

endscope


as you can see, i set e to the data, and use it, everything works except the calling of CAS near the bottom, i call it twice, its not that it doesn't work, its bugging somehow.

well anyway, heres what a regular shoot arrow looks like..

JASS:
call CAS_SA('h00J',u,cx,cy,tx,ty,0.03,60,33,MaxDist(i),Damage(i),0,null,0,0,null,grav[GetPlayerId(GetOwningPlayer(u))])


the 0 and the nulls near the end of the function tell the code that "i dont want any special effects or abilities to trail the arrow" for example. a fire trail.

which is shown here.

JASS:
call CAS_SA('h00K',d.u,d.cx,d.cy,d.tx,d.ty,0.03,150,33,MaxDist(d.i),Damage2(d.i),'A00A',"flamestrike",d.i,250.00,"Abilities\\Spells\\Human\\MarkOfChaos\\MarkOfChaosTarget.mdl",0)


yes well, if you look at my image, its supposed to mimic the previous arrow. hence image.

JASS:
call CAS_SA(GetUnitTypeId(tu),u,x,y,txol,tyol,0.03,e.r,e.moved,end,damage,e.aid,e.as,e.aidlevel,e.int,e.sfx,e.func)
as you can see, i used e.r (radius), e.moved (distance), e.aid (spell ability id, e.aidlevel (level of aid), e.int (interval of sfx and ability), e.sfx(sfx path)

so... as you can see its supposed to copy the arrow, if it has a trail, the clones have a trail too. heres where the problem starts, i shoot an arrow without trail, and clone it, perfect, it works. shoot a trail arrow and clone it, pefect, also works, NOW, i shoot an arrow without trail, yet the trail still appears???, its getting the wrong struct data if the original didn't have the trail but the clones have it. whats going on? (sorry you had to read through all this) =.=
 

Builder Bob

Live free or don't
Reaction score
249
It is not coming from the wrong struct instance. It's just leftovers from a previous instance that used the same index as the cloned arrow. It's easy to fix. All you need to do is set all variables to something when you create the struct. If you don't the variables will still be what they were set to when they were used last.

Add this and any other variables you need to set to a default value to your create method.

JASS:
set d.aid = 0
set d.as = ""
etc.
 

cleeezzz

The Undead Ranger.
Reaction score
268
i forgot to say, i changed CAS a little bit

JASS:
if aid != 0 or sfx != null then
                set d.spell = true
                    if aid != 0 then
                        set d.aid = aid
                        set d.as = as
                        set d.int = int
                        set d.next = int
                        set d.aidlevel = lvl
                        set d.a = CreateUnit(GetOwningPlayer(u),'h000',cx,cy,0)
                        call UnitAddAbility(d.a,aid)
                        call SetUnitAbilityLevel(d.a,aid,lvl)
                        call UnitApplyTimedLife(d.a,'BTLF',60)
                    else
                        set d.aid = 0
                        set d.as = null
                        set d.int = 0
                    endif
                    if sfx != null then
                        set d.sfx = sfx
                    else
                        set d.sfx = null
                    endif


so i did initialize it. still does the same thing
 

Builder Bob

Live free or don't
Reaction score
249
What you showed me in your last post is not enough. If aid == 0 and sfx == null your variables will be whatever they were in the last instance unless you set them earlier in the method.

would you mind posting the whole CAS?
 

cleeezzz

The Undead Ranger.
Reaction score
268
okay.

JASS:
library CAS requires CSData,CSSafety,HandyFunctions

globals
    private constant real Start = 50.00   
    private constant real Scale = 1.00            
    private constant real Fly_height = 60.00   
    private constant attacktype A = ATTACK_TYPE_CHAOS
    private constant damagetype D = DAMAGE_TYPE_UNIVERSAL
    private unit Caster = null
endglobals

private function FilterIsEnemyAlive takes nothing returns boolean
    return IsUnitEnemy(GetFilterUnit(), GetOwningPlayer(Caster)) and GetWidgetLife(GetFilterUnit())>0.405
endfunction  

               
//=======================================================================
struct Arrow
    //! runtextmacro PUI()
    unit u
    unit d
    unit a
    real moved
    real cd
    real maxd
    real dmg
    real angle
    real r
    real plx
    real ply
    real bases
    group g = CreateGroup()
    timer t
    integer aid
    integer lvl
    real int
    real next
    boolean spell
    string sfx
    string as
    integer func
    real csd
    integer aidlevel
       
    static method create takes integer ut, unit u, real cx, real cy, real tx, real ty, real period, real r, real moved, real maxd, real dmg, integer aid, string as, integer lvl, real int, string sfx, integer func returns Arrow
        local integer index
        local item    indexItem
        local integer i
        local real angle = AngleXY(cx,cy,tx,ty)
        local unit arrow = CreateUnit(GetOwningPlayer(u),ut, PolarProjectionX (cx, Start, angle), PolarProjectionY (cy, Start, angle) , Rad2Deg(angle))
        local Arrow d = Arrow.allocate()
        set Arrow[arrow] = d
        set d.t = NewTimer()
        set d.u = u
        set d.cd = Start
        set d.csd = 0
        set d.maxd = maxd
        set d.angle = angle
        set d.dmg = dmg
        set d.r = r
        set d.d = arrow
        set d.plx = GetUnitX(d.d)
        set d.ply = GetUnitY(d.d)
        call GroupAddUnit(Arrows,d.d)
        call SetUnitMoveSpeed(d.d, moved)
        set d.bases = moved
        set index = 0
            loop
                exitwhen index > 5
                set indexItem = UnitItemInSlot(u, index)
                    if indexItem != null then
                        if GetItemTypeId(indexItem) == 'I00G' or GetItemTypeId(indexItem) == 'I00M' then
                            set i = GetRandomInt(1, 100)
                                if i <= 15 then
                                    call UnitAddItemById(d.d,'I00V')
                                endif
                        endif
                        if GetItemTypeId(indexItem) == 'I00J' or GetItemTypeId(indexItem) == 'I00M' then
                            set i = GetRandomInt(1 , 100)
                                if i <= 15 then
                                    call UnitAddItemById(d.d,'I00X')
                                endif
                        endif
                        if GetItemTypeId(indexItem) == 'I00F' or GetItemTypeId(indexItem) == 'I00M' then
                            set i = GetRandomInt(1 , 100)
                                if i <= 17 then
                                    call UnitAddItemById(d.d, 'I00W')
                                endif
                        endif
                        if GetItemTypeId(indexItem) == 'I007' then
                            set i = GetRandomInt(1 , 100)
                                if i <= 10 then
                                    call UnitAddItemById(d.d, 'I007')
                                endif
                        endif
                        if GetItemTypeId(indexItem) == 'I006' then
                            set i = GetRandomInt(1 , 100)
                                if i <= 15 then
                                    call UnitAddItemById(d.d, 'I006')
                                endif
                        endif
                        if GetItemTypeId(indexItem) == 'I008' then
                            set i = GetRandomInt(1 , 100)
                                if i <= 20 then
                                    call UnitAddItemById(d.d, 'I008')
                                endif
                        endif
                    endif
                set index = index + 1
            endloop
        set indexItem = null
        set d.moved = moved
        set Caster = u
            if aid != 0 or sfx != null then
                set d.spell = true
                    if aid != 0 then
                        set d.aid = aid
                        set d.as = as
                        set d.int = int
                        set d.next = int
                        set d.aidlevel = lvl
                        set d.a = CreateUnit(GetOwningPlayer(u),'h000',cx,cy,0)
                        call UnitAddAbility(d.a,aid)
                        call SetUnitAbilityLevel(d.a,aid,lvl)
                        call UnitApplyTimedLife(d.a,'BTLF',60)
                    else
                        set d.aid = 0
                        set d.as = null
                        set d.int = 0
                        set d.aidlevel = 0
                    endif
                    if sfx != null then
                        set d.sfx = sfx
                    else
                        set d.sfx = null
                    endif
            else
                set d.spell = false
            endif
                if func == 1 then
                    if GetUnitState( u, UNIT_STATE_MANA) >= 1 then
                        call SetUnitState( u, UNIT_STATE_MANA, GetUnitState( u, UNIT_STATE_MANA) - 1)
                        call SetUnitMoveSpeed(d.d, moved - 7)
                        set d.bases = moved - 7
                        set d.func = func
                    else
                        set d.func = 0
                    endif
                else 
                    set d.func = 0
                endif
        call SetUnitPathing(d.d,false)
        call SetUnitScale(d.d,Scale,Scale,Scale)
        call SetUnitFlyHeight(d.d,Fly_height,0.00)
                
        call TimerStart(d.t,period,true,function Arrow.Execute)
        call SetCSData(d.t,d)
        
        return Arrow[d.d]
    endmethod
    
    static method Execute takes nothing returns nothing
        local real x
        local real y
        local real x2
        local real y2
        local real a
        local unit u
        local group g = CreateGroup()
        local real dist
        local real rdist
        local Arrow d = GetCSData(GetExpiredTimer())
        
        set x = GetUnitX(d.d)
        set y = GetUnitY(d.d)
        set rdist = DistanceXY( x, y, d.plx, d.ply)

        set d.cd = d.cd + rdist
        set d.plx = x
        set d.ply = y
        
            if d.cd >= d.maxd or GetUnitState(d.d,UNIT_STATE_LIFE) < .405 then
                set u = null
                call DestroyGroup(g)
                set g = null
                set d.func = 0
                call d.release()
                return
            endif

  
        
        set d.angle =  Deg2Rad(GetUnitFacing(d.d))
        set x = PolarProjectionX(x, d.moved, d.angle)
        set y = PolarProjectionY(y, d.moved, d.angle)
        
            if x > GMaxX or x < GMinX or y > GMaxY or y < GMinY then
                call RemoveUnit(d.d)
                set d.d = null
                set u = null
                call DestroyGroup(g)
                set g = null
                set d.func = 0
                call d.release()
                return
            endif
            
        call SetUnitX(d.d, x)
        call SetUnitY(d.d, y)
            if d.moved < d.bases then
                set d.moved = d.moved + 0.3
            endif
        call GroupEnumUnitsInRange(g,x,y,d.r,Condition(function FilterIsEnemyAlive))
            
            loop
                set u = FirstOfGroup(g)
                exitwhen u == null
                    if not(IsUnitInGroup(u,d.g)) then
                        call GroupAddUnit(d.g,u)
                        call UnitDamageTarget(d.d,u,d.dmg,false,false,A,D,null)
                        
                    endif 
                call GroupRemoveUnit(g,u)                
            endloop
        call DestroyGroup(g)
        set g = null

            if GetUnitState(d.d, UNIT_STATE_LIFE) > .405 then
                if d.spell == true then
                    set d.csd = d.csd + rdist
                        if d.csd >= d.int then
                            set d.csd = 0
                                if d.aid != 0 then
                                    call IssuePointOrder(d.a, d.as, x, y)
                                endif
                                if d.sfx != null then
                                    call DestroyEffect(AddSpecialEffect( d.sfx, x, y ))
                                endif
                        endif
                endif
            endif
            if d.func == 1 then
                set g = CreateGroup()
                call GroupEnumUnitsInRange(g,x,y,600,Condition(function FilterIsEnemyAlive))
                call GroupAddGroupAdv(Arrows, g)
                loop
                    set u = FirstOfGroup(g)
                    if u == d.d then
                        call GroupRemoveUnit(g,u)
                        set u = FirstOfGroup(g)
                    endif
                    exitwhen u == null
                    set x2 = GetUnitX(u)
                    set y2 = GetUnitY(u)
                    set dist = DistanceXY(x,y,x2,y2)
                        if dist <= 600 then
                            set a = AngleXY(x2,y2,x,y)
                                if 400/dist <= dist then
                                    set x2 = SafeX(PolarProjectionX(x2,(d.moved/(dist/d.moved*2)),a))
                                    set y2 = SafeY(PolarProjectionY(y2,(d.moved/(dist/d.moved*2)),a))
                                endif
                            call SetUnitX(u,x2)
                            call SetUnitY(u,y2)
                        endif
                    call GroupRemoveUnit(g,u)
                endloop
                set u = null
                call DestroyGroup(g)
                set g = null
            endif                                 
    endmethod
    
    method onDestroy takes nothing returns nothing
        call RemoveUnit(.d)
        call RemoveUnit(.a)
        set .u = null
        set .d = null
        set .a = null
        call GroupRemoveUnit(Arrows,.d)
        call GroupClear(.g)
        call DestroyGroup(.g)
        set .g = null
        call ReleaseTimer(.t)
        set .spell = false
        set .func = 0

    endmethod
endstruct

public function SA takes integer ut, unit u, real cx, real cy, real tx, real ty, real period, real r, real moved, real maxd, real dmg, integer aid, string as, integer lvl, real int, string sfx, integer func returns nothing    
    call Arrow.create(ut,u,cx,cy,tx,ty,period,r,moved,maxd,dmg,aid,as,lvl,int,sfx,func)
endfunction  

endlibrary
 

Builder Bob

Live free or don't
Reaction score
249
Now, this is not guaranteed to work, but I think you can do the correct adjustments.

JASS:
library CAS requires CSData,CSSafety,HandyFunctions

globals
    private constant real Start = 50.00   
    private constant real Scale = 1.00            
    private constant real Fly_height = 60.00   
    private constant attacktype A = ATTACK_TYPE_CHAOS
    private constant damagetype D = DAMAGE_TYPE_UNIVERSAL
    private unit Caster = null
endglobals

private function FilterIsEnemyAlive takes nothing returns boolean
    return IsUnitEnemy(GetFilterUnit(), GetOwningPlayer(Caster)) and GetWidgetLife(GetFilterUnit())>0.405
endfunction  

               
//=======================================================================
struct Arrow
    //! runtextmacro PUI()
    unit u
    unit d
    unit a
    real moved
    real cd
    real maxd
    real dmg
    real angle
    real r
    real plx
    real ply
    real bases
    //moved the CreateGroup() to the create method
    group g// = CreateGroup() this will only be called the first time the instance is used. Not every time you run the create method.
    timer t
    integer aid
    integer lvl
    real int
    real next
    boolean spell
    string sfx
    string as
    integer func
    real csd
    integer aidlevel
       
    static method create takes integer ut, unit u, real cx, real cy, real tx, real ty, real period, real r, real moved, real maxd, real dmg, integer aid, string as, integer lvl, real int, string sfx, integer func returns Arrow
        local integer index
        local item    indexItem
        local integer i
        local real angle = AngleXY(cx,cy,tx,ty)
        local unit arrow = CreateUnit(GetOwningPlayer(u),ut, PolarProjectionX (cx, Start, angle), PolarProjectionY (cy, Start, angle) , Rad2Deg(angle))
        local Arrow d = Arrow.allocate()
        set Arrow[arrow] = d
        set d.t = NewTimer()
        set d.u = u
        set d.cd = Start
        set d.csd = 0
        set d.maxd = maxd
        set d.angle = angle
        set d.dmg = dmg
        set d.r = r
        set d.d = arrow
        set d.plx = GetUnitX(d.d)
        set d.ply = GetUnitY(d.d)
        call GroupAddUnit(Arrows,d.d)
        call SetUnitMoveSpeed(d.d, moved)
        set d.bases = moved
        //added
        set d.a = null
        set d.moved = 0.
        set d.g = CreateGroup()
        set d.aid = 0
        set d.lvl = 0
        set d.int = 0.
        set d.next = 0.
        set d.spell = false
        set d.sfx = ""
        set d.as = ""
        set d.func = 0
        set d.aidlevel = 0
        //added end
        set index = 0
            loop
                exitwhen index > 5
                set indexItem = UnitItemInSlot(u, index)
                    if indexItem != null then
                        if GetItemTypeId(indexItem) == 'I00G' or GetItemTypeId(indexItem) == 'I00M' then
                            set i = GetRandomInt(1, 100)
                                if i <= 15 then
                                    call UnitAddItemById(d.d,'I00V')
                                endif
                        endif
                        if GetItemTypeId(indexItem) == 'I00J' or GetItemTypeId(indexItem) == 'I00M' then
                            set i = GetRandomInt(1 , 100)
                                if i <= 15 then
                                    call UnitAddItemById(d.d,'I00X')
                                endif
                        endif
                        if GetItemTypeId(indexItem) == 'I00F' or GetItemTypeId(indexItem) == 'I00M' then
                            set i = GetRandomInt(1 , 100)
                                if i <= 17 then
                                    call UnitAddItemById(d.d, 'I00W')
                                endif
                        endif
                        if GetItemTypeId(indexItem) == 'I007' then
                            set i = GetRandomInt(1 , 100)
                                if i <= 10 then
                                    call UnitAddItemById(d.d, 'I007')
                                endif
                        endif
                        if GetItemTypeId(indexItem) == 'I006' then
                            set i = GetRandomInt(1 , 100)
                                if i <= 15 then
                                    call UnitAddItemById(d.d, 'I006')
                                endif
                        endif
                        if GetItemTypeId(indexItem) == 'I008' then
                            set i = GetRandomInt(1 , 100)
                                if i <= 20 then
                                    call UnitAddItemById(d.d, 'I008')
                                endif
                        endif
                    endif
                set index = index + 1
            endloop
        set indexItem = null
        set d.moved = moved
        set Caster = u
            if aid != 0 or sfx != null then
                set d.spell = true
                    if aid != 0 then
                        set d.aid = aid
                        set d.as = as
                        set d.int = int
                        set d.next = int
                        set d.aidlevel = lvl
                        set d.a = CreateUnit(GetOwningPlayer(u),'h000',cx,cy,0)
                        call UnitAddAbility(d.a,aid)
                        call SetUnitAbilityLevel(d.a,aid,lvl)
                        call UnitApplyTimedLife(d.a,'BTLF',60)
                    else
                        set d.aid = 0
                        set d.as = null
                        set d.int = 0
                        set d.aidlevel = 0
                    endif
                    if sfx != null then
                        set d.sfx = sfx
                    else
                        set d.sfx = null
                    endif
            else
                set d.spell = false
            endif
                if func == 1 then
                    if GetUnitState( u, UNIT_STATE_MANA) >= 1 then
                        call SetUnitState( u, UNIT_STATE_MANA, GetUnitState( u, UNIT_STATE_MANA) - 1)
                        call SetUnitMoveSpeed(d.d, moved - 7)
                        set d.bases = moved - 7
                        set d.func = func
                    else
                        set d.func = 0
                    endif
                else 
                    set d.func = 0
                endif
        call SetUnitPathing(d.d,false)
        call SetUnitScale(d.d,Scale,Scale,Scale)
        call SetUnitFlyHeight(d.d,Fly_height,0.00)
                
        call TimerStart(d.t,period,true,function Arrow.Execute)
        call SetCSData(d.t,d)
        
        return Arrow[d.d]
    endmethod
    
    static method Execute takes nothing returns nothing
        local real x
        local real y
        local real x2
        local real y2
        local real a
        local unit u
        local group g = CreateGroup()
        local real dist
        local real rdist
        local Arrow d = GetCSData(GetExpiredTimer())
        
        set x = GetUnitX(d.d)
        set y = GetUnitY(d.d)
        set rdist = DistanceXY( x, y, d.plx, d.ply)

        set d.cd = d.cd + rdist
        set d.plx = x
        set d.ply = y
        
            if d.cd >= d.maxd or GetUnitState(d.d,UNIT_STATE_LIFE) < .405 then
                set u = null
                call DestroyGroup(g)
                set g = null
                set d.func = 0
                call d.release()
                return
            endif

  
        
        set d.angle =  Deg2Rad(GetUnitFacing(d.d))
        set x = PolarProjectionX(x, d.moved, d.angle)
        set y = PolarProjectionY(y, d.moved, d.angle)
        
            if x > GMaxX or x < GMinX or y > GMaxY or y < GMinY then
                call RemoveUnit(d.d)
                set d.d = null
                set u = null
                call DestroyGroup(g)
                set g = null
                set d.func = 0
                call d.release()
                return
            endif
            
        call SetUnitX(d.d, x)
        call SetUnitY(d.d, y)
            if d.moved < d.bases then
                set d.moved = d.moved + 0.3
            endif
        call GroupEnumUnitsInRange(g,x,y,d.r,Condition(function FilterIsEnemyAlive))
            
            loop
                set u = FirstOfGroup(g)
                exitwhen u == null
                    if not(IsUnitInGroup(u,d.g)) then
                        call GroupAddUnit(d.g,u)
                        call UnitDamageTarget(d.d,u,d.dmg,false,false,A,D,null)
                        
                    endif 
                call GroupRemoveUnit(g,u)                
            endloop
        call DestroyGroup(g)
        set g = null

            if GetUnitState(d.d, UNIT_STATE_LIFE) > .405 then
                if d.spell == true then
                    set d.csd = d.csd + rdist
                        if d.csd >= d.int then
                            set d.csd = 0
                                if d.aid != 0 then
                                    call IssuePointOrder(d.a, d.as, x, y)
                                endif
                                if d.sfx != null then
                                    call DestroyEffect(AddSpecialEffect( d.sfx, x, y ))
                                endif
                        endif
                endif
            endif
            if d.func == 1 then
                set g = CreateGroup()
                call GroupEnumUnitsInRange(g,x,y,600,Condition(function FilterIsEnemyAlive))
                call GroupAddGroupAdv(Arrows, g)
                loop
                    set u = FirstOfGroup(g)
                    if u == d.d then
                        call GroupRemoveUnit(g,u)
                        set u = FirstOfGroup(g)
                    endif
                    exitwhen u == null
                    set x2 = GetUnitX(u)
                    set y2 = GetUnitY(u)
                    set dist = DistanceXY(x,y,x2,y2)
                        if dist <= 600 then
                            set a = AngleXY(x2,y2,x,y)
                                if 400/dist <= dist then
                                    set x2 = SafeX(PolarProjectionX(x2,(d.moved/(dist/d.moved*2)),a))
                                    set y2 = SafeY(PolarProjectionY(y2,(d.moved/(dist/d.moved*2)),a))
                                endif
                            call SetUnitX(u,x2)
                            call SetUnitY(u,y2)
                        endif
                    call GroupRemoveUnit(g,u)
                endloop
                set u = null
                call DestroyGroup(g)
                set g = null
            endif                                 
    endmethod
    
    method onDestroy takes nothing returns nothing
        call RemoveUnit(.d)
        call RemoveUnit(.a)
        set .u = null
        set .d = null
        set .a = null
        call GroupRemoveUnit(Arrows,.d)
        call GroupClear(.g)
        call DestroyGroup(.g)
        set .g = null
        call ReleaseTimer(.t)
        set .spell = false
        set .func = 0

    endmethod
endstruct

public function SA takes integer ut, unit u, real cx, real cy, real tx, real ty, real period, real r, real moved, real maxd, real dmg, integer aid, string as, integer lvl, real int, string sfx, integer func returns nothing    
    call Arrow.create(ut,u,cx,cy,tx,ty,period,r,moved,maxd,dmg,aid,as,lvl,int,sfx,func)
endfunction  

endlibrary
 

cleeezzz

The Undead Ranger.
Reaction score
268
haha thanks. it worked

and if possible, why is it still leaking, updated again.

JASS:
library CAS requires CSData,CSSafety,HandyFunctions

globals
    private constant real Start = 50.00   
    private constant real Scale = 1.00            
    private constant real Fly_height = 60.00   
    private constant attacktype A = ATTACK_TYPE_CHAOS
    private constant damagetype D = DAMAGE_TYPE_UNIVERSAL
    private unit Caster = null
endglobals

private function FilterIsEnemyAlive takes nothing returns boolean
    return IsUnitEnemy(GetFilterUnit(), GetOwningPlayer(Caster)) and GetWidgetLife(GetFilterUnit())>0.405
endfunction  

               
//=======================================================================
struct Arrow
    //! runtextmacro PUI()
    unit u
    unit d
    unit a
    real moved
    real cd
    real maxd
    real dmg
    real angle
    real r
    real plx
    real ply
    real bases
    group g
    timer t
    integer aid
    integer lvl
    real int
    real next
    boolean spell
    string sfx
    string as
    integer func
    real csd
    integer aidlevel
       
    static method create takes integer ut, unit u, real cx, real cy, real tx, real ty, real period, real r, real moved, real maxd, real dmg, integer aid, string as, integer lvl, real int, string sfx, integer func returns Arrow
        local integer index
        local item    indexItem
        local integer i
        local real angle = AngleXY(cx,cy,tx,ty)
        local unit arrow = CreateUnit(GetOwningPlayer(u),ut, PolarProjectionX (cx, Start, angle), PolarProjectionY (cy, Start, angle) , Rad2Deg(angle))
        local Arrow d = Arrow.allocate()
        set Arrow[arrow] = d
        set d.t = NewTimer()
        set d.u = u
        set d.cd = Start
        set d.csd = 0
        set d.maxd = maxd
        set d.angle = angle
        set d.dmg = dmg
        set d.r = r
        set d.d = arrow
        set d.plx = GetUnitX(d.d)
        set d.ply = GetUnitY(d.d)
        call GroupAddUnit(Arrows,d.d)
        call SetUnitMoveSpeed(d.d, moved)
        set d.bases = moved
        set d.a = null
        set d.moved = 0
        set d.aid = 0
        set d.lvl = 0
        set d.int = 0
        set d.next = 0
        set d.spell = false
        set d.sfx = null
        set d.as = null
        set d.func = 0
        set d.aidlevel = 0

        set index = 0
            loop
                exitwhen index > 5
                set indexItem = UnitItemInSlot(u, index)
                    if indexItem != null then
                        if GetItemTypeId(indexItem) == 'I00G' or GetItemTypeId(indexItem) == 'I00M' then
                            set i = GetRandomInt(1, 100)
                                if i <= 15 then
                                    call UnitAddItemById(d.d,'I00V')
                                endif
                        endif
                        if GetItemTypeId(indexItem) == 'I00J' or GetItemTypeId(indexItem) == 'I00M' then
                            set i = GetRandomInt(1 , 100)
                                if i <= 15 then
                                    call UnitAddItemById(d.d,'I00X')
                                endif
                        endif
                        if GetItemTypeId(indexItem) == 'I00F' or GetItemTypeId(indexItem) == 'I00M' then
                            set i = GetRandomInt(1 , 100)
                                if i <= 17 then
                                    call UnitAddItemById(d.d, 'I00W')
                                endif
                        endif
                        if GetItemTypeId(indexItem) == 'I007' then
                            set i = GetRandomInt(1 , 100)
                                if i <= 10 then
                                    call UnitAddItemById(d.d, 'I007')
                                endif
                        endif
                        if GetItemTypeId(indexItem) == 'I006' then
                            set i = GetRandomInt(1 , 100)
                                if i <= 15 then
                                    call UnitAddItemById(d.d, 'I006')
                                endif
                        endif
                        if GetItemTypeId(indexItem) == 'I008' then
                            set i = GetRandomInt(1 , 100)
                                if i <= 20 then
                                    call UnitAddItemById(d.d, 'I008')
                                endif
                        endif
                    endif
                set index = index + 1
            endloop
        set indexItem = null
        set d.moved = moved
        set Caster = u
            if aid != 0 or sfx != null then
                set d.spell = true
                    if aid != 0 then
                        set d.aid = aid
                        set d.as = as
                        set d.int = int
                        set d.next = int
                        set d.aidlevel = lvl
                        set d.a = CreateUnit(GetOwningPlayer(u),'h000',cx,cy,0)
                        call UnitAddAbility(d.a,aid)
                        call SetUnitAbilityLevel(d.a,aid,lvl)
                        call UnitApplyTimedLife(d.a,'BTLF',60)
                    else
                        set d.aid = 0
                        set d.as = null
                        set d.int = 0
                        set d.aidlevel = 0
                    endif
                    if sfx != null then
                        set d.sfx = sfx
                    else
                        set d.sfx = null
                    endif
            else
                set d.spell = false
            endif
                if func == 1 then
                    if GetUnitState( u, UNIT_STATE_MANA) >= 1 then
                        call SetUnitState( u, UNIT_STATE_MANA, GetUnitState( u, UNIT_STATE_MANA) - 1)
                        call SetUnitMoveSpeed(d.d, moved - 7)
                        set d.bases = moved - 7
                        set d.func = func
                    else
                        set d.func = 0
                    endif
                else 
                    set d.func = 0
                endif
        call SetUnitPathing(d.d,false)
        call SetUnitScale(d.d,Scale,Scale,Scale)
        call SetUnitFlyHeight(d.d,Fly_height,0.00)
                
        call TimerStart(d.t,period,true,function Arrow.Execute)
        call SetCSData(d.t,d)
        set arrow = null
        
        return Arrow[d.d]
    endmethod
    
    static method Execute takes nothing returns nothing
        local real x
        local real y
        local real x2
        local real y2
        local real a
        local unit u
        local group g
        local real dist
        local real rdist
        local Arrow d = GetCSData(GetExpiredTimer())
        
        set x = GetUnitX(d.d)
        set y = GetUnitY(d.d)
        set rdist = DistanceXY( x, y, d.plx, d.ply)

        set d.cd = d.cd + rdist
        set d.plx = x
        set d.ply = y
        
            if d.cd >= d.maxd or GetUnitState(d.d,UNIT_STATE_LIFE) < .405 then
                set d.func = 0
//if you compare to the previous codes, i removed a bunch of stuff from here mainly because, i was nulling variables that were already null. and destroying a group that wasnt even used
                call d.release()
                return
            endif

  
        
        set d.angle =  Deg2Rad(GetUnitFacing(d.d))
        set x = PolarProjectionX(x, d.moved, d.angle)
        set y = PolarProjectionY(y, d.moved, d.angle)
        
            if x > GMaxX or x < GMinX or y > GMaxY or y < GMinY then
                set d.func = 0
                call d.release()
                return
            endif
            
        call SetUnitX(d.d, x)
        call SetUnitY(d.d, y)
            if d.moved < d.bases then
                set d.moved = d.moved + 0.3
            endif
        set g = CreateGroup()
        call GroupEnumUnitsInRange(g,x,y,d.r,Condition(function FilterIsEnemyAlive))
            
            loop
                set u = FirstOfGroup(g)
                exitwhen u == null
                    if not(IsUnitInGroup(u,d.g)) then
                        call GroupAddUnit(d.g,u)
                        call UnitDamageTarget(d.d,u,d.dmg,false,false,A,D,null)
                        
                    endif 
                call GroupRemoveUnit(g,u)                
            endloop
        call DestroyGroup(g)
        set g = null

            if GetUnitState(d.d, UNIT_STATE_LIFE) > .405 then
                if d.spell == true then
                    set d.csd = d.csd + rdist
                        if d.csd >= d.int then
                            set d.csd = 0
                                if d.aid != 0 then
                                    call IssuePointOrder(d.a, d.as, x, y)
                                endif
                                if d.sfx != null then
                                    call DestroyEffect(AddSpecialEffect( d.sfx, x, y ))
                                endif
                        endif
                endif
            endif
            if d.func == 1 then
                set g = CreateGroup()
                call GroupEnumUnitsInRange(g,x,y,600,Condition(function FilterIsEnemyAlive))
                call GroupAddGroupAdv(Arrows, g)
                loop
                    set u = FirstOfGroup(g)
                        if u == d.d then
                            call GroupRemoveUnit(g,u)
                            set u = FirstOfGroup(g)
                        endif
                    exitwhen u == null
                    set x2 = GetUnitX(u)
                    set y2 = GetUnitY(u)
                    set dist = DistanceXY(x,y,x2,y2)
                        if dist <= 600 then
                            set a = AngleXY(x2,y2,x,y)
                                if 400/dist <= dist then
                                    set x2 = SafeX(PolarProjectionX(x2,(d.moved/(dist/d.moved*2)),a))
                                    set y2 = SafeY(PolarProjectionY(y2,(d.moved/(dist/d.moved*2)),a))
                                endif
                            call SetUnitX(u,x2)
                            call SetUnitY(u,y2)
                        endif
                    call GroupRemoveUnit(g,u)
                endloop
                set u = null
                call DestroyGroup(g)
                set g = null
            endif                                 
    endmethod
    
    method onDestroy takes nothing returns nothing
        call RemoveUnit(.d)
        call RemoveUnit(.a)
        set .u = null
        set .d = null
        set .a = null
        call GroupRemoveUnit(Arrows,.d)
        call GroupClear(.g)
        call DestroyGroup(.g)
        set .g = null
        call ReleaseTimer(.t)
        set .spell = false
        set .func = 0
        set .sfx = null
        set .as = null

    endmethod
endstruct

public function SA takes integer ut, unit u, real cx, real cy, real tx, real ty, real period, real r, real moved, real maxd, real dmg, integer aid, string as, integer lvl, real int, string sfx, integer func returns nothing    
    call Arrow.create(ut,u,cx,cy,tx,ty,period,r,moved,maxd,dmg,aid,as,lvl,int,sfx,func)
endfunction  

endlibrary
 
General chit-chat
Help Users
  • No one is chatting at the moment.

      The Helper Discord

      Members online

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top