scope Net initializer init import DummyUnitStack import DamageOverTime import RegisterPlayerUnitEvent native UnitAlive takes unit u returns boolean struct NetData real delX real delY real distance unit dummy effect attached player caster end constant string NET_FX = "Abilities\\Spells\\Orc\\Ensnare\\ensnareTarget.mdl" constant string NET_MODEL = "Abilities\\Spells\\Orc\\Ensnare\\EnsnareMissile.mdl" constant integer NET_ID = 'A006' // Spellcode for net ability constant integer NET_SLOW_ID = 'A005' // Spellcode of net slow dummy ability // An arbitrary value for making the net buff mutually exclusive in the // context of the DamageOverTime module. constant integer EXCLUSIVITY_NET = 'hnet' constant real DELAY = .2 constant real RADIUS = 200. constant real CLOCK_PERIOD = 1. / 30. constant real NET_VELOCITY = 600. constant real COLLISION_RADIUS = 80. constant real MAX_DISTANCE = 500. group grp = CreateGroup() timer clock = CreateTimer() NetData array dataDb integer dbIndex = -1 function strikeUnits takes real x, real y, player caster returns nothing unit iter unit dummy GroupEnumUnitsInRange(grp, x, y, RADIUS, null) loop iter = FirstOfGroup(grp) exitwhen iter == null if IsUnitEnemy(iter, caster) and UnitAlive(iter) then dummy = DummyUnitStack.get() SetUnitX(dummy, GetUnitX(iter)) SetUnitY(dummy, GetUnitY(iter)) UnitAddAbility(dummy, NET_SLOW_ID) IssueTargetOrder(dummy, "slow", iter) DamageOverTime.add(null, iter, 0, 9, NET_FX, DamageOverTime.FX_FLAG_COORDS, EXCLUSIVITY_NET) DummyUnitStack.delayedRelease(dummy, 3.) end GroupRemoveUnit(grp, iter) end end function periodic takes nothing returns nothing integer index = 0 NetData tempDat unit iter loop exitwhen index > dbIndex tempDat = dataDb[index] real dX = tempDat.dummy.getX() real dY = tempDat.dummy.getY() bool hit = false tempDat.dummy..setX(dX + tempDat.delX) ..setY(dY + tempDat.delY) ..setFlyHeight(50., 0.) tempDat.distance -= NET_VELOCITY * CLOCK_PERIOD // Check if a beast has been struck. GroupEnumUnitsInRange(grp, dX, dY, COLLISION_RADIUS, null) loop iter = FirstOfGroup(grp) exitwhen iter == null if IsUnitEnemy(iter, tempDat.caster) and UnitAlive(iter) hit = true exitwhen true end GroupRemoveUnit(grp, iter) end if hit or tempDat.distance < 0. strikeUnits(dX, dY, tempDat.caster) // Clean up this instance tempDat.attached.destr() DummyUnitStack.delayedRelease(tempDat.dummy, 3.) dataDb[index] = dataDb[dbIndex] dbIndex-- index-- if dbIndex == -1 PauseTimer(clock) end end index++ end end function act takes nothing returns nothing NetData nd if GetSpellAbilityId() == NET_ID then unit tU = GetTriggerUnit() real uX = GetUnitX(tU) real uY = GetUnitY(tU) real ang = Atan2(GetSpellTargetY() - uY, GetSpellTargetX() - uX) nd = new NetData() nd.delX = NET_VELOCITY * Cos(ang) * CLOCK_PERIOD nd.delY = NET_VELOCITY * Sin(ang) * CLOCK_PERIOD nd.caster = GetOwningPlayer(tU) nd.distance = MAX_DISTANCE nd.dummy = DummyUnitStack.get() nd.attached = AddSpecialEffectTarget(NET_MODEL, nd.dummy, "origin") nd.dummy..setX(uX)..setY(uY)..setOwner(nd.caster, true) dbIndex++ dataDb[dbIndex] = nd if dbIndex == 0 TimerStart(clock, CLOCK_PERIOD, true, function periodic) end end end function init takes nothing returns nothing registerPlayerUnitEvent(EVENT_PLAYER_UNIT_SPELL_EFFECT, function act) end endscope