[JASS] [vJASS]Script Bug

Level 16
Joined
Mar 3, 2006
Messages
1,564

JASS:
scope AoETemplate initializer Init
    private keyword Data
    globals
        private constant real TIMER_INTERVAL = 0.02
        private constant real DIST = 32.00
        private constant real NOVA_RADIUS = 512.00 // radius of the Nova
        private constant integer NOVA_SIZE = 64 // number of the Nova Units
        private constant integer UNIT_ID = 'e001' // rawcode of the Nova Unit
        private constant integer ABIL_ID = 'A001' // rawcode of the Dummy Spell
        private timer tm
        private Data array temp_dat
        private integer index = 0
    endglobals
    private struct Data
        unit caster
        unit array Nova[NOVA_SIZE]
        player owner
        static real cx // cx: Centre X
        static real cy // cy: Centre Y
        static real r = 32.00 // current radius of the nova. initial value = 32.00
        static real dr = DIST // radius increment
        static real array nux[NOVA_SIZE]   // nux: Nova Unit X
        static real array nuy[NOVA_SIZE]   // nuy: Nova Unit Y
        static method NovaExpand takes nothing returns nothing
            local Data dat
            local integer i = 0
            local real rmax = NOVA_RADIUS
            local real A = 0
            local real dA = 360.00 / NOVA_SIZE
//      nova expanding
            loop
                exitwhen i >= NOVA_SIZE
                set dat = temp_dat[i]
                set dat.nux[i] = Data.cx + Data.r * Cos( A * bj_DEGTORAD )
                set dat.nuy[i] = Data.cy + Data.r * Sin( A * bj_DEGTORAD )
                call SetUnitX( dat.Nova[i] , Data.nux[i] )
                call SetUnitY( dat.Nova[i] , Data.nuy[i] )
                set i = i + 1
                set A = A + dA
            endloop
 
            if Data.r >= rmax then
                call dat.destroy()
            endif
 
            set Data.r = Data.r + Data.dr
        endmethod
        static method NovaCreate takes unit caster, location centre returns Data
            local Data dat = Data.allocate()
            local integer i = 0
            local real A = 0.00
            local real dA = 360.00 / NOVA_SIZE
            set dat.caster = caster
            set dat.owner = GetOwningPlayer(dat.caster)
            set Data.cx = GetLocationX(centre)
            set Data.cy = GetLocationY(centre)
            loop
                exitwhen i >= NOVA_SIZE
                set dat.Nova[i] = CreateUnit( dat.owner , UNIT_ID , dat.cx , dat.cy , A )
                set A = A + dA
                set i = i + 1
            endloop
 
            if index == 0 then
                call TimerStart(tm,TIMER_INTERVAL,true,function Data.NovaExpand)
            endif
 
            set temp_dat[index] = dat            
            set index = index + 1
            return dat
        endmethod
        method onDestroy takes nothing returns nothing
         local integer i = 0
            call PauseTimer(tm)
            loop
                exitwhen i >= NOVA_SIZE
                call KillUnit(.Nova[i])
                set .Nova[i] = null
                set i = i + 1
            endloop
            set index = index - 1
        endmethod
    endstruct
     private function Conditions takes nothing returns boolean
        return GetSpellAbilityId() == ABIL_ID
     endfunction
     private function Actions takes nothing returns nothing
        call Data.NovaCreate(GetTriggerUnit(), GetUnitLoc(GetTriggerUnit()))
     endfunction
     private function Init takes nothing returns nothing
        local trigger t = CreateTrigger()
        call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
        call TriggerAddCondition(t,Condition(function Conditions))
        call TriggerAddAction(t,function Actions)
        set tm = CreateTimer()
     endfunction
endscope


Why isn't onDestroy called ?
 
Level 11
Joined
Apr 6, 2008
Messages
760
JASS:
if Data.r >= rmax then
    call dat.destroy()
endif

this is the problem

Data.r is a global (static struct member the same as a global bound to the struct)

Reall Data.r shouldn't be a global make it a member for the struct

You could solve this like this

