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. The raddest synthwave tracks were chosen - Check out our Music Contest #12 - Results and congratulate the winners!
    Dismiss Notice
  5. The poll for Hive's 12th Concept Art Contest is up! Go cast your vote for your favourite genie!
    Dismiss Notice
  6. 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
  7. The 18th Icon Contest is ON! Choose any ingame unit and give him/her Hero abilities. Good luck to all.
    Dismiss Notice
  8. 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
  9. Colour outside the lines! Techtree Contest #13 is a go. The contest is optionally paired.
    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.

Apex Blizzard V1.00

Submitted by Tank-Commander
This bundle is marked as approved. It works and satisfies the submission rules.
Zephyr Contest #15 entry - Apex Blizzard

Tooltip


Q - Apex Blizzard
Releases a torrent of ice from the target point which locks on to the first target hit dealing damage while engulfing them and all nearby units in ice, stunning them

Level 1 - 300 damage to primary target, 125 damage AOE, 3 second stun
Level 2 - 400 damage to primary target, 200 damage AOE, 4 second stun
Level 3 - 500 damage to primary target, 275 damage AOE, 5 second stun

Code

Show
Code (vJASS):
////////////////////////////////////////////////////////////////////
//                       APEX BLIZZARD V1.00                      //
//  Author: Tank-Commander                                        //
//  Purpose: Designed for General Frank's Icecrown Overlord       //
//           to blast away vast swathes of enemies in a           //
//           literally cool style                                 //
//                                                                //
//  Notes:                                                        //
//    -  Read the readme before you try modifying the config      //
//    -  Use the "Helpful files" to help you import the system    //
//                                                                //
//  Credits:                                                      //
//    -  (Dummy.mdl) Vexorian                                     //
//    -  (IceCube.mdl) Pyritie                                    //
//    -  (FrostNova.mdl) JetFangInferno                           //
//    -  (FrozenShell.mdl) Daelin                                 //
//    -  (FrozenOrb.mdl) Daelin                                   //
//                                                                //
//  If you have used this spell in your map, you are required     //
//  to give credits to Tank-Commander for the creation of it      //
//  If you would like to use snippets of code from this for       //
//  whatever, getting permission and crediting the source/linking //
//  would be much appreciated.                                    //
////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////
//  README:                                                       //
//    Before modifying this spell a few things need to be         //
//    understood and read, this is one of those things, while     //
//    most modification can be considered intuitive, it still     //
//    helps to read through these intstructions, as they will     //
//    inform you about how to configure this spell to your        //
//    desire.                                                     //
//----------------------------------------------------------------//
//  Initial importing: The variable creator trigger can be        //
//  imported first and if you have the correct settings (file,    //
//  preferences, General, automatically create unknown variables  //
//  checked, then when you paste in the variable creator it       //
//  will automatically give you all the variables you need for    //
//  this spell                                                    //
//                                                                //
//  While the remaining object editor based data is not required  //
//  to function (provided they're replaced with equivelents)      //
//  it's recommended that they are also imported, if their data   //
//  value are not the same as listed in the configuration, those  //
//  configurables will need to be changed to work correctly       //
//----------------------------------------------------------------//
//                           MISC                                 //
//----------------------------------------------------------------//
//  TimerSpeed: the time in seconds between each iteration of     //
//  the main loop function (default is 0.031250000) it's          //
//  recommended you leave it like that                            //
constant function APEX_TimerSpeed takes nothing returns real
    return 0.031250000
endfunction
//----------------------------------------------------------------//
//  AbilityID: This is the data value used for the base of the    //
//  ability, it's recommended you base this off channel           //
//  (use Ctrl + D to view raw data in the object editor, do it    //
//  again to return to the normal view)                           //
constant function APEX_AbilityID takes nothing returns integer
    return 'A001'
endfunction
//----------------------------------------------------------------//
//  BuffID: This is the data value of the ability used to apply   //
//  the buff signifying that a unit is currently the target of    //
//  the spell, recommended to base this off slow aura             //
constant function APEX_BuffID takes nothing returns integer
    return 'A000'
endfunction
//----------------------------------------------------------------//
//  StunAbility: This is the data value of the ability used to    //
//  stun the units that are frozen by the ability recommended to  //
//  base this of war stomp                                        //
constant function APEX_StunAbilityID takes nothing returns integer
    return 'A003'
endfunction
//----------------------------------------------------------------//
//  StunBuffID: This is the data value of the buff that           //
//  signifies that a unit has been stunned, it should be applied  //
//  by the StunAbility when it stuns a unit                       //
constant function APEX_StunBuffID takes nothing returns integer
    return 'B001'
endfunction
//----------------------------------------------------------------//
//  DummyID: This is the data value of the dummy unit used as a   //
//  base for all of the effects of the spell, it should use       //
//  dummy.mdl as its model                                        //
constant function APEX_DummyID takes nothing returns integer
    return 'u000'
endfunction
//----------------------------------------------------------------//
//  DummyPlayer: This is the player that has ownership of all     //
//  the dummy units created by the spell, setting it to 14        //
//  ensures that the scoreboard is not interfered with            //
constant function APEX_DummyPlayer takes nothing returns player
    return Player(14)
endfunction
//----------------------------------------------------------------//
//  StunOrderID: This is the Order ID for the stun ability, for   //
//  war stomp this is 852127, it must match or units will not be  //
//  stunned by the spell                                          //
constant function APEX_StunOrderID takes nothing returns integer
    return 852127
endfunction
//----------------------------------------------------------------//
//                          DAMAGE                                //
//----------------------------------------------------------------//
//  Range: This is how far the seeking projectiles will travel    //
//  from the spell origin before being destroyed                  //
function APEX_Range takes real level returns real
    return 300 + (50 * level)
endfunction
//----------------------------------------------------------------//
//  AOE: This is the area of effect of the damage and stun of     //
//  the spell, it will be centered around the target rather than  //
//  the origin of the spell                                       //
function APEX_AOE takes real level returns real
    return 300 + (50 * level)
