1. Are you planning to upload your awesome spell or system to Hive? Please review the rules here.
    Dismiss Notice
  2. Updated Resource Submission Rules: All model & skin resource submissions must now include an in-game screenshot. This is to help speed up the moderation process and to show how the model and/or texture looks like from the in-game camera.
    Dismiss Notice
  3. DID YOU KNOW - That you can unlock new rank icons by posting on the forums or winning contests? Click here to customize your rank or read our User Rank Policy to see a list of ranks that you can unlock. Have you won a contest and still havn't received your rank award? Then please contact the administration.
    Dismiss Notice
  4. Travel to distant realms and encounter scenes unknown to the common folk. The Greatest of Adventures is upon us with the 8th Cinematic Contest. Join in on a fun ride.
    Dismiss Notice
  5. The 18th Icon Contest is ON! Choose any ingame unit and give him/her Hero abilities. Good luck to all.
    Dismiss Notice
  6. The Secrets of Warcraft 3 have revealed interesting works. The RESULTS for Abelhawk's Mini-Mapping Contest #15 have come out!
    Dismiss Notice
  7. Contestants are to create a scene set in the Stone Age. Come and see what you can come up with. We wish you the best of luck!
    Dismiss Notice
  8. Colour outside the lines! Techtree Contest #13 is a go. The contest is optionally paired.
    Dismiss Notice
  9. Night Rider gained several songs for his journey. The poll for the 12th Music Contest has started. Check it out!
    Dismiss Notice
  10. Greetings cerebrates, our Swarm needs new spawners that will have numerous children. Join the HIVE's 31st Modeling Contest - Spawners and Spawned! The contest is optionally paired.
    Dismiss Notice
  11. Check out the Staff job openings thread.
    Dismiss Notice
Dismiss Notice
60,000 passwords have been reset on July 8, 2019. If you cannot login, read this.

Blizzard Alternative v1.2.1

Submitted by BPower
This bundle is marked as approved. It works and satisfies the submission rules.

Blizzard



Calls down waves of freezing ice shards that damage units in a target area.


