• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

Brutal Blizzard v1.5

  • Like
Reactions: Lordul Dracula

Description

Calls down a massive freezing shards that damage enemy ground units in a target area.
Damaged unit gets freezed and unable to move.​

Trigger

  • Brutal Blizzard Configuration
    • Events
      • Map initialization
    • Conditions
    • Actions
      • -------- --------------------------- --------
      • -------- Determines the ability object --------
      • Set Bblz_Ability = Brutal Blizzard
      • -------- --------------------------- --------
      • -------- Determines the order id of the ability --------
      • Set Bblz_OrderId = (Order(blizzard))
      • -------- --------------------------- --------
      • -------- Determines the ability used to disable unit --------
      • Set Bblz_FreezeAbility = Brutal Blizzard Freeze
      • -------- --------------------------- --------
      • -------- Determines the unit-type of the dummies used by this spell --------
      • Set Bblz_DummyType = Brutal Blizzard Dummy
      • -------- --------------------------- --------
      • -------- Determines the unit-type of the "tree checker" --------
      • -------- Note: Must be a unit that can harvest lumber --------
      • Set Bblz_HarvesterType = Peasant
      • -------- --------------------------- --------
      • -------- Determines the area where the shards will fall onto --------
      • Set Bblz_AoE[1] = 500.00
      • Set Bblz_AoE[2] = 500.00
      • Set Bblz_AoE[3] = 500.00
      • -------- --------------------------- --------
      • -------- Determines the duration of the spell --------
      • Set Bblz_Duration[1] = 3.00
      • Set Bblz_Duration[2] = 4.00
      • Set Bblz_Duration[3] = 5.00
      • -------- --------------------------- --------
      • -------- Determines the model of the shards --------
      • Set Bblz_ShardModel = Abilities\Spells\Undead\FreezingBreath\FreezingBreathMissile.mdl
      • -------- --------------------------- --------
      • -------- Determines the size of the shards --------
      • Set Bblz_ShardSize[1] = 0.80
      • Set Bblz_ShardSize[2] = 0.80
      • Set Bblz_ShardSize[3] = 0.80
      • -------- --------------------------- --------
      • -------- Determines the fall speed of the shards --------
      • Set Bblz_ShardFallSpeed[1] = 50.00
      • Set Bblz_ShardFallSpeed[2] = 50.00
      • Set Bblz_ShardFallSpeed[3] = 50.00
      • -------- --------------------------- --------
      • -------- Determines from which direction the shards will fall --------
      • Set Bblz_ShardSpawnAngle = 0.00
      • -------- --------------------------- --------
      • -------- Determines the initial height of the shards --------
      • Set Bblz_ShardSpawnHeight = 800.00
      • -------- --------------------------- --------
      • -------- Determines the distance between the fall strike point and spawn point of each shards --------
      • Set Bblz_ShardSpawnOffset = 400.00
      • -------- --------------------------- --------
      • -------- Determines the spawn interval of the shards --------
      • Set Bblz_ShardInterval = 0.09
      • -------- --------------------------- --------
      • -------- Determines the radius of terrain deformation caused by shard --------
      • Set Bblz_ShardTDeformRadius = 250.00
      • -------- --------------------------- --------
      • -------- Determines the depth of terrain deformation caused by shard --------
      • Set Bblz_ShardTDeformDepth = 80.00
      • -------- --------------------------- --------
      • -------- Determines the hit effect --------
      • Set Bblz_HitSFX = Abilities\Spells\Undead\FreezingBreath\FreezingBreathMissile.mdl
      • -------- --------------------------- --------
      • -------- Determines hit effect attachment point --------
      • Set Bblz_HitSFXPoint = origin
      • -------- --------------------------- --------
      • -------- Determines the explosion effect --------
      • Set Bblz_ExplosionSFX[1] = war3mapImported\IceNova.mdx
      • Set Bblz_ExplosionSFX[2] = war3mapImported\IceSlam.mdx
      • -------- --------------------------- --------
      • -------- Determines the freeze duration --------
      • Set Bblz_FreezeDuration[1] = 5.00
      • Set Bblz_FreezeDuration[2] = 6.00
      • Set Bblz_FreezeDuration[3] = 7.00
      • -------- --------------------------- --------
      • -------- Determines the freeze damage --------
      • Set Bblz_FreezeDamage[1] = 50.00
      • Set Bblz_FreezeDamage[2] = 60.00
      • Set Bblz_FreezeDamage[3] = 70.00
      • -------- --------------------------- --------
      • -------- Determines the freeze effect --------
      • Set Bblz_FreezeSFX = Abilities\Spells\Undead\FreezingBreath\FreezingBreathTargetArt.mdl
      • -------- --------------------------- --------
      • -------- Determines freeze effect attachment point --------
      • Set Bblz_FreezeSFXPoint = origin
      • -------- --------------------------- --------
      • -------- Determines the damage dealt by each shards --------
      • Set Bblz_DamagePerShard[1] = 30.00
      • Set Bblz_DamagePerShard[2] = 40.00
      • Set Bblz_DamagePerShard[3] = 50.00
      • -------- --------------------------- --------
      • -------- Determines the damage radius of each shards --------
      • Set Bblz_DamageRadius[1] = 200.00
      • Set Bblz_DamageRadius[2] = 200.00
      • Set Bblz_DamageRadius[3] = 200.00
      • -------- --------------------------- --------
      • -------- Determines the attack-type --------
      • Set Bblz_AttackType = Siege
      • -------- --------------------------- --------
      • -------- Determines the damage-type --------
      • Set Bblz_DamageType = Cold
      • -------- --------------------------- --------
      • -------- True - Shards explosion will destroy trees --------
      • -------- False - Shards explosion will not destroy trees --------
      • Set Bblz_DestroyTrees = True
      • -------- --------------------------- --------
      • -------- Determines the owner of all dummies created by this spell --------
      • Set Bblz_DummiesOwner = Neutral Passive
      • -------- --------------------------- --------
      • -------- Determines the speed of the periodic timer --------
      • -------- Recommended: 0.03 --------
      • Set Bblz_PeriodicInterval = 0.03
      • -------- --------------------------- --------
      • -------- End of configuration --------
      • -------- =========================================================================== --------
      • Custom script: call ExecuteFunc("Bblz_Preload")