endfunction
//----------------------------------------------------------------//
//  AOEDamageHealth: This is the amount of damage dealt to all    //
//  units within the AOE (primary target also takes this damage)  //
function APEX_AOEDamageHealth takes real level returns real
    return 50 + (75 * level)
endfunction
//----------------------------------------------------------------//
//  AOEDamageMana: This is the amount of mana lossed by all       //
//  units within the AOE (primary target also takes this loss)    //
function APEX_AOEDamageMana takes real level returns real
    return 0.
endfunction
//----------------------------------------------------------------//
//  ProjectileDamageHealth: This is the total amount of damage    //
//  the projectiles will deal to the primary target's health      //
function APEX_ProjectileDamageHealth takes real level returns real
    return 200 + (100 * level)
endfunction
//----------------------------------------------------------------//
//  ProjectileDamageMana: This is the total amount of damage      //
//  the projectiles will deal to the primary target's mana        //
function APEX_ProjectileDamageMana takes real level returns real
    return 0.
endfunction
//----------------------------------------------------------------//
//  StunDuration: This is how long all units are stunned by the   //
//  ability in seconds                                            //
function APEX_StunDuration takes real level returns real
    return 2. + (1. * level)
endfunction
//----------------------------------------------------------------//
//  StunStartMaxTimeout: This is how long in seconds it takes     //
//  for the furthert targets (targets at max AOE distance) to     //
//  become stunned - this create a more natural expanding feel    //
//  to the stun                                                   //
function APEX_StunStartMaxTimeout takes real level returns real
    return 0.15
endfunction
//----------------------------------------------------------------//
//  AttachkType: This is the attack type used by all damaging     //
//  aspects of the spell                                          //
constant function APEX_AttackType takes nothing returns attacktype
    return ATTACK_TYPE_NORMAL
endfunction
//----------------------------------------------------------------//
//  AttachkType: This is the damage type used by all damaging     //
//  aspects of the spell                                          //
constant function APEX_DamageType takes nothing returns damagetype
    return DAMAGE_TYPE_NORMAL
endfunction
//----------------------------------------------------------------//
//  AttachkType: This is the weapon type used by all damaging     //
//  aspects of the spell                                          //
constant function APEX_WeaponType takes nothing returns weapontype
    return null
endfunction
//----------------------------------------------------------------//
//                         BEHAVIOUR                              //
//----------------------------------------------------------------//
//  ProjectileCountCircle: This is the amount of seeking lines    //
//  created by the spell (more makes it easier to hit targets)    //
function APEX_ProjectileCountCircle takes real level returns integer
    return 10
endfunction
//----------------------------------------------------------------//
//  ProjectileCountArc: This is the amount of projectiles that    //
//  are launched down each seek line, (more makes the seek line   //
//  longer and thus easier to hit targets) mostly makes the       //
//  spell look better                                             //
function APEX_ProjectileCountArc takes real level returns integer
    return 0 + (1 * R2I(level))
endfunction
//----------------------------------------------------------------//
//  ProjectileHitBox: This is how close to another unit a         //
//  seeking projectile has to get in order to hit it and set it   //
//  as the spell target                                           //
function APEX_ProjectileHitBox takes real level returns real
    return 80.
endfunction
//----------------------------------------------------------------//
//  TargetHeight: This is how far off the ground the projectiles  //
//  will aim to be (visual effect only)                           //
constant function APEX_TargetHeight takes nothing returns real
    return 70.
endfunction
//----------------------------------------------------------------//
//  ProjectileTurnRate: This is the strength at which the         //
//  Projectiles are pulled towards the target - this does affect  //
//  the speed of the projectile and should almost never be a      //
//  a negative value as that may cause crashes                    //
constant function APEX_ProjectileTurnRate takes real level returns real
    return 1.
endfunction
//----------------------------------------------------------------//
//  ProjectileTurnEfficiency: This is the rate at which existing  //
//  momentum is converted to be toward the target unit (this      //
//  will cause the projectile to slow when turning) 1 converts    //
//  50% each cycle, 0.5 converts 25% and so on                    //
constant function APEX_ProjectileTurnEfficiency takes real level returns real
    return 0.08
endfunction
//----------------------------------------------------------------//
//  ProjectileAcceleration: This is the percentage increase in    //
//  speed the projectile gains or loses each cycle (1.01 being    //
//  an increase of 1% speed)                                      //
constant function APEX_ProjectileAcceleration takes real level returns real
    return 1.01
endfunction
//----------------------------------------------------------------//
//  ProjectileLaunchPower: This is the net momentum that          //
//  projectiles are launched out of the origin point of the       //
//  spell                                                         //
constant function APEX_ProjectileLaunchPower takes real level returns real
    return 40.
endfunction
//----------------------------------------------------------------//
//  SpeedMultiplyer: This is the number of movement steps         //
//  calculated when a target has been caught, increasing this     //
//  number takes up much more processing but increases the speed  //
//  that projectiles hit their target without altering their      //
//  behaviour otherwise, 2-4 are safe values                      //
constant function APEX_SpeedMultiplyer takes real level returns integer
    return 2
endfunction
//----------------------------------------------------------------//
//  Gravity: This is the strength at which unguided projectiles   //
//  are pulled towards the ground regardless of their own         //
//  intended direction                                            //
constant function APEX_Gravity takes nothing returns real
    return 0.3065
endfunction
//----------------------------------------------------------------//
//                          MODELS                                //
//----------------------------------------------------------------//
//  ProjectileAttachmentPoint: This is where on the dummy unit    //
//  that the ProjectileModel will be attached                     //
constant function APEX_ProjectileAttachmentPoint takes nothing returns string
    return "origin"