JASS:
scope AoETemplate initializer Init
    // private keyword Data don't need this keyword
    
    globals
        private constant real TIMER_INTERVAL = 0.02
        private constant real DIST = 32.00
        private constant real NOVA_RADIUS = 512.00 // radius of the Nova
        private constant integer NOVA_SIZE = 64 // number of the Nova Units
        private constant real dA = 360/NOVA_SIZE
        private constant integer UNIT_ID = 'e001' // rawcode of the Nova Unit
        private constant integer ABIL_ID = 'A001' // rawcode of the Dummy Spell
        
        private timer tm = CreateTimer()
        private Data array temp_dat
        private integer index = 0
    endglobals
    
    private struct Data
        unit caster
        unit array Nova[NOVA_SIZE]
        
        real expand //this is what i replaced with the static member r with
        real Cx
        real Cy
        
        player owner
        
        static real x
        static real y
        static real a
        static integer index
        
        // static real cx //This wont make it MUI
        // static real cy 
        // static real array nux[NOVA_SIZE] Seriosly global arrays for setting x/y cords?
        // static real array nuy[NOVA_SIZE]
        
        static method NovaExpand takes nothing returns nothing
            local thistype dat
            local integer i = 0
            
            loop //you for this loop to go thru the structs here
                set dat = temp_dat[i]
            
                // nova expanding
                set thistype.index = 0
                set thistype.a = 0
                
                loop
                    exitwhen thistype.index >= NOVA_SIZE
                    // set dat = temp_dat[i] we dont loop structs here, this is the reason it wouldnt call destroy
                    set thistype.x = dat.Cx + dat.expand * Cos( A * bj_DEGTORAD )
                    set thistype.y = dat.Cy + dat.expand * Sin( A * bj_DEGTORAD )
                    call SetUnitX( dat.Nova[i] , thistype.x )
                    call SetUnitY( dat.Nova[i] , thistype.y )
                    set i = i + 1
                    set A
                    set thistype.a = thistype.a + dA
                endloop
                
                if dat.expand >= NOVA_RADIUS then
                    set temp_dat[i] = temp_dat[index]
                    set index = index - 1
                    set i = i - 1
                    call dat.destroy()
                endif
                
                set i = i + 1
            endloop
            
            if index == 0 then
                call PauseTimer(tm)
            endif
        endmethod
        
        static method NovaCreate takes unit caster returns Data
            local thistype dat = thistype.allocate()
            local integer i = 0
            local real A = 0.00
            set dat.caster = caster
            set dat.owner = GetOwningPlayer(dat.caster)
            set dat.Cx = GetUnitX(dat.caster)
            set dat.Cy = GetUnitY(dat.caster)
            
            loop
                exitwhen i >= NOVA_SIZE
                set dat.Nova[i] = CreateUnit( dat.owner , UNIT_ID , dat.cx , dat.cy , A )
                set A = A + dA
                set i = i + 1
            endloop

            if index == 0 then
                call TimerStart(tm,TIMER_INTERVAL,true,function Data.NovaExpand)
            endif
            
            set temp_dat[index] = dat
            set index = index + 1
            return dat
        endmethod
        
        method onDestroy takes nothing returns nothing
         local integer i = 0
            call PauseTimer(tm)
            loop
                exitwhen i >= NOVA_SIZE
                call KillUnit(.Nova[i])
                set .Nova[i] = null
                set i = i + 1
            endloop
            set index = index - 1
        endmethod
        
    endstruct
    
     private function Conditions takes nothing returns boolean
        return GetSpellAbilityId() == ABIL_ID
     endfunction
     
     private function Actions takes nothing returns nothing
        local unit u = GetTriggerUnit()
        call Data.NovaCreate(u)
        set u = null
     endfunction
     
     private function Init takes nothing returns nothing
        local trigger t = CreateTrigger()
        call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
        call TriggerAddCondition(t,Condition(function Conditions))
        call TriggerAddAction(t,function Actions)
        set t = null
     endfunction
     
endscope
 
Last edited:
Level 13
Joined
Nov 18, 2007
Messages
815
you leak centre. And unless you have some hidden code in there, you dont reset Data.r anywhere, so after the first time Data.r went over rmax, it wont happen again (because you pause the timer triggering the NovaExpand function). Also, you only destroy the last Data instance (seems to me like the algorithm is messed up).

Edit:
JASS:
set Data.r = Data.r + Data.dr
Data.r is NOT constant
 
Level 11
Joined
Apr 6, 2008
Messages
760
check my post. i fix up yours code abit

one of the problems u had was in the loop

