1. Are you planning to upload your awesome spell or system to Hive? Please review the rules here.
    Dismiss Notice
  2. Seek unity between the elements in the 22nd Terraining Contest Poll.
    Dismiss Notice
  3. Seize the moment! The 18th Mini Mapping Contest has commenced.
    Dismiss Notice
  4. The heavens smile on the old faithful. The 16th Techtree Contest has begun.
    Dismiss Notice
  5. Check out the Staff job openings thread.
    Dismiss Notice
Dismiss Notice
60,000 passwords have been reset on July 8, 2019. If you cannot login, read this.

Gummy Leash v2.5

Submitted by Kazeon
This bundle is marked as approved. It works and satisfies the submission rules.
Description

Summons a mythical orb upon the target point. Nearby enemy units will be captured by an elastical energy stream which will keep them from moving further away from the orb.​

Preview
[​IMG]

External Dependencies
- IsTerrainWalkable by Anitarf and Vexorian
- CTL by Nestharus
- AutoFly by Nestharus
- WorldBounds by Nestharus
- UnitIndexer by Nestharus
- GetClosestWidget by Bannar
- SpellEffectEvent by Bribe
- UnitZ by Garfield1337
Code
Consists of 2 triggers:
GummyLink
Code (vJASS):
library GummyLink uses CTL, WorldBounds, UnitZ, IsTerrainWalkable optional AutoFly
    /*
                        Gummy Link v2.5
       
        Descriptions:
            A library used to create magical link between
            two units which will drag the target toward the
            source elastically.
           
         !! Source of any link should not be able to move !!
       
        External Dependencies:
            (Required)
            - CTL
            - UnitZ
            - WorldBounds
            - UnitIndexer
            - IsTerrainWalkable
           
            (Optional)
            - AutoFly
           
        How to use:
            struct GummyLink
                1. Create connection between two units
                static method connect takes unit s, unit t, real z, real power, real elastic, string mdl, boolean is3D returns thistype
                    s       => source
                    t       => target
                    z       => lightning z offset
                    power   => drag power
                    elastic => link elasticity
                    mdl     => lightning model string
                    is3D      => simulate 3D effect
               
                2. Remove a connection
                method remove takes nothing returns nothing
           
        Credits:
            - IsTerrainWalkable by Anitarf and Vexorian
            - CTL               by Nestharus
            - AutoFly           by Nestharus
            - WorldBounds       by Nestharus
            - UnitIndexer       by Nestharus
            - GetClosestWidget  by Bannar
            - SpellEffectEvent  by Bribe
            - UnitZ             by Garfield1337
            - OrbDragonX.mdx    by Frankster
            - BTNManaBreathe    by D.ee
            - LaserBlue.blp     by Erkki2
           
        Link:
            hiveworkshop.com/forums/spells-569/gummy-leash-v1-0-a-257717/
    */

                        // CONFIGURATIONS
    globals
        // Unit flying height reset rate
        private constant real RESET_RATE = 15.0
       
        // Add KB effect after unit's link destroy
        private constant boolean ENABLE_KB = true
    endglobals
   
    // Just skip these KB datas if ENABLE_KB is false
    private module KBData
        // Friction rate when units flung on the ground
        static constant real FRICTION_FACTOR_GROUND = 0.04
       
        // Friction rate when units flung in the air
        static constant real FRICTION_FACTOR_AIR = 0.5
       
        // General destructable heights
        // For better idea, this is minimum height
        // before pathability checking is performed
        static constant real DEST_HEIGHT = 100.0
    endmodule
   
    // =============================================================================
       
    // Check whether given coords is in map bound or not
    private constant function inBound takes real x, real y returns boolean
        return x < WorldBounds.maxX and y < WorldBounds.maxY and x > WorldBounds.minX and y > WorldBounds.minY
    endfunction
   
    private module KBModule
   
        unit target
        real speed
        real rate
        real cos
        real sin
       
        implement KBData
   
        implement CTL
            local real f
            local real x
            local real y
           
        implement CTLExpire
            if .speed > .rate then
                set x = GetUnitX(.target) + .speed * .cos
                set y = GetUnitY(.target) + .speed * .sin
                set f = GetUnitFlyHeight(.target)
                if f > DEST_HEIGHT then
                    // Ignore any pathability issue except world bounds
                    if inBound(x, y) then
                        call SetUnitX(.target, x)
                        call SetUnitY(.target, y)
                    endif
                else
                    if IsTerrainWalkable(x, y) then
                        call SetUnitX(.target, x)
                        call SetUnitY(.target, y)
                    else
                        call destroy()
                        set .target = null
                    endif
                endif
                if f > .01 then
                    set .speed = .speed - .rate * FRICTION_FACTOR_AIR
                else
                    set .speed = .speed - .rate
                endif
            else
                call destroy()
                set .target = null
            endif
        implement CTLEnd
       
        static method knock takes unit u, real a, real s returns nothing
       
            local thistype this = create()
           
            set .target = u
            set .speed  = s
            set .cos    = Cos(a)
            set .sin    = Sin(a)
            set .rate   = s * FRICTION_FACTOR_GROUND
           
        endmethod
       
    endmodule
   
    // Add simple KB effect to a unit
    private struct SimpleKB extends array
        static if ENABLE_KB then
            implement KBModule
        endif
    endstruct
   
    // Struct used to modify and save unit's fly height
    // since the default one doesn't fit my needs
    private struct UnitZ extends array
   
        unit unit
        real rate
        real height
       
        static real array Height
        static thistype array Index
       
        implement CTL
            local integer dex
           
        implement CTLExpire
            set dex = GetUnitUserData(.unit)
            if Height[dex] > .height then
                set Height[dex] = Height[dex] - .rate
                if Height[dex] < .height then
                    set Height[dex] = .height
                endif
                call SetUnitFlyHeight(.unit, Height[dex], 0)
            elseif Height[dex] < .height then
                set Height[dex] = Height[dex] + .rate
                if Height[dex] > .height then
                    set Height[dex] = .height
                endif
                call SetUnitFlyHeight(.unit, Height[dex], 0)
            else
                set Index[dex] = 0
                call destroy()
                set .unit = null
            endif
        implement CTLEnd
       
        static method get takes unit u returns real
            return Height[GetUnitUserData(u)]
        endmethod
       
        static method apply takes unit u, real h, real r returns nothing
           
            local thistype this
            local integer  dex  = GetUnitUserData(u)
           
            // If instant rate
            if r < 1 then
                set Height[dex] = h
                call SetUnitFlyHeight(u, Height[dex], 0)
                if Index[dex] != 0 then
                    set Index[dex].height = h
                endif
            else
                if Index[dex] == 0 then
                    set this        = create()
                    set .unit       = u
                    set .height     = h
                    set .rate       = r
                    set Index[dex]  = this
                    set Height[dex] = GetUnitFlyHeight(u)
                else
                    set Index[dex].height = h
                    set Index[dex].rate = r
                endif
            endif
           
        endmethod
       
        static method onIndex takes nothing returns boolean
            set Height[GetIndexedUnitId()] = GetUnitFlyHeight(GetIndexedUnit())
            return false
        endmethod
       
        static method onInit takes nothing returns nothing
            call RegisterUnitIndexEvent(Condition(function thistype.onIndex), UnitIndexer.INDEX)
        endmethod
       
    endstruct
   
    struct GummyLink extends array
       
        readonly unit source
        readonly unit target
       
        private real z
        private real pow
        private real elstc
       
        private boolean   b
        private boolean   is3D
        private lightning link
       
        private static real    array sX
        private static real    array sY
        private static real    array tX
        private static real    array tY
        private static real    array HVel
        private static real    array VVel
        private static real    array Height
        private static boolean array Bool
       
        private static constant real TAU = bj_PI*2
        private static constant real HP  = bj_PI/2
        private static constant real M   = 0.2
       
        // Gets circular differences between two radians
        private static method circDifference takes real a, real b returns real
       
            local real r = RAbsBJ(a-b)
           
            if r * 2 <= TAU then
                return r
            else
                return TAU - r
            endif
           
        endmethod
       
        implement CTL
            local real    a
            local real    v
            local real    z
            local integer sDex
            local integer tDex
           
        implement CTLExpire
            set sDex = GetUnitUserData(.source)
            set tDex = GetUnitUserData(.target)
            // Automatically destroy link if unit has been removed
            if .b and GetUnitTypeId(.source) != 0 and GetUnitTypeId(.target) != 0 then
                set a = Atan2(tY[tDex] - sY[sDex], tX[tDex] - sX[sDex])
                // Calculate horizontal velocity
                if HVel[tDex] >= 0 then
                    set HVel[tDex] = HVel[tDex] - .elstc
                else
                    set HVel[tDex] = HVel[tDex] - .pow
                endif
               
                set tX[tDex] = tX[tDex] + HVel[tDex] * Cos(a)
                set tY[tDex] = tY[tDex] + HVel[tDex] * Sin(a)
                if circDifference(a, Atan2(tY[tDex] - sY[sDex], tX[tDex] - sX[sDex])) > HP then
                    set HVel[tDex] = HVel[tDex] *  -1
                endif
               
                set z  = GetUnitZ(.source) + .z
                // If 3D simulation is enabled
                if .is3D then
                    // Calculate vertical velocity
                    if Height[tDex] < z then
                        set VVel[tDex] = VVel[tDex] + .pow*M
                    else
                        set VVel[tDex] = VVel[tDex] - (.elstc+elstc*(1-M))
                    endif
                   
                    set Height[tDex] = Height[tDex] + VVel[tDex]
                    if Height[tDex] < 0 then
                        set Height[tDex] = 0
                        if VVel[tDex] < HVel[tDex] then
                            set VVel[tDex] = 0
                        endif
                    endif
                    call UnitZ.apply(.target, Height[tDex], 0)
                endif
               
                if inBound(tX[tDex], tY[tDex]) then
                    call SetUnitX(.target, tX[tDex])
                    call SetUnitY(.target, tY[tDex])
                    // Update the lightning
                    call MoveLightningEx(.link, false, sX[sDex], sY[sDex], z, tX[tDex], tY[tDex], GetUnitZ(.target) + .z)
                endif
            else
                call SetUnitPathing(.source, true)
                call SetUnitPathing(.target, true)
                static if ENABLE_KB then
                    // Determine KB direction
                    if HVel[tDex] < 0 then
                        call SimpleKB.knock(.target, Atan2(sY[sDex] - tY[tDex], sX[sDex] - tX[tDex]), RAbsBJ(HVel[tDex]))
                    else
                        call SimpleKB.knock(.target, Atan2(tY[tDex] - sY[sDex], tX[tDex] - sX[sDex]), HVel[tDex])
                    endif
                endif
               
                // Reset fly height
                if .is3D then
                    call UnitZ.apply(.target, GetUnitDefaultFlyHeight(.target), RESET_RATE)
                endif
               
                call DestroyLightning(.link)
                set Bool[tDex] = false
                set HVel[tDex] = 0
                set VVel[tDex] = -RESET_RATE
               
                call destroy()
                set .source = null
                set .target = null
                set .link   = null
            endif
        implement CTLEnd
       
        method remove takes nothing returns nothing
            set .b = false
        endmethod
       
        static method connect takes unit s, unit t, real z, real power, real elastic, string mdl, boolean is3D returns thistype
           
            local thistype this = 0
            local integer  dex
           
            if not Bool[GetUnitUserData(t)] then
                set this      = create()
               
                set .z        = z
                set .source   = s
                set .target   = t
                set .is3D     = is3D
               
                set .pow      = power
                set .elstc    = elastic
                set .b        = true
                set .link     = AddLightningEx(mdl, false, GetUnitX(s), GetUnitY(s), GetUnitZ(s) + z, GetUnitX(t), GetUnitY(t), GetUnitZ(t) + z)
               
                set dex       = GetUnitUserData(s)
                set sX[dex]   = GetUnitX(s)
                set sY[dex]   = GetUnitY(s)
                set Bool[dex] = true
               
                set dex       = GetUnitUserData(t)
                set tX[dex]   = GetUnitX(t)
                set tY[dex]   = GetUnitY(t)
                set Bool[dex] = true
               
                call SetUnitPathing(s, false)
                call SetUnitPathing(t, false)
                if is3D then
                    set Height[dex]  = UnitZ.get(t)
                    static if not LIBRARY_AutoFly then
                        if UnitAddAbility(t, 'Amrf') and UnitRemoveAbility(t, 'Amrf') then
                        endif
                    endif
                endif
            debug else
                debug call BJDebugMsg("Connecting failed: target is already connected to other instance.")
            endif
           
            return this
        endmethod
       
    endstruct
   