endfunction
//----------------------------------------------------------------//
//  ProjectileModel: This is the path for the model used for the  //
//  projecitles, remember to place double slashes ("\\") instead  //
//  of single slashes ("\") as this will cause a compilation      //
//  error                                                         //
constant function APEX_ProjectileModel takes nothing returns string
    return "war3mapImported\\FrozenOrb.mdl"
endfunction
//----------------------------------------------------------------//
//  ProjectileScale: This is the size of the projectiles relative //
//  to the base model's size (1. = 100% or normal size)           //
function APEX_ProjectileScale takes real level returns real
    return 0.8 + (0.1 * level)
endfunction
//----------------------------------------------------------------//
//  ExplosionAttachmentPoint: This is where on the dummy unit     //
//  that the explosion (AOE effect) will be attached              //
constant function APEX_ExplosionAttachmentPoint takes nothing returns string
    return "origin"
endfunction
//----------------------------------------------------------------//
//  ExplosionModel: This is the path for the model used for the   //
//  explosion (AOE effect)                                        //
constant function APEX_ExplosionModel takes nothing returns string
    return "war3mapImported\\FrostNova.mdx"
endfunction
//----------------------------------------------------------------//
//  TargetAttachmentPoint: This is where on the target unit that  //
//  the target marker (identifies that this unit is being         //
//  targetted by the spell) will be attached                      //
constant function APEX_TargetAttachmentPoint takes nothing returns string
    return "chest"
endfunction
//----------------------------------------------------------------//
//  TargetModel: This is the path for the model used for the      //
//  target marker                                                 //
constant function APEX_TargetModel takes nothing returns string
    return "war3mapImported\\FrozenShell.MDX"
endfunction
//----------------------------------------------------------------//
//  FrozenAttachmentPoint: This is where on frozen units that     //
//  the frozen effect (identifies that this unit is stunned)      //
//  will be attached                                              //
constant function APEX_FrozenAttachmentPoint takes nothing returns string
    return "origin"
endfunction
//----------------------------------------------------------------//
//  FrozenModel: This is the path for the model used for the      //
//  frozen effect                                                 //
constant function APEX_FrozenModel takes nothing returns string
    return "war3mapImported\\ice cube.mdx"
endfunction
//----------------------------------------------------------------//
//  StartEffectModel: This is the path for the effect used at     //
//  start of the spell that projectiles are launched from         //
constant function APEX_StartEffectModel takes nothing returns string
    return "Abilities\\Spells\\Undead\\FrostNova\\FrostNovaTarget.mdl"
endfunction
//----------------------------------------------------------------//
//                        READ ONLY                               //
//----------------------------------------------------------------//
//  SpellCoreStageID: This is the ID given to spell cores to      //
//  make sure they run their aspects of the code only             //
constant function APEX_SpellCoreStageID takes nothing returns integer
    return 1
endfunction
//----------------------------------------------------------------//
//  ProjectileStageID: This is the ID given to proejctiles to     //
//  make sure they run their aspects of the code only             //
constant function APEX_ProjectileStageID takes nothing returns integer
    return 2
endfunction
//----------------------------------------------------------------//
//  StunnedUnitStageID: This is the ID given to stunned units to  //
//  make sure they run their aspects of the code only             //
constant function APEX_StunnedUnitStageID takes nothing returns integer
    return 3
endfunction
//----------------------------------------------------------------//
//                     END OF CONFIGURATION                       //
//----------------------------------------------------------------//
////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////
//  Target filter function used to differentiate between units    //
//  that can be hit by the spell and those that cannot            //
////////////////////////////////////////////////////////////////////
function APEX_TargetFilter takes unit u, player pl returns boolean
    return (not IsUnitType(u, UNIT_TYPE_STRUCTURE)) and (not IsUnitType(u, UNIT_TYPE_MAGIC_IMMUNE)) and (IsUnitEnemy(u, pl)) and (GetUnitTypeId(u) != APEX_DummyID()) and not(IsUnitType(u, UNIT_TYPE_DEAD) or GetUnitTypeId(u) == 0)
endfunction

////////////////////////////////////////////////////////////////////
//  Function used to get the Z location height at a given point   //
////////////////////////////////////////////////////////////////////
function APEX_GetZ takes real x, real y returns real
    call MoveLocation(udg_APEX_ZLoc, x, y)
    return GetLocationZ(udg_APEX_ZLoc)
endfunction

////////////////////////////////////////////////////////////////////
//  Function used to make sure that the location is within the    //
//  map bounds so that units cannot be moved outside of it and    //
//  get permanently stuck                                         //
////////////////////////////////////////////////////////////////////
function APEX_ValidateLocation takes real x, real y returns boolean
    //Check if the point is within the map bounds
    return (x < udg_APEX_MapMaxX) and (x > udg_APEX_MapMinX) and (y < udg_APEX_MapMaxY) and (y > udg_APEX_MapMinY)
endfunction

////////////////////////////////////////////////////////////////////
//  Function used to get the distance between two points (3D)     //
////////////////////////////////////////////////////////////////////
function APEX_Get3DDistance takes real x, real x2, real y, real y2, real z, real z2 returns real
    return SquareRoot((x2 - x) * (x2 - x) + (y2 - y) * (y2 - y) + (z2 - z) * (z2 - z))
endfunction

////////////////////////////////////////////////////////////////////
//  Function used to get the distance between two points (2D)     //
////////////////////////////////////////////////////////////////////
function APEX_Get2DDistance takes real x, real x2, real y, real y2 returns real
    return SquareRoot((x2 - x) * (x2 - x) + (y2 - y) * (y2 - y))
endfunction

////////////////////////////////////////////////////////////////////
//  Function used to remove instances from the linked list once   //
//  they have expired                                             //
////////////////////////////////////////////////////////////////////
function APEX_RecycleNode takes integer node returns nothing
    set udg_APEX_RecycleNodes[udg_APEX_RecyclableNodes] = node
    set udg_APEX_RecyclableNodes = udg_APEX_RecyclableNodes + 1
    set udg_APEX_NextNode[udg_APEX_PrevNode[node]] = udg_APEX_NextNode[node]
    set udg_APEX_PrevNode[udg_APEX_NextNode[node]] = udg_APEX_PrevNode[node]
