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

DamageOverTime(DOT) 1.7

This system allows you to damage a unit over time. You can deal, lets say 200 damage over 0.7 secconds if you want to.

This system is not a "Damage After Time", but a Damage Over Time.

System requires JassNewGenPack

Fixes
  • v1.0 - Release
  • v1.1 - Fixed a minior bug
  • v1.2 - Added the manual
  • v1.3 - Minior Fixing
  • v1.4 - Last fixes thanks to Dr Super Good
  • v1.5 - Added one more comment + Added one more test.
  • v1.6 - Scripted the code all over again, now more effective :D
  • v1.7 - After a long time I'm finaly reuploading this after it got deleted, and I've redone the whole ting. More efficient than ever.
Please, if any bugs or ways of improvement is found. Please post. Thx

JASS:
// o o o o o o o o o o o o o o o o o o o o o o o
// o Damage Over Time by Dynasti o Version 1.7 o
// o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o
// o                                                      How To Implement                                                   o
// o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o
// o                                                                                                                         o
// o    1. - Make sure that you opened the system in the newest version of JNGP                                              o
// o    2. - Copy this trigger into you map                                                                                  o
// o                                                                                                                         o
// o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o
// o                                                      How to Use                                                         o
// o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o
// o                                                                                                                         o
// o    - This system requires you to give 8 variables for it to function perfectly.                                         o
// o        Variables are:                                                                                                   o
// o            1. - A unit that does the damage, lets call it " A "                                                         o
// o            2. - A widget that is given the damage, lets call it " B "                                                   o
// o            3. - A real value that is the damage, lets call it " D "                                                     o
// o            4. - A real value that is the time it takes to do the damage, lets call it " T "                             o
// o            5. - An attacktype that is used to regulate the damage, lets call it " AT "                                  o
// o            6. - A damagetype that is used to regulate the damage, lets call it " DT "                                   o
// o            7. - A string that is the model of the period effect, lets call it " EX "                                    o
// o            8. - A string that is the attachment for the " EX " string, lets call it " ExAttach "                        o
// o                                                                                                                         o
// o        The call:                                                                                                        o
// o            call DamageOverTimeEx( A , B , D , T , AT , DT , EX , ExAttach )                                             o
// o            you have now succesfully called the function and started the damage over time.                               o
// o                                                                                                                         o
// o            if you want something simpler and not have the effect do this:                                               o
// o                call DamageOverTime( A , B , D , T , AT , DT )                                                           o
// o            now you have done the simpler call.                                                                          o
// o                                                                                                                         o
// o        Tips:                                                                                                            o
// o            To not make the target " B " run away or run after you, do this:                                             o
// o                call DamageOverTimeEx( B , B , D , T , AT , DT , EX , ExAttach )                                         o
// o            Or for the simpler call:                                                                                     o
// o                call DamageOverTime( B , B , D , T , AT , DT )                                                           o
// o                                                                                                                         o
// o            What we now have done is set the unit that does the damage to the unit that takes the damage, " B ".         o
// o            This does so that the unit " B " does damage to itself and will not run away or attack any unit.             o
// o                NB: Damaging itself will result to bounty for the own dying unit or, no bounty at all for the killer.    o
// o                                                                                                                         o
// o                                                                                                                         o
// o        If for any reason you want to cancel you need to save the DOT struct as a variable in whatever you're using.     o
// o                                                                                                                         o
// o        First, you need to have the DOT struct variable stored as some integer to cancel a DOT.                          o
// o        Example:                                                                                                         o
// o        [...]                                                                                                            o
// o            set SomeInteger = DamageOverTime(A, B, D, T, AT, DT, EX, ExAttach)                                           o
// o                                                                                                                         o
// o            Since function DamageOverTimeEx or DamageOverTime returns the struct to you, you can store it for later use  o
// o                IMPORTANT!: If you do the stopcall after the DoT has stopped you might screw up things. To do this, you  o
// o                            can use the "check" function to check if the struct value you have stored is running and to  o
// o                            what unit.                                                                                   o
// o                                                                                                                         o 
// o        The "Check" function:                                                                                            o
// o            the function "IsDamageRunning takes DOT dat returns unit" will return 'null' as a value if the struct isn't  o
// o            running, and will return a unit handle if the struct is running. But wait, you might be thinking:            o
// o            What if it is another unit than the unit I started it with?! Well do this:                                   o
// o                [...]                                                                                                    o
// o                    if MyUnitVariable == IsDamageRunning(StructVariable) then                                            o
// o                        [your actions here]                                                                              o
// o                        call EndDamageOverTime(StructVariable)                                                           o
// o                    else                                                                                                 o
// o                        set StructVariable = 0                                                                           o
// o                    endif                                                                                                o
// o                                                                                                                         o
// o                By doing this, it will insure you that you won't accedently end another unit's DOT effect                o
// o                                                                                                                         o
// o                                                                                                                         o
// o    - For more info go to: www.HiveWorkshop.com or visit www.Ngo.clan.su , user at both sites are Dynasti                o
// o                                                                                                                         o
// o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o
library DOT initializer Init

    globals
        private constant integer FPS = 40 // This is how many times the struct loop will run in a single second. 30-40 is recomended
        
        // DO NOT TUCH! =)
        private constant real Interval = (1.0 / FPS)
    endglobals
    
    private struct DOT
        unit Attacker
        widget Target

        real Damage
        integer EndCount

        attacktype AttackType
        damagetype DamageType
        
        effect Effect
        
        static integer array Index
        static integer Total = 0
        
        static timer Tim = null
        
        static integer Count = -2147483648 // Just a random low number, it is needed
        
        static method Loop takes nothing returns nothing
            local DOT dat
            local integer i = 0

            set DOT.Count = DOT.Count + 1
            
            loop
                exitwhen i >= DOT.Total
                set dat = DOT.Index[i]
                
                if DOT.Count > dat.EndCount or GetWidgetLife(dat.Target) <= .405 then
                    call DestroyEffect(dat.Effect)

                    set dat.Effect     = null
                    set dat.Attacker   = null
                    set dat.Target     = null
                    set dat.AttackType = null
                    set dat.DamageType = null
            
                    call dat.destroy()
                    
                    set DOT.Total = DOT.Total - 1
                    set DOT.Index[i] = DOT.Index[DOT.Total]

                    set i = i - 1
                else
                    call UnitDamageTarget(dat.Attacker, dat.Target, dat.Damage, false, false, dat.AttackType, dat.DamageType, null)
                endif
                
                set i = i + 1
            endloop
            
            if DOT.Total == 0 then
                call PauseTimer(DOT.Tim)
            endif
        endmethod
        
        static method Start takes unit Attacker, widget Target, real Damage, real Time, attacktype AttackType, damagetype DamageType, string Effect, string EffectAttach returns DOT
            local DOT dat = DOT.allocate()
            
            set dat.Attacker   = Attacker
            set dat.Target     = Target
            set dat.AttackType = AttackType
            set dat.DamageType = DamageType
            
            if Effect != "" and Effect != null then
                if EffectAttach != "" and EffectAttach != null then
                    set dat.Effect = AddSpecialEffectTarget(Effect, Target, EffectAttach)
                endif
            endif
            
            set dat.Damage   = Damage * Interval / Time
            set dat.EndCount = DOT.Count + R2I(Time / Interval)
            
            if DOT.Total == 0 then
                call TimerStart(DOT.Tim, Interval, true, function DOT.Loop)
            endif
            
            set DOT.Index[DOT.Total] = dat
            set DOT.Total = DOT.Total + 1
            
            return dat
        endmethod
    endstruct
    
