• Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
  • Read Evilhog's interview with Gregory Alper, the original composer of the music for WarCraft: Orcs & Humans 🔗Click here to read the full interview.

Thunderstorm v1.1

This bundle is marked as useful / simple. Simplicity is bliss, low effort and/or may contain minor bugs.
------------------------------------
:: Thunderstorm v1.1 ::
by Shadowleaves
------------------------------------


> Description <
Summons a thunderstorm to strikes down all enemies with terrible lightning bolts. Focus its energy to deal a large amount of damage to unit that stand in the center. Deals 200% int damage to heroes, 150% int damage to units and 500% int damage to centered target with 400% int splash damage. 1 max target for each thundercloud and less accuracy of focus strike.

JASS:
function AbThunderstorm_GetInt takes integer x returns integer
                        // <Integer Section>
    if (x==0) then      //Thunderstorm Ability Id
                 return 'A000'
    elseif (x==1) then  //Thundercloud Unit Id
                 return 'e001'
    elseif (x==2) then  //DummyCaster Unit Id
                 return 'e000'
    elseif (x==3) then  //Number of cloud
                 return 7
    endif               //
endfunction             //
function AbThunderstorm_GetReal takes integer x, integer str, integer agi, integer int returns real
                        // <Real Section>
    if (x==0) then      //Spell Duration
                 return 12.0
    elseif (x==1) then  //Damage - focus strike on centered unit
                 return int * 1.0
    elseif (x==2) then  //Damage - deal to hero
                 return int * 2.0
    elseif (x==3) then  //Damage - deal to unit
                 return int * 1.5
    elseif (x==4) then  //Damage - AoE of focus strike
                 return int * 4.0
    endif               //
endfunction             //
function AbThunderstorm_GetString takes integer x returns string
                        // <String Section>
    if (x==1) then      //Model - the weather model
                 return "effects\\raining.mdl"
    elseif (x==2) then  //Model - Lightning Impact
                 return "Abilities\\Weapons\\Bolt\\BoltImpact.mdl"
    elseif (x==3) then  //Model - AoE Focus Strike
                 return "Abilities\\Spells\\Human\\Thunderclap\\ThunderClapCaster.mdl"
    elseif (x==4) then  //Sound - Raining looping
                 return "Abilities\\Spells\\Other\\Monsoon\\MonsoonRainLoop.wav"
    elseif (x==5) then  //Lightning - lightning type
                 return "FORK"
    endif               //
endfunction
//-End of Configuration----------------------------------------------

function AbThunderstorm_TrueBoolexpr takes nothing returns boolean
    return true
endfunction

function AbThunderstorm_lightning takes nothing returns nothing
    local integer h = GetHandleId(GetTriggeringTrigger())
    local real delay = LoadReal(udg_AbData, h, StringHash("delay"))
    local lightning l = LoadLightningHandle(udg_AbData, h, StringHash("light"))
    local unit u = LoadUnitHandle(udg_AbData, h, StringHash("caster"))
    local unit u2 = LoadUnitHandle(udg_AbData, h, StringHash("target"))
    if ( delay == .8 ) then
        call DestroyEffect(AddSpecialEffectTarget(AbThunderstorm_GetString(2), u2, "origin"))
        set l = AddLightningEx(AbThunderstorm_GetString(5), true, GetUnitX(u), GetUnitY(u), GetUnitFlyHeight(u), GetUnitX(u2), GetUnitY(u2), GetUnitFlyHeight(u2))
        call SaveLightningHandle(udg_AbData, h, StringHash("light"), l)
        call UnitDamageTarget(u, u2, LoadReal(udg_AbData, h, StringHash("damage")), true, false, ATTACK_TYPE_MAGIC, DAMAGE_TYPE_MAGIC, null)
    elseif (delay <= .5) then
        call SetLightningColor(l, 1, 1, 1, GetLightningColorA(l) - .197)
    endif
    call MoveLightningEx(l, true, GetUnitX(u), GetUnitY(u), GetUnitFlyHeight(u), GetUnitX(u2), GetUnitY(u2), GetUnitFlyHeight(u2))
    set u = null
    set u2 = null
    set l = null
    set delay = delay - .1
    call SaveReal(udg_AbData, h, StringHash("delay"), delay)
    if ( delay <= 0 ) then
        call DestroyLightning( LoadLightningHandle(udg_AbData, h, StringHash("light")) )
        call FlushChildHashtable(udg_AbData, h)
        call DestroyTrigger(GetTriggeringTrigger())
    endif