endfunction

////////////////////////////////////////////////////////////////////
//  Function used to add new nodes to the linked list used by the //
//  spell                                                         //
////////////////////////////////////////////////////////////////////
function APEX_CreateNode takes nothing returns integer
    local integer node

    if (udg_APEX_RecyclableNodes == 0) then
        set udg_APEX_NodeNumber = udg_APEX_NodeNumber + 1
        set node = udg_APEX_NodeNumber
    else
        set udg_APEX_RecyclableNodes = udg_APEX_RecyclableNodes - 1
        set node = udg_APEX_RecycleNodes[udg_APEX_RecyclableNodes]
    endif
 
    set udg_APEX_NextNode[node] = 0
    set udg_APEX_NextNode[udg_APEX_PrevNode[0]] = node
    set udg_APEX_PrevNode[node] = udg_APEX_PrevNode[0]
    set udg_APEX_PrevNode[0] = node
 
    return node
endfunction

////////////////////////////////////////////////////////////////////
//  Function used to handle the behaviour of the projectiles      //
//  while in-flight and reports if the projectile has crashed     //
////////////////////////////////////////////////////////////////////
function APEX_MoveProjectile takes integer node returns boolean
    //Set up locals
    local real dy = udg_APEX_TargetY[node] - udg_APEX_ProjectileY[node]
    local real dx = udg_APEX_TargetX[node]- udg_APEX_ProjectileX[node]
    local real x
    local real y
    local real z
    local real Angle = Atan2(dy, dx)
    local real Angle2 = Atan2((APEX_GetZ(udg_APEX_TargetX[node], udg_APEX_TargetY[node]) + udg_APEX_TargetZ[node]) - (APEX_GetZ(udg_APEX_ProjectileX[node], udg_APEX_ProjectileY[node]) + GetUnitFlyHeight(udg_APEX_Unit[node])), Pow(dx * dx + dy * dy, 0.5))
    local real TempReal = Pow((udg_APEX_ZVel[node] * udg_APEX_ZVel[node]) + (udg_APEX_XVel[node] * udg_APEX_XVel[node]) + (udg_APEX_YVel[node] * udg_APEX_YVel[node]), 0.5) * udg_APEX_ProjectileTurnEfficiency[udg_APEX_Parent[node]]
    local real TempReal2 = 1/(1 + udg_APEX_ProjectileTurnEfficiency[udg_APEX_Parent[node]])
    local unit u
 
    //Calculate new velocities
    set udg_APEX_ZVel[node] = ((udg_APEX_ZVel[node] + (TempReal + udg_APEX_ProjectileTurnRate[udg_APEX_Parent[node]]) * Sin(Angle2)) * udg_APEX_ProjectileAcceleration[udg_APEX_Parent[node]]) * TempReal2
    set udg_APEX_XVel[node] = ((udg_APEX_XVel[node] + (TempReal + udg_APEX_ProjectileTurnRate[udg_APEX_Parent[node]]) * Cos(Angle) * Cos(Angle2)) * udg_APEX_ProjectileAcceleration[udg_APEX_Parent[node]]) * TempReal2
    set udg_APEX_YVel[node] = ((udg_APEX_YVel[node] + (TempReal + udg_APEX_ProjectileTurnRate[udg_APEX_Parent[node]]) * Sin(Angle) * Cos(Angle2)) * udg_APEX_ProjectileAcceleration[udg_APEX_Parent[node]]) * TempReal2
    set udg_APEX_ProjectileHeight[node] = udg_APEX_ProjectileHeight[node] + udg_APEX_ZVel[node] - APEX_Gravity()
 
    set x = udg_APEX_ProjectileX[node] + udg_APEX_XVel[node]
    set y = udg_APEX_ProjectileY[node] + udg_APEX_YVel[node]
    set z = udg_APEX_ProjectileHeight[node] - APEX_GetZ(x, y)
 
    //Make sure the location is within the map bounds
    if APEX_ValidateLocation(x, y) then
        set udg_APEX_ProjectileX[node] = x
        set udg_APEX_ProjectileY[node] = y
        call SetUnitX(udg_APEX_Unit[node], x)
        call SetUnitY(udg_APEX_Unit[node], y)
    endif
 
    //Apply visuals
    call SetUnitFlyHeight(udg_APEX_Unit[node], z, 0.)
    call SetUnitFacing(udg_APEX_Unit[node], bj_RADTODEG * Atan2(udg_APEX_YVel[node], udg_APEX_XVel[node]))
    set udg_APEX_ProjectileAnimation[node] = R2I(Atan2((udg_APEX_ZVel[node]), Pow((udg_APEX_XVel[node] * udg_APEX_XVel[node]) + (udg_APEX_YVel[node] * udg_APEX_YVel[node]), 0.5) * bj_RADTODEG + 0.5)) + 70
    call SetUnitAnimationByIndex(udg_APEX_Unit[node], udg_APEX_ProjectileAnimation[node])
 
    //Update target unit information if applicable
    if (udg_APEX_Target[udg_APEX_Parent[node]] == null) then
 
        //Check range from origin point
        if (APEX_Get3DDistance(x, udg_APEX_OriginX[udg_APEX_Parent[node]], y, udg_APEX_OriginY[udg_APEX_Parent[node]], udg_APEX_ProjectileHeight[node], udg_APEX_OriginZ[udg_APEX_Parent[node]]) >= udg_APEX_Range[udg_APEX_Parent[node]]) then
            //Too far, destroy
            set udg_APEX_ProjectileCount[udg_APEX_Parent[node]] = udg_APEX_ProjectileCount[udg_APEX_Parent[node]] - 1
            call DestroyEffect(udg_APEX_CurrentEffect[node])
            call KillUnit(udg_APEX_Unit[node])
            call APEX_RecycleNode(node)
        else
            //Look for targets
            call GroupEnumUnitsInRange(udg_APEX_TempGroup, x, y, udg_APEX_ProjectileHitBox[udg_APEX_Parent[node]], null)
       
            loop
                set u = FirstOfGroup(udg_APEX_TempGroup)
                exitwhen (u == null or not(udg_APEX_Target[udg_APEX_Parent[node]] == null))
                   
                if (APEX_TargetFilter(u, udg_APEX_Player[udg_APEX_Parent[node]])) then
                    //Target found, set up data
                    set udg_APEX_ProjectileDamageHealth[udg_APEX_Parent[node]] = udg_APEX_ProjectileDamageHealth[udg_APEX_Parent[node]] / udg_APEX_ProjectileCount[udg_APEX_Parent[node]]
                    set udg_APEX_ProjectileDamageMana[udg_APEX_Parent[node]] = udg_APEX_ProjectileDamageMana[udg_APEX_Parent[node]] / udg_APEX_ProjectileCount[udg_APEX_Parent[node]]
                    set udg_APEX_Target[udg_APEX_Parent[node]] = u
                    set udg_APEX_SpeedMultiplyer[udg_APEX_Parent[node]] = udg_APEX_MaxSpeed[udg_APEX_Parent[node]]
                    set udg_APEX_CurrentEffect[udg_APEX_Parent[node]] = AddSpecialEffectTarget(APEX_TargetModel(), u, APEX_TargetAttachmentPoint())
                    call UnitAddAbility(u, APEX_BuffID())
                endif
                   
                call GroupRemoveUnit(udg_APEX_TempGroup, u)
            endloop
 
        endif
 
    //Check if target has been hit
    elseif (APEX_Get3DDistance(x, udg_APEX_TargetX[node], y, udg_APEX_TargetY[node], z, udg_APEX_TargetZ[node]) <= udg_APEX_ProjectileHitBox[udg_APEX_Parent[node]]) then
        return true
    else
        //Update target point
        set udg_APEX_TargetX[node] = GetUnitX(udg_APEX_Target[udg_APEX_Parent[node]])
        set udg_APEX_TargetY[node] = GetUnitY(udg_APEX_Target[udg_APEX_Parent[node]])
        set udg_APEX_TargetZ[node] = GetUnitFlyHeight(udg_APEX_Target[udg_APEX_Parent[node]]) + APEX_TargetHeight()
    endif
 
    return false
