• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

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.
 
Top