• 🏆 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!

Holy Dash v1.1

This bundle is marked as useful / simple. Simplicity is bliss, low effort and/or may contain minor bugs.
  • Like
Reactions: 1 person
The Paladin move fast toward one point, causing damage to all enemy units in the way and healing your allies for 30% of the inflicted damage.

- Level 1 - 700 cast range, 90 damage + 9% of strength.
- Level 2 - 900 cast range, 170 damage + 17% of strength.
- Level 3 - 1100 cast range, 280 damage + 24% of strength.
- Level 4 - 1300 cast range, 360 damage + 30% of strength.

Cooldown: 19/17/15/13 seconds.

Code:
JASS:
scope HolyDash
/***********************************************************************************
*   HolyDash
*   ________
*   v1.0.1.1
*   by Thelordmarshall
*
*   The Paladin move fast toward one point, causing damage to all enemy 
*   units in the way and healing your allies for 30% of the inflicted 
*   damage.
*   
*   Level 1 - 700 cast range, 90 damage + 9% of strength (Configurable).
*   Level 2 - 900 cast range, 170 damage + 17% of strength (Configurable).
*   Level 3 - 1100 cast range, 280 damage + 24% of strength (Configurable).
*   Level 4 - 1300 cast range, 360 damage + 30% of strength (Configurable).
*   
*   Cooldown: 19/17/15/13 seconds.
*   
*   How to import:
*   ______________
*
*       - Copy the folder "Requires" and "Holy Dash Spell".
*       - Copy the dummy unit and ability.
*       - Copy the ability Unit Indexing.
*       - Configure all raw codes in UnitIndexer and HolyDash triggers.
*       - You can configure other parameters of the spell (optional).
*       - Enjoy.
*
*   Credits:
*   ________
*
*       - Vexorian: TimerUtils.
*       - Nestharus: UnitIndexer.
*       - PitzerMike: DestructableLib functions.
*       - Rising_Dusk: TerrainPathability
*
*   Copyright © 2014.
************************************************************************************/

    globals
        private real array dmgLvl
        private real array attLvl
    endglobals

    //CONFIGURATION
    globals
        //Raw codes
        private constant integer    SPELL_ID          = 'A001'           //Raw code of your ability.
        private constant integer    DASH_DUMMY        = 'h000'           //Dummy raw code.
        private constant integer    MAIN_CASTER       = 'H001'           //Raw code of the main caster.
        //Basic Configuration
        private constant real       DASH_SPEED_TIME   = .8               //Max speed of the dash (in seconds).
        private constant real       DASH_AOE          = 90.              //Units affected in this range.
        private constant real       TAG_SIZE          = .02              //Textag size.
        private constant real       DASH_ANIM_SPEED   = 120.             //Caster animation speed.
        private constant real       DUMMY_ANIM_SPEED  = 220.             //Dummy animation speed.
        private constant integer    MOTION_BLUR_LEVEL = 90               //Transparency of the dummy unit (from 0 to 255).
        private constant integer    MOTION_TIME       = 4                //Time/speed to add transparency and remove the dummy unit.
        private constant string     ATTACH_FX_CASTER  = "weapon"         //Attach point of the fx caster.
        private constant string     ATTACH_FX         = "origin"         //Attach point of the fx enemys.
        private constant string     DASH_ANIMATION    = "attack"         //Animation for the caster.
        private constant string     DUMMY_ANIMATION   = "attack"         //Animation for dummys.
        private constant damagetype DASH_DMG_TYPE     = DAMAGE_TYPE_DIVINE
        //Tag colors
        private constant string     TAG_HEAL_COLOR    = "|c00FEBA0E"
        private constant string     TAG_DMG_COLOR     = "|c00FF0000"
        //Fx
        private constant string     DASH_FX_CASTER    = "Abilities\\Spells\\Other\\HealingSpray\\HealBottleMissile.mdl"
        private constant string     DASH_FX_ALLY      = "Abilities\\Spells\\Human\\HolyBolt\\HolyBoltSpecialArt.mdl"
        private constant string     DASH_FX_ENEMY     = "Abilities\\Spells\\Demon\\DarkPortal\\DarkPortalTarget.mdl"
        private constant string     DASH_EXTRA_FX     = "Abilities\\Weapons\\AncientProtectorMissile\\AncientProtectorMissile.mdl" //fx used in not walkable terrain.
        //Knockback fxs (if use the knockback feature)
        private constant string     KNOCKBACKED_FX1   = "Abilities\\Weapons\\AncientProtectorMissile\\AncientProtectorMissile.mdl" //fx in land.
        private constant string     KNOCKBACKED_FX2   = "Abilities\\Spells\\Undead\\AbsorbMana\\AbsorbManaBirthMissile.mdl"        //fx in water.
        //Advance Configuration
        private constant boolean    SHOW_TEXT_TAG     = true
        private constant boolean    PAUSE_CASTER      = true
        private constant boolean    HIT_TREES         = true
        private constant boolean    USE_KNOCKBACK     = true        //Konckback for enemys.
        private constant real       KNOCKBACKED_DIS   = 85.
        private constant real       KNOCKBACKED_SPEED = 1.
        private constant real       REFRESH_PERIOD    = .03125      //Recomended: .03125 (or 0.03 in GUI)
        private constant real       DEBUG_PERIOD      = 5.          //Time to disable the ability, only in case if not turn off automatically.
    endglobals

    //Damage base for each level.
    private function DamageConfig takes nothing returns nothing
        set dmgLvl[1] = 90.
        set dmgLvl[2] = 170.
        set dmgLvl[3] = 280.
        set dmgLvl[4] = 360.
    endfunction
    
    //Attribute % for each level.
    private function AttributePercentConfig takes nothing returns nothing
        set attLvl[1] = 9.
        set attLvl[2] = 17.
        set attLvl[3] = 24.
        set attLvl[4] = 30.
    endfunction

    //Attribute type, used for damage calculation, you can use str, int or agi.
    private function AttributeType takes unit caster returns integer
        return GetHeroStr(caster,true)
    endfunction
    
    //Heal calculation.
    private function GetHeal takes real dmg returns real
        return dmg*30./100. // =30%
    endfunction
    
    //Filter for afected units.
    private function ConfigFilter takes unit u returns boolean
        return GetWidgetLife(u) > .405 and not IsUnitType(u,UNIT_TYPE_STRUCTURE) and not IsUnitType(u,UNIT_TYPE_MAGIC_IMMUNE)
    endfunction
    //ENDCONFIGURATION
    
    //Core.
    private struct HolyDash extends array
        static if HIT_TREES then
            static rect treesRect
            static unit treesMurderer
        endif
        static if USE_KNOCKBACK then
            unit knockbacked
        endif
        unit caster
        player p
        real cos
        real sin
        real dmg
        real d1
        real d2
        real tTotal
        group dashGroup
        effect fx
        
        method showTag takes string s, real x, real y returns nothing
            local texttag tag = CreateTextTag()
            call SetTextTagText(tag,s,TAG_SIZE)
            call SetTextTagPos(tag,x,y,16.)
            call SetTextTagVelocity(tag,0.,.0355)
            call SetTextTagFadepoint(tag,1.5)
            call SetTextTagLifespan(tag,2.)
            call SetTextTagPermanent(tag,false)
            set tag = null
        endmethod
        
        static method fxOnGround takes real x, real y returns nothing
            local real AoE         = 250.
            local integer duration = R2I(.4*1000.)
            local real spaceWave   = 5.*duration/10.
            local real timeWave    = 5.*AoE/200.
            local real radiusRatio = AoE/50.
            call TerrainDeformStop(TerrainDeformRipple(x,y,AoE,80.,duration,2,spaceWave,timeWave,radiusRatio,true),duration)
        endmethod
        
        static if HIT_TREES then
            //Credits to PitzerMike for this function.
            static method isDesIsTree takes destructable d returns boolean
                local boolean result = false
                if d != null then
                    call PauseUnit(treesMurderer,false)
                    set result = IssueTargetOrder(treesMurderer,"harvest",d)
                    call PauseUnit(treesMurderer,true)
                endif
                return result
            endmethod
        
            static method destoyTrees takes nothing returns nothing
                local destructable d = GetEnumDestructable()
                if GetDestructableLife(d) > .405 and .isDesIsTree(d) then
                    call KillDestructable(d)
                endif
                set d = null
            endmethod
        endif
        
        static if USE_KNOCKBACK then
            static method onKnockback takes nothing returns nothing
                local timer t       = GetExpiredTimer()
                local thistype this = GetTimerData(t)
                local real x        = GetUnitX(.knockbacked)
                local real y        = GetUnitY(.knockbacked)
                
                set .tTotal = .tTotal+REFRESH_PERIOD

                if not IsUnitPaused(.knockbacked) then
                    call PauseUnit(.knockbacked,true)
                endif
                call SetUnitPosition(.knockbacked,x+.d1*.cos,y+.d1*.sin)
                if IsTerrainLand(x,y) then
                    call DestroyEffect(AddSpecialEffect(KNOCKBACKED_FX1,x,y))
                elseif IsTerrainShallowWater(x,y) then
                    call DestroyEffect(AddSpecialEffect(KNOCKBACKED_FX2,x,y))
                endif
                set .d1 = .d1-.d2
            
                if .d1 <= 0. or .tTotal >= DEBUG_PERIOD then
                    call PauseUnit(.knockbacked,false)
                    call SetUnitPathing(.knockbacked,true)
                    set .knockbacked = null
                    call ReleaseTimer(t)
                endif
                set t = null
            endmethod
            
            static method startKnockback takes unit u, real a returns nothing
                local thistype this = thistype[GetUnitId(u)]
                local integer q     = R2I(KNOCKBACKED_SPEED/REFRESH_PERIOD)
                
                set .knockbacked = u
                set .cos         = Cos(a)
                set .sin         = Sin(a)
                set .d1          = 2.*KNOCKBACKED_DIS/q+1.
                set .d2          = .d1/q
                set .tTotal      = 0.
                call SetUnitPathing(.knockbacked,false)
                call TimerStart(NewTimerEx(this),REFRESH_PERIOD,true,function thistype.onKnockback)
            endmethod
        endif
        
        method destroy takes nothing returns nothing
            call SetUnitTimeScale(.caster,100.*.01)
            call SetUnitAnimation(.caster,"attack")
            call PauseUnit(.caster,false)
            call SetUnitPathing(.caster,true)
            call DestroyGroup(.dashGroup)
            call DestroyEffect(.fx)
            call MotionBlur[.caster].destroy()
            set .p         = null
            set .caster    = null
            set .dashGroup = null
        endmethod

        static method onLoop takes nothing returns nothing
            local timer t       = GetExpiredTimer()
            local thistype this = GetTimerData(t)
            local real x        = GetUnitX(.caster)
            local real y        = GetUnitY(.caster)
            local real x2
            local real y2
            local real maxLife
            local real life
            local real heal
            local unit u
            
            set .tTotal = .tTotal+REFRESH_PERIOD
            
            static if PAUSE_CASTER then
                if not IsUnitPaused(.caster) then
                    call PauseUnit(.caster,true)
                endif
            endif

            call SetUnitPosition(.caster,x+.d1*.cos,y+.d1*.sin)
            call SetUnitAnimation(.caster,DASH_ANIMATION)
            
            if not IsTerrainWalkable(x,y) then
                call DestroyEffect(AddSpecialEffect(DASH_EXTRA_FX,x,y))
            endif
            
            call GroupEnumUnitsInRange(bj_lastCreatedGroup,x,y,DASH_AOE,null)
            loop
                set u = FirstOfGroup(bj_lastCreatedGroup)
                call GroupRemoveUnit(bj_lastCreatedGroup,u)
                if ConfigFilter(u) and not IsUnitInGroup(u,.dashGroup) and u != .caster then
                    set x2 = GetUnitX(u)
                    set y2 = GetUnitY(u)
                    if IsUnitEnemy(u,.p) then 
                        call UnitDamageTarget(.caster,u,.dmg,false,false,ATTACK_TYPE_HERO,DASH_DMG_TYPE,null)
                        //! textmacro OnHit takes FX,TAG_COLOR,REAL_VALUE
                        call DestroyEffect(AddSpecialEffectTarget($FX$,u,ATTACH_FX))
                        static if SHOW_TEXT_TAG then
                            call .showTag($TAG_COLOR$+I2S(R2I($REAL_VALUE$))+"!|r",GetUnitX(u),GetUnitY(u))
                        endif
                        call .fxOnGround(x2,y2)
                        //! endtextmacro
                        //! runtextmacro OnHit("DASH_FX_ENEMY","TAG_DMG_COLOR",".dmg")
                        static if USE_KNOCKBACK then
                            call .startKnockback(u,Atan2(y2-y,x2-x))
                        endif
                    else //If ally
                        set maxLife = GetUnitState(u,UNIT_STATE_MAX_LIFE)
                        set life = GetUnitState(u,UNIT_STATE_LIFE)
                        if life < maxLife then
                            set heal = GetHeal(.dmg)
                            call SetWidgetLife(u,life+heal)
                            //! runtextmacro OnHit("DASH_FX_ALLY","TAG_HEAL_COLOR","heal")
                        endif
                    endif
                    call GroupAddUnit(.dashGroup,u)
                endif
                exitwhen u == null
            endloop
            
            static if HIT_TREES then
                call MoveRectTo(treesRect,x,y)
                call EnumDestructablesInRect(treesRect,null,function thistype.destoyTrees)
            endif
            
            set .d1 = .d1-.d2

            if .d1 <= 0. or tTotal >= DEBUG_PERIOD then
                call .fxOnGround(x,y)
                call .destroy()
                call ReleaseTimer(t)
            endif
            set t = null
        endmethod    
    
        static method onCast takes nothing returns boolean
            local unit u        = GetTriggerUnit()
            local real x1       = GetUnitX(u)
            local real y1       = GetUnitY(u)
            local real x2       = GetSpellTargetX()
            local real y2       = GetSpellTargetY()
            local real a        = Atan2(y2-y1,x2-x1)
            local integer lvl   = GetUnitAbilityLevel(u,SPELL_ID)
            local integer id    = GetUnitTypeId(u)
            local integer q     = R2I(DASH_SPEED_TIME/REFRESH_PERIOD)
            local thistype this = thistype[GetUnitId(u)]
            
            if GetSpellAbilityId() == SPELL_ID then
                set .caster    = u
                set .p         = GetTriggerPlayer()
                set .cos       = Cos(a)
                set .sin       = Sin(a)
                set .d1        = 2.*SquareRoot(Pow(x2-x1,2)+Pow(y2-y1,2))/(q+1.)
                set .d2        = .d1/q
                set .dmg       = dmgLvl[lvl]+I2R(AttributeType(.caster))*attLvl[lvl]/100.
                set .fx        = AddSpecialEffectTarget(DASH_FX_CASTER,.caster,ATTACH_FX_CASTER)
                set .dashGroup = CreateGroup()
                set .tTotal    = 0.
                
                //Activating the motion blur.
                if id == MAIN_CASTER then
                    call MotionBlur[.caster].add(DASH_DUMMY,DUMMY_ANIMATION,DUMMY_ANIM_SPEED,MOTION_BLUR_LEVEL,MOTION_TIME,false)
                else
                    call MotionBlur[.caster].add(id,DUMMY_ANIMATION,DUMMY_ANIM_SPEED,MOTION_BLUR_LEVEL,MOTION_TIME,true)
                endif
                
                call SetUnitPathing(.caster,false)
                call SetUnitTimeScale(.caster,DASH_ANIM_SPEED*.01)
                call TimerStart(NewTimerEx(this),REFRESH_PERIOD,true,function thistype.onLoop)
            endif
            
            set u = null
            return false
        endmethod

        static method onInit takes nothing returns nothing
            local trigger t = CreateTrigger()
            call DamageConfig()
            call AttributePercentConfig()
            //Configuring the trees murderer dummy unit and rect(used for EnumDestructablesInRect).
            static if HIT_TREES then
                set treesMurderer = CreateUnit(Player(15),'hfoo',0.,0.,0.)
                call ShowUnit(treesMurderer,false)
                call UnitAddAbility(treesMurderer,'Ahrl')
                call UnitAddAbility(treesMurderer,'Aloc')
                call PauseUnit(treesMurderer,true)
                set treesRect = Rect(-DASH_AOE,-DASH_AOE,DASH_AOE,DASH_AOE)
            endif
            call TriggerRegisterAnyUnitEventBJ(t,EVENT_PLAYER_UNIT_SPELL_EFFECT)
            call TriggerAddCondition(t,Condition(function thistype.onCast))
        endmethod
    endstruct