endlibrary
GummyLeash
Code (vJASS):
scope GummyLeash
    /*
                        Gummy Leash v2.5
                       
        Descriptions:
            Summons a mythical orb upon the target point.
            Nearby enemy units will be captured by an
            elastical energy stream which will keep them
            from moving further away from the orb.
       
        Requires:
            - GummyLink
           
        External Dependencies:
            (Required)
            - CTL
            - UnitIndexer
            - WorldBounds
           
            (Optional)
            - GetClosestWidget
            - SpellEffectEvent
           
        How to import:
            - Install and configure all dependencies properly
            - Copy GummyLeash trigger group into your map
            - Import all necessary stuffs (OE & import data) to your map
            - Configure the spell
           
        Credits:
            - IsTerrainWalkable by Anitarf and Vexorian
            - CTL               by Nestharus
            - AutoFly           by Nestharus
            - WorldBounds       by Nestharus
            - UnitIndexer       by Nestharus
            - GetClosestWidget  by Bannar
            - SpellEffectEvent  by Bribe
            - UnitZ             by Garfield1337
            - OrbDragonX.mdx    by Frankster
            - BTNManaBreathe    by D.ee
            - LaserBlue.blp     by Erkki2
           
        Link:
            hiveworkshop.com/forums/spells-569/gummy-leash-v1-0-a-257717/
    */

                        // CONFIGURATIONS
                       
    // Native declaration
    native UnitAlive takes unit id returns boolean
   
    globals
   
        // Summoned unit's rawcode
        private constant integer    WARD_ID             = 'h000'
       
        // Main ability's rawcode
        private constant integer    MAIN_ID             = 'A000'
       
        // Adjust z offset of the lightning
        // As example, if you use a floating model for the ward
        // then you can adjust the lightning's z offset here
        private constant real       Z_OFFSET            = 75.0
       
        // Lightning effect string
        private constant string     LIGHTNING_EFFECT    = "BLUE"
       
        // Allow ward to detect for new targets during lifespan
        private constant boolean    ALLOW_NEW_TARGET    = true
       
        // Simulate 3D effect for GummyLink
        private constant boolean    ENABLE_3D           = true
       
        // Add timed life bar to the ward
        private constant boolean    ADD_TIMED_LIFE      = true
        private constant integer    TIMED_LIFE          = 'BTLF'
       
        // Maximum possible target
        // Set this to target count at max ability level
        private constant integer    MAXIMUM_TARGET      = 5
       
        // Attached sfx on victims
        private constant string     TARGET_SFX          = "war3mapImported\\GummyLeash.mdx"
        private constant string     TARGET_SFX_PT       = "chest"
       
        // Add buff effect (stun) to targets
        private constant boolean    ADD_BUFF            = true
       
        // Damage configuration
        private constant attacktype ATTACK_TYPE         = ATTACK_TYPE_NORMAL
        private constant damagetype DAMAGE_TYPE         = DAMAGE_TYPE_NORMAL
        private constant weapontype WEAPON_TYPE         = WEAPON_TYPE_WHOKNOWS
       
    endglobals
   
    // Just skip these buff datas if ADD_BUFF is false
    private module BuffData
   
        // Dummy unit's rawcode
        static  constant integer    DUMMY_ID            = 'h001'
       
        // Buff ability rawcode
        static  constant integer    SPELL_ID            = 'A001'
       
        // Buff rawcode
        static  constant integer    BUFF_ID             = 'B000'
       
        // Stun order id
        static  constant integer    BUFF_ORDER          = 852127 // stomp
       
        // The higher the safer but just leave it
        static  constant real       BUFF_SAFETY         = 64.0
       
    endmodule
   
    // Maximum targets per ward
    private constant function count takes integer level returns integer
        return 2 + level
    endfunction
   
    // Ward's lifespan
    private constant function duration takes integer level returns real
        return 3.0 + 2.0 * level
    endfunction
   
    // Apply damage interval
    private constant function delay takes integer level returns real
        return 0.0
    endfunction
   
    // Dealt damage amount
    private constant function damage takes integer level returns real
        return 0.0
    endfunction
   
    // Detect AoE
    private constant function aoe takes integer level returns real
        return 600.0
    endfunction
   
    // Drag power of the link (when shrinking)
    private constant function power takes integer level returns real
        return 3.2
    endfunction
   
    // Drag power of the link (when stretching)
    private constant function elasticity takes integer level returns real
        return 3.2
    endfunction
   
    // Configure desired targets
    // By default, it's unable to targets structures and magic immune
    private function targets takes unit u, player p returns boolean
        return UnitAlive(u) and IsUnitEnemy(u, p) and not IsUnitType(u, UNIT_TYPE_MECHANICAL)
    endfunction
   
    // This function is called whenever a unit takes damage from this spell
    private function onDamage takes unit caster, unit target returns nothing
    endfunction
   
    // This function is called whenever a unit is released by this spell
    private function onRelease takes unit caster, unit target returns nothing
    endfunction
   
    // =============================================================================

    private struct LeashBuff extends array
       
        unit    target
        boolean dispose
        effect  sfx
       
        static unit  Caster
        static group Group = CreateGroup()
        static boolean  array Bool
        static thistype array Index
       
        static if ADD_BUFF then
            implement BuffData
        endif
       
        method remove takes nothing returns nothing
            set .dispose = true
        endmethod
       
        implement CTLExpire
            if .dispose or not UnitAlive(.target) then
                set Bool[GetUnitUserData(.target)] = false
                static if ADD_BUFF then
                    call UnitRemoveAbility(.target, BUFF_ID)
                endif
                call DestroyEffect(.sfx)
                call destroy()
                set .sfx = null
                set .target = null
            endif
        implement CTLEnd
       
        static method apply takes unit target returns thistype
       
            local thistype this = 0
            local integer  dex  = GetUnitUserData(target)
            local real     x
            local real     y
           
            if Bool[dex] then
                set this = Index[dex]
            else
                if not(IsUnitType(target, UNIT_TYPE_STRUCTURE)) then
                    set this = create()
                   
                    set .target = target
                    set .dispose = false
                    set .sfx = AddSpecialEffectTarget(TARGET_SFX, .target, TARGET_SFX_PT)
                    set Bool[dex]  = true
                    set Index[dex] = this
                   
                    static if ADD_BUFF then
                        set x = GetUnitX(target)
                        set y = GetUnitY(target)
                        // If unit don't have the buff yet
                        if GetUnitAbilityLevel(target, BUFF_ID) == 0 then
                            call SetUnitX(Caster, x)
                            call SetUnitY(Caster, y)
                            call IssueImmediateOrderById(Caster, BUFF_ORDER)
                            call SetUnitPosition(Caster, WorldBounds.maxX, WorldBounds.maxY)
                        endif
                        // Remove unwanted buff
                        call GroupEnumUnitsInRange(Group, x, y, BUFF_SAFETY, null)
                        loop
                            set target = FirstOfGroup(Group)
                            exitwhen target == null
                            call GroupRemoveUnit(Group, target)
                            if GetUnitAbilityLevel(target, BUFF_ID) > 0 and not Bool[GetUnitUserData(target)] then
                                call UnitRemoveAbility(target, BUFF_ID)
                            endif
                        endloop
                    endif
                debug else
                    debug call BJDebugMsg("Error occured: failed to attach buff")
                endif
            endif
           
            return this
        endmethod
       
        private static method onInit takes nothing returns nothing
            static if ADD_BUFF then
                set Caster = CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE), DUMMY_ID, WorldBounds.maxX, WorldBounds.maxY, 0)
                call UnitAddAbility(Caster, SPELL_ID)
            endif
        endmethod
       
    endstruct
   
    // Container for targets per instance
    private struct LeashTargets
        unit      array target[MAXIMUM_TARGET]
        GummyLink array link[MAXIMUM_TARGET]
        LeashBuff array buff[MAXIMUM_TARGET]
    endstruct

    private struct GummyLeash extends array
       
        real x
        real y
        real dur
       
        real aoe
        real pow
        real elstc
       
        real dly
        real dlyx
        real dmg
       
        integer ct
        integer ctx
       
        player p
        unit caster
        unit ward
       
        LeashTargets t
       
        static group    Group = CreateGroup()
        static player   TempPlayer
        static thistype TempDex
        static boolean array Bool
       
        // Target filtration, made to be compatible for GetClosestUnit
        static method filter takes nothing returns boolean
            return targets(GetFilterUnit(), TempPlayer)
        endmethod
       
        implement CTL
            local unit    u
            local integer i
            local integer dex
           
        implement CTLExpire
            if .dur > 0.03125 and UnitAlive(.ward) then
                set .dur = .dur - 0.03125
                set .dly = .dly - 0.03215
                set i = 0
                loop
                    exitwhen i >= .ct
                    if UnitAlive(.t.target[i]) then
                        if .dly <= 0 and .dmg > 0 then
                            call onDamage(.caster, .t.target[i])
                            call UnitDamageTarget(.caster, .t.target[i], .dmg, true, false, ATTACK_TYPE, DAMAGE_TYPE, WEAPON_TYPE)
                        endif
                    else
                        call onRelease(.caster, .t.target[i])
                        set Bool[GetUnitUserData(.t.target[i])] = false
                        call .t.link[i].remove()
                        // Deindex
                        set .ct = .ct - 1
                        set .t.target[i] = .t.target[.ct]
                        set .t.link[i] = .t.link[.ct]
                        set .t.buff[i] = .t.buff[.ct]
                        set .t.target[.ct] = null
                        set i = i - 1
                    endif
                    set i = i + 1
                endloop
                if .dly <= 0 then
                    set .dly = .dlyx
                endif
           
                static if ALLOW_NEW_TARGET then
                    if .ct < .ctx then
                        set TempPlayer = .p
                        call GroupEnumUnitsInRange(Group, .x, .y, .aoe, function thistype.filter)
                        loop
                            exitwhen .ct >= .ctx
                            static if LIBRARY_GetClosestWidget then
                                set u = GetClosestUnitInGroup(.x, .y, Group)
                            else
                                set u = FirstOfGroup(Group)
                            endif
                            exitwhen u == null
                            call GroupRemoveUnit(Group, u)
                           
                            set dex = GetUnitUserData(u)
                            if not Bool[dex] then
                                set .t.buff[.ct] = LeashBuff.apply(u)
                                // If successfully buffed
                                if .t.buff[.ct] != 0 then
                                    set .t.link[.ct] = GummyLink.connect(.ward, u, Z_OFFSET, .pow, .elstc, LIGHTNING_EFFECT, ENABLE_3D)
                                    // If successfully connected
                                    if .t.link[.ct] != 0 then
                                        set Bool[dex] = true
                                        set .t.target[.ct] = u
                                        set .ct = .ct + 1
                                    endif
                                endif
                            endif
                        endloop
                        set u = null
                    endif
                endif
            else
                set i = 0
                loop
                    exitwhen i >= .ct
                    call onRelease(.caster, .t.target[i])
                    set Bool[GetUnitUserData(.t.target[i])] = false
                    call .t.link[i].remove()
                    call .t.buff[i].remove()
                    set .t.target[i] = null
                    set i = i + 1
                endloop
                call KillUnit(.ward)
                call .t.destroy()
                call destroy()
                set .ward = null
                set .caster = null
            endif
           
        implement CTLEnd
       
        static method onCast takes nothing returns boolean
       
            local thistype this = create()
            local integer  level
            local integer  dex
            local unit     fog
           
            set .caster = GetTriggerUnit()
            set .p      = GetTriggerPlayer()
            set .ward   = CreateUnit(.p, WARD_ID, GetSpellTargetX(), GetSpellTargetY(), bj_UNIT_FACING)
            set .x      = GetUnitX(.ward)
            set .y      = GetUnitY(.ward)
            set .ct     = 0
           
            set level   = GetUnitAbilityLevel(.caster, MAIN_ID)
            set .aoe    = aoe(level)
            set .dur    = duration(level)
            set .elstc  = elasticity(level)
            set .pow    = power(level)
            set .ctx    = count(level)
            set .dlyx   = delay(level)
            set .dmg    = damage(level)
            set .dly    = .dlyx
           
            set .t      = LeashTargets.create()
            static if ADD_TIMED_LIFE then
                call UnitApplyTimedLife(.ward, TIMED_LIFE, .dur)
            endif
           
            set TempPlayer = .p
            call GroupEnumUnitsInRange(Group, .x, .y, .aoe, function thistype.filter)
            loop
                exitwhen .ct >= .ctx
                static if LIBRARY_GetClosestWidget then
                    set fog = GetClosestUnitInGroup(.x, .y, Group)
                else
                    set fog = FirstOfGroup(Group)
                endif
                exitwhen fog == null
                call GroupRemoveUnit(Group, fog)
               
                set dex = GetUnitUserData(fog)
                if not Bool[dex] then
                    set .t.buff[.ct] = LeashBuff.apply(fog)
                    // If successfully buffed
                    if .t.buff[.ct] != 0 then
                        set .t.link[.ct] = GummyLink.connect(.ward, fog, Z_OFFSET, .pow, .elstc, LIGHTNING_EFFECT, ENABLE_3D)
                        // If successfully connected
                        if .t.link[.ct] != 0 then
                            set Bool[dex] = true
                            set .t.target[.ct] = fog
                            set .ct = .ct + 1
                        endif
                    endif
                endif
            endloop
            set fog = null
           
            return false
        endmethod
           
        static if not LIBRARY_SpellEffectEvent then
            private static method checkId takes nothing returns boolean
                if GetSpellAbilityId() == MAIN_ID then
                    call thistype.onCast()
                endif
                return false
            endmethod
        endif
       
        static method onInit takes nothing returns nothing
            static if LIBRARY_SpellEffectEvent then
                call RegisterSpellEffectEvent(MAIN_ID, function thistype.onCast)
            else
                set gg_trg_GummyLeash = CreateTrigger()
                call TriggerRegisterAnyUnitEventBJ(gg_trg_GummyLeash, EVENT_PLAYER_UNIT_SPELL_EFFECT)
                call TriggerAddAction(gg_trg_GummyLeash, Condition(function thistype.checkId))
            endif
        endmethod
       
    endstruct
   
