HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

First time working with structs, help!

08-09-2009, 02:19 PM#1
thehellman
Code:
scope FearLibrary

struct FearDat 
    unit u               = null
    real duration     = 0.
    real x               = 0.
    real y               = 0.
    real dx             = 0.
    real dy             = 0.
    real switchTime = 0.
    static method create takes unit u, real duration returns FearDat
        local FearDat d = FearDat.allocate()
            set d.u = u
            set d.duration = duration
            set d.x = GetUnitX(u)
            set d.y = GetUnitY(u)
            set d.dx = GetUnitX(u)+GetRandomReal(-400, 400)
            set d.dy = GetUnitY(u)+GetRandomReal(-400, 400)
            set d.switchTime = 5
        return d
    endmethod
endstruct

globals
    private FearDat array FearData
    private integer FearDataIndex = 0
    private timer FearTimer
    private boolean FirstTime = TRUE
endglobals

private function CreateDummy takes player whichPlayer, unit whichUnit, integer abilityID, integer level, real life returns unit
    local unit d = CreateUnit( whichPlayer, 'h002', GetUnitX( whichUnit), GetUnitY(whichUnit), 0 )
    call UnitApplyTimedLife( d, 'BTLF', life)
    call UnitAddAbility( d, abilityID)
    call SetUnitAbilityLevel( d, abilityID, level)
    return d
endfunction

function FearTimerLoop takes nothing returns nothing
    local FearDat fd = 0
    local integer i = 0

        loop
        exitwhen i >= FearDataIndex
            
            set fd = FearData[ i ]
            debug call BJDebugMsg( SCOPE_PREFIX + "Working With: " + I2S(fd) )
            set fd.switchTime = fd.switchTime-1            

            if( fd.duration <= 0.1 and fd > 0) then
                call UnitRemoveAbility(fd.u, 'B005')                
                call fd.destroy()   
                set FearDataIndex = FearDataIndex - 1
            endif            
            if( fd.switchTime == 0 ) then
                set fd.switchTime = 5
                set fd.dx = fd.x+GetRandomReal(-400, 400)
                set fd.dy = fd.y+GetRandomReal(-400, 400)
            endif        
            call IssuePointOrder( fd.u, "move", fd.dx, fd.dy )
            set fd.duration = fd.duration-0.1
            set i = i+1        

        endloop
        

endfunction

function AddFear takes unit u, real duration returns nothing    
    local unit d = CreateDummy( GetOwningPlayer(u), u, 'A00K', 1, 1 )
    local FearDat fd = 0    
    set fd = FearDat.create( u, duration )
    set FearData[ FearDataIndex] = fd
    
    if( FirstTime ) then
        set FirstTime = FALSE
        set FearTimer = CreateTimer()
        call TimerStart( FearTimer, 0.1, true, function FearTimerLoop )
    endif
    
    set FearDataIndex = FearDataIndex + 1
    
    call IssueTargetOrder( d, "bloodlust", u )
    set d = null
endfunction

endscope

This library is supposed to give me this ability:

The ability to Fear a unit where the unit will be rapidly ordered to move towards a random point around them, with this point changing every 0.5 seconds to anew position a round them.

I use to have it working with a local timer created for each instance, but I want to make it more efficient. Right now, I'm unable to get it working when there are more than 1 instances at the same time.

Problem: It isn't destroying the second instance and gives an error that says: "Double free of type: FearData"

I'm trying to make the transfer to structs, but I'm running into a lot of problems. Some assistance would be greatly appreciated.
08-09-2009, 02:41 PM#2
Fireeye
You need to set the current destroy struct, meaning global_struct_array[i] equal to the struct in the latest struct of that array.
Change this part
Collapse JASS:
            if( fd.duration <= 0.1 and fd > 0) then
                call UnitRemoveAbility(fd.u, 'B005')                
                call fd.destroy()   
                set FearDataIndex = FearDataIndex - 1
            endif

into this and remove the set i = i + 1 you got later
Collapse JASS:
            if( fd.duration <= 0.1 and fd > 0) then
                call UnitRemoveAbility(fd.u, 'B005')                
                call fd.destroy()
                set FearDataIndex = FearDataIndex - 1
                set FearData[i] = set FearData[FearDataIndex]
            else
                set i = i + 1
            endif 

As further explaing, you destroy and instance and reduce the max index, thus the loop will get less iterations.
However you don't switch the datas of an active struct with the just destroyed, thus you get a double free error.

Code:
U - Used
D - Destroy
X - 'Lost'
Loops : 6
Struct Arrays [0] [1] [2] [3] [4] [5]
               U   U   U   U   U   U  //Let's say slot 3 get's destroyed
Loops: 5
Struct Arrays [0] [1] [2] [3] [4] [5]
               U   U   U   D   U   X //Let's say slot 1 get's destroyed now
Loops: 4
Struct Arrays [0] [1] [2] [3] [4] [5]
               U   D   U   D   X   X //As you can see, you're trying to access already destroyed structs
Now the same scenario with the small changes.
Code:
U - Used
D - Destroy
X - 'Lost'
Loops : 6
Struct Arrays [0] [1] [2] [3] [4] [5]
               U   U   U   U   U   U  //Let's say slot 3 get's destroyed and swap it with 5
Loops: 5
Struct Arrays [0] [1] [2] [5] [4] [3]
               U   U   U   U   U   D //Let's say slot 1 get's destroyed and swaped with 4 now
Loops: 4
Struct Arrays [0] [4] [2] [5] [1] [3]
               U   U   U   U   D   D

Hope i didn't forgot anything, kinda forgetful at the moment.
08-09-2009, 06:02 PM#3
thehellman
Nevermind I think I got it working. Thanks a lot! +rep
08-09-2009, 06:22 PM#4
Fireeye
My fault, missed 1 thing.
Switch those 2 lines
Collapse JASS:
    set FearDataIndex = FearDataIndex + 1 //Switch this line
    set FearData[ FearDataIndex] = FearDat.create( u, duration ) //with this line
as you don't assign any struct to array index 0.
Other than that i can not find anything else at the moment, causing such a problem.

---Edit---
Posted the same time xD