endscope

Keywords:
Holy, dash, paladin, spell, motion, blur, transparency, alpha, vjass, jass.
Contents

Holy Dash v1.1 (Map)

Reviews
12th Dec 2015 IcemanBo: For long time as NeedsFix. Rejected. 14:56, 5th Jan 2015 Maker: Check my reply in this thread

Moderator

M

Moderator

12th Dec 2015
IcemanBo: For long time as NeedsFix. Rejected.

14:56, 5th Jan 2015
Maker: Check my reply in this thread
 
Level 8
Joined
Nov 9, 2011
Messages
326
I think that it lacks some configuration.

1. knocking back enemies could be an option.
2. showing another effect at the end of the dash could look nice as well.
3. make the user select the str scaling and if possible make it able to stack on int/agi
4. destroy nearby tress when dashing (you can turn it off in the config)

im getting used to ur new avatar
i always think its some random guy :D
 
Level 9
Joined
Jun 21, 2012
Messages
432
I think that it lacks some configuration.

1. knocking back enemies could be an option.
2. showing another effect at the end of the dash could look nice as well.
3. make the user select the str scaling and if possible make it able to stack on int/agi
4. destroy nearby tress when dashing (you can turn it off in the config)

1. knocking back enemies //Done.
2. showing another effect at the end of the dash. //not looking good.
3. make the user select the str scaling and if possible make it able to stack on int/agi //Done.
4. destroy nearby tress when dashing //Done.

I upload the new version maybe tomorrow.
 
Level 9
Joined
Jun 21, 2012
Messages
432
I think that it lacks some configuration.

1. knocking back enemies could be an option.
2. showing another effect at the end of the dash could look nice as well.
3. make the user select the str scaling and if possible make it able to stack on int/agi
4. destroy nearby tress when dashing (you can turn it off in the config)

well here is the update....
 
Top