Spell Frozen Orb

Tom_Kazansky

--- wraith it ! ---
Reaction score
157
Frozen Orb

There is Frozen Orb made by Flare (right ?), but I made this because someone request me to.

MUI: yes
Lagless: maybe
Leakless: (I think)
vJass

------------------------
Description:
Creates a globe of frozen death that spreads out ice bolts.

Screenshot

frozenorbxg7.jpg


Code

(non Safe XY )
JASS:
scope FrozenOrb initializer Init 

globals
    private constant integer AbilID = 'A000' //raw id of the Frozen Orb ability
    private constant integer IceID = 'A001' //raw id of the Frozen Orb Slow and Damage ability
    private constant string IceOrder = "frostnova" //order string of the Frozen Orb Slow and Damage ability
    private constant integer DummyId = 'n000' //dummy unit's raw id (caster)
    private constant integer OrbId = 'n001' //raw id of the Frozen Orb dummy
    private constant integer BoltId = 'n002' //raw id of the Ice Bolt dummy
    private constant real OrbHitRange = 150. //when a unit comes within this range of the Orb, it will spread out more ice bolts
    private constant real OrbSpeed = 500 // speed of the Frozen Orb
    private constant real BoltHitRange = 50. //when a unit comes within this range of the ice bolt, it got hit.
    private constant real BoltSpeed = 1000 // speed of the Ice Bolts
    private constant string SOUNDPATH = "Abilities\\Spells\\Human\\Blizzard\\BlizzardLoop1.wav" //sound which is played during the spell
endglobals

//=======================
private function GetIceBoltDist takes integer lvl returns real
    return 750.
endfunction

private function GetOrbDist takes integer lvl returns real
    return 1000.
endfunction

//==== Do not modify anything below ====
//=============================
private struct dataI
    unit c
    unit d
    integer lvl
    integer tick
    real angle
    real speed
endstruct
//=============================
private struct data
    unit c
    unit d1
    unit d2
    unit d3
    group hit 
    
    sound bliz
    
    real dx
    real dy
    real df
    
    integer lvl
    real speed
    real angle
    
    real shootAngle
    
    integer tick = 40
    integer tks = 0
endstruct

globals
    private group ENUMER = CreateGroup()
    
    private data array ORBDATA
    private integer ORBDATACOUNT = -1
    private dataI array BOLTDATA
    private integer BOLTDATACOUNT = -1
    private integer TEMPINT
endglobals

private function GetPPX takes real x, real dist, real angle returns real
    return x + dist * Cos(angle * bj_DEGTORAD)
endfunction

private function GetPPY takes real y, real dist, real angle returns real
    return y + dist * Sin(angle * bj_DEGTORAD)
endfunction

private function SetUnitZ takes unit u, real h returns nothing
    call UnitAddAbility( u , 'Amrf')
    call UnitRemoveAbility( u , 'Amrf' )
    call SetUnitFlyHeight( u , h, 0. )
endfunction

private function AngleLocXY takes real x1, real y1, real x2, real y2 returns real
    return bj_RADTODEG * Atan2(y2 - y1, x2 - x1)
endfunction
    

private function IceBoltF takes nothing returns boolean
    local dataI d = TEMPINT
    local unit a = GetFilterUnit()
    local boolean ok = false
    if IsUnitInRange(a,d.d,BoltHitRange) then
        if GetWidgetLife(a) > 0.405 then
            if IsUnitEnemy(a,GetOwningPlayer(d.c)) then
                if IsUnitType(a,UNIT_TYPE_STRUCTURE) == false then
                    if IsUnitType(a,UNIT_TYPE_MAGIC_IMMUNE) == false then
                        set ok = true
                    endif
                endif
            endif
        endif
    endif
    set a = null
    return ok
endfunction

private function IceBoltM takes dataI d returns boolean
    local boolexpr bx
    local unit a
    local unit c
    
    set d.tick = d.tick - 1
    if d.tick == 0 then
        call KillUnit(d.d)
        return true
    endif
    set TEMPINT = d
    call GroupEnumUnitsInRange( ENUMER, GetUnitX(d.d), GetUnitY(d.d) , BoltHitRange + 100 , Condition( function IceBoltF ) )
    set a = FirstOfGroup(ENUMER)
    call GroupClear(ENUMER)
    if a != null then
        set c = CreateUnit(GetOwningPlayer(d.c),DummyId,GetUnitX(a),GetUnitY(a),0. )
        call UnitApplyTimedLife(c,'BTLF',0.5)
        call UnitAddAbility(c, IceID )
        call SetUnitAbilityLevel(c, IceID, d.lvl)
        call IssueTargetOrder(c,IceOrder,a)
        set c = null
        set a = null
        call KillUnit(d.d)
        return true
    endif
    call SetUnitX( d.d, GetPPX(GetUnitX(d.d),d.speed, d.angle ) )
    call SetUnitY( d.d, GetPPY(GetUnitY(d.d),d.speed, d.angle ) )
    return false
endfunction

