Shadow Images Sword v1.1

This bundle is marked as useful / simple. Simplicity is bliss, low effort and/or may contain minor bugs.
  • Like
Reactions: IcemanBo
Spell Look Like
Screen shot
143.jpg

220.jpg
Spell code
JASS:
//***************************************************************************
//***************************************************************************
//***************************************************************************
//      S H A D O W S    I M A G E S     S W O R D
//                      -----------------------------------------
//                                          By: Nyuu
//      Version: 1.1
//
//      Sepll Description: 
//  `                       - Use energy and power of the ground, Blade Master jump up from the ground to the target point, 
//                          but because the power of the blade is too powerful, his sword cause the image of him has been splitted into two, 
//                          this creates two illusions of him and has the same power plunges straight down to the ground, 
//                          when the illusions hit the ground, it causing 100/150/200/250 damages to enemies simultaneously 
//                          stunning them for 2/2.25/2.50/2.75 seconds around 250 range of the illusions, and then, 
//                          the sword will pull them back, after mirage disappears, it creates a shock ground, 
//                          making him invisible for 1.5 seconds.

//     Credits:
//              BoundSentinel - http://www.wc3c.net/showthread.php?t=102576

//          - Installation:
//                                - Import/copy Spell Code and Requires folder to your map
//                                - Import/copy the custom ability and unit to your map and change the SPELL_ID, DUMMY_ID, DUMMY_SPELL_ID,
//                               BUFF_ID if needed
//                                - You may view the raw ID of the objects by pressing CTRL+D in the object editor
//                                - You may play with the configurables below
//
//
//***************************************************************************
//***************************************************************************
//***************************************************************************

