scope FireBall initializer init
//=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=
//= Exploding Fireball Spell By Ciebron *=
//= *=
//= A request by Starquizer *=
//= *=
//=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=
//=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*Setup Starts=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=
//=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=
globals
private constant integer Abil_id = 'A000'
//Rawcode of the Ability
private constant integer Dummy_id = 'h000'
//Rawcode of the Dummy projectile
private constant integer Nova_id = 'h001'
//Rawcode of the Dummy's that will make the nova
private constant real Curve = 6
//A value used by the JumpParabola (lower number makes it go higher and the other way around)
private constant real Move_Dist = 30.
//How much the Projectile will move Every interval
private constant real Nova_MDist = 20.
//How much the Nova will Expand every interval
private constant real Aoe = 300.
//How big the Aoe will be
private constant integer Nova_Size = 16
//Number of the dummys that will make the nova
private constant attacktype AtkType = ATTACK_TYPE_MAGIC
//Attack Type of the spell
private constant damagetype DmgType = DAMAGE_TYPE_MAGIC
//Damage Type of the spell
private constant real Interval = 0.03
//Freqency of the spell
private constant real NInterval = 0.03
//Freqency of the Nova to expand
endglobals
//This function is based on the level of the spell
private function Damage takes integer level returns real
return 125.+(50.*level)
endfunction
//=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=
//=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*Setup Ends=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=
//=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=
//A JumpParabola that make so the projectile arc nicely
//Credits to Shadow1500
function JumpParabola takes real dist, real maxdist, real curve returns real
local real t = (dist * 2) / maxdist - 1
return (- t * t + 1) * (maxdist / curve)
endfunction
globals
//Used by the spell don't touch these :)
private integer Struct
private boolexpr Bool
endglobals
private struct NovaData
unit u
unit array dummy [Nova_Size]
player P
real dist
real x
real y
real array cos [Nova_Size]
real array sin [Nova_Size]
real damage
group g
static group G = CreateGroup()
static integer Total = 0
static integer array Ar
static timer Time = CreateTimer()
static integer index
static unit TempU
static method create takes unit u,real x,real y,real dmg returns NovaData
local NovaData Dat = NovaData.allocate()
local integer i = 0
local real a = 0
local real ai = 360/Nova_Size
set Dat.u = u
set Dat.x = x
set Dat.y = y
set Dat.dist = 0.
set Dat.damage = dmg
loop
exitwhen i >= Nova_Size
set Dat.dummy[i] = CreateUnit(GetOwningPlayer(Dat.u),Nova_id,x,y,a)
set Dat.cos[i] = Cos(a*bj_DEGTORAD)
set Dat.sin[i] = Sin(a*bj_DEGTORAD)
set a = a + ai
set i = i + 1
endloop
if Dat.Total == 0 then
call TimerStart(Dat.Time,NInterval,true,function NovaData.Loop)
endif
set Dat.Ar[Dat.Total] = Dat
set Dat.Total = Dat.Total + 1
return Dat
endmethod
static method Loop takes nothing returns nothing
local NovaData Dat
local integer i = 0
loop
exitwhen i >= Dat.Total
set Dat = Dat.Ar[i]
set Dat.index = 0
set Dat.dist = Dat.dist + Nova_MDist
loop
exitwhen Dat.index >= Nova_Size
call SetUnitX(Dat.dummy[Dat.index],Dat.x+Dat.dist*Dat.cos[Dat.index])
call SetUnitY(Dat.dummy[Dat.index],Dat.y+Dat.dist*Dat.sin[Dat.index])
set Dat.index = Dat.index + 1
endloop
set Struct = Dat
call GroupEnumUnitsInRange(Dat.G,Dat.x,Dat.y,Dat.dist,Bool)
loop
set Dat.TempU = FirstOfGroup(Dat.G)
exitwhen Dat.TempU == null
call GroupRemoveUnit(Dat.G,Dat.TempU)
call UnitDamageTarget(Dat.u,Dat.TempU,Dat.damage,false,false,AtkType,DmgType,null)
endloop
if Dat.dist >= Aoe then
set Dat.index = 0
loop
exitwhen Dat.index >= Nova_Size
call KillUnit(Dat.dummy[Dat.index])
set Dat.index = Dat.index + 1
endloop
set Dat.Total = Dat.Total - 1
set Dat.Ar[i] = Dat.Ar[Dat.Total]
set i = i - 1
call Dat.destroy()
endif
set i = i + 1
endloop
if Dat.Total == 0 then
call PauseTimer(Dat.Time)
endif
endmethod
static method UnitFilter takes nothing returns boolean
local NovaData Dat = Struct
local unit f = GetFilterUnit()
local boolean ok = GetWidgetLife(f) <= .305 and IsUnitEnemy(f,Dat.P) and not IsUnitType(f,UNIT_TYPE_MAGIC_IMMUNE)
set f = null
return ok
endmethod
method onDestroy takes nothing returns nothing
local integer i = 0
set .u = null
loop
exitwhen i >= Nova_Size
set .dummy[i] = null
set i = i + 1
endloop
endmethod
endstruct
private struct Data
unit u
unit Dummy
real cos
real sin
real dist
real maxdist
real damage
static integer Total = 0
static integer array Ar
static timer Time = CreateTimer()
static real z
static real x
static real y
static method create takes unit u,real x,real y returns Data
local Data Dat = Data.allocate()
local real ux = GetUnitX(u)
local real uy = GetUnitY(u)
local real DistX = x-ux
local real DistY = y-uy
local real a = Atan2(DistY,DistX)
set Dat.u = u
set Dat.Dummy = CreateUnit(GetOwningPlayer(Dat.u),Dummy_id,ux,uy,a*bj_RADTODEG)
set Dat.cos = Cos(a)
set Dat.sin = Sin(a)
set Dat.maxdist = SquareRoot(DistX*DistX+DistY*DistY)
set Dat.dist = 0
set Dat.damage = Damage(GetUnitAbilityLevel(Dat.u,Abil_id))
if Dat.Total == 0 then
call TimerStart(Dat.Time,Interval,true,function Data.Loop)
endif
set Dat.Ar[Dat.Total] = Dat
set Dat.Total = Dat.Total + 1
set u = null
return Dat
endmethod
static method Loop takes nothing returns nothing
local Data Dat
local integer i = 0
loop
exitwhen i >= Dat.Total
set Dat = Dat.Ar[i]
set Dat.dist = Dat.dist + Move_Dist
set Dat.z = JumpParabola(Dat.dist,Dat.maxdist,Curve)
set Dat.x = GetUnitX(Dat.Dummy)+Move_Dist*Dat.cos
set Dat.y = GetUnitY(Dat.Dummy)+Move_Dist*Dat.sin
call SetUnitFlyHeight(Dat.Dummy,Dat.z,0.)
call SetUnitX(Dat.Dummy,Dat.x)
call SetUnitY(Dat.Dummy,Dat.y)
if Dat.z <= 0. then
call KillUnit(Dat.Dummy)
call NovaData.create(Dat.u,Dat.x,Dat.y,Dat.damage)
set Dat.Total = Dat.Total - 1
set Dat.Ar[i] = Dat.Ar[Dat.Total]
set i = i - 1
call Dat.destroy()
endif
set i = i + 1
endloop
if Dat.Total == 0 then
call PauseTimer(Dat.Time)
endif
endmethod
method onDestroy takes nothing returns nothing
set .u = null
set .Dummy = null
endmethod
endstruct
private function OnCast takes nothing returns boolean
local unit u
local location Tloc
if GetSpellAbilityId()==Abil_id then
set u = GetTriggerUnit()
set Tloc = GetSpellTargetLoc()
call Data.create(u,GetLocationX(Tloc),GetLocationY(Tloc))
call RemoveLocation(Tloc)
set Tloc = null
set u = null
endif
return false
endfunction
private function init takes nothing returns nothing
local trigger trig = CreateTrigger()
local integer index = 0
loop
call TriggerRegisterPlayerUnitEvent(trig, Player(index),EVENT_PLAYER_UNIT_SPELL_EFFECT, null)
set index = index + 1
exitwhen index == bj_MAX_PLAYER_SLOTS
endloop
//We use condition instead of action because condition is faster
call TriggerAddCondition(trig,Condition(function OnCast))
//Setting the Boolexpr filter
set Bool = Filter(function NovaData.UnitFilter)
set trig = null
endfunction
endscope