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

Lightning Invocation v1.3

  • Like
Reactions: Lambdadelta
Calls forth lightning from the abyss, targets enemy units within 600 AoE to follow under the caster command as long as the spell channeled. Also healing friendly allied hero units for 10 hit points per second.

Requires:
- TimerUtils by Vexorian
- PUI by Cohadar
- GroupUtils by Rising_Dusk


JASS:
//******************************************************************************
//*                                                                            *
//*                          Lightning Invocation                              *
//*                                  v1.30                                     *
//*                                                                            *
//*                  By: scorpion182 aka ranzi aka ada_aja                     *
//*                         http://www.jade-wars.com                           *
//*                                                                            *
//******************************************************************************
library LightningInvocation initializer init requires TimerUtils, PolarProjection, GroupUtils, PUI
//*************************************************************
//* Configuration Constants
    globals
    
        private constant integer DUMMY_ID='e000' //Dummy Caster Unit Rawcode
        private constant integer SPELL_ID='A000' //Spell Rawcode
        private constant integer LIGHTNING_NUM=6 //Number of Lightning
        private constant real LIGHTNING_HEIGHT=500. //Lightning Height
        private constant string LIGHTNING_ID="AFOD" //Lighting Rawcode
        private constant string GROUND_FX="Abilities\\Weapons\\VengeanceMissile\\VengeanceMissile.mdl" //Effect attach to lightning
        private constant string HEAL_FX="Abilities\\Weapons\\VengeanceMissile\\VengeanceMissile.mdl" //Effect attach to target heal unit
        private constant string CASTER_FX="Abilities\\Spells\\Orc\\Voodoo\\VoodooAura.mdl" //Effect attach to caster
        private constant string CASTER_ATTCH="origin" //caster attachment point
        private constant string TARGT_H_ATTCH="origin" //target heal attachment point 
        private constant string ORDER_ID="starfall" //spell order id
        private constant real INTERVAL=0.1 //timer interval
        private constant boolean CLOCKWISE=false //rotate clockwise?
        private constant real ANGLE_INCREMENT=.15 //angle movement
    endglobals
    
//*****************************************************************
//* Configuration Functions

//* Spell Damage
    private constant function HEAL_AMOUNT takes integer lvl returns real
        return lvl*10.0*INTERVAL
    endfunction
//* Spell Area of Effect Radius
    private constant function RADIUS takes integer lvl returns real
        return lvl*600.
    endfunction

