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

Deadly Strike v1.6

  • Like
Reactions: Saif and Ken-E
JASS:
//=================        CUSTOM SCRIPT FUNCTIONS        =================

function RapidStrike_AddSpecialEffectTimed_Timer takes nothing returns nothing
    local timer t = GetExpiredTimer()
    local effect e = LoadEffectHandle(udg_RapidStrike_Hash,GetHandleId(t),0)
    
    call DestroyEffect(e)
    call FlushChildHashtable(udg_RapidStrike_Hash,GetHandleId(t))
    call DestroyTimer(t)
    
    set e = null
    set t = null    
endfunction

function RapidStrike_AddSpecialEffectTimed takes string modelName, real x, real y, real time returns nothing
    local timer t = CreateTimer()
    
    call SaveEffectHandle(udg_RapidStrike_Hash,GetHandleId(t),0,AddSpecialEffect(modelName,x,y))
    call TimerStart(t,time,false,function RapidStrike_AddSpecialEffectTimed_Timer)
    
    set t = null
endfunction

function RapidStrike_IsUnitMatching takes unit whichUnit, unit caster returns boolean
    return IsUnitEnemy(whichUnit,GetOwningPlayer(caster)) and not IsUnitPaused(whichUnit) and not IsUnitType(whichUnit,UNIT_TYPE_DEAD) and not IsUnitType(whichUnit,UNIT_TYPE_STRUCTURE) and not IsUnitType(whichUnit,UNIT_TYPE_MAGIC_IMMUNE)    
endfunction

//=================          SPELL CONSTANTS              =================

constant function RapidStrike_AbilId takes nothing returns integer
    // 'Deadly Strike' ability rawcode.
    return 'A000'
endfunction

constant function RapidStrike_DummyId takes nothing returns integer
    // Dummy rawcode.
    return 'n000'
endfunction

constant function RapidStrike_SoulId takes nothing returns integer
    // Soul rawcode.
    return 'n001'
endfunction

constant function RapidStrike_DummyAbilId takes nothing returns integer
    // Dummy cast ability rawcode.
    return 'A001'
endfunction

constant function RapidStrike_EffInt1 takes nothing returns real
    // Interval between ray effects spawn.
    return .6
endfunction

constant function RapidStrike_EffInt2 takes nothing returns real
    // Interval between thunderclap effects spawn.
    return .3
endfunction

constant function RapidStrike_EffDist takes nothing returns real
    // Offset from hero to effect spawns.
    return 250.
endfunction

constant function RapidStrike_MaxHeight takes nothing returns real
    // Maximal height that unit reaches when casting.
    return 280.
endfunction

constant function RapidStrike_StartAng takes nothing returns real
    // Starting angle for spawning the effects.
    return 90.
endfunction

constant function RapidStrike_PickRadius takes nothing returns real
    // Radius where units'll be picked and tossed up to the sky.
    return 340.
endfunction

constant function RapidStrike_SoulHeight takes nothing returns real
    // Maximal height that soul reaches when casting.
    return 420.
endfunction

constant function RapidStrike_RayEffPath takes nothing returns string
    // Black rays effect path.
    return "war3mapImported\\unholyStrikeX20c.mdx"
endfunction

constant function RapidStrike_StompEffPath takes nothing returns string
    // Stomp effect path.
    return "Abilities\\Spells\\Orc\\WarStomp\\WarStompCaster.mdl"
endfunction

constant function RapidStrike_TCEffPath takes nothing returns string
    // Thunderclap effect path.
    return "Abilities\\Spells\\Human\\Thunderclap\\ThunderClapCaster.mdl"
endfunction

//=================          SPELL FUNCTIONS              =================

function Trig_RapidStrike_Conditions takes nothing returns boolean
    return GetSpellAbilityId() == RapidStrike_AbilId()
endfunction