//=========================================================================================
    
    function DamageOverTimeEx takes unit Attacker, widget Target, real Damage, real Time, attacktype AttackType, damagetype DamageType, string Effect, string EffectAttach returns DOT
        return DOT.Start(Attacker, Target, Damage, Time, AttackType, DamageType, Effect, EffectAttach)
    endfunction
    
    function DamageOverTime takes unit Attacker, widget Target, real Damage, real Time, attacktype AttackType, damagetype DamageType returns DOT
        return DOT.Start(Attacker, Target, Damage, Time, AttackType, DamageType, "", "")
    endfunction
    
    function EndDamageOverTime takes DOT dat returns nothing
        set dat.EndCount = DOT.Count + 1
    endfunction
    
    function IsDamageRunning takes DOT dat returns unit
        return dat.Target
    endfunction
    
//=========================================================================================

    private function Init takes nothing returns nothing
        set DOT.Tim = CreateTimer()
    endfunction

endlibrary
JASS:
library DOT initializer Init // Function 'Init' will be run at map start

    globals
        private constant integer FPS = 40 // This is how many times the struct loop will run in a single second. 30-40 is recomended
        
        // DO NOT TUCH! =)
        private constant real Interval = (1.0 / FPS)
    endglobals
    
    private struct DOT
        unit Attacker // The unit that will deal damage to the target
        widget Target // The unit that will be dealt damage to by the Attacker

        real Damage // Used for storing the damage value for each tick
        integer EndCount // Used for knowing when the dot will stop

        attacktype AttackType // Attack Type of the damage 
        damagetype DamageType // Damage type of the damage dealt
        
        effect Effect // The effect that will stick to the unit for the duration
        
        static integer array Index // Used for indexing system
        static integer Total = 0 // Used for indexing system
        
        static timer Tim = null // Timer for the loop
        
        static integer Count = -2147483648 // Just a random low number, it is needed. I used for indexing system
        
        static method Loop takes nothing returns nothing // Loop method
            local DOT dat // Localizing the struct
            local integer i = 0 // Integer used for the loop

            set DOT.Count = DOT.Count + 1 // Adding 1 more to the counter. The counter is made that when the count
                                          // that is stored in the struct is larger than the Struct count, the DOT is finished.
            
            loop // Loop
                exitwhen i >= DOT.Total // If there is no structs need to be run, loop will end
                set dat = DOT.Index[i] // Indexing
                
                if DOT.Count > dat.EndCount or GetWidgetLife(dat.Target) <= .405 then // If the DOT's time is over or the target is dead,
                                                                                      //it will end the DOT period
                    call DestroyEffect(dat.Effect)

                    set dat.Effect     = null
                    set dat.Attacker   = null
                    set dat.Target     = null
                    set dat.AttackType = null
                    set dat.DamageType = null
            
                    call dat.destroy()
                    
                    set DOT.Total = DOT.Total - 1
                    set DOT.Index[i] = DOT.Index[DOT.Total]

                    set i = i - 1
                else // Else if the target is alive and DOT's time isn't done, it will deal damage
                    call UnitDamageTarget(dat.Attacker, dat.Target, dat.Damage, false, false, dat.AttackType, dat.DamageType, null)
                endif
                
                set i = i + 1 // Couning the loop
            endloop
            
            if DOT.Total == 0 then // If there is no more structs left, the timer will pause
                call PauseTimer(DOT.Tim)
            endif
        endmethod // End of loop methond
        
        static method Start takes unit Attacker, widget Target, real Damage, real Time, attacktype AttackType, damagetype DamageType, string Effect, string EffectAttach returns DOT // The start method
            local DOT dat = DOT.allocate() // Allocating a new struct value
            
            // Storing the variables
            set dat.Attacker   = Attacker
            set dat.Target     = Target
            set dat.AttackType = AttackType
            set dat.DamageType = DamageType
            //======================
            
            if Effect != "" and Effect != null then // If no effect is asked for, it will not store it
                if EffectAttach != "" and EffectAttach != null then // This is done for efficency tasks, if effect is not asked for, it will not checked if attach is asked for.
                    set dat.Effect = AddSpecialEffectTarget(Effect, Target, EffectAttach)
                endif
            endif
            
            set dat.Damage   = Damage * Interval / Time // Calucating the damage that needs to be done each loop
            set dat.EndCount = DOT.Count + R2I(Time / Interval) // Calculating the DOT's time
            
            if DOT.Total == 0 then // If there is no other structs running the timer is paused, so it needs to be started again
                call TimerStart(DOT.Tim, Interval, true, function DOT.Loop)
            endif
            
            set DOT.Index[DOT.Total] = dat // Indexing
            set DOT.Total = DOT.Total + 1 // Indexing
            
            return dat
        endmethod
    endstruct
    