endfunction

function AbThunderstorm takes nothing returns nothing
    local integer h = GetHandleId( GetTriggeringTrigger() )
    local player p = Player( LoadInteger(udg_AbData, h, StringHash("player")) )
    local integer i = 1
    local integer str = LoadInteger(udg_AbData, h, StringHash("str"))
    local integer agi = LoadInteger(udg_AbData, h, StringHash("agi"))
    local integer int = LoadInteger(udg_AbData, h, StringHash("int"))
    local integer lvl = LoadInteger(udg_AbData, h, StringHash("level"))
    local real delay = LoadReal(udg_AbData, h, StringHash("delay"))
    local real x = LoadReal(udg_AbData, h, StringHash("x"))
    local real y = LoadReal(udg_AbData, h, StringHash("y"))
    local real x2
    local real y2
    local real r = GetRandomReal(0,360)
    local unit u
    local unit u2
    local group g = CreateGroup()
    local sound S
    local integer charge
    local trigger t
    
    if ( delay==LoadReal(udg_AbData, h, StringHash("Cdelay")) ) then
        call SaveEffectHandle(udg_AbData, h, StringHash("weather0"), AddSpecialEffect(AbThunderstorm_GetString(1), x, y))
        loop
            exitwhen i > AbThunderstorm_GetInt(3)
            set x2 = x + 300*Cos((r + 360/7*i)*bj_DEGTORAD)
            set y2 = y + 300*Sin((r + 360/7*i)*bj_DEGTORAD)
            set u = CreateUnit(p, AbThunderstorm_GetInt(1), x2, y2, GetRandomReal(0,360))
            call SetUnitPosition(u, x2, y2)
            call SetUnitFlyHeight(u, GetRandomReal(512, 768), 0)
            call SetUnitScale(u, GetRandomReal(.5, .75), GetRandomReal(.5, .75), GetRandomReal(.5, .75))
            call SetUnitAnimation(u, "birth")
            call SaveUnitHandle(udg_AbData, h, StringHash("dummy"+I2S(i)), u)
            set x2 = x + 450*Cos((r + 360/7*i)*bj_DEGTORAD)
            set y2 = y + 450*Sin((r + 360/7*i)*bj_DEGTORAD)
            call SaveEffectHandle(udg_AbData, h, StringHash("weather"+I2S(i)), AddSpecialEffect(AbThunderstorm_GetString(1), x2, y2))
            set i = i + 1
        endloop
        set S = CreateSound(AbThunderstorm_GetString(4), true, true, true, 10, 10, "DefaultEAXON")
        call SetSoundPosition(S, x, y, 256)
        call StartSound(S)
        call SaveSoundHandle(udg_AbData, h, StringHash("sound"), S)
    endif
    
    set i = 1
    loop
        exitwhen i > AbThunderstorm_GetInt(3)
        if (lvl==1) then                    // ---------
            set charge = 1                  // Max targets of clouds
        elseif (lvl==2) then                // 1 when lvl 1
            set charge = GetRandomInt(1, 2) // 1 or 2 when lvl 2
        else                                // 2 when lvl 3
            set charge = 2                  //
        endif                               // ---------
        set u = LoadUnitHandle(udg_AbData, h, StringHash("dummy"+I2S(i)))
        set x2 = GetUnitX(u)
        set y2 = GetUnitY(u)
        call GroupEnumUnitsInRange(g, x, y, 25*lvl, Filter(function AbThunderstorm_TrueBoolexpr)) // Accuracy of focus strike depends on level
        loop                                                      // Max targets will decrease to 1 only
            set u2 = FirstOfGroup(g)
            exitwhen u2 == null
            call GroupRemoveUnit(g, u2)
            if (charge > 0) and IsUnitEnemy(u2, p) and not IsUnitType(u2, UNIT_TYPE_DEAD) then
                set t = CreateTrigger()
                call SaveReal(udg_AbData, GetHandleId(t), StringHash("delay"), .8)
                call SaveReal(udg_AbData, GetHandleId(t), StringHash("damage"), AbThunderstorm_GetReal(1,str,agi,int))
                call SaveUnitHandle(udg_AbData, GetHandleId(t), StringHash("caster"), u)
                call SaveUnitHandle(udg_AbData, GetHandleId(t), StringHash("target"), u2)
                call TriggerAddCondition(t, Condition(function AbThunderstorm_lightning))
                call TriggerRegisterTimerEvent(t, .1, true)
                set charge = -1
            endif
        endloop
        if (charge > 0) then
            call GroupEnumUnitsInRange(g, x2, y2, 300, Filter(function AbThunderstorm_TrueBoolexpr))
            loop
                set u2 = FirstOfGroup(g)
                exitwhen u2 == null
                call GroupRemoveUnit(g, u2)
                if (charge > 0) and IsUnitEnemy(u2, p) and not IsUnitType(u2, UNIT_TYPE_DEAD) and IsUnitType(u2, UNIT_TYPE_HERO) then
                    set t = CreateTrigger()
                    call SaveReal(udg_AbData, GetHandleId(t), StringHash("delay"), .8)
                    call SaveReal(udg_AbData, GetHandleId(t), StringHash("cdelay"), .8)
                    call SaveReal(udg_AbData, GetHandleId(t), StringHash("damage"), AbThunderstorm_GetReal(2,str,agi,int))
                    call SaveUnitHandle(udg_AbData, GetHandleId(t), StringHash("caster"), u)
                    call SaveUnitHandle(udg_AbData, GetHandleId(t), StringHash("target"), u2)
                    call TriggerAddCondition(t, Condition(function AbThunderstorm_lightning))
                    call TriggerRegisterTimerEvent(t, .1, true)
                    set charge = charge - 1
                endif
            endloop
        endif
        if (charge > 0) then
            call GroupEnumUnitsInRange(g, x2, y2, 300, Filter(function AbThunderstorm_TrueBoolexpr))
            loop
                set u2 = FirstOfGroup(g)
                exitwhen u2 == null
                call GroupRemoveUnit(g, u2)
                if (charge > 0) and IsUnitEnemy(u2, p) and not IsUnitType(u2, UNIT_TYPE_DEAD) and not IsUnitType(u2, UNIT_TYPE_HERO) then
                    set t = CreateTrigger()
                    call SaveReal(udg_AbData, GetHandleId(t), StringHash("delay"), .8)
                    call SaveReal(udg_AbData, GetHandleId(t), StringHash("cdelay"), .8)
                    call SaveReal(udg_AbData, GetHandleId(t), StringHash("damage"), AbThunderstorm_GetReal(3,str,agi,int))
                    call SaveUnitHandle(udg_AbData, GetHandleId(t), StringHash("caster"), u)
                    call SaveUnitHandle(udg_AbData, GetHandleId(t), StringHash("target"), u2)
                    call TriggerAddCondition(t, Condition(function AbThunderstorm_lightning))
                    call TriggerRegisterTimerEvent(t, .1, true)
                    set charge = charge - 1
                endif
            endloop
        endif
        set i = i + 1
    endloop
    if (charge < 0) then    //FocusThunder triggered
        call GroupEnumUnitsInRange(g, x, y, 275, Filter(function AbThunderstorm_TrueBoolexpr))
        loop
            set u2 = FirstOfGroup(g)
            exitwhen u2 == null
            call GroupRemoveUnit(g, u2)
            if IsUnitEnemy(u2, p) and not IsUnitType(u2, UNIT_TYPE_DEAD) then
                call UnitDamageTarget(u, u2, AbThunderstorm_GetReal(4,str,agi,int), true, false, ATTACK_TYPE_MAGIC, DAMAGE_TYPE_MAGIC, null)
            endif
        endloop
        set u = CreateUnit(p, AbThunderstorm_GetInt(2), x, y, 0)
        call UnitAddAbility(u, 'A002')
        call IssueImmediateOrder(u, "thunderclap")
        call UnitApplyTimedLife(u, 'BTLF', .01)
        call DestroyEffect(AddSpecialEffect(AbThunderstorm_GetString(3), x, y))
    endif
    
    //call BJDebugMsg("Thunderstorm's delay = |cffffcc00"+R2S(delay)+"|R")
    call DestroyGroup(g)
    set u = null
    set u2 = null
    set g = null
    set S = null
    set t = null
    set delay = delay - .75
    call SaveReal(udg_AbData, h, StringHash("delay"), delay)
    if (delay <= 0) or LoadBoolean(udg_AbData, h, StringHash("stop")) then
        set i = 0
        loop
            exitwhen i > AbThunderstorm_GetInt(3)
            call KillUnit( LoadUnitHandle(udg_AbData, h, StringHash("dummy"+I2S(i))) )
            call DestroyEffect( LoadEffectHandle(udg_AbData, h, StringHash("weather"+I2S(i))) )
            set i = i + 1
        endloop
        //call KillSoundWhenDone( LoadSoundHandle(udg_AbData, h, StringHash("sound") )
        call StopSound( LoadSoundHandle(udg_AbData, h, StringHash("sound")), true, true )
        call FlushChildHashtable(udg_AbData, GetHandleId( LoadTriggerHandle(udg_AbData, h, StringHash("channel")) ))
        call DestroyTrigger(LoadTriggerHandle(udg_AbData, h, StringHash("channel")))
        call FlushChildHashtable(udg_AbData, h)
        call DestroyTrigger(GetTriggeringTrigger())
    endif
