1. Are you planning to upload your awesome spell or system to Hive? Please review the rules here.
    Dismiss Notice
  2. The long-awaited results for Concept Art Contest #11 have finally been released!
    Dismiss Notice
  3. Join Texturing Contest #30 now in a legendary battle of mythological creatures!
    Dismiss Notice
  4. The Aftermath has been revealed for the 19th Terraining Contest! Be sure to check out the Results and see what came out of it.
    Dismiss Notice
  5. Hivers united and created a bunch of 2v2 melee maps. Vote for the best in our Melee Mapping Contest #4 - Poll!
    Dismiss Notice
  6. Check out the Staff job openings thread.
    Dismiss Notice

Static Charge v1.3

Submitted by Malhorne
This bundle is marked as approved. It works and satisfies the submission rules.
Static Charge

This is a spellpack that contains 4 abilities all having the same concept,movement.

Requirements :
- JNGP
- TerrainPathability by Rising Dusk : http://www.wc3c.net/showthread.php?t=103862


(Q) When used pulls all nearby enemy units close to the hero dealing 30-75 damage. The unit takes more damage the farther it is from the caster.

(W) When used pushes all nearby units away from the hero dealing 30-75 damage. The unit takes more damage the closer it is from the caster.

(E) When used pulls all enemies in a designated location dealing 30-75 damage. The unit takes more damage the farther it is from the location.

(R) When used pushes away all units from the designated location dealing 30-75 damage. The unit takes more damage the closer it is from the location.