endscope
Credits
- IsTerrainWalkable by Anitarf and Vexorian
- CTL by Nestharus
- WorldBounds by Nestharus
- AutoFly by Nestharus
- UnitIndexer by Nestharus
- GetClosestWidget by Bannar
- SpellEffectEvent by Bribe
- UnitZ by Garfield1337
- OrbDragonX.mdx by Frankster
- BTNManaBreathe by D.ee
- LaserBlue.blp by Erkki2
Author Message
Please, report any bug/glitch/error on this thread! Thank you.

Latest update changelog (v2.5):
- Now the spell works with spell immune units
- Some variable names improvements
:O
Contents

Gummy Leash (Map)

Reviews
Moderator
14:18, 10th Mar 2015 IcemanBo: Very nice and good looking spell. http://www.hiveworkshop.com/forums/spells-569/gummy-leash-v2-2-a-257717/index2.html#post2662797
  1. GywGod133

    GywGod133

    Joined:
    Jul 16, 2012
    Messages:
    630
    Resources:
    3
    Maps:
    1
    Spells:
    1
    Tutorials:
    1
    Resources:
    3
    Cool............
     
  2. BPower

    BPower

    Joined:
    Mar 18, 2012
    Messages:
    1,709
    Resources:
    21
    Spells:
    15
    Tutorials:
    1
    JASS:
    5
    Resources:
    21
    Null instance arrays which may cause a leak.
     
  3. kakuzu

    kakuzu

    Joined:
    May 11, 2014
    Messages:
    1,233
    Resources:
    0
    Resources:
    0
    Nice animation !
     
  4. Kazeon

    Kazeon

    Joined:
    Oct 12, 2011
    Messages:
    3,296
    Resources:
    38
    Icons:
    2
    Tools:
    1
    Maps:
    7
    Spells:
    21
    Tutorials:
    3
    JASS:
    4
    Resources:
    38
    Ops, fixed. Thanks :)

    And there are some adjustment on gravity factor.
     
  5. BPower

    BPower

    Joined:
    Mar 18, 2012
    Messages:
    1,709
    Resources:
    21
    Spells:
    15
    Tutorials:
    1
    JASS:
    5
    Resources:
    21
    Delete "local unit f" in static method onCast.

    You may have a local unit leak here, if more than the maximum valid amount (.ctx) of units are enumerated.

    Like I already mentioned above, null instance arrays like ward, s (in LeashBuff), ... once you don't need them anymore.

    Is it really required to check if the buff has been applied to a wrong unit?

    What does NORMAL_Z do, what should I expect when increasing/decreasing this value?
    Make the description more userfriendly

    Function names could follow the JPAG standard --> function MyFunction takes ...
     
  6. Kazeon

    Kazeon

    Joined:
    Oct 12, 2011
    Messages:
    3,296
    Resources:
    38
    Icons:
    2
    Tools:
    1
    Maps:
    7
    Spells:
    21
    Tutorials:
    3
    JASS:
    4
    Resources:
    38
    Ok
    Ok
    I've asked about this to you multiple times yet you haven't answered. Since I don't understand how default struct destroy() method works, I'm affraid I will misnulled things. So the question is: am I need to null after/before I call destroy() method?
    Yes
    It allows user to adjust lightning's normal z, so it doesnt looks like hitting units' feet.
    I think camelCase is better for private.

    Thanks..
     
    Last edited: Sep 29, 2014
  7. BPower

    BPower

    Joined:
    Mar 18, 2012
    Messages:
    1,709
    Resources:
    21
    Spells:
    15
    Tutorials:
    1
    JASS:
    5
    Resources:
    21
    Doesn't make any difference. You can do it before or afterwards. Destroy is a simple recycling process, it does not influence the current struct instance you are dealing with.

    In your case destroy looks like the following: ns is next stack, t is the current instance.
    Code (vJASS):
                set ns[t]=ns[0]
                set ns[0]=t
     
  8. gorillabull

    gorillabull

    Joined:
    Jul 17, 2011
    Messages:
    1,368
    Resources:
    2
    Spells:
    2
    Resources:
    2
    i really like this effect i dunno why 5/5
     
  9. Dat-C3

    Dat-C3

    Joined:
    Mar 15, 2012
    Messages:
    2,555
    Resources:
    10
    Models:
    1
    Maps:
    5
    Spells:
    3
    Tutorials:
    1
    Resources:
    10
    Good job on a 5/5 resource. Hope to see more in wc3 from you.
     
  10. DelmarVladek

    DelmarVladek

    Joined:
    Jul 28, 2012
    Messages:
    36
    Resources:
    0
    Resources:
    0
    Bungee Gum. XD
    This is cool XD I wanna use this alot XD
     
  11. qt_upheaval

    qt_upheaval

    Joined:
    Apr 16, 2013
    Messages:
    11
    Resources:
    1
    Maps:
    1
    Resources:
    1
    his is even more than 5\5. very big.
     
    Last edited: Oct 8, 2014
  12. Zed

    Zed

    Joined:
    Feb 22, 2014
    Messages:
    238
    Resources:
    0
    Resources:
    0
    I don't see any gum here.
    4/5
     
  13. Zed

    Zed

    Joined:
    Feb 22, 2014
    Messages:
    238
    Resources:
    0
    Resources:
    0
    It looks really good.
     
  14. Trigger.edge

    Trigger.edge

    Joined:
    Jun 21, 2012
    Messages:
    419
    Resources:
    0
    Resources:
    0
    Downloading....
     
  15. IcemanBo

    IcemanBo

    Joined:
    Sep 6, 2013
    Messages:
    6,537
    Resources:
    23
    Maps:
    3
    Spells:
    11
    Template:
    1
    Tutorials:
    5
    JASS:
    3
    Resources:
    23
    Thread opened.
     
  16. IcemanBo

    IcemanBo

    Joined:
    Sep 6, 2013
    Messages:
    6,537
    Resources:
    23
    Maps:
    3
    Spells:
    11
    Template:
    1
    Tutorials:
    5
    JASS:
    3
    Resources:
    23
    Spell works very nice and it's visuals also look very smooth. The code is well structured and written efficient.

    if r * 2 <= TAU then

    ->
    if r <= bj_PI

    :D

    I don't want be nitpicky but some names could be better.
    For example
    boolean array Bool
    is just not descriptive at all.

    Personaly I would prefer having as less imports as possible. You could still recommend the imports in your spell description.

    Additionaly you could think of adding a damage feature, like over time, or also if spell finished.
    It would not take too much of changes I think.

    Else I like the concept much. Great spell!

    Approved.
     
  17. jonbon29

    jonbon29

    Joined:
    Aug 19, 2014
    Messages:
    1,098
    Resources:
    0
    Resources:
    0
    Wow this spell is nice and I like, I'll use this on my map.
     
  18. Daffa

    Daffa

    Joined:
    Jan 30, 2013
    Messages:
    8,201
    Resources:
    31
    Packs:
    1
    Maps:
    9
    Spells:
    18
    Tutorials:
    3
    Resources:
    31
    Great spell, and extremely good visuals.
    If I may recommend, use in-game models for less imports :)

    One of few I could say extremely well done, it deserves 5/5 ^^

    I'll get a view on the code later, but still, this is very rare and well done, Quilnez ^^

    EDIT :
    I don't think Unit Indexer has to be Nes'
    Bribe's can do the job well (judging by GummyLink's code)

    EDIT 2 :
    I just noticed that the image doesn't use your special cover in it, why? It looks cool with the cover (personal taste)

    Code :
    Pretty much great, can't spot errors there, except some variables aren't descriptive, that's all ^^
     
    Last edited: May 17, 2015