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

Stigma System 2.01 by Adiktuz

Basically it is a Damage over time system that deals damage based on a percentage of the life points missing from the target. If you play DotA, you can think of it as a DoT reaper scythe. I've also included a linear one which increases damage every interval and can be used as a normal DoT by setting increment to 0.

This system is flexible meaning you can configure almost anything using a single function call. (damage, interval, max duration, buff effect, damage effect etc)

Also you can use both systems without causing errors.

How to use in at the top of the library

CODES

JASS:
/*Stigma System by Adiktuz
  Version 2.01

  Requires:
  
  T32 - http://www.thehelper.net/forums/showthread.php/132538-Timer32
  Table - http://www.hiveworkshop.com/forums/jass-resources-412/snippet-new-table-188084/
  
    Description:
        Inflicts damage every interval to the target depending of the difference between its max life and
        its current life.

        If you play DotA, you can think of this spell as a DamageOverTime reaper's scythe

        You can modify the amount of damage, total duration and damage interval with each call of the function

        You can also have multiple spells that use this library and supports multi-level spells

        System is MUI
        
        Also, the effect of Stigma can stack up on individual units if a spell using the system is casted unpon them successively.
        the stacking effect works for every spell using stigma

    How to use
    
    just call the function: 
    
        Stigma.create(unit target, unit caster, real interval, real totalduration, boolean usebuff, attacktype at, 
        damagetype dt, real percent, string buffeffect, string damageeffect, string apoint, integer abil)
    
        unit target is the unit to be afflicted by stigma
        unit caster is the unit who caused the stigma
        real interval is the interval in seconds in which the damage occurs
        real totalduration is the duration of the stigma in seconds
            For best results use reals divisible by .03
        attacktype at is the attack type of the spell
        damagetype dt is the damage type of the spell
        real percent if the multiplier of the difference between the units maxlife and its current life to be dealt as damage per interval
        string buffeffect is the effect that attaches to the unit during the duration of stigma
        string damageeffect is the effect played every damage interval
        string apoint is the attachment point of the effects
        integer abil is the rawcode of the spell
        
    If you need simpler functions:
        
        Without attacktype,damagetype and damageeffect settings:
        
            Stigma.Simple(unit target, unit caster, real interval, real totalduration,
            real percent, string buffeffect, integer abil)
            
        Further without buffeffect
        
            Stigma.Simpler(unit target, unit caster, real interval, real totalduration,
            real percent, integer abil)
            
    Registering onXX events:

        Stigma.registerDamageEvent(integer abil, code action)
            -> runs when a unit is damaged
        Stigma.registerFinishEvent(integer abil, code action)
            -> runs when an instance of the stigma linear has ended
    
        You can use Stigma_L.data to get the instance of stigma that triggered the events
*/

