scope Chernobyliss initializer OnInit
//Chernobyliss by Strikest
//Requires TimerUtils by Vexorian(http://www.wc3c.net/showthread.php?t=101322)
//Optionally requires KBS by kenny(http://www.thehelper.net/threads/knockback-system-kbs.96837/)
globals
private constant integer ABIL_ID = 'A000' //Raw code of ability.
private constant integer SLOW_ID = 'A001' //Raw code of the slow ability that is attached to affected units.
private constant string EFFECT1 = "war3mapImported\\Acid Ex.mdx"//Path of the desired special effect that is shown at target area.
private constant string EFFECT2 = "war3mapImported\\VenomousGaleV2_Portrait.mdx" //Path of the desired special effect you want attached to affected units.
private constant string EFFECT3 = "Abilities\\Spells\\Other\\AcidBomb\\BottleMissile.mdl"//Path of the desired special effect that is shown when a unit is affected.
private constant string ATTACH = "chest" //String of the desired attachment point for EFFECT2.
private constant string ATTACH2 = "chest"//String of the desired attachment point for EFFECT3
private constant string KB_SFX = "" //Path of the desired special effect you want attached to knocked back units.
private constant real TIMER_INTERVAL = 32. //Timer interval.
private constant real KB_DURATION = .6 //Duration of optional knockback.
private constant boolean CHANGE_VERTEX_COLOR = true//Choose whether or not you want to gradually change the vertex color of affected units as their health decreases.
private constant attacktype ATTACK_TYPE = ATTACK_TYPE_MAGIC //Attacktype you want
private constant damagetype DAMAGE_TYPE = DAMAGE_TYPE_MAGIC //Damagetype you want
private constant real TREE_AOE = 0.0
private constant boolean ALLOW_MOVE = false
private constant boolean CHECK_PATHING = false
//Copied from kenny's KBS trigger
//** - TREE_AOE - This determines whether or not trees will be knocked down. **
//** For trees to be knocked down, a positive number (real) must **
//** be used, such as 150.00, which would give a radius of 150.00 **
//** in which trees will be knocked down. **
//** For trees to not be knocked down, a negative number (real) **
//** must be used, such as -150.00, which would create a radius **
//** that if a tree comes within it, the unit will stop moving. **
//** For none of those effects, the number 0 (0.00) can be used. **
//** This will just cause the units to "bounce" off trees.
//** -ALLOW_MOVE - This boolean will decided whether or not you want the unit **
//** to have the ability to move while being knocked back. **
//** "true" will allow them to move, while "false" will not. **
//** -CHECK_PATHING - A boolean that, if true, will check for unpathable terrain **
//** such as a wall or cliff, or where doodads may be. If false **
//** it will ignore these changes and the unit will be pushed **
//** along the wall, cliff or doodad.
private constant group GROUP = CreateGroup( )//Don't touch.
private unit CASTER //Don't touch this either.
private real SPELL_X
private real SPELL_Y
endglobals
private constant function DamagePerSecond takes integer level,integer herostr,integer heroagi, integer heroint returns real
return (7. + level * 2.) / TIMER_INTERVAL
endfunction
private constant function Duration takes integer level returns real
return 12. + level * 2.
endfunction
private constant function AoE takes integer level returns real //Area of effect of the spell.
return 215. + (10. * level)
endfunction
private constant function SpreadAoE takes integer level returns real //Area of effect around affected units that it will spread to.
return 170.
endfunction
private constant function KBDistance takes integer level returns real //Distance the enemy will optionally be knocked back from target point.
return 200. + level * 10.
endfunction
private constant function ChanceToSpread takes integer level returns real //Chance to spread the toxin. A value of 1. will mean that it has a 100% of spreading.
return 100. / TIMER_INTERVAL
endfunction
private constant function FilterUnits takes unit u returns boolean //Filter which units will be afffected.
return IsUnitEnemy( u, GetOwningPlayer( CASTER ) )
endfunction
//////////////////////////////////////////////////////NO TOUCHY PAST THIS POINT UNLESS YOU KNOW WHAT YOU ARE DOING/////////////////////////////////////////////////////////////////////////////
private struct Cbliss
unit cast
unit t
real x
real y
real dur
integer lvl
effect attach
method destroy takes nothing returns nothing
set this.cast = null
set this.t = null
set this.attach = null
call this.deallocate()
endmethod
endstruct
native UnitAlive takes unit id returns boolean
private function Handler takes nothing returns nothing
local timer t = GetExpiredTimer( )
local Cbliss data = GetTimerData( t )
local unit u
local unit ug = null
local unit cast
local integer lvl = data.lvl
local real dur = data.dur - 1. / TIMER_INTERVAL
local real life
local real mlife
local real plife
set cast = data.cast
if data.dur <= 0 or not UnitAlive(data.t) then
call DestroyEffect( data.attach )
call UnitRemoveAbility( data.t, SLOW_ID )
static if CHANGE_VERTEX_COLOR then
call SetUnitVertexColor(data.t,255,255,255,255)
endif
call data.destroy( )
call ReleaseTimer( t )
else
call UnitDamageTarget(data.cast,data.t,DamagePerSecond(data.lvl,GetHeroStr(data.cast,true),GetHeroAgi(data.cast,true),GetHeroInt(data.cast,true)),false,true,ATTACK_TYPE,DAMAGE_TYPE,WEAPON_TYPE_WHOKNOWS)
static if CHANGE_VERTEX_COLOR then
set life = GetWidgetLife(data.t)
set mlife = GetUnitState(data.t,UNIT_STATE_MAX_LIFE)
set plife = life/mlife
if plife >= .3 then
call SetUnitVertexColor(data.t,R2I(plife* 255.),255,R2I(plife* 255.),255)
else
call SetUnitVertexColor(data.t,60,130,60,255)
endif
endif
set data.dur = data.dur - 1. / TIMER_INTERVAL
call SetTimerData( t, data )
call TimerStart( t, 1. / TIMER_INTERVAL, false, function Handler )
set data.x = GetUnitX(data.t)
set data.y = GetUnitY(data.t)
call GroupEnumUnitsInRange( GROUP,data.x,data.y, SpreadAoE(lvl), null )
loop
set ug = FirstOfGroup(GROUP)
exitwhen ug == null
if UnitAlive(ug) and GetUnitAbilityLevel(ug,SLOW_ID) == 0 and data.dur > 1. / TIMER_INTERVAL and GetRandomInt(0,100) <= R2I(ChanceToSpread(lvl)) then
if FilterUnits(ug) then
set data = data.create()
set data.cast = cast
set data.t = ug
set data.x = GetUnitX(ug)
set data.y = GetUnitY(ug)
set data.lvl = lvl
set data.dur = dur
set data.attach = AddSpecialEffectTarget(EFFECT2,ug,ATTACH)
call DestroyEffect(AddSpecialEffectTarget(EFFECT3,ug,ATTACH2))
call UnitAddAbility(ug,SLOW_ID)
call SetUnitAbilityLevel(ug,SLOW_ID,lvl)
call TimerStart(NewTimerEx(data),1. / TIMER_INTERVAL,false,function Handler)
endif
endif
call GroupRemoveUnit(GROUP,ug)
endloop
endif
set t = null
set u = null
set ug = null
set cast = null
endfunction
private function FilterActions takes nothing returns boolean
local Cbliss data
local unit u = GetFilterUnit()
local real x1 = SPELL_X
local real y1 = SPELL_Y
local real x2 = GetUnitX(u)
local real y2 = GetUnitY(u)
local real a = bj_RADTODEG * Atan2(y2 - y1, x2 - x1)
local integer lvl = GetUnitAbilityLevel(CASTER,ABIL_ID)
if UnitAlive(u) then
if FilterUnits(u) then
static if LIBRARY_KBS then
call KBS_BeginEx( u, KBDistance(lvl), KB_DURATION, a, KB_SFX, TREE_AOE, ALLOW_MOVE, CHECK_PATHING )
endif
set data = Cbliss.create()
set data.cast = CASTER
set data.t = u
set data.x = x2
set data.y = y2
set data.attach = AddSpecialEffectTarget(EFFECT2,u,ATTACH)
set data.lvl = lvl
set data.dur = Duration(lvl)
call DestroyEffect(AddSpecialEffectTarget(EFFECT3,u,ATTACH2))
call UnitAddAbility(u,SLOW_ID)
call SetUnitAbilityLevel(u,SLOW_ID,lvl)
call TimerStart(NewTimerEx(data),1. / TIMER_INTERVAL,false,function Handler)
endif
endif
set u = null
return false
endfunction
private function OnSpell takes nothing returns boolean
local real x = GetSpellTargetX()
local real y = GetSpellTargetY()
if GetSpellAbilityId() == ABIL_ID then
call DestroyEffect(AddSpecialEffect(EFFECT1,x,y))
set CASTER = GetTriggerUnit()
set SPELL_X = x
set SPELL_Y = y
call GroupEnumUnitsInRange(GROUP,x,y,AoE(GetUnitAbilityLevel(CASTER,ABIL_ID)), Filter( function FilterActions ) )
endif
return false
endfunction
private function OnInit takes nothing returns nothing
local trigger trig = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ( trig, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( trig, Condition( function OnSpell ) )
set trig = null
endfunction
endscope