• 💀 Happy Halloween! 💀 It's time to vote for the best terrain! Check out the entries to Hive's HD Terrain Contest #2 - Vampire Folklore.❗️Poll closes on November 14, 2023. 🔗Click here to cast your vote!
  • 🏆 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!
  • 🏆 HD Level Design Contest #1 is OPEN! Contestants must create a maze with at least one entry point, and at least one exit point. The map should be made in HD mode, and should not be openable in SD. Only custom models from Hive's HD model and texture sections are allowed. The only exceptions are DNC models and omnilights. This is mainly a visual and design oriented contest, not technical. The UI and video walkthrough rules are there to give everyone an equal shot at victory by standardizing how viewers see the terrain. 🔗Click here to enter!

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

Status
Not open for further replies.
Level 6
Joined
May 12, 2018
Messages
79
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 58
Joined
Aug 10, 2018
Messages
5,847
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 6
Joined
May 12, 2018
Messages
79
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