library DashSpell initializer init requires Knockback3D
globals
private constant integer SPELL_ID = 'AEbl'
private constant attacktype ATTACK_TYPE = ATTACK_TYPE_MAGIC
private constant damagetype DAMAGE_TYPE = DAMAGE_TYPE_NORMAL
private constant weapontype WEAPON_TYPE = WEAPON_TYPE_WHOKNOWS
// The Art - Caster field of Blink allows you to play an effect on the targeted location when the unit appears there
// The knockback dust sliding effect can be changed/removed in the Knockback3D library itself, where it's called FRICTION_MODEL
// There are many other configurables for the knockback in the Knockback3D library, such as bouncing, destroying trees, friction, etc.
private keyword LEVEL
endglobals
// you can use the LEVEL global variable here to refer to the spell's level on-cast
private constant function KnockbackRadius takes nothing returns real
return 200.00 + 100.00*LEVEL
endfunction
private constant function KnockbackDamage takes nothing returns real
return 20.00*LEVEL
endfunction
// not really a distance, this is sort of wonky because of how Knockback3D works
// you may need to try different values to get what you want, or change the frction value in KB3D
private constant function KnockbackStrength takes nothing returns real
return 1000.00
endfunction
// probably don't want it to go up but hey maybe you do; this is in radians, not degrees
private constant function KnockbackVerticalAngle takes nothing returns real
return 0.00
endfunction
// LEVEL is still valid here if you want to use it
private function KnockbackIsValidTarget takes unit TargetUnit, unit CastingUnit, player CasterOwner returns boolean
return IsUnitEnemy(TargetUnit, CasterOwner) /* check if enemy
*/ and GetWidgetLife(TargetUnit) > 0.405 /* check if alive
*/ and not IsUnitType(TargetUnit, UNIT_TYPE_STRUCTURE) /* check if not a structure
*/ and not IsUnitType(TargetUnit, UNIT_TYPE_MAGIC_IMMUNE)/* check if not spell-immune
*/ and GetUnitAbilityLevel(TargetUnit, 'Avul') == 0 /* check if not invulnerable
*/
endfunction
globals
public trigger SpellTrig
private timer DelayTimer
private group SearchGroup
private unit Caster
private player CastOwner
private integer LEVEL
private boolexpr KBFilter
endglobals
private function CastCheck takes nothing returns boolean
return GetSpellAbilityId() == SPELL_ID
endfunction
private function KBTargeting takes nothing returns boolean
return KnockbackIsValidTarget(GetFilterUnit(), Caster, CastOwner)
endfunction
private function OnCastDelayed takes nothing returns nothing
local real cx = GetUnitX(Caster)
local real cy = GetUnitY(Caster)
local unit u
local real ux
local real uy
call GroupEnumUnitsInRange(SearchGroup, cx, cy, KnockbackRadius(), KBFilter)
loop
set u = FirstOfGroup(SearchGroup)
exitwhen u == null
call GroupRemoveUnit(SearchGroup, u)
set ux = GetUnitX(u)
set uy = GetUnitY(u)
call UnitDamageTarget(Caster, u, KnockbackDamage(), false, false, ATTACK_TYPE, DAMAGE_TYPE, WEAPON_TYPE)
call Knockback3D.add(u, KnockbackStrength(), Atan2(uy-cy, ux-cx), KnockbackVerticalAngle())
endloop
endfunction
private function OnCast takes nothing returns nothing
set Caster = GetTriggerUnit()
set CastOwner = GetOwningPlayer(Caster)
set LEVEL = GetUnitAbilityLevel(Caster, SPELL_ID)
call TimerStart(DelayTimer, 0.00, false, function OnCastDelayed)
// necessary because the unit is still at its initial location when the blink 'happens'
// and blink has a special cast paradigm that allows you to target as far away as you can see
// but only blinks the maximum distance toward that point, thus checking the spell's target
// point does not work properly
endfunction
private function init takes nothing returns nothing
set DelayTimer = CreateTimer()
set SearchGroup = CreateGroup()
set KBFilter = Filter(function KBTargeting)
set SpellTrig = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(SpellTrig, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(SpellTrig, Condition(function CastCheck))
call TriggerAddAction(SpellTrig, function OnCast)
endfunction
endlibrary