endfunction

function AbThunderstorm_Channel takes nothing returns nothing
    local integer h = GetHandleId(GetTriggeringTrigger())
    if ( GetTriggerUnit() == LoadUnitHandle(udg_AbData, h, StringHash("caster")) ) then
        call SaveBoolean(udg_AbData, LoadInteger(udg_AbData, h, StringHash("h")), StringHash("stop"), true)
    endif
endfunction

function Trig_AbThunderstorm_Cast takes nothing returns nothing
    local trigger t
    local integer h
    local unit u
    if (GetSpellAbilityId() == AbThunderstorm_GetInt(0)) then
        set t = CreateTrigger()
        set h = GetHandleId( t )
        set u = GetTriggerUnit()
        call SaveInteger(udg_AbData, h, StringHash("str"),GetHeroStr(u, true))
        call SaveInteger(udg_AbData, h, StringHash("agi"),GetHeroAgi(u, true))
        call SaveInteger(udg_AbData, h, StringHash("int"),GetHeroInt(u, true))
        call SaveInteger(udg_AbData, h, StringHash("level"), GetUnitAbilityLevel(u, AbThunderstorm_GetInt(0)))
        call SaveInteger(udg_AbData, h, StringHash("player"), GetPlayerId(GetOwningPlayer(u)))
        call SaveReal(udg_AbData, h, StringHash("delay"), AbThunderstorm_GetReal(0,0,0,0))
        call SaveReal(udg_AbData, h, StringHash("Cdelay"), AbThunderstorm_GetReal(0,0,0,0))
        call SaveReal(udg_AbData, h, StringHash("x"), GetSpellTargetX())
        call SaveReal(udg_AbData, h, StringHash("y"), GetSpellTargetY())
        call TriggerAddCondition(t, Condition(function AbThunderstorm))
        call TriggerRegisterTimerEvent(t, .75, true)
        set t = CreateTrigger()
        call SaveInteger(udg_AbData, GetHandleId(t), StringHash("h"), h)
        call SaveUnitHandle(udg_AbData, GetHandleId(t), StringHash("caster"), u)
        call TriggerAddCondition(t, Condition(function AbThunderstorm_Channel))
        call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_ENDCAST)
        call SaveTriggerHandle(udg_AbData, h, StringHash("channel"), t)
        set t = null
        set u = null
    endif