function Trig_RapidStrike_FlyDown takes nothing returns nothing
    local timer t = GetExpiredTimer()
    local integer id = GetHandleId(t)
    local unit u = LoadUnitHandle(udg_RapidStrike_Hash,id,0)
    local unit gu = LoadUnitHandle(udg_RapidStrike_Hash,id,1)
    local unit d = CreateUnit(GetOwningPlayer(u),RapidStrike_DummyId(),GetUnitX(u),GetUnitY(u),0.)

    call UnitAddAbility(d,RapidStrike_DummyAbilId())
    call SetUnitAbilityLevel(d,RapidStrike_DummyAbilId(),GetUnitAbilityLevel(u,RapidStrike_AbilId()))
    call IssueTargetOrderById(d,852095,gu)
    call UnitApplyTimedLife(d,'BTLF',.75)
    call SetUnitFlyHeight(gu,0.,RapidStrike_MaxHeight()/.3)
    
    call FlushChildHashtable(udg_RapidStrike_Hash,id)
    call DestroyTimer(t)

    set t = null
    set u = null
    set gu = null
    set d = null
endfunction

function Trig_RapidStrike_EffTimer takes nothing returns nothing  
    local timer t = GetExpiredTimer()
    local integer id = GetHandleId(t)
    local unit u = LoadUnitHandle(udg_RapidStrike_Hash,id,0)
    local unit soul = LoadUnitHandle(udg_RapidStrike_Hash,id,5)
    local real ux = GetUnitX(u)
    local real uy = GetUnitY(u)
    local real a = LoadReal(udg_RapidStrike_Hash,id,4)
    local real x = ux + RapidStrike_EffDist() * Cos(a*.0174532)
    local real y = uy + RapidStrike_EffDist() * Sin(a*.0174532)
    local boolean b = LoadBoolean(udg_RapidStrike_Hash,id,2)
    local unit gu
    local timer gt
    local integer gtid
    
    if not b then
    
        if a >= RapidStrike_StartAng() + 360. then
            call SaveBoolean(udg_RapidStrike_Hash,id,2,true)
            call SetUnitAnimation(u,"stand")
            call DestroyEffect(AddSpecialEffect(RapidStrike_StompEffPath(),ux,uy))
            call RemoveUnit(soul)
        
            call SaveReal(udg_RapidStrike_Hash,GetHandleId(t),4,RapidStrike_StartAng())
        
            call TimerStart(t,RapidStrike_EffInt2(),true,function Trig_RapidStrike_EffTimer)
        else
            if a >= RapidStrike_StartAng() + 180. then
                call SetUnitFlyHeight(u,0.,RapidStrike_MaxHeight()/(RapidStrike_EffInt1()*2.))
                call SetUnitFlyHeight(soul,0.,RapidStrike_SoulHeight()/(RapidStrike_EffInt1()*2.))
            endif
            call RapidStrike_AddSpecialEffectTimed(RapidStrike_RayEffPath(),x,y,1.5)
            call SaveReal(udg_RapidStrike_Hash,id,4,a+90.)
        endif
        
    else
    
        if a >= RapidStrike_StartAng() + 360. then
            call SetUnitInvulnerable(u,false)
            call PauseUnit(u,false)
            call FlushChildHashtable(udg_RapidStrike_Hash,id)
            call PauseTimer(t)
            call DestroyTimer(t)
        else
            call SaveEffectHandle(udg_RapidStrike_Hash,id,1,AddSpecialEffect(RapidStrike_TCEffPath(),x,y))
            call GroupEnumUnitsInRange(bj_lastCreatedGroup,x,y,RapidStrike_PickRadius(),null)
            loop
                set gu = FirstOfGroup(bj_lastCreatedGroup)
                exitwhen gu == null
                if not LoadBoolean(udg_RapidStrike_Hash,id,GetHandleId(gu)) and RapidStrike_IsUnitMatching(gu,u) then
                    call SaveBoolean(udg_RapidStrike_Hash,id,GetHandleId(gu),true)
                    if UnitAddAbility(gu,'Arav') then
                        call UnitRemoveAbility(gu,'Arav')
                    endif
                    call SetUnitFlyHeight(gu,RapidStrike_MaxHeight(),RapidStrike_MaxHeight()/.3)
                    set gt = CreateTimer()
                    set gtid = GetHandleId(gt)
                    call SaveUnitHandle(udg_RapidStrike_Hash,gtid,0,u)
                    call SaveUnitHandle(udg_RapidStrike_Hash,gtid,1,gu)
                    call TimerStart(gt,.2,false,function Trig_RapidStrike_FlyDown)
                    set gt = null
                endif
                call GroupRemoveUnit(bj_lastCreatedGroup,gu)
            endloop
            call SaveReal(udg_RapidStrike_Hash,id,4,a+90.)
        endif
        
    endif
    
    set soul = null
    set t = null
    set u = null
