• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

[JASS]Shadow Slashes v1.0

This bundle is marked as useful / simple. Simplicity is bliss, low effort and/or may contain minor bugs.
  • Description
    Moves so fast to random point nearby while slashing all enemy ground units nearby the caster and dealing damage each slash.
  • Screenshots
    Shadow%20Slashes2.jpg

    Shadow%20Slashes3.jpg

  • Codes/Triggers
    • Shadow Slashes Setting
      • Events
        • Map initialization
      • Conditions
      • Actions
        • -------- --------------------------- --------
        • -------- Ability object --------
        • Set Ssla_ability = Shadow Slashes
        • -------- --------------------------- --------
        • -------- Ability order ID --------
        • Set Ssla_orderID = (Order(stomp))
        • -------- --------------------------- --------
        • -------- Determines the slash times --------
        • Set Ssla_slashCount[1] = 30
        • Set Ssla_slashCount[2] = 40
        • Set Ssla_slashCount[3] = 50
        • Set Ssla_slashCount[4] = 60
        • -------- --------------------------- --------
        • -------- Determines the damage per slash --------
        • Set Ssla_slashDamage[1] = 10.00
        • Set Ssla_slashDamage[2] = 12.00
        • Set Ssla_slashDamage[3] = 14.00
        • Set Ssla_slashDamage[4] = 16.00
        • -------- --------------------------- --------
        • -------- Determines the slash damage radius --------
        • Set Ssla_slashRadius[1] = 100.00
        • Set Ssla_slashRadius[2] = 100.00
        • Set Ssla_slashRadius[3] = 100.00
        • Set Ssla_slashRadius[4] = 100.00
        • -------- --------------------------- --------
        • -------- Determines the slash AoE --------
        • Set Ssla_slashAoE[1] = 500.00
        • Set Ssla_slashAoE[2] = 500.00
        • Set Ssla_slashAoE[3] = 500.00
        • Set Ssla_slashAoE[4] = 500.00
        • -------- --------------------------- --------
        • -------- Determines the slash animation --------
        • Set Ssla_slashAnimation = attack
        • -------- --------------------------- --------
        • -------- Determines the slash animation speed --------
        • Set Ssla_slashAnimationSpeed = 400.00
        • -------- --------------------------- --------
        • -------- Determines the slash hit effect --------
        • Set Ssla_slashEffect = Abilities\Spells\Other\Stampede\StampedeMissileDeath.mdl
        • Set Ssla_slashEffectPoint = origin
        • -------- --------------------------- --------
        • -------- Determines the effect attached on caster while casting the spell --------
        • Set Ssla_attachedEffect = Abilities\Weapons\PhoenixMissile\Phoenix_Missile_mini.mdl
        • Set Ssla_attachedEffectPoint[1] = hand left
        • Set Ssla_attachedEffectPoint[2] = hand right
        • -------- --------------------------- --------
        • -------- Determines the move effect --------
        • Set Ssla_moveEffect = Abilities\Spells\NightElf\Blink\BlinkCaster.mdl
        • -------- --------------------------- --------
        • -------- Determines the attack-type --------
        • Set Ssla_attackType = Spells
        • -------- --------------------------- --------
        • -------- Determines the damage-type --------
        • Set Ssla_damageType = Shadow Strike
    JASS:
    //***************************************************************************
    //*                                                                         *
    //*  Shadow Slashes v1.0                                                    *
    //*  by Haley                                                               *
    //*                                                                         *
    //***************************************************************************
    //*                                                                         *
    //*  Moves so fast to random point nearby while slashing all enemy ground   *
    //*  units nearby the caster and dealing damage each slash.                 *
    //*                                                                         *
    //***************************************************************************
    //*                                                                         *
    //*  Visit www.hiveworkshop.com for more spells                             *
    //*                                                                         *
    //***************************************************************************
    
    constant function Ssla_timerSpeed takes nothing returns real
        return 0.03125
    endfunction
    
    constant function Ssla_stopOrder takes nothing returns integer
        return OrderId("stop")
    endfunction
    
    constant function Ssla_harvestOrder takes nothing returns integer
        return OrderId("harvest")
    endfunction
    
    function Ssla_TreeEnumeration takes nothing returns nothing
        local destructable d=GetEnumDestructable()
        if GetWidgetLife(d)>0 then
            call IssueTargetOrderById(udg_Ssla_harvester,Ssla_harvestOrder(),d)
            if GetUnitCurrentOrder(udg_Ssla_harvester)==Ssla_harvestOrder() then
                call KillDestructable(d)
            endif
        endif
        set d=null
    endfunction
    
    function Ssla_Periodic takes nothing returns nothing
        local integer index=1
        local real aoe
        local real angle
        local unit u
        local location l
        loop
            exitwhen index>udg_Ssla_maxIndex
            if GetUnitCurrentOrder(udg_Ssla_caster[index])==udg_Ssla_orderID then
                if udg_Ssla_counter[index]>0 then
                    call GroupEnumUnitsInRange(udg_Ssla_tempGroup,udg_Ssla_orgX[index],udg_Ssla_orgY[index],udg_Ssla_slashAoE[udg_Ssla_level[index]],null)
                    call GroupRemoveUnit(udg_Ssla_tempGroup,udg_Ssla_target[index])
                    set udg_Ssla_target[index]=null
                    loop
                        set u=FirstOfGroup(udg_Ssla_tempGroup)
                        exitwhen u==null
                        if not IsUnitType(u,UNIT_TYPE_DEAD) and IsUnitEnemy(u,udg_Ssla_owner[index]) and IsUnitType(u,UNIT_TYPE_GROUND) and not IsUnitType(u,UNIT_TYPE_MAGIC_IMMUNE) then
                            set udg_Ssla_target[index]=u
                            exitwhen true
                        else
                            call GroupRemoveUnit(udg_Ssla_tempGroup,u)
                        endif
                    endloop
                    if udg_Ssla_target[index]==null then
                        set aoe=GetRandomReal(0,udg_Ssla_slashAoE[udg_Ssla_level[index]])
                        set angle=GetRandomReal(0,6.2892)
                        set udg_Ssla_mapX[2]=udg_Ssla_orgX[index]+aoe*Cos(angle)
                        set udg_Ssla_mapY[2]=udg_Ssla_orgY[index]+aoe*Sin(angle)
                        if udg_Ssla_mapX[2]<udg_Ssla_mapX[0] then
                            set udg_Ssla_mapX[2]=udg_Ssla_mapX[0]
                        elseif udg_Ssla_mapX[2]>udg_Ssla_mapX[1] then
                            set udg_Ssla_mapX[2]=udg_Ssla_mapX[1]
                        endif
                        if udg_Ssla_mapY[2]<udg_Ssla_mapY[0] then
                            set udg_Ssla_mapY[2]=udg_Ssla_mapY[0]
                        elseif udg_Ssla_mapY[2]>udg_Ssla_mapY[1] then
                            set udg_Ssla_mapY[2]=udg_Ssla_mapY[1]
                        endif
                    else
                        set udg_Ssla_mapX[2]=GetUnitX(udg_Ssla_target[index])
                        set udg_Ssla_mapY[2]=GetUnitY(udg_Ssla_target[index])
                    endif
                    call DestroyEffect(AddSpecialEffect(udg_Ssla_moveEffect,udg_Ssla_mapX[2],udg_Ssla_mapY[2]))
                    call SetUnitX(udg_Ssla_caster[index],udg_Ssla_mapX[2])
                    call SetUnitY(udg_Ssla_caster[index],udg_Ssla_mapY[2])
                    call SetUnitAnimation(udg_Ssla_caster[index],udg_Ssla_slashAnimation)
                    call GroupEnumUnitsInRange(udg_Ssla_tempGroup,udg_Ssla_mapX[2],udg_Ssla_mapY[2],udg_Ssla_slashRadius[udg_Ssla_level[index]],null)
                    call GroupRemoveUnit(udg_Ssla_tempGroup,udg_Ssla_caster[index])
                    loop
                        set u=FirstOfGroup(udg_Ssla_tempGroup)
                        exitwhen u==null
                        if not IsUnitType(u,UNIT_TYPE_DEAD) and IsUnitEnemy(u,udg_Ssla_owner[index]) and IsUnitType(u,UNIT_TYPE_GROUND) and not IsUnitType(u,UNIT_TYPE_MAGIC_IMMUNE) then
                            call UnitDamageTarget(udg_Ssla_caster[index],u,udg_Ssla_slashDamage[udg_Ssla_level[index]],true,false,udg_Ssla_attackType,udg_Ssla_damageType,null)
                            call DestroyEffect(AddSpecialEffectTarget(udg_Ssla_slashEffect,u,udg_Ssla_slashEffectPoint))
                        endif
                        call GroupRemoveUnit(udg_Ssla_tempGroup,u)
                    endloop
                    set u=null
                    set l=Location(udg_Ssla_mapX[2],udg_Ssla_mapY[2])
                    call EnumDestructablesInCircleBJ(udg_Ssla_slashRadius[udg_Ssla_level[index]],l,function Ssla_TreeEnumeration)
                    call IssueImmediateOrderById(udg_Ssla_harvester,Ssla_stopOrder())
                    call RemoveLocation(l)
                    set l=null
                    set udg_Ssla_counter[index]=udg_Ssla_counter[index]-1
                else
                    call SetUnitX(udg_Ssla_caster[index],udg_Ssla_orgX[index])
                    call SetUnitY(udg_Ssla_caster[index],udg_Ssla_orgY[index])
                    call IssueImmediateOrderById(udg_Ssla_caster[index],Ssla_stopOrder())
                endif
            else
                if not IsUnitType(udg_Ssla_caster[index],UNIT_TYPE_DEAD) then
                    call SetUnitX(udg_Ssla_caster[index],udg_Ssla_orgX[index])
                    call SetUnitY(udg_Ssla_caster[index],udg_Ssla_orgY[index])
                endif
                call DestroyEffect(udg_Ssla_effect[index])
                call DestroyEffect(udg_Ssla_effect2[index])
                call SetUnitTimeScalePercent(udg_Ssla_caster[index],100)
                call SetUnitPathing(udg_Ssla_caster[index],true)
                set udg_Ssla_caster[index]=udg_Ssla_caster[udg_Ssla_maxIndex]
                set udg_Ssla_counter[index]=udg_Ssla_counter[udg_Ssla_maxIndex]
                set udg_Ssla_effect[index]=udg_Ssla_effect[udg_Ssla_maxIndex]
                set udg_Ssla_effect2[index]=udg_Ssla_effect2[udg_Ssla_maxIndex]
                set udg_Ssla_level[index]=udg_Ssla_level[udg_Ssla_maxIndex]
                set udg_Ssla_orgX[index]=udg_Ssla_orgX[udg_Ssla_maxIndex]
                set udg_Ssla_orgY[index]=udg_Ssla_orgY[udg_Ssla_maxIndex]
                set udg_Ssla_owner[index]=udg_Ssla_owner[udg_Ssla_maxIndex]
                set udg_Ssla_maxIndex=udg_Ssla_maxIndex-1
                if udg_Ssla_maxIndex==0 then
                    call PauseTimer(udg_Ssla_timer)
                else
                    set index=index-1
                endif
            endif
            set index=index+1
        endloop
    endfunction
    
    function Ssla_Cast takes nothing returns boolean
        if GetSpellAbilityId()==udg_Ssla_ability then
            if udg_Ssla_maxIndex==0 then
                call TimerStart(udg_Ssla_timer,Ssla_timerSpeed(),true,function Ssla_Periodic)
            endif
            set udg_Ssla_maxIndex=udg_Ssla_maxIndex+1
            set udg_Ssla_caster[udg_Ssla_maxIndex]=GetTriggerUnit()
            set udg_Ssla_owner[udg_Ssla_maxIndex]=GetTriggerPlayer()
            set udg_Ssla_level[udg_Ssla_maxIndex]=GetUnitAbilityLevel(udg_Ssla_caster[udg_Ssla_maxIndex],udg_Ssla_ability)
            set udg_Ssla_counter[udg_Ssla_maxIndex]=udg_Ssla_slashCount[udg_Ssla_level[udg_Ssla_maxIndex]]
            set udg_Ssla_orgX[udg_Ssla_maxIndex]=GetUnitX(udg_Ssla_caster[udg_Ssla_maxIndex])
            set udg_Ssla_orgY[udg_Ssla_maxIndex]=GetUnitY(udg_Ssla_caster[udg_Ssla_maxIndex])
            set udg_Ssla_effect[udg_Ssla_maxIndex]=AddSpecialEffectTarget(udg_Ssla_attachedEffect,udg_Ssla_caster[udg_Ssla_maxIndex],udg_Ssla_attachedEffectPoint[1])
            set udg_Ssla_effect2[udg_Ssla_maxIndex]=AddSpecialEffectTarget(udg_Ssla_attachedEffect,udg_Ssla_caster[udg_Ssla_maxIndex],udg_Ssla_attachedEffectPoint[2])
            call SetUnitTimeScalePercent(udg_Ssla_caster[udg_Ssla_maxIndex],udg_Ssla_slashAnimationSpeed)
            call SetUnitPathing(udg_Ssla_caster[udg_Ssla_maxIndex],false)
        endif
        return false
    endfunction
    
    //===========================================================================
    function InitTrig_Shadow_Slashes takes nothing returns nothing
        set gg_trg_Shadow_Slashes=CreateTrigger()
        call TriggerRegisterAnyUnitEventBJ(gg_trg_Shadow_Slashes,EVENT_PLAYER_UNIT_SPELL_EFFECT)
        call TriggerAddCondition(gg_trg_Shadow_Slashes,Filter(function Ssla_Cast))
        set udg_Ssla_mapX[0]=GetRectMinX(GetWorldBounds())
        set udg_Ssla_mapY[0]=GetRectMinY(GetWorldBounds())
        set udg_Ssla_mapX[1]=GetRectMaxX(GetWorldBounds())
        set udg_Ssla_mapY[1]=GetRectMaxY(GetWorldBounds())
        set udg_Ssla_harvester=CreateUnit(Player(15),'hpea',0,0,0)
        call UnitAddAbility(udg_Ssla_harvester,'Aloc')
        call ShowUnit(udg_Ssla_harvester,false)
    endfunction
  • Last Message
    My first JASS spell...!!
    See Readme in map and please rate, thank you for downloading...