endfunction

function InitTrig_AbThunderstorm takes nothing returns nothing
    set gg_trg_AbThunderstorm = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( gg_trg_AbThunderstorm, EVENT_PLAYER_UNIT_SPELL_EFFECT )
    call TriggerAddCondition( gg_trg_AbThunderstorm, Condition(function Trig_AbThunderstorm_Cast) )
endfunction

> Comment <
This is my first update of this spell. Any suggestion or bug please report to me.
If you use my spell, please give me credits. thx!


Keywords:
Thunder, storm, lightning, weather, disaster
Contents

Thunderstorm (Map)

Reviews
12th Dec 2015 IcemanBo: Too long as NeedsFix. Rejected. 21st May 2012 Bribe: Instead of StringHash, please use normal, unique integers such as 1,2,3,4,5,6, etc. "return true" functions have been useless for some years now. Get rid of that and...

Moderator

M

Moderator

12th Dec 2015
IcemanBo: Too long as NeedsFix. Rejected.

21st May 2012
Bribe: Instead of StringHash, please use normal, unique integers such as 1,2,3,4,5,6, etc.

"return true" functions have been useless for some years now. Get rid of that and just use "null".

Creating and destroying groups locally is overkill, please use a global group such as bj_lastCreatedGroup and DO NOT destroy it.