JASS:
            loop
                exitwhen i >= NOVA_SIZE
                set dat = temp_dat[i] //you loop the structs here
                set dat.nux[i] = Data.cx + Data.r * Cos( A * bj_DEGTORAD )
                set dat.nuy[i] = Data.cy + Data.r * Sin( A * bj_DEGTORAD )
                call SetUnitX( dat.Nova[i] , Data.nux[i] )
                call SetUnitY( dat.Nova[i] , Data.nuy[i] )
                set i = i + 1
                set A = A + dA
            endloop

And i also made it MUI and abit more efficent
 
Level 16
Joined
Mar 3, 2006
Messages
1,564
There is something wrong with the script that slows the game greatly.

JASS:
scope AoETemplate initializer Init
    private keyword Data
    globals
        private constant real TIMER_INTERVAL = 0.02
        private constant real DIST = 32.00
        private constant real NOVA_RADIUS = 512.00 // radius of the Nova
        private constant integer NOVA_SIZE = 24 // number of the Nova Units
        private constant real dA = 360/NOVA_SIZE
        private constant integer UNIT_ID = 'e001' // rawcode of the Nova Unit
        private constant integer ABIL_ID = 'A001' // rawcode of the Dummy Spell
        private timer tm = CreateTimer()
        private Data array temp_dat
        private integer index = 0
    endglobals
    private struct Data
        unit caster
        unit array Nova[NOVA_SIZE]
        real expand //this is what i replaced with the static member r with
        real Cx
        real Cy
        player owner
        static real x
        static real y
        static real a
        static integer index
        static method NovaExpand takes nothing returns nothing
            local thistype dat
            local integer i = 0
            loop
                set dat = temp_dat[i]
                // Nova Expanding
                set thistype.index = 0
                set thistype.a = 0
                loop
                    exitwhen thistype.index >= NOVA_SIZE
                    set thistype.x = dat.Cx + dat.expand * Cos( thistype.a * bj_DEGTORAD )
                    set thistype.y = dat.Cy + dat.expand * Sin( thistype.a * bj_DEGTORAD )
                    call SetUnitX( dat.Nova[i] , thistype.x )
                    call SetUnitY( dat.Nova[i] , thistype.y )
                    set i = i + 1
                    set thistype.a = thistype.a + dA
                endloop
                if dat.expand >= NOVA_RADIUS then
                    set temp_dat[i] = temp_dat[index]
                    set index = index - 1
                    set i = i - 1
                    call dat.destroy()
                endif
                set i = i + 1
            endloop
            if index == 0 then
                call PauseTimer(tm)
            endif
        endmethod
        static method NovaCreate takes unit caster returns Data
            local thistype dat = thistype.allocate()
            local integer i = 0
            local real A = 0.00
            set dat.caster = caster
            set dat.owner = GetOwningPlayer(dat.caster)
            set dat.Cx = GetUnitX(dat.caster)
            set dat.Cy = GetUnitY(dat.caster)
            loop
                exitwhen i >= NOVA_SIZE
                set dat.Nova[i] = CreateUnit( dat.owner , UNIT_ID , dat.Cx , dat.Cy , A )
                set A = A + dA
                set i = i + 1
            endloop
            
            if index == 0 then
                call TimerStart(tm,TIMER_INTERVAL,true,function Data.NovaExpand)
            endif
            
            set temp_dat[index] = dat            
            set index = index + 1
            return dat
        endmethod
        method onDestroy takes nothing returns nothing
         local integer i = 0
            call PauseTimer(tm)
            loop
                exitwhen i >= NOVA_SIZE
                call KillUnit(.Nova[i])
                set .Nova[i] = null
                set i = i + 1
            endloop
            set index = index - 1
        endmethod
    endstruct
     private function Conditions takes nothing returns boolean
        return GetSpellAbilityId() == ABIL_ID
     endfunction
     private function Actions takes nothing returns nothing
        local unit u = GetTriggerUnit()
        call Data.NovaCreate(u)
        set u = null
     endfunction
     private function Init takes nothing returns nothing
        local trigger t = CreateTrigger()
        call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
        call TriggerAddCondition(t,Condition(function Conditions))
        call TriggerAddAction(t,function Actions)
        set t = null
     endfunction
endscope
 
Level 16
Joined
Mar 3, 2006
Messages
1,564
the method NovaExpand has a nested loop. The first loop never exits.

