HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

Extremely weird bug.

12-26-2008, 11:51 PM#1
Gwypaas
I'm creating a spell that is a half sphere and then it implodes but now I have an extremely weird bug.

When I cast it once then it fucks up totally, when that instance finish and I casts it again then it fucks up but in another way, BUT if I first cast it and it fucks up and then casts it again while the other is still running then it works.

How I can see the bug: If the instance is fucked up then the units moves totally randomly.


Collapse JASS:
library OtherSummon initializer Init requires HSAS
globals
    private constant integer SPELL_ID = 'A002'
    private constant integer DUMMY_ID = 'o001'
    private constant real RADIUS = 400
    
    private constant integer UNITS_PER_LAYER = 16
    private constant real TIMER_PERIOD = 0.025
    private constant real DECREASE_TIME = 4
endglobals

//! runtextmacro HSAS_Static("Other", "8190", "private")

private struct otherdata
    real x
    real y
    group g
    unit u
    player p
    real array xyspeeds[200]
    real array heightspeeds[200]
    integer iterator
    
    static method create takes unit u, real x, real y returns otherdata
        local otherdata d = .allocate()
        set d.x = x
        set d.y = y
        set d.u = u
        set d.g = CreateGroup() 
        set d.p = GetOwningPlayer(u)
        set d.iterator = 0
        return d
    endmethod
endstruct


globals
    private otherdata dddddd
endglobals

private function CallbackForgroup takes nothing returns nothing
    local unit u = GetEnumUnit()
    local real x = GetUnitX(u)
    local real y = GetUnitY(u)
    local otherdata d = dddddd
    local real angle = (Atan2(y - d.y, x - d.x))
    local real height = GetUnitFlyHeight(u)
    local real distance = SquareRoot((x - d.x) * (x - d.x) + (y - d.y) * (y - d.y))
    if distance == 0 then
        set distance = 1
    endif

    if distance >= 20 then
        call SetUnitX(u, d.x + (distance - d.xyspeeds[d.iterator]) * Cos(angle))
        call SetUnitY(u, d.y + (distance - d.xyspeeds[d.iterator]) * Sin(angle))
    endif
    if height > 10 then
        call SetUnitFlyHeight(u, height - d.heightspeeds[d.iterator], 0 )
    endif
    
    if distance < 20 and height <= 10 then
        call GroupRemoveUnit(d.g, u)
    endif
    set d.iterator = d.iterator + 1
endfunction


private function Callback takes nothing returns nothing
    local otherdata d = GetAttachedStructOther(GetExpiredTimer()) 
    set dddddd = d
    if FirstOfGroup(d.g) == null then
        call d.destroy()
        call PauseTimer(GetExpiredTimer())
        call DestroyTimer(GetExpiredTimer())
    else
        call ForGroup(d.g , function CallbackForgroup)
    endif
    
    set d.iterator = 0
endfunction



private function Act takes nothing returns nothing
    local location loc = GetSpellTargetLoc()
    local unit u = GetTriggerUnit()
    local otherdata d = otherdata.create(u, GetLocationX(loc), GetLocationY(loc))
    local integer i = 0
    local real angleBetween = (360/UNITS_PER_LAYER) // The amount of units on the height = this/2
    local real angleDone = 0
    local real angleDoneHeight = 0
    local real cz = 1
    local timer t = CreateTimer()
    local real dist
    loop
        exitwhen cz < 0
        loop 
            exitwhen angleDone >= 360. or cz < 0
            set cz = RADIUS * Cos(angleDoneHeight*bj_DEGTORAD)
            set u = CreateUnit(d.p, DUMMY_ID, d.x + RADIUS * Sin(angleDoneHeight*bj_DEGTORAD) * Cos(angleDone*bj_DEGTORAD) , d.y + RADIUS * Sin(angleDoneHeight*bj_DEGTORAD) * Sin(angleDone*bj_DEGTORAD) , 270)
            call UnitApplyTimedLife( u, 'BTLF', 6)
            call SetUnitFlyHeight(u, cz + 10, 0)
            call GroupAddUnit(d.g, u)
            set angleDone = angleDone + angleBetween
            
            set dist = SquareRoot((GetUnitX(u) - d.x) * (GetUnitX(u)  - d.x) + (GetUnitY(u)  - d.y) * (GetUnitY(u) - d.y))
            set d.xyspeeds[i] = (dist * TIMER_PERIOD) / DECREASE_TIME
            set d.heightspeeds[i] = (GetUnitFlyHeight(u) * TIMER_PERIOD) / DECREASE_TIME
            set u = null
            set i = i + 1
        endloop
        set angleDone = 0
        set angleDoneHeight = angleDoneHeight+angleBetween
    endloop

    
    call AttachStructOther(t, d)
    call TimerStart(t, TIMER_PERIOD, true, function Callback)
    