Static Field - Attract [Q] :
Code
Code (vJASS):
scope StaticFieldA
    native UnitAlive takes unit id returns boolean
   
    globals
        private constant real FPS = 0.0312500
        private constant string MODEL_PATH = "Abilities\\Spells\\Human\\ThunderClap\\ThunderClapCaster.mdl"
        private constant integer SPELL_ID = 'A000'
        private constant string LIGHTNING_ID = "FORK"
        private constant real LIGHTNING_RED = 0.15
        private constant real LIGHTNING_GREEN = 0.45
        private constant real LIGHTNING_BLUE = 1.
        private constant real LIGHTNING_ALPHA = 1.
        private constant real DURATION = 0.75
        private constant attacktype A_TYPE = ATTACK_TYPE_MAGIC
        private constant damagetype D_TYPE = DAMAGE_TYPE_MAGIC
    endglobals
   
    private constant function MaxDamage takes integer level returns real
        return 75.*level
    endfunction
   
    private constant function MinDamage takes integer level returns real
        return 30.*level
    endfunction
   
    private constant function Aoe takes integer level returns real
        return 600 + 75.*level
    endfunction
   
    private function UnitFilter takes player source, unit targ returns boolean
        return IsUnitEnemy(targ, source) and UnitAlive(targ) and not IsUnitType(targ, UNIT_TYPE_MAGIC_IMMUNE)
    endfunction
   
    //! textmacro_once STATIC_FIELD_ALLOC
        if thistype(0).prev == 0 then
            set count = count + 1
            set this = count
        else
            set this = thistype(0).prev
            set thistype(0).prev = thistype(0).prev.prev
        endif
        if thistype(0).next == 0 then
            call TimerStart(period, FPS, true, function thistype.periodic)
        else
            set thistype(0).next.prev = this
        endif
        set this.next = thistype(0).next
        set thistype(0).next = this
        set this.prev = thistype(0)
    //! endtextmacro
   
    private struct Caster extends array
        real x
        real y
        real temp
        thistype prev
        thistype next
        static integer count
        static timer period
       
        method destroy takes nothing returns nothing
            if this.next != 0 then
                set this.next.prev = this.prev
            endif
            set this.prev.next = this.next
            set this.prev = thistype(0).prev
            set thistype(0).prev = this
            if thistype(0).next == 0 then
                call PauseTimer(period)
            endif
        endmethod
       
        static method periodic takes nothing returns nothing
            local thistype this = thistype(0).next
            loop
                exitwhen this == 0
                set this.temp = this.temp - FPS
                if this.temp <= 0 then
                    call DestroyEffect(AddSpecialEffect(MODEL_PATH, this.x, this.y))
                    call this.destroy()
                endif
                set this = this.next
            endloop
        endmethod
       
        static method add takes real x, real y returns nothing
            local thistype this
            //! runtextmacro STATIC_FIELD_ALLOC()
            set this.x = x
            set this.y = y
            set this.temp = DURATION
        endmethod
       
        static method onInit takes nothing returns nothing
            set count = 0
            set period = CreateTimer()
        endmethod
    endstruct
   
    private struct SF extends array
        unit targ
        unit cast
        lightning light
        real dmg
        real cx
        real cy
        real cz
        real tx
        real ty
        real x
        real y
        real z
        integer steps
        thistype prev
        thistype next
        static integer count
        static timer period
        static group g
        static location loc
       
        method destroy takes nothing returns nothing
            if this.next != 0 then
                set this.next.prev = this.prev
            endif
            set this.prev.next = this.next
            set this.prev = thistype(0).prev
            set thistype(0).prev = this
            if thistype(0).next == 0 then
                call PauseTimer(period)
            endif
            call UnitDamageTarget(this.cast, this.targ, this.dmg, true, false, A_TYPE, D_TYPE, null)
            call DestroyLightning(this.light)
            call SetUnitPropWindow(this.targ, GetUnitDefaultPropWindow(this.targ)*bj_DEGTORAD)
            set this.light = null
            set this.cast = null
            set this.targ = null
        endmethod
       
        static method periodic takes nothing returns nothing
            local thistype this = thistype(0).next
            loop
                exitwhen this == 0
                set this.tx = this.tx+this.x
                set this.ty = this.ty+this.y
                call MoveLocation(loc, this.tx, this.ty)
                set this.z = GetLocationZ(loc) + 20 + GetUnitFlyHeight(this.targ)
                if IsTerrainWalkable(this.tx, this.ty) then
                    call MoveLightningEx(this.light, true, this.cx, this.cy, this.cz, this.tx, this.ty, this.z)
                    call SetUnitX(this.targ, this.tx)
                    call SetUnitY(this.targ, this.ty)
                endif
                set this.steps = this.steps - 1
                if this.steps == 0 then
                    call this.destroy()
                endif
                set this = this.next
            endloop
        endmethod
       
        static method cond takes nothing returns boolean
            local thistype this
            local integer lvl
            local real angle
            local unit u
            local unit v
            local real x
            local real y
            local player p
            local real dist
            if GetSpellAbilityId() == SPELL_ID then
                set u = GetTriggerUnit()
                set x = GetUnitX(u)
                set y = GetUnitY(u)
                set p = GetOwningPlayer(u)
                set lvl = GetUnitAbilityLevel(u, SPELL_ID)
                call GroupEnumUnitsInRange(g, x, y, Aoe(lvl), null)
                loop
                    set v = FirstOfGroup(g)
                    exitwhen v == null
                    call GroupRemoveUnit(g,v)
                    if UnitFilter(p,v) then
                        //! runtextmacro STATIC_FIELD_ALLOC()
                        set this.cast = u
                        set this.targ = v
                        set this.cx = x
                        set this.cy = y
                        set this.tx = GetUnitX(v)
                        set this.ty = GetUnitY(v)
                        set angle = Atan2(this.ty-y, this.tx-x)
                        set dist = SquareRoot((this.tx-x)*(this.tx-x) + (this.ty-y)*(this.ty-y))
                        set this.dmg = MinDamage(lvl) + (dist/Aoe(lvl))*(MaxDamage(lvl)-MinDamage(lvl))
                        set this.x = -(dist/DURATION)*FPS*Cos(angle)
                        set this.y = -(dist/DURATION)*FPS*Sin(angle)
                        call MoveLocation(loc, x, y)
                        set this.cz = GetLocationZ(loc) + 20
                        call MoveLocation(loc, this.tx, this.ty)
                        set this.z = GetLocationZ(loc) + 20 + GetUnitFlyHeight(v)
                        set this.light = AddLightningEx(LIGHTNING_ID, true, this.cx, this.cy, this.cz, this.tx, this.ty, this.z)
                        call SetLightningColor(this.light, LIGHTNING_RED, LIGHTNING_GREEN, LIGHTNING_BLUE, LIGHTNING_ALPHA)
                        call SetLightningColor(this.light, LIGHTNING_RED, LIGHTNING_GREEN, LIGHTNING_BLUE, LIGHTNING_ALPHA)
                        set this.steps = R2I(DURATION/FPS)
                        call SetUnitPropWindow(this.targ, 0)
                    endif
                endloop
                call Caster.add(x,y)
                set u = null
                set p = null
            endif
            return false
        endmethod
       
        static method onInit takes nothing returns nothing
            local trigger t = CreateTrigger()
            call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
            call TriggerAddCondition(t, Condition(function thistype.cond))
            call Preload(MODEL_PATH)
            set count = 0
            set period = CreateTimer()
            set g = CreateGroup()
            set loc = Location(0,0)
            set t = null
        endmethod
    endstruct
endscope


