• Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
  • Read Evilhog's interview with Gregory Alper, the original composer of the music for WarCraft: Orcs & Humans 🔗Click here to read the full interview.
  • The Hive's 22nd Icon Contest: Creep Abilities is now concluded, time to vote for your favourite set of icons! Click here to vote!
  • ✅ The POLL for Hive's Texturing Contest #34 is OPEN! Vote for the TOP 3 SKINS! 🔗Click here to cast your vote!
  • ✅ The POLL for Hive's Techtree Contest #20 is OPEN! Vote for the TOP 3 FACTIONS! 🔗Click here to cast your vote!

[Spell] [Solved] How to apply a 'BUFF' to a unit which is affected by the spell?

Level 7
Joined
Nov 3, 2015
Messages
81
Hey. This is driving me nuts. I've got a Windwalk spell. When the caster attacks a unit, bonus damage is applied on the first attack + an armor reduction on the target. But I want a buff to appear at the status bar for the debuffed unit.

A0F1 (armor debuff) and B056.
1765721061931.png
1765721089055.png


Windwalk active:
1765720662074.png


Attacked the spider, and armor is properly reduced. But no buff is visible in the status bar.
1765720961753.png


The spell.
vJASS:
scope Nightrunner

globals
    private constant integer ID      = 'AOwk' //Windwalk
    private constant integer BUFFID  = 'B03S' //Buff on caster
    private constant integer ARMORID = 'A0F1' //Armor reduction ability

    private constant real WINDOW = 0.50
    private constant real DUR    = 10.00

    private hashtable ht = null
endglobals

private function WindowExpire takes nothing returns nothing
    local timer w = GetExpiredTimer()
    local integer wid = GetHandleId(w)
    local unit tgt = LoadUnitHandle(ht, wid, 0)
    local integer uid

    if tgt != null then
        set uid = GetHandleId(tgt)
        call SaveBoolean(ht, uid, 2, false)
        call RemoveSavedHandle(ht, uid, 0)
    endif

    call FlushChildHashtable(ht, wid)
    call DestroyTimer(w)

    set tgt = null
    set w = null
endfunction

private function MarkWindow takes unit tgt returns nothing
    local integer uid = GetHandleId(tgt)
    local timer w = LoadTimerHandle(ht, uid, 0)

    call SaveBoolean(ht, uid, 2, true)

    if w == null then
        set w = CreateTimer()
        call SaveTimerHandle(ht, uid, 0, w)
        call SaveUnitHandle(ht, GetHandleId(w), 0, tgt)
    endif

    call TimerStart(w, WINDOW, false, function WindowExpire)

    set w = null
endfunction

private function ConsumeWindow takes unit tgt returns nothing
    local integer uid = GetHandleId(tgt)
    local timer w = LoadTimerHandle(ht, uid, 0)

    call SaveBoolean(ht, uid, 2, false)

    if w != null then
        call FlushChildHashtable(ht, GetHandleId(w))
        call DestroyTimer(w)
        call RemoveSavedHandle(ht, uid, 0)
    endif

    set w = null
endfunction

private function DebuffExpire takes nothing returns nothing
    local timer t = GetExpiredTimer()
    local integer tid = GetHandleId(t)
    local unit tgt = LoadUnitHandle(ht, tid, 0)
    local integer uid

    if tgt != null then
        call UnitRemoveAbility(tgt, ARMORID)
        set uid = GetHandleId(tgt)
        call RemoveSavedHandle(ht, uid, 1)
    endif

    call FlushChildHashtable(ht, tid)
    call DestroyTimer(t)

    set tgt = null
    set t = null
endfunction

private function ApplyDebuff takes unit tgt, integer lvl returns nothing
    local integer uid = GetHandleId(tgt)
    local timer t = LoadTimerHandle(ht, uid, 1)

    if t == null then
        set t = CreateTimer()
        call SaveTimerHandle(ht, uid, 1, t)
        call SaveUnitHandle(ht, GetHandleId(t), 0, tgt)
    endif

    call UnitAddAbility(tgt, ARMORID)
    if lvl < 1 then
        set lvl = 1
    endif
    call SetUnitAbilityLevel(tgt, ARMORID, lvl)

    call TimerStart(t, DUR, false, function DebuffExpire)

    set t = null
endfunction


private function OnAttacked takes nothing returns boolean
    local unit attacker = GetAttacker()
    if GetUnitAbilityLevel(attacker, BUFFID) > 0 then
        call MarkWindow(GetTriggerUnit())
    endif
    set attacker = null
    return false
endfunction

private function OnDamaged takes nothing returns boolean
    local unit tgt = GetTriggerUnit()
    local integer uid = GetHandleId(tgt)
    local unit src
    local integer lvl

    if LoadBoolean(ht, uid, 2) and GetEventDamage() > 5.00 then
        set src = GetEventDamageSource()
        set lvl = GetUnitAbilityLevel(src, ID)

        if lvl > 0 then
            call ConsumeWindow(tgt)
            call ApplyDebuff(tgt, lvl)
        endif

        set src = null
    endif

    set tgt = null
    return false
endfunction

function TriggerStartNightRunner takes nothing returns nothing
    local trigger t

    if ht == null then
        set ht = InitHashtable()
    endif

    set t = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_ATTACKED)
    call TriggerAddCondition(t, Condition(function OnAttacked))

    set t = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_DAMAGED)
    call TriggerAddCondition(t, Condition(function OnDamaged))

    set t = null
endfunction

endscope
 

Attachments

  • 1765720858360.png
    1765720858360.png
    1 MB · Views: 34
Make an ability based on Item corruption (it doesn't display in the command card), when your hero uses Windwalk you give them the ability, and remove it whenever they deal normal damage to an unit
You'd also need to remove it after X seconds if the hero hasn't attacked anything during the windwalk
Simple and perfect. Thank you.
 
Back
Top