Thunder Bolt v1.01

Thunder Bolt

Conjures a thunder ball which will explode into waves of lightning at targeted point.


JASS:
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



Requires:
- TimerUtils by Vexorian
- xe by Vexorian
- BoundSentinel by Vexorian

History
~ v1.00 First Release.
~ v1.01 Fixed destructables issues :D.

Keywords:
lightning, bolt, area, damage, group, ground, electric, wave, thunder, whatever
Contents

Thunder Bolt v1.01 (Map)

Reviews
10:43, 30th Jan 2010 TriggerHappy: Very cool and overall it's good enough to be approved. You could store the targetX/Y to save two function calls. GetSpellAbilityUnit -> GetTriggerUnit. I don't see the point in storing the timer, you...

Moderator

M

Moderator

10:43, 30th Jan 2010
TriggerHappy:

Very cool and overall it's good enough to be approved.

  • You could store the targetX/Y to save two function calls.
  • GetSpellAbilityUnit -> GetTriggerUnit.
  • I don't see the point in storing the timer, you could just inline the release before you call .destroy instead of using onDestroy.
 
Level 14
Joined
Nov 18, 2007
Messages
1,084
Nice visual effects and execution!
I only have a few minor comments:

  • Could you have used xed.damageAOE instead?
  • Could you have done
    JASS:
    call xed.useSpecialEffect(DAMAGE_FX,DAMAGE_ATTCH)
    inside the function DamageOptions?
  • How come you use GetSpellAbilityUnit() instead of GetTriggerUnit()?
 
Top