endfunction

////////////////////////////////////////////////////////////////////
//  Function used to detect if a unit is currently stunned by     //
//  the spell to permit spell overwrite                           //
////////////////////////////////////////////////////////////////////
function APEX_GetStunNode takes unit u returns integer
    local integer node = 0
 
    loop
        set node = udg_APEX_NextNode[node]
        exitwhen node == 0 or udg_APEX_Unit[node] == u
    endloop
 
    if (node == 0) then
        set node = APEX_CreateNode()
        set udg_APEX_NO_PREV_STUN = true
    else
        set udg_APEX_NO_PREV_STUN = false
    endif
 
    return node
endfunction

////////////////////////////////////////////////////////////////////
//  Function used to set up new units being stunned and adding    //
//  them to the linked list                                       //
////////////////////////////////////////////////////////////////////
function APEX_FreezeUnit takes unit u, integer parent, real x, real y returns nothing
    local integer node = APEX_GetStunNode(u)
 
    set udg_APEX_Unit[node] = u
    set udg_APEX_StageID[node] = APEX_StunnedUnitStageID()
 
    if (udg_APEX_NO_PREV_STUN) then
        set udg_APEX_NotStunned[node] = true
        set udg_APEX_StunStartTimeout[node] = APEX_Get2DDistance(x, GetUnitX(u), y, GetUnitY(u)) * udg_APEX_StunStartMultiplyer[parent]
        set udg_APEX_StunDurationTimeout[node] = udg_APEX_StunDuration[parent]
    elseif udg_APEX_StunDuration[parent] > udg_APEX_StunDurationTimeout[node] then
        set udg_APEX_StunDurationTimeout[node] = udg_APEX_StunDuration[parent]
    endif
 