JASS:
//***************************************************************************
//*                                                                         *
//*   Brutal Blizzard v1.5                                         [Bblz_]  *
//*   by Ofel                                                               *
//*                                                                         *
//*                                                  www.hiveworkshop.com   *
//*                                                                         *
//***************************************************************************

//***************************************************************************
//*                                                                         *
//*   Configuration below requires JASS knowledge                           *
//*                                                                         *
//***************************************************************************

// ---------------------------
//  Unit alive filter function
// ---------------------------
function Bblz_IsUnitAlive takes unit u returns boolean
    return not IsUnitType(u,UNIT_TYPE_DEAD)
endfunction

// ---------------------------
//  Damage filter function
// ---------------------------
function Bblz_DamageTargetFilter takes unit u,player owner returns boolean
    return IsUnitEnemy(u,owner) and not IsUnitType(u,UNIT_TYPE_FLYING) and not IsUnitType(u,UNIT_TYPE_MAGIC_IMMUNE)
endfunction

// ---------------------------
//  Freeze filter function
// ---------------------------
function Bblz_FreezeTargetFilter takes unit u returns boolean
    return not IsUnitType(u,UNIT_TYPE_STRUCTURE)
endfunction

// ---------------------------
//  End of configuration
//===========================================================================

// ---------------------------
//  Preloader function
// ---------------------------
function Bblz_Preload takes nothing returns nothing
    local integer i=1
    local real time
    local real r=udg_Bblz_ShardSpawnHeight*udg_Bblz_ShardInterval
    loop
        exitwhen i>3
        set time=r/udg_Bblz_ShardFallSpeed[i]
        set udg_Bblz_HSpeed[i]=udg_Bblz_ShardSpawnOffset/(time/udg_Bblz_ShardInterval)
        set udg_Bblz_FreezeDamage[i]=udg_Bblz_FreezeDamage[i]*udg_Bblz_ShardInterval
        set i=i+1
    endloop
    set udg_Bblz_SpawnFacing=udg_Bblz_ShardSpawnAngle+180
    set udg_Bblz_OffsetAngle=udg_Bblz_ShardSpawnAngle*bj_DEGTORAD
    if udg_Bblz_ShardTDeformDepth<=0 then
        set udg_Bblz_ShardTDeformDepth=0.01
    endif
    set udg_Bblz_Harvester=CreateUnit(udg_Bblz_DummiesOwner,udg_Bblz_HarvesterType,0,0,0)
    call UnitAddAbility(udg_Bblz_Harvester,'Ahar')
    call SetUnitInvulnerable(udg_Bblz_Harvester,true) // In case hidden unit get damaged by another trigger
    call ShowUnit(udg_Bblz_Harvester,false)
    call UnitAddAbility(udg_Bblz_Harvester,udg_Bblz_Ability)
    call UnitRemoveAbility(udg_Bblz_Harvester,udg_Bblz_Ability)
    set udg_Bblz_MapX[1]=GetRectMinX(bj_mapInitialPlayableArea)
    set udg_Bblz_MapY[1]=GetRectMinY(bj_mapInitialPlayableArea)
    set udg_Bblz_MapX[2]=GetRectMaxX(bj_mapInitialPlayableArea)
    set udg_Bblz_MapY[2]=GetRectMaxY(bj_mapInitialPlayableArea)
    call Preload(udg_Bblz_ShardModel)
    call Preload(udg_Bblz_HitSFX)
    set i=1
    loop
        exitwhen udg_Bblz_ExplosionSFX[i]==null
        call Preload(udg_Bblz_ExplosionSFX[i])
        set i=i+1
    endloop
    call Preload(udg_Bblz_FreezeSFX)