library Stigma requires T32, Table

    //Do not edit below this line unless you are sure of what you're doing
    
    function StigmaDamage takes unit target, real percent returns real
        return (GetUnitState(target, UNIT_STATE_MAX_LIFE) - GetWidgetLife(target))*percent
    endfunction
    
    private module init
        static method onInit takes nothing returns nothing
            set thistype.onDamageTable = Table.create()
            set thistype.onFinishTable = Table.create()
        endmethod
    endmodule
    
    struct Stigma
        static Table onDamageTable
        static Table onFinishTable
        static thistype data
        unit target
        unit caster
        real interval
        real totalduration
        real timeelapsed
        real damagetime
        attacktype at
        damagetype dt
        real percent
        string damageeffect
        effect be
        string apoint
        integer abil
        
        static method registerDamageEvent takes integer abil, code action returns nothing
            if not onDamageTable.handle.has(abil) then
                set onDamageTable.trigger[abil] = CreateTrigger()
            endif
            call TriggerAddCondition(onDamageTable.trigger[abil], Filter(action))
        endmethod
        
        static method registerFinishEvent takes integer abil, code action returns nothing
            if not onFinishTable.handle.has(abil) then
                set onFinishTable.trigger[abil] = CreateTrigger()
            endif
            call TriggerAddCondition(onFinishTable.trigger[abil], Filter(action))
        endmethod
        
        method finish takes nothing returns nothing
            set this.target = null
            set this.caster = null
            set this.at = null
            set this.dt = null
            call DestroyEffect(this.be)
            set this.be = null
            call this.deallocate()
        endmethod
        
        method periodic takes nothing returns nothing
            set this.timeelapsed = this.timeelapsed + T32_PERIOD
            set data = this
            if this.timeelapsed >= this.damagetime then
                set this.damagetime = this.damagetime + this.interval
                call UnitDamageTarget(this.caster, this.target, StigmaDamage(this.target, this.percent), false, false, this.at, this.dt, WEAPON_TYPE_WHOKNOWS )
                if onDamageTable.handle.has(this.abil) then
                    call TriggerEvaluate(onDamageTable.trigger[this.abil])
                endif
                call DestroyEffect(AddSpecialEffectTarget(this.damageeffect, this.target, this.apoint))
            endif
            if (this.timeelapsed >= this.totalduration) or (GetWidgetLife(this.target) <= .405) then
                if onFinishTable.handle.has(this.abil) then
                    call TriggerEvaluate(onFinishTable.trigger[this.abil])
                endif
                call this.stopPeriodic()
                call this.finish()
            endif
        endmethod
    
        implement T32x
        
        static method create takes unit target, unit caster, real interval, real totalduration, /*
        */attacktype at, damagetype dt, real percent, string buffeffect, string damageeffect, /*
        */string apoint, integer abil returns thistype
            local thistype stigma = .allocate()
            set stigma.caster = caster
            set stigma.target = target
            set stigma.interval = interval
            set stigma.totalduration = totalduration
            set stigma.damagetime = interval
            set stigma.at = at
            set stigma.dt = dt
            set stigma.percent = percent
            set stigma.timeelapsed = 0.00
            set stigma.be = AddSpecialEffectTarget(buffeffect, target, apoint)
            set stigma.apoint = apoint
            set stigma.damageeffect = damageeffect
            set stigma.abil = abil
            call stigma.startPeriodic()
            return stigma
        endmethod    
        
        static method simple takes unit target, unit caster, real interval, real totalduration,/*
        */real percent, string buffeffect, integer abil returns thistype
            return thistype.create(target,caster,interval,totalduration,ATTACK_TYPE_NORMAL,DAMAGE_TYPE_NORMAL,percent,buffeffect,"","origin",abil)
        endmethod
        
        static method simpler takes unit target, unit caster, real interval, real totalduration,/*
        */real percent, integer abil returns thistype
            return thistype.create(target,caster,interval,totalduration,ATTACK_TYPE_NORMAL,DAMAGE_TYPE_NORMAL,percent,"","","origin",abil)
        endmethod
        
        implement init
    endstruct
    
endlibrary


JASS:
/*Stigma System by Adiktuz
  Version 2.01 Linear

  
  Requires:
  
  T32 - http://www.thehelper.net/forums/showthread.php/132538-Timer32
  Table - http://www.hiveworkshop.com/forums/jass-resources-412/snippet-new-table-188084/
  
    Description:
        Inflicts damage every interval which increases by a set amount
        
        You can modify the amount of damage, total duration and damage interval with each call of the function

        You can also have multiple spells that use this library and supports multi-level spells

        System is MUI
        
        Also, the effect of Stigma can stack up on individual units if a spell using the system is casted unpon them successively.
        the stacking effect works for every spell using stigma

    How to use
    
    just call the function: 
    
        Stigma_L.create(unit target, unit caster, real interval, real totalduration, boolean usebuff, attacktype at, 
        damagetype dt, real base, real increment string buffeffect, string damageeffect, string apoint, integer abil)
    
        unit target is the unit to be afflicted by stigma
        unit caster is the unit who caused the stigma
        real interval is the interval in seconds in which the damage occurs
        real totalduration is the duration of the stigma in seconds
            For best results use reals divisible by .03
        attacktype at is the attack type of the spell
        damagetype dt is the damage type of the spell
        real base is the base damage of the stigma (first damage is already base + increment)
        real increment is the additional damage dealth by stigma per interval
        string buffeffect is the effect that attaches to the unit during the duration of stigma
        string damageeffect is the effect played every damage interval
        string apoint is the attachment point of the effects
        integer abil is the rawcode of the spell
        
    If you need simpler functions:
        
        Without attacktype,damagetype and damageeffect settings:
        
            Stigma_L.simple(unit target, unit caster, real interval, real totalduration,
            real base,real increment, string buffeffect, integer abil)
            
        Further without buffeffect
        
            Stigma_L.simpler(unit target, unit caster, real interval, real totalduration,
            real base,real increment, integer abil)
            
        Further without base
        
            Stigma_L.simplest(unit target, unit caster, real interval, real totalduration,
            real increment, integer abil)
            
    Registering onXX events:

        Stigma_L.registerDamageEvent(integer abil, code action)
            -> runs when a unit is damaged
        Stigma_L.registerFinishEvent(integer abil, code action)
            -> runs when an instance of the stigma linear has ended
    
        You can use Stigma_L.data to get the instance of stigma that triggered the events
*/