Static Field - Expulse [W] :
Code
Code (vJASS):
scope StaticFieldE
    //native UnitAlive takes unit id returns boolean
   
    globals
        private constant real FPS = 0.0312500
        private constant string MODEL_PATH = "Abilities\\Spells\\Human\\ThunderClap\\ThunderClapCaster.mdl"
        private constant integer SPELL_ID = 'A001'
        private constant string LIGHTNING_ID = "FORK"
        private constant real LIGHTNING_RED = 1
        private constant real LIGHTNING_GREEN = 0.45
        private constant real LIGHTNING_BLUE = 0.15
        private constant real LIGHTNING_ALPHA = 1.
        private constant real DURATION = 0.75
        private constant attacktype A_TYPE = ATTACK_TYPE_MAGIC
        private constant damagetype D_TYPE = DAMAGE_TYPE_MAGIC
        private constant real SPEED = 600.
    endglobals
   
    private constant function MaxDamage takes integer level returns real
        return 75.*level
    endfunction
   
    private constant function MinDamage takes integer level returns real
        return 30.*level
    endfunction
   
    private constant function Aoe takes integer level returns real
        return 600 + 75.*level
    endfunction
   
    private function UnitFilter takes player source, unit targ returns boolean
        return IsUnitEnemy(targ, source) and UnitAlive(targ) and not IsUnitType(targ, UNIT_TYPE_MAGIC_IMMUNE)
    endfunction
   
    //! textmacro_once STATIC_FIELD_ALLOC
        if thistype(0).prev == 0 then
            set count = count + 1
            set this = count
        else
            set this = thistype(0).prev
            set thistype(0).prev = thistype(0).prev.prev
        endif
        if thistype(0).next == 0 then
            call TimerStart(period, FPS, true, function thistype.periodic)
        else
            set thistype(0).next.prev = this
        endif
        set this.next = thistype(0).next
        set thistype(0).next = this
        set this.prev = thistype(0)
    //! endtextmacro
   
    private struct SF extends array
        unit targ
        unit cast
        lightning light
        real dmg
        real cx
        real cy
        real cz
        real tx
        real ty
        real x
        real y
        real z
        integer steps
        thistype prev
        thistype next
        static integer count
        static timer period
        static group g
        static location loc
       
        method destroy takes nothing returns nothing
            if this.next != 0 then
                set this.next.prev = this.prev
            endif
            set this.prev.next = this.next
            set this.prev = thistype(0).prev
            set thistype(0).prev = this
            if thistype(0).next == 0 then
                call PauseTimer(period)
            endif
            call UnitDamageTarget(this.cast, this.targ, this.dmg, true, false, A_TYPE, D_TYPE, null)
            call DestroyLightning(this.light)
            call SetUnitPropWindow(this.targ, GetUnitDefaultPropWindow(this.targ)*bj_DEGTORAD)
            set this.light = null
            set this.cast = null
            set this.targ = null
        endmethod
       
        static method periodic takes nothing returns nothing
            local thistype this = thistype(0).next
            loop
                exitwhen this == 0
                set this.tx = this.tx+this.x
                set this.ty = this.ty+this.y
                call MoveLocation(loc, this.tx, this.ty)
                set this.z = GetLocationZ(loc) + 20 + GetUnitFlyHeight(this.targ)
                if IsTerrainWalkable(this.tx, this.ty) then
                    call MoveLightningEx(this.light, true, this.cx, this.cy, this.cz, this.tx, this.ty, this.z)
                    call SetUnitX(this.targ, this.tx)
                    call SetUnitY(this.targ, this.ty)
                endif
                set this.steps = this.steps - 1
                if this.steps == 0 then
                    call this.destroy()
                endif
                set this = this.next
            endloop
        endmethod
       
        static method cond takes nothing returns boolean
            local thistype this
            local integer lvl
            local real angle
            local unit u
            local unit v
            local real x
            local real y
            local player p
            local real dist
            if GetSpellAbilityId() == SPELL_ID then
                set u = GetTriggerUnit()
                set x = GetUnitX(u)
                set y = GetUnitY(u)
                set p = GetOwningPlayer(u)
                set lvl = GetUnitAbilityLevel(u, SPELL_ID)
                call GroupEnumUnitsInRange(g, x, y, Aoe(lvl), null)
                call DestroyEffect(AddSpecialEffect(MODEL_PATH, x, y))
                loop
                    set v = FirstOfGroup(g)
                    exitwhen v == null
                    call GroupRemoveUnit(g,v)
                    if UnitFilter(p,v) then
                        //! runtextmacro STATIC_FIELD_ALLOC()
                        set this.cast = u
                        set this.targ = v
                        set this.cx = x
                        set this.cy = y
                        set this.tx = GetUnitX(v)
                        set this.ty = GetUnitY(v)
                        set angle = Atan2(this.ty-y, this.tx-x)
                        set dist = SquareRoot((this.tx-x)*(this.tx-x) + (this.ty-y)*(this.ty-y))
                        set this.dmg = MinDamage(lvl) + (1-(dist/Aoe(lvl)))*(MaxDamage(lvl)-MinDamage(lvl))
                        set this.x = SPEED*FPS*Cos(angle)
                        set this.y = SPEED*FPS*Sin(angle)
                        call MoveLocation(loc, x, y)
                        set this.cz = GetLocationZ(loc)
                        call MoveLocation(loc, this.tx, this.ty)
                        set this.z = GetLocationZ(loc) + 20 + GetUnitFlyHeight(v)
                        set this.light = AddLightningEx(LIGHTNING_ID, true, this.cx, this.cy, this.cz, this.tx, this.ty, this.z)
                        call SetLightningColor(this.light, LIGHTNING_RED, LIGHTNING_GREEN, LIGHTNING_BLUE, LIGHTNING_ALPHA)
                        call SetLightningColor(this.light, LIGHTNING_RED, LIGHTNING_GREEN, LIGHTNING_BLUE, LIGHTNING_ALPHA)
                        set this.steps = R2I(DURATION/FPS)
                        call SetUnitPropWindow(this.targ, 0)
                    endif
                endloop
                set u = null
                set p = null
            endif
            return false
        endmethod
       
        static method onInit takes nothing returns nothing
            local trigger t = CreateTrigger()
            call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
            call TriggerAddCondition(t, Condition(function thistype.cond))
            call Preload(MODEL_PATH)
            set count = 0
            set period = CreateTimer()
            set g = CreateGroup()
            set loc = Location(0,0)
            set t = null
        endmethod
    endstruct