private function IceBolt takes unit c, integer lvl, real x, real y, real f returns nothing
    set BOLTDATACOUNT = BOLTDATACOUNT + 1
    set BOLTDATA[BOLTDATACOUNT] = dataI.create()
    set BOLTDATA[BOLTDATACOUNT].c = c
    set BOLTDATA[BOLTDATACOUNT].d = CreateUnit( GetOwningPlayer(c), BoltId , x, y, f )
    call SetUnitZ( BOLTDATA[BOLTDATACOUNT].d , 125. )
    set BOLTDATA[BOLTDATACOUNT].lvl = lvl
    set BOLTDATA[BOLTDATACOUNT].angle = f
    set BOLTDATA[BOLTDATACOUNT].speed = BoltSpeed / 25.
    set BOLTDATA[BOLTDATACOUNT].tick = R2I(GetIceBoltDist( lvl ) / BOLTDATA[BOLTDATACOUNT].speed)
    
endfunction

//=============================
    
private function OrbF takes nothing returns boolean
    local data d = TEMPINT
    local unit a = GetFilterUnit()
    local boolean ok = false
    if IsUnitInRangeXY(a,d.dx,d.dy,OrbHitRange) then
        if not IsUnitInGroup(a,d.hit) then
            if GetWidgetLife(a) > 0.405 then
                if IsUnitEnemy(a,GetOwningPlayer(d.c)) then
                    if IsUnitType(a,UNIT_TYPE_STRUCTURE) == false then
                        if IsUnitType(a,UNIT_TYPE_MAGIC_IMMUNE) == false then
                            set ok = true
                        endif
                    endif
                endif
            endif
        endif
    endif
    set a = null
    return ok
endfunction
    
private function ActE takes data d returns boolean
    local integer i = 0
    local unit a
    local unit c
    local real dx
    local real dy
    set d.tick = d.tick - 1
    if d.tick == 0 then
        call StopSound( d.bliz, true, false )
        call SetUnitX(d.d1,d.dx)
        call SetUnitX(d.d2,d.dx)
        call SetUnitX(d.d3,d.dx)
        call SetUnitY(d.d1,d.dy)
        call SetUnitY(d.d2,d.dy)
        call SetUnitY(d.d3,d.dy)
        call KillUnit(d.d1)
        call KillUnit(d.d2)
        call KillUnit(d.d3)
        loop
            exitwhen i > 11
            call IceBolt( d.c, d.lvl, GetPPX(d.dx,50.,i*30), GetPPY(d.dy,50.,i*30), i*30. + 90. )
            set i = i + 1
        endloop
        call DestroyGroup(d.hit)
        return true
    endif
    
    set d.df = d.df + 5
    set d.dx = GetPPX( d.dx, d.speed, d.angle )
    set d.dy = GetPPY( d.dy, d.speed, d.angle )
    call SetSoundPosition(d.bliz, d.dx, d.dy, 0 )
    call SetUnitX(d.d1,GetPPX(d.dx,-75,d.df))
    call SetUnitY(d.d1,GetPPY(d.dy,-75,d.df))
    call SetUnitFacing(d.d1,d.df)
    call SetUnitX(d.d2,GetPPX(d.dx,-75,d.df+120.))
    call SetUnitY(d.d2,GetPPY(d.dy,-75,d.df+120.))
    call SetUnitFacing(d.d2,d.df+120.)
    call SetUnitX(d.d3,GetPPX(d.dx,-75,d.df+240.))
    call SetUnitY(d.d3,GetPPY(d.dy,-75,d.df+240.))
    call SetUnitFacing(d.d3,d.df+240.)
    set TEMPINT = d
    call GroupEnumUnitsInRange( ENUMER, d.dx, d.dy , OrbHitRange + 100 , Condition( function OrbF ) )
    set a = FirstOfGroup(ENUMER)
    call GroupClear(ENUMER)
    if a != null then
        call GroupAddUnit(d.hit,a)
        loop
            exitwhen i > 11
            call IceBolt( d.c, d.lvl, GetPPX(d.dx,50.,i*30), GetPPY(d.dy,50.,i*30), i*30. + 90. )
            set i = i + 1
        endloop
        set a = null
    endif
    
    if d.tks == 0 then
        set dx = GetPPX( d.dx, 50., d.shootAngle)
        set dy = GetPPY( d.dy, 50., d.shootAngle)
        call IceBolt( d.c, d.lvl, dx, dy, d.shootAngle + 90 )
        set dx = GetPPX( d.dx, 50., d.shootAngle+180.)
        set dy = GetPPY( d.dy, 50., d.shootAngle+180.)
        call IceBolt( d.c, d.lvl, dx, dy, d.shootAngle + 180. + 90 )
        set d.shootAngle = d.shootAngle + (30. + 15 * GetRandomInt(0,1))
        set d.tks = 3
    endif
    set d.tks = d.tks - 1
    
    return false
endfunction