JASS:
loop
    ...
    loop
        exitwhen ...
    endloop
// needs another exitwhen somewhere
endloop
Thanks for the info, I found it also and fixed it but the script only works once; when the spell is cast once again the dummies are created but don't move.


JASS:
scope AoETemplate initializer Init
    private keyword Data
    globals
        private constant real TIMER_INTERVAL = 0.03
        private constant real DIST = 32.00
        private constant real NOVA_RADIUS = 512.00 // radius of the Nova
        private constant integer NOVA_SIZE = 24 // number of the Nova Units
        private constant real dA = 360/NOVA_SIZE
        private constant integer UNIT_ID = 'e001' // rawcode of the Nova Unit
        private constant integer ABIL_ID = 'A001' // rawcode of the Dummy Spell
        private timer tm = CreateTimer()
        private Data array temp_dat
        private integer index = 0
    endglobals
    private struct Data
        unit caster
        unit array Nova[NOVA_SIZE]
        real expand //this is what i replaced with the static member r with
        real Cx
        real Cy
        player owner
        static real x
        static real y
        static real a
        static integer index
        static method NovaExpand takes nothing returns nothing
            local thistype dat
            local integer i = 0
            loop
                exitwhen i >= index
                set dat = temp_dat[i]
                // Nova Expanding
                set thistype.index = 0
                set thistype.a = 0
                loop
                    exitwhen thistype.index >= NOVA_SIZE
                    set thistype.x = dat.Cx + dat.expand * Cos( thistype.a * bj_DEGTORAD )
                    set thistype.y = dat.Cy + dat.expand * Sin( thistype.a * bj_DEGTORAD )
                    call SetUnitX( dat.Nova[thistype.index] , thistype.x )
                    call SetUnitY( dat.Nova[thistype.index] , thistype.y )
                    set thistype.index = thistype.index + 1
                    set thistype.a = thistype.a + dA
                endloop
                if dat.expand >= NOVA_RADIUS then
                    set temp_dat[i] = temp_dat[index]
                    set index = index - 1
                    set i = i - 1
                    call dat.destroy()
                endif
                set dat.expand = dat.expand + DIST
                set i = i + 1
            endloop
            if index == 0 then
                call PauseTimer(tm)
            endif
        endmethod
        static method NovaCreate takes unit caster returns Data
            local thistype dat = thistype.allocate()
            local integer i = 0
            local real A = 0.00
            set dat.caster = caster
            set dat.owner = GetOwningPlayer(dat.caster)
            set dat.Cx = GetUnitX(dat.caster)
            set dat.Cy = GetUnitY(dat.caster)
            loop
                exitwhen i >= NOVA_SIZE
                set dat.Nova[i] = CreateUnit( dat.owner , UNIT_ID , dat.Cx , dat.Cy , A )
                set A = A + dA
                set i = i + 1
            endloop
            
            if index == 0 then
                call TimerStart(tm,TIMER_INTERVAL,true,function Data.NovaExpand)
            endif
            
            set temp_dat[index] = dat            
            set index = index + 1
            return dat
        endmethod
        method onDestroy takes nothing returns nothing
         local integer i = 0
            call PauseTimer(tm)
            loop
                exitwhen i >= NOVA_SIZE
                call KillUnit(.Nova[i])
                set .Nova[i] = null
                set i = i + 1
            endloop
            set index = index - 1
        endmethod
    endstruct
     private function Conditions takes nothing returns boolean
        return GetSpellAbilityId() == ABIL_ID
     endfunction
     private function Actions takes nothing returns nothing
        local unit u = GetTriggerUnit()
        call Data.NovaCreate(u)
        set u = null
     endfunction
     private function Init takes nothing returns nothing
        local trigger t = CreateTrigger()
        call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
        call TriggerAddCondition(t,Condition(function Conditions))
        call TriggerAddAction(t,function Actions)
        set t = null
     endfunction
endscope


Thanks in advance for any help.
 
Level 11
Joined
Feb 22, 2006
Messages
752
JASS:
set temp_dat[i] = temp_dat[index]

The last non-zero index of the array is actually index - 1.

JASS:
set index = index - 1

You have that both right before you destroy dat in the NovaExpand method and in Data's onDestroy method. There should only be one. Get rid of one or the other.

JASS:
method onDestroy takes nothing returns nothing
    local integer i = 0
    call PauseTimer(tm)

