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
[/HIDDEN]