scope Knife initializer init import DummyUnitStack import TerrainData import DamageType import RegisterPlayerUnitEvent native UnitAlive takes unit u returns boolean struct DummyAlloc unit u end constant integer KNIFE_ID = 'A002' constant string FX = "Abilities\\Weapons\\ShadowHunterMissile\\ShadowHunterMissile.mdl" constant string FX_PROC = "Abilities\\Weapons\\HydraliskImpact\\HydraliskImpact.mdl" constant string FX_EXPLODED = "Objects\\Spawnmodels\\Human\\HumanLargeDeathExplode\\HumanLargeDeathExplode.mdl" constant string FX_PROC_ATTACH_POINT = "chest" constant real OFFSET = 70. constant real EFFECT_HEIGHT = 50. constant real FX_DURATION = 1.6 constant real RADIUS = 75. constant real EXECUTE_MAX_HEALTH = 60. constant real BASE_DAMAGE = 35. constant real SHORT_COOLDOWN = 5. group grp = CreateGroup() function resetCooldown takes nothing returns nothing timer tim = GetExpiredTimer() DummyAlloc d = tim.getData() castTo DummyAlloc UnitRemoveAbility(d.u, KNIFE_ID) UnitAddAbility(d.u, KNIFE_ID) destroy d DestroyTimer(tim) end function releaseDummy takes nothing returns nothing timer tim = GetExpiredTimer() DummyAlloc d = tim.getData() castTo DummyAlloc DummyUnitStack.release(d.u) destroy d DestroyTimer(tim) end function act takes nothing returns nothing unit tU unit iter unit selected = null player p real selectedRange = 2. * RADIUS real facing real x real y unit dum timer tim timer cdTim DummyAlloc d if GetSpellAbilityId() == KNIFE_ID then tU = GetTriggerUnit() p = GetOwningPlayer(tU) facing = GetUnitFacing(tU) * bj_DEGTORAD x = GetUnitX(tU) + OFFSET * Cos(facing) y = GetUnitY(tU) + OFFSET * Sin(facing) // fx dum = DummyUnitStack.get() SetUnitX(dum, x) SetUnitY(dum, y) SetUnitFlyHeight(dum, EFFECT_HEIGHT, 0.) DestroyEffect(AddSpecialEffectTarget(FX, dum, "origin")) tim = CreateTimer() d = new DummyAlloc() d.u = dum tim.setData(d castTo int) TimerStart(tim, FX_DURATION, false, function releaseDummy) // damage GroupEnumUnitsInRange(grp, x, y, RADIUS, null) loop iter = FirstOfGroup(grp) exitwhen iter == null if IsUnitEnemy(iter, p) and UnitAlive(iter) and IsUnitInRangeXY(iter, x, y, selectedRange) then selected = iter selectedRange = TerrainData.distanceBetweenXY(GetUnitX(iter), x, GetUnitY(iter), y) end GroupRemoveUnit(grp, iter) end if selected != null then DestroyEffect(AddSpecialEffectTarget(FX_PROC, selected, FX_PROC_ATTACH_POINT)) if GetWidgetLife(selected) <= EXECUTE_MAX_HEALTH then DestroyEffect(AddSpecialEffectTarget(FX_EXPLODED, selected, "origin")) DamageType.dealCodeDamage(tU, selected, 2. * EXECUTE_MAX_HEALTH) // cut cooldown in half cdTim = CreateTimer() d = new DummyAlloc() d.u = tU cdTim.setData(d castTo int) TimerStart(cdTim, SHORT_COOLDOWN, false, function resetCooldown) else DamageType.dealCodeDamage(tU, selected, BASE_DAMAGE) end end end end function init takes nothing returns nothing registerPlayerUnitEvent(EVENT_PLAYER_UNIT_SPELL_EFFECT, function act) end endscope