Get rid of that PauseTimer() call.

JASS:
static method NovaCreate

change that method name to just create()
 
Level 16
Joined
Mar 3, 2006
Messages
1,564
JASS:
scope AoETemplate initializer Init
    private keyword Data
    globals
        private constant real TIMER_INTERVAL = 0.03
        private constant real DIST = 32.00
        private constant real NOVA_RADIUS = 512.00 // radius of the Nova
        private constant integer NOVA_SIZE = 36 // number of the Nova Units
        private constant real dA = 360/NOVA_SIZE
        private constant integer UNIT_ID = 'e001' // rawcode of the Nova Unit
        private constant integer ABIL_ID = 'AHtc' // rawcode of the Dummy Spell
        private timer tm = CreateTimer()
        private Data array temp_dat
        private integer index = 0
        private integer iFilter     // Filter Index
        private boolexpr fFilter    // Filter function
    endglobals
    private struct Data
        unit Caster
        unit array Nova[NOVA_SIZE]
        real expand
        real Cx
        real Cy
        player Owner
        group Group = CreateGroup()
        group dGroup = CreateGroup()   // Damged Units Group
        unit TempU
        static real x
        static real y
        static real a
        static integer index
        static method NovaExpand takes nothing returns nothing
            local thistype dat
            local integer i = 0
            loop    // this loop cycles through all the casters who have casted the spell
                exitwhen i >= index
                set dat = temp_dat[i]
                //set dat.expand = dat.expand + DIST
            // Nova Expanding
                set thistype.index = 0
                set thistype.a = 0
                loop
                    exitwhen thistype.index >= NOVA_SIZE
                    set thistype.x = dat.Cx + dat.expand * Cos( thistype.a * bj_DEGTORAD )
                    set thistype.y = dat.Cy + dat.expand * Sin( thistype.a * bj_DEGTORAD )
                    call SetUnitX( dat.Nova[thistype.index] , thistype.x )
                    call SetUnitY( dat.Nova[thistype.index] , thistype.y )
                    set thistype.index = thistype.index + 1
                    set thistype.a = thistype.a + dA
                endloop
            // Damage Units that the nova has reached them
                set iFilter = dat
                call GroupEnumUnitsInRange(dat.Group,dat.Cx,dat.Cy,dat.expand,fFilter)
                loop
                    set dat.TempU = FirstOfGroup(dat.Group)
                    exitwhen dat.TempU == null
                    call GroupRemoveUnit(dat.Group,dat.TempU)
                    call GroupAddUnit(dat.dGroup,dat.TempU)
                    call UnitDamageTarget(dat.Caster,dat.TempU,100,false,false,ATTACK_TYPE_NORMAL,DAMAGE_TYPE_FIRE,null)
                endloop
                if dat.expand >= NOVA_RADIUS then   // check if the nova has reached its max AoE
                    set temp_dat[i] = temp_dat[index]
                    set index = index - 1
                    set i = i - 1
                    call dat.destroy()
                endif
                set dat.expand = dat.expand + DIST
                set i = i + 1
            endloop
        endmethod
        static method Create takes unit caster returns Data
            local thistype dat = thistype.allocate()
            local integer i = 0
            local real A = 0.00
            set dat.Caster = caster
            set dat.Owner = GetOwningPlayer(dat.Caster)
            set dat.Cx = GetUnitX(dat.Caster)
            set dat.Cy = GetUnitY(dat.Caster)
            loop
                exitwhen i >= NOVA_SIZE
                set dat.Nova[i] = CreateUnit( dat.Owner , UNIT_ID , dat.Cx , dat.Cy , A )
                set A = A + dA
                set i = i + 1
            endloop
            if index == 0 then
                call TimerStart(tm,TIMER_INTERVAL,true,function Data.NovaExpand)
            endif
            set temp_dat[index] = dat            
            set index = index + 1
            return dat
        endmethod
        static method FilterUnit takes nothing returns boolean
            local Data dat = iFilter
            local unit f = GetFilterUnit()
            local boolean bool = GetWidgetLife(f) >= .305 and IsUnitEnemy(f,dat.Owner) and not IsUnitType(f,UNIT_TYPE_MAGIC_IMMUNE) and not IsUnitInGroup(f,dat.dGroup)
            set f = null
            return bool
        endmethod
        method onDestroy takes nothing returns nothing
         local integer i = 0
            call PauseTimer(tm)
            loop
                exitwhen i >= NOVA_SIZE
                call KillUnit(.Nova[i])
                set .Nova[i] = null
                set .expand = 0
                set i = i + 1
            endloop
            //set index = index - 1
        endmethod
    endstruct
     private function Conditions takes nothing returns boolean
        return GetSpellAbilityId() == ABIL_ID
     endfunction
     private function Actions takes nothing returns nothing
        local unit u = GetTriggerUnit()
        call Data.Create(u)
        set u = null
     endfunction
     private function Init takes nothing returns nothing
        local trigger t = CreateTrigger()
        call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
        call TriggerAddCondition(t,Condition(function Conditions))
        call TriggerAddAction(t,function Actions)
        set t = null
        set fFilter = Filter(function Data.FilterUnit)
     endfunction