library StigmaLinear requires T32, Table

    //Do not edit below this line unless you are sure of what you're doing
    
    function StigmaLinearDamage takes real base, real increment returns real
        return base + increment
    endfunction
    
    private module init
        static method onInit takes nothing returns nothing
            set thistype.onDamageTable = Table.create()
            set thistype.onFinishTable = Table.create()
        endmethod
    endmodule
    
    struct Stigma_L
        static Table onDamageTable
        static Table onFinishTable
        static thistype data
        unit target
        unit caster
        real interval
        real totalduration
        real timeelapsed = 0
        real damagetime
        attacktype at
        damagetype dt
        real base
        real increment
        string damageeffect
        effect be
        string apoint
        integer abil
        
        static method registerDamageEvent takes integer abil, code action returns nothing
            if not onDamageTable.handle.has(abil) then
                set onDamageTable.trigger[abil] = CreateTrigger()
            endif
            call TriggerAddCondition(onDamageTable.trigger[abil], Filter(action))
        endmethod
        
        static method registerFinishEvent takes integer abil, code action returns nothing
            if not onFinishTable.handle.has(abil) then
                set onFinishTable.trigger[abil] = CreateTrigger()
            endif
            call TriggerAddCondition(onFinishTable.trigger[abil], Filter(action))
        endmethod
        
        method finish takes nothing returns nothing
            set this.target = null
            set this.caster = null
            set this.at = null
            set this.dt = null
            call DestroyEffect(this.be)
            set this.be = null
            call this.deallocate()
        endmethod
        
        method periodic takes nothing returns nothing
            set this.timeelapsed = this.timeelapsed + T32_PERIOD
            set data = this
            if this.timeelapsed >= this.damagetime then
                set this.damagetime = this.damagetime + this.interval
                call UnitDamageTarget(this.caster, this.target, StigmaLinearDamage(this.base, this.increment), false, false, this.at, this.dt, WEAPON_TYPE_WHOKNOWS )
                if onDamageTable.handle.has(this.abil) then
                    call TriggerEvaluate(onDamageTable.trigger[this.abil])
                endif
                set this.base = this.base + this.increment
                call DestroyEffect(AddSpecialEffectTarget(this.damageeffect, this.target, this.apoint))
            endif
            if (this.timeelapsed >= this.totalduration) or (GetWidgetLife(this.target) <= .405) then
                if onFinishTable.handle.has(this.abil) then
                    call TriggerEvaluate(onFinishTable.trigger[this.abil])
                endif
                call this.stopPeriodic()
                call this.finish()
            endif
        endmethod
        
        implement T32x
        
        static method create takes unit target, unit caster, real interval, real totalduration, /*
        */attacktype at, damagetype dt, real base, real increment, string buffeffect, /*
        */string damageeffect, string apoint, integer abil returns thistype
            local thistype stigma = .allocate()
            set stigma.caster = caster
            set stigma.target = target
            set stigma.interval = interval
            set stigma.totalduration = totalduration
            set stigma.damagetime = interval
            set stigma.at = at
            set stigma.dt = dt
            set stigma.base = base
            set stigma.increment = increment
            set stigma.be = AddSpecialEffectTarget(buffeffect, target, apoint)
            set stigma.apoint = apoint
            set stigma.damageeffect = damageeffect
            set stigma.abil = abil
            call stigma.startPeriodic()
            return stigma
        endmethod
        
        static method simple takes unit target, unit caster, real interval, real totalduration,/*
        */real base,real increment, string buffeffect,integer abil returns thistype
            return thistype.create(target,caster,interval,totalduration,ATTACK_TYPE_NORMAL,DAMAGE_TYPE_NORMAL,base,increment,buffeffect,"","origin",abil)
        endmethod
        
        static method simpler takes unit target, unit caster, real interval, real totalduration,/*
        */real base,real increment, integer abil returns thistype
            return thistype.create(target,caster,interval,totalduration,ATTACK_TYPE_NORMAL,DAMAGE_TYPE_NORMAL,base,increment,"","","origin",abil)
        endmethod
        
        static method simplest takes unit target, unit caster, real interval, real totalduration,/*
        */real increment, integer abil returns thistype
            return thistype.create(target,caster,interval,totalduration,ATTACK_TYPE_NORMAL,DAMAGE_TYPE_NORMAL,increment,increment,"","","origin",abil)
        endmethod
        
        implement init
    endstruct
    