Keywords:
Slash, Fast, Quick, Teleport, Instant, MUI.
Contents

testmap (Map)

Reviews
IcemanBo: Too long as NeedsFix. Rejected. 09:20, 7th May 2014 BPower: http://www.hiveworkshop.com/forums/spells-569/jass-shadow-slashes-v1-0-a-250246/#post2523356

Moderator

M

Moderator

IcemanBo: Too long as NeedsFix. Rejected.

09:20, 7th May 2014
BPower:
http://www.hiveworkshop.com/forums/spells-569/jass-shadow-slashes-v1-0-a-250246/#post2523356
 
Level 22
Joined
Sep 24, 2005
Messages
4,821
JASS:
constant function Ssla_stopOrder takes nothing returns integer
    return OrderId("stop")
endfunction

constant function Ssla_harvestOrder takes nothing returns integer
    return OrderId("harvest")
endfunction
You should replace those OrderId calls with constants, also, try to get rid of those location uses if possible.

Here's the OrderId list
 

Kazeon

Hosted Project: EC
Level 33
Joined
Oct 12, 2011
Messages
3,449
glad we got new Jasser :p

CODE:
  • call SetUnitTimeScalePercent(udg_Ssla_caster[index],100) => call SetUnitTimeScale(udg_Ssla_caster[index], 1)
    100% in integer equal to 1.00 in real
  • call EnumDestructablesInCircleBJ(udg_Ssla_slashRadius[udg_Ssla_level[index]],l,function Ssla_TreeEnumeration)
    don't use BJ

    but you can keep that
    call TriggerRegisterAnyUnitEventBJ(gg_trg_Shadow_Slashes,EVENT_PLAYER_UNIT_SPELL_EFFECT)
    ala you only use it for once.
  • JASS:
        set udg_Ssla_mapX[0]=GetRectMinX(GetWorldBounds())
        set udg_Ssla_mapY[0]=GetRectMinY(GetWorldBounds())
        set udg_Ssla_mapX[1]=GetRectMaxX(GetWorldBounds())
        set udg_Ssla_mapY[1]=GetRectMaxY(GetWorldBounds())
    don't use array, use normal variable like minX, minY, maxX, maxY
  • start maxindex from -1 and index from 0, but it's okay since you make it GUI-friendly so this is not a problem
  • set l=Location(udg_Ssla_mapX[2],udg_Ssla_mapY[2])don't ever try to use location in Jass
  • JASS:
    udg_Ssla_mapX[2]
    udg_Ssla_mapY[2]
    if I read your code correctly, it's coordinate of dummy unit, so it's not a good practice, just use local real for that.

    and don't use array if you are not using same type too often (in this case you are only using it three times which means you don't need to use array)
  • Chobibro is right :) fix it
  • JASS:
                        set udg_Ssla_mapX[2]=udg_Ssla_orgX[index]+aoe*Cos(angle)
                        set udg_Ssla_mapY[2]=udg_Ssla_orgY[index]+aoe*Sin(angle)
                        if udg_Ssla_mapX[2]<udg_Ssla_mapX[0] then
                            set udg_Ssla_mapX[2]=udg_Ssla_mapX[0]
                        elseif udg_Ssla_mapX[2]>udg_Ssla_mapX[1] then
                            set udg_Ssla_mapX[2]=udg_Ssla_mapX[1]
                        endif
    IMO =>
    JASS:
                        set x = udg_Ssla_orgX[index]+aoe*Cos(angle)
                        if x < udg_Ssla_maxX then
                            call SetUnitX(udg_Ssla_caster[index], x)
                        else
                            call SetUnitX(udg_Ssla_caster[index], udg_Ssla_maxX)
                        endif
    and y is the same. x and y is local real
  • call GroupRemoveUnit(udg_Ssla_tempGroup,udg_Ssla_caster[index])
    remove it, since if IsUnitEnemy(u,udg_Ssla_owner[index])
  • set u=null
    remove it since the loop exitwhen u == null
  • change
    • Set Ssla_slashAoE[1] = 500.00
    =>
    • Set Ssla_slashMaxDistance[1] = 500.00
    ?
  • change
    • Set Ssla_slashRadius[1] = 100.00
    =>
    • Set Ssla_slashAoE[1] = 100.00
    ?
  • no need to use array for this
    • Set Ssla_attachedEffectPoint[1] = hand left
    • Set Ssla_attachedEffectPoint[2] = hand right

