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

[Spell] How can I make stacking debuff and damage?

Status
Not open for further replies.
Level 8
Joined
May 12, 2018
Messages
106
Hi there, I am writing a script after receiving a tutorial.
I want to make the spell that deals damage and occurs debuff to a target unit, and deals damage more over and over (maybe up to 3 times) by casting the spell to the same target while debuff exists.
And when debuff is removed, the stacks becomes zero, debuff can be dispelled. ( I used Unholy Frenzy)
(Ex: Shadow Demon's Shadow Poison in DotA, Shadow Priest's Mind Spike in WoW 4.0.0 Mind Spike - Spells - Cataclysm )

Here is the script I'm writing, I've tested it, but it has problems those I don't know how to connect debuff checker and stack limitation and don't know if this clears memory leakage perfectly, and the damage stacks are never reset even if timer is expired.

JASS:
// the basic is written by zam
scope MindSpike
  globals
    private constant integer Abil0Id = 'A03D'
    private constant integer Abil1Id = 'A01A'
    private constant integer Abil2Id = 'A036'
  endglobals

  private constant function Damage takes integer AbilLv0, integer AbilLv1 returns real
    return ( 55.0 + ( 41.25 * ( AbilLv0 - 1 ) ) ) * ( 1 + ( AbilLv1 * 0.33 ) )
  endfunction

  private function MindSpikeEnd takes nothing returns nothing
    local timer t = GetExpiredTimer()
    set udg_MindSpikeStack[GetUnitUserData(LoadUnitHandle(udg_SpellsHash, GetHandleId(t), 0 ) )] = 0
    call RemoveSavedHandle( udg_SpellsHash, GetHandleId(t), 0 )
    set t = null
  endfunction

  private function Conditions takes nothing returns boolean
    return GetSpellAbilityId() == Abil0Id
  endfunction

  private function Actions takes nothing returns nothing
    local timer t = CreateTimer()
    local unit Targ = GetSpellTargetUnit()
    local unit Cast= GetSpellAbilityUnit()
    local real dam = Damage(GetUnitAbilityLevelSwapped( Abil1Id, Cast ), GetUnitAbilityLevelSwapped(Abil2Id, Cast ) )
    call SaveUnitHandle(udg_SpellsHash, GetHandleId(t), 0, Targ)
    set udg_MindSpikeStack[GetUnitUserData(Targ)] = ( udg_MindSpikeStack[GetUnitUserData(Targ)] + 1 )
    call UnitDamageTarget( Cast, Targ, dam * udg_MindSpikeStack[GetUnitUserData(Targ)], false, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_MAGIC , WEAPON_TYPE_WHOKNOWS )
    if ( IsUnitType(Targ, UNIT_TYPE_RESISTANT) == true ) then
      call TimerStart(t, 5, false, function MindSpikeEnd)
    else
      call TimerStart(t, 10, false, function MindSpikeEnd)
    endif
    set Targ = null
    set Cast = null
    set t = null
  endfunction


//===========================================================================
function InitTrig_ShadowformMindSpikeC takes nothing returns nothing
    set gg_trg_ShadowformMindSpikeC = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( gg_trg_ShadowformMindSpikeC, EVENT_PLAYER_UNIT_SPELL_EFFECT )
    call TriggerAddCondition( gg_trg_ShadowformMindSpikeC, Condition( function Conditions ) )
    call TriggerAddAction( gg_trg_ShadowformMindSpikeC, function Actions )
endfunction

endscope
 
Last edited:

Uncle

Warcraft Moderator
Level 64
Joined
Aug 10, 2018
Messages
6,557
Quenching mod is purely visual as far as I know.

It looks like the MindSpikeStacks should reset to 0 when the timer ends. Maybe you mistyped something.

Anyway, you would have to periodically check the state of the target and see if it has the buff or not. When it loses the buff, reset the stacks and destroy it's timers.

The leaks look all accounted for.
 
Level 8
Joined
May 12, 2018
Messages
106
Here's the script I rewrote with TimerUtils() library.
But I still don't know how to use hashtable correctly.
I guess both Caster and Target should be stored in Hashtable, because I don't want different Casters having the same damage amplification effect to the same target..

JASS:
scope MindSpike

  globals
    private constant integer Abil0Id = 'A03D'
    private constant integer Abil1Id = 'A01A'
    private constant integer Abil2Id = 'A036'
    private constant integer BuffId = 'B01B'
    private constant real    Period = 0.5
  endglobals

  private constant function Damage takes integer AbilLv0, integer AbilLv1 returns real
    return ( 55.0 + ( 41.25 * ( AbilLv0 - 1 ) ) ) * ( 1 + ( AbilLv1 * 0.33 ) )
  endfunction

  private struct Data
    unit Cast
    unit Targ
    boolean HasBuff = false
    real counter
    static method create takes unit c, unit t returns Data
      local Data D = Data.allocate()
      set D.Cast = c
      set D.Targ = t
      set D.counter = 0.
      return D
    endmethod
    method onDestroy takes nothing returns nothing
      set .HasBuff = false
    endmethod
  endstruct

  private function Loop takes nothing returns nothing
    local timer t = GetExpiredTimer()
    local Data D = Data( GetTimerData(t) )
    local real Dur

    if IsUnitType(D.Targ, UNIT_TYPE_RESISTANT) == true then
      set Dur = 5.1
    else
      set Dur = 10.1
    endif
    if not D.HasBuff and GetUnitAbilityLevel( D.Targ, BuffId ) > 0 then
      set D.HasBuff = true
    endif
    if D.HasBuff and GetUnitAbilityLevel( D.Targ, BuffId ) > 0 then
      set D.counter = D.counter + Period
    endif
    if D.HasBuff and ( D.counter > Dur or GetUnitAbilityLevel( D.Targ, BuffId ) < 1 or GetUnitTypeId(D.Targ) == 0  ) or ( IsUnitType(D.Targ, UNIT_TYPE_DEAD) == true ) then
      call D.destroy()
      call ReleaseTimer(t)
    endif 

    set t = null
  endfunction   

  private function Actions takes nothing returns nothing
    local unit Cast = GetSpellAbilityUnit()
    local unit Targ = GetSpellTargetUnit()
    local Data D = Data.create( Cast, Targ )
    local timer t = CreateTimer()
    local real dam = Damage(GetUnitAbilityLevelSwapped( Abil1Id, Cast ), GetUnitAbilityLevelSwapped(Abil2Id, Cast ) )
    call SetTimerData( t, integer(D) )
    call TimerStart ( t, Period, true, function Loop )
    set t = null
    set Cast = null
    set Targ = null
  endfunction

  private function Conditions takes nothing returns boolean
    return GetSpellAbilityId() == Abil0Id
  endfunction

//===========================================================================
  function InitTrig_ShadowformMindSpike takes nothing returns nothing
    set gg_trg_ShadowformMindSpike = CreateTrigger(  )
    call TriggerAddCondition( gg_trg_ShadowformMindSpike, Condition ( function Conditions ) )
    call TriggerAddAction( gg_trg_ShadowformMindSpike, function Actions )
  endfunction

endscope
 
Status
Not open for further replies.
Top