Obligatory Requirements


  • Code (vJASS):
    //===========================================================================
    // Blizzard ( Ability ) by BPower.
    //     - Version 1.2.1
    //===========================================================================
    //
    //    Calls down waves of freezing ice shards that damage units in a target area.
    //
    //===========================================================================
    //
    //    Requirements:
    //
    //        CTL                 -    github.com/nestharus/JASS/tree/master/jass/Systems/ConstantTimerLoop32
    //        Table               -    hiveworkshop.com/forums/jass-resources-412/snippet-new-table-188084/
    //        SpellEffectEvent    -    hiveworkshop.com/forums/jass-resources-412/snippet-spelleffectevent-187193/
    //
    //===========================================================================
    //
    //    Credits:
    //
    //        To Nestharus for CTL
    //        To Bribe for Table and SpellEffectEvent
    //        To Vexorian for dummy.mdx
    //
    //===========================================================================

    native UnitAlive takes unit id returns boolean

    scope Blizzard initializer Init

        // User settings:
        // ==============
       
        globals        
            // Object editor fields:
            private constant integer    BLIZZARD_ABILITY      = 'A000'
            private constant integer    DUMMY_UNIT_ID         = 'dumi'
           
            // Damage options:
            private constant attacktype ATTACK_TYPE           = ATTACK_TYPE_NORMAL
            private constant damagetype DAMAGE_TYPE           = DAMAGE_TYPE_MAGIC
           
            // Effect options:
            private constant real       NEEDLE_FX_DURATION    = 0.8// Requires testing. Try and error.
            private constant string     NEEDLE_FX             = "war3mapImported\\SnowyBlizzardTarget.mdx"
            private constant string     GROUND_FX             = "war3mapImported\\FreezingField.mdx"
           
            // Balance options:
            // Bring structure into the chaos, by dividing the area of effect into sectors.
            // New needles will be created in random unique sectors to
            // ensure a better distribution of spawned effects.
            private constant integer    DISTRIBUTION_FACTOR   = 10
           
            // Accuracy options:
            // Maximum collision size in your map.
            private constant real       MAX_COLLISION_SIZE    = 64.
            private constant real       NEEDLE_COLLISION_SIZE = 48.
        endglobals
       
        // Filter valid targets.
        private function TargetFilter takes unit target, player owner returns boolean
            return UnitAlive(target) and not IsUnitType(target, UNIT_TYPE_MAGIC_IMMUNE) and not IsUnitType(target, UNIT_TYPE_STRUCTURE) and IsUnitEnemy(target, owner)
        endfunction
       
        // Returns the damage amount per needle.
        private function GetImpactDamage takes integer level returns real
            return GetRandomReal(10., 15.) + 20.*level
        endfunction
       
        // Returns the amount of needles created per seconds.
        private constant function GetNeedlesPerSecond takes integer level returns integer
            return 1 + 2*level
        endfunction
       
        // Returns the total spell duration in seconds.
        private constant function GetSpellDuration takes integer level returns real
            return 3. + 2.*level
        endfunction
         
        // Returns the radius of the blizzard field.
        private constant function GetFieldRadius takes integer level returns real
            return 200. + 50.*level
        endfunction
       
        // Returns the duration of the frost buff.
        private constant function GetBuffDuration takes integer level returns real
            return 4. + 0.*level
        endfunction
       
        // Returns the proper scaling of the ground effect. Eventually requires try and error.
        private constant function GetFieldEffectScale takes real fieldSize returns real
            return fieldSize/400.
        endfunction
       
        private function IsChanneling takes unit caster, integer level returns boolean
            return true
        endfunction
       
        // Global condition to keep the spell running.
        private function CasterCondition takes unit caster returns boolean
            return UnitAlive(caster)
        endfunction
       
        // The following struct "Buff" creates the buff- and frostnova effect.
        // Adjust the constants to your needs.    
        private struct Buff
            // Buff type settings.
            private static constant integer BUFF_ORDER_ID  = 852226
            private static constant integer BUFF_ABILITY   = 'A001'
            private static constant integer BUFF           = 'Bfro'
            //
            private static constant integer CASTER_UNIT_ID = 'n000'
            private static constant player  NEUTRAL_PLAYER = Player(bj_PLAYER_NEUTRAL_EXTRA)
            private static constant timer   TIMER          = CreateTimer()
            private static constant real    TIMER_TIMEOUT  = .03125
            private static constant integer LOCUST_ABILITY = 'Aloc'
       
            private static thistype array prev
            private static thistype array next
       
            private static unit  caster
            private static Table table
       
            private unit source
            private real time
           
            static method unitHasBuff takes unit whichUnit returns boolean
                return GetUnitAbilityLevel(whichUnit, BUFF) != 0
            endmethod
           
            method destroy takes nothing returns nothing
                call UnitRemoveAbility(source, BUFF)
                call table.remove(GetHandleId(source))
                call deallocate()
           
                set next[prev[this]] = next[this]
                set prev[next[this]] = prev[this]
                if next[0] == 0 then
                    call PauseTimer(TIMER)
                endif
               
                set source = null
            endmethod
       
            private static method onPeriodic takes nothing returns nothing
                local thistype this = next[0]
           
                loop
                    exitwhen this == 0
                    if time > 0. and UnitAlive(source) and unitHasBuff(source) then
                        set time = time - TIMER_TIMEOUT
                    else
                         call destroy()
                    endif
                    set this = next[this]
                endloop
            endmethod
           
            static method apply takes player owner, unit target, real duration returns nothing
                local integer  id = GetHandleId(target)
                local thistype this
           
                if table.has(id) then
                    set this = table[id]
                    if unitHasBuff(source) then
                        set time = duration
                        return
                    endif
                    call destroy()
                endif
           
                call IssueTargetOrderById(caster, BUFF_ORDER_ID, target)
                set this = allocate()
                set table[id] = this
                set source = target
                set time = duration
               
                set next[this] = 0
                set prev[this] = prev[0]
                set next[prev[0]] = this
                set prev[0] = this
                if prev[this] == 0 then
                    call TimerStart(TIMER, TIMER_TIMEOUT, true, function thistype.onPeriodic)
                endif
            endmethod
       
            private static method onInit takes nothing returns nothing
                set table = Table.create()
                set caster = CreateUnit(NEUTRAL_PLAYER, CASTER_UNIT_ID, 0., 0., 0.)
                call SetUnitPosition(caster, 2147483647, 2147483647)
                call UnitAddAbility(caster, BUFF_ABILITY)
                call UnitAddAbility(caster, LOCUST_ABILITY)
                call ShowUnit(caster, false)
            endmethod
        endstruct
       
    //================================================================
    // Blizzard source code. Make changes carefully.
    //================================================================
       
        private function Random takes nothing returns real
            return GetRandomReal(0., 1.)
        endfunction
       
        private function GetRandomRange takes real radius returns real
            local real r = Random() + Random()
            if r > 1. then
                return (2 - r)*radius
            endif
            return r*radius
        endfunction

        private struct Needle
            real x
            real y
            real time
           
            static method create takes real centerX, real centerY, real maxRange, integer factor returns thistype
                local thistype this = thistype.allocate()
                local real spacing  = 2*bj_PI/DISTRIBUTION_FACTOR
                local real min      = spacing*factor
                local real max      = min + spacing
                local real theta    = GetRandomReal(min, max)
                local real radius   = GetRandomRange(maxRange)
               
                set x    = centerX + radius*Cos(theta)
                set y    = centerY + radius*Sin(theta)
                set time = NEEDLE_FX_DURATION
                call DestroyEffect(AddSpecialEffect(NEEDLE_FX, x, y))
               
                return this
            endmethod
           
        endstruct
       
        private struct Blizzard extends array
            static constant group   ENUM_GROUP       = CreateGroup()
            static constant real    TIMER_TIMEOUT    = .03125
            static constant real    DUMMY_DEATH_TIME = .01
            static constant integer TIMED_LIFE       = 'BTLF'
            static constant integer TABLE_OFFSET     = 0x2710
           
            Table   table
            integer size
            integer sectors

            unit    source
            unit    dummy
            effect  fx
            player  user
           
            real    radius
            real    time
            real    timeout
            real    centerX
            real    centerY
            real    duration
            integer level
            integer order
            boolean channel
       
            method getRandomSector takes nothing returns integer
                local integer random
                local integer sector
               
                if DISTRIBUTION_FACTOR == 1 then
                    return 0
               
                // Fills up the table with unique integers from 0 to DISTRIBUTION_FACTOR.
                elseif sectors == 0 then
                    loop
                        exitwhen sectors == DISTRIBUTION_FACTOR
                        set table[TABLE_OFFSET + sectors] = sectors
                        set sectors = sectors + 1
                    endloop
                endif
               
                // Get an unique integer from the table.
                set sectors = sectors - 1
                set random  = GetRandomInt(0, sectors)
                set sector  = table[TABLE_OFFSET + random]
                set table[TABLE_OFFSET + random] = table[TABLE_OFFSET + sectors]
               
                return sector
            endmethod
       
            implement CTL
                local unit u
                local Needle needle
                local integer index
                local real damage
                local real slow
            implement CTLExpire
           
                if not CasterCondition(source) or duration <= 0. or (channel and GetUnitCurrentOrder(source) != order) then
                    if size == 0 then
                        call destroy()
                        call table.destroy()
                        call DestroyEffect(fx)
                        call UnitApplyTimedLife(dummy, TIMED_LIFE, DUMMY_DEATH_TIME)
                       
                        set fx = null
                        set user = null
                        set dummy = null
                        set source = null
                    endif
                else
                    set duration = duration - TIMER_TIMEOUT
                    set time = time + TIMER_TIMEOUT
                    loop
                        exitwhen time < timeout
                        set table[size] = Needle.create(centerX, centerY, radius, getRandomSector())
                        set size = size + 1
                        set time = time - timeout
                    endloop
                endif

                // Loop over all falling needles.
                set index = 0
                loop
                    exitwhen index == size
                    set needle = table[index]
                   
                    if needle.time > 0. then
                        set needle.time = needle.time - TIMER_TIMEOUT
                        set index = index + 1
                    else
                        set damage = GetImpactDamage(level)
                        set slow   = GetBuffDuration(level)
                   
                        call GroupEnumUnitsInRange(ENUM_GROUP, needle.x, needle.y, NEEDLE_COLLISION_SIZE + MAX_COLLISION_SIZE, null)
                        loop
                            set u = FirstOfGroup(ENUM_GROUP)
                            exitwhen u == null
                            call GroupRemoveUnit(ENUM_GROUP, u)
       
                            if IsUnitInRangeXY(u, needle.x, needle.y, NEEDLE_COLLISION_SIZE*1.5) and TargetFilter(u, user) then
                                if UnitDamageTarget(source, u, damage, false, false, ATTACK_TYPE, DAMAGE_TYPE, null) then
                                    call Buff.apply(user, u, slow)
                                endif
                            endif
                        endloop
                       
                        call needle.destroy()
                        set size = size - 1
                        set table[index] = table[size]
                    endif
                endloop
            implement CTLEnd
       
            static method onEffect takes nothing returns nothing
                local thistype this = thistype.create()
               
                set user     = GetTriggerPlayer()
                set source   = GetTriggerUnit()
                set centerX  = GetSpellTargetX()
                set centerY  = GetSpellTargetY()
                set level    = GetUnitAbilityLevel(source, BLIZZARD_ABILITY)
                set radius   = GetFieldRadius(level)
                set duration = GetSpellDuration(level)
                set timeout  = 1./IMaxBJ(1, GetNeedlesPerSecond(level))
                set channel  = IsChanneling(source, level)
                set order    = GetUnitCurrentOrder(source)
                set dummy    = CreateUnit(user, DUMMY_UNIT_ID, centerX, centerY, 2*bj_PI*Random())
                set fx       = AddSpecialEffectTarget(GROUND_FX, dummy, "origin")
                set table    = Table.create()
                set time     = 0.
                set sectors  = 0// Available sectors. Like cutting a piece of cake.
                call SetUnitScale(dummy, GetFieldEffectScale(radius), 0., 0.)
            endmethod

        endstruct
       
        private function Init takes nothing returns nothing
            debug local string text
            debug if DISTRIBUTION_FACTOR <= 0 then
                debug set text = "|cffffa500Error:|r |cff99b4d1In trigger Blizzard, scope Blizzard!|r\n"
                debug set text = text + "|cffffa500Global user settings: |cff99b4d1constant integer DISTRIBUTION_FACTOR = " + I2S(DISTRIBUTION_FACTOR) + "!|r\n"
                debug set text = text + "|cffffa500Solution: |cff99b4d1DISTRIBUTION_FACTOR must be bigger than 0!|r"
           
                debug call DisplayTimedTextToPlayer(GetLocalPlayer(), 0.00, 0.00, 3600.00, text)
            debug endif
            //
            call RegisterSpellEffectEvent(BLIZZARD_ABILITY, function Blizzard.onEffect)
        endfunction
       
    endscope