endfunction

// ---------------------------
//  X point checker function
// ---------------------------
function Bblz_IsXInMap takes real x returns boolean
    return x>=udg_Bblz_MapX[1] and x<=udg_Bblz_MapX[2]
endfunction

// ---------------------------
//  Y point checker function
// ---------------------------
function Bblz_IsYInMap takes real y returns boolean
    return y>=udg_Bblz_MapY[1] and y<=udg_Bblz_MapY[2]
endfunction

// ---------------------------
//  Unit disabler function
// ---------------------------
function Bblz_DisableUnit takes unit u,integer level returns nothing
    local unit u2=CreateUnit(udg_Bblz_DummiesOwner,udg_Bblz_DummyType,GetUnitX(u),GetUnitY(u),0)
    call UnitAddAbility(u2,udg_Bblz_FreezeAbility)
    call SetUnitAbilityLevel(u2,udg_Bblz_FreezeAbility,level)
    call IssueTargetOrderById(u2,852095,u)
    call UnitApplyTimedLife(u2,'BTLF',0.1)
    set u2=null
endfunction

// ---------------------------
//  Tree destroyer function
// ---------------------------
function Bblz_DestroyTrees takes nothing returns nothing
    local destructable tree=GetEnumDestructable()
    if IssueTargetOrderById(udg_Bblz_Harvester,852018,tree) then
        call KillDestructable(tree)
    endif
    set tree=null
endfunction

// ---------------------------
//  Tree scanner function
// ---------------------------
function Bblz_ScanTrees takes real x,real y,real radius returns nothing
    call SetRect(udg_Bblz_tempRect,x-radius,y-radius,x+radius,y+radius)
    set bj_enumDestructableCenter=Location(x,y)
    set bj_enumDestructableRadius=radius
    call EnumDestructablesInRect(udg_Bblz_tempRect,filterEnumDestructablesInCircleBJ,function Bblz_DestroyTrees)
    call RemoveLocation(bj_enumDestructableCenter)
endfunction

// ---------------------------
//  Terrain deformation function
// ---------------------------
function Bblz_TerrainDeform takes real radius,real depth,real x,real y returns nothing
    call TerrainDeformCrater(x,y,radius,depth,100,false)
endfunction