endscope


Distant Field - Attract [E] :
Code
Code (vJASS):
scope DistantFieldA
    //native UnitAlive takes unit id returns boolean
   
    globals
        private constant real FPS = 0.0312500
        private constant string MODEL_PATH = "Abilities\\Spells\\Human\\ThunderClap\\ThunderClapCaster.mdl"
        private constant integer SPELL_ID = 'A002'
        private constant string LIGHTNING_ID = "FORK"
        private constant real LIGHTNING_RED = 0.15
        private constant real LIGHTNING_GREEN = 0.45
        private constant real LIGHTNING_BLUE = 1.
        private constant real LIGHTNING_ALPHA = 1.
        private constant real DURATION = 0.75
        private constant attacktype A_TYPE = ATTACK_TYPE_MAGIC
        private constant damagetype D_TYPE = DAMAGE_TYPE_MAGIC
    endglobals
   
    private constant function MaxDamage takes integer level returns real
        return 75.*level
    endfunction
   
    private constant function MinDamage takes integer level returns real
        return 30.*level
    endfunction
   
    private constant function Aoe takes integer level returns real
        return 600 + 75.*level
    endfunction
   
    private function UnitFilter takes player source, unit targ returns boolean
        return IsUnitEnemy(targ, source) and UnitAlive(targ) and not IsUnitType(targ, UNIT_TYPE_MAGIC_IMMUNE)
    endfunction
   
    //! textmacro_once STATIC_FIELD_ALLOC
        if thistype(0).prev == 0 then
            set count = count + 1
            set this = count
        else
            set this = thistype(0).prev
            set thistype(0).prev = thistype(0).prev.prev
        endif
        if thistype(0).next == 0 then
            call TimerStart(period, FPS, true, function thistype.periodic)
        else
            set thistype(0).next.prev = this
        endif
        set this.next = thistype(0).next
        set thistype(0).next = this
        set this.prev = thistype(0)
    //! endtextmacro
   
    private struct Caster extends array
        real x
        real y
        real temp
        thistype prev
        thistype next
        static integer count
        static timer period
       
        method destroy takes nothing returns nothing
            if this.next != 0 then
                set this.next.prev = this.prev
            endif
            set this.prev.next = this.next
            set this.prev = thistype(0).prev
            set thistype(0).prev = this
            if thistype(0).next == 0 then
                call PauseTimer(period)
            endif
        endmethod
       
        static method periodic takes nothing returns nothing
            local thistype this = thistype(0).next
            loop
                exitwhen this == 0
                set this.temp = this.temp - FPS
                if this.temp <= 0 then
                    call DestroyEffect(AddSpecialEffect(MODEL_PATH, this.x, this.y))
                    call this.destroy()
                endif
                set this = this.next
            endloop
        endmethod
       
        static method add takes real x, real y returns nothing
            local thistype this
            //! runtextmacro STATIC_FIELD_ALLOC()
            set this.x = x
            set this.y = y
            set this.temp = DURATION
        endmethod
       
        static method onInit takes nothing returns nothing
            set count = 0
            set period = CreateTimer()
        endmethod
    endstruct
   
    private struct SF extends array
        unit targ
        unit cast
        lightning light
        real dmg
        real cx
        real cy
        real cz
        real tx
        real ty
        real x
        real y
        real z
        integer steps
        thistype prev
        thistype next
        static integer count
        static timer period
        static group g
        static location loc
       
        method destroy takes nothing returns nothing
            if this.next != 0 then
                set this.next.prev = this.prev
            endif
            set this.prev.next = this.next
            set this.prev = thistype(0).prev
            set thistype(0).prev = this
            if thistype(0).next == 0 then
                call PauseTimer(period)
            endif
            call UnitDamageTarget(this.cast, this.targ, this.dmg, true, false, A_TYPE, D_TYPE, null)
            call DestroyLightning(this.light)
            call SetUnitPropWindow(this.targ, GetUnitDefaultPropWindow(this.targ)*bj_DEGTORAD)
            set this.light = null
            set this.cast = null
            set this.targ = null
        endmethod
       
        static method periodic takes nothing returns nothing
            local thistype this = thistype(0).next
            loop
                exitwhen this == 0
                set this.tx = this.tx+this.x
                set this.ty = this.ty+this.y
                call MoveLocation(loc, this.tx, this.ty)
                set this.z = GetLocationZ(loc) + 20 + GetUnitFlyHeight(this.targ)
                if IsTerrainWalkable(this.tx, this.ty) then
                    call MoveLightningEx(this.light, true, this.cx, this.cy, this.cz, this.tx, this.ty, this.z)
                    call SetUnitX(this.targ, this.tx)
                    call SetUnitY(this.targ, this.ty)
                endif
                set this.steps = this.steps - 1
                if this.steps == 0 then
                    call this.destroy()
                endif
                set this = this.next
            endloop
        endmethod
       
        static method cond takes nothing returns boolean
            local thistype this
            local integer lvl
            local real angle
            local unit u
            local unit v
            local real x
            local real y
            local player p
            local real dist
            if GetSpellAbilityId() == SPELL_ID then
                set u = GetTriggerUnit()
                set x = GetSpellTargetX()
                set y = GetSpellTargetY()
                set p = GetOwningPlayer(u)
                set lvl = GetUnitAbilityLevel(u, SPELL_ID)
                call GroupEnumUnitsInRange(g, x, y, Aoe(lvl), null)
                loop
                    set v = FirstOfGroup(g)
                    exitwhen v == null
                    call GroupRemoveUnit(g,v)
                    if UnitFilter(p,v) then
                        //! runtextmacro STATIC_FIELD_ALLOC()
                        set this.cast = u
                        set this.targ = v
                        set this.cx = x
                        set this.cy = y
                        set this.tx = GetUnitX(v)
                        set this.ty = GetUnitY(v)
                        set angle = Atan2(this.ty-y, this.tx-x)
                        set dist = SquareRoot((this.tx-x)*(this.tx-x) + (this.ty-y)*(this.ty-y))
                        set this.dmg = MinDamage(lvl) + (dist/Aoe(lvl))*(MaxDamage(lvl)-MinDamage(lvl))
                        set this.x = -(dist/DURATION)*FPS*Cos(angle)
                        set this.y = -(dist/DURATION)*FPS*Sin(angle)
                        call MoveLocation(loc, x, y)
                        set this.cz = GetLocationZ(loc) + 20
                        call MoveLocation(loc, this.tx, this.ty)
                        set this.z = GetLocationZ(loc) + 20 + GetUnitFlyHeight(v)
                        set this.light = AddLightningEx(LIGHTNING_ID, true, this.cx, this.cy, this.cz, this.tx, this.ty, this.z)
                        call SetLightningColor(this.light, LIGHTNING_RED, LIGHTNING_GREEN, LIGHTNING_BLUE, LIGHTNING_ALPHA)
                        call SetLightningColor(this.light, LIGHTNING_RED, LIGHTNING_GREEN, LIGHTNING_BLUE, LIGHTNING_ALPHA)
                        set this.steps = R2I(DURATION/FPS)
                        call SetUnitPropWindow(this.targ, 0)
                    endif
                endloop
                call Caster.add(x,y)
                set u = null
                set p = null
            endif
            return false
        endmethod
       
        static method onInit takes nothing returns nothing
            local trigger t = CreateTrigger()
            call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
            call TriggerAddCondition(t, Condition(function thistype.cond))
            call Preload(MODEL_PATH)
            set count = 0
            set period = CreateTimer()
            set g = CreateGroup()
            set loc = Location(0,0)
            set t = null
        endmethod
    endstruct