library ShadowImagesSword
    
    globals
    
        //-------------------------------------------------------------------------------------------------------------------------
        //-------------------------------------------------SPELL CONFIGURABLE------------------------------------------------------
        //-------------------------------------------------------------------------------------------------------------------------
        
        //Spell rawcode, change if needed
        private constant integer        SPELL_ID            ='A000'
        //Dummy stun spell rawcode, change if needed
        private constant integer        DUMMY_SPELL_ID      ='A001'
        //Rawcode of the dummy id, change if needed
        private constant integer        DUMMY_CASTER        ='e000'
        //Rawcode of the buff id, change if needed
        private constant integer        BUFF_ID             ='B000'
        //Rawcode of the fly ability, you can leave it alone :)
        private constant integer        FLY_ABILITY         ='Amrf'
        //Images alpha increase when it come back to the caster
        private constant integer        FADE_BACK_PERIOD    =3
        //Original dummy alpha
        private constant integer        DUMMY_ALPHA         =100
        //Spell periodic, you can leave it alone :)
        private constant real           PERIODIC            = .031250
        //Time to pause the caster animation
        private constant real           ANIMATION_PAUSE_TIME=0.5
        //Max height of the caster when he jumping
        private constant real           MAX_HEIGHT          =400.
        //The images will dehisce after reach this percent
        private constant real           DISTANCE_PERCENT    =50.
        //Caster jumping speed
        private constant real           SPEED               =10.
        //Enemies speed when they got hits from the caster
        private constant real           TARGET_SPEED        =20.
        //Enemies max height
        private constant real           TARGET_HEIGHT       =300.
        //Images separate speed
        private constant real           SEPARATE_SPEED      =10.
        //Images come back speed
        private constant real           DUMMY_FADE_BACK     =5.
        //Animation time after the images has separated
        private constant real           TIME_ANIMATION      =0.4
        //Sword distance of the images when they hit the ground
        private constant real           SWORD_DISTANCE      =100.
        //Slash area of effect
        private constant real           SLASH_AOE           =500.
        //Enemies knockback min distance
        private constant real           TARGET_MIN_DISTANCE =250.
        //Enemies knockback max distance
        private constant real           TARGET_MAX_DISTANCE =250.
        //Caster animation when he casting this spell
        private constant string         CASTER_ANIMATION    ="slam"
        //Spell dummy stun order id
        private constant string         DUMMY_ORDER         ="thunderbolt"
        //Spell dummy invisible order id
        private constant string         DUMMY_INVI_ORDER    ="invisibility"
        //The attachment of the images when they separate
        private constant string         ATTACHMENT          ="weapon"
        //Images sepatate effect
        private constant string         MIRROR_IMAGE_EFFECT ="Abilities\\Spells\\Orc\\MirrorImage\\MirrorImageCaster.mdl"
        //Caster jump effect
        private constant string         JUMP_EFFECT         ="Abilities\\Spells\\Orc\\WarStomp\\WarStompCaster.mdl"
        //Effect attach on the images
        private constant string         SWORD_EFFECT        ="Abilities\\Weapons\\IllidanMissile\\IllidanMissile.mdl"
        //Effect of the images when they hit the ground
        private constant string         SLASH_EFFECT        ="Abilities\\Spells\\Human\\Thunderclap\\ThunderClapCaster.mdl"
        //Knockback effect when the enemies got hits
        private constant string         KNOCK_EFFECT        ="Abilities\\Spells\\Human\\FlakCannons\\FlakTarget.mdl"
        //Effect of the caster when the images is back
        private constant string         EFFECT_BACK         ="Objects\\Spawnmodels\\NightElf\\EntBirthTarget\\EntBirthTarget.mdl"
        
        //**************************************************************
        private constant attacktype     AT                  = ATTACK_TYPE_HERO
        private constant damagetype     DT                  = DAMAGE_TYPE_DEATH
        private constant weapontype     WT                  = WEAPON_TYPE_CLAW_HEAVY_SLICE
        //Damage base of this spell
        private constant real           DAMAGE_BASE         = 100.
        //**************************************************************
        
        //-------------------------------------------------------------------------------------------------------------------------
        //-------------------------------------------------------------------------------------------------------------------------
        //-------------------------------------------------------------------------------------------------------------------------
        
        //------------------------------------------------------------
        //----------------------NON CONFIGURABLE----------------------
        //------------------------------------------------------------
        /**/    private          integer M=-1
        /**/    private          integer M2=-1
        /**/    private          integer array MData
        /**/    private          integer array MData2
        /**/    
        /**/    private constant timer T=CreateTimer()
        /**/    private constant timer T2=CreateTimer()
        /**/    
        /**/    private constant group G=CreateGroup()
        /**/
        /**/    private          location L=Location(0.,0.)
        /**/    private          unit   DummyCaster
        /**/    private          unit   First
        //------------------------------------------------------------
        //------------------------------------------------------------
        //------------------------------------------------------------
        
    endglobals
    
    //Filter Function Settings******************************************
    private constant function filterFunc takes unit filterUnit, player casterOwner returns boolean
        return not IsUnitType(filterUnit,UNIT_TYPE_DEAD) and GetUnitTypeId(filterUnit) != 0 and IsUnitEnemy(filterUnit,casterOwner)
    endfunction
    //********************************************************************
    
    //Damage settings*****************************************************
    private constant function getDamage takes integer lvl returns real
        return DAMAGE_BASE+(lvl+50.)
    endfunction
    //******************************************************************
    
    function AddSpecialEffectZ takes string path, real x, real y, real z returns effect
        local destructable d = CreateDestructableZ( 'OTip', x, y, z, 0.00, 1, 0 )
        set bj_lastCreatedEffect = AddSpecialEffect( path, x, y )
        call RemoveDestructable( d )
        set d = null
        return bj_lastCreatedEffect
    endfunction
    
    struct KnockBackZ
    
        unit caster
        
        real distance
        real cos
        real sin
        real tick
        real reach=0.
    
        static method onPeriodic takes nothing returns nothing
            local thistype this
            local integer i=0
            
            local real x
            local real y
            local real f
            
            loop
                exitwhen i>M2
                
                set this=MData2[i]
                
                if reach<distance then
                    set reach=reach+tick
                    
                    set x=GetUnitX(caster)+cos
                    set y=GetUnitY(caster)+sin
                    call MoveLocation(L,x,y)
                    
                    set f=(4*TARGET_HEIGHT*reach)/distance*(1-(reach/distance))+GetLocationZ(L)
                    
                    call SetUnitPosition(caster,x,y)
                    call SetUnitFlyHeight(caster,f,0.)
                    call DestroyEffect(AddSpecialEffectZ(KNOCK_EFFECT,x,y,f))
                else
                
                    set caster=null
                
                    set MData2[this]=MData2[M2]
                    set MData2[M2]=-1
                    set M2=M2-1
                    
                    if M2==-1 then
                        call PauseTimer(T2)
                    endif
                    
                    call destroy()
                    
                    return
                    
                endif
                
                set i=i+1
            endloop
        endmethod
        
        static method knockAdd takes unit whichUnit,real whichAngle returns nothing
            local thistype this=allocate()
            
            set M2=M2+1
            set MData2[M2]=this
            
            set caster=whichUnit
            
            set distance=GetRandomReal(TARGET_MIN_DISTANCE,TARGET_MAX_DISTANCE)
            set tick=distance/TARGET_HEIGHT*TARGET_SPEED
            
            set cos=tick*Cos(whichAngle)
            set sin=tick*Sin(whichAngle)
            
            if UnitAddAbility(caster,FLY_ABILITY) then
                call UnitRemoveAbility(caster,FLY_ABILITY)
            endif
            
            if M2==0 then
                call TimerStart(T2,PERIODIC,true,function thistype.onPeriodic)
            endif
        endmethod
        
    endstruct
    
    struct ShadowImagesSword
        
        unit caster
        unit dummy
        
        effect e_caster
        effect e_dummy
        
        player casterOwner
        
        boolean stopFading=false
        
        real angle
        real angle2
        real max
        real time=0.
        real reach=0.
        real tick
        real dmg
        real distance_counter=0.
        real cos
        real sin
        
        integer fade_alpha
        
        method GroupEnumUnits takes unit cast,real x, real y returns nothing
            local real fx
            
            call GroupEnumUnitsInRange(G,x,y,SLASH_AOE,null)
            
            set x=GetUnitX(cast)
            set y=GetUnitY(cast)
            
            loop
                set First=FirstOfGroup(G)
                exitwhen First==null
                
                if filterFunc(First,casterOwner) then
                
                    set fx=GetUnitX(First)
                    set time=GetUnitY(First)
                    
                    call KnockBackZ.knockAdd(First,Atan2(time-y,fx-x))
                    call UnitDamageTarget(caster,First,dmg,true,false,AT,DT,WT)
                    
                    call SetUnitX(DummyCaster,fx)
                    call SetUnitY(DummyCaster,time)
                    call IssueTargetOrder(DummyCaster,DUMMY_ORDER,First)
                endif
                
                call GroupRemoveUnit(G,First)
            endloop
        endmethod
        
        static method onPeriodic takes nothing returns nothing
            local thistype this
            local integer i=0
            
            local real x
            local real y
            local real percent
            local real s
            
            loop
                exitwhen i>M
                
                set this=MData[i]
                
                if reach<max then
                
                    set x=GetUnitX(caster)+cos
                    set y=GetUnitY(caster)+sin
                    
                    call SetUnitX(caster,x)
                    call SetUnitY(caster,y)

                    set x=GetUnitX(dummy)+cos
                    set y=GetUnitY(dummy)+sin
                    
                    call SetUnitX(dummy,x)
                    call SetUnitY(dummy,y)
                    
                    set reach=reach+tick
                    
                    call MoveLocation(L,x,y)
                    
                    set s=(4*MAX_HEIGHT*reach)/max*(1-(reach/max))+GetLocationZ(L)
                    
                    call SetUnitFlyHeight(caster,s,0.)
                    call SetUnitFlyHeight(dummy,s,0.)
                    
                    if not stopFading then
                    
                        if time<ANIMATION_PAUSE_TIME then
                            set time=time+PERIODIC
                        else
                            call SetUnitTimeScale(dummy,0.)
                            call SetUnitTimeScale(caster,0.)
                        endif
                        
                        set percent=reach/max*100.
                        
                        if percent>= DISTANCE_PERCENT then
                            set stopFading=true
                            
                            set e_caster=AddSpecialEffectTarget(SWORD_EFFECT,caster,ATTACHMENT)
                            set e_dummy=AddSpecialEffectTarget(SWORD_EFFECT,dummy,ATTACHMENT)
                            
                            if GetLocalPlayer()==casterOwner then
                                call SelectUnit(caster,false)
                            endif
                            
                            call UnitAddAbility(caster,'Aloc')
                            call SetUnitVertexColor(caster,255,255,255,DUMMY_ALPHA)
                            call DestroyEffect(AddSpecialEffectZ(MIRROR_IMAGE_EFFECT,x,y,s))
                            
                            call SetUnitTimeScale(dummy,TIME_ANIMATION)
                            call SetUnitTimeScale(caster,TIME_ANIMATION)
                        endif
                        
                    else

                        set percent=SEPARATE_SPEED*Cos(angle2)
                        set s=SEPARATE_SPEED*Sin(angle2)
                        
                        set x=GetUnitX(dummy)+percent
                        set y=GetUnitY(dummy)+s
                        
                        call SetUnitX(dummy,x)
                        call SetUnitY(dummy,y)
                        
                        set x=GetUnitX(caster)-percent
                        set y=GetUnitY(caster)-s
                        
                        call SetUnitX(caster,x)
                        call SetUnitY(caster,y)
                        
                        set distance_counter=distance_counter+SEPARATE_SPEED
                        
                    endif
                    
                    if reach>=max then
                    
                        set cos=SWORD_DISTANCE*Cos(angle)
                        set sin=SWORD_DISTANCE*Sin(angle)
                        
                        set x=GetUnitX(caster)+cos
                        set y=GetUnitY(caster)+sin
                        
                        call DestroyEffect(AddSpecialEffect(SLASH_EFFECT,x,y))
                        
                        call SetUnitAbilityLevel(DummyCaster,DUMMY_SPELL_ID,fade_alpha)
                        
                        set fade_alpha=DUMMY_ALPHA
                        
                        call GroupEnumUnits(caster,x,y)
                        
                        set x=GetUnitX(dummy)+cos
                        set y=GetUnitY(dummy)+sin
                        
                        call DestroyEffect(AddSpecialEffect(SLASH_EFFECT,x,y))
                        
                        call GroupEnumUnits(dummy,x,y)
                        
                        set cos=DUMMY_FADE_BACK*Cos(angle2)
                        set sin=DUMMY_FADE_BACK*Sin(angle2)
                        
                        call DestroyEffect(e_caster)
                        call DestroyEffect(e_dummy)
                        set e_caster=null
                        set e_dummy=null
                    endif

                else
                    
                    set x=GetUnitX(dummy)-cos
                    set y=GetUnitY(dummy)-sin
                    
                    call SetUnitX(dummy,x)
                    call SetUnitY(dummy,y)
                    
                    set x=GetUnitX(caster)+cos
                    set y=GetUnitY(caster)+sin
                    
                    call SetUnitX(caster,x)
                    call SetUnitY(caster,y)
                    
                    if distance_counter>DUMMY_FADE_BACK then
                    
                        set distance_counter=distance_counter-DUMMY_FADE_BACK
                        set fade_alpha=fade_alpha+FADE_BACK_PERIOD
                        
                        call SetUnitVertexColor(dummy,255,255,255,fade_alpha)
                        call SetUnitVertexColor(caster,255,255,255,fade_alpha)
                        
                    else

                        call UnitRemoveAbility(caster,'Aloc')
                        call ShowUnit(caster,false)
                        call ShowUnit(caster,true)
                        call UnitRemoveAbility(caster,BUFF_ID)
                        call DestroyEffect(AddSpecialEffect(EFFECT_BACK,x,y))
                        
                        call SetUnitX(DummyCaster,x)
                        call SetUnitY(DummyCaster,y)
                        call IssueTargetOrder(DummyCaster,DUMMY_INVI_ORDER,caster)

                        call SetUnitTimeScale(caster,1.)
                        
                        call SetUnitAnimation(caster,"stand")
                        call SetUnitVertexColor(caster,255,255,255,255)
                        
                        if GetLocalPlayer()==casterOwner then
                            call SelectUnit(caster,true)
                        endif
                        
                        call RemoveUnit(dummy)
                        
                        set caster=null
                        set dummy=null
                        set casterOwner=null
                    
                        set MData[i]=MData[M]
                        set MData[M]=-1
                        set M=M-1
                        
                        if M==-1 then
                            call PauseTimer(T)
                        endif
                        
                        call destroy()
                        return
                    endif
                    
                endif
                
                set i=i+1
            endloop
            
        endmethod
        
        static method onCast takes nothing returns boolean
            local thistype this
            
            local real x
            local real y
            local real o
            local real z
            
            if GetSpellAbilityId()==SPELL_ID then
                
                set this=allocate()
                
                set M=M+1
                set MData[M]=this
                
                set caster=GetTriggerUnit()
                set casterOwner=GetTriggerPlayer()
                
                set x=GetUnitX(caster)
                set y=GetUnitY(caster)
                set o=GetSpellTargetX()
                set z=GetSpellTargetY()                
                
                set fade_alpha=GetUnitAbilityLevel(caster,SPELL_ID)
                
                set dmg=getDamage(fade_alpha)
                
                set max=SquareRoot((x-o)*(x-o)+(y-z)*(y-z))
                
                set angle2=(57.29583*Atan2(z-y,o-x)+90.)
                set angle=(angle2-90.)
                set angle2=angle2*.0174533
                
                set tick=max/MAX_HEIGHT*SPEED
                
                set dummy= CreateUnit(Player(15),GetUnitTypeId(caster),x,y,angle)
                
                set angle=angle*.0174533
                
                set cos=tick*Cos(angle)
                set sin=tick*Sin(angle)
                
                call SetUnitColor(dummy,GetPlayerColor(casterOwner))
                
                if UnitAddAbility(dummy,FLY_ABILITY) and UnitAddAbility(caster,FLY_ABILITY) then
                    call UnitRemoveAbility(dummy,FLY_ABILITY)
                    call UnitRemoveAbility(caster,FLY_ABILITY)
                    call UnitAddAbility(dummy,'Aloc')
                    
                    call SetUnitVertexColor(dummy,255,255,255,DUMMY_ALPHA)
                    
                    call SetUnitX(dummy,x)
                    call SetUnitY(dummy,y)
                endif
                
                call SetUnitAnimation(caster,CASTER_ANIMATION)
                call SetUnitAnimation(dummy,CASTER_ANIMATION)
                
                call SetUnitX(DummyCaster,x)
                call SetUnitY(DummyCaster,y)
                call SetUnitAbilityLevel(DummyCaster,DUMMY_SPELL_ID,5)
                call IssueTargetOrder(DummyCaster,DUMMY_ORDER,caster)
                
                call DestroyEffect(AddSpecialEffect(JUMP_EFFECT,x,y))
                
                if M==0 then
                    call TimerStart(T,PERIODIC,true,function thistype.onPeriodic)
                endif
                
            endif
            
            return false
        endmethod
        
        static method onInit takes nothing returns nothing
            local integer i=0
            local trigger t=CreateTrigger()
            
            loop
                exitwhen i>15
                
                call TriggerRegisterPlayerUnitEvent(t,Player(i),EVENT_PLAYER_UNIT_SPELL_EFFECT,null)
                
                set i=i+1
            endloop
            
            call TriggerAddCondition(t,function thistype.onCast)
            
            set DummyCaster=CreateUnit(Player(15),DUMMY_CASTER,0.,0.,0.)
        
            set t=null
        endmethod
        
    endstruct
    