OBJECT:
  • none

MISCS:
  • Give instructions how to import your spell
  • the spell is not overkill and channeling which is nice, I like it.. and I think the concept is not very similliar with other slashes..

SUGGESTION:
  • if not IsUnitType(u,UNIT_TYPE_DEAD) and IsUnitEnemy(u,udg_Ssla_owner[index]) and IsUnitType(u,UNIT_TYPE_GROUND) and not IsUnitType(u,UNIT_TYPE_MAGIC_IMMUNE) then
    add custom filtration function for user, so they can configure it
  • Maybe give user option to choose wheter they want the target is random or the closest unit.
  • Also give option for user if they don't want the caster to slash previous targets (can't slash the same target)
  • learn vJass ASAP :thumbs_up:
 
Level 29
Joined
Oct 24, 2012
Messages
6,543
You should not use this to detect dead units. It does not work.
JASS:
GetWidgetLife(d)>0
Units are dead when they are lower than .405 health.
You should use this to properly detect dead / removed units.
JASS:
GetWidgetLife( u) > .405 and not IsUnitType( u, UNIT_TYPE_DEAD) and GetUnitTypeId( u) != 0
Replace u with the unit you are checking.

Also as said above never use locations unless you are trying to get somethings Z height.
 
Level 8
Joined
Feb 3, 2013
Messages
277
haha this is a really cute spell

