library ThunderBolt requires TimerUtils, xefx, xedamage, optional BoundSentinel
//--------------------------------------------------------------------------------------------
// Thunder Bolt v1.01 by scorpion182
// requires:
// [-x-] TimerUtils, BoundSentinel, xe by vexorian
//
//--------------------------------------------------------------------------------------------
//----CALIBRATION SECTION---------------------------------------------------------------------
globals
private constant integer SPELL_ID='A001' //spell id
private constant real BOLT_SCALE=2. //bolt scale
private constant real BOLT_H=100. //bolt height
private constant string BOLT_PATH="Abilities\\Weapons\\FarseerMissile\\FarseerMissile.mdl" //bolt effect
private constant string BOLT_FLASH="Abilities\\Spells\\Other\\Monsoon\\MonsoonBoltTarget.mdl" //bolt on-destroy effect
private constant string LWAVE_PATH="Abilities\\Weapons\\Bolt\\BoltImpact.mdl" //lightning wave effect
private constant integer MAX_LWAVE=50 //maximum lightning wave
private constant real MIN_DIST=100. //distance between wave
private constant string DAMAGE_FX="" //effect on-damage
private constant string DAMAGE_ATTCH="origin" //damage effect attachment point
private constant boolean PRELOAD_FX=true //preload fx?
endglobals
private constant function GetSpeed takes integer lvl returns real
return lvl*0.+800.*XE_ANIMATION_PERIOD //missile speed
endfunction
private constant function GetDistance takes integer lvl returns real
return lvl*0+100. //distance between wave
endfunction
private constant function GetAoE takes integer lvl returns real
return lvl*0+400. //area of effect, must match with object editor field
endfunction
private constant function GetCount takes integer lvl returns integer
return lvl*0+8 //lightning wave count
endfunction
private constant function GetDamage takes integer lvl returns real
return 100.+lvl*0 //deal damage per second
endfunction
private constant function GetCollision takes integer lvl returns real
return 100.+lvl*0 //lighting wave collision size
endfunction
//damage filter
private function DamageOptions takes xedamage spellDamage returns nothing
set spellDamage.dtype=DAMAGE_TYPE_UNIVERSAL
set spellDamage.atype=ATTACK_TYPE_NORMAL
set spellDamage.exception=UNIT_TYPE_STRUCTURE //don't damage building
set spellDamage.visibleOnly=true //only damage visible unit
set spellDamage.damageAllies=false //damage allies if true
set spellDamage.damageTrees=true //damage destructables?
endfunction
//--------END OF CALIBRATION------------------------------------------------------------------
globals
private xedamage xed
endglobals
private struct wave
unit caster
timer t
xefx fx
real distdone=0
real distance
integer lvl
boolean wave
real wave_dis=0
static method onLoop takes nothing returns nothing
local wave this=wave(GetTimerData(GetExpiredTimer()))
if .distdone<.distance then
if .wave then
set .wave_dis=.wave_dis+GetSpeed(.lvl)
if (.wave_dis>=MIN_DIST) then
call DestroyEffect(AddSpecialEffect(LWAVE_PATH,.fx.x,.fx.y))
set .wave_dis=0
endif
endif
call xed.damageAOE(.caster,.fx.x,.fx.y,GetCollision(.lvl),GetDamage(.lvl)*XE_ANIMATION_PERIOD)
set .distdone=.distdone+GetSpeed(.lvl)
set .fx.x=.fx.x+GetSpeed(.lvl)*Cos(.fx.xyangle)
set .fx.y=.fx.y+GetSpeed(.lvl)*Sin(.fx.xyangle)
else
call .destroy()
endif
endmethod
static method create takes unit c, real x, real y, real a, real dis, boolean iswave returns wave
local wave this=wave.allocate()
set .t=NewTimer()
set .caster=c
set .fx=xefx.create(x,y,a)
set .fx.scale=BOLT_SCALE
set .wave=iswave
if not .wave then
set .fx.fxpath=BOLT_PATH
endif
set .fx.z=BOLT_H
set .distance=dis
set .lvl=GetUnitAbilityLevel(c,SPELL_ID)
call SetTimerData(.t,this)
call TimerStart(.t,XE_ANIMATION_PERIOD,true,function wave.onLoop)
return this
endmethod
private method onDestroy takes nothing returns nothing
call ReleaseTimer(.t)
if not .wave then
call .fx.flash(BOLT_FLASH)
endif
call .fx.destroy()
endmethod
endstruct
globals
private constant real A=2*bj_PI
endglobals
private struct data
wave array missile[MAX_LWAVE]
timer t
integer total
real distance
real x
real y
unit caster
private method onDestroy takes nothing returns nothing
call ReleaseTimer(.t)
endmethod
static method onFinish takes nothing returns nothing
local data this=data(GetTimerData(GetExpiredTimer()))
local integer i=0
loop
exitwhen i==.total
set .missile[i]=wave.create(.caster,.x,.y,i*A/.total,.distance,true)
set i=i+1
endloop
call .destroy()
endmethod
static method create takes unit c, real x, real y, real dis, integer count, real time returns data
local data this=data.allocate()
set .total=count
set .caster=c
set .x=x
set .y=y
set .distance=dis
set .t=NewTimer()
call SetTimerData(.t,this)
call TimerStart(.t,time,false,function data.onFinish)
return this
endmethod
static method SpellEffect takes nothing returns boolean
local data this
local wave m
local unit c=GetTriggerUnit()
local real x=GetUnitX(c)
local real y=GetUnitY(c)
local real tx=GetSpellTargetX()
local real ty=GetSpellTargetY()
local real angle=Atan2(ty-y,tx-x)
local real dx=tx-x
local real dy=ty-y
local real dis=SquareRoot(dx*dx+dy*dy)
local real time
if GetSpellAbilityId()==SPELL_ID then
set m=wave.create(c,x,y,angle,dis,false)
set time=dis/(GetSpeed(m.lvl)/XE_ANIMATION_PERIOD)
set this=data.create(c,tx,ty,GetAoE(m.lvl),GetCount(m.lvl),time)
endif
set c=null
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,Condition(function data.SpellEffect))
//init xedamage
set xed=xedamage.create()
call DamageOptions(xed)
call xed.useSpecialEffect(DAMAGE_FX,DAMAGE_ATTCH)
//preload fx
static if PRELOAD then
call Preload(BOLT_PATH)
call Preload(BOLT_FLASH)
call Preload(LWAVE_PATH)
call Preload(DAMAGE_FX)
endif
endmethod
endstruct
endlibrary