endscope


Distant Field - Expulse [R] :
Code
Code (vJASS):
scope DistantFieldE
    //native UnitAlive takes unit id returns boolean
   
    globals
        private constant real FPS = 0.0312500
        private constant string MODEL_PATH = "Abilities\\Spells\\Human\\ThunderClap\\ThunderClapCaster.mdl"
        private constant integer SPELL_ID = 'A003'
        private constant string LIGHTNING_ID = "FORK"
        private constant real LIGHTNING_RED = 1
        private constant real LIGHTNING_GREEN = 0.45
        private constant real LIGHTNING_BLUE = 0.15
        private constant real LIGHTNING_ALPHA = 1.
        private constant real DURATION = 0.75
        private constant attacktype A_TYPE = ATTACK_TYPE_MAGIC
        private constant damagetype D_TYPE = DAMAGE_TYPE_MAGIC
        private constant real SPEED = 600.
    endglobals
   
    private constant function MaxDamage takes integer level returns real
        return 75.*level
    endfunction
   
    private constant function MinDamage takes integer level returns real
        return 30.*level
    endfunction
   
    private constant function Aoe takes integer level returns real
        return 600 + 75.*level
    endfunction
   
    private function UnitFilter takes player source, unit targ returns boolean
        return IsUnitEnemy(targ, source) and UnitAlive(targ) and not IsUnitType(targ, UNIT_TYPE_MAGIC_IMMUNE)
    endfunction
   
    //! textmacro_once STATIC_FIELD_ALLOC
        if thistype(0).prev == 0 then
            set count = count + 1
            set this = count
        else
            set this = thistype(0).prev
            set thistype(0).prev = thistype(0).prev.prev
        endif
        if thistype(0).next == 0 then
            call TimerStart(period, FPS, true, function thistype.periodic)
        else
            set thistype(0).next.prev = this
        endif
        set this.next = thistype(0).next
        set thistype(0).next = this
        set this.prev = thistype(0)
    //! endtextmacro
   
    private struct SF extends array
        unit targ
        unit cast
        lightning light
        real dmg
        real cx
        real cy
        real cz
        real tx
        real ty
        real x
        real y
        real z
        integer steps
        thistype prev
        thistype next
        static integer count
        static timer period
        static group g
        static location loc
       
        method destroy takes nothing returns nothing
            if this.next != 0 then
                set this.next.prev = this.prev
            endif
            set this.prev.next = this.next
            set this.prev = thistype(0).prev
            set thistype(0).prev = this
            if thistype(0).next == 0 then
                call PauseTimer(period)
            endif
            call UnitDamageTarget(this.cast, this.targ, this.dmg, true, false, A_TYPE, D_TYPE, null)
            call DestroyLightning(this.light)
            call SetUnitPropWindow(this.targ, GetUnitDefaultPropWindow(this.targ)*bj_DEGTORAD)
            set this.light = null
            set this.cast = null
            set this.targ = null
        endmethod
       
        static method periodic takes nothing returns nothing
            local thistype this = thistype(0).next
            loop
                exitwhen this == 0
                set this.tx = this.tx+this.x
                set this.ty = this.ty+this.y
                call MoveLocation(loc, this.tx, this.ty)
                set this.z = GetLocationZ(loc) + 20 + GetUnitFlyHeight(this.targ)
                if IsTerrainWalkable(this.tx, this.ty) then
                    call MoveLightningEx(this.light, true, this.cx, this.cy, this.cz, this.tx, this.ty, this.z)
                    call SetUnitX(this.targ, this.tx)
                    call SetUnitY(this.targ, this.ty)
                endif
                set this.steps = this.steps - 1
                if this.steps == 0 then
                    call this.destroy()
                endif
                set this = this.next
            endloop
        endmethod
       
        static method cond takes nothing returns boolean
            local thistype this
            local integer lvl
            local real angle
            local unit u
            local unit v
            local real x
            local real y
            local player p
            local real dist
            if GetSpellAbilityId() == SPELL_ID then
                set u = GetTriggerUnit()
                set x = GetSpellTargetX()
                set y = GetSpellTargetY()
                set p = GetOwningPlayer(u)
                set lvl = GetUnitAbilityLevel(u, SPELL_ID)
                call GroupEnumUnitsInRange(g, x, y, Aoe(lvl), null)
                call DestroyEffect(AddSpecialEffect(MODEL_PATH, x, y))
                loop
                    set v = FirstOfGroup(g)
                    exitwhen v == null
                    call GroupRemoveUnit(g,v)
                    if UnitFilter(p,v) then
                        //! runtextmacro STATIC_FIELD_ALLOC()
                        set this.cast = u
                        set this.targ = v
                        set this.cx = x
                        set this.cy = y
                        set this.tx = GetUnitX(v)
                        set this.ty = GetUnitY(v)
                        set angle = Atan2(this.ty-y, this.tx-x)
                        set dist = SquareRoot((this.tx-x)*(this.tx-x) + (this.ty-y)*(this.ty-y))
                        set this.dmg = MinDamage(lvl) + (1-(dist/Aoe(lvl)))*(MaxDamage(lvl)-MinDamage(lvl))
                        set this.x = SPEED*FPS*Cos(angle)
                        set this.y = SPEED*FPS*Sin(angle)
                        call MoveLocation(loc, x, y)
                        set this.cz = GetLocationZ(loc) + 20
                        call MoveLocation(loc, this.tx, this.ty)
                        set this.z = GetLocationZ(loc) + 20 + GetUnitFlyHeight(v)
                        set this.light = AddLightningEx(LIGHTNING_ID, true, this.cx, this.cy, this.cz, this.tx, this.ty, this.z)
                        call SetLightningColor(this.light, LIGHTNING_RED, LIGHTNING_GREEN, LIGHTNING_BLUE, LIGHTNING_ALPHA)
                        set this.steps = R2I(DURATION/FPS)
                        call SetUnitPropWindow(this.targ, 0)
                    endif
                endloop
                set u = null
                set p = null
            endif
            return false
        endmethod
       
        static method onInit takes nothing returns nothing
            local trigger t = CreateTrigger()
            call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
            call TriggerAddCondition(t, Condition(function thistype.cond))
            call Preload(MODEL_PATH)
            set count = 0
            set period = CreateTimer()
            set g = CreateGroup()
            set loc = Location(0,0)
            set t = null
        endmethod
    endstruct