endfunction

private function Cond takes nothing returns boolean
    return GetSpellAbilityId() == SPELL_ID
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 Cond))
    call TriggerAddAction(Trig, function Act)
endfunction
endlibrary

Edit - I know that it leaks but there's no leaks in the periodic stuff :)
12-27-2008, 05:28 AM#2
Pyrogasm
Perhaps it's an error with HSAS? Have you tried with a different attachment system?

I don't see anything that would do stuff like that besides attaching getting fucked up.
12-27-2008, 03:38 PM#3
Gwypaas
Ok, made it use ABC instead but there was no improvment.
12-27-2008, 10:42 PM#4
cohadar
I don't think it is the attachment system that is making problems here.
(but I do think you should use TT for spells like this)

Post a demo map with this spell, that is the fastest way to get help with problems like this.
12-27-2008, 11:16 PM#5
Gwypaas
> (but I do think you should use TT for spells like this)
Easily changed, add return boolean and some returns + TT calls :P

> Post a demo map with this spell, that is the fastest way to get help with problems like this.

Posted a demo map
Attached Files
File type: w3xBuggy Spell.w3x (36.6 KB)
12-28-2008, 08:54 AM#6
cohadar
Collapse JASS:
library OtherSummon initializer Init requires TT
globals
    private constant integer SPELL_ID = 'A002'
    private constant integer DUMMY_ID = 'o001'
    private constant integer MAX_DUMMIES = 200
    private constant real RADIUS = 400
    
    
    private constant integer UNITS_PER_LAYER = 16
    private constant real DECREASE_TIME = 4
endglobals

private struct Data
    real x
    real y
    //group g
    unit u
    player p
    
    integer N // unit counter
    unit array U[MAX_DUMMIES] // using array instead of group
    
    boolean array active[MAX_DUMMIES] // <-----<<
    
    real array coss[MAX_DUMMIES] // Optimize ffs
    real array sins[MAX_DUMMIES]
    
    real array xyspeeds[MAX_DUMMIES]
    real array heightspeeds[MAX_DUMMIES]
    //integer iterator
    
    static method create takes unit u, real x, real y returns Data
        local Data d = .allocate()
        set d.x = x
        set d.y = y
        set d.u = u
        
        //set d.g = CreateGroup() 
        set d.N = 0
        
        set d.p = GetOwningPlayer(u)
        //set d.iterator = 0
        return d
    endmethod
endstruct



//===========================================================================
private function MoveUnit takes Data d, integer i returns nothing
    //local unit u = GetEnumUnit()
    local real x = GetUnitX(d.U[i])
    local real y = GetUnitY(d.U[i])
    //local real angle = (Atan2(y - d.y, x - d.x))
    local real height = GetUnitFlyHeight(d.U[i])
    local real distance = SquareRoot((x - d.x) * (x - d.x) + (y - d.y) * (y - d.y))
    if distance == 0 then
        set distance = 1
    endif

    if distance >= 20 then
        call SetUnitX(d.U[i], d.x + (distance - d.xyspeeds[i]) * d.coss[i])
        call SetUnitY(d.U[i], d.y + (distance - d.xyspeeds[i]) * d.sins[i])
    endif
    if height > 10 then
        call SetUnitFlyHeight(d.U[i], height - d.heightspeeds[i], 0 )
    endif
    
    if distance < 20 and height <= 10 then
        //call GroupRemoveUnit(d.g, d.U[i])
        set d.active[i] = false
    endif
