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

Doit v3.00

This bundle is marked as useful / simple. Simplicity is bliss, low effort and/or may contain minor bugs.
A damage / healing over time system with a few unique features: can refresh, stack damage, refresh and stack, stack damage with any remaining damage from previous instances, refresh and stack that damage. Can do the same thing with healing over time.
This system also has "events" which run each time an instance occurs and allow you to modify every variable containing data for each instance.

This is an improved version of http://www.hiveworkshop.com / forums / spells - 569 / dot - damage - over - interval - time - v3 - 229931 / however i am uploading this separately because i want the simpler recourse to exist as an alternative.

code:

JASS:
library DamageOverIntervalTime initializer Init /* v 3.00 by Gorillabul
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 
 * A damage / healing over time system capable of: dealing damage / healing over time, refreshing, stacking, stacking and refreshing, stacking the new damage
 * with any remainder of the damage from the previous instance, refreshing that damage, stacking and refreshing that damage.
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 
 */ 
globals
	private unit array doitDamager //The Unit dealing the damage.
	private unit array doitTarget // The target Unit
	private real array doitDamage //Amount of damage PER INTERVAL
	private integer array doitCounting
	private integer array doitRecycler
	private integer array doitPrev
	private integer array doitNext
	private integer array doitIterations //Number of times to add 1 to doitCurrentIteration ( interval / 0.03125 )
	private integer array doitCurrentIteration //Counting variable
	private integer array totalCurrentDoitIterations //Total iterations for an instance, if u specify a duration of 15 second and interval of 3 this is 5 (duration / interval)
	private integer array doitTci //Used to generate a consecutive Damage over time instance.
	private timer doitTimer //Timer to loop through the instances and pause if unused.
	private attacktype array doitAttackTypeIndex // the attacktype that deals damage for each instance(hero fortified siege...)
	private integer array doitInstanceIndex //the attacktype index is set by the user when using ApplyDotEffect and is set to integer aid
	private integer array doitSpellId // the id of the current damage over time instance, this is from the spell which causes this effect
	private real array doitRemainingDamage // the damage of the current doit instnance this needs to be reduced each tick
	private real array doitStackingDamage
	private integer array doitMaxStackNumberPerInstance // the maximum number of times a spell can stack. this is configured through the function call. should be > 2 so u have at least 2 stacks..
	private integer array doitStackCount //current stack count of an instance
	 /* 
	set doitAttackTypeIndex[0] = ATTACK_TYPE_CHAOS
	set doitAttackTypeIndex[1] = ATTACK_TYPE_MAGIC
	set doitAttackTypeIndex[2] = ATTACK_TYPE_NORMAL
	set doitAttackTypeIndex[3] = ATTACK_TYPE_PIERCE
	set doitAttackTypeIndex[5] = ATTACK_TYPE_SIEGE
	 */ 
endglobals
 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 
 * HOW TO USE - 
 * 
 * function ApplyDotEffect takes unit damager , unit target , real damg , real duration , real interval, integer attacktypeindex , integer instanceID , integer instancekind , integer maxNumOfStacks returns nothing
 * 
 * - this function will register a unit to be damaged or healed over time, the names are self explanatory duration is how long
 * you want your target to be damaged for and interval is the timeout between dealing damage.
 * For example a unit takes damage every 3 seconds for 15 seconds would define an interval of 3 and a duration of 15.
 * The aid integer corresponds to doitInstanceIndex and determines the attacktype used per instance, look at how doitAttackTypeIndex
 * is set.
 * Instance types are as follows:
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 
 * 0 - dont refresh, dont stack only create new instance
 * 1 - refresh dont stack .. refresh checks if the current instance is the same as any of the instances on the list and thus refreshes that instance if instnacetype is 1
 * 2 - stack (new damage + total old damage) stacks the current damage to previous original + current , this is very powerful and should probly only be used without refresh
 * 3 - refresh AND stack (new damage + total old damage) refreshes the dot to its orignal duration and stacks the damage very very very powerful
 * 4 - stack (new damage + remainder of old damage ) far more harmless i suppose if u have 500 damage left from an original 3000 damage this is not much of a boost
 * 5 - refresh AND stack (new damage + remainder of old damage ) a bit more volatile but still not as fatal
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 
 * 
 * 
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 
 * HOW TO IMPORT
 * 
 * Copy this trigger into your map, then call ApplyDotEffect(caster, target, amount , duration , interval, attacktypeindex, instanceID, instancetype ...... ) set amount to a negative value
 * for healing over time, and take a look at the example.
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 





//this function takes a spell id and if this id is on the list of spell ids which have created a damage/healing over time instance it retrieves the current instance of that spellID
function doitGetSpellInstanceID takes integer spellID returns integer
	local integer l = doitNext[0]

	if doitNext[0] == 0 then
		return 0 // there are no current isntances
	elseif doitNext[0] > 0 then
		loop
			exitwhen l == 0
			if doitSpellId[l] == spellID then //we found it!
				return l
			endif
			set l = doitNext[l]
		endloop
	endif
	return 0