Use actual timers instead of triggers with timer events.
 
Level 10
Joined
Sep 19, 2011
Messages
527
Well, you have a lot of work over here xD.

Maybe you can try with vJASS (it makes the work more "easy").

First of all, you should use only timers instead of all of those triggers.

StringHash: it's better work with only integers.

In "Trig_AbThunderstorm_Cast" function:

GetOwningPlayer(u) should be GetTriggerPlayer

JASS:
call TriggerAddCondition(t, Condition(function AbThunderstorm))
call TriggerRegisterTimerEvent(t, .75, true)
As I said, here you can use timers instead of a trigger.

call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_ENDCAST)
Don't register this event to all units, only to the unit that is casting ;).

In "AbThunderstorm" function:

local group g = CreateGroup()
For enumerations you can use bj_lastCreatedGroup. With this group, you don't need to create a new one and also you don't need to destroy it (only clean it when you done).

call GroupEnumUnitsInRange(g, x, y, 25*lvl, Filter(function AbThunderstorm_TrueBoolexpr))
Don't use a filter (in this case) to filter the units in a enumeration, make it (the filter) in the loop.

IsUnitType(u2, UNIT_TYPE_DEAD)
To check if the unit is dead, look at his life with GetWidgetLife.

I don't like at all what you're doing on that loop :S. You're creating a new trigger per iteration. If you look at that, you have the same period (wich is 1), so (if I'm not wrong, sorry if I'm) you can use only one trigger/timer for all of the units.

set u2 = null
You don't need to null this. Check the loop's condition ;).

And, I think that the sounds must be destroyed.

You should really try to work with vJASS ;).

Greetings, nice work :) and sorry for my english e__e.
 
Top