endlibrary
Changelogs
v1.0: First release version
v1.1: Minor mistake fixed
Keywords:
shadow, images, sword
Contents

Shadow Images Sword (Map)

Reviews
12th Dec 2015 IcemanBo: Too long as NeedsFix. Rejected. 15:57, 1st Jan 2015 Maker: IcemanBo and edo did a pretty good review. Follow the advice given there.

Moderator

M

Moderator

12th Dec 2015
IcemanBo: Too long as NeedsFix. Rejected.

15:57, 1st Jan 2015
Maker: IcemanBo and edo did a pretty good review.
Follow the advice given there.
 

Kazeon

Hosted Project: EC
Level 33
Joined
Oct 12, 2011
Messages
3,443
  • JASS:
    set dummy= CreateUnit(Player(15),GetUnitTypeId(caster),x,y,angle)
    Store Player(15) in a constant global variable
  • JASS:
                    if UnitAddAbility(dummy,FLY_ABILITY) and UnitAddAbility(caster,FLY_ABILITY) then
                        call UnitRemoveAbility(dummy,FLY_ABILITY)
                        call UnitRemoveAbility(caster,FLY_ABILITY)
                        call UnitAddAbility(dummy,'Aloc')
                        
                        call SetUnitVertexColor(dummy,255,255,255,DUMMY_ALPHA)
                        
                        call SetUnitX(dummy,x)
                        call SetUnitY(dummy,y)
                    endif
    Just follow the convention:
    JASS:
    if UnitAddAbility(dummy,FLY_ABILITY) and UnitRemoveAbility(dummy,FLY_ABILITY) then
    endif
    if UnitAddAbility(caster,FLY_ABILITY) and UnitRemoveAbility(caster,FLY_ABILITY) then
    endif
    Then put the rest actions outside the block. Currently, it may fails if user has a dummy unit with Crow Form ability defaultly from OE (some coders prefer this way). And call UnitAddAbility(dummy,'Aloc'), dummy unit should have locust ability by default in OE. Just remove that line.
  • For sake of elegance, I would prefer to add all of dummy abilities via trigger. Beside, you only need those abilities just for one dummy caster. And in case users want to use their own dummy unit. Users don't need to have multiple dummy units for every spell on their maps right?
  • Personally, I don't like spells which make the caster become invulnerable. It's often considered as overpowered spell.
  • Stun ability has 5 levels?
 