//* Configuration End
//*****************************************************************
    globals
        private integer array UnitData
        private boolexpr b
        private group CastersGroup
    endglobals
    //set unit's integer
    private function AttachIntegerToUnit takes unit u, integer i returns nothing
        set UnitData[GetUnitIndex(u)] = i
    endfunction
    //get unit's integer 
    private function GetIntegerFromUnit takes unit u returns integer
        return UnitData[GetUnitIndex(u)]
    endfunction
    //spell filter function
    private function Spell_Filter takes nothing returns boolean
        return (IsUnitType(GetFilterUnit(),UNIT_TYPE_STRUCTURE)==false) and (IsUnitType(GetFilterUnit(), UNIT_TYPE_MAGIC_IMMUNE)==false) and (GetWidgetLife(GetFilterUnit()) > 0.405)
    endfunction
    //spell struct
    private struct data
        unit caster
        unit dum
        unit array missile[LIGHTNING_NUM]
        lightning array lg[LIGHTNING_NUM]
        real array angle[LIGHTNING_NUM] 
        effect fx
        timer t
        group g
        integer lvl
        
        static method create takes unit c, timer t returns data
            local data d=data.allocate()
            
            set d.g=NewGroup()
            set d.caster=c
            set d.t=t
            
            set d.fx=AddSpecialEffectTarget(CASTER_FX, d.caster,CASTER_ATTCH)
            set d.dum=CreateUnit(GetOwningPlayer(d.caster),DUMMY_ID,GetUnitX(d.caster),GetUnitY(d.caster),0)
            set d.lvl=GetUnitAbilityLevel(d.caster,SPELL_ID)
            
            call GroupAddUnit(CastersGroup,d.caster)
            
            return d
        endmethod
        //update victim group
        method Update_Group takes nothing returns nothing
            local unit s
            local group temp=NewGroup()
            local integer lvl=GetUnitAbilityLevel(.caster,SPELL_ID)
            local integer idx
            
            call GroupEnumUnitsInRange(temp,GetUnitX(.caster),GetUnitY(.caster),RADIUS(lvl),b)
            //convert owner, and heal allies
            loop
                set s=FirstOfGroup(temp)
            exitwhen s==null
                //convert owner
                if (IsUnitEnemy(s,GetOwningPlayer(.caster))==true and IsUnitInGroup(s,.g)==false and IsUnitType(s,UNIT_TYPE_HERO)==false) then
                    call AttachIntegerToUnit(s,GetPlayerId(GetOwningPlayer(s)))
                    call SetUnitOwner(s,GetOwningPlayer(.caster),true)
                    call GroupAddUnit(.g,s)
                //heal friendly unit
                elseif (IsUnitAlly(s,GetOwningPlayer(.caster))==true and s!=.caster and IsUnitType(s,UNIT_TYPE_HERO)==true) then
                    call SetUnitState(s,UNIT_STATE_LIFE,GetUnitState(s,UNIT_STATE_LIFE)+HEAL_AMOUNT(lvl))
                    call DestroyEffect(AddSpecialEffectTarget(HEAL_FX, s,TARGT_H_ATTCH))
                endif
                call GroupRemoveUnit(temp,s)
            endloop
            
            //out of range?
            call GroupAddGroup(.g,temp)
            
            loop
                set s=FirstOfGroup(temp)
            exitwhen s==null
                if (Unit_Distance(s,.caster)>RADIUS(lvl)) then
                    set idx=GetIntegerFromUnit(s)
                    call SetUnitOwner(s,Player(idx),true)
                    call GroupRemoveUnit(.g,s)
                endif
                call GroupRemoveUnit(temp,s)
            endloop
            
            call ReleaseGroup(temp)
            
            set temp=null
        endmethod
        
        private method onDestroy takes nothing returns nothing
            local integer i=0
            local unit s
            local integer idx
            
            call ReleaseTimer(.t)
            call DestroyEffect(.fx)
            call KillUnit(.dum)
            
            //revert creeps to original owner
            loop
                set s=FirstOfGroup(.g)
            exitwhen s==null
                set idx=GetIntegerFromUnit(s)
                call SetUnitOwner(s,Player(idx),true)
                call GroupRemoveUnit(.g,s)
            endloop
            
            call ReleaseGroup(.g)
            //destroy lightning
            loop
            exitwhen i>LIGHTNING_NUM
                call DestroyLightning(.lg[i])
                call KillUnit(.missile[i])
                set i=i+1
            endloop
            
            call GroupRemoveUnit(CastersGroup,.caster)
        endmethod
        
    endstruct
    //rotate the lightning
    private function Clock takes nothing returns nothing
        local timer t = GetExpiredTimer()
        local data d=data(GetTimerData(t))
        local integer i=0
        local real x1 
        local real y1 
        local real x2 = GetUnitX(d.dum)
        local real y2 = GetUnitY(d.dum)
        local real angle
        local integer lvl=d.lvl
        
        if (GetUnitCurrentOrder(d.caster)==OrderId(ORDER_ID)) then
            
            call d.Update_Group()
            call TimerStart(t,INTERVAL,false,function Clock)
            
            loop
            exitwhen i>LIGHTNING_NUM
                set x1 = GetUnitX(d.missile[i])
                set y1 = GetUnitY(d.missile[i])
                //rotate counter clockwise
                if CLOCKWISE==false then
                    set angle=d.angle[i]+ANGLE_INCREMENT
                //rotate clockwise
                else
                    set angle=d.angle[i]-ANGLE_INCREMENT
                endif
                //move lightning
                call SetUnitPosition(d.missile[i], x2+RADIUS(lvl)*Cos(angle), y2+RADIUS(lvl)*Sin(angle))
                call MoveLightningEx(d.lg[i],true,GetUnitX(d.dum),GetUnitY(d.dum),GetUnitFlyHeight(d.dum)+LIGHTNING_HEIGHT,GetUnitX(d.missile[i]),GetUnitY(d.missile[i]),GetUnitFlyHeight(d.missile[i]))
                call DestroyEffect(AddSpecialEffectTarget(GROUND_FX, d.missile[i],"origin"))
                set d.angle[i]=angle
                set i=i+1
            endloop
        else
            call d.destroy()
        endif
        
        set t=null
    endfunction
    //spell trigger actions
    private function Actions takes nothing returns boolean
        local timer t
        local unit u=GetSpellAbilityUnit()
        local data d
        local integer i=0
        local integer lvl=GetUnitAbilityLevel(u,SPELL_ID)
        
        if (IsUnitInGroup(u,CastersGroup)==false and GetSpellAbilityId() == SPELL_ID) then
        
            set t=NewTimer()
            set d=data.create(u,t)
        
            call SetTimerData(t,integer(d))
            //create lightning
        
            loop
            exitwhen i>LIGHTNING_NUM
                set d.missile[i]=CreateUnit(GetOwningPlayer(d.caster),DUMMY_ID, PolarProjectionX(GetUnitX(d.caster),RADIUS(lvl), 360/LIGHTNING_NUM*i), PolarProjectionY(GetUnitY(d.caster), RADIUS(lvl), 360/LIGHTNING_NUM*i), 0.00)
                set d.lg[i]=AddLightningEx(LIGHTNING_ID,true,GetUnitX(d.dum),GetUnitY(d.dum),GetUnitFlyHeight(d.dum)+LIGHTNING_HEIGHT,GetUnitX(d.missile[i]),GetUnitY(d.missile[i]),GetUnitFlyHeight(d.missile[i]))
                set d.angle[i]=bj_DEGTORAD*360/LIGHTNING_NUM*i
                set i=i+1
            endloop
        
            call TimerStart(t,INTERVAL,false,function Clock)
            
            set u=null
            set t=null
            return true
        endif
        
        set u=null
        set t=null
        return false
    endfunction

    private function init takes nothing returns nothing
    
        local trigger t=CreateTrigger()
        call TriggerRegisterAnyUnitEventBJ(t,EVENT_PLAYER_UNIT_SPELL_EFFECT)
        call TriggerAddCondition(t,Condition(function Actions))
        
        set b=Condition(function Spell_Filter)
        set CastersGroup=NewGroup()
        //Preload FX
        call Preload(GROUND_FX)
        call Preload(CASTER_FX)
        call Preload(HEAL_FX)
    
    endfunction
    