endfunction 

function Trig_RapidStrike_Actions takes nothing returns nothing
    local unit u = GetTriggerUnit()
    local timer t = CreateTimer()
    local integer id = GetHandleId(t)
    local unit soul = CreateUnit(GetOwningPlayer(u),RapidStrike_SoulId(),GetWidgetX(u),GetWidgetY(u),GetUnitFacing(u))
    
    call SetUnitPathing(soul,false)
    call SetUnitX(soul,GetWidgetX(u))
    call SetUnitY(soul,GetWidgetY(u))
    call SetUnitVertexColor(soul,50,100,200,100)
                                                  
    call SaveUnitHandle(udg_RapidStrike_Hash,id,0,u)         
    call SaveBoolean(udg_RapidStrike_Hash,id,2,false)
    call SaveReal(udg_RapidStrike_Hash,id,4,RapidStrike_StartAng())
    call SaveUnitHandle(udg_RapidStrike_Hash,id,5,soul)

    if UnitAddAbility(u,'Amrf') then
        call UnitRemoveAbility(u,'Amrf')
    endif
    
    call PauseUnit(u,true)
    call SetUnitInvulnerable(u,true)
    call SetUnitAnimation(u,"spell channel")
    call SetUnitAnimation(soul,"spell channel")
    
    call SetUnitFlyHeight(u,RapidStrike_MaxHeight(),RapidStrike_MaxHeight()/(RapidStrike_EffInt1()*2.))
    call SetUnitFlyHeight(soul,RapidStrike_SoulHeight(),RapidStrike_SoulHeight()/(RapidStrike_EffInt1()*2.))
    
    call TimerStart(t,RapidStrike_EffInt1(),true,function Trig_RapidStrike_EffTimer)
    
    set soul = null
    set t = null 
    set u = null
endfunction

//===========================================================================
function InitTrig_DeadlyStrike takes nothing returns nothing
    set udg_RapidStrike_Hash = InitHashtable()
    set gg_trg_DeadlyStrike = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ(gg_trg_DeadlyStrike,EVENT_PLAYER_UNIT_SPELL_EFFECT)
    call TriggerAddCondition(gg_trg_DeadlyStrike,Condition(function Trig_RapidStrike_Conditions))
    call TriggerAddAction(gg_trg_DeadlyStrike,function Trig_RapidStrike_Actions)
endfunction

1. Create a hashtable variable named 'RapidStrike_Hash'.
2. Copy all the Object Editor data (Dummy and the spells).
3. Copy the Spell folder and paste into your map.
4. Don't forget to credit me (bowser499) and Nasrudin (for Unholy Strike Model) if you use this spell.
5. Enjoy!

Kael summons his astral apparation that summons dark energy. After a few seconds circular lightning appears to stun nearby enemy units and deal damage to them.

Level 1 - 100 damage, 1 second stun.
Level 2 - 200 damage, 1.6 second stun.
Level 3 - 300 damage, 2.8 second stun.
Cooldown - 40 seconds


Former Kael ultimate from my Oasis and Desert project.