Credits:
Nestharus, Bribe​

Keywords:
Blizzard, ice, snow, cold, slow
Contents

Blizzard ( Ability ) (Map)

Reviews
Moderator
Blizzard Alternative v1.0.0.0 | Reviewed by Maker | 02.01.14 Concept[/COLOR]] [IMG] Recreating an already existing spell is not extremely exciting but it can be useful since one has more flexibility over the standard spell [IMG] The...
  1. Blizzard Alternative v1.0.0.0 | Reviewed by Maker | 02.01.14
    • Concept[/COLOR]]
      [​IMG]
      • Recreating an already existing spell is not extremely exciting
        but it can be useful since one has more flexibility over the
        standard spell
      [​IMG]
      • The standard Blizzard is channeled so you could add an option for that
    • Triggers[/COLOR]]
      [​IMG]
      • Very good coding. High performance, leakless, MUI
        and overall very clear
      [​IMG]
      • Regarding damage types, cold, fire, poison etc. are all of the same main category, magical.
        I recommend using
        DAMAGE_TYPE_MAGIC
        ,
        but it works just the same as cold
      • Nulling the local trigger is not needed
        but it won't make a difference if you do null it
    • Objects[/COLOR]]
      [​IMG]
      • Everything seems to be in order here
        Though it is a bit weird that the hotkey is not coloured
        in the learned tooltip
    • Effects[/COLOR]]
      [​IMG]
      • The effects are fine, could not ask for more
    • Rating[/COLOR]]
      CONCEPT TRIGGERS OBJECTS EFFECTS RATING STATUS
      [​IMG] [​IMG] [​IMG] [​IMG] [​IMG] APPROVED

     
  2. TriggerHappy

    TriggerHappy

    Code Moderator

    Joined:
    Jun 23, 2007
    Messages:
    3,654
    Resources:
    22
    Spells:
    11
    Tutorials:
    2
    JASS:
    9
    Resources:
    22
    Yes! You made the trivial requirements optional!

    The coding is great, but I did notice this;

    Code (vJASS):

    set d = (NEUTRAL,DUMMY_CASTER,0,0,0)

    // should be

    set d = CreateUnit(NEUTRAL,DUMMY_CASTER,0,0,0)
     
     
    Last edited: Dec 21, 2013
  3. BPower

    BPower

    Joined:
    Mar 18, 2012
    Messages:
    1,741
    Resources:
    21
    Spells:
    15
    Tutorials:
    1
    JASS:
    5
    Resources:
    21
    Oh I missed that while debugging, thank you. Fixed.
     
    Last edited: Dec 21, 2013
  4. TriggerHappy

    TriggerHappy

    Code Moderator

    Joined:
    Jun 23, 2007
    Messages:
    3,654
    Resources:
    22
    Spells:
    11
    Tutorials:
    2
    JASS:
    9
    Resources:
    22
    I personally would just hide the unit on initialization rather than settings it's position to the edge of the map.

    SetUnitPosition is extremely slow (compared to other natives) as you can see in my bencharking thread.
     
  5. Rheiko

    Rheiko

    Joined:
    Aug 27, 2013
    Messages:
    2,936
    Resources:
    7
    Icons:
    2
    Spells:
    3
    Tutorials:
    2
    Resources:
    7
  6. BPower

    BPower

    Joined:
    Mar 18, 2012
    Messages:
    1,741
    Resources:
    21
    Spells:
    15
    Tutorials:
    1
    JASS:
    5
    Resources:
    21
    Hidden units can't issue orders (going to test that). So I would have to check for every spell cast if the unit is hidden or run a timer after map init and unhide it.

    SetUnitPos is called one time per game, it shouldn't matter at all nor noticeable prolong the loading time.
     
  7. Ofel

    Ofel

    Joined:
    Mar 29, 2012
    Messages:
    439
    Resources:
    10
    Spells:
    10
    Resources:
    10
    The effects is awesome!
     
  8. Doomlord

    Doomlord

    Joined:
    Dec 15, 2011
    Messages:
    1,150
    Resources:
    14
    Spells:
    12
    JASS:
    2
    Resources:
    14
    Hello.

    I just came across this one by chance and I noticed that it is quite similiar to my own http://www.hiveworkshop.com/forums/spells-569/jass-freezing-field-v1-1d-228101/. Reckon that it is the "written once before" spell you mentioned. I may be wrong though so please forgive if I misunderstood.

    This spell has overall better performance than mine for sure but I think that the ice shards' positioning could be improved a bit so that it can spread equally around the AoE (which more or less lessens the chance an enemy can pass through this unharmed). I am perfectly alright if you don't approve of my suggestion though, don't worry :)
     
  9. BPower

    BPower

    Joined:
    Mar 18, 2012
    Messages:
    1,741
    Resources:
    21
    Spells:
    15
    Tutorials:
    1
    JASS:
    5
    Resources:
    21
    Hi Doomlord,

    indeed it is your resource I am refering to. After checking a lot of potential Blizzard ice shard models, I didn't found one which could be used for a acceptable missle.

    So I sticked to the idea you already had, by just using an effect and making the falling time not configurable.

    Yes true I'll think about it, shouldn't be too difficult. :)

    If you want I can add a link to your spell in the description as good alternative. Afterall it has no requirements and is written in JASS which can be plus.
     
  10. Doomlord

    Doomlord

    Joined:
    Dec 15, 2011
    Messages:
    1,150
    Resources:
    14
    Spells:
    12
    JASS:
    2
    Resources:
    14
    If that is alright with you then I am more than willing to accept. Thank you :)

    Good luck with your work on this spell :grin:
     
  11. BPower

    BPower

    Joined:
    Mar 18, 2012
    Messages:
    1,741
    Resources:
    21
    Spells:
    15
    Tutorials:
    1
    JASS:
    5
    Resources:
    21
    I was quite sure, that I'll never update this spell ... :/

    Small update:

    1. The spell can now also be channeling, similar to the Archmage Blizzard spell.

    2. Improved documentation.

    3. MissileRecycler is now an optional requirement. This will allow you to scale the ground effect.

    4. Slightly improved the code.
    Code (vJASS):
            static if not LIBRARY_SpellEffectEvent then
                private static method condition takes nothing returns boolean
                    return (GetSpellAbilityId() == ABILITY_ID) and thistype.onCast()
                endmethod
            endif


    5. Removed alloc module as requirement.

    6. Cleaned up the demo map a bit.

    7. Imapct damage is now more dynamic, as it is computated now everytime before the group enum, instead of once on cast.
     
  12. Bribe

    Bribe

    Joined:
    Sep 26, 2009
    Messages:
    8,006
    Resources:
    25
    Maps:
    3
    Spells:
    10
    Tutorials:
    3
    JASS:
    9
    Resources:
    25
    Code (vJASS):
    R2I(GetDuration(level)/.031250000)

    ->

    R2I(GetDuration(level)/.03125 + 0.50) //This way it rounds up if it should

    local real angle = GetRandomReal(0, TWO_PI)

    ->

    local real angle = GetRandomReal(-bj_PI, bj_PI) //Sin and Cos take numbers in this range
     
     
  13. BPower

    BPower

    Joined:
    Mar 18, 2012
    Messages:
    1,741
    Resources:
    21
    Spells:
    15
    Tutorials:
    1
    JASS:
    5
    Resources:
    21
    Seems legit. Changes made.
     
  14. xorkatoss

    xorkatoss

    Joined:
    Jul 12, 2010
    Messages:
    1,509
    Resources:
    7
    Models:
    5
    Maps:
    1
    Spells:
    1
    Resources:
    7
    hmm can't really comment on the coding since i don't know vJass but the spell is neat good job man!
     
  15. pred1980

    pred1980

    Joined:
    Mar 19, 2010
    Messages:
    844
    Resources:
    1
    Maps:
    1
    Resources:
    1
    great spell... Interested in creating a complete hero for my map?
     
  16. BPower

    BPower

    Joined:
    Mar 18, 2012
    Messages:
    1,741
    Resources:
    21
    Spells:
    15
    Tutorials:
    1
    JASS:
    5
    Resources:
    21
    Sounds cool, but I don't have enought time to do that.

    Thanks for the feedback :)
     
  17. pred1980

    pred1980

    Joined:
    Mar 19, 2010
    Messages:
    844
    Resources:
    1
    Maps:
    1
    Resources:
    1
    ok :( - If you have time, let me know :)
     
  18. BPower

    BPower

    Joined:
    Mar 18, 2012
    Messages:
    1,741
    Resources:
    21
    Spells:
    15
    Tutorials:
    1
    JASS:
    5
    Resources:
    21
    Changelog:
    • Distribution is now circular and uniform. Thanks to Flux.
    • The dummy recycler is no longer required. It's just one unit per spell cast.
    • I put the buff into a seperate struct to allow better user configuration.
    • Added a distribution factor to add a balancing factor.
     
  19. Bribe

    Bribe

    Joined:
    Sep 26, 2009
    Messages:
    8,006
    Resources:
    25
    Maps:
    3
    Spells:
    10
    Tutorials:
    3
    JASS:
    9
    Resources:
    25
    So with this update, the effects no longer overlap? That's something which bugs me with the custom Blizzard I recently made for Spell System.