scope Fireball /*v1.0.0.0
*************************************************************************************
*
* The caster hurls a fireball towards the target location,
* dealing damage in a small aoe on impact.
*
*************************************************************************************
*
* uses CTL, Dummy, WorldBounds
* optional SpellEffectEvent
*
*************************************************************************************
*
* Credits
*
* To Nestharus
* -----------------------
*
* For CTL, UnitIndexer, WorldBounds, Event, ErrorMessage, Alloc, Dummy
*
* To Bribe
* -----------------------
*
* For SpellEffectEvent
*
*
****************************************************************************
*
* SETTINGS
*
*/
globals
private constant integer FIREBALL_ABILITY = 'A007'//Ability raw-code of Fireball
private constant attacktype ATTACK_TYPE = ATTACK_TYPE_NORMAL
private constant damagetype DAMAGE_TYPE = DAMAGE_TYPE_MAGIC
/*
* FLY_HEIGHT is the height of the fireball towards the ground.
* DETECTION_AOE is the range the fireball searches for targets.
*/
private constant real FLY_HEIGHT = 65.
private constant real DETECTION_AOE = 48.
/*
* Effects
*
* SCALE is the scaling of the fireball dummy.
* MODEL is the model of the fireball .(in case you change it it could be any missle)
* EXPLODE is the model used for the explosion effect, note this effect can't scaled.
*/
private constant real SCALE = 1.
private constant string MODEL = "Abilities\\Weapons\\FireBallMissile\\FireBallMissile.mdl"
private constant string EXPLODE = "Abilities\\Spells\\Other\\Incinerate\\FireLordDeathExplode.mdl"
endglobals
native UnitAlive takes unit id returns boolean
//Filter out which units take damage on impact.
private function TargetFilter takes unit target, player owner returns boolean
return UnitAlive(target) and IsUnitEnemy(target, owner) and not IsUnitType(target, UNIT_TYPE_STRUCTURE)
endfunction
//Filter out if the fireball should explode.
private function ExplosionFilter takes unit target, player owner returns boolean
return (UnitAlive(target) and IsUnitEnemy(target, owner)) or IsUnitType(target, UNIT_TYPE_STRUCTURE)
endfunction
//The maximum time the fireball lasts.
private constant function GetFlyTime takes integer level returns real
return 1.25 + (0.25*level)
endfunction
//The Aoe in which damage is applied.
private constant function GetExplosionRadius takes integer level returns real
return 200. + (0*level)
endfunction
//The speed the fireball has is measured in movementspeed.
private constant function GetSpeed takes integer level returns real
return 640. + (0*level)
endfunction
//The aoe damage on impact.
private constant function GetDamage takes integer level returns real
return 70. + (70.*level)
endfunction
/*
* END OF SETTINGS
*/
private module init
private static method onInit takes nothing returns nothing
static if LIBRARY_SpellEffectEvent then
call RegisterSpellEffectEvent(FIREBALL_ABILITY, function thistype.run)
else
local trigger t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(t, Condition(function thistype.check))
set t = null
endif
endmethod
endmodule
private struct F extends array
static group enu = CreateGroup()
static constant real TIMEOUT = 0.031250000
player owner
unit caster
Dummy ball//Dummy used for the fireball
effect sfx//Model of the fireball
real dmg
real x
real y
real cos//Offset
real sin
real rad//Explosion Aoe
integer t
implement CTL
local unit u
implement CTLExpire
if (t > 0) then
set t = t - 1
set x = x + cos
set y = y + sin
if (x < WorldBounds.maxX) and (x > WorldBounds.minX) and (y < WorldBounds.maxY) and (y > WorldBounds.minY) then
call SetUnitX(ball.unit, x)
call SetUnitY(ball.unit, y)
call GroupEnumUnitsInRange(enu, x, y, DETECTION_AOE, null)
loop
set u = FirstOfGroup(enu)
exitwhen u == null
call GroupRemoveUnit(enu, u)
/*
* One of tousand ways to
* exit a loop on impact.
*/
if (ExplosionFilter(u, owner)) then
set t = 0
exitwhen true
endif
endloop
call GroupClear(enu)
if (t == 0) then
call GroupEnumUnitsInRange(enu, x, y, rad, null)
loop
set u = FirstOfGroup(enu)
exitwhen u == null
call GroupRemoveUnit(enu, u)
if (TargetFilter(u, owner)) then
call UnitDamageTarget(caster, u, dmg, false, false, ATTACK_TYPE, DAMAGE_TYPE, null)
endif
endloop
endif
else
set t = 0
endif
else
call DestroyEffect(sfx)
call DestroyEffect(AddSpecialEffect(EXPLODE, x, y))
call SetUnitScale(ball.unit, 1, 1,1)
call ball.destroy()
set owner = null
set caster= null
set sfx = null
call destroy()
endif
implement CTLEnd
private static method run takes nothing returns boolean
local thistype this = create()
local real angle
local integer lvl
local real speed
set owner = GetTriggerPlayer()
set caster = GetTriggerUnit()
set lvl = GetUnitAbilityLevel(caster, FIREBALL_ABILITY)
set dmg = GetDamage(lvl)
set rad = GetExplosionRadius(lvl)
set t = R2I(GetFlyTime(lvl)/TIMEOUT)
set speed = GetSpeed(lvl)*TIMEOUT
set x = GetUnitX(caster)
set y = GetUnitY(caster)
set angle = Atan2(GetSpellTargetY() - y, GetSpellTargetX() - x)
set cos = speed*Cos(angle)
set sin = speed*Sin(angle)
set x = x + cos
set y = y + sin
set ball = Dummy.create(x, y, angle*bj_RADTODEG)
set sfx = AddSpecialEffectTarget(MODEL, .ball.unit, "origin")
call SetUnitScale(ball.unit, SCALE, 1,1)
call SetUnitFlyHeight(ball.unit, FLY_HEIGHT, 0)
return false
endmethod
static if not LIBRARY_SpellEffectEvent then
private static method check takes nothing returns boolean
if (GetSpellAbilityId() == FIREBALL_ABILITY) then
call thistype.run()
endif
return false
endmethod
endif
implement init
endstruct
endscope