endscope
The script finally works but can someone check for its MUI, leak or any other hidden errors please.

EDIT: I have changed the script; it now damages units in the AoE
 
Last edited:
Ouch yeah, pausing the timer like that stops you from being able to cast the spell again until all instances have finished. Pause it only if index == 0

EDIT:
JASS:
[B][COLOR=Navy][/COLOR][/B]set thistype.index = 0
set thistype.a = 0
loop
    exitwhen thistype.index >= NOVA_SIZE
    set thistype.x = dat.Cx + dat.expand * Cos( thistype.a * bj_DEGTORAD )
    set thistype.y = dat.Cy + dat.expand * Sin( thistype.a * bj_DEGTORAD )
    call SetUnitX( dat.Nova[thistype.index] , thistype.x )
    call SetUnitY( dat.Nova[thistype.index] , thistype.y )
    set thistype.index = thistype.index + 1
    set thistype.a = thistype.a + dA
endloop
What's this about as well? Why do you use static variables for all this? Just use locals. It makes it much easier to read.
 
Level 16
Joined
Mar 3, 2006
Messages
1,564
Ouch yeah, pausing the timer like that stops you from being able to cast the spell again until all instances have finished. Pause it only if index == 0

EDIT:
What's this about as well? Why do you use static variables for all this? Just use locals. It makes it much easier to read.
I got the code from Ciebron and I am not vGood at vJASSing so he gave the script and I can't argue or modify many things in order not to spoil it. I take his script with few modification and it worked and after that I asked for anyone to check if it works perfectly or not.

I will try and fix what you have said but I hope it doesn't spoil again.
 
Level 11
Joined
Apr 6, 2008
Messages
760
Put this above the loop where u move the units,else the first "call" wont move them

JASS:
 set dat.expand = dat.expand + DIST

but acctuly, why dont you use timerutlis instead? much esier to work with then indexer
 
Level 16
Joined
Mar 3, 2006
Messages
1,564
I found another bug but I don't know why.

When I set the timer to 1 sec instead of 0.03 sec to slow it and see how it works I found that when you cast the spell and cast it again the Nova Units will stop moving once the Nova Units of the first cast is killed and if you cast it third time it won't work; just the Nova Units are created at the caster.
 
Level 16
Joined
Mar 3, 2006
Messages
1,564
I dont know what the hell with that script but I have attached a map containg the script. The spell works but you must not cast it again unitl the first one finishes completely. I have made a trigger that will cause 2 units to cast the spell at the same time so that whoever will help me see how the bug happens.
 

Attachments

  • vJASS Learning.w3x
    26.6 KB · Views: 38