//=========================================================================================
    
    // The function for DOT with effect
    function DamageOverTimeEx takes unit Attacker, widget Target, real Damage, real Time, attacktype AttackType, damagetype DamageType, string Effect, string EffectAttach returns DOT
        return DOT.Start(Attacker, Target, Damage, Time, AttackType, DamageType, Effect, EffectAttach)
    endfunction
    
    // The easier function for DOT with no effect
    function DamageOverTime takes unit Attacker, widget Target, real Damage, real Time, attacktype AttackType, damagetype DamageType returns DOT
        return DOT.Start(Attacker, Target, Damage, Time, AttackType, DamageType, "", "")
    endfunction
    
    // Function for stopping a DOT
    function EndDamageOverTime takes DOT dat returns nothing
        set dat.EndCount = DOT.Count + 1
    endfunction
    
    // Function for checkign if the struct is running, will return 'null' if not, else it will return a unit handle
    function IsDamageRunning takes DOT dat returns unit
        return dat.Target
    endfunction
    
//=========================================================================================

    private function Init takes nothing returns nothing // Creating the timer
        set DOT.Tim = CreateTimer()
    endfunction

endlibrary

IMPORTANT. MAP ISN'T COMPILED ATM TO THE NEWEST VERSION BECAUSE I'M A FUCKNUT AND HAVE NO CLUE HOW TO FIX MY vJASS EDITOR. HELP IS APPRECIATED.