private function Act takes nothing returns nothing
    local location loc = GetSpellTargetLoc()
    set ORBDATACOUNT = ORBDATACOUNT + 1
    set ORBDATA[ORBDATACOUNT] = data.create()
    set ORBDATA[ORBDATACOUNT].c = GetTriggerUnit()
    set ORBDATA[ORBDATACOUNT].lvl = GetUnitAbilityLevel(ORBDATA[ORBDATACOUNT].c,AbilID)
    set ORBDATA[ORBDATACOUNT].dx = GetUnitX(ORBDATA[ORBDATACOUNT].c)
    set ORBDATA[ORBDATACOUNT].dy = GetUnitY(ORBDATA[ORBDATACOUNT].c)
    set ORBDATA[ORBDATACOUNT].df = AngleLocXY( ORBDATA[ORBDATACOUNT].dx, ORBDATA[ORBDATACOUNT].dy, GetLocationX(loc), GetLocationY(loc) )
    set ORBDATA[ORBDATACOUNT].d1 = CreateUnit( GetOwningPlayer(ORBDATA[ORBDATACOUNT].c),OrbId,ORBDATA[ORBDATACOUNT].dx, ORBDATA[ORBDATACOUNT].dy, ORBDATA[ORBDATACOUNT].df )
    call SetUnitZ(ORBDATA[ORBDATACOUNT].d1,100. )
    set ORBDATA[ORBDATACOUNT].d2 = CreateUnit( GetOwningPlayer(ORBDATA[ORBDATACOUNT].c),OrbId,ORBDATA[ORBDATACOUNT].dx, ORBDATA[ORBDATACOUNT].dy, ORBDATA[ORBDATACOUNT].df+120 )
    call SetUnitZ(ORBDATA[ORBDATACOUNT].d2,100. )
    set ORBDATA[ORBDATACOUNT].d3 = CreateUnit( GetOwningPlayer(ORBDATA[ORBDATACOUNT].c),OrbId,ORBDATA[ORBDATACOUNT].dx, ORBDATA[ORBDATACOUNT].dy, ORBDATA[ORBDATACOUNT].df+240 )
    call SetUnitZ(ORBDATA[ORBDATACOUNT].d3,100. )
    set ORBDATA[ORBDATACOUNT].speed = OrbSpeed / 25.
    set ORBDATA[ORBDATACOUNT].angle = ORBDATA[ORBDATACOUNT].df
    set ORBDATA[ORBDATACOUNT].tick = R2I( GetOrbDist(ORBDATA[ORBDATACOUNT].lvl) / ORBDATA[ORBDATACOUNT].speed )
    set ORBDATA[ORBDATACOUNT].shootAngle = ORBDATA[ORBDATACOUNT].angle
    
    set ORBDATA[ORBDATACOUNT].bliz = CreateSound(SOUNDPATH,true,true,true,12700, 12700, "")
    call SetSoundPosition(ORBDATA[ORBDATACOUNT].bliz, ORBDATA[ORBDATACOUNT].dx, ORBDATA[ORBDATACOUNT].dy, 0 )
    call SetSoundVolume(ORBDATA[ORBDATACOUNT].bliz,127)
    call StartSound(ORBDATA[ORBDATACOUNT].bliz)
    
    set ORBDATA[ORBDATACOUNT].hit = CreateGroup()
    
    call RemoveLocation( loc )
    set loc = null
endfunction
    
private function Time takes nothing returns nothing
    local integer i = 0
    local integer j
    local boolean stop
    loop
        exitwhen i > ORBDATACOUNT
        set stop = ActE(ORBDATA<i>)
        if stop then
            call ORBDATA<i>.destroy()
            if i &lt; ORBDATACOUNT then
                set ORBDATA<i> = ORBDATA[ORBDATACOUNT]
            endif
            set ORBDATACOUNT = ORBDATACOUNT - 1
            set i = i - 1
        endif
        set i = i + 1
    endloop
    
    set i = 0
    loop
        exitwhen i &gt; BOLTDATACOUNT
        set stop = IceBoltM(BOLTDATA<i>)
        if stop then
            call BOLTDATA<i>.destroy()
            if i &lt; BOLTDATACOUNT then
                set BOLTDATA<i> = BOLTDATA[BOLTDATACOUNT]
            endif
            set BOLTDATACOUNT = BOLTDATACOUNT - 1
            set i = i - 1
        endif
        set i = i + 1
    endloop
    
endfunction
    
private function Cond takes nothing returns boolean
    return GetSpellAbilityId() == AbilID
endfunction

public function Init takes nothing returns nothing
    local trigger t = CreateTrigger( )
    call TriggerRegisterAnyUnitEventBJ( t, EVENT_PLAYER_UNIT_SPELL_EFFECT )
    call TriggerAddAction( t, function Act )
    call TriggerAddCondition( t, Condition ( function Cond ) )
    
    set t = CreateTrigger( )
    call TriggerRegisterTimerEvent(t,0.04, true )
    call TriggerAddAction( t, function Time )
    
endfunction

endscope</i></i></i></i></i></i>


(Safe XY)

JASS:
scope FrozenOrb initializer Init 