endfunction
////////////////////////////////////////////////////////////////////
//  Function used to run the main engine of the spell, handles    //
//  creation of new units, buff control and projectile control    //
////////////////////////////////////////////////////////////////////
function APEX_Loop takes nothing returns nothing
    //Set up locals
    local integer node = 0
    local integer i = 0
    local unit u
    local real x
    local real y
 
    loop
        set node = udg_APEX_NextNode[node]
        exitwhen node == 0
 
        //Handle projectiles
        if (udg_APEX_StageID[node] == APEX_ProjectileStageID()) then
            set i = 0
 
            //Handle speed boost
            loop
                set i = i + 1
                exitwhen ((i > udg_APEX_SpeedMultiplyer[udg_APEX_Parent[node]]) or IsUnitType(udg_APEX_Unit[node], UNIT_TYPE_DEAD))
 
                //Move projectiles
                if (APEX_MoveProjectile(node)) then
                    //Target hit damage and destroy projectile
                    call UnitDamageTarget(udg_APEX_Unit[udg_APEX_Parent[node]], udg_APEX_Target[udg_APEX_Parent[node]], udg_APEX_ProjectileDamageHealth[udg_APEX_Parent[node]], false, false, APEX_AttackType(), APEX_DamageType(), APEX_WeaponType())
                    call SetUnitState(udg_APEX_Target[udg_APEX_Parent[node]], UNIT_STATE_MANA, GetUnitState(udg_APEX_Target[udg_APEX_Parent[node]], UNIT_STATE_MANA) - udg_APEX_ProjectileDamageMana[udg_APEX_Parent[node]])
                    call DestroyEffect(udg_APEX_CurrentEffect[node])
                    call KillUnit(udg_APEX_Unit[node])
                    call APEX_RecycleNode(node)
       
                    set udg_APEX_ProjectileCount[udg_APEX_Parent[node]] = udg_APEX_ProjectileCount[udg_APEX_Parent[node]] - 1
                endif
   
   
            endloop
 
        //Handle frozen units
        elseif (udg_APEX_StageID[node] == APEX_StunnedUnitStageID()) then
            if (udg_APEX_NotStunned[node]) then
 
                if (udg_APEX_StunStartTimeout[node] <= 0.) then
                    //Stun the unit
                    set udg_APEX_CurrentEffect[node] = AddSpecialEffectTarget(APEX_FrozenModel(), udg_APEX_Unit[node], APEX_FrozenAttachmentPoint())
                    call SetUnitX(udg_APEX_Stunner, GetUnitX(udg_APEX_Unit[node]))
                    call SetUnitY(udg_APEX_Stunner, GetUnitY(udg_APEX_Unit[node]))
                    call IssueImmediateOrderById(udg_APEX_Stunner, APEX_StunOrderID())
                    call SetUnitTimeScale(udg_APEX_Unit[node], 0.)
                    set udg_APEX_NotStunned[node] = false
                endif
   
                set udg_APEX_StunStartTimeout[node] = udg_APEX_StunStartTimeout[node] - APEX_TimerSpeed()
 
            elseif (udg_APEX_StunDurationTimeout[node] <= 0.) or (IsUnitType(udg_APEX_Unit[node], UNIT_TYPE_DEAD)) then
                //Remove the stun
                call UnitRemoveAbility(udg_APEX_Unit[node], APEX_StunBuffID())
                call SetUnitTimeScale(udg_APEX_Unit[node], 1.)
                call DestroyEffect(udg_APEX_CurrentEffect[node])
                call APEX_RecycleNode(node)
   
               //Stops the timer if this is the only remaining Node
                if (udg_APEX_PrevNode[0] == 0) then
                    call PauseTimer(udg_APEX_Timer)
                endif
   
            else
                set udg_APEX_StunDurationTimeout[node] = udg_APEX_StunDurationTimeout[node] - APEX_TimerSpeed()
            endif
 
        //Handle spell core
        elseif (udg_APEX_ProjectileCount[node] == 0) then
   
            if not(udg_APEX_Target[node] == null) then
                //Play ending effect
                call UnitRemoveAbility(udg_APEX_Target[node], APEX_BuffID())
                call DestroyEffect(udg_APEX_CurrentEffect[node])
                call DestroyEffect(AddSpecialEffectTarget(APEX_ExplosionModel(), udg_APEX_Target[node], APEX_ExplosionAttachmentPoint()))
 
                //Damage and freeze units
                set x = GetUnitX(udg_APEX_Target[node])
                set y = GetUnitY(udg_APEX_Target[node])
                call GroupEnumUnitsInRange(udg_APEX_TempGroup, x, y, udg_APEX_AOE[node], null)
 
                loop
                    set u = FirstOfGroup(udg_APEX_TempGroup)
                    exitwhen u == null
                       
                    if (APEX_TargetFilter(u, udg_APEX_Player[node])) then
                        call UnitDamageTarget(udg_APEX_Unit[node], u, udg_APEX_AOEDamageHealth[node], false, false, APEX_AttackType(), APEX_DamageType(), APEX_WeaponType())
                        call SetUnitState(u, UNIT_STATE_MANA, GetUnitState(u, UNIT_STATE_MANA) - udg_APEX_AOEDamageMana[node])
                        call APEX_FreezeUnit(u, node, x, y)
                    endif
                       
                    call GroupRemoveUnit(udg_APEX_TempGroup, u)
                endloop
   
            endif
 
            call APEX_RecycleNode(node)
 
            //Stops the timer if this is the only remaining Node
            if (udg_APEX_PrevNode[0] == 0) then
                call PauseTimer(udg_APEX_Timer)
            endif
 
        endif
 
    endloop
 
endfunction

////////////////////////////////////////////////////////////////////
//  Function used to create new projectiles                       //
////////////////////////////////////////////////////////////////////
function APEX_CreateProjectile takes integer parent, real x, real y, real angle, real angle2, real arc returns nothing
    local integer node = APEX_CreateNode()
 
    //set up projectile data
    set udg_APEX_Parent[node] = parent
    set udg_APEX_Unit[node] = CreateUnit(APEX_DummyPlayer(), APEX_DummyID(), udg_APEX_OriginX[udg_APEX_Parent[node]], udg_APEX_OriginY[udg_APEX_Parent[node]], angle)
    set udg_APEX_StageID[node] = APEX_ProjectileStageID()
    set udg_APEX_CurrentEffect[node] = AddSpecialEffectTarget(APEX_ProjectileModel(), udg_APEX_Unit[node], APEX_ProjectileAttachmentPoint())
    call SetUnitScale(udg_APEX_Unit[node], udg_APEX_ProjectileScale[parent], 0., 0.)
    if UnitAddAbility(udg_APEX_Unit[node], 'Amrf') and UnitRemoveAbility(udg_APEX_Unit[node], 'Amrf') then
    endif
 
    set udg_APEX_ProjectileX[node] = udg_APEX_OriginX[udg_APEX_Parent[node]]
    set udg_APEX_ProjectileY[node] = udg_APEX_OriginY[udg_APEX_Parent[node]]
    set udg_APEX_TargetX[node] = x
    set udg_APEX_TargetY[node] = y
    set udg_APEX_TargetZ[node] = APEX_TargetHeight()
    set udg_APEX_ProjectileHeight[node] = udg_APEX_OriginZ[udg_APEX_Parent[node]]
    call SetUnitFlyHeight(udg_APEX_Unit[node], udg_APEX_ProjectileHeight[node] - udg_APEX_TempReal[udg_APEX_Parent[node]], 0.)
 
    set udg_APEX_XVel[node] = udg_APEX_ProjectileLaunchPower[udg_APEX_Parent[node]] * Cos(angle2) * Cos(arc)
    set udg_APEX_YVel[node] = udg_APEX_ProjectileLaunchPower[udg_APEX_Parent[node]] * Sin(angle2) * Cos(arc)
    set udg_APEX_ZVel[node] = udg_APEX_ProjectileLaunchPower[udg_APEX_Parent[node]] * Sin(arc)
 