endfunction

//these functions right here are called whenever any of the actions they are associated with are executed, you can do aditional modifications here such as: modifying the damage/healing
// by some other factor like a percentage since these funcions give you the current instance of the dot/hot to work with you can essentially modify all the private globals here..
// example: if spellID[instance] = 'abcd' then
// set doitDamage[instance] = 50k
//endif
// you can call these functions with any kind of ids however since the dot/how instances change value you might need to call the function doitGetSpellInstanceID if you want to
//retrieve the instance of a certain spell that has been cast.

private function onOnlyRefresh takes integer spellID returns nothing
	call BJDebugMsg("instance# " + I2S(doitGetSpellInstanceID(spellID)) + " has been refreshed" )
endfunction

private function onOnlyStack takes integer spellID returns nothing
	call BJDebugMsg("the damage for instance# " + I2S(doitGetSpellInstanceID(spellID)) + " has been stacked")
endfunction
private function onStackAndRefresh takes integer spellID returns nothing
	call BJDebugMsg("the damage for instance # " + I2S(doitGetSpellInstanceID(spellID)) + " has been refreshed AND stacked" )
endfunction

private function onStackOld takes integer spellID returns nothing
	call BJDebugMsg("the damage for instance # " + I2S(doitGetSpellInstanceID(spellID)) + " has been stacked with any remaining damage to deal" )
endfunction

private function onRefreshANDStackOld takes integer spellID returns nothing

endfunction

private function onRefreshOld takes integer spellID returns nothing

endfunction

private function onMaxStackReached takes integer spellID returns nothing
	call BJDebugMsg("max stack has been reached for instance # " + I2S(doitGetSpellInstanceID(spellID)) + "from now this will only be refreshed.")

endfunction



private function DoitLoop takes nothing returns nothing
	local integer l = doitNext[0]

	if l == 0 then
		call PauseTimer(doitTimer)
	endif
	loop
		exitwhen l == 0
		set doitCurrentIteration[l] = doitCurrentIteration[l] + 1
		if doitCurrentIteration[l] == doitIterations[l] then
			set doitCurrentIteration[l] = 0
			set doitTci[l] = doitTci[l] + 1 // one instance has occured
			if not IsUnitType(doitTarget[l], UNIT_TYPE_DEAD) then
				if doitDamage[l] > 0 then
					call UnitDamageTarget( doitDamager[l] , doitTarget[l], doitDamage[l] , true, false, doitAttackTypeIndex[doitInstanceIndex[l]], DAMAGE_TYPE_UNIVERSAL, null)
					set doitRemainingDamage[l] = doitRemainingDamage[l] - doitDamage[l] //since we have dealt damage the total damage needed to be dealt is decreased.
				else
					call SetWidgetLife(doitTarget[l], GetWidgetLife(doitTarget[l]) + (doitDamage[l] * - 1 ))
				endif
			else // if the unit is dead destroy everything
				set doitNext[doitPrev[l]] = doitNext[l]
				set doitPrev[doitNext[l]] = doitPrev[l]
				set doitRecycler[l] = doitRecycler[0]
				set doitRecycler[0] = l
				set totalCurrentDoitIterations[l] = 0
				set doitIterations[l] = 0
				set doitTci[l] = 0
				set doitSpellId[l] = 0
			endif
		endif
		if doitTci[l] == totalCurrentDoitIterations[l] and IsUnitType(doitTarget[l], UNIT_TYPE_DEAD) == false then
			set doitNext[doitPrev[l]] = doitNext[l]
			set doitPrev[doitNext[l]] = doitPrev[l]
			set doitRecycler[l] = doitRecycler[0]
			set doitRecycler[0] = l
			set totalCurrentDoitIterations[l] = 0
			set doitIterations[l] = 0
			set doitTci[l] = 0
			set doitSpellId[l] = 0
		endif
		set l = doitNext[l]
	endloop
endfunction