globals
    private constant integer AbilID = &#039;A000&#039; //raw id of the Frozen Orb ability
    private constant integer IceID = &#039;A001&#039; //raw id of the Frozen Orb Slow and Damage ability
    private constant string IceOrder = &quot;frostnova&quot; //order string of the Frozen Orb Slow and Damage ability
    private constant integer DummyId = &#039;n000&#039; //dummy unit&#039;s raw id (caster)
    private constant integer OrbId = &#039;n001&#039; //raw id of the Frozen Orb dummy
    private constant integer BoltId = &#039;n002&#039; //raw id of the Ice Bolt dummy
    private constant real OrbHitRange = 150. //when a unit comes within this range of the Orb, it will spread out more ice bolts
    private constant real OrbSpeed = 500 // speed of the Frozen Orb
    private constant real BoltHitRange = 50. //when a unit comes within this range of the ice bolt, it got hit.
    private constant real BoltSpeed = 1000 // speed of the Ice Bolts
    private constant string SOUNDPATH = &quot;Abilities\\Spells\\Human\\Blizzard\\BlizzardLoop1.wav&quot; //sound which is played during the spell
endglobals

//=======================
private function GetIceBoltDist takes integer lvl returns real
    return 750.
endfunction

private function GetOrbDist takes integer lvl returns real
    return 1000.
endfunction

//==== Do not modify anything below ====
//=============================
private struct dataI
    unit c
    unit d
    integer lvl
    integer tick
    real angle
    real speed
endstruct
//=============================
private struct data
    unit c
    unit d1
    unit d2
    unit d3
    group hit 
    
    sound bliz
    
    real dx
    real dy
    real df
    
    integer lvl
    real speed
    real angle
    
    real shootAngle
    
    integer tick = 40
    integer tks = 0
endstruct

globals
    private group ENUMER = CreateGroup()
    private real MAPMIN_X
    private real MAPMAX_X
    private real MAPMIN_Y
    private real MAPMAX_Y
    
    private data array ORBDATA
    private integer ORBDATACOUNT = -1
    private dataI array BOLTDATA
    private integer BOLTDATACOUNT = -1
    private integer TEMPINT
endglobals

private function CheckSafeX takes real x returns real
    if x&gt;MAPMAX_X then
        return MAPMAX_X
    endif
    if x&lt;MAPMIN_X then
        return MAPMIN_X
    endif
    return x
endfunction

private function CheckSafeY takes real y returns real
    if y&gt;MAPMAX_Y then
        return MAPMAX_Y
    endif
    if y&lt;MAPMIN_Y then
        return MAPMIN_Y
    endif
    return y
endfunction

private function GetPPX takes real x, real dist, real angle returns real
    return x + dist * Cos(angle * bj_DEGTORAD)
endfunction

private function GetPPY takes real y, real dist, real angle returns real
    return y + dist * Sin(angle * bj_DEGTORAD)
endfunction