Level 23
Joined
Apr 16, 2012
Messages
4,041
Shadow Images Sword v1.1 - Review by IcemanBo & edo494

Concept:

Hero jump up to the sky, and while mid-air, he creates 2 illusions that jump to different directions, and upon reaching the ground they deal varying AoE damage and stun all enemies in certain range for certain time. After they land, the illusions disappear and the caster goes invisible for certain amount of time.

Code:
  • instead of it being library, make it a scope. Library is used for systems that are meant to be seen by the whole code.

  • instead of using strings, you could use orderids(integers) in the configurable

  • Spell should not work in deep water, because if unit gets pushed there(or caster jumps there). You will have to somehow check if user doesnt try to jump into deep water

  • Inside AddSpecialEffectZ you dont use the destructable you create, if you meant to create special effect on the destructable, use AddSpecialEffectTarget(path, d, "some attachment"). If you dont, you can directly return AddSpecialEffect(path, x, y)

  • struct KnockBackZ => private struct KnockBackZ, struct ShadowImagesSword => private struct ShadowImagesSword

  • Inside ShadowImagesSword.onPeriodic, inside the if not stopFading then and if percent>= DISTANCE_PERCENT then you create 2 effects, but you never remove them(if reach>=max evaluates to false). My(Edo) point of view on this is that if you create handle in certain scope, you should remove it in that scope, or before end of loop or end of function. You do neither in that if, you follow this on the rest tho.

  • Return statement inside KnockBackZ.onPeriodic inside the else block is useless. It may cause glitches, because you can potentially stop iterating mid-way The same return statement problem appears inside ShadowImagesSword.onPeriodic, you potentially return while iterating over the list.

  • 57.29583, *.0174533 => what is this magical sorcery constant?

  • if UnitAddAbility(dummy,FLY_ABILITY) and UnitAddAbility(caster,FLY_ABILITY) then could be if UnitAddAbility(dummy,FLY_ABILITY) and UnitAddAbility(caster,FLY_ABILITY) and UnitRemoveAbility(dummy,FLY_ABILITY) and UnitRemoveAbility(caster,FLY_ABILITY) then, + it can fail if unit already has crow form ability on it when you call it(it will return false)

  • set dummy= CreateUnit(Player(15),GetUnitTypeId(caster),x,y,angle) You could store Player(15) inside constant variable, or use one provided by blizzard(Yes, I am looking at you PLAYER_NEUTRAL_PASSIVE

  • Quality of life: You dont need to actually loop inside the onInit, you could've just called the BJ, it does it for you anyways.
    You also dont need to null the trigger, as you never destroy it(I agree it is good practice, but technically just waste of 22 bytes :D)

  • Inside ShadowImagesSword.onPeriodic you periodically call SelectUnit(caster,false/true), and this is not really mentioned, nor is it really required. You could make a constant boolean DE_SELECT_ON_PERIODIC and wrap the selection in static if

  • Also, you should follow JPAG with naming, for instance private integer M=-1 is not really descriptive. And yes, not only the configurable should be descriptive.

Visuals:

  • When jumping over cliffs, the jump does not look very smooth
  • The skill icon does not fit well into the spell
  • tooltip could use some love(Improve the wordings, because it is kind of a mess as of now)
  • The ending effect is not really all that fitting, considering its origins(Mind control I believe)
Conclusion:

The code is pretty solid, with a few flaws in it, but no real logical errors. The concept of the spell is above average, because it "stands out of ordinary" with the spells of type "Jump, hit ground, knockback, damage", but this spell does a little bit unique stuff by spliting to two different units and Comboing the units.
The visuals could've been improved, mainly the tooltip and icon of the spell.

Rating: 3.5/5 Unique, will change to 4/5 when updated

 
Top