private function doitDefault takes unit damager , unit target , real damg , real duration , real interval, integer attacktypeindex , integer instanceID , integer instancekind, integer maxNumOfStacks returns nothing
	local integer instance = R2I(duration / interval )
	local integer id = doitRecycler[0]
	local integer instChecker = 0
	set instChecker = doitNext[0]

	call TimerStart(doitTimer, 0.031250000, true , function DoitLoop )
	if id == 0 then
		set doitCounting[0] = doitCounting[0] + 1
		set id = doitCounting[0]
	else
		set doitRecycler[0] = doitRecycler[id]
	endif
	set doitNext[id] = 0
	set doitPrev[id] = doitPrev[0]
	set doitNext[doitPrev[0]] = id
	set doitPrev[0] = id
	set doitDamager[ id] = damager
	set doitTarget[ id] = target
	set doitIterations[id] = R2I(interval / 0.03125)
	set totalCurrentDoitIterations[id] = R2I(instance)
	set doitDamage[id] = damg / instance
	set doitInstanceIndex[id] = attacktypeindex
	set doitSpellId[id] = instanceID
	set doitStackingDamage[id] = damg // set this to damage so we can stack it later.
	set doitRemainingDamage[id] = damg //initially is equal to the full damage.
	set doitMaxStackNumberPerInstance[id ] = maxNumOfStacks // this will be set to + 1 on each stack
	set doitStackCount[id ] = 0
endfunction




function ApplyDotEffect takes unit damager , unit target , real damg , real duration , real interval, integer attacktypeindex , integer instanceID , integer instancekind , integer maxNumOfStacks returns nothing
	local integer instance = R2I(duration / interval )
	local integer id = doitRecycler[0]
	local integer instChecker = 0
	local boolean sameUnit = false
	set instChecker = doitNext[0]


	if doitNext[0] == 0 then // if there are no instances then ve need to create one
		call doitDefault(damager, target, damg, duration, interval, attacktypeindex, instanceID, instancekind , maxNumOfStacks )
	elseif doitNext[0] > 0 then
		set instChecker = doitNext[0]
		loop
			exitwhen instChecker == 0
			if doitSpellId[instChecker] == instanceID and target == doitTarget[instChecker] then // in any case the spell id and the unit must be the same
//now we check the instancekind and perform the nesessary operations
				if instancekind == 1 then
					set doitTci[instChecker] = 1 //reset the instance count for the desired instance to 0 so that it can keep damaging over time until it expires of its called again
					call onOnlyRefresh(doitSpellId[instChecker])
					set sameUnit = true
				elseif instancekind == 2 then //stack new damage no refreshing
					if doitMaxStackNumberPerInstance[instChecker ] != 0 and doitStackCount[instChecker] != doitMaxStackNumberPerInstance[instChecker ] then //can not have infinite instances and have not reached the total stack count
						set doitStackingDamage[instChecker] = doitStackingDamage[instChecker] + damg //stack damage
						set doitDamage[instChecker] = doitStackingDamage[instChecker] / instance //reset the damage to the new
						set doitStackCount[instChecker] = doitStackCount[instChecker] + 1
					elseif doitMaxStackNumberPerInstance[id ] == 0 then //infinite stacks :D !!!
						set doitStackingDamage[instChecker] = doitStackingDamage[instChecker] + damg //stack damage
						set doitDamage[instChecker] = doitStackingDamage[instChecker] / instance //reset the damage to the new
					endif
					if doitStackCount[instChecker] == doitMaxStackNumberPerInstance[instChecker ] then//we have reached the total number of stacks and now can only refresh
					endif
					call onOnlyStack(doitSpellId[instChecker])
					set sameUnit = true
				elseif instancekind == 3 then //refresh and stack
					if doitMaxStackNumberPerInstance[instChecker ] != 0 and doitStackCount[instChecker] != doitMaxStackNumberPerInstance[instChecker ] then //can not have infinite instances and have not reached the total stack count
						set doitStackingDamage[instChecker] = doitStackingDamage[instChecker] + damg //stack damage
						set doitDamage[instChecker] = doitStackingDamage[instChecker] / instance //reset the damage to the new
						set doitTci[instChecker] = 1 //reset the instance count for the desired instance to 0 so that it can keep damaging over time until it expires of its called again
						set doitStackCount[instChecker] = doitStackCount[instChecker] + 1
					elseif doitMaxStackNumberPerInstance[id ] == 0 then //infinite stacks :D !!!
						set doitStackingDamage[instChecker] = doitStackingDamage[instChecker] + damg //stack damage
						set doitDamage[instChecker] = doitStackingDamage[instChecker] / instance //reset the damage to the new
						set doitTci[instChecker] = 1 //reset the instance count for the desired instance to 0 so that it can keep damaging over time until it expires of its called again
					endif
					if doitStackCount[instChecker] == doitMaxStackNumberPerInstance[instChecker ] then//we have reached the total number of stacks and now can only refresh
						call onMaxStackReached(doitSpellId[instChecker])
						set doitTci[instChecker] = 1 //reset the instance count for the desired instance to 0 so that it can keep damaging over time until it expires of its called again
					endif
					call onStackAndRefresh(doitSpellId[instChecker])
					set sameUnit = true
				elseif instancekind == 4 then
					if doitMaxStackNumberPerInstance[instChecker ] != 0 and doitStackCount[instChecker] != doitMaxStackNumberPerInstance[instChecker ] then //can not have infinite instances and have not reached the total stack count
						set doitDamage[instChecker] = (damg + doitRemainingDamage[instChecker]) / instance //stack damage
						set doitStackCount[instChecker] = doitStackCount[instChecker] + 1
					elseif doitMaxStackNumberPerInstance[id ] == 0 then //infinite stacks :D !!!
						set doitDamage[instChecker] = (damg + doitRemainingDamage[instChecker]) / instance //stack damage
					endif
					call onStackOld(doitSpellId[instChecker])
					set sameUnit = true
				elseif instancekind == 5 then
					if doitMaxStackNumberPerInstance[instChecker ] != 0 and doitStackCount[instChecker] != doitMaxStackNumberPerInstance[instChecker ] then //can not have infinite instances and have not reached the total stack count
						set doitDamage[instChecker] = (damg + doitRemainingDamage[instChecker]) / instance //stack damage
						set doitTci[instChecker] = 1 //reset the instance count for the desired instance to 0 so that it can keep damaging over time until it expires of its called again
						set doitStackCount[instChecker] = doitStackCount[instChecker] + 1
					elseif doitMaxStackNumberPerInstance[id ] == 0 then //infinite stacks :D !!!
						set doitDamage[instChecker] = (damg + doitRemainingDamage[instChecker]) / instance //stack damage
						set doitTci[instChecker] = 1 //reset the instance count for the desired instance to 0 so that it can keep damaging over time until it expires of its called again
					endif
					if doitStackCount[instChecker] == doitMaxStackNumberPerInstance[instChecker ] then//we have reached the total number of stacks and now can only refresh
						call onMaxStackReached(doitSpellId[instChecker])
						set doitTci[instChecker] = 1 //reset the instance count for the desired instance to 0 so that it can keep damaging over time until it expires of its called again 0
					endif

					call onRefreshANDStackOld(doitSpellId[instChecker])
					set sameUnit = true
				endif
			endif
			set instChecker = doitNext[instChecker]
		endloop

		if sameUnit == false then // we have cast our dot spell on a different unit and must now add it to the system.
			if id == 0 then
				set doitCounting[0] = doitCounting[0] + 1
				set id = doitCounting[0]
			else
				set doitRecycler[0] = doitRecycler[id]
			endif
			call doitDefault(damager, target, damg, duration, interval, attacktypeindex, instanceID, instancekind, maxNumOfStacks )
		endif

	endif
	if instancekind == 0 then
		call doitDefault(damager, target, damg, duration, interval, attacktypeindex, instanceID, instancekind, maxNumOfStacks )
	endif

