library FireEscort uses CTL
globals
private constant integer SPELL_ID = 'A002' //Howl of Terror(rawID)
private constant integer DUMMY_SPELL_ID = 'A000' //Firebolt(rawID)
private constant integer ORDER_ID = 852231 //Firebolt
private constant integer DUMMY_ID = 'h000' //rawID
private constant integer BOMB_ID = 'h001' //rawID
private constant real INTERVAL = 0.03125
endglobals
native UnitAlive takes unit u returns boolean
//! textmacro SE takes UNT
set x = GetUnitX($UNT$)
set y = GetUnitY($UNT$)
set angle = Atan2(y-yDum, x-xDum)
set distance = getDistance(x,y,xDum,yDum)
loop
exitwhen index==maxbombs
call SetUnitX(.d[index], xDum+.offset*Cos(.gap[index]))
call SetUnitY(.d[index], yDum+.offset*Sin(.gap[index]))
call SetUnitFlyHeight(.d[index], .flyheight, 0)
set .gap[index] = .gap[index] + gapdist
set index = index + 1
endloop
if distance > distancetoreach then
call SetUnitX(.dummy, xDum+followspeed*Cos(angle))
call SetUnitY(.dummy, yDum+followspeed*Sin(angle))
endif
//! endtextmacro
private function LoadFirst takes nothing returns nothing
local unit u = CreateUnit(Player(15), DUMMY_ID,0,0,0)
call UnitAddAbility(u, DUMMY_SPELL_ID)
call KillUnit(u)
set u = null
endfunction
private struct FE
unit caster
unit target
unit dummy
unit array d[1]
real array gap[1]
real duration
real offset
real search
real flyheight
player owner
//Configurables:
static integer maxbombs = 6
static real rotationspeed = 1
static real followspeed = 7
static real gapdist = 1 //recommended for 6 bombs
static real raisespeed = 2
static real offsetspeed = 2
static real maxoffset = 300
static real aoe = 900
static real searchinterval = 2
static real maxheight = 400 //this should not be greater than your CAST RANGE
static real maxduration = 60 //sets the life of the dummy captain
static real distancetofollow = 640000 //SquareRoot is 800
static real distancetoreach = 3600 //Squareroot is 60
//==========
method getDistance takes real x1, real y1, real x2, real y2 returns real
return (x2-x1)*(x2-x1)+(y2-y1)*(y2-y1)
endmethod
method filterThem takes unit caster, unit target returns boolean
return UnitAlive(target) and IsUnitEnemy(caster,GetOwningPlayer(target)) and not (IsUnitType(target, UNIT_TYPE_STRUCTURE) and /*
*/ IsUnitType(target, UNIT_TYPE_MECHANICAL) and IsUnitType(target, UNIT_TYPE_MAGIC_IMMUNE))
endmethod
implement CTL
local unit first
local real x
local real y
local real xDum
local real yDum
local real angle
local real distance
local real distance2
local integer index
local integer dumID
implement CTLExpire
set index = 0
set dumID = GetHandleId(.dummy)
if UnitAlive(.caster) and .duration > 0 then
set .duration = .duration - INTERVAL
set xDum = GetUnitX(.dummy)
set yDum = GetUnitY(.dummy)
if .offset < maxoffset then
set .offset = .offset + offsetspeed
endif
if .flyheight < maxheight then
set .flyheight = .flyheight + raisespeed
endif
if .target==null then
//! runtextmacro SE(".caster")
set .search = search + INTERVAL
if .search > searchinterval and distance < 4000 then
call GroupEnumUnitsInRange(bj_lastCreatedGroup,xDum,yDum,aoe,null)
loop
set first = FirstOfGroup(bj_lastCreatedGroup)
exitwhen first==null
if filterThem(.caster, first) then
set .target = first
endif
call GroupRemoveUnit(bj_lastCreatedGroup, first)
endloop
set searchinterval = 0
endif
else
if UnitAlive(.target) then
//! runtextmacro SE(".target")
if .flyheight >= maxheight then
set distance2 = getDistance(GetUnitX(.caster),GetUnitY(.caster),xDum,yDum)
if distance2 < distancetofollow then
set index = 0
loop
exitwhen index==maxbombs
call IssueTargetOrderById(.d[index],ORDER_ID,.target)
set index = index + 1
endloop
else
set .target = null
endif
endif
else
set .target = null
endif
endif
else //End the Spell
call KillUnit(.dummy)
loop
exitwhen index==maxbombs
call KillUnit(.d[index])
set .d[index] = null
set index = index + 1
endloop
set .caster = null
set .target = null
set .dummy = null
call .destroy()
endif
implement CTLEnd
static method setup takes unit u, player p returns nothing
local thistype this = create()
local integer lvl = GetUnitAbilityLevel(u, SPELL_ID)
local integer index = 0
local real g = 0
local integer dumID
set .caster = u
set .target = null
set .duration = maxduration
set .owner = p
set .dummy = CreateUnit(p,DUMMY_ID,GetUnitX(u),GetUnitY(u),0)
set .offset = 0
set .flyheight = 0
set .search = 0
set dumID = GetHandleId(.dummy)
loop
exitwhen index==maxbombs
set .d[index] = CreateUnit(p,BOMB_ID,0,0,0)
set .gap[index] = g
call SetUnitFlyHeight(.d[index], 0,0)
call UnitAddAbility(.d[index], DUMMY_SPELL_ID)
call SetUnitAbilityLevel(.d[index],DUMMY_SPELL_ID, lvl)
set g = g + gapdist
set index = index + 1
endloop
endmethod
static method cast takes nothing returns boolean
if GetSpellAbilityId()==SPELL_ID then
call setup(GetTriggerUnit(), GetTriggerPlayer())
endif
return false
endmethod
static method onInit takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(t, function thistype.cast)
call LoadFirst()
set t = null
endmethod
endstruct
endlibrary