private function SetUnitZ takes unit u, real h returns nothing
    call UnitAddAbility( u , &#039;Amrf&#039;)
    call UnitRemoveAbility( u , &#039;Amrf&#039; )
    call SetUnitFlyHeight( u , h, 0. )
endfunction

private function AngleLocXY takes real x1, real y1, real x2, real y2 returns real
    return bj_RADTODEG * Atan2(y2 - y1, x2 - x1)
endfunction
    

private function IceBoltF takes nothing returns boolean
    local dataI d = TEMPINT
    local unit a = GetFilterUnit()
    local boolean ok = false
    if IsUnitInRange(a,d.d,BoltHitRange) then
        if GetWidgetLife(a) &gt; 0.405 then
            if IsUnitEnemy(a,GetOwningPlayer(d.c)) then
                if IsUnitType(a,UNIT_TYPE_STRUCTURE) == false then
                    if IsUnitType(a,UNIT_TYPE_MAGIC_IMMUNE) == false then
                        set ok = true
                    endif
                endif
            endif
        endif
    endif
    set a = null
    return ok
endfunction

private function IceBoltM takes dataI d returns boolean
    local boolexpr bx
    local unit a
    local unit c
    
    set d.tick = d.tick - 1
    if d.tick == 0 then
        call KillUnit(d.d)
        return true
    endif
    set TEMPINT = d
    call GroupEnumUnitsInRange( ENUMER, GetUnitX(d.d), GetUnitY(d.d) , BoltHitRange + 100 , Condition( function IceBoltF ) )
    set a = FirstOfGroup(ENUMER)
    call GroupClear(ENUMER)
    if a != null then
        set c = CreateUnit(GetOwningPlayer(d.c),DummyId,GetUnitX(a),GetUnitY(a),0. )
        call UnitApplyTimedLife(c,&#039;BTLF&#039;,0.5)
        call UnitAddAbility(c, IceID )
        call SetUnitAbilityLevel(c, IceID, d.lvl)
        call IssueTargetOrder(c,IceOrder,a)
        set c = null
        set a = null
        call KillUnit(d.d)
        return true
    endif
    call SetUnitX( d.d, CheckSafeX(GetPPX(GetUnitX(d.d),d.speed, d.angle )) )
    call SetUnitY( d.d, CheckSafeY(GetPPY(GetUnitY(d.d),d.speed, d.angle ) ) )
    return false
endfunction

private function IceBolt takes unit c, integer lvl, real x, real y, real f returns nothing
    set BOLTDATACOUNT = BOLTDATACOUNT + 1
    set BOLTDATA[BOLTDATACOUNT] = dataI.create()
    set BOLTDATA[BOLTDATACOUNT].c = c
    set BOLTDATA[BOLTDATACOUNT].d = CreateUnit( GetOwningPlayer(c), BoltId , x, y, f )
    call SetUnitZ( BOLTDATA[BOLTDATACOUNT].d , 125. )
    set BOLTDATA[BOLTDATACOUNT].lvl = lvl
    set BOLTDATA[BOLTDATACOUNT].angle = f
    set BOLTDATA[BOLTDATACOUNT].speed = BoltSpeed / 25.
    set BOLTDATA[BOLTDATACOUNT].tick = R2I(GetIceBoltDist( lvl ) / BOLTDATA[BOLTDATACOUNT].speed)
    
endfunction

//=============================
    
private function OrbF takes nothing returns boolean
    local data d = TEMPINT
    local unit a = GetFilterUnit()
    local boolean ok = false
    if IsUnitInRangeXY(a,d.dx,d.dy,OrbHitRange) then
        if not IsUnitInGroup(a,d.hit) then
            if GetWidgetLife(a) &gt; 0.405 then
                if IsUnitEnemy(a,GetOwningPlayer(d.c)) then
                    if IsUnitType(a,UNIT_TYPE_STRUCTURE) == false then
                        if IsUnitType(a,UNIT_TYPE_MAGIC_IMMUNE) == false then
                            set ok = true
                        endif
                    endif
                endif
            endif
        endif
    endif
    set a = null
    return ok
endfunction
    
private function ActE takes data d returns boolean
    local integer i = 0
    local unit a
    local unit c
    local real dx
    local real dy
    set d.tick = d.tick - 1
    if d.tick == 0 then
        call StopSound( d.bliz, true, false )
        call SetUnitX(d.d1,d.dx)
        call SetUnitX(d.d2,d.dx)
        call SetUnitX(d.d3,d.dx)
        call SetUnitY(d.d1,d.dy)
        call SetUnitY(d.d2,d.dy)
        call SetUnitY(d.d3,d.dy)
        call KillUnit(d.d1)
        call KillUnit(d.d2)
        call KillUnit(d.d3)
        loop
            exitwhen i &gt; 11
            call IceBolt( d.c, d.lvl, GetPPX(d.dx,50.,i*30), GetPPY(d.dy,50.,i*30), i*30. + 90. )
            set i = i + 1
        endloop
        call DestroyGroup(d.hit)
        return true
    endif
    
    set d.df = d.df + 5
    set d.dx = CheckSafeX(GetPPX( d.dx, d.speed, d.angle ))
    set d.dy = CheckSafeY(GetPPY( d.dy, d.speed, d.angle ))
    call SetSoundPosition(d.bliz, d.dx, d.dy, 0 )
    call SetUnitX(d.d1,GetPPX(d.dx,-75,d.df))
    call SetUnitY(d.d1,GetPPY(d.dy,-75,d.df))
    call SetUnitFacing(d.d1,d.df)
    call SetUnitX(d.d2,GetPPX(d.dx,-75,d.df+120.))
    call SetUnitY(d.d2,GetPPY(d.dy,-75,d.df+120.))
    call SetUnitFacing(d.d2,d.df+120.)
    call SetUnitX(d.d3,GetPPX(d.dx,-75,d.df+240.))
    call SetUnitY(d.d3,GetPPY(d.dy,-75,d.df+240.))
    call SetUnitFacing(d.d3,d.df+240.)
    set TEMPINT = d
    call GroupEnumUnitsInRange( ENUMER, d.dx, d.dy , OrbHitRange + 100 , Condition( function OrbF ) )
    set a = FirstOfGroup(ENUMER)
    call GroupClear(ENUMER)
    if a != null then
        call GroupAddUnit(d.hit,a)
        loop
            exitwhen i &gt; 11
            call IceBolt( d.c, d.lvl, GetPPX(d.dx,50.,i*30), GetPPY(d.dy,50.,i*30), i*30. + 90. )
            set i = i + 1
        endloop
        set a = null
    endif
    
    if d.tks == 0 then
        set dx = GetPPX( d.dx, 50., d.shootAngle)
        set dy = GetPPY( d.dy, 50., d.shootAngle)
        call IceBolt( d.c, d.lvl, dx, dy, d.shootAngle + 90 )
        set dx = GetPPX( d.dx, 50., d.shootAngle+180.)
        set dy = GetPPY( d.dy, 50., d.shootAngle+180.)
        call IceBolt( d.c, d.lvl, dx, dy, d.shootAngle + 180. + 90 )
        set d.shootAngle = d.shootAngle + (30. + 15 * GetRandomInt(0,1))
        set d.tks = 3
    endif
    set d.tks = d.tks - 1
    
    return false
endfunction

private function Act takes nothing returns nothing
    local location loc = GetSpellTargetLoc()
    set ORBDATACOUNT = ORBDATACOUNT + 1
    set ORBDATA[ORBDATACOUNT] = data.create()
    set ORBDATA[ORBDATACOUNT].c = GetTriggerUnit()
    set ORBDATA[ORBDATACOUNT].lvl = GetUnitAbilityLevel(ORBDATA[ORBDATACOUNT].c,AbilID)
    set ORBDATA[ORBDATACOUNT].dx = GetUnitX(ORBDATA[ORBDATACOUNT].c)
    set ORBDATA[ORBDATACOUNT].dy = GetUnitY(ORBDATA[ORBDATACOUNT].c)
    set ORBDATA[ORBDATACOUNT].df = AngleLocXY( ORBDATA[ORBDATACOUNT].dx, ORBDATA[ORBDATACOUNT].dy, GetLocationX(loc), GetLocationY(loc) )
    set ORBDATA[ORBDATACOUNT].d1 = CreateUnit( GetOwningPlayer(ORBDATA[ORBDATACOUNT].c),OrbId,ORBDATA[ORBDATACOUNT].dx, ORBDATA[ORBDATACOUNT].dy, ORBDATA[ORBDATACOUNT].df )
    call SetUnitZ(ORBDATA[ORBDATACOUNT].d1,100. )
    set ORBDATA[ORBDATACOUNT].d2 = CreateUnit( GetOwningPlayer(ORBDATA[ORBDATACOUNT].c),OrbId,ORBDATA[ORBDATACOUNT].dx, ORBDATA[ORBDATACOUNT].dy, ORBDATA[ORBDATACOUNT].df+120 )
    call SetUnitZ(ORBDATA[ORBDATACOUNT].d2,100. )
    set ORBDATA[ORBDATACOUNT].d3 = CreateUnit( GetOwningPlayer(ORBDATA[ORBDATACOUNT].c),OrbId,ORBDATA[ORBDATACOUNT].dx, ORBDATA[ORBDATACOUNT].dy, ORBDATA[ORBDATACOUNT].df+240 )
    call SetUnitZ(ORBDATA[ORBDATACOUNT].d3,100. )
    set ORBDATA[ORBDATACOUNT].speed = OrbSpeed / 25.
    set ORBDATA[ORBDATACOUNT].angle = ORBDATA[ORBDATACOUNT].df
    set ORBDATA[ORBDATACOUNT].tick = R2I( GetOrbDist(ORBDATA[ORBDATACOUNT].lvl) / ORBDATA[ORBDATACOUNT].speed )
    set ORBDATA[ORBDATACOUNT].shootAngle = ORBDATA[ORBDATACOUNT].angle
    
    set ORBDATA[ORBDATACOUNT].bliz = CreateSound(SOUNDPATH,true,true,true,12700, 12700, &quot;&quot;)
    call SetSoundPosition(ORBDATA[ORBDATACOUNT].bliz, ORBDATA[ORBDATACOUNT].dx, ORBDATA[ORBDATACOUNT].dy, 0 )
    call SetSoundVolume(ORBDATA[ORBDATACOUNT].bliz,127)
    call StartSound(ORBDATA[ORBDATACOUNT].bliz)
    
    set ORBDATA[ORBDATACOUNT].hit = CreateGroup()
    
    call RemoveLocation( loc )
    set loc = null
endfunction
    
private function Time takes nothing returns nothing
    local integer i = 0
    local integer j
    local boolean stop
    loop
        exitwhen i &gt; ORBDATACOUNT
        set stop = ActE(ORBDATA<i>)
        if stop then
            call ORBDATA<i>.destroy()
            if i &lt; ORBDATACOUNT then
                set ORBDATA<i> = ORBDATA[ORBDATACOUNT]
            endif
            set ORBDATACOUNT = ORBDATACOUNT - 1
            set i = i - 1
        endif
        set i = i + 1
    endloop
    
    set i = 0
    loop
        exitwhen i &gt; BOLTDATACOUNT
        set stop = IceBoltM(BOLTDATA<i>)
        if stop then
            call BOLTDATA<i>.destroy()
            if i &lt; BOLTDATACOUNT then
                set BOLTDATA<i> = BOLTDATA[BOLTDATACOUNT]
            endif
            set BOLTDATACOUNT = BOLTDATACOUNT - 1
            set i = i - 1
        endif
        set i = i + 1
    endloop
    
endfunction
    
private function Cond takes nothing returns boolean
    return GetSpellAbilityId() == AbilID
endfunction

public function Init takes nothing returns nothing
    local trigger t = CreateTrigger( )
    call TriggerRegisterAnyUnitEventBJ( t, EVENT_PLAYER_UNIT_SPELL_EFFECT )
    call TriggerAddAction( t, function Act )
    call TriggerAddCondition( t, Condition ( function Cond ) )
    
    set t = CreateTrigger( )
    call TriggerRegisterTimerEvent(t,0.04, true )
    call TriggerAddAction( t, function Time )
    
    set MAPMAX_X = GetRectMaxX(bj_mapInitialPlayableArea)
    set MAPMAX_Y = GetRectMaxY(bj_mapInitialPlayableArea)
    set MAPMIN_X = GetRectMinX(bj_mapInitialPlayableArea)
    set MAPMIN_Y = GetRectMinY(bj_mapInitialPlayableArea)
endfunction

endscope</i></i></i></i></i></i>


------------------------
Implementation Instructions
- Copy ability: Frozen Orb ( A000 ) and Frozen Orb- Slow & Damage ( A001 )
- Copy dummy unit: Dummy Unit (n000), Dummy Unit - Frozen Orb (n001), Dummy Unit - Ice Bolt (n002)
- Copy trigger FrozenOrb, change raw id and some other data.
------------------------
Credit:
- thanks Tinki3 for the Test map Template
-------
EDIT: 7th update !
 

Attachments

  • [Spell] Frozen Orb.w3x
    48.6 KB · Views: 225
  • [Spell] Frozen Orb (safe xy).w3x
    50.1 KB · Views: 248

WolfieeifloW

WEHZ Helper
Reaction score
372
I don't know, but I didn't see you null the units anywhere?
Don't you have to do that?

Nice spell though.
 

WolfieeifloW

WEHZ Helper
Reaction score
372
Even in:
JASS:
private function IceBoltH takes nothing returns nothing

I don't see unit "c" nulled?

Maybe because you're applying a timed life you don't have to null it?
I just always nulled the dummy in my spells and no one said anything ;) !
 

Kenny

Back for now.
Reaction score
202
You seem to be using lots of triggers... Why not just use GroupEnumUnitsInRange() instead, it would remove the need for ABC, and gets rid of those dynamic triggers.

If you dont want to do that, at least use TriggerAddCondition instead of TriggerAddAction.

Also:

JASS:
    if d.tick == 0 then
        call KillUnit(d.d)
        set d.stop = true
    endif    
    if d.stop then
        call ClearTriggerStructA( d.trig )
        call TriggerRemoveAction(d.trig, d.trigact )
        call DestroyTrigger(d.trig)
        call d.destroy()
        return true
    endif


Why?

Why not just use: if d.tick == 0 then, it would save a struct member, and be much easier.

This is a pretty mad spell. Probably the best frozen orb I've seen. I like how you use the orbs to create the "glow" at three different angles. And it rotates :). Nice work.
 

lindenkron

You can change this now in User CP
Reaction score
102
Anyone else got

when they used the spell ? Or was that just me?
errorhu3.jpg


Nice spell though, Diablo II Sorceress ? :rolleyes:
 

Tom_Kazansky

--- wraith it ! ---
Reaction score
157
@kenny!, I think it's lagger if I use GroupEnumUnitsInRange()
>use TriggerAddCondition instead of TriggerAddAction
so I can use TriggerClearCondition ?

JASS:
//
    if d.tick == 0 then
        call KillUnit(d.d)
        set d.stop = true
    endif    
    if d.stop then
        call ClearTriggerStructA( d.trig )
        call TriggerRemoveAction(d.trig, d.trigact )
        call DestroyTrigger(d.trig)
        call d.destroy()
        return true
    endif


this is because when the ice bolt hits a unit, d.stop will be set to true, but when the d.tick == 0, the ice bolt "could be alive" :D <- I can only exlain it like that :D

@lindenkron, maybe because you cast it "out" of the map, well, I use SetUnitX, SetUnitY you know.
And, Diablo II Sorceress :D
---
EDIT: I updated the code a bit. :) and add a little sound (blizzard's loop sound)
 
Reaction score
91
Firstly, I'd suggest make the configurable stuff at least constant functions. I, personally, would like to increase the speed of the orb each level, not keep it the same.
You could at least use only ABC for the timer part not add TimerTicker as well since ABC will do you the same (speed difference isn't dramatical).

> so I can use TriggerClearCondition?
You wouldn't need to clear the action and this saves you a struct member, besides conditions are faster than actions.

>
JASS:

Leak. Not nulled and not removed.

>
JASS:

public function Init takes nothing returns nothing
    ...
    set t = null
endfunction

Nulling the trigger in any Init function isn't needed because it will still be contained in-game until the end. But keep it as it is.

>
JASS:

if not IsUnitType(a,UNIT_TYPE_STRUCTURE) then
    ... and all other ifs with &quot;not&quot;

Compare the booleans that use not with false. As it seems there are rare bugs with not comparisions.
 

Tom_Kazansky

--- wraith it ! ---
Reaction score
157
>ou could at least use only ABC for the timer part not add TimerTicker as well since ABC will do you the same (speed difference isn't dramatical).

I think use one 0.04s timer is better (or faster) than many 0.04s timers, right ? :confused:

>Leak. Not nulled and not removed.

oh, my bad :)

>Compare the booleans that use not with false. As it seems there are rare bugs with not comparisions.

hmm... I will fix that right away.
----
Update ! again :D
 
Reaction score
91
> I think use one 0.04s timer is better (or faster) than many 0.04s timers, right ?
I didn't notice you were creating more than one timer, my bad (that's because I haven't looked deeply into the code).

> call IssueTargetOrder(c,"frostnova",a)
The string needs to get on top of the script in the globals since somebody might want to base his spell on another one, not Frost Nova.
> set d.bliz = CreateSound("Abilities\\Spells\\Human\\Blizzard\\BlizzardLoop1.wav",true,true,true,12700, 12700, "")
Same here, more configuration. :p

Anyway, I just tested the spell and it seems very cute. +rep; EDIT: Blargh, I can't >_<
 

Kenny

Back for now.
Reaction score
202
@kenny!, I think it's lagger if I use GroupEnumUnitsInRange()

Not necessarily. If you use them properly, there should be no noticable difference. I have used multiple GroupEnumUnit... functions within high frequency timers and it was fine. AS long as you have "decent" usage of groups it will be ok.

And again it would get rid of ABC.

this is because when the ice bolt hits a unit, d.stop will be set to true, but when the d.tick == 0, the ice bolt "could be alive" <- I can only exlain it like that

Ahaaa, i didnt see that you set d.stop = true in the triggeraction, my bad. :D

Also you could probably just use a static timer loop instead of any system, as the basics of this spell are not overly complicated. That would get rid of the need for TT as well. Then it would be independant :D. And it would still keep one 0.04 timer, which is still as fast as... one 0.04 second timer.

However its up to you, getting rid of both ABC and TT would be a little bit of work, but the results would be worth it.

Nice idea with the sound too, "completes" the spell nicely.
 

Tom_Kazansky

--- wraith it ! ---
Reaction score
157
@Tyrande_ma3x, ok more configuration, :)

Also you could probably just use a static timer loop instead of any system, as the basics of this spell are not overly complicated. That would get rid of the need for TT as well. Then it would be independant . And it would still keep one 0.04 timer, which is still as fast as... one 0.04 second timer.

However its up to you, getting rid of both ABC and TT would be a little bit of work, but the results would be worth it.

independant sounds great, but maybe another time :D

Nice idea with the sound too, "completes" the spell nicely.

thanks ! :D

---
Updated ! again ! :)
 

Flare

Stops copies me!
Reaction score
662
There is Frozen Orb made by Flare (right ?), but I made this because someone request me to.
Well, my one is in GUI so... :D

I think it's lagger if I use GroupEnumUnitsInRange()
Well, that depends on the number of units enumerated. Sure, it's a call made every timer execution, but if little/no units are in range, or they are all ineligible for the filter, there's minimal execution dealt with there.

I, personally, would like to increase the speed of the orb each level, not keep it the same.
Well, generally values like that would be constant at all levels (for this kind of spell at least, maybe something like a charge spell would make better use of it), so adding a config function for speed would be fairly limited as regards useful-ness

Compare the booleans that use not with false. As it seems there are rare bugs with not comparisions.
The problem isn't the use of 'not', it's the use of IsUnitType without a comparison to true/false. AFAIK, only some unit types are affected by it (I believe UNIT_TYPE_TOWNHALL is one, there's a thread posted by Vexorian over at WC3JASS about it) and if you make a Boolean2Int function, you get some obscure number (I believe 1 was true, 2 was false, and the returned number for the B2I with a bad IsUnitType was 64, although exact numbers may not be correct)

Using something like this for a 'Unit is alive' check
JASS:
not GetWidgetLife (someWidget) == 0

shouldn't be buggy at all (rubbish example, but I think it'll get the idea across)

EDIT: Since I couldn't find the thread by Vex on it, I'll just quote phyrex1an's Writing Effective Code tutorial:
So to the bug. This is a condition, i.e. it is a function used in a trigger that returns a boolean value.
It is not used as a stand-alone function as the other condition we had.
In the condition we use the IsUnitType() function, and it is here the bug comes.
IsUnitType() MUST be used togheter with a comparison. I.E. IsUnitType() == true.
Else it will give bugs. Now UNIT_TYPE_HERO and RANGED_ATTACKER are the only values that don’t give bugs with this. (Strange isn't it)
But for good practice I always use the bug proof way when using this function.
 

Tom_Kazansky

--- wraith it ! ---
Reaction score
157
@Flare, about the GroupEnumUnitsInRange(), I think I just leave it like that, triggers are not very bad :)

>Why the fuck are you using 2 dynamic triggers?
hmm....

>Also, why do you need both ABC and TT?
well, I use ABC for triggers and TT for "high frequency timers"
 

Vestras

Retired
Reaction score
248
> well, I use ABC for triggers and TT for "high frequency timers"

If I were you I'd cut the dynamic triggers and use timers instead, then delete those two systems and use TimerUtils instead. (I know TimerUtils doesn't do the same thing as TT)
 

Tom_Kazansky

--- wraith it ! ---
Reaction score
157
I satisfied with how this spell currently work. :)

@Vestras, well, these two systems still work very well for me. I will try out TimerUtils later :rolleyes:

@mods, will my spell be approved in its current state ? or Do I have to improve anything ? :confused:
 

Romek

Super Moderator
Reaction score
963
Well, I don't plan to approve this until you remove the dynamic trigger usage.
You can't full destroy them (I heard actions leak), and it can cause problems with maps. Especially ones that use gamecache.
 
General chit-chat
Help Users
  • No one is chatting at the moment.

      The Helper Discord

      Members online

      No members online now.

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top