• 🏆 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!

Lightning Tendrils v1.1

So here is another spell made in vJass

Requires:
* JNGP (JassHelper 0.9.G.0)
* xDModules
* BoolexprUtils

Thanks to Vexorian for JassHelper and BoolexprUtils


The hero soars up and creates tendriles consisting of pure energy. If a tendril
hits an enemy the unit will be damaged.



Changelog
----------

v.1.1
* Implemented ForGroup loop instead of group loop
* Added Sounds
* The caster now can fly through units etc.

JASS:
//********************************************************************************************
//* Lightning Tendrils v1.1 by xD.Schurke  
//* -------------------------------------
//*
//* Requires:
//*           * JNGP (JassHelper 0.9.G.0)
//*           * xDModules
//*           * BoolexprUtils
//*
//* Thanks to Vexorian for JassHelper and BoolexprUtils
//*
//* The hero soars up and creates tendriles consisting of pure energy. If a tendril
//* hits an enemy the unit will be damaged.
//*
//*
//* Changelog
//* ----------
//* 
//* v.1.1
//*      * Implemented ForGroup loop instead of group loop
//*      * Added Sounds
//*      * The caster now can fly through units etc.
//*
//*
//********************************************************************************************
library LightningTendrils initializer init requires xDModules,BoolexprUtils
globals
    //Constants adjust to your map specific data/values
    private constant integer      spellID          = 'A000'                                                            //The spell raw-code
    private constant integer      flyID            = 'Amrf'                                                            //The fly raw-code DO NOT CHANGE THIS ONE
                                                                
    private constant real         interval         = 0.03125                                                           //The updating interval
    private constant real         tendrilInterval  = 0.1                                                               //The interval which moves the tendrils
    private constant real         heightDecStart   = 13.75                                                             //after this time the unit starts to move to the ground
    private constant real         range            = 350.                                                              //The range where the tendrils will move in
    private constant real         damageRange      = 50.                                                               //The range of the tendril impact damage
    private constant real         damage           = 3.                                                                
    private constant real         damageInc        = 2.
    private constant real         flyHeight        = 500.                                                              //The height where the hero will be
    private constant real         flyHeightInc     = 12.5
    private constant real         flyHeightDec     = -12.5
    private constant real         duration         = 15.                                                               //Duration of the spell
    
    private constant integer      tendrils         = 8                                                                 //Number of tendrils + increasement per level
    private constant integer      tendrilsInc      = 3
    
    //Following vars are for the effects
    private constant string       tendrilEffect    = "CLPB"
    private constant string       hitEffect        = "Abilities\\Spells\\Orc\\Purge\\PurgeBuffTarget.mdl"
    private constant string       endEffect        = "Abilities\\Spells\\Human\\Thunderclap\\ThunderClapCaster.mdl"
    private constant string       attach           = "chest"
    
    //Sound effects
    private constant string       sfxString        = "Abilities\\Spells\\Orc\\LightningBolt\\LightningBolt.wav"
    
    //DO NOT CHANGE THOSE VARIABLES DUE OF IMPORTANT USAGE
    private          group        tmpG             = CreateGroup()
    private          unit         tmpU
    private          player       tmpP
    private          boolexpr     filter
endglobals

//*************************************Formulas***********************************************
private function tendrilCount takes integer lvl returns integer
    return tendrils+((lvl-1)*tendrilsInc)
endfunction

private function tendrilDamage takes integer lvl returns real
    return damage+((lvl-1)*damageInc)
endfunction
//********************************************************************************************


//*************************************Some functions*****************************************
private function GroupFilter takes nothing returns boolean
    return IsUnitEnemy(GetFilterUnit(),tmpP) and (GetUnitState(GetFilterUnit(),UNIT_STATE_LIFE)>0) and IsUnitType(GetFilterUnit(),UNIT_TYPE_GROUND)
endfunction

private function GetRandomXInRect takes rect r returns real
    return GetRandomReal(GetRectMinX(r),GetRectMaxX(r))
