Name | Type | is_array | initial_value |
//TESH.scrollpos=-1
//TESH.alwaysfold=0
scope BloodCloud
// recquires CTL
// http://www.hiveworkshop.com/forums/jass-resources-412/snippet-constant-timer-loop-32-a-201381/
//=====================================//
// INSTRUCTIONS //
//=====================================//
// How to import :
// 1) Download the attached map.
// 2) Export-import the blood cloud model and the icon (made by CRAZZYRUSSIAN).
// 3) Copy-paste the unit "Blood Cloud", the buff "Blood Cloud (Aura of Slow)"
// and the spells "Summon Blood Cloud" and "Aura of Slow (Blood Cloud)".
// 4) Update the unit's ability list and the aura spell's buff.
// 5) Copy-paste the following script in an empty converted trigger.
// 6) Edit the datas in the CONFIGURATION BLOC below accordingly to your tastes and the Objects' ID.
//
//=====================================//
//=====================================//
// //
// CONFIGURATION BLOC //
// //
//=====================================//
globals
private constant integer SPELL_ID = 'A000' // The castable spell
private constant integer SPELL_AURA_ID = 'A001' // The aura spell
private constant integer BUFF_ID = 'B000' // The aura's buff
private constant integer CLOUD_ID = 'n000' // The invocation unit
private constant attacktype ATTACK = ATTACK_TYPE_MAGIC // For the DoT
private constant damagetype DAMAGE = DAMAGE_TYPE_UNIVERSAL // For the DoT
private constant string DRAIN_SFX = "Objects\\Spawnmodels\\Critters\\Albatross\\CritterBloodAlbatross.mdl"
private constant string DRAIN_ATTACHMENT = "chest"
private constant string HEAL_SFX = "Abilities\\Spells\\Undead\\VampiricAura\\VampiricAuraTarget.mdl"
private constant string HEAL_ATTACHMENT = "chest"
private constant real TIMEOUT = 0.03125 // CTL Timeout
private constant boolean USE_AURA_LEVELS = false // Set to true if your aura spell uses several levels
private real array BaseDamageOverTime // Base DoT for units affected by the rain
private real array LifeDrainAmount // Percentage of current life drained for summoning
private real array BonusDamageOverTime // Factor of life drained turned into DoT
private real array HealFactor // Factor of life drained occasionally healed
private real array LifeDrainRadius // Radius of the spell
private real array CloudDuration // Duration of the invocation
endglobals
private function SetupDatas takes nothing returns nothing
// Level 1
set BaseDamageOverTime[1]=15*TIMEOUT // = 15 damage per second
set LifeDrainAmount[1]=0.1 // = 10% of current life drained
set BonusDamageOverTime[1]=0.1*TIMEOUT // = 10% of life drained dealt per second
set HealFactor[1]=0.2
set LifeDrainRadius[1]=150
set CloudDuration[1]=12
// Level 2
set BaseDamageOverTime[2]=20*TIMEOUT
set LifeDrainAmount[2]=0.1
set BonusDamageOverTime[2]=0.15*TIMEOUT
set HealFactor[2]=0.2
set LifeDrainRadius[2]=250
set CloudDuration[2]=16
// Level 3
set BaseDamageOverTime[3]=25*TIMEOUT
set LifeDrainAmount[3]=0.1
set BonusDamageOverTime[3]=0.2*TIMEOUT
set HealFactor[3]=0.2
set LifeDrainRadius[3]=350
set CloudDuration[3]=20
endfunction
// Filter for units affected by the blood drain
private function DrainFilter takes unit target,unit caster,integer lvl returns boolean
return GetOwningPlayer(target)==GetOwningPlayer(caster) and /*
*/ not IsUnitType(target,UNIT_TYPE_DEAD) and /*
*/ not IsUnitType(target,UNIT_TYPE_MECHANICAL) and /*
*/ not IsUnitType(target,UNIT_TYPE_MAGIC_IMMUNE)
endfunction
// Filter for units affected by the heal on cloud's death
private function HealFilter takes unit target,unit cloud,integer lvl returns boolean
return IsUnitAlly(target,GetOwningPlayer(cloud)) and /*
*/ not IsUnitType(target,UNIT_TYPE_DEAD) and /*
*/ not IsUnitType(target,UNIT_TYPE_MECHANICAL)
endfunction
// Note: the filter for units affected by the damage over time is the aura spell's filter
//=====================================//
// //
// END OF CONFIGURATION BLOC //
// //
//=====================================//
globals
private group TmpGroup=CreateGroup()
endglobals
private struct SpellData extends array
unit invoc
integer lvl
real lifedrained
implement CTL
local unit target
implement CTLExpire
if IsUnitType(this.invoc,UNIT_TYPE_DEAD) or GetUnitTypeId(this.invoc)==0 then
if GetUnitTypeId(this.invoc)!=0 then
call GroupEnumUnitsInRange(TmpGroup,GetUnitX(this.invoc),GetUnitY(this.invoc),600,null)
loop
set target=FirstOfGroup(TmpGroup)
exitwhen target==null
call GroupRemoveUnit(TmpGroup,target)
if HealFilter(target,this.invoc,this.lvl) and IsUnitInRangeXY(target,GetUnitX(this.invoc),GetUnitY(this.invoc),400) then
call SetWidgetLife(target,GetWidgetLife(target)+this.lifedrained*HealFactor[this.lvl])
call DestroyEffect(AddSpecialEffectTarget(HEAL_SFX,target,HEAL_ATTACHMENT))
endif
endloop
endif
call this.destroy()
else
call GroupEnumUnitsInRange(TmpGroup,GetUnitX(this.invoc),GetUnitY(this.invoc),300,null)
loop
set target=FirstOfGroup(TmpGroup)
exitwhen target==null
call GroupRemoveUnit(TmpGroup,target)
if GetUnitAbilityLevel(target,BUFF_ID)>0 then
call UnitDamageTarget(this.invoc,target,BaseDamageOverTime[this.lvl]+BonusDamageOverTime[this.lvl]*this.lifedrained,true,false,ATTACK,DAMAGE,null)
endif
endloop
endif
implement CTLNull
implement CTLEnd
private static method SpellCast takes nothing returns nothing
local thistype this=create()
local real x=GetUnitX(GetSpellTargetUnit())
local real y=GetUnitY(GetSpellTargetUnit())
local unit caster=GetTriggerUnit()
local unit tmp
set this.invoc=CreateUnit(GetOwningPlayer(caster),CLOUD_ID,x,y,GetUnitFacing(caster))
set this.lvl=GetUnitAbilityLevel(caster,SPELL_ID)
set this.lifedrained=0
call GroupEnumUnitsInRange(TmpGroup,x,y,LifeDrainRadius[this.lvl]+200,null)
loop
set tmp=FirstOfGroup(TmpGroup)
exitwhen tmp==null
call GroupRemoveUnit(TmpGroup,tmp)
if DrainFilter(tmp,caster,this.lvl) and IsUnitInRangeXY(tmp,x,y,LifeDrainRadius[this.lvl]) then
set this.lifedrained=this.lifedrained+LifeDrainAmount[this.lvl]*GetWidgetLife(tmp)
call SetWidgetLife(tmp,GetWidgetLife(tmp)*(1-LifeDrainAmount[this.lvl]))
call DestroyEffect(AddSpecialEffectTarget(DRAIN_SFX,tmp,DRAIN_ATTACHMENT))
endif
endloop
call UnitApplyTimedLife(this.invoc,'BTLF',CloudDuration[this.lvl])
call SetUnitAnimation(this.invoc,"birth")
call QueueUnitAnimation(this.invoc,"stand")
static if USE_AURA_LEVELS then
call SetUnitAbilityLevel(this.invoc,SPELL_AURA_ID,this.lvl)
endif
set caster=null
endmethod
private static method SpellCondition takes nothing returns boolean
if GetSpellAbilityId()==SPELL_ID then
call SpellCast()
endif
return false
endmethod
private static method onInit takes nothing returns nothing
local trigger t=CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t,EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(t,Condition(function thistype.SpellCondition))
call SetupDatas()
endmethod
endstruct
endscope
//TESH.scrollpos=-1
//TESH.alwaysfold=0
library CTL /* v1.2.0.1
*************************************************************************************
*
* CTL or Constant Timer Loop provides a loop for constant merged timers of timeout .03125
*
* Similar to T32 but pauses timer when no structs have instances and removes structs
* from timer trigger when those structs have no instances.
*
* This can also create new timers after destroying a previous timer and generates less
* code in the module. It also generates no triggers so long as the module is implemented
* at the top of the struct.
*
************************************************************************************
*
* module CTL
*
* Allows creation/destruction of timers in a struct. Provides instancing of those timers.
*
* - static method create takes nothing returns thistype
* - method destroy takes nothing returns nothing
*
* CTL (optional)
* local variables, code before running any timers
* CTLExpire (not optional)
* timer code
* CTLNull (optional)
* null any locals, runs after all timers
* CTLEnd (not optional)
*
* module CT32
*
* Converts struct into a timer group. Allows the timer group to be started and stopped.
* Instancing and looping through active timers is up to the user.
*
* - static method start takes nothing returns nothing
* - static method stop takes nothing returns nothing
*
* CT32 (not optional)
* timer code
* CT32End (not optional)
*
* struct TimerGroup32 extends array
*
* Allows for the creation of timer groups. Timer instancing and looping is entirely up
* to the user.
*
* - static method create takes code func returns thistype
* - method destroy takes nothing returns nothing
* - method start takes nothing returns nothing
* - method stop takes nothing returns nothing
*
************************************************************************************/
globals
private integer tgc = 0 //timer group count
private integer array tgr //timer group recycler
private integer ic=0 //instance count
private integer tc=0 //timer count
private integer array rf //root first
private integer array n //next
private integer array p //previous
private integer array th //timer head
private integer array ns //next stack
private trigger t=CreateTrigger()
private timer m=CreateTimer()
private triggercondition array ct
private conditionfunc array rc
private boolean array e32 //enabled
private integer array i32r //ct32 recycler
private integer i32cr = 0 //ct32 count recycler
private boolean array ir32 //is recycling
private boolean array id32 //is destroying
endglobals
private function E takes nothing returns nothing
local integer i=ns[0]
set ns[0]=0
loop
exitwhen 0==i
if (0==p[i]) then
if (0==n[i]) then
call TriggerRemoveCondition(t,ct[th[i]])
set ct[th[i]]=null
set tc=tc-1
set rf[th[i]]=0
else
set rf[th[i]]=n[i]
set p[n[i]]=0
endif
else
set p[n[i]]=p[i]
set n[p[i]]=n[i]
endif
set n[i]=n[0]
set n[0]=i
set i=ns[i]
endloop
loop
exitwhen 0 == i32cr
set i32cr = i32cr - 1
set i = i32r[i32cr]
if (not e32[i]) then
call TriggerRemoveCondition(t,ct[i])
set ct[i] = null
if (id32[i]) then
set tgr[i] = tgr[0]
set tgr[0] = i
set id32[i] = false
set e32[i] = false
set ir32[i] = false
endif
endif
endloop
if (0==tc) then
call PauseTimer(m)
else
call TriggerEvaluate(t)
endif
endfunction
private function CT takes integer r returns integer
local integer i
local integer f
if (0==n[0]) then
set i=ic+1
set ic=i
else
set i=n[0]
set n[0]=n[i]
endif
set th[i]=r
set ns[i]=-1
set f=rf[r]
if (0==f) then
set n[i]=0
set p[i]=0
set rf[r]=i
set ct[r]=TriggerAddCondition(t,rc[r])
//set ct[r] = null
if (0==tc) then
call TimerStart(m,.031250000,true,function E)
endif
set tc=tc+1
else
set n[i]=f
set p[i]=0
set p[f]=i
set rf[r]=i
endif
return i
endfunction
private function DT takes integer t returns nothing
debug if (0>ns[t]) then
set ns[t]=ns[0]
set ns[0]=t
debug else
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"TIMER LOOP ERROR: ATTEMPT TO DESTROY NULL TIMER")
debug endif
endfunction
private function A takes code c returns integer
local integer i = tgr[0]
if (0 == i) then
set i = tgc + 1
set tgc = i
else
set tgr[0] = tgr[i]
endif
set rc[i]=Condition(c)
return i
endfunction
private function A32 takes integer i returns nothing
if (not e32[i]) then
if (not ir32[i] and not id32[i]) then
set ct[i] = TriggerAddCondition(t, rc[i])
endif
if (0 == tc) then
call TimerStart(m,.031250000,true,function E)
endif
set tc = tc + 1
set e32[i] = true
endif
endfunction
private function SR32 takes integer i returns nothing
if (e32[i]) then
if (not ir32[i] and not id32[i]) then
set i32r[i32cr] = i
set i32cr = i32cr + 1
set ir32[i] = true
endif
set e32[i] = false
set tc = tc - 1
endif
endfunction
private function DT32 takes integer i returns nothing
if (not id32[i]) then
if (not ir32[i]) then
set ir32[i] = true
set tc = tc - 1
set i32r[i32cr] = i
set i32cr = i32cr + 1
set e32[i] = false
endif
set id32[i] = true
endif
endfunction
private keyword r
private keyword e
module CTL
static integer rctl32
static method create takes nothing returns thistype
return CT(rctl32)
endmethod
method destroy takes nothing returns nothing
call DT(this)
endmethod
static method ectl32 takes nothing returns boolean
local thistype this=rf[rctl32]
endmodule
module CTLExpire
implement CTL
loop
exitwhen 0==this
endmodule
module CTLNull
set this=n[this]
endloop
endmodule
module CTLEnd
implement CTLNull
return false
endmethod
private static method onInit takes nothing returns nothing
set rctl32 = A(function thistype.ectl32)
endmethod
endmodule
module CT32
static integer rctl32
static method ectl32 takes nothing returns boolean
endmodule
module CT32End
return false
endmethod
static method start takes nothing returns nothing
call A32(rctl32)
endmethod
static method stop takes nothing returns nothing
call SR32(rctl32)
endmethod
private static method onInit takes nothing returns nothing
set rctl32 = A(function thistype.ectl32)
endmethod
endmodule
struct TimerGroup32 extends array
static method create takes code c returns thistype
return A(c)
endmethod
method destroy takes nothing returns nothing
call DT32(this)
endmethod
method start takes nothing returns nothing
call A32(this)
endmethod
method stop takes nothing returns nothing
call SR32(this)
endmethod
endstruct
endlibrary