endfunction

////////////////////////////////////////////////////////////////////
//  Function used to start an instance of the spell               //
////////////////////////////////////////////////////////////////////
function APEX_OnCast takes nothing returns boolean
    //Set up locals
    local integer node
    local integer spellID = GetSpellAbilityId()
    local integer projCountCircle
    local integer projCountArc
    local integer i = 0
    local integer i2
    local real level
    local real angle = 0
    local real radAngle
    local real angleIncrement
    local real arc = 0
    local real arcIncrement
    local real x
    local real y
    local real z
 
    //Check if something was infected
    if (spellID == APEX_AbilityID()) then
        //Set up spell data
        set node = APEX_CreateNode()
        set udg_APEX_Unit[node] = GetTriggerUnit()
        set level = GetUnitAbilityLevel(udg_APEX_Unit[node], APEX_AbilityID())
        set projCountCircle = APEX_ProjectileCountCircle(level)
        set projCountArc = APEX_ProjectileCountArc(level)
        set udg_APEX_StageID[node] = APEX_SpellCoreStageID()
        set udg_APEX_Parent[node] = node
        set udg_APEX_Target[node] = null
        set udg_APEX_Player[node] = GetTriggerPlayer()
        set udg_APEX_TempReal[node] = APEX_GetZ(udg_APEX_OriginX[node], udg_APEX_OriginY[node])
        set udg_APEX_OriginX[node] = GetSpellTargetX()
        set udg_APEX_OriginY[node] = GetSpellTargetY()
        set udg_APEX_OriginZ[node] = udg_APEX_TempReal[node] + APEX_TargetHeight()
        set udg_APEX_ProjectileScale[node] = APEX_ProjectileScale(level)
        set udg_APEX_AOE[node] = APEX_AOE(level)
        set udg_APEX_AOEDamageHealth[node] = APEX_AOEDamageHealth(level)
        set udg_APEX_AOEDamageMana[node] = APEX_AOEDamageMana(level)
        set udg_APEX_Range[node] = APEX_Range(level)
        set udg_APEX_StunDuration[node] = APEX_StunDuration(level)
        set udg_APEX_StunStartMultiplyer[node] = APEX_StunStartMaxTimeout(level) / udg_APEX_AOE[node]
        set udg_APEX_ProjectileCount[node] = projCountCircle * projCountArc
        set udg_APEX_ProjectileDamageHealth[node] = APEX_ProjectileDamageHealth(level)
        set udg_APEX_ProjectileDamageMana[node] = APEX_ProjectileDamageMana(level)
        set udg_APEX_ProjectileHitBox[node] = APEX_ProjectileHitBox(level)
        set udg_APEX_ProjectileTurnRate[node] = APEX_ProjectileTurnRate(level)
        set udg_APEX_ProjectileTurnEfficiency[node] = APEX_ProjectileTurnEfficiency(level)
        set udg_APEX_ProjectileAcceleration[node] = APEX_ProjectileAcceleration(level)
        set udg_APEX_ProjectileLaunchPower[node] = APEX_ProjectileLaunchPower(level)
        set udg_APEX_SpeedMultiplyer[node] = 1
        set udg_APEX_MaxSpeed[node] = APEX_SpeedMultiplyer(level)
 
        //Start Timer
        if udg_APEX_PrevNode[node] == 0 then
            call TimerStart(udg_APEX_Timer, APEX_TimerSpeed(), true, function APEX_Loop)
        endif
 
        call DestroyEffect(AddSpecialEffect(APEX_StartEffectModel(), udg_APEX_OriginX[node], udg_APEX_OriginY[node]))
 
        //Create projectiles
        set angleIncrement = 360. / projCountCircle
        set arcIncrement = bj_PI / 2. / projCountArc
 
        loop
            set i = i + 1
            exitwhen i > projCountCircle
            set i2 = 0
            set angle = angle + angleIncrement
            set radAngle = bj_DEGTORAD * angle
            set arc = 0
 
            set x = udg_APEX_OriginX[node] + udg_APEX_Range[node] * Cos(radAngle)
            set y = udg_APEX_OriginY[node] + udg_APEX_Range[node] * Sin(radAngle)
 
            loop
                set i2 = i2 + 1
                exitwhen i2 > projCountArc
   
                call APEX_CreateProjectile(node, x, y, angle, radAngle, arc)

                set arc = arc + arcIncrement
            endloop
 
        endloop
 
    endif
 
    return false
endfunction

////////////////////////////////////////////////////////////////////
//  Function used to register the trigger of the ability          //
////////////////////////////////////////////////////////////////////
function InitTrig_Apex_Blizzard takes nothing returns nothing
    //Set up local variables
    local trigger t = CreateTrigger()
 
    //Set up trigger
    call TriggerRegisterAnyUnitEventBJ(t,EVENT_PLAYER_UNIT_SPELL_EFFECT)
    call TriggerAddCondition(t, Condition(function APEX_OnCast))
    set udg_APEX_ZLoc = Location(0., 0.)
 
    //Sets up the variables used to make sure a point is within the map area
    set udg_APEX_MapMaxX = GetRectMaxX(bj_mapInitialPlayableArea)
    set udg_APEX_MapMinX = GetRectMinX(bj_mapInitialPlayableArea)
    set udg_APEX_MapMaxY = GetRectMaxY(bj_mapInitialPlayableArea)
    set udg_APEX_MapMinY = GetRectMinY(bj_mapInitialPlayableArea)
    set udg_APEX_Stunner = CreateUnit(APEX_DummyPlayer(), APEX_DummyID(), 0., 0., 0.)
    call UnitAddAbility(udg_APEX_Stunner, APEX_StunAbilityID())