endfunction

private function GetRandomYInRect takes rect r returns real
    return GetRandomReal(GetRectMinY(r),GetRectMaxY(r))
endfunction
//********************************************************************************************

//****************************************Core Part*******************************************
private function callback takes nothing returns nothing
    local unit u = GetEnumUnit()
    call UnitDamageTarget(tmpU,u,tendrilDamage(GetUnitAbilityLevel(tmpU,spellID)),false,false,ATTACK_TYPE_NORMAL,DAMAGE_TYPE_NORMAL,null)
    set u = null
endfunction

private struct tendrilStruct
    unit      caster
    lightning tendril
    real      time      = 0.    
    method actions takes nothing returns nothing
        //local variable initialization
        local real x1 = GetUnitX(.caster)
        local real y1 = GetUnitY(.caster)
        local real z1 = GetUnitFlyHeight(.caster)        
        local rect r  = Rect(x1 -range,y1 -range,x1+range,y1+range) //<== Creates a rect where the tendril will move in
        local real x2 = GetRandomXInRect(r)
        local real y2 = GetRandomYInRect(r)
        local real z2 = 0  
        local sound sfx = CreateSound(sfxString,false,true,true,0,0,"")
        //setting the sound
        call SetSoundPosition(sfx, x2, y2, 0)
        call SetSoundVolume(sfx, R2I(100 * I2R(127) * 0.01))
        call StartSound(sfx)     
        call KillSoundWhenDone(sfx)
        //end of initialization
        set .time = .time + tendrilInterval
        //Tendril movement
        call MoveLightningEx(.tendril,true,x1,y1,z1,x2,y2,z2) 
        call DestroyEffect(AddSpecialEffect(hitEffect,x2,y2))
        
        //Tendril damage
        set tmpP = GetOwningPlayer(.caster)
        set tmpU = .caster
        call GroupEnumUnitsInRange(tmpG,x2,y1,damageRange,filter)
        call ForGroup(tmpG,function callback)
        
        //when should this end??
        if .time >= duration then
            call DestroyEffect(AddSpecialEffect(endEffect,x2,y2))
            call DestroyLightning(.tendril)
            set .tendril = null
            set .caster = null
            call .destroy()
        endif
        //clear all leaks!!
        call RemoveRect(r)
        set sfx = null
        set r = null
    endmethod
    // for this look into xDModules :)
    implement structStack
endstruct

private struct tendrilCaster
    unit      caster
    real      height = 0.
    real      heightInc = flyHeightInc
    real      time    = 0.
    method actions takes nothing returns nothing                
        //First setting the height and time for increasing flyHeight etc.
        set .time = .time + interval
        set .height = .height + .heightInc   
        call SetUnitFlyHeight(.caster,.height,0)        
        if .height >= flyHeight then
            set .heightInc = 0
        endif
        if .time >= heightDecStart then
            set .heightInc = flyHeightDec
        endif
        //everything ends!!
        if .time >= duration then
            call SetUnitPathing(.caster,true)
            set .caster = null
            call .destroy()
        endif
    endmethod
    // for this look into xDModules :)
    implement structStack
endstruct
//Just another stupid condition function... realy blablabla
private function cond takes nothing returns boolean
    return GetSpellAbilityId() == spellID
endfunction

//action function takes care of initializate the structs and is the main protagonist in this little story XD
private function action takes nothing returns nothing
    local tendrilStruct dat
    local tendrilCaster data = tendrilCaster.create(interval)
    local unit caster = GetTriggerUnit()
    local integer i = 0
    set data.caster = caster
    call UnitAddAbility(caster,flyID)
    call UnitRemoveAbility(caster,flyID)
    call SetUnitPathing(caster,false)
    loop
        exitwhen i >= tendrilCount(GetUnitAbilityLevel(caster,spellID))
        set dat = tendrilStruct.create(tendrilInterval)
        set dat.tendril = AddLightningEx(tendrilEffect,true,GetUnitX(caster),GetUnitY(caster),GetUnitFlyHeight(caster),GetUnitX(caster),GetUnitY(caster),GetUnitFlyHeight(caster))
        set dat.caster= caster
        set i = i + 1
    endloop
    set caster = null