Don't forget to credit me (bowser499) for creating the spell and Nasrudin (for Unholy Strike Model) if you use this spell.

v1.1: Removed all the messy code, now consist some configure constants.
v1.2: Removed some leaks, made the code a little bit faster.
v1.3: Fixed more leaks, added custom functions - the code looks better now and it's even faster than it was.
v1.4: Made changes requested by Bribe.
v1.5: Made more changes requested by Bribe, optimized the code once again.
v1.6: Astral apparation visual added.

Keywords:
kael, astral, summon, deadly, strike, spell, fly
Contents

Deadly Strike (Map)

Reviews
23 Feb 2012 Bribe: Looks nice, code is clean and easy to read. Very good configurable functions as well. Approved 4/5 (Recommended). Required Changes Add importing instructions to the map (for example mention the user needs to create the...

Moderator

M

Moderator

23 Feb 2012
Bribe: Looks nice, code is clean and easy to read. Very good configurable functions as well.

Approved 4/5 (Recommended).


Required Changes
  • Add importing instructions to the map (for example mention the user needs to create the hashtable variable)
  • Change the name of your hashtable to something like DeadlyStrike_Hash. Names like "Hashtable" are not allowed because they are not specific enough.

Optional Change: Make this (highlighted text) configurable instead of hardcoded:

JASS:
if not LoadBoolean(udg_Hashtable,id,GetHandleId(gu)) @and IsUnitEnemy(gu,GetOwningPlayer(u)) and not IsUnitPaused(gu) and not IsUnitType(gu,UNIT_TYPE_DEAD) and not IsUnitType(gu,UNIT_TYPE_STRUCTURE) and not IsUnitType(gu,UNIT_TYPE_MAGIC_IMMUNE)@ then

19 Oct 2011
Bribe: Delete this line, "Custom script: set bj_lastCreatedGroup = CreateGroup()". bj_lastCreatedGroup is already set to a fresh group.

You forgot to destroy the effect in "AddSpecialEffectTimed_Timer".

== false is a useless comparison. use the keyword "not".

AddSpecialEffectTimed and its companion need to be prefixed.

You should use FirstOfGroup loops instead of a filter.

'Arav' should be configurable and initially set to 'Amrf' because that is used less commonly.

You should not create any locals unless you know for sure that the spell is the right one. Split the function into two parts, the first one checks the ability and the second one performs the actions.
 
Level 7
Joined
Oct 11, 2008
Messages
304
example of loop which you could use:

JASS:
function Trig_RapidStrike_GroupInit1 takes nothing returns nothing
    local unit u = GetTriggerUnit()
    local group array g
    local integer i = 0
    local integer ii = 1
    loop
        exitwhen i == 4
        set g[ii] = LoadGroupHandle(udg_Hashtable,GetHandleId(u),i)
        set i = i + 1
        set ii = ii + 1
    endloop
    if IsUnitInGroup(GetEnumUnit(),g[2]) or IsUnitInGroup(GetEnumUnit(),g[3]) or IsUnitInGroup(GetEnumUnit(),g[4]) then //this can be looped too
        call GroupRemoveUnit(g[1],GetEnumUnit())
    endif
    set i = 1
    loop
        exitwhen i == 4
        set i = i + 1
        set g[i] = null
    endloop
    set u = null
endfunction
 
• You didn't null "u" in the GroupFly function.
• I don't see any reason to use GetWidgetX(), simply use GetUnitX/Y().
• You can also use bj_lastCreatedGroup as your global group.
• I insist you took a look at this tutorial: http://www.hiveworkshop.com/forums/tutorial-submission-283/how-give-unit-ability-fly-201936/
JASS:
LoadBoolean(udg_Hashtable,id,GetHandleId(gu))
Instead of loading and then saving the boolean with an id that would call a function, use a static number, e.g. "0".
• I really suggest you used a jump system, instead of the built-in rate change of the SetUnitFlyHeight() function.
• Make the damage configurable per level.
 
Top