library DreamCoil uses SpellEffectEvent, Tt, UnitIndexer
//===========================================================================
// CONFIGURABLES
//===========================================================================
globals
private constant integer ABIL_ID = 'ABDC' // raw code of ability "Dream Coil"
private constant integer DUM_ABIL_ID = 'ADC0' // raw code of ability "Dream Coil (Stun)"
private constant integer BUFF_ID = 'BBDC' // raw code of buff "Dream Coil"
private constant integer CASTER_ID = 'cAST' // raw code of unit "Caster Dummy"
private constant integer DUMMY_ID = 'duDC' // raw code of unit "Dream Coil Dummy"
private constant string ANIM = "channel" // animation of dummy
private constant integer RED = 255 // red vertex color of DUMMY_ID
private constant integer GREEN = 255 // green vertex color of DUMMY_ID
private constant integer BLUE = 255 // blue vertex color of DUMMY_ID
private constant integer TRANS = 255 // transparency of DUMMY_ID, where 0 is fully transparent
private constant integer SCALE = 1 // scale size of DUMMY_ID
private constant real HEIGHT = 100. // height of DUMMY_ID
private constant string LIGHTNING = "MFPB" // lightning type used
private constant integer LIGHTNING_RED = 255 // red vertex color of LIGHTNING
private constant integer LIGHTNING_GREEN = 255 // green vertex color ot LIGHTNING
private constant integer LIGHTNING_BLUE = 255 // blue vertex color ot LIGHTNING
private constant integer LIGHTNING_TRANS = 255 // transparency of LIGHTNING, where 0 is fully transparent
private constant real LIGHTNING_HEIGHT = 50. // lightning attachment height offset (relative to unit's fly height)
private constant string ORDER_ID = "firebolt" // order string of ability "Dream Coil (Stun)"
private constant real ENUM_RADIUS = 176. // max collision size of a unit in your map
private constant attacktype ATK = ATTACK_TYPE_NORMAL // attack type
private constant damagetype DMG = DAMAGE_TYPE_MAGIC // damage type
endglobals
// area of effect
private constant function GetArea takes integer level returns real
return 375.
endfunction
// duration of coil
private constant function GetDuration takes integer level returns real
return 5.
endfunction
// initial damage dealt
private constant function GetInitialDamage takes integer level returns real
return 50. * level + 50.
endfunction
// initial stun duration
private constant function GetInitialDuration takes integer level returns real
return 0.5
endfunction
// distance in which the coil snaps
private constant function GetSnapArea takes integer level returns real
return 600.
endfunction
// break damage dealt
private constant function GetSnapDamage takes integer level returns real
return 50. * level + 50.
endfunction
// break stun duration
private constant function GetSnapDuration takes integer level returns real
return 0.75 * level + 0.75
endfunction
// target types allowed for dealing damage
private constant function GetFilter takes unit caster, unit target returns boolean
return /*
*/ not IsUnitType(target, UNIT_TYPE_DEAD) and /* // target is alive
*/ IsUnitEnemy(target, GetOwningPlayer(caster)) and /* // target is an enemy of caster
*/ not IsUnitType(target, UNIT_TYPE_STRUCTURE) and /* // target is not a structure
*/ not IsUnitType(target, UNIT_TYPE_MECHANICAL) // target is not mechanic
endfunction
//===========================================================================
// END CONFIGURABLES
//===========================================================================
globals
private constant player NEUTRAL_PASSIVE = Player(PLAYER_NEUTRAL_PASSIVE)
private constant real TRUE_RED = LIGHTNING_RED / 255
private constant real TRUE_GREEN = LIGHTNING_GREEN / 255
private constant real TRUE_BLUE = LIGHTNING_BLUE / 255
private constant real TRUE_TRANS = LIGHTNING_TRANS / 255
private group G = bj_lastCreatedGroup
endglobals
private struct Main extends array
private lightning l
private unit u
private unit target
private boolean b
private boolean check
private real dmg
private real dist
private real dur
private real stun
private real snapStun
private real x
private real y
private static unit castDummy
private static integer array store
private static constant real TIMEOUT = 0.031250000
implement CTTC
local real x
local real y
implement CTTCExpire
if IsUnitType(this.target, UNIT_TYPE_DEAD) or GetUnitTypeId(this.target) == 0 then
call DestroyLightning(this.l)
set this.l = null
call this.destroy()
else
if this.b then
if this.stun > 0 then
set this.stun = this.stun - TIMEOUT
if this.stun <= 0 then
call UnitRemoveAbility(this.target, BUFF_ID)
elseif GetUnitAbilityLevel(this.target, BUFF_ID) == 0 then
call IssueTargetOrder(thistype.castDummy, ORDER_ID, this.target)
endif
endif
set this.dur = this.dur - TIMEOUT
if this.dur <= 0 then
if this.check then
set this.check = false
call DestroyLightning(this.l)
set this.l = null
endif
if this.stun <= 0 then
call this.destroy()
endif
else
set x = GetUnitX(this.target)
set y = GetUnitY(this.target)
call MoveLightningEx(this.l, true, this.x, this.y, HEIGHT, x, y, GetUnitFlyHeight(this.target) + LIGHTNING_HEIGHT)
set x = x - this.x
set y = y - this.y
if x * x + y * y > this.dist then
set this.b = false
set thistype.store[GetUnitId(this.target)] = this
call DestroyLightning(this.l)
call UnitDamageTarget(this.u, this.target, this.dmg, true, false, ATK, DMG, null)
call IssueTargetOrder(thistype.castDummy, ORDER_ID, this.target)
set this.l = null
endif
endif
else
set this.snapStun = this.snapStun - TIMEOUT
if this.snapStun <= 0 then
call UnitRemoveAbility(this.target, BUFF_ID)
call this.destroy()
elseif GetUnitAbilityLevel(this.target, BUFF_ID) == 0 then
call IssueTargetOrder(thistype.castDummy, ORDER_ID, this.target)
endif
endif
endif
implement CTTCEnd
private static method onDeath takes nothing returns boolean
call RemoveUnit(GetTriggerUnit())
call DestroyTrigger(GetTriggeringTrigger())
return false
endmethod
private static method onCast takes nothing returns boolean
local thistype this
local trigger t = CreateTrigger()
local unit caster = GetTriggerUnit()
local unit u
local integer level = GetUnitAbilityLevel(caster, ABIL_ID)
local real area = GetArea(level)
local real dur = GetDuration(level)
local real dmg = GetInitialDamage(level)
local real stun = GetInitialDuration(level)
local real snapArea = GetSnapArea(level)
local real snapDmg = GetSnapDamage(level)
local real snapStun = GetSnapDuration(level)
local real x = GetSpellTargetX()
local real y = GetSpellTargetY()
set snapArea = snapArea * snapArea
set u = CreateUnit(NEUTRAL_PASSIVE, DUMMY_ID, x, y, 0)
call SetUnitVertexColor(u, RED, GREEN, BLUE, TRANS)
call SetUnitScale(u, SCALE, 0, 0)
call SetUnitFlyHeight(u, HEIGHT, 0)
call SetUnitAnimation(u, ANIM)
call UnitApplyTimedLife(u, 'BTLF', dur)
call TriggerRegisterUnitEvent(t, u, EVENT_UNIT_DEATH)
call TriggerAddCondition(t, Condition(function thistype.onDeath))
call GroupEnumUnitsInRange(G, x, y, area + ENUM_RADIUS, null)
loop
set u = FirstOfGroup(G)
exitwhen u == null
call GroupRemoveUnit(G, u)
if GetFilter(caster, u) and IsUnitInRangeXY(u, x, y, area) then
set this = thistype.create()
set this.l = AddLightningEx(LIGHTNING, true, x, y, HEIGHT, GetUnitX(u), GetUnitY(u), GetUnitFlyHeight(u) + LIGHTNING_HEIGHT)
set this.u = caster
set this.target = u
set this.b = true
set this.check = true
set this.dmg = snapDmg
set this.dist = snapArea
set this.dur = dur
set this.stun = stun
set this.snapStun = snapStun
set this.x = x
set this.y = y
call SetLightningColor(this.l, TRUE_RED, TRUE_GREEN, TRUE_BLUE, TRUE_TRANS)
call UnitDamageTarget(caster, u, dmg, true, false, ATK, DMG, null)
call IssueTargetOrder(thistype.castDummy, ORDER_ID, u)
endif
endloop
set t = null
set caster = null
return false
endmethod
private static method onInit takes nothing returns nothing
set thistype.castDummy = CreateUnit(NEUTRAL_PASSIVE, CASTER_ID, 0, 0, 0)
call UnitAddAbility(thistype.castDummy, DUM_ABIL_ID)
call RegisterSpellEffectEvent(ABIL_ID, function thistype.onCast)
endmethod
endstruct
endlibrary