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