endfunction


private function Callback takes nothing returns boolean
    //local Data d = GetAttachedStructOther(GetExpiredTimer()) 
    local Data d = TT_GetData()
    local integer i
    
    //if FirstOfGroup(d.g) == null then
    if d.N <= 0 then
        call d.destroy()
        return true
        //call ClearTimerStructA(GetExpiredTimer())
        //call PauseTimer(GetExpiredTimer())
        //call DestroyTimer(GetExpiredTimer())
    else
        set i = 0
        loop
            exitwhen i >= d.N
            
            if d.active[i] then
                call MoveUnit(d, i)
            endif
            
            set i = i + 1
        endloop    
        return false
    endif
 endfunction



private function Act takes nothing returns nothing
    local location temp = GetSpellTargetLoc()
    local unit u = GetTriggerUnit()
    local Data d = Data.create(u, GetLocationX(temp), GetLocationY(temp))
    local integer i = 0
    local real angleBetween = (360/UNITS_PER_LAYER) // The amount of units on the height = this/2
    local real angleDone = 0
    local real angleDoneHeight = 0
    
    local real angle
    
    local real cz = 1
    //local timer t = CreateTimer()
    local real dist
    
    call RemoveLocation(temp) // <-----<< shame on you
    set temp = null
    
    loop
        exitwhen cz < 0
        loop 
            exitwhen angleDone >= 360. or cz < 0
            set cz = RADIUS * Cos(angleDoneHeight*bj_DEGTORAD)
            set u = CreateUnit(d.p, DUMMY_ID, d.x + RADIUS * Sin(angleDoneHeight*bj_DEGTORAD) * Cos(angleDone*bj_DEGTORAD) , d.y + RADIUS * Sin(angleDoneHeight*bj_DEGTORAD) * Sin(angleDone*bj_DEGTORAD) , 270)
            call UnitApplyTimedLife( u, 'BTLF', 6)
            call SetUnitFlyHeight(u, cz + 10, 0)
            //call GroupAddUnit(d.g, u)
            set angleDone = angleDone + angleBetween
            
            set dist = SquareRoot((GetUnitX(u) - d.x) * (GetUnitX(u)  - d.x) + (GetUnitY(u)  - d.y) * (GetUnitY(u) - d.y))
            set d.xyspeeds[i] = (dist * TT_PERIOD) / DECREASE_TIME
            set d.heightspeeds[i] = (GetUnitFlyHeight(u) * TT_PERIOD) / DECREASE_TIME
            
            set angle = Atan2(GetUnitY(u) - d.y, GetUnitX(u) - d.x) // <-----<<
            set d.coss[i] = Cos(angle)
            set d.sins[i] = Sin(angle)
            
            set d.U[i] = u  // <-----<<
            set d.active[i] = true // <-----<<
            set d.N = d.N + 1
            
            set u = null
            set i = i + 1
        endloop
        set angleDone = 0
        set angleDoneHeight = angleDoneHeight+angleBetween
    endloop
    
    //call SetTimerStructA(t , d)
    call TT_Start(function Callback, d)
    
endfunction

private function Cond takes nothing returns boolean
    return GetSpellAbilityId() == SPELL_ID
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 Cond))
    call TriggerAddAction(Trig, function Act)
endfunction
endlibrary

The problem with spell was that you used both groups and iteration, so when unit was removed from group it fucked up iteration counter.

I recoded the spell to use iteration only.
Replaced attachment systems with TT (not really important)
and finally optimized Cos and Sin usage.

PS: I saw in demo map a HandleCounter with period of 0.001,
that is stupid, first because it lags and second because dialog display works on 1.0 period and even if it was not human eye cannot detect 0.001 changes in number display.
12-28-2008, 05:25 PM#7
Gwypaas
Lol.. the bug was pretty obvious when you saw it...


And the Handle Counter is only a CnP of the Handle Counter "system" that's posted on Th.net.


Thanks for the help :)