I am trying to create an ability. It should shoot a missile towards the middle of the target location and when it arrives at the location it should start an aoe pull effect that pulls all enemies towards the middle.
I was trying to do it myself and it was almost working. But I kept trying to mess around with it and got new and new problems. So I am here and hope for someone that can give it a fix.
I would appreciate it a lot, I am sure right now I am just making it worse
This is what I have right now.
I was trying to do it myself and it was almost working. But I kept trying to mess around with it and got new and new problems. So I am here and hope for someone that can give it a fix.
I would appreciate it a lot, I am sure right now I am just making it worse
This is what I have right now.
JASS:
library Vacuum initializer Init requires TimerUtils
globals
private constant integer ABILITY_ID = 'A0LD'
private constant integer PROJECTILE_UNIT_ID = 'h031'
private constant real VACUUM_RADIUS = 400.0
private constant real PULL_INTERVAL = 0.03
private constant real PULL_DISTANCE = 15.0
private constant real PROJECTILE_SPEED = 1000.0
private constant real VACUUM_DURATION = 1.0
endglobals
struct VacuumData
unit caster
unit projectile
real targetX
real targetY
real duration
group units
timer pullTimer
static method create takes unit caster, real x, real y returns VacuumData
local VacuumData data = VacuumData.allocate()
set data.caster = caster
set data.targetX = x
set data.targetY = y
set data.duration = VACUUM_DURATION
set data.units = null
set data.projectile = CreateUnit(GetOwningPlayer(caster), PROJECTILE_UNIT_ID, GetUnitX(caster), GetUnitY(caster), 0)
set data.pullTimer = null
return data
endmethod
method onDestroy takes nothing returns nothing
call DestroyGroup(this.units)
call RemoveUnit(this.projectile)
if this.pullTimer != null then
call ReleaseTimer(this.pullTimer)
endif
call this.deallocate()
endmethod
endstruct
private function Vacuum_PullEffect takes nothing returns nothing
local VacuumData data = GetTimerData(GetExpiredTimer())
local unit u
local real x
local real y
local real angle
if data.units == null then
set data.units = CreateGroup()
call GroupEnumUnitsInRange(data.units, data.targetX, data.targetY, VACUUM_RADIUS, null)
endif
set data.duration = data.duration - PULL_INTERVAL
if data.duration <= 0 then
call data.destroy()
return
endif
loop
set u = FirstOfGroup(data.units)
exitwhen u == null
call GroupRemoveUnit(data.units, u)
if not IsUnitType(u, UNIT_TYPE_MAGIC_IMMUNE) and not IsUnitType(u, UNIT_TYPE_STRUCTURE) then
set x = GetUnitX(u)
set y = GetUnitY(u)
set angle = Atan2(data.targetY - y, data.targetX - x)
// Ensure unit can be positioned safely
if IsTerrainPathable(x + PULL_DISTANCE * Cos(angle), y + PULL_DISTANCE * Sin(angle), PATHING_TYPE_WALKABILITY) then
call SetUnitPosition(u, x + PULL_DISTANCE * Cos(angle), y + PULL_DISTANCE * Sin(angle))
endif
endif
endloop
endfunction
private function OnProjectileMove takes nothing returns nothing
local timer t = GetExpiredTimer()
local VacuumData data = GetTimerData(t)
local real projX = GetUnitX(data.projectile)
local real projY = GetUnitY(data.projectile)
local real angle = Atan2(data.targetY - projY, data.targetX - projX)
local real newX = projX + PROJECTILE_SPEED * PULL_INTERVAL * Cos(angle)
local real newY = projY + PROJECTILE_SPEED * PULL_INTERVAL * Sin(angle)
// Move projectile towards the target
call SetUnitX(data.projectile, newX)
call SetUnitY(data.projectile, newY)
if (newX - data.targetX) * (newX - data.targetX) + (newY - data.targetY) * (newY - data.targetY) <= 100.0 then
set data.pullTimer = NewTimer()
call SetTimerData(data.pullTimer, data)
call TimerStart(data.pullTimer, PULL_INTERVAL, true, function Vacuum_PullEffect)
call ReleaseTimer(t)
endif
endfunction
private function LaunchProjectile takes unit caster, real x, real y returns nothing
local VacuumData data = VacuumData.create(caster, x, y)
local timer t = NewTimer()
call SetTimerData(t, data)
call TimerStart(t, PULL_INTERVAL, true, function OnProjectileMove)
endfunction
private function OnCast takes nothing returns nothing
local unit caster = GetTriggerUnit()
local real x = GetSpellTargetX()
local real y = GetSpellTargetY()
if GetSpellAbilityId() == ABILITY_ID then
call LaunchProjectile(caster, x, y)
endif
endfunction
private function Init takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddAction(t, function OnCast)
endfunction
endlibrary