endfunction

//usual init stuff like preloading or setting filter
private function init takes nothing returns nothing
    local trigger int = CreateTrigger()
    local integer i = 0
    loop
        call TriggerRegisterPlayerUnitEvent(int,Player(i),EVENT_PLAYER_UNIT_SPELL_EFFECT,BOOLEXPR_TRUE)
        set i = i + 1
        exitwhen i >= bj_MAX_PLAYER_SLOTS
    endloop
    call TriggerAddCondition(int,Condition(function cond))
    call TriggerAddAction(int,function action)
    set int = null
    set filter = Condition(function GroupFilter)
    call Preload(hitEffect)
    call Preload(endEffect)
endfunction
endlibrary


JASS:
//**********************************************************************************
//* xDModules v1.1 by xD.Schurke  -  16.04.2009
//* --------------------------------------------
//*       
//* Requires:
//*     * JNGP (JassHelper v0.9.G.0)
//*     
//*
//*     * Implement the module in your structs, which need timers.
//*     * The struct needs a method called actions 
//*
//* Example:
//*
//* struct Data
//*     integer count = 0
//*     method actions takes nothing returns nothing
//*         call BJDebugMsg("Hello World")
//*         if count == 5 then
//*             set .active = false 
//*         endif
//*     endmethod
//*     implement structStack
//* endstruct
//*
//* If you want to destroy the struct just the this.active = false (.active = false).
//* But don't forget to clear all leaks before
//*
//* Changelog:
//*     * Now the timer interval are commited by the create parameters
//*
//*
//**********************************************************************************
library xDModules
    module structStack
        boolean active = true
        
        private integer i    
        private static integer Total = 0
        private static thistype array Data
        private static timer Tim = CreateTimer()
        private static method callback takes nothing returns nothing
            local thistype dat
            local integer i = 0
            loop
                exitwhen i >= thistype.Total
                set dat = thistype.Data[i]
                if dat.active == true then
                    call dat.actions()
                else                
                    call thistype.destroy(dat)
                    set i = i - 1
                endif
                set i = i + 1
            endloop
            if thistype.Total == 0 then
                call PauseTimer(thistype.Tim)
            endif 
        endmethod
    
        static method create takes real interval returns thistype
            local thistype dat = thistype.allocate()
            if thistype.Total == 0 then
                call TimerStart(thistype.Tim,interval,true,function thistype.callback)
            endif
            set thistype.Data[thistype.Total] = dat
            set dat.i = thistype.Total
            set thistype.Total = thistype.Total + 1
            return dat
        endmethod
        
        private method onDestroy takes nothing returns nothing
            set thistype.Total=thistype.Total-1
            set thistype.Data[.i]=thistype.Data[thistype.Total]
            set thistype.Data[.i].i=.i     
        endmethod
    endmodule
endlibrary

Keywords:
vJass,JESP,Schurke,Lightning,light,tendril,tendrils,energy,jass,good
Contents

Lightning Tendrils v1.1 (Map)

Reviews
10:32, 19th Oct 2009 TriggerHappy187: Decent enough to be approved. Whats the point of using a local here, you save no function calls. private function callback takes nothing returns nothing local unit u = GetEnumUnit() call...

Moderator

M

Moderator

10:32, 19th Oct 2009
TriggerHappy187:

Decent enough to be approved.

  • Whats the point of using a local here, you save no function calls.
    JASS:
    private function callback takes nothing returns nothing
        local unit u = GetEnumUnit()
        call UnitDamageTarget(tmpU,u,tendrilDamage(GetUnitAbilityLevel(tmpU,spellID)),false,false,ATTACK_TYPE_NORMAL,DAMAGE_TYPE_NORMAL,null)
        set u = null
    endfunction
  • You should be using GetWidgetLife instead of GetUnitState.
  • BOOLEXPR_TRUE is completely unneded in your event. You also don't need to set int to null.
 