endfunction
////////////////////////////////////////////////////////////////////
//END OF THE SPELL                                                //
////////////////////////////////////////////////////////////////////



Spell Information

- 803 lines of pure JASS
- 42 Configurables reaching all aspects of the ability
- 1 ability, part skillshot part massive AOE obliteration
- Extensive Readme to help you configure the ability
- Doesn't interfere with game scorescreen
- Compatiable with Vanilla WE
- Functions for ground and flying heroes
- Visually works for both ground and flying targets
- Arcs are stable on uneven terrain
- Features can be adapted to your liking due to the configuration including complete removal
- Attractive yet functional
- Easy to reach target filtering (done through object data)
- Ignores magic immune enemies correctly
- Buffs for all status conditions
- Works well as a boss spell or a regular heroes ultimate (hope you don't miss)
- Swapping out models is easy to create one to match any element
- Makes you feel powerful

Tips and Tricks

- The seeking lines of the spell are consistent with every cast - use this knowledge to aim the ability to hit targets you want specifically
- If you cast the spell directly underneath your target it will activate the stun immediately
- Stuns can stack so you can keep refreezing an enemy you've caught (if the cooldown is short enough)
- The seeking lines work well to ward off enemies in a large AOE even if it is unlikely to hit them

Helpful Files

- Variable Creator: Copy and paste into your map, you now have all the variables needed for the spell to run
Variable Creator
  • Variable Creator
    • Events
    • Conditions
    • Actions
      • Set APEX_AOE[0] = 0.00
      • Set APEX_AOEDamageHealth[0] = 0.00
      • Set APEX_AOEDamageMana[0] = 0.00
      • Set APEX_CurrentEffect[0] = APEX_CurrentEffect[0]
      • Set APEX_MapMaxX = 0.00
      • Set APEX_MapMaxY = 0.00
      • Set APEX_MapMinX = 0.00
      • Set APEX_MapMinY = 0.00
      • Set APEX_MaxSpeed[0] = 0
      • Set APEX_NO_PREV_STUN = False
      • Set APEX_NextNode[0] = 0
      • Set APEX_NodeNumber = 0
      • Set APEX_NotStunned[0] = False
      • Set APEX_OriginX[0] = 0.00
      • Set APEX_OriginY[0] = 0.00
      • Set APEX_OriginZ[0] = 0.00
      • Set APEX_Parent[0] = 0
      • Set APEX_Player[0] = APEX_Player[0]
      • Set APEX_PrevNode[0] = 0
      • Set APEX_ProjectileAcceleration[0] = 0.00
      • Set APEX_ProjectileAnimation[0] = 0
      • Set APEX_ProjectileCount[0] = 0
      • Set APEX_ProjectileDamageHealth[0] = 0.00
      • Set APEX_ProjectileDamageMana[0] = 0.00
      • Set APEX_ProjectileHeight[0] = 0.00
      • Set APEX_ProjectileHitBox[0] = 0.00
      • Set APEX_ProjectileLaunchPower[0] = 0.00
      • Set APEX_ProjectileScale[0] = 0.00
      • Set APEX_ProjectileTurnEfficiency[0] = 0.00
      • Set APEX_ProjectileTurnRate[0] = 0.00
      • Set APEX_ProjectileX[0] = 0.00
      • Set APEX_ProjectileY[0] = 0.00
      • Set APEX_Range[0] = 0.00
      • Set APEX_RecyclableNodes = 0
      • Set APEX_RecycleNodes[0] = 0
      • Set APEX_SpeedMultiplyer[0] = 0
      • Set APEX_StageID[0] = 0
      • Set APEX_StunDuration[0] = 0.00
      • Set APEX_StunDurationTimeout[0] = 0.00
      • Set APEX_StunStartMultiplyer[0] = 0.00
      • Set APEX_StunStartTimeout[0] = 0.00
      • Set APEX_Stunner = APEX_Stunner
      • Set APEX_Target[0] = APEX_Target[0]
      • Set APEX_TargetX[0] = 0.00
      • Set APEX_TargetY[0] = 0.00
      • Set APEX_TargetZ[0] = 0.00
      • Set APEX_TempGroup = APEX_TempGroup
      • Set APEX_TempReal[0] = 0.00
      • Set APEX_Timer = APEX_Timer
      • Set APEX_Unit[0] = APEX_Unit[0]
      • Set APEX_XVel[0] = 0.00
      • Set APEX_YVel[0] = 0.00
      • Set APEX_ZLoc = APEX_ZLoc
      • Set APEX_ZVel[0] = 0.00



WIP Links

- Zephyr Contest #15 - Model Based
- Zephyr Contest #15 - Model Based

Images


Contents

Apex Blizzard V1.00 (Map)

Reviews
KILLCIDE
Highest score in code for the contest, so not much to say here. I found your code and concept to be both the best out of everyone, hence why I voted for you. I read through IcemanBo's review for your entry, and I did not notice anything game breaking,...
  1. KILLCIDE

    KILLCIDE

    Administrator

    Joined:
    Jul 22, 2015
    Messages:
    3,497
    Resources:
    20
    Models:
    2
    Icons:
    10
    Spells:
    7
    Tutorials:
    1
    Resources:
    20
    Highest score in code for the contest, so not much to say here. I found your code and concept to be both the best out of everyone, hence why I voted for you. I read through IcemanBo's review for your entry, and I did not notice anything game breaking, so I have no reason not to approve this resource.

    Needs Fixed

    • Nothing

    Suggestions

    • Nothing

    Status


    Approved
     
  2. JC Helas

    JC Helas

    Joined:
    Oct 19, 2014
    Messages:
    155
    Resources:
    2
    Spells:
    2
    Resources:
    2
    awesome indexing :eek::eek: Very confusing the way you recycle your nodes hahays :(
     
    Last edited: Nov 9, 2018