endscope


To import one of those spells :
- Copy and paste the code of the spell you want.
- Copy the ability and paste.
- Change the rawcode if necessary in the globals block of the spell.
- Customize the spell with everything above the textmacro
- Enjoy !


Credits :
- Vexorian for vJASS
- Rising Dusk for the TerrainPathability library

Another Credits :
- My mother for giving birth to me
- My neighbour that hasn't called the police yet even though if I blast Conception@max volume on 3 A.M.
- Roy Khan for singing in Conception and Kamelot
- Riot Games for creating League of Legends
- Black Sabbath for creating Metal
- My fencing sword that hasn't broken
- My battery that has died and deserves a proper burial.
- The Hive Workshop because...it exists?
- My imaginary friend that told me Warcraft 3 is awesome
- My fridge for conserving my food
- All the animals that are butchered just to be turned to food so I can survive.
- The Blood Mage that let me teach him some cool spells
- My bed that lets me sleep on it
- All my clothes that keep me warm
- Last but not least, all my organs that keep working :D
- Paliouras for finding all those useless credits :p


Constructive criticism is welcome !
WARNING : No real footmen were hurt during the process...oh well maybe some!

Changelog
v1.0 : Initial release :)

v1.1 : Added TerrainPathability :p

v1.2 : Added textmacro_once :)

