scope Firestorm initializer OnInit
//=====================================================================//
// CONFIGURATION //
//=====================================================================//
globals
private constant integer ABILID = 'ABFS' // raw code of ability "Firestorm"
private constant integer DUMMYID = 'h002' // raw code of unit "Firestorm Dummy"
private constant real AOE = 500.0 // area of effect
private constant real MAXHEIGHT = 500.0 // maximum height of fireballs
private constant real SPEED = 1000.0 // knockback speed (per second)
private constant real HRATE = 250.0 // rate of change in height (per second)
private constant real OFFRATE = 500.0 // rate of change in distance (per second)
private constant real KNOCKBACK = 300.00 // knockback distance
endglobals
private function GetFireCount takes integer level returns integer
return level * 3 // number of fireballs
endfunction
private function GetDamage takes integer level returns real
return level * 50.0 // damage per fireball
endfunction
//=====================================================================//
// END CONFIGURATION //
//=====================================================================//
//Don't touch unless you know what you're doing
globals
private hashtable HASH = InitHashtable()
private group GROUP = CreateGroup()
private unit FILTER
private unit CASTER
private unit FIRE
endglobals
native UnitAlive takes unit id returns boolean
private struct Firestorm
real damage
real interval
integer count
group firegroup
unit caster
endstruct
private struct Knockback
real damage
real height
real speed
real interval
real x
real y
real angle
real dist
boolean check
unit caster
unit fire
unit target
endstruct
private function GroupFilter takes nothing returns boolean
local unit u = GetFilterUnit()
if IsUnitEnemy(u, GetOwningPlayer(CASTER)) and UnitAlive(u) and not IsUnitType(u, UNIT_TYPE_STRUCTURE) and not LoadBoolean(HASH, GetHandleId(u), 0) then
set FILTER = u
endif
set u = null
return false
endfunction
private function GroupFunc takes nothing returns nothing
local real x = GetUnitX(FILTER)
local real y = GetUnitY(FILTER)
local real mindist = 99999.0
local unit u = GetEnumUnit()
local real dx = GetUnitX(u) - x
local real dy = GetUnitY(u) - y
local real dist = SquareRoot(dx * dx + dy * dy)
if dist < mindist then
set FIRE = u
set mindist = dist
endif
set u = null
endfunction
private function DamageKnock takes nothing returns boolean
local Knockback k = KT_GetData()
local real dx
local real dy
local real x
local real y
local real a
local effect e
if k.dist <= 0 and k.check then
call k.destroy()
call SaveBoolean(HASH, GetHandleId(k.target), 0, false)
call FlushChildHashtable(HASH, GetHandleId(k.target))
set e = null
return true
endif
if k.check then
set x = GetUnitX(k.target)
set y = GetUnitY(k.target)
set a = Atan2(y - k.y, x - k.x)
set x = x + k.speed * Cos(k.angle)
set y = y + k.speed * Sin(k.angle)
call SetUnitPosition(k.target, x, y)
set k.dist = k.dist - k.speed
else
set dx = GetUnitX(k.fire)
set dy = GetUnitY(k.fire)
set x = GetUnitX(k.target) - dx
set y = GetUnitY(k.target) - dy
if SquareRoot(x * x + y * y) <= 50 then
call UnitDamageTarget(k.caster, k.target, k.damage, true, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_NORMAL, WEAPON_TYPE_WHOKNOWS)
set e = AddSpecialEffect("Abilities\\Weapons\\RedDragonBreath\\RedDragonMissile.mdl", dx, dy)
call DestroyEffect(e)
set e = AddSpecialEffect("Objects\\Spawnmodels\\Other\\NeutralBuildingExplosion\\NeutralBuildingExplosion.mdl", dx, dy)
call DestroyEffect(e)
set k.x = GetUnitX(k.caster)
set k.y = GetUnitY(k.caster)
set k.dist = KNOCKBACK
set k.angle = Atan2(GetUnitY(k.target) - dy, GetUnitX(k.target) - dx)
call RemoveUnit(k.fire)
set k.check = true
else
set k.height = (GetUnitFlyHeight(k.fire) - 50) / ((SquareRoot(x * x + y * y) / SPEED) / k.interval)
call SetUnitFlyHeight(k.fire, GetUnitFlyHeight(k.fire) - k.height, 0)
set x = x + dx
set y = y + dy
set a = Atan2(y - dy, x - dx)
set x = dx + k.speed * Cos(a)
set y = dy + k.speed * Sin(a)
call SetUnitPosition(k.fire, x, y)
call SetUnitFacing(k.fire, a * bj_RADTODEG)
endif
endif
set e = null
return false
endfunction
globals
private group Periodic_group
endglobals
private function Periodic takes nothing returns boolean
local Firestorm d = KT_GetData()
local Knockback k
local real a
local real x
local real y
local real dx = GetUnitX(d.caster)
local real dy = GetUnitY(d.caster)
local real r
local real min
local real max
local unit u
if d.count == 0 then
call Group.release(d.firegroup)
call d.destroy()
return true
endif
set CASTER = d.caster
set FILTER = null
call GroupEnumUnitsInRange(GROUP, GetUnitX(d.caster), GetUnitY(d.caster), AOE, Filter(function GroupFilter))
if FILTER != null then
set k = Knockback.create()
call ForGroup(d.firegroup, function GroupFunc)
set k.damage = d.damage
set k.speed = d.interval * SPEED
set k.interval = 0.04
set k.check = false
set k.caster = d.caster
set k.fire = FIRE
set k.target = FILTER
call SaveBoolean(HASH, GetHandleId(k.target), 0, true)
call KT_Add(function DamageKnock, k, k.interval)
call FlushChildHashtable(HASH, GetHandleId(k.fire))
call GroupRemoveUnit(d.firegroup, FIRE)
set d.count = d.count - 1
endif
set Periodic_group = Group.get()
call GroupAddGroup(d.firegroup, Periodic_group)
loop
set u = FirstOfGroup(Periodic_group)
exitwhen u == null
set x = GetUnitX(u) - dx
set y = GetUnitY(u) - dy
set a = GetUnitFacing(u)
if SquareRoot(x * x + y * y) >= AOE then
set a = a + GetRandomReal(0, 90.0)
call SaveBoolean(HASH, GetHandleId(u), 0, true)
elseif SquareRoot(x * x + y * y) <= 150.0 then
set a = a + GetRandomReal(-90.0, 0)
call SaveBoolean(HASH, GetHandleId(u), 0, false)
else
if LoadBoolean(HASH, GetHandleId(u), 0) then
set a = a + GetRandomReal(-15.0, 45.0)
else
set a = a + GetRandomReal(-45.0, 15.0)
endif
endif
set x = GetUnitX(u) + GetRandomReal(0, (d.interval * OFFRATE)) * Cos(a * bj_DEGTORAD)
set y = GetUnitY(u) + GetRandomReal(0, (d.interval * OFFRATE)) * Sin(a * bj_DEGTORAD)
set a = 90.0 + (Atan2(y - dy, x - dx) * bj_RADTODEG)
call SetUnitPosition(u, x, y)
call SetUnitFacing(u, a)
set r = GetUnitFlyHeight(u)
if not LoadBoolean(HASH, GetHandleId(u), 1) then
if r >= MAXHEIGHT then
call SaveBoolean(HASH, GetHandleId(u), 1, true)
set r = 0
else
set r = GetRandomReal(0.0, d.interval * HRATE)
endif
else
if r <= 50 then
call SaveBoolean(HASH, GetHandleId(u), 1, false)
set r = 0
else
set r = GetRandomReal(-d.interval * HRATE, 0)
endif
endif
set r = GetUnitFlyHeight(u) + r
call SetUnitFlyHeight(u, r, 0)
call GroupRemoveUnit(Periodic_group, u)
endloop
call Group.release(Periodic_group)
return false
endfunction
private function Actions takes nothing returns nothing
local Firestorm d = Firestorm.create()
local real a
local real x
local real y
local integer i
local integer loopmax
local integer level
local unit u
set d.caster = GetTriggerUnit()
set d.firegroup = Group.get()
set level = GetUnitAbilityLevel(d.caster, ABILID)
set d.damage = GetDamage(level)
set d.interval = 0.04
set d.count = 0
set loopmax = GetFireCount(level)
set i = 0
loop
exitwhen i == loopmax
set x = GetUnitX(d.caster) + GetRandomReal(100.0, AOE) * Cos(GetRandomReal(0.0, 360.0) * bj_DEGTORAD)
set y = GetUnitY(d.caster) + GetRandomReal(100.0, AOE) * Sin(GetRandomReal(0.0, 360.0) * bj_DEGTORAD)
set a = 90.0 + Atan2(y - GetUnitY(d.caster), x - GetUnitX(d.caster)) * bj_RADTODEG
set u = CreateUnit(GetOwningPlayer(d.caster), DUMMYID, x, y, a)
call SetUnitFlyHeight(u, GetRandomReal(50.0, MAXHEIGHT), 0)
call SaveBoolean(HASH, GetHandleId(u), 0, false)
call SaveBoolean(HASH, GetHandleId(u), 1, false)
call GroupAddUnit(d.firegroup, u)
set d.count = d.count + 1
set i = i + 1
endloop
call KT_Add(function Periodic, d, d.interval)
set u = null
endfunction
private function Conditions takes nothing returns boolean
return GetSpellAbilityId() == ABILID
endfunction
private function OnInit takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(t, Condition(function Conditions))
call TriggerAddAction(t, function Actions)
endfunction
endscope