Spell Path of Shadows

Kenny

Back for now.
Reaction score
202
Bumpskies. I know the moderators are pretty busy lately, but I'm just looking for some feedback from anyone who cares to read the script and test the spell.

I'm also thinking of updating the spell to include "shadows", however I havent got warcraft on me for a while, so I have no idea how it will look. I have made the script, and everything looks okay, I just cant test it.

Heres the latest on the spell:

JASS:
//------------------------------------------------------------------------------------\\
//                             Path of Shadows [v11]                                  \\
//                                   By kenny!                                        \\
//                            Constructed using vJASS                                 \\
//                         Requires NewGen WE & GTrigger                              \\
//------------------------------------------------------------------------------------\\

scope PathofShadows initializer Init

    globals
    // Configurables:

    // Integers and Reals:
        private constant integer LEARN_ID           = 'A000'
        private constant integer READY_ID           = 'A001'
        private constant integer COOLDOWN_ID        = 'A002'
        private constant integer ANIM_INDEX         = 7
        private constant integer RED                = 255
        private constant integer GREEN              = 255
        private constant integer BLUE               = 255
        private constant integer ALPHA              = 128
        private constant real    INTERVAL           = 0.04 // Or 0.02
        private constant real    DISTANCE           = 50.00
        private constant real    COLLISION          = 100.00

    // Special Effects:
        private constant boolean PLAY_DASH_SFX      = false
        private constant string  DASH_SFX           = "Abilities\\Spells\\Undead\\CarrionSwarm\\CarrionSwarmDamage.mdl"
        
        private constant boolean PLAY_CONSTANT_SFX  = false
        private constant string  CONSTANT_SFX       = "Abilities\\Weapons\\AvengerMissile\\AvengerMissile.mdl"
        private constant string  CONSTANT_POINT     = "chest"

        private constant boolean PLAY_COOLDOWN_SFX  = true
        private constant string  COOLDOWN_SFX       = "Abilities\\Spells\\Undead\\CarrionSwarm\\CarrionSwarmDamage.mdl"
        private constant string  COOLDOWN_POINT     = "overhead"

        private constant boolean PLAY_DAMAGE_SFX    = true
        private constant string  DAMAGE_SFX         = "Abilities\\Spells\\Undead\\DeathandDecay\\DeathandDecayTarget.mdl"
        private constant string  DAMAGE_POINT       = "head"
        
    // Error Messsage:
        private constant string  ERROR_MSG          = "Your hero does not have enough mana to walk the path of shadows."
        
    // Booleans:
        private constant boolean ALLOW_PRELOAD      = true
        private constant boolean ALLOW_PATHING      = true
        private constant boolean ALLOW_MANA_COST    = false   
        private constant boolean ALLOW_DAMAGE       = true    
        private constant boolean ALLOW_ERROR_MSG    = true
        
        private constant boolean ALLOW_ORDER_MOVE   = true
        private constant boolean ALLOW_ORDER_SMART  = true
        private constant boolean ALLOW_ORDER_ATTACK = true
        
    // Attack/Damage/Weapon types of damage dealt:
        private constant attacktype A_TYPE          = ATTACK_TYPE_CHAOS
        private constant damagetype D_TYPE          = DAMAGE_TYPE_UNIVERSAL
        private constant weapontype W_TYPE          = WEAPON_TYPE_WHOKNOWS
    endglobals
    
    //---------------------------------------------------------------------\\
    globals
        private constant real    REQUIRED_DIST      = 20.00
        private constant real    OFFSET             = 15.00
        private constant integer ALPHA_START        = 250
        private constant integer ALPHA_MINUS        = 50
        private constant integer LOCUST_ID          = 'Aloc'
        private constant integer CROW_ID            = 'Amrf'
    endglobals

    //---------------------------------------------------------------------\\
    private function Max_dist takes integer lvl returns real
        return 400.00 + (100.00 * lvl)
    endfunction

    private function Min_dist takes integer lvl returns real
        return 200.00 + (50.00 * lvl)
    endfunction                  

    private function Movement_speed takes integer lvl returns real
        return 1000.00 + (250.00 * lvl)
    endfunction                  

    private function Time_scale takes integer lvl returns real
        return 1.00 + (1.00 * lvl)
    endfunction

    private function Cool_down takes integer lvl returns real
        return 2.00 + (0.00 * lvl)
    endfunction

    private function Damage_dealt takes integer lvl returns real
        return 25.00 * lvl
    endfunction

    private function Mana_cost takes integer lvl returns integer
        return 20 + (20 * lvl)
    endfunction

    private function Enemy_filt takes nothing returns boolean
        return GetWidgetLife(GetFilterUnit()) > 0.405 and IsUnitType(GetFilterUnit(),UNIT_TYPE_STRUCTURE) == false and GetUnitFlyHeight(GetFilterUnit()) < 40.00
    endfunction

    //---------------------------------------------------------------------\\
    //                                                                     \\
    //  DO NOT TOUCH PAST THIS POINT UNLESS YOU KNOW WHAT YOUR ARE DOING!  \\
    //                                                                     \\
    //---------------------------------------------------------------------\\

    globals
    // Needed non-constant globals:
        private item     array H1                // Needed for hidding necessary items.
        private integer  H1_total       = 0      // Needed for counting hidden items.
        private real     Game_maxX      = 0.00   // Used to set up map bounds.
        private real     Game_minX      = 0.00   // Used to set up map bounds.
        private real     Game_maxY      = 0.00   // Used to set up map bounds.
        private real     Game_minY      = 0.00   // Used to set up map bounds.
        private item     Path_item      = null   // Item needed for pathing detection.
        private rect     Path_rect      = null   // Rect needed for pathing detection.
        private sound    Error_sound    = null   // Error sound used for error message.
        
    // Needed Constant Globals:
        private constant real    MAX_RANGE    = 10.00  // Needed for checking pathing.
        private constant integer ORDER_STOP   = 851972 // Order ID of the command "stop".
        private constant integer ORDER_MOVE   = 851986 // Order ID of the command "move".
        private constant integer ORDER_SMART  = 851971 // Order ID of the command "Smart".
        private constant integer ORDER_ATTACK = 851983 // Order ID of the command "attack".
    endglobals

    //---------------------------------------------------------------------\\
    private function Safe_x takes real x returns real
        if x < Game_minX then
            return Game_minX
        elseif x > Game_maxX then    // Sets a safe x position.
            return Game_maxX
        endif
        return x
    endfunction

    private function Safe_y takes real y returns real
        if y < Game_minY then
            return Game_minY
        elseif y > Game_maxY then    // Sets a safe x position.
            return Game_maxY
        endif
        return y
    endfunction

    //---------------------------------------------------------------------\\
    private function Filter_items takes nothing returns nothing
        if IsItemVisible(GetEnumItem()) then
            set H1[H1_total] = GetEnumItem()
            call SetItemVisible(H1[H1_total],false) // Hides unwanted items.
            set H1_total = H1_total + 1
        endif
    endfunction

    // Thanks to Vexorian for original concept, and Anitarf for the up-to-date version. (Slightly midified).
    private function Check_pathability takes real x1, real y1 returns boolean
        local real x2 = 0.00
        local real y2 = 0.00
        
        call MoveRectTo(Path_rect,x1,y1)
        call EnumItemsInRect(Path_rect,null,function Filter_items)

        call SetItemPosition(Path_item,x1,y1)
        set x2 = GetItemX(Path_item)
        set y2 = GetItemY(Path_item)
        call SetItemVisible(Path_item,false)

        loop
            exitwhen H1_total <= 0
            set H1_total = H1_total - 1
            call SetItemVisible(H1[H1_total],true)
            set H1[H1_total] = null
        endloop

        return (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2) < MAX_RANGE * MAX_RANGE
    endfunction

    //---------------------------------------------------------------------\\
    private function Sim_error takes player whichplayer, string message returns nothing
        set message = "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n|cffffcc00" + message + "|r"
        if (GetLocalPlayer() == whichplayer) then
            call ClearTextMessages()
            call DisplayTimedTextToPlayer(whichplayer,0.5125,0.97120,2.00,message)
            call StartSound(Error_sound) // Replicates a sim error.
        endif
    endfunction

    //---------------------------------------------------------------------\\
    private function Is_dashing takes unit whichunit returns boolean
        local integer i = 1
        
        private keyword Data1
        
        loop
            exitwhen i > Data1.Total
            if Data1.D1<i>.cast == whichunit then
                return true
            endif
            set i = i + 1
        endloop
        
        return false
    endfunction
    
    //---------------------------------------------------------------------\\
    private struct Shadow2
    
        unit    shadow = null
        integer alpha  = 0
        integer anim   = 0
        integer id     = 0
        
        static Shadow2 array S2
        static timer   Timer = null
        static integer Total = 0
        
        static method create takes unit caster, integer id, integer animation, real angle, real timescale, real x, real y returns Shadow2
            local Shadow2 s2 = Shadow2.allocate()
            
            set s2.id = id
            set s2.anim = animation
            set s2.alpha = ALPHA_START
            set s2.shadow = CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE),s2.id,x,y,GetUnitFacing(caster))
            
            call SetUnitColor(s2.shadow,GetPlayerColor(GetOwningPlayer(caster)))
            call SetUnitVertexColor(s2.shadow,255,255,255,s2.alpha)
            call SetUnitAnimationByIndex(s2.shadow,s2.anim)
            call SetUnitTimeScale(s2.shadow,timescale)
            call UnitAddAbility(s2.shadow,LOCUST_ID)
            call SetUnitPathing(s2.shadow,false)
            
            call SetUnitX(s2.shadow,x + OFFSET * Cos(angle))
            call SetUnitY(s2.shadow,y + OFFSET * Sin(angle))
            
            if GetUnitFlyHeight(caster) &gt; 1.00 then
                call UnitAddAbility(s2.shadow,CROW_ID)
                call UnitRemoveAbility(s2.shadow,CROW_ID)
                call SetUnitFlyHeight(s2.shadow,GetUnitFlyHeight(caster),0.00)
            endif
            
            set Shadow2.Total = Shadow2.Total + 1
            set Shadow2.S2[Shadow2.Total] = s2
            if Shadow2.Total == 1 then
                call TimerStart(Shadow2.Timer,INTERVAL,true,function Shadow2.update)
            endif
            
            return s2
        endmethod
        
        static method update takes nothing returns nothing
            local Shadow2 s2 = 0
            local integer i  = 1
            
            loop
                exitwhen i &gt; Shadow2.Total
                
                set s2 = Shadow2.S2<i>
                
                if s2.alpha &lt;= 0 then
                    call s2.destroy()
                    set Shadow2.S2<i> = Shadow2.S2[Shadow2.Total]
                    set Shadow2.Total = Shadow2.Total - 1
                    set i = i - 1
                else        
                    call SetUnitVertexColor(s2.shadow,255,255,255,s2.alpha)
                    call SetUnitAnimationByIndex(s2.shadow,s2.anim)
                    
                    set s2.alpha = s2.alpha - ALPHA_MINUS
                endif
                
                set i = i + 1
            endloop
            
            if Shadow2.Total &lt;= 0 then
                call PauseTimer(Shadow2.Timer)
                set Shadow2.Total = 0
            endif
        endmethod
        
        method onDestroy takes nothing returns nothing
            call RemoveUnit(.shadow)
            set .shadow = null
        endmethod
        
        static method onInit takes nothing returns nothing
            set Shadow2.Timer = CreateTimer()
        endmethod
        
    endstruct

    //---------------------------------------------------------------------\\
    private struct Shadow1

        unit    cast  = null
        real    scale = 0.00
        real    x     = 0.00
        real    y     = 0.00
        integer id    = 0
        integer anim  = 0
        
        boolean stop  = false
        
        static Shadow1 array S1
        static timer   Timer = null
        static integer Total = 0
        
        static method create takes unit caster, integer unitid, integer animation, real timescale returns Shadow1
            local Shadow1 s1 = Shadow1.allocate()
            
            set s1.cast  = caster
            set s1.id    = unitid
            set s1.anim  = animation
            set s1.scale = timescale
            set s1.x     = GetUnitX(s1.cast)
            set s1.y     = GetUnitY(s1.cast)
            
            set Shadow1.Total = Shadow1.Total + 1
            set Shadow1.S1[Shadow1.Total] = s1
            if Shadow1.Total == 1 then
                call TimerStart(Shadow1.Timer,INTERVAL,true,function Shadow1.update)
            endif
            
            return s1
        endmethod
        
        private static method update takes nothing returns nothing
            local Shadow1 s1 = 0
            local integer i  = 1
            local real    x  = 0.00
            local real    y  = 0.00
            local real    d  = 0.00
            
            loop
                exitwhen i &gt; Shadow1.Total
                
                set s1 = Shadow1.S1<i>
                
                if s1.stop then
                    call s1.destroy()
                    set Shadow1.S1<i> = Shadow1.S1[Shadow1.Total]
                    set Shadow1.Total = Shadow1.Total - 1
                    set i = i - 1
                else
                    set x  = GetUnitX(s1.cast)
                    set y  = GetUnitY(s1.cast)

                    set d  = ((x - s1.x) * (x - s1.x) + (y - s1.y) * (y - s1.y))

                    if d &gt;= REQUIRED_DIST * REQUIRED_DIST then
                        call Shadow2.create(s1.cast,s1.id,s1.anim,Atan2((s1.y - y),(s1.x - x)),s1.scale,x,y)
                    endif
                
                    set s1.x = x
                    set s1.y = y
                endif
                    
                set i = i + 1
            endloop
            
            if Shadow1.Total &lt;= 0 then
                call PauseTimer(Shadow1.Timer)
                set Shadow1.Total = 0
            endif
        endmethod
        
        private method onDestroy takes nothing returns nothing
            set .cast  = null
        endmethod
        
        private static method onInit takes nothing returns nothing
            set Shadow1.Timer = CreateTimer()
        endmethod
        
    endstruct

    //---------------------------------------------------------------------\\
    private struct Data1

        unit    cast   = null
        effect  sfx    = null
        widget  t      = null
        group   g      = null
        real    tx     = 0.00
        real    ty     = 0.00
        real    move   = 0.00
        real    cos    = 0.00
        real    sin    = 0.00
        integer ticks  = 0
        integer lvl    = 0
        integer id     = 0
        Shadow1 s1     = 0
        
        static Data1    array D1
        static integer  Total = 0
        static timer    Timer = null
        static group    Group = null
        static boolexpr Filt  = null
        
        static method create takes real dist, real targx, real targy, widget targ, integer order returns Data1
            local Data1 d1    = Data1.allocate()
            local real  angle = 0.00
            local real  castx = 0.00
            local real  casty = 0.00
            
            set d1.cast = GetTriggerUnit()
            set castx   = GetUnitX(d1.cast)
            set casty   = GetUnitY(d1.cast)
            set d1.tx   = targx
            set d1.ty   = targy
            set d1.lvl  = GetUnitAbilityLevel(d1.cast,COOLDOWN_ID)
            set d1.move = Movement_speed(d1.lvl) * INTERVAL
            set angle   = Atan2((d1.ty - casty),(d1.tx - castx))
            set d1.cos  = Cos(angle)
            set d1.sin  = Sin(angle)
            set d1.t    = targ
            set d1.id   = order
            
            set d1.s1 = Shadow1.create(d1.cast,GetUnitTypeId(d1.cast),ANIM_INDEX,Time_scale(d1.lvl))
            
            if dist &gt; Max_dist(d1.lvl) then
                set dist = Max_dist(d1.lvl) // Sets max distance.
            endif
            
            set d1.ticks = R2I(dist / d1.move)
        
            // Sets up unit.
            call SetUnitPathing(d1.cast,false)
            call SetUnitFacing(d1.cast,angle * bj_RADTODEG)
            call SetUnitTimeScale(d1.cast,Time_scale(d1.lvl))
            call SetUnitVertexColor(d1.cast,RED,GREEN,BLUE,ALPHA)
            
            if ALLOW_DAMAGE then // If we want to damage units, create group.
                set d1.g = CreateGroup()
            endif
            
            if PLAY_DASH_SFX then
                call DestroyEffect(AddSpecialEffect(DASH_SFX,castx,casty)) // Plays DASH_SFX if wanted.
            endif
            
            if PLAY_CONSTANT_SFX then
                set d1.sfx = AddSpecialEffectTarget(CONSTANT_SFX,d1.cast,CONSTANT_POINT) // Plays CONSTANT_SFX if wanted.
            endif
            
            set Data1.Total = Data1.Total + 1
            set Data1.D1[Data1.Total] = d1
            if Data1.Total == 1 then // Starts timer if its not running.
                call TimerStart(Data1.Timer,INTERVAL,true,function Data1.update)
            endif

            return d1
        endmethod
        
        static method update takes nothing returns nothing
            local Data1   d1 = 0
            local integer i  = 1
            local integer j  = 0
            local real    x  = 0.00
            local real    y  = 0.00
            local unit    u  = null
             
            loop
                exitwhen i &gt; Data1.Total
                
                set d1 = Data1.D1<i>
                
                set x = GetUnitX(d1.cast)
                set y = GetUnitY(d1.cast)
                
                if ALLOW_PATHING then // Checks for pathing, if desired.
                    if Check_pathability(x + DISTANCE * d1.cos,y + DISTANCE * d1.sin) == false then
                        set j = 1
                    endif
                endif
            
                if d1.ticks &lt;= 0 or j == 1 or GetWidgetLife(d1.cast) &lt; 0.406 then  // Stops when the max dist has been reached, or if the location isnt pathable.
                    call d1.destroy()
                    set Data1.D1<i> = Data1.D1[Data1.Total]
                    set Data1.Total = Data1.Total - 1
                    set i = i - 1
                    set j = 0
                else
                    set x = Safe_x(x + d1.move * d1.cos)
                    set y = Safe_y(y + d1.move * d1.sin)
                    
                    call SetUnitX(d1.cast,x)
                    call SetUnitY(d1.cast,y) // Sets new position.
                    call SetUnitAnimationByIndex(d1.cast,ANIM_INDEX)
                    call IssueImmediateOrderById(d1.cast,ORDER_STOP)
                    
                    // Damages unit who are hit by the caster.
                    if ALLOW_DAMAGE then
                        call GroupEnumUnitsInRange(Data1.Group,x,y,COLLISION,Data1.Filt)
                        loop
                            set u = FirstOfGroup(Data1.Group)
                            exitwhen u == null
                            call GroupRemoveUnit(Data1.Group,u)
                            if not(IsUnitInGroup(u,d1.g)) and IsUnitEnemy(u,GetOwningPlayer(d1.cast)) == true then
                                call GroupAddUnit(d1.g,u)
                                call UnitDamageTarget(d1.cast,u,Damage_dealt(d1.lvl),false,false,A_TYPE,D_TYPE,W_TYPE)
                                if PLAY_DAMAGE_SFX then
                                    call DestroyEffect(AddSpecialEffectTarget(DAMAGE_SFX,u,DAMAGE_POINT))
                                endif
                            endif
                        endloop
                    endif
                    
                    set d1.ticks = d1.ticks - 1
                endif
                
                set i = i + 1
            endloop
            
            if Data1.Total &lt;= 0 then
                call PauseTimer(Data1.Timer)
                set Data1.Total = 0
            endif
            
            set u = null
        endmethod
        
        method onDestroy takes nothing returns nothing
            if .sfx != null then
                call DestroyEffect(.sfx)
            endif
            
            // Resets the casting unit.
            set .s1.stop = true
            call SetUnitPathing(.cast,true)
            call SetUnitTimeScale(.cast,1.00)
            call SetUnitAnimation(.cast,&quot;stand&quot;)
            call SetUnitVertexColor(.cast,255,255,255,255)
            
            if .t != null then
                call IssueTargetOrderById(.cast,.id,.t)
            else
                call IssuePointOrderById(.cast,.id,.tx,.ty)
            endif
            
            if PLAY_DASH_SFX then
                call DestroyEffect(AddSpecialEffect(DASH_SFX,GetUnitX(.cast),GetUnitY(.cast))) // Plays DASH_SFX if wanted.
            endif
            
            if ALLOW_DAMAGE then // If the group has been created, destroy it.
                call GroupClear(.g)
                call DestroyGroup(.g)
            endif
            
            set .g    = null   
            set .t    = null
            set .sfx  = null
            set .cast = null
        endmethod
        
        static method onInit takes nothing returns nothing
            set Data1.Timer = CreateTimer()
            set Data1.Group = CreateGroup()
            set Data1.Filt  = Filter(function Enemy_filt)
        endmethod
        
    endstruct

    //---------------------------------------------------------------------\\
    private struct Data2

        unit cast   = null
        real time   = 0.00
        
        static Data2   array D2
        static integer Total = 0
        static timer   Timer = null
        
        static method create takes nothing returns Data2
            local Data2   d2  = Data2.allocate()
            local integer lvl = 0
            
            set d2.cast = GetTriggerUnit()
            set lvl     = GetUnitAbilityLevel(d2.cast,READY_ID)
            set d2.time = Cool_down(lvl)
            
            call UnitRemoveAbility(d2.cast,READY_ID)
            call UnitAddAbility(d2.cast,COOLDOWN_ID) // Changes the dummy ability to the second one.
            call SetUnitAbilityLevel(d2.cast,COOLDOWN_ID,lvl)
            
            set Data2.Total = Data2.Total + 1
            set Data2.D2[Data2.Total] = d2
            if Data2.Total == 1 then
                call TimerStart(Data2.Timer,INTERVAL,true,function Data2.update)
            endif
            
            return d2
        endmethod

        static method update takes nothing returns nothing
            local Data2   d2 = 0
            local integer i  = 1
            
            loop
                exitwhen i &gt; Data2.Total
                
                set d2 = Data2.D2<i>
                
                if d2.time &lt;= 0.00 or GetWidgetLife(d2.cast) &lt; 0.406 then // stop when the cooldown has been reached or the hero died.
                    call d2.destroy()
                    set Data2.D2<i> = Data2.D2[Data2.Total]
                    set Data2.Total = Data2.Total - 1
                    set i = i - 1
                else
                    set d2.time = d2.time - INTERVAL // Loop through the structs and add time on.
                endif
                
                set i = i + 1
            endloop
            
            if Data2.Total &lt;= 0 then
                call PauseTimer(Data2.Timer)
                set Data2.Total = 0
            endif
        endmethod
        
        method onDestroy takes nothing returns nothing
            local string  sfx = &quot;&quot;
            local integer lvl = GetUnitAbilityLevel(.cast,COOLDOWN_ID)
        
            call UnitRemoveAbility(.cast,COOLDOWN_ID)
            call UnitAddAbility(.cast,READY_ID)
            call SetUnitAbilityLevel(.cast,READY_ID,lvl) // Resets the ability.
                
            if PLAY_COOLDOWN_SFX then // Plays the special effect to the local player if wanted.
                set sfx = COOLDOWN_SFX
                
                if GetLocalPlayer() != GetOwningPlayer(.cast) then
                    set sfx = &quot;&quot;
                endif
                
                call DestroyEffect(AddSpecialEffectTarget(sfx,.cast,COOLDOWN_POINT))
            endif
            
            set .cast = null
        endmethod
        
        static method onInit takes nothing returns nothing
            set Data2.Timer = CreateTimer()
        endmethod
        
    endstruct

    //---------------------------------------------------------------------\\
    private function Move_actions takes nothing returns boolean
        local unit     cast  = GetTriggerUnit()
        local widget   targ  = GetOrderTarget()
        local real     castx = GetUnitX(cast)
        local real     casty = GetUnitY(cast)        
        local real     targx = 0.00
        local real     targy = 0.00
        local real     dist  = 0.00
        local integer  lvl   = GetUnitAbilityLevel(cast,READY_ID)
        local integer  id    = GetIssuedOrderId()
                
        if lvl &gt; 0 and Is_dashing(cast) == false then
            if targ != null then
                set targx = GetWidgetX(targ)
                set targy = GetWidgetY(targ)
            else
                set targx = GetOrderPointX()
                set targy = GetOrderPointY()
            endif
            
            set dist = SquareRoot((targx - castx) * (targx - castx) + (targy - casty) * (targy - casty))
            
            if dist &gt; Min_dist(lvl) then  // Checks for minimum distance, if there is any.
                if ALLOW_MANA_COST then   // Checks for mana cost, if there is any.
                    if GetUnitState(cast,UNIT_STATE_MANA) &gt;= Mana_cost(lvl) then
                        call SetUnitState(cast,UNIT_STATE_MANA,GetUnitState(cast,UNIT_STATE_MANA) - Mana_cost(lvl)) // If there is enoguh mana, use the skill.
                        call Data2.create()
                        call Data1.create(dist,targx,targy,targ,id) // Start path of shadows if the unit has enough mana.
                    else
                        if ALLOW_ERROR_MSG then
                            call Sim_error(GetOwningPlayer(cast),ERROR_MSG) // Otherwise, don&#039;t. And show an error message.
                        endif
                    endif
                else
                    call Data2.create() // If there is no mana cost, just run the skill.
                    call Data1.create(dist,targx,targy,targ,id)
                endif
            endif
        endif
        
        set cast = null
        set targ = null
        
        return false // Used condition so that it compiles with GTrigger.
    endfunction

    //---------------------------------------------------------------------\\
    private function Learn_conditions takes nothing returns boolean
        local unit cast = GetLearningUnit()
        
        if GetUnitAbilityLevel(cast,LEARN_ID) == 1 then
            call UnitAddAbility(cast,READY_ID) // If its the first level of the ability, then add the dummy one.
        else
            if GetUnitAbilityLevel(cast,READY_ID) &gt; 0 then
                call IncUnitAbilityLevel(cast,READY_ID) // Else, just level the dummy one.
            elseif GetUnitAbilityLevel(cast,COOLDOWN_ID) &gt; 0 then
                call IncUnitAbilityLevel(cast,COOLDOWN_ID)
            endif
        endif
        
        set cast = null
        
        return false // Used condition, as it is safer than action.
    endfunction

    //---------------------------------------------------------------------\\
    private function Init takes nothing returns nothing
        local trigger trig = CreateTrigger()
        
        // Setting up map bounds:
        set Game_maxX = GetRectMaxX(bj_mapInitialPlayableArea) - 64.00
        set Game_minX = GetRectMinX(bj_mapInitialPlayableArea) + 64.00
        set Game_maxY = GetRectMaxY(bj_mapInitialPlayableArea) - 64.00
        set Game_minY = GetRectMinY(bj_mapInitialPlayableArea) + 64.00
        
        // Registering target and point order events:
        if ALLOW_ORDER_MOVE then
            call GT_RegisterPointOrderEvent(trig,ORDER_MOVE)
            call GT_RegisterTargetOrderEvent(trig,ORDER_MOVE)
        endif
        if ALLOW_ORDER_SMART then
            call GT_RegisterPointOrderEvent(trig,ORDER_SMART)
            call GT_RegisterTargetOrderEvent(trig,ORDER_SMART)
        endif
        if ALLOW_ORDER_ATTACK then
            call GT_RegisterPointOrderEvent(trig,ORDER_ATTACK)
            call GT_RegisterTargetOrderEvent(trig,ORDER_ATTACK)
        endif
        
        // Adding action to above events:
        call TriggerAddCondition(trig,Condition(function Move_actions))
        
        // Registering learn ability event:
        call GT_AddLearnsAbilityAction(function Learn_conditions,LEARN_ID)
        
        // Preloads effects, if desired:
        if ALLOW_PRELOAD then
            call DestroyEffect(AddSpecialEffect(DASH_SFX,0.00,0.00))
            call DestroyEffect(AddSpecialEffect(CONSTANT_SFX,0.00,0.00))
            call DestroyEffect(AddSpecialEffect(COOLDOWN_SFX,0.00,0.00))
            call DestroyEffect(AddSpecialEffect(DAMAGE_SFX,0.00,0.00))
        endif
        
        // Sets up rect and item to check for pathing. As well as Sound variable:
        set Error_sound  = CreateSoundFromLabel(&quot;InterfaceError&quot;,false,false,false,10,10)
        set Path_rect = Rect(0.00,0.00,128.00,128.00)
        set Path_item = CreateItem(&#039;ciri&#039;,0.00,0.00)
        call SetItemVisible(Path_item,false) 
    endfunction

endscope

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


If you copy and paste that into the map, it should work just fine I think, so test it out if you have time, and tell me what you think.
 

Kenny

Back for now.
Reaction score
202
Version 11 released. Check first post for latest changelog. Nothing major, just some eye-canding touch ups with a few minor optimisations and changes.
 

Kenny

Back for now.
Reaction score
202
As said... Make it allow the unit to go around stuff by using the unit's facing as the direction to propel. Max out the turn speed for the duration of the spell, heh.

I tried it, and it didn't really work at all. Even setting units turn speed to max didn't work. It was very inaccurate and looked pretty bad. Although the path finding worked (kinda).

Oh, and maybe make the image units a bit transparent? They kinda look just a little ugly.

There are configurables there for people to change. I would suggest maybe halving what the values currently are and giving it a try (250 - 125 and 50 - 25).
 

BRUTAL

I'm working
Reaction score
118
has one mod even left a comment yet? :p
i remember seeing this spell the day it was submitted, damn its old lol
i dont have much to say about the code; i dont like reading code anyways
but i remember what the spell is like :thup:
 

Kenny

Back for now.
Reaction score
202
Bump. Seems like things are getting approved. Maybe this old thread can finally get a mods comment or even an approval. :p
 

Viikuna

No Marlo no game.
Reaction score
265
Its a cool spell. Rising Dusk has similiar in his DoE map, but without damage dealing stuff.

You should probably switch this passive ability to active one, which cools down, during the cooldown phase. Since this deals damage and all, it would be nice to know how soon you can dash again. In DoE that spell has cooldown thingy like that, and its pretty cool.

That handle counter in test map uses return bug btw, so it must be disabled in order to be able to test the spell.

Anyways, its a neat spell.
 

Kenny

Back for now.
Reaction score
202
o_O

Holy shit! Haha, I can't believe this finally got noticed, let alone approved. Thank you Jesus4Lyf.

@ Viikuna:

I got the idea from DoE, but Dusk doesn't like to give away how he does things, so I made this (I think I've said that somewhere in this thread before).

And I have thought about changing the passive ability to an active one many times, but I came to the conclusion that it just isn't worth it. Using an active ability ruins the 'polish' of the spell. Once in cooldown, you can click on the ability and it will go "Ability is still in cooldown" or whatever. In my opinion that looks crap.

This also has two visual representations for the cooldown:

1) In the tooltip, there is a part that shows the status of the spell. Either in cooldown or ready.
2) A special effect is played for the owner to show the spell is ready again.

I personally think that is enough, and still leaves the spell looking 'polished'.

It also depends on what version of wc3 you are using as to whether the handle counter should be disabled. I am on 1.22 and I cannot update to the newest patch.

But I may update this soon, and get rid of the counter and change a few things.

Thank you for your comments, and thanks for the approval.
 

Sim

Forum Administrator
Staff member
Reaction score
534
Thanks!

Naturally, if the author is to fix these spells, they will most probably be approved once again!
 
General chit-chat
Help Users
  • No one is chatting at the moment.

      The Helper Discord

      Members online

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top