// ---------------------------
//  Periodic/core function
// ---------------------------
function Bblz_Periodic takes nothing returns boolean
    local integer index=0
    local real x
    local real y
    local real x2
    local real y2
    local real offset
    local real angle
    local real facing
    local integer i
    local unit u
    loop
        exitwhen index>udg_Bblz_MaxIndex
        // ---------------------------
        // Method 1: Falling shards
        // ---------------------------
        if udg_Bblz_Method[index]==1 then
            set x=GetUnitX(udg_Bblz_Dummy[index])
            set y=GetUnitY(udg_Bblz_Dummy[index])
            if udg_Bblz_Height[index]>0 then
                set udg_Bblz_Height[index]=udg_Bblz_Height[index]-udg_Bblz_ShardFallSpeed[udg_Bblz_Level[index]]
                call SetUnitFlyHeight(udg_Bblz_Dummy[index],udg_Bblz_Height[index],0)
                set x=x+udg_Bblz_HSpeed[udg_Bblz_Level[index]]*Cos(udg_Bblz_HAngle[index])
                set y=y+udg_Bblz_HSpeed[udg_Bblz_Level[index]]*Sin(udg_Bblz_HAngle[index])
                call SetUnitX(udg_Bblz_Dummy[index],x)
                call SetUnitY(udg_Bblz_Dummy[index],y)
            else
                set i=1
                loop
                    exitwhen udg_Bblz_ExplosionSFX[i]==null
                    call DestroyEffect(AddSpecialEffect(udg_Bblz_ExplosionSFX[i],x,y))
                    set i=i+1
                endloop
                call GroupEnumUnitsInRange(udg_Bblz_tempGroup,x,y,udg_Bblz_DamageRadius[udg_Bblz_Level[index]],null)
                loop
                    set u=FirstOfGroup(udg_Bblz_tempGroup)
                    exitwhen u==null
                    if Bblz_IsUnitAlive(u) and Bblz_DamageTargetFilter(u,udg_Bblz_Owner[index]) then
                        call UnitDamageTarget(udg_Bblz_Caster[index],u,udg_Bblz_DamagePerShard[udg_Bblz_Level[index]],true,false,udg_Bblz_AttackType,udg_Bblz_DamageType,null)
                        call DestroyEffect(AddSpecialEffectTarget(udg_Bblz_HitSFX,u,udg_Bblz_HitSFXPoint))
                        if Bblz_IsUnitAlive(u) and Bblz_FreezeTargetFilter(u) then
                            if IsUnitInGroup(u,udg_Bblz_FreezedUnits) then
                                set i=1
                                loop
                                    exitwhen i>udg_Bblz_MaxIndex
                                    if udg_Bblz_Target[i]==u then
                                        set udg_Bblz_realTimer[i]=udg_Bblz_FreezeDuration[udg_Bblz_Level[index]]
                                        call Bblz_DisableUnit(u,udg_Bblz_Level[index])
                                    endif
                                    set i=i+1
                                endloop
                            else
                                set udg_Bblz_MaxIndex=udg_Bblz_MaxIndex+1
                                set udg_Bblz_Target[udg_Bblz_MaxIndex]=u
                                set udg_Bblz_Caster[udg_Bblz_MaxIndex]=udg_Bblz_Caster[index]
                                set udg_Bblz_Level[udg_Bblz_MaxIndex]=udg_Bblz_Level[index]
                                set udg_Bblz_AttachedFX[udg_Bblz_MaxIndex]=AddSpecialEffectTarget(udg_Bblz_FreezeSFX,u,udg_Bblz_FreezeSFXPoint)
                                set udg_Bblz_realTimer[udg_Bblz_MaxIndex]=udg_Bblz_FreezeDuration[udg_Bblz_Level[index]]
                                call SetUnitTimeScale(u,0)
                                call Bblz_DisableUnit(u,udg_Bblz_Level[index])
                                set udg_Bblz_Method[udg_Bblz_MaxIndex]=2
                                call GroupAddUnit(udg_Bblz_FreezedUnits,u)
                            endif
                        endif
                    endif
                    call GroupRemoveUnit(udg_Bblz_tempGroup,u)
                endloop
                if udg_Bblz_DestroyTrees then
                    call Bblz_ScanTrees(x,y,udg_Bblz_DamageRadius[udg_Bblz_Level[index]]) // Custom destructable enumeration function :D
                endif
                call Bblz_TerrainDeform(udg_Bblz_ShardTDeformRadius,udg_Bblz_ShardTDeformDepth,x,y)
                call DestroyEffect(udg_Bblz_AttachedFX[index])
                call KillUnit(udg_Bblz_Dummy[index])
                set udg_Bblz_Method[index]=4
            endif
            // ---------------------------
            // Method 2: Freezing units
            // ---------------------------
        elseif udg_Bblz_Method[index]==2 then
            if not Bblz_IsUnitAlive(udg_Bblz_Target[index]) then
                set udg_Bblz_realTimer[index]=0
            endif
            if udg_Bblz_realTimer[index]>0 then
                set udg_Bblz_realTimer[index]=udg_Bblz_realTimer[index]-udg_Bblz_PeriodicInterval
                call UnitDamageTarget(udg_Bblz_Caster[index],udg_Bblz_Target[index],udg_Bblz_FreezeDamage[udg_Bblz_Level[index]],true,false,udg_Bblz_AttackType,udg_Bblz_DamageType,null)
            else
                call DestroyEffect(udg_Bblz_AttachedFX[index])
                call SetUnitTimeScale(udg_Bblz_Target[index],1)
                call GroupRemoveUnit(udg_Bblz_FreezedUnits,udg_Bblz_Target[index])
                set udg_Bblz_Method[index]=4
            endif
            // ---------------------------
            // Method 3: Creating shards and spell timer
            // ---------------------------
        elseif udg_Bblz_Method[index]==3 then
            if GetUnitCurrentOrder(udg_Bblz_Caster[index])==udg_Bblz_OrderId and udg_Bblz_realTimer[index]>0 then
                set udg_Bblz_realTimer[index]=udg_Bblz_realTimer[index]-udg_Bblz_PeriodicInterval
                set udg_Bblz_realTimer2[index]=udg_Bblz_realTimer2[index]-udg_Bblz_PeriodicInterval
                if udg_Bblz_realTimer2[index]<=0 then
                    set udg_Bblz_realTimer2[index]=udg_Bblz_ShardInterval
                    set angle=GetRandomReal(0,2*bj_PI)
                    set offset=GetRandomReal(0,udg_Bblz_AoE[udg_Bblz_Level[index]])
                    set x=udg_Bblz_TargetX[index]+offset*Cos(angle)
                    set y=udg_Bblz_TargetY[index]+offset*Sin(angle)
                    set x2=x+udg_Bblz_ShardSpawnOffset*Cos(udg_Bblz_OffsetAngle)
                    set y2=y+udg_Bblz_ShardSpawnOffset*Sin(udg_Bblz_OffsetAngle)
                    if not Bblz_IsXInMap(x2) or not Bblz_IsYInMap(y2) then
                        set x2=x-udg_Bblz_ShardSpawnOffset*Cos(udg_Bblz_OffsetAngle)
                        set y2=y-udg_Bblz_ShardSpawnOffset*Sin(udg_Bblz_OffsetAngle)
                        set facing=udg_Bblz_SpawnFacing+180
                    else
                        set facing=udg_Bblz_SpawnFacing
                    endif
                    set udg_Bblz_MaxIndex=udg_Bblz_MaxIndex+1
                    set udg_Bblz_Dummy[udg_Bblz_MaxIndex]=CreateUnit(udg_Bblz_DummiesOwner,udg_Bblz_DummyType,x2,y2,facing)
                    set udg_Bblz_AttachedFX[udg_Bblz_MaxIndex]=AddSpecialEffectTarget(udg_Bblz_ShardModel,udg_Bblz_Dummy[udg_Bblz_MaxIndex],"origin")
                    call SetUnitScale(udg_Bblz_Dummy[udg_Bblz_MaxIndex],udg_Bblz_ShardSize[udg_Bblz_Level[index]],0,0)
                    call SetUnitFlyHeight(udg_Bblz_Dummy[udg_Bblz_MaxIndex],udg_Bblz_ShardSpawnHeight,0)
                    set udg_Bblz_Height[udg_Bblz_MaxIndex]=udg_Bblz_ShardSpawnHeight
                    set udg_Bblz_Caster[udg_Bblz_MaxIndex]=udg_Bblz_Caster[index]
                    set udg_Bblz_Owner[udg_Bblz_MaxIndex]=udg_Bblz_Owner[index]
                    set udg_Bblz_Level[udg_Bblz_MaxIndex]=udg_Bblz_Level[index]
                    set udg_Bblz_HAngle[udg_Bblz_MaxIndex]=facing*bj_DEGTORAD
                    set udg_Bblz_Method[udg_Bblz_MaxIndex]=1
                endif
            else
                set udg_Bblz_Method[index]=4
            endif
            // ---------------------------
            // Method 4: Recycling indexes
            // ---------------------------
        elseif udg_Bblz_Method[index]==4 then
            set udg_Bblz_AttachedFX[index]=udg_Bblz_AttachedFX[udg_Bblz_MaxIndex]
            set udg_Bblz_Caster[index]=udg_Bblz_Caster[udg_Bblz_MaxIndex]
            set udg_Bblz_Dummy[index]=udg_Bblz_Dummy[udg_Bblz_MaxIndex]
            set udg_Bblz_HAngle[index]=udg_Bblz_HAngle[udg_Bblz_MaxIndex]
            set udg_Bblz_Height[index]=udg_Bblz_Height[udg_Bblz_MaxIndex]
            set udg_Bblz_Level[index]=udg_Bblz_Level[udg_Bblz_MaxIndex]
            set udg_Bblz_Method[index]=udg_Bblz_Method[udg_Bblz_MaxIndex]
            set udg_Bblz_Owner[index]=udg_Bblz_Owner[udg_Bblz_MaxIndex]
            set udg_Bblz_realTimer[index]=udg_Bblz_realTimer[udg_Bblz_MaxIndex]
            set udg_Bblz_realTimer2[index]=udg_Bblz_realTimer2[udg_Bblz_MaxIndex]
            set udg_Bblz_Target[index]=udg_Bblz_Target[udg_Bblz_MaxIndex]
            set udg_Bblz_TargetX[index]=udg_Bblz_TargetX[udg_Bblz_MaxIndex]
            set udg_Bblz_TargetY[index]=udg_Bblz_TargetY[udg_Bblz_MaxIndex]
            set udg_Bblz_Caster[udg_Bblz_MaxIndex]=null
            set udg_Bblz_Dummy[udg_Bblz_MaxIndex]=null
            set udg_Bblz_Owner[udg_Bblz_MaxIndex]=null
            set udg_Bblz_Target[udg_Bblz_MaxIndex]=null
            set index=index-1
            set udg_Bblz_MaxIndex=udg_Bblz_MaxIndex-1
            if udg_Bblz_MaxIndex==0 then
                call PauseTimer(udg_Bblz_PeriodicTimer)
            endif
        endif
        set index=index+1
    endloop
    return false