endlibrary



1.1 - Made the system run on T32, and added onDamage and onFinish interface methods
- also removed the usebuff parameter for now...
2.01 - Remade how damage and finish events are handled


Credits:
Jesus4Lyf -> T32 - http://www.thehelper.net/forums/showthread.php/132538-Timer32
Bribe -> Table - http://www.hiveworkshop.com/forums/jass-resources-412/snippet-new-table-188084/


Keywords:
damage, vjass, jass, system, life, over time, reaper scythe,
Contents

Stigma v 2.01 (Map)

Reviews
09:47, 17th Jun 2010 The_Reborn_Devil: The coding looks good, but you don't need WEAPON_TYPE_WHOKNOWS as the value of that constant is null, so just put null there. You should also point out that //DNE means Do Not Edit (it might have a different...

Moderator

M

Moderator

09:47, 17th Jun 2010
The_Reborn_Devil:

The coding looks good, but you don't need WEAPON_TYPE_WHOKNOWS as the value of that constant is null, so just put null there. You should also point out that //DNE means Do Not Edit (it might have a different meaning, I dunno, but that makes sense). Anyway, it seems to be in good enough shape for approval. Easy to use for GUI users too.


Status: Approved
Rating: Recommended
 
Level 13
Joined
Jul 26, 2008
Messages
1,009
You know, I've become confused on what method is best:

GetWidgetLife(u) >= 0.405
IsUnitAlive native
IsUnitType(u, UNIT_TYPE_DEAD)

I've heard since dead units can have life manipulated the first one isn't the safest though it is the fastest. The native has some odd issues, can't remember. And IsUnitType(u, UNIT_TYPE_DEAD) is slow. So which is the best?

Also couldn't you use a global private constant real to set the timer interval so it can easily be adjusted?

JASS:
global
    private constant real TICK = 0.03
endglobals

Then replace the 0.03's in the map with tick.
It's pretty cool, but I think the post prior to this are right. It is too static to be a public resource. There's not much you can adjust with this, only set up.
 
I think the effect should be no constant but a struct member and editable per instance. Same goes for the buff etc. I think the system is way to static to be approved. Also we already have enough dot system.

the effect isnt a constant (I just forgot to remove the global at the linear stigma library and if you read the whole library you can see that it uses a parameter for the effects) one as well as the buff special effect... you can change it per function call...

if ur talking about the main buff (aura) it is just optional, I just added it because I used channel as a base spell and I cant add a buff directly to the channel spell, it does not work... anyway the BUFF is optional...


You know, I've become confused on what method is best:

GetWidgetLife(u) >= 0.405
IsUnitAlive native
IsUnitType(u, UNIT_TYPE_DEAD)

I've heard since dead units can have life manipulated the first one isn't the safest though it is the fastest. The native has some odd issues, can't remember. And IsUnitType(u, UNIT_TYPE_DEAD) is slow. So which is the best?

Also couldn't you use a global private constant real to set the timer interval so it can easily be adjusted?

JASS:
global
    private constant real TICK = 0.03
endglobals

Then replace the 0.03's in the map with tick.
It's pretty cool, but I think the post prior to this are right. It is too static to be a public resource. There's not much you can adjust with this, only set up.

I'm not sure whats the best method for checking if a unit is dead...
I use .03 because it works pretty good for this because if you set the timer interval to a high value it can cause bugs since I'm just using one timer for all instances...

I only thought for it to be a simple DoT reaper scythe style but I thought that making it as a system is better... ^^

and yeah, its really simple and as you say static...

EDIT: Thinking of updating this, adding an auto calculate feature with the Stigma Linear. Meaning you just put the max damage it should deal, the total duration plus the damage intervals and it will automatically calculate the damage per interval... This would be an added new start function in the StigmaLinear which means you can still use the current method...
 
Level 20
Joined
Jul 14, 2011
Messages
3,213
Hey Adiktuz, I may implement this on my map also. Can I use it to heal over time based on stat? aso dmg over time based on stats? MUI?
 
Top