endfunction


private function Init takes nothing returns nothing
	local integer l = 0
	local trigger t = CreateTrigger( )
	set doitRecycler[0] = 0

	loop
		exitwhen l > 15
		set doitCounting [l] = 0
		set l = l + 1
	endloop
	set doitAttackTypeIndex[0] = ATTACK_TYPE_CHAOS
	set doitAttackTypeIndex[1] = ATTACK_TYPE_MAGIC
	set doitAttackTypeIndex[2] = ATTACK_TYPE_NORMAL
	set doitAttackTypeIndex[3] = ATTACK_TYPE_PIERCE
	set doitAttackTypeIndex[5] = ATTACK_TYPE_SIEGE
	set doitCounting[0] = 0
	set doitTimer = CreateTimer()
endfunction

endlibrary



Keywords:
damage, over, time, interval, per, second , duration
Contents

Damage Over Interval Time (Map)

Reviews
12th Dec 2015 IcemanBo: Too long as NeedsFix. Rejected. 09:56, 26th Jul 2013 Magtheridon96: Review bool == false -> not bool bool == true -> bool This: local integer l = doitNext[0] if doitNext[0] == 0 then return 0 // there...

Moderator

M

Moderator

12th Dec 2015
IcemanBo: Too long as NeedsFix. Rejected.

09:56, 26th Jul 2013
Magtheridon96:

Review

  • bool == false -> not bool
  • bool == true -> bool
  • This:
    JASS:
    local integer l = doitNext[0]
    if doitNext[0] == 0 then
        return 0 // there are no current isntances
    elseif doitNext[0] > 0 then
        loop
            exitwhen l == 0
            if doitSpellId[l] == spellID then //we found it!
                return l
            endif
            set l = doitNext[l]
        endloop
    endif
    return 0

    may as well be this:

    JASS:
    local integer l = doitNext[0]
    loop
        exitwhen l == 0
        if doitSpellId[l] == spellID then //we found it!
            return l
        endif
        set l = doitNext[l]
    endloop
    return 0
  • if not IsUnitType(doitTarget[l], UNIT_TYPE_DEAD) then is insufficient. In addition to this, you should check if GetUnitTypeId(u) != 0. Currently, invalid units will be marked as alive.
  • Clean your code man :v. Look at the code here for a reference.
 
Top