endfunction

// ---------------------------
//  Activation function
// ---------------------------
function Bblz_Cast takes nothing returns boolean
    local integer i
    if GetSpellAbilityId()==udg_Bblz_Ability then
        set udg_Bblz_Caster[0]=GetTriggerUnit()
        if udg_Bblz_MaxIndex==0 then
            call TimerStart(udg_Bblz_PeriodicTimer,udg_Bblz_PeriodicInterval,true,function Bblz_Periodic)
        else
            set i=1
            loop
                exitwhen i>udg_Bblz_MaxIndex
                if udg_Bblz_Caster[i]==udg_Bblz_Caster[0] and udg_Bblz_Method[i]==3 then
                    set udg_Bblz_Method[i]=4
                endif
                set i=i+1
            endloop
        endif
        set udg_Bblz_MaxIndex=udg_Bblz_MaxIndex+1
        set udg_Bblz_Caster[udg_Bblz_MaxIndex]=udg_Bblz_Caster[0]
        set udg_Bblz_Owner[udg_Bblz_MaxIndex]=GetTriggerPlayer()
        set udg_Bblz_Level[udg_Bblz_MaxIndex]=GetUnitAbilityLevel(udg_Bblz_Caster[udg_Bblz_MaxIndex],udg_Bblz_Ability)
        set udg_Bblz_TargetX[udg_Bblz_MaxIndex]=GetSpellTargetX()
        set udg_Bblz_TargetY[udg_Bblz_MaxIndex]=GetSpellTargetY()
        set udg_Bblz_realTimer[udg_Bblz_MaxIndex]=udg_Bblz_Duration[udg_Bblz_Level[udg_Bblz_MaxIndex]]
        set udg_Bblz_realTimer2[udg_Bblz_MaxIndex]=0
        set udg_Bblz_Method[udg_Bblz_MaxIndex]=3
    endif
    return false