endlibrary



-v1.0 First release.
-v1.1 Make the unit revert back to the original owner if the unit out of range. (The_Dead_Fight)
-v1.2 1.24 compatibility.
-v1.3 Did some Hodgepodge things.


Keywords:
lightning, invoke, ground, area, hero, undead, red, no, target, active, spell, ability, invocation, thunder
Contents

Lightning Invocation v1.3 (Map)

Reviews
17:48, 7th Oct 2009 TriggerHappy187: Read this. Though the spell is good enough to be approved, but please give thought into improving your codes efficiency.

Moderator

M

Moderator

17:48, 7th Oct 2009
TriggerHappy187:

Read this.

Though the spell is good enough to be approved, but please give thought into improving your codes efficiency.
 
Level 17
Joined
Mar 17, 2009
Messages
1,349
Well to start with, the SFX is sort of big. Also, and that's only my opinion, i think it lacks creativity.
This now, isn't a big issue, but i guess that's too many libraries :p

Yet, regardless, it's good coding you've got there. I skimmed through it, and there's some issue:
JASS:
call KillUnit(.dum)
Ok this kills the unit but doesn't remove him from the game. What you could do is RemoveUnit or UnitApplyTimedLife(whichUnit, 'BTLF'. .001). The first doesn't play the death effect, while the seconds does ;)
 
Level 4
Joined
May 20, 2009
Messages
96
how do you download spells?

dont answer me on here i never check my messages/whatever

contact me at [email protected] please
and tell me what spell this was on not ur username
thank you if you do so

And what i need is how do you import it, idk theres no tutorial like a model
 
Some improvements.

  • You may want to think of only using a condition thread instead of combining actions/conditions. It creates one less thread and saves a function call. Like this;
    JASS:
    private function Actions takes nothing returns boolean
        if YOUR_CONDITION then
            // Do actions
        endif
        return false
    endfunction
    
    private function onInit takes nothing returns nothing
        local trigger t = CreateTrigger()
        call TriggerRegisterSomeEvent(t)
        call TriggerAddCondition(t, Condition(function Actions))
    endfunction
  • Why are you using locations, they just add extra lines/function calls to your code.
  • You don't need to set s=null in your destroy method, the local will already be null by the end of the first loop.
  • Shouldn't you store the level of the spell inside the struct?
  • In your update group method, your dynamically creating groups, just re-use a global one.
 
Top