v1.3 : Fix bug with flying height of units


Keywords:
static, static field, lightning, Malhorne, malhorne, vJASS, JESP, spellpack, attract, expulse, static charge, charge, field
Contents

Just another Warcraft III map (Map)

Reviews
Moderator
22:25, 9th Feb 2014 BPower: Required changes made and overall good coding. Approved.
  1. 22:25, 9th Feb 2014
    BPower:
    Required changes made and overall good coding.
    Approved.
     
  2. Malhorne

    Malhorne

    Joined:
    Sep 14, 2012
    Messages:
    2,336
    Resources:
    6
    Spells:
    4
    Tutorials:
    1
    JASS:
    1
    Resources:
    6
    Reserved~

    I'll change the screenshot as soon as I get my computer back :s
     
  3. IcemanBo

    IcemanBo

    Joined:
    Sep 6, 2013
    Messages:
    6,054
    Resources:
    22
    Maps:
    3
    Spells:
    11
    Template:
    1
    Tutorials:
    4
    JASS:
    3
    Resources:
    22
    Yo Malhorne, nice credit list you got there! ^^

    You're using MoveUnitX/Y and this causes some unwilled situations for me.

    I changed test map a bit and I was able to push units over cliffs, into buildings, into water, and yes also into deep water.

    Please make some kind of pathing check before you move units.

    For spell itself... I really like the concept, man! I especially enjoyed the spell where you cast on a point and pushes all enemies away. This can be nice support to help nearby units which have low life, for example. :csmile:
     
  4. Malhorne

    Malhorne

    Joined:
    Sep 14, 2012
    Messages:
    2,336
    Resources:
    6
    Spells:
    4
    Tutorials:
    1
    JASS:
    1
    Resources:
    6
    Ah yes I think I'll include some IsTerrainPathable library in the next update :)
    Anyway thanks for the reply and I'm glad you liked it :)

    EDIT : Wanted to include BoundSentinel but that's not enough xD And at last I include nothing that's why ^^' My bad xD
     
  5. Rheiko

    Rheiko

    Joined:
    Aug 27, 2013
    Messages:
    2,943
    Resources:
    7
    Icons:
    2
    Spells:
    3
    Tutorials:
    2
    Resources:
    7
    i almost died because of reading the credit list ._.
     
  6. Malhorne

    Malhorne

    Joined:
    Sep 14, 2012
    Messages:
    2,336
    Resources:
    6
    Spells:
    4
    Tutorials:
    1
    JASS:
    1
    Resources:
    6
    Glad you didn't die thou
     
  7. IcemanBo

    IcemanBo

    Joined:
    Sep 6, 2013
    Messages:
    6,054
    Resources:
    22
    Maps:
    3
    Spells:
    11
    Template:
    1
    Tutorials:
    4
    JASS:
    3
    Resources:
    22
    What I forgot to say in my first post:

    In my test map I created some big chickens. I tryed to push them, bud sadly it didnt work. :<

    So I would also make it configurable to cast on neutrale passive, as well :D
     
  8. Malhorne

    Malhorne

    Joined:
    Sep 14, 2012
    Messages:
    2,336
    Resources:
    6
    Spells:
    4
    Tutorials:
    1
    JASS:
    1
    Resources:
    6
    See the function Filter :)
    Change IsUnitEnemy to not IsUnitAlly
     
  9. BPower

    BPower

    Joined:
    Mar 18, 2012
    Messages:
    1,745
    Resources:
    21
    Spells:
    15
    Tutorials:
    1
    JASS:
    5
    Resources:
    21
    Great tooltips.
    I don't see a benefit in the textmacros in Expulse, because you only need them once.
    GetUnitDefaultPropWindow(this.targ)*bj_DEGTORAD
    I will test this myself later, I know you told me it works flawless.
    The code itself looks good on a first impression.
     
  10. Malhorne

    Malhorne

    Joined:
    Sep 14, 2012
    Messages:
    2,336
    Resources:
    6
    Spells:
    4
    Tutorials:
    1
    JASS:
    1
    Resources:
    6
    There isn't a benefice but at start I used the same for every spell
    But then I forgot that those spell could be separated xD
     
  11. Malhorne

    Malhorne

    Joined:
    Sep 14, 2012
    Messages:
    2,336
    Resources:
    6
    Spells:
    4
    Tutorials:
    1
    JASS:
    1
    Resources:
    6
    Updated !

    Changelog
    v1.0 : Initial release :)

    v1.1 : Added TerrainPathability :p
     
  12. TriggerHappy

    TriggerHappy

    Code Moderator

    Joined:
    Jun 23, 2007
    Messages:
    3,578
    Resources:
    22
    Spells:
    11
    Tutorials:
    2
    JASS:
    9
    Resources:
    22
    I haven't had a chance to test it yet but here's some comments

    • The screenshot needs to be fixed.
    • You don't need to comment the UnitAlive declaration, JassHelper handles it correctly (vexorian's at least).
    • The Aloc textmacros could possibly be a modules (thus being private). The name should at least be a bit more unique. Although I think I would prefer the standard allocation.
    • Preloading should be optional.
    • You should be using GroupUtils's ENUM_GROUP instead of creating 4 groups for each variation.
     
  13. Malhorne

    Malhorne

    Joined:
    Sep 14, 2012
    Messages:
    2,336
    Resources:
    6
    Spells:
    4
    Tutorials:
    1
    JASS:
    1
    Resources:
    6
    - Yes but I can't use my computer atm I'm truly sorry for the screenshot :/
    - Vexorian's bug on UnitAlive.
    - Inline is 55% faster so textmacros>modules
    - What about preloading :eek: ?
    - I hate using other resources and just for this ...
     
  14. TriggerHappy

    TriggerHappy

    Code Moderator

    Joined:
    Jun 23, 2007
    Messages:
    3,578
    Resources:
    22
    Spells:
    11
    Tutorials:
    2
    JASS:
    9
    Resources:
    22
    What bug? The map optimizer works perfectly fine with UnitAlive and so does JassHelper.

    Modules are basically text macros, why don't you compile and see.

    It should be optional with static if's.

    Static if's.
     
  15. Malhorne

    Malhorne

    Joined:
    Sep 14, 2012
    Messages:
    2,336
    Resources:
    6
    Spells:
    4
    Tutorials:
    1
    JASS:
    1
    Resources:
    6
    If you declare multiple times UnitAlive it throws an error.

    I inline my allocation in the function whereas Alloc module is a function so calling it is slower....

    I don't get why ?
    It is always better for the sake of the spell that I preload :/
    But if you think it is necessary why not.

    I won't use other people resource as usual.
     
  16. BPower

    BPower

    Joined:
    Mar 18, 2012
    Messages:
    1,745
    Resources:
    21
    Spells:
    15
    Tutorials:
    1
    JASS:
    5
    Resources:
    21
    Just with Cohadars JassHelper. Vexorians is totally fine with it.
     
  17. Malhorne

    Malhorne

    Joined:
    Sep 14, 2012
    Messages:
    2,336
    Resources:
    6
    Spells:
    4
    Tutorials:
    1
    JASS:
    1
    Resources:
    6
    Yes but some people (like me) use Cohadar's for speed :)

    EDIT : Sorry I said Vex instead of Cohadar before :/
     
  18. BPower

    BPower

    Joined:
    Mar 18, 2012
    Messages:
    1,745
    Resources:
    21
    Spells:
    15
    Tutorials:
    1
    JASS:
    5
    Resources:
    21
    All spells share the same textmacro, hence you will do the following:
    Code (vJASS):
        //! textmacro_once STATIC_FIELD_ALLOC
            if thistype(0).prev == 0 then
                set count = count + 1
                set this = count
            else
                set this = thistype(0).prev
                set thistype(0).prev = thistype(0).prev.prev
            endif
            if thistype(0).next == 0 then
                call TimerStart(period, FPS, true, function thistype.periodic)
            else
                set thistype(0).next.prev = this
            endif
            set this.next = thistype(0).next
            set thistype(0).next = this
            set this.prev = thistype(0)
        //! endtextmacro

    Similar to library_once the textmacro_once allows you to declare the same textmacro name twice, it would just ignore the second declaration and avoid to add its contents instead of showing a syntax error.

    - Preloading could be optional, because it consumes extra time while loading the map.
    - The tooltips are horrible.
    - The screenshot is horrible.
    - Overall good coding.
    - SpellEffectEvent could be optional.
     
  19. Malhorne

    Malhorne

    Joined:
    Sep 14, 2012
    Messages:
    2,336
    Resources:
    6
    Spells:
    4
    Tutorials:
    1
    JASS:
    1
    Resources:
    6
    Oh I didn't knew the trick of textmacro once thanks :)

    Ok for preloading.
    Computers at school seem to have gimp so normally the picture could be resized during the week.
    Thanks.
    I won't as usual xD !

    EDIT :
    Why changing your mind after xD ?
     
    Last edited: Feb 5, 2014