endfunction

// ---------------------------
//  Initializer function
// ---------------------------
function InitTrig_Brutal_Blizzard takes nothing returns nothing
    set gg_trg_Brutal_Blizzard=CreateTrigger()
    set udg_Bblz_tempRect=Rect(0,0,0,0)
    call TriggerRegisterAnyUnitEventBJ(gg_trg_Brutal_Blizzard,EVENT_PLAYER_UNIT_SPELL_EFFECT)
    call TriggerAddCondition(gg_trg_Brutal_Blizzard,Filter(function Bblz_Cast))
endfunction

Changelog

  • v1.0 - Initial version.
  • v1.1 - Fixed damage filteration, added new function called Bblz_IsUnitAlive, fixed script inside Bblz_DestroyTrees function, unused handles are nulled.
  • v1.2 - Fixed issue on map border, preload trigger removed, added freeze ability and buff, added new functions, renamed function, lot of script fixes applied.
  • v1.3 - Added new function, now shards cause temporary terrain deformation when explode.
  • v1.4 - Ability now channeling, new configurable variables, optimized script.
  • v1.5 - Script optimized, freeze duration now update on freezed units.

Credits

  • Vexorian for dummy.mdx model
  • -Berz- for GlacierBlades.blp icon
  • JetFangInferno for IceNova.mdx model
  • Valkemiere for IceSlam.mdx model

You can find import instruction inside the test map
Rate please :D

Thanks to Quilnez, BPower and IcemanBo for their review.​

Keywords:
Blizzard, Ice, Shards, Rain, Freeze, Channeling, GUI.
Contents

Brutal Blizzard (Map)

Reviews
Submission: Brutal Blizzard v1.5 Date: 12.07.2015 Status: Approved Rating: 4/5 Review Link Moderator: IcemanBo

Moderator

M

Moderator


Submission:
Brutal Blizzard v1.5

Date:
12.07.2015

Status:
Approved

Rating:
4/5

Review
Link

Moderator:
IcemanBo
 

Kazeon

Hosted Project: EC
Level 33
Joined
Oct 12, 2011
Messages
3,449
Just some quick hints ;)


JASS:
constant function Bblz_DummiesOwner takes nothing returns player
    return Player(15) // Neutral Passive
endfunction
Just use a variable just like the other configurations, since "Player()" is basically a function call which can slow things down.


I don't know how the spell works but call PauseUnit(u,true) should be avoided. Try to use a stun system instead or create yours.


This is not enough to check is unit dead:
JASS:
if GetWidgetLife(udg_Bblz_Target[index])<=0.405 then
Should be:
JASS:
if GetWidgetLife(udg_Bblz_Target[index])<=0.405 and IsUnitType(udg_Bblz_Target[index], UNIT_TYPE_DEAD) then


I do not agree on this part since I think it's just for bloating effects:
JASS:
                set i=0
                loop
                    exitwhen i>udg_Bblz_ExplosionSFXNumber
                    call DestroyEffect(AddSpecialEffect(udg_Bblz_ExplosionSFX[i],x,y))
                    set i=i+1
                endloop


This could be added in configuration part:
JASS:
if GetWidgetLife(u)>0.405 and @IsUnitEnemy(u,udg_Bblz_Owner[index]) and not IsUnitType(u,UNIT_TYPE_FLYING) and not IsUnitType(u,UNIT_TYPE_MAGIC_IMMUNE)@ then
But it's rather optional to do.