code still works tho, just not map. Will fix asap
Contents

DOT By Dynasti (Map)

Reviews
15:36, 6th Mar 2010 The_Reborn_Devil: It's a pretty neat and useful system. Easy to use and well documented. Status: Approved Rating: Recommended

Moderator

M

Moderator

15:36, 6th Mar 2010
The_Reborn_Devil:
It's a pretty neat and useful system. Easy to use and well documented.


Status: Approved
Rating: Recommended
 
Well thats what a good, efficient, etc. system should be like...
full review will follow...
BUT one question:
you did this:
JASS:
    private struct DOT
            ...
        static timer Tim = null
            ...
    endstruct
            ...
    private function Init takes nothing returns nothing
        set DOT.Tim = CreateTimer()
    endfunction

But why?? couldn't it be this too (which is much shorter)??:
JASS:
    private struct DOT
            ...
        static timer Tim = CreateTimer()
            ...
    endstruct
            ...
 
Level 18
Joined
Oct 18, 2007
Messages
930
Well due to the fact that this has been known to cause bugs. Atleast in the older versions of vJass. I'm on the safe side, and it has nothing to do with efficiency. It runs at the beginning of the map ( when it's loading). 1/10000 of a second faster? No one will notice. :)
 
Well due to the fact that this has been known to cause bugs. Atleast in the older versions of vJass. I'm on the safe side, and it has nothing to do with efficiency. It runs at the beginning of the map ( when it's loading). 1/10000 of a second faster? No one will notice. :)

sry i didn't want to offend you ;D

i just wanted to maybe learn something new, as i did because of your fast answer;D
 
Level 18
Joined
Oct 18, 2007
Messages
930
Update test-map please so we can see an example of its use.

He's right!! Your map can't be opened in Warcraft (it can in WE)...

but the code you posted here seems all right...

please fix that!!

I quote myself in the first post:

Dynasti said:
IMPORTANT. MAP ISN'T COMPILED ATM TO THE NEWEST VERSION BECAUSE I'M A FUCKNUT AND HAVE NO CLUE HOW TO FIX MY vJASS EDITOR. HELP IS APPRECIATED.

code still works tho, just not map. Will fix asap
 
Level 9
Joined
Aug 2, 2008
Messages
219
Interesting problem you have there. I´ve been doing some debugging with your code and i found something out. When i tested the map without anything changed wc3 directed my to the main menu as the other reported too.
I figured out that the functions DamageOverTimeEx, DamageOverTime, EndDamageOverTime and IsDamageRunning are somehow causing this malfunction.
When i removed them and replaced their calls in the demo triggers with the .start method of the struct everything worked fine.

Im attatching the changed map so others can tell if this generally works or just for me.
~TNT
 

Attachments

  • DOT - Damage Over Time by Dynasti (FIXED).w3x
    40.7 KB · Views: 141
By the way, this crashes on load because of this function:
JASS:
    function IsDamageRunning takes DOT dat returns unit
        return dat.Target
    endfunction

It seems fine at first, but look at this:
JASS:
    private struct DOT
        unit Attacker
        widget Target

Widget. It can't convert the widget to a unit so it crashes. =)

You can change the returns unit to returns widget, or change the parameter to take a unit and change the struct member, or whatever is best. But anyway, that's the cause for your crash.

Also, you don't need to null struct members, since they are globals (they don't cause reference leaks like locals do). =)

Nice system otherwise.
 
Top