very good for your first man :)

some things to consider for the next time:
- have a filter func that filters alive enemy units sth like
JASS:
    function AliveEnemyUnits takes nothing returns boolean
        return not IsUnitType(GetFilterUnit(), UNIT_TYPE_DEAD) and IsUnitEnemy(GetFilterUnit(), udg_filterReferencePlayer)
    endfunction

    function YourFunc takes nothing returns nothing
        set udg_filterReferencePlayer = (GetOwningPlayer(u))
        call GroupEnumUnitsInRange(g, x, y, 300., Filter(function AliveEnemyUnits)
        loop
            // Now you don't have check if a unit is an alive enemy or not, while looping through your group
            call UnitDamageTarget(blah blah)
        endloop
    endfunction
- consider using vJass and stuff like LinkedList modules and PeriodicTimer modules so you can save time not having to reindex spells
 
Level 29
Joined
Oct 24, 2012
Messages
6,543
- have a filter func that filters alive enemy units sth like
JASS:
    function AliveEnemyUnits takes nothing returns boolean
        return IsUnitType(GetFilterUnit(), UNIT_TYPE_DEAD) and IsUnitEnemy(GetFilterUnit(), udg_filterReferencePlayer)
    endfunction

    function YourFunc takes nothing returns nothing
        set udg_filterReferencePlayer = (GetOwningPlayer(u))
        call GroupEnumUnitsInRange(g, x, y, 300., Filter(function AliveEnemyUnits)
        loop
            // Now you don't have check if a unit is an alive enemy or not, while looping through your group
            call UnitDamageTarget(blah blah)
        endloop
    endfunction

The above function does not accurately filter out alive and dead units. Please see my above post for the proper way to filter out units. But yes It's own function is nice as it makes it so the user can add units they do not want to be damaged by the spell.
 
You could create one global location variable and then take usage of...

native MoveLocation takes location whichLocation, real newX, real newY returns nothing

instead of creating a local location that has to be cleaned after usage each time.

GetWorldBounds() can be stored into a variable. Also you don't really need array here. Use 4 normal real variables:

maxX
minX
maxY
minY
 
Level 19
Joined
Mar 18, 2012
Messages
1,716
Haven't read previous comments, so there is a chance I repeat what was already mentioned:

The 4 world boundary variables should be global and non array, label them as IcemanBo said.

call SetUnitTimeScalePercent(...) should be SetUnitTimeScale(...), of course this laso changes the configuration part by factor 100.

set u=null is not required bec ause of the FoG loop.

The location is not required. You could also use EnumDestructablesInRect which only requires one global rect.

You have to stop the harvester in the end and the critical life for trees is 0.405 and not 0.00

udg_Ssla_mapX[2]/udg_Ssla_mapY[2] should be local real variables.

It looks not bad, still I'll set it to Need Fix for now.
 
Top