After recycling the indexes, you have to null handles at the max index.
JASS:
.... // deindex part
            set udg_Bblz_Caster[udg_Bblz_MaxIndex]=null
            set udg_Bblz_Dummy[udg_Bblz_MaxIndex]=null


JASS:
    set bj_enumDestructableCenter=Location(x,y)
You can create one global temporary location variable on initialization and simply move it around using MoveLocation(loc, x, y) to avoid re-creating locations over and over again. But wait, you don't even use that location so just remove it.


JASS:
function Bblz_DestroyTrees takes nothing returns nothing
    local destructable tree=GetEnumDestructable()
    call IssueTargetOrderById(udg_Bblz_Harvester,852018,tree)
    if GetUnitCurrentOrder(udg_Bblz_Harvester)==852018 then
        call KillDestructable(tree)
    endif
    set tree=null
endfunction
Use this function instead:
JASS:
function Bblz_DestroyTrees takes nothing returns nothing
    local destructable tree=GetEnumDestructable()
    if IssueTargetOrderById(udg_Bblz_Harvester,852018,tree) then
        call KillDestructable(tree)
    endif
    set tree=null
endfunction


JASS:
    call UnitAddAbility(udg_Bblz_Harvester,udg_Bblz_Ability)
    call UnitRemoveAbility(udg_Bblz_Harvester,udg_Bblz_Ability)
    call Preload(udg_Bblz_ShardModel)
    call Preload(udg_Bblz_HitSFX)
    set i=1
    loop
        exitwhen i>udg_Bblz_ExplosionSFXNumber
        call Preload(udg_Bblz_ExplosionSFX[i])
        set i=i+1
    endloop
    call Preload(udg_Bblz_FreezeSFX)
Are those needed? Where do you call that function even?


Phew, it's been a while since the last time I did a code review. Anyway, 4/5 from me :D
 

Kazeon

Hosted Project: EC
Level 33
Joined
Oct 12, 2011
Messages
3,449
^Dummy units can be paused, no problem. Widget life check can be removed completely, UNIT_TYPE_DEAD check is pretty good. One can use native UnitAlive, just declare it first.

Hm. But he is pausing affected units.

UnitAlive should only be used for vJass since native declaration only valid in JNGP, iirc.
 
Level 13
Joined
Mar 29, 2012
Messages
530
@Quilnez
JASS:
constant function Bblz_DummiesOwner takes nothing returns player
    return Player(15) // Neutral Passive
endfunction
Lets just say its for safety.

JASS:
    call UnitAddAbility(udg_Bblz_Harvester,udg_Bblz_Ability)
    call UnitRemoveAbility(udg_Bblz_Harvester,udg_Bblz_Ability)
    call Preload(udg_Bblz_ShardModel)
    call Preload(udg_Bblz_HitSFX)
    set i=1
    loop
        exitwhen i>udg_Bblz_ExplosionSFXNumber
        call Preload(udg_Bblz_ExplosionSFX[i])
        set i=i+1
    endloop
    call Preload(udg_Bblz_FreezeSFX)
Are those needed? Where do you call that function even?
From the configuration trigger.

Be right back

@Maker
Lol, I didn't pause dummies.

Seriously, can I pause affected units? What are the risk?
 
Globals doesn't have to be Nulled, but it's a good practice.

TriggerAddAction -> TriggerAddCondition

Is it just me or the entire tree stuffs can be optimized? The scan feels unnecessary IMO. Just use circular check should be enough. Unless of course, spell mechanics.

Still, 4/5 from me, nicely done lad :)

EDIT :
Use SetUnitPropWindow(u,0), SetUnitAnimationSpeed(u,0) and SetUnitPropWindow(u,GetUnitPropWindow(u)*bj_RADTODEG), SetUnitAnimationSpeed(u,100)instead of pause unit. Unless these are for dummies.

The code aren't exact since I don't look for them at editor, but roughly enough to guess what should be done.

Pause unit has some annoying behaviors.
 
Level 19
Joined
Mar 18, 2012
Messages
1,716
Review based on the thread description.

1.) What's the purpose of the preload trigger, use a simple function call in the init trigger instead.

2.) Harvesting trees is optional, but you always create an harvester unit.

3.) Which units should be affected is part of user configuration. In GUI this is impossible,
but you are using a JASS/GUI mix. So make it a customizeable function call.

4.) IsUnitType(u,UNIT_TYPE_DEAD) is enough to check if a unit is alove or not.

5.) Pausing non dummy units is very unprofessional. It comes along with unwanted side effects.

6.) GetRandomReal(0,360)*bj_DEGTORAD --> GetRandomReal(0, 2*bj_PI) :)
 