Code cleaned up and fixed (I haven't tested it)
JASS:
scope AoETemplate initializer Init
    private keyword Data
    globals
        private constant real TIMER_INTERVAL = 0.03
        private constant real DIST = 32.00
        private constant real NOVA_RADIUS = 512.00 // radius of the Nova
        private constant integer NOVA_SIZE = 36 // number of the Nova Units
        private constant real dA = 360/NOVA_SIZE
        private constant integer UNIT_ID = 'e001' // rawcode of the Nova Unit
        private constant integer ABIL_ID = 'AHtc' // rawcode of the Dummy Spell
        private timer tm = CreateTimer()
        private Data array temp_dat
        private integer index = 0
        private Data iFilter // Filter Data
        private boolexpr fFilter // Filter function
        
        private group TempGroup = CreateGroup()
    endglobals
    private struct Data
        unit Caster
        unit array Nova[NOVA_SIZE]
        real expand
        real Cx
        real Cy
        player Owner
        group dGroup = CreateGroup() // Damaged Units Group
        static method NovaExpand takes nothing returns nothing
            local thistype dat
            
            local integer i = 0
            
            local integer j
            
            local real x
            local real y
            local real a
            
            local unit u
            
            loop // this loop cycles through all the casters which have cast the spell
                exitwhen i >= index
                set dat = temp_dat[i]
                
                // Nova Expanding
                set j = 0
                set a = 0
                set dat.expand = dat.expand + DIST
                loop
                    exitwhen j >= NOVA_SIZE
                    set x = dat.Cx + dat.expand * Cos( a * bj_DEGTORAD )
                    set y = dat.Cy + dat.expand * Sin( a * bj_DEGTORAD )
                    call SetUnitX( dat.Nova[index] , x )
                    call SetUnitY( dat.Nova[index] , y )
                    set j = j + 1
                    set a = a + dA
                endloop
                
                // Damage Units that the nova has reached
                set iFilter = dat
                call GroupEnumUnitsInRange(TempGroup, dat.Cx, dat.Cy, dat.expand, fFilter)
                loop
                    set u = FirstOfGroup(TempGroup)
                    exitwhen u == null
                    
                    call GroupAddUnit(dat.dGroup, u)
                    call UnitDamageTarget(dat.Caster, u, 100, false, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_FIRE, null)
                    
                    call GroupRemoveUnit(TempGroup, u)
                endloop
                
                if dat.expand >= NOVA_RADIUS then // check if the nova has reached its max AoE
                    set index = index - 1
                    set temp_dat[i] = temp_dat[index]
                    set i = i - 1
                    call dat.destroy()
                endif
                
                set i = i + 1
            endloop
            
            set u = null
        endmethod
        
        static method create takes unit caster returns Data
            local thistype dat = thistype.allocate()
            local integer i = 0
            local real A = 0.00
            set dat.Caster = caster
            set dat.Owner = GetOwningPlayer(dat.Caster)
            set dat.Cx = GetUnitX(dat.Caster)
            set dat.Cy = GetUnitY(dat.Caster)
            loop
                exitwhen i >= NOVA_SIZE
                set dat.Nova[i] = CreateUnit( dat.Owner , UNIT_ID , dat.Cx , dat.Cy , A )
                set A = A + dA
                set i = i + 1
            endloop
            if index == 0 then
                call TimerStart(tm,TIMER_INTERVAL,true,function Data.NovaExpand)
            endif
            set temp_dat[index] = dat
            set index = index + 1
            return dat
        endmethod
        
        static method FilterUnit takes nothing returns boolean
            return GetWidgetLife(GetFilterUnit()) >= .305 and IsUnitEnemy(GetFilterUnit(),iFilter.Owner) and not IsUnitType(GetFilterUnit(),UNIT_TYPE_MAGIC_IMMUNE) and not IsUnitInGroup(GetFilterUnit(),iFilter.dGroup)
        endmethod
        
        method onDestroy takes nothing returns nothing
            local integer i = 0
            
            loop
                exitwhen i >= NOVA_SIZE
                call KillUnit(.Nova[i])
                set .Nova[i] = null
                set .expand = 0
                set i = i + 1
            endloop
            
            if index == 0 then
                call PauseTimer(tm)
            endif
        endmethod
     endstruct
    
     private function Conditions takes nothing returns boolean
        return GetSpellAbilityId() == ABIL_ID
     endfunction
     
     private function Actions takes nothing returns nothing
        call Data.create(GetTriggerUnit())
     endfunction
     
     private function Init takes nothing returns nothing
        local trigger t = CreateTrigger()
        call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
        call TriggerAddCondition(t,Condition(function Conditions))
        call TriggerAddAction(t,function Actions)
        set fFilter = Filter(function Data.FilterUnit)
     endfunction
endscope
 
Level 16
Joined
Mar 3, 2006
Messages
1,564
Thanks for the script and your efforts but there was a simple bug concerning moving the dummy units of the nova; only one unit moved. I'll try and fix it. (rep system limits me from giving you some. I owe you 4)

<< ADDED >>

The problem was inside the nova animation loop; you replaced the j index with the index.

Still thanks for the efforts.

And another question: what was wrong with my script ?
 
Top