Level 15
Joined
Jul 19, 2007
Messages
618
yo mate xD.Schurke xD!

well nice spell very nice its coded great in performances and is leakless + MUI. well there is again that loop which loops through the group just note that ForGroup is at least 6 times faster then loop in jass (6 times is minumum even more maybe) but still i dont think it will lag when casted multiple times.

there is currently one thing which i would really like you to add and that is ofc sound. plz add some lightning sound for example from chain lightning or lightning bolt... any would be good just add it xD

it will be 5/5 from me nothing more to say i like your module and boolexpr utils! great work once more! +rep

off topic:
Nevaaa!!! I will ask you soooo long until yo u tell it to me!! :D

well from time i first checked dingos pack and give a few tips he understanded them well so ill try to explain him this time too!

modules are parts of code which can be added in structure of data and must follow other methodes in that struct like one from xD.Schurke which requires actions method.

modules are using thistype which points to type in which struct they are implemented and all code in module now is accessible in that struct. however private members of module are not accessible in that struct nor in any other function / method. public members are accessible everywhere.

so simple to say module is group of data which is used to perform single action type for each struct. in his module he is using it for looping (with timer).

modules can as well be optional implemeted:
JASS:
struct xxx
implement optional myMod
endstruct

which means that module will be added if by any chance possible while implement forces to add given module optional mode checks does it exist.

if you still do not understand you can pm me to explain in more detail!

Greets all!
~Dark Dragon
 
Level 16
Joined
Feb 22, 2006
Messages
960
yo mate xD.Schurke xD!

well nice spell very nice its coded great in performances and is leakless + MUI. well there is again that loop which loops through the group just note that ForGroup is at least 6 times faster then loop in jass (6 times is minumum even more maybe) but still i dont think it will lag when casted multiple times.

there is currently one thing which i would really like you to add and that is ofc sound. plz add some lightning sound for example from chain lightning or lightning bolt... any would be good just add it xD

Yeah will update both parts (ForGroup and sounds :D)
btw. I'm working on a jass editor XD

...and +rep for explaining modules for dingo :)
 
Level 8
Joined
Apr 7, 2008
Messages
176
The lightning moves too fast.... way too fast
And my hero died and didnt come back. :(

But other than that nice spell. Exactly like the guy in Ulduar.
Fix the tendril speed, and make a Hero revive trigger. And the Test Map will be alot more fun. Maybe add a unit revive trigger aswell.
 
Level 7
Joined
Mar 24, 2008
Messages
184
Nice spell, just one thing

Even though i know it has no Cooldown for testing reasons, you should make something to avoid this spell being spammed, weird things happens if i cast it too many times (like all unit models disappear and get merged in a polygons
mess at the center of the map :eek: )
 
Level 7
Joined
Mar 24, 2008
Messages
184
Yes, that's true, but it's the first time i have that by spamming a spell (usually it just starts lagging). I'd put some limit on the number of active spells possible or something if i made a spell that could cause this problem
 
Level 19
Joined
Feb 4, 2009
Messages
1,313
the sound is too loud imho but it's easy to adjust it so screw it
you could make some effect blasting the unit into the air and one for the unit falling down (the random mass thunder clap is a nice try but a single one under the aster would fit better I think)
you should also think about making the lightning effects spawn directly out of the caster and not under it

and this would make it more realistic:
  • StopAttackFlying
    • Events
      • Unit - A unit Is attacked
    • Conditions
      • ((Attacked unit) is in LightningTendrilsCasterGroup) Equal to True
      • ((Triggering unit) is Able to attack flying units) Equal to False
    • Actions
      • Unit - Order (Triggering unit) to Stop
 
Top