Level 13
Joined
Mar 29, 2012
Messages
530
Added terrain deformation, the final version, hopefully.

You wouldn't believe me that terrain deformation can also make windows crash. My laptop screen turned blue with some kind of debug messages.
 
Last edited:
Level 13
Joined
Mar 29, 2012
Messages
530
It's a temporary terrain deformation. But idk, let's wait :)

Edit:
Nope, I guess not. I've played about 15 minutes with maybe about 50 casts and seems like not much lagging.
 
Last edited:
  • At the moment the channeling is not mimicked quite well.
    The animation is played once, but is completly independant of the spell duration.
    This is not really characteristic for a channel ability.
    What also would be characteristic is that spell gets canceled if newOrder/onDeath for example.
    Well, this is my opinion how it would make mimic the original spell some better.
  • Quillnez made a good suggestion when he said to change the player function into variable.
    It can be just part of normal GUI configuration. Nothing will be lost.
    .
    .
    • -------- Determines how many explosion effect will be used --------
    • Set Bblz_ExplosionSFXNumber = 2
    ^Not neessarily needed. Could be avoided if you check in loop exitwhen effect[index] == null.
  • In loop you don't need 2 seperate if statements to filter and to check if unit is alive:
    if alive(u) and filter(u) then ...
  • Add harvest ability to your worker via trigger to ensure he can.
  • You start the "create effect loop" with initial value of 0,
    but in init you start with 1 with assignment. Align them.
  • If you want optimization, one global rect could be used for enum destrucables.
  • TerrainDeformation is meant to leak a reference, but it can't be avoided,
    and it's also used in wc3 default abilities, so I don't ban to use it.
  • Methods: 3 -> 1 -> 2 -> 4. Why not make it just increasing? ^^
  • onDeindex also decrement the loop index. Else you potentialy forget about 1 instance.
  • Spell makes really fun and looks nice. Freezing damaged unit looks coool


About this preload. Ofel has to ensure the config trigger runs before the Preload runs.
So a simple call in his JASS init might not be enough. (timer must be used)
But I don't see why you didn't move the preload in GUI so it just can run after the config part in same thread.
 
Level 13
Joined
Mar 29, 2012
Messages
530
@IcemanBo
Methods: 3 -> 1 -> 2 -> 4. Why not make it just increasing? ^^
I feels like its a little faster. See method 1 is the most often block that will be run periodically since it handles many shards to be moved, so it is putted on top, method 2: freezing units, takes the 2nd place as the most often and so on.
 
What must be changed is:
If unit gets freezed it gets into group.
Now the freezing time won't be refreshed onNewHit, because there is a condition
to filter units out that already are in freezing group. But they should be freezed again.

Also this:
You interrupt channeling now, it's good. For most cases it works, but there exists one mistake.
You only check if orderId is correct castOrder of spell. But now, when a unit is channeling already,
and then starts the same effect again it is still the same orderId, and so the first one won't be interrupted.
-> 2 blizzdards can be casted at same time by caster, or more.

JASS:
if GetUnitAbilityLevel(udg_Bblz_Harvester,'Ahar')==0 then
    call UnitAddAbility(udg_Bblz_Harvester,'Ahar')
endif
Just add ability, nothing bad will happen:). ->
call UnitAddAbility(udg_Bblz_Harvester,'Ahar')

Global rect can be used over re-constructing one local over and over again.

Preload function is not necessarily needed. Could run right after user config.
 
Level 13
Joined
Mar 29, 2012
Messages
530
What must be changed is:
If unit gets freezed it gets into group.
Now the freezing time won't be refreshed onNewHit, because there is a condition
to filter units out that already are in freezing group. But they should be freezed again.
Should I use hashtable or Unit Indexer?

Global rect can be used over re-constructing one local over and over again.
How?

Preload function is not necessarily needed. Could run right after user config.
Well sorry, I thought you said it's optional.
 
A bit delay, but here we go.

Concept: 3/5

Idea is not unique.
The idea is to mimic the "Blizzard" default ability in warcraft III, which succeeded.
It's an AoE spell with falling shards that damage and freezes affected units for certain duration.


Code: 3.5/5

The code is a mix of GUI and JASS.
The user has possibility to config most of the spell in GUI, which is positive for most beginners.
Core system is written in plain JASS.

- One global dummy could be used for freezing affected units. Creating/removing is not needed.
- I find your scan trees functions okay with loc, as well, but here too one global could be used.
- Imo "IsYInMap" and "IsXInMap" don't have to be seperated here.

(rating is tending to 4 for me here atm)


Visuals: 4/5

I like visuals actually, but for my personal taste the second effect looks to spammy with such a big appearance rate.


Conclusion: 3.5 -> 4/5

Approved
 
Top