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

Infernal Collapse v1.4

  • Like
Reactions: deepstrasz and Kam
Description
Calls forth exploding magmatic shards around the target point. All enemy units around the explosion site will receive fire damage.​
How to import
  • Copy "Infernal Collapse" trigger group to your map
  • Delete variable creator trigger
  • Export all necessary import data to your map
  • Copy dummy unit (Object Editor) to your map
  • Copy main ability (Object Editor) to your map
  • Configure the spell
Code
JASS:
    // ********************************************************
    // *
    // *                Infernal Collapse v1.4
    // *                            by Quilnez
    // *
    // *    Description:
    // *        Calls forth exploding magmatic shards all around the
    // *        target  point. All enemy units around the  explosion
    // *        site will receive fire damage.
    // *    
    // *    Requirement(s):
    // *        None
    // *    
    // *    How to import:
    // *        • Copy "Infernal Collapse" trigger group to your map
    // *        • Delete variable creator trigger
    // *        • Export all necessary import data to your map
    // *          (Except "TerrainArt\Outland\Outland_Dirt.blp")
    // *        • Copy dummy unit (Object Editor) to your map
    // *        • Copy main ability (Object Editor) to your map
    // *        • Configure the spell
    // *    
    // *    Credits:
    // *        • BTNEvaporate By M0rbid
    // *        • Explosion.mdx By JetFangInferno
    // *        • ExplosiveTornado.mdx By JetFangInferno
    // *        • FlameBomb.mdx By WILL THE ALMIGHTY
    // *        • Fire Low.mdx By Pyritie
    // *        • LightningSphere_FX.mdx By PeeKay
    // *        • Shockwave.mdx By Vestras
    // *        • dummy.mdx By Vexorian
    // *            (All models are edited to fulfill the
    // *                    needs of this spell)
    // *    
    // *    Author's note:
    // *        If you need assistanance on installing this to your
    // *        map, or to request another form of this spell, just
    // *        contact me anytime
    // *    
    // ********************************************************
    
    // ********************************************************
    // *    
    // *                   Configuration
    // *    
    // *    1. Dummy unit's raw code at object editor
            constant function ICol__DummyID takes nothing returns integer
                return 'h000'
            endfunction
    // *    
    // *    2. Main ability's raw code at object editor
            constant function ICol__SpellID takes nothing returns integer
                return 'A000'
            endfunction
    // *    
    // *    3. Just leave it as it is
            constant function ICol__Interval takes nothing returns real
                return 0.0312500
            endfunction
    // *    
    // *    4. Time given to special effects to decay before being removed
            constant function ICol__SFXDecayTime takes nothing returns real
                return 5.0
            endfunction
    // *    
    // *    5. If true, spell will become channeling:
    // *       The spell will be stopped whenever the caster is given another
    // *       order
            constant function ICol__Channeling takes nothing returns boolean
                return false
            endfunction
    // *    
    // *    6. Order id of the main ability, only useful when the spell is
    // *       channeling
            constant function ICol__OrderID takes nothing returns integer
                return 852218 // carrionswarm
            endfunction
    // *    
    // *    7. Core of the orb's model path
            constant function ICol__CoreSFX takes nothing returns string
                return "war3mapImported\\Fire Low.mdx"
            endfunction
    // *    
    // *    8. (i) Orb's minimum size (scale)
            constant function ICol__CoreMinSize takes nothing returns real
                return 1.0
            endfunction
    // *    
    // *       (ii) Orb's maximum size (scale)
            constant function ICol__CoreMaxSize takes nothing returns real
                return 2.0
            endfunction
    // *       * Orbs will be spawned at random starting size (scale)
    // *    
    // *    9. Size of the orb when it's ready to explode
    // *       The grow rate of the orb will be automatically calculated
    // *       based on interval and orb's lifespan (configurable at the
    // *       dynamic configuration part below)
            constant function ICol__CoreTargetSize takes nothing returns real
                return 0.15
            endfunction
    // *    
    // *    10. Swirl effect's model path, will be attached to the orb
            constant function ICol__SwirlSFX takes nothing returns string
                return "war3mapImported\\ExplosiveTornado.mdx"
            endfunction
    // *    
    // *    11. Glow effect's model path, will be attached to the orb
            constant function ICol__GlowSFX takes nothing returns string
                return "war3mapImported\\LightningSphere_FX.mdx"
            endfunction
    // *    
    // *    12. Explosion effect's model path, will be used on explode event
            constant function ICol__ExplosionSFX takes nothing returns string
                return "war3mapImported\\FlameBomb.mdx"
            endfunction
    // *    
    // *    13. Wave effect's model path, will be used on explode event
            constant function ICol__WaveSFX takes nothing returns string
                return "war3mapImported\\Shockwave.mdx"
            endfunction
    // *    
    // *    14. Wave effect's model path, will be used on explode event
            constant function ICol__SphereSFX takes nothing returns string
                return "war3mapImported\\Explosion.mdx"
            endfunction
    // *    
    // *    15. Lifespan of the orb before exploded, may affects grow rate
            constant function ICol__CoreLifespan takes integer level returns real
                return 0.75
            endfunction
    // *    
    // *    16. (i) Orb's minimum distance from cast point
            constant function ICol__MinDistance takes integer level returns real
                return 150.0
            endfunction
    // *    
    // *        (ii) Orb's maximum distance from cast point
            constant function ICol__MaxDistance takes integer level returns real
                return 300.0 + 150.0*level
            endfunction
    // *        * Orbs will be spawned at random location around the cast point
    // *    
    // *    17. (i) Orb's minimum fly height
            constant function ICol__MinHeight takes integer level returns real
                return 150.0
            endfunction
    // *    
    // *        (ii) Orb's maximum fly height
            constant function ICol__MaxHeight takes integer level returns real
                return 300.0
            endfunction
    // *        * Orbs will be spawned at random height
    // *    
    // *    18. (i) Minimum delay before spawning another orb
            constant function ICol__MinDelay takes integer level returns real
                return 0.0
            endfunction
    // *    
    // *        (ii) Maximum delay before spawning another orb
            constant function ICol__MaxDelay takes integer level returns real
                return 0.15
            endfunction
    // *        * Orbs have random spawn rate
    // *    
    // *    19. Maximum duration of the spell
    // *        Use 0 or lower to remove duration limit
            constant function ICol__Duration takes integer level returns real
                return 0.8*level
            endfunction
    // *    
    // *    20. Maximum count of spawned orbs per cast
    // *        Use 0 or lower to remove spawn limit
            constant function ICol__Count takes integer level returns integer
                return 0
            endfunction
    // *    
    // *    21. Maximum distance from target to the orb to take damage
            constant function ICol__AoE takes integer level returns real
                return 300.0
            endfunction
    // *    
    // *    22. If true, the AoE will become spherical
            constant function ICol__3DAoE takes nothing returns boolean
                return true
            endfunction
    // *    
    // *    23. Damage dealt to targets within explosion AoE
            constant function ICol__Damage takes integer level returns real
                return 70.0*level
            endfunction
    // *    
    // *    24. Attack type of dealt damage
            constant function ICol__AttackType takes nothing returns attacktype
                return ATTACK_TYPE_NORMAL
            endfunction
    // *    
    // *    25. Damage type of dealt damage
            constant function ICol__DamageType takes nothing returns damagetype
                return DAMAGE_TYPE_FIRE
            endfunction
    // *    
    // *    26. Weapon type of dealt damage
            constant function ICol__WeaponType takes nothing returns weapontype
                return WEAPON_TYPE_WHOKNOWS
            endfunction
    // *    
    // *    27. This part allows you to change spell's casting type, is it
    // *        point target or no target. For example if you want to change
    // *        it to no target (instant), you can modify this to
    // *            "return GetUnitX(caster)"
            function ICol__GetCastTargetX takes unit caster returns real
                return GetSpellTargetX()
            endfunction
    // *    
    // *    28. Same as above. For example if you want to change it to no
    // *        target (instant), you can modify this to
    // *            "return GetUnitY(caster)"
            function ICol__GetCastTargetY takes unit caster returns real
                return GetSpellTargetY()
            endfunction
    // *        * Targeting unit cast type is not recommended
    // *    
    // *    29. No need to touch this, used to check is unit alive or not
            function ICol__isAlive takes unit id returns boolean
                return GetWidgetLife(id) > 0.405 and not IsUnitType(id, UNIT_TYPE_DEAD)
            endfunction
    // *    
    // *    30. Classification of unit which can become a victim of the spell
            function ICol__Targets takes unit target, player caster returns boolean
                return ICol__isAlive(target) and IsUnitEnemy(target, caster) and not(IsUnitType(target, UNIT_TYPE_STRUCTURE) or IsUnitType(target, UNIT_TYPE_MAGIC_IMMUNE))
            endfunction
    // *    
    // *    31. This function will be called whenever a unit is damaged by this spell
            function ICol__OnDamage takes unit target, unit caster, integer level returns nothing
                call DestroyEffect(AddSpecialEffectTarget("Abilities\\Spells\\Items\\AIfb\\AIfbSpecialArt.mdl", target, "chest"))
                // call BJDebugMsg(GetUnitName(target) + " took " + R2SW(ICol__Damage(level), 4, 1) + " damage from " + GetUnitName(caster) + ".")
            endfunction
    // *    
    // *    32. This function will be called whenever an orb is exploded
            function ICol__OnExplode takes unit caster, integer level, real x, real y, real z returns nothing
                // call BJDebugMsg("Alert! An orb (level " + I2S(level) + " from " + GetUnitName(caster) + " has been exploded at [x: " + R2SW(x, 4, 1) + ", y: " + R2SW(y, 4, 1) + ", z: " + R2SW(z, 4, 1) + "]")
            endfunction
    // *    
    // *    33. This function will be called whenever an orb is spawned
            function ICol__OnSpawn takes unit caster, integer level, real x, real y, real z returns nothing
                // call BJDebugMsg("Alert! An orb (level " + I2S(level) + " from " + GetUnitName(caster) + " has been spawned at [x: " + R2SW(x, 4, 1) + ", y: " + R2SW(y, 4, 1) + ", z: " + R2SW(z, 4, 1) + "]")
            endfunction
    // *    
    // *                End of Configuration
    // *    
    // ********************************************************
        
        function ICol__getZ takes real x, real y returns real
            call MoveLocation(udg_ICol__TempLoc, x, y)
            return GetLocationZ(udg_ICol__TempLoc)
        endfunction
        
        function ICol__setZ takes unit u, real z returns nothing
            call SetUnitFlyHeight(u, z - ICol__getZ(GetUnitX(u), GetUnitY(u)), 0)
        endfunction
    
    // Orb periodic callback
        function ICol__orb__periodic takes nothing returns nothing
            
            local integer i = 1
            local boolean b
            local unit u
            local real d
            local real x
            local real y
            local real z
            
            loop
                exitwhen i > udg_ICol__Orb__Count
                // If still need to grow
                if udg_ICol__Orb__Scale[i] > ICol__CoreTargetSize() then
                    set udg_ICol__Orb__Scale[i] = udg_ICol__Orb__Scale[i] - udg_ICol__Orb__ScaleRate[i]
                    call SetUnitScale(udg_ICol__Orb__Dummy[i], udg_ICol__Orb__Scale[i], 1, 1)
                else
                    set udg_ICol__OCount[udg_ICol__Orb__Source[i]] = udg_ICol__OCount[udg_ICol__Orb__Source[i]] - 1
                    call UnitApplyTimedLife(udg_ICol__Orb__Dummy[i], 'BTLF', ICol__SFXDecayTime())
                    call DestroyEffect(udg_ICol__Orb__CoreFx[i])
                    call DestroyEffect(udg_ICol__Orb__GlowFx[i])
                    call DestroyEffect(udg_ICol__Orb__SwirlFx[i])
                    
                    // If the caster is still alive then allow orb to explode
                    if ICol__isAlive(udg_ICol__Caster[udg_ICol__Orb__Source[i]]) then
                        call ICol__OnExplode(udg_ICol__Caster[udg_ICol__Orb__Source[i]], udg_ICol__Level[udg_ICol__Orb__Source[i]], udg_ICol__Orb__X[i], udg_ICol__Orb__Y[i], udg_ICol__Orb__Z[i])
                        // We need dummy to adjust explosion effects' height
                        set u = CreateUnit(udg_ICol__Owner[udg_ICol__Orb__Source[i]], ICol__DummyID(), udg_ICol__Orb__X[i], udg_ICol__Orb__Y[i], 0)
                        if UnitAddAbility(u, 'Amrf') and UnitRemoveAbility(u, 'Amrf') then
                        endif
                        call ICol__setZ(u, udg_ICol__Orb__Z[i])
                        call DestroyEffect(AddSpecialEffectTarget(ICol__ExplosionSFX(), u, "origin"))
                        call DestroyEffect(AddSpecialEffectTarget(ICol__WaveSFX(), u, "origin"))
                        call DestroyEffect(AddSpecialEffectTarget(ICol__SphereSFX(), u, "origin"))
                        call UnitApplyTimedLife(u, 'BTLF', ICol__SFXDecayTime())
                        
                        call GroupEnumUnitsInRange(udg_ICol__TempGroup, udg_ICol__Orb__X[i], udg_ICol__Orb__Y[i], udg_ICol__AoE[udg_ICol__Orb__Source[i]], null)
                        loop
                            set u = FirstOfGroup(udg_ICol__TempGroup)
                            exitwhen u == null
                            call GroupRemoveUnit(udg_ICol__TempGroup, u)
                            
                            if ICol__Targets(u, udg_ICol__Owner[udg_ICol__Orb__Source[i]]) then
                                set b = true
                                if ICol__3DAoE() then
                                    // Spherical collision (AoE)
                                    set x = GetUnitX(u)
                                    set y = GetUnitY(u)
                                    set z = udg_ICol__Orb__Z[i]-(ICol__getZ(x, y)+GetUnitFlyHeight(u))
                                    set d = SquareRoot((udg_ICol__Orb__X[i] - x)*(udg_ICol__Orb__X[i] - x) + (udg_ICol__Orb__Y[i] - y)*(udg_ICol__Orb__Y[i] - y))
                                    set b = (d*d)+(z*z) < udg_ICol__AoE[udg_ICol__Orb__Source[i]]*udg_ICol__AoE[udg_ICol__Orb__Source[i]]
                                endif
                                if b then
                                    call UnitDamageTarget(udg_ICol__Caster[udg_ICol__Orb__Source[i]], u, udg_ICol__Damage[udg_ICol__Orb__Source[i]], false, false, ICol__AttackType(), ICol__DamageType(), ICol__WeaponType())
                                    call ICol__OnDamage(u, udg_ICol__Caster[udg_ICol__Orb__Source[i]], udg_ICol__Level[udg_ICol__Orb__Source[i]])
                                endif
                            endif
                        endloop
                    endif
                    
                    if i != udg_ICol__Orb__Count then
                        // Deindexing
                        set udg_ICol__Orb__Dummy[i] = udg_ICol__Orb__Dummy[udg_ICol__Orb__Count]
                        set udg_ICol__Orb__CoreFx[i] = udg_ICol__Orb__CoreFx[udg_ICol__Orb__Count]
                        set udg_ICol__Orb__SwirlFx[i] = udg_ICol__Orb__SwirlFx[udg_ICol__Orb__Count]
                        set udg_ICol__Orb__GlowFx[i] = udg_ICol__Orb__GlowFx[udg_ICol__Orb__Count]
                        set udg_ICol__Orb__Scale[i] = udg_ICol__Orb__Scale[udg_ICol__Orb__Count]
                        set udg_ICol__Orb__ScaleRate[i] = udg_ICol__Orb__ScaleRate[udg_ICol__Orb__Count]
                        set udg_ICol__Orb__Source[i] = udg_ICol__Orb__Source[udg_ICol__Orb__Count]
                        set udg_ICol__Orb__X[i] = udg_ICol__Orb__X[udg_ICol__Orb__Count]
                        set udg_ICol__Orb__Y[i] = udg_ICol__Orb__Y[udg_ICol__Orb__Count]
                        set udg_ICol__Orb__Z[i] = udg_ICol__Orb__Z[udg_ICol__Orb__Count]
                    endif
                    // Remove leaks
                    set udg_ICol__Orb__Dummy[udg_ICol__Orb__Count] = null
                    set udg_ICol__Orb__CoreFx[udg_ICol__Orb__Count] = null
                    set udg_ICol__Orb__SwirlFx[udg_ICol__Orb__Count] = null
                    set udg_ICol__Orb__GlowFx[udg_ICol__Orb__Count] = null
                    set udg_ICol__Orb__Count = udg_ICol__Orb__Count - 1
                    if udg_ICol__Orb__Count < 1 then
                        call PauseTimer(udg_ICol__Orb__Timer)
                    else
                        set i = i - 1
                    endif
                endif
                set i = i + 1
            endloop
            
        endfunction
        
    // To create an orb at given coordinates
        function ICol__orb__create takes integer source, real x, real y, real z returns nothing
            
            set udg_ICol__Orb__Count = udg_ICol__Orb__Count + 1
            set udg_ICol__Orb__Source[udg_ICol__Orb__Count] = source
            set udg_ICol__Orb__Dummy[udg_ICol__Orb__Count] = CreateUnit(udg_ICol__Owner[source], ICol__DummyID(), x, y, 0)
            set udg_ICol__Orb__CoreFx[udg_ICol__Orb__Count] = AddSpecialEffectTarget(ICol__CoreSFX(), udg_ICol__Orb__Dummy[udg_ICol__Orb__Count], "origin")
            set udg_ICol__Orb__SwirlFx[udg_ICol__Orb__Count] = AddSpecialEffectTarget(ICol__SwirlSFX(), udg_ICol__Orb__Dummy[udg_ICol__Orb__Count], "origin")
            set udg_ICol__Orb__GlowFx[udg_ICol__Orb__Count] = AddSpecialEffectTarget(ICol__GlowSFX(), udg_ICol__Orb__Dummy[udg_ICol__Orb__Count], "origin")
            set udg_ICol__Orb__Scale[udg_ICol__Orb__Count] = GetRandomReal(ICol__CoreMinSize(), ICol__CoreMaxSize())
            set udg_ICol__Orb__ScaleRate[udg_ICol__Orb__Count] = (udg_ICol__Orb__Scale[udg_ICol__Orb__Count]-ICol__CoreTargetSize())/(udg_ICol__Lifespan[source]/ICol__Interval())
            // Update orb's coordinate in case it's created at different loc (exceed map boundaries/pathing issue)
            set udg_ICol__Orb__X[udg_ICol__Orb__Count] = GetUnitX(udg_ICol__Orb__Dummy[udg_ICol__Orb__Count])
            set udg_ICol__Orb__Y[udg_ICol__Orb__Count] = GetUnitY(udg_ICol__Orb__Dummy[udg_ICol__Orb__Count])
            set udg_ICol__Orb__Z[udg_ICol__Orb__Count] = z+ICol__getZ(udg_ICol__Orb__X[udg_ICol__Orb__Count], udg_ICol__Orb__Y[udg_ICol__Orb__Count])
            
            if UnitAddAbility(udg_ICol__Orb__Dummy[udg_ICol__Orb__Count], 'Amrf') and UnitRemoveAbility(udg_ICol__Orb__Dummy[udg_ICol__Orb__Count], 'Amrf') then
            endif
            call SetUnitFlyHeight(udg_ICol__Orb__Dummy[udg_ICol__Orb__Count], z, 0)
            call SetUnitScale(udg_ICol__Orb__Dummy[udg_ICol__Orb__Count], udg_ICol__Orb__Scale[udg_ICol__Orb__Count], 1, 1)
            call ICol__OnSpawn(udg_ICol__Caster[source], udg_ICol__Level[source], x, y, z)
            
            if udg_ICol__Orb__Count == 1 then
                call TimerStart(udg_ICol__Orb__Timer, ICol__Interval(), true, function ICol__orb__periodic)
            endif
            
        endfunction
        
    // Main spell's periodic callback
        function ICol__periodic takes nothing returns nothing
            
            local integer h
            local integer i = 1
            local integer j
            local real d
            local real a
            
            loop
                exitwhen i > udg_ICol__Count
                if not udg_ICol__Dispose[i] then
                    if udg_ICol__Duration[i] > 0 then
                        set udg_ICol__Duration[i] = udg_ICol__Duration[i] - ICol__Interval()
                        set udg_ICol__Dispose[i] = udg_ICol__Duration[i] <= 0
                    endif
                    
                    // If current order still matches
                    if not udg_ICol__Dispose[i] then
                        set udg_ICol__Dispose[i] = not ICol__isAlive(udg_ICol__Caster[i]) or ICol__Channeling() and GetUnitCurrentOrder(udg_ICol__Caster[i]) != ICol__OrderID()
                    endif
                    
                    if not udg_ICol__Dispose[i] then
                        if udg_ICol__Delay[i] > ICol__Interval() then
                            set udg_ICol__Delay[i] = udg_ICol__Delay[i] - ICol__Interval()
                        else
                            // If still able to spawn more orbs
                            if udg_ICol__SpawnCount[i] > 0 then
                                set udg_ICol__SpawnCount[i] = udg_ICol__SpawnCount[i] - 1
                                set udg_ICol__Dispose[i] = udg_ICol__SpawnCount[i] == 0
                            endif
                            set udg_ICol__Delay[i] = GetRandomReal(udg_ICol__DelayMin[i], udg_ICol__DelayMax[i])
                            // Create new orb at random coordinate around the cast point
                            set d = GetRandomReal(udg_ICol__DistanceMin[i], udg_ICol__DistanceMax[i])
                            set a = GetRandomReal(-bj_PI, bj_PI)
                            set udg_ICol__OCount[i] = udg_ICol__OCount[i] + 1
                            call ICol__orb__create(i, udg_ICol__X[i]+d*Cos(a), udg_ICol__Y[i]+d*Sin(a), GetRandomReal(udg_ICol__HeightMin[i], udg_ICol__HeightMax[i]))
                        endif
                    endif
                endif
                
                // If the spell is ended
                if udg_ICol__Dispose[i] then
                    if udg_ICol__OCount[i] <= 0 then
                        set h = GetHandleId(udg_ICol__Caster[i])
                        if HaveSavedInteger(udg_ICol__Hashtable, h, 0) then
                            if ICol__Channeling() then
                                if LoadInteger(udg_ICol__Hashtable, h, 0) == i then
                                    call RemoveSavedInteger(udg_ICol__Hashtable, h, 0)
                                endif
                            endif
                        endif
                        if i != udg_ICol__Count then
                            // Index correction
                            if ICol__Channeling() then
                                call SaveInteger(udg_ICol__Hashtable, GetHandleId(udg_ICol__Caster[udg_ICol__Count]), 0, i)
                            endif
                            
                            // Deindexing
                            set udg_ICol__Caster[i] = udg_ICol__Caster[udg_ICol__Count]
                            set udg_ICol__Owner[i] = udg_ICol__Owner[udg_ICol__Count]
                            set udg_ICol__X[i] = udg_ICol__X[udg_ICol__Count]
                            set udg_ICol__Y[i] = udg_ICol__Y[udg_ICol__Count]
                            set udg_ICol__Level[i] = udg_ICol__Level[udg_ICol__Count]
                            set udg_ICol__Damage[i] = udg_ICol__Damage[udg_ICol__Count]
                            set udg_ICol__Dispose[i] = udg_ICol__Dispose[udg_ICol__Count]
                            
                            set udg_ICol__OCount[i] = udg_ICol__OCount[udg_ICol__Count]
                            set udg_ICol__AoE[i] = udg_ICol__AoE[udg_ICol__Count]
                            set udg_ICol__Lifespan[i] = udg_ICol__Lifespan[udg_ICol__Count]
                            set udg_ICol__SpawnCount[i] = udg_ICol__SpawnCount[udg_ICol__Count]
                            set udg_ICol__Duration[i] = udg_ICol__Duration[udg_ICol__Count]
                            set udg_ICol__DistanceMin[i] = udg_ICol__DistanceMin[udg_ICol__Count]
                            set udg_ICol__DistanceMax[i] = udg_ICol__DistanceMax[udg_ICol__Count]
                            
                            set udg_ICol__HeightMin[i] = udg_ICol__HeightMin[udg_ICol__Count]
                            set udg_ICol__HeightMax[i] = udg_ICol__HeightMax[udg_ICol__Count]
                            set udg_ICol__DelayMin[i] = udg_ICol__DelayMin[udg_ICol__Count]
                            set udg_ICol__DelayMax[i] = udg_ICol__DelayMax[udg_ICol__Count]
                            set udg_ICol__Delay[i] = udg_ICol__Delay[udg_ICol__Count]
                        
                            // Source index corrections
                            set j = 1
                            loop
                                exitwhen j > udg_ICol__Orb__Count
                                if udg_ICol__Orb__Source[j] == udg_ICol__Count then
                                    set udg_ICol__Orb__Source[j] = i
                                endif
                                set j = j + 1
                            endloop
                        endif
                        // Remove leak
                        set udg_ICol__Caster[udg_ICol__Count] = null
                        set udg_ICol__Count = udg_ICol__Count - 1
                        if udg_ICol__Count < 1 then
                            call PauseTimer(udg_ICol__Timer)
                        else
                            set i = i - 1
                        endif
                    endif
                endif
                set i = i + 1
            endloop
            
        endfunction
        
    // On cast event
        function ICol__onCast takes nothing returns boolean
            
            local integer h
            
            if GetSpellAbilityId() == ICol__SpellID() then
                set udg_ICol__Count = udg_ICol__Count + 1
                set udg_ICol__Caster[udg_ICol__Count] = GetTriggerUnit()
                set udg_ICol__Owner[udg_ICol__Count] = GetTriggerPlayer()
                set udg_ICol__Dispose[udg_ICol__Count] = false
                set udg_ICol__OCount[udg_ICol__Count] = 0
                
                // Get cast point coordinate (customizable by user)
                set udg_ICol__X[udg_ICol__Count] = ICol__GetCastTargetX(udg_ICol__Caster[udg_ICol__Count])
                set udg_ICol__Y[udg_ICol__Count] = ICol__GetCastTargetY(udg_ICol__Caster[udg_ICol__Count])
                set udg_ICol__Level[udg_ICol__Count] = GetUnitAbilityLevel(udg_ICol__Caster[udg_ICol__Count], ICol__SpellID())
                set udg_ICol__Damage[udg_ICol__Count] = ICol__Damage(udg_ICol__Level[udg_ICol__Count])
                set udg_ICol__AoE[udg_ICol__Count] = ICol__AoE(udg_ICol__Level[udg_ICol__Count])
                set udg_ICol__Lifespan[udg_ICol__Count] = ICol__CoreLifespan(udg_ICol__Level[udg_ICol__Count])
                set udg_ICol__SpawnCount[udg_ICol__Count] = ICol__Count(udg_ICol__Level[udg_ICol__Count])
                set udg_ICol__Duration[udg_ICol__Count] = ICol__Duration(udg_ICol__Level[udg_ICol__Count])
                
                set udg_ICol__DistanceMin[udg_ICol__Count] = ICol__MinDistance(udg_ICol__Level[udg_ICol__Count])
                set udg_ICol__DistanceMax[udg_ICol__Count] = ICol__MaxDistance(udg_ICol__Level[udg_ICol__Count])
                set udg_ICol__HeightMin[udg_ICol__Count] = ICol__MinHeight(udg_ICol__Level[udg_ICol__Count])
                set udg_ICol__HeightMax[udg_ICol__Count] = ICol__MaxHeight(udg_ICol__Level[udg_ICol__Count])
                set udg_ICol__DelayMin[udg_ICol__Count] = ICol__MinDelay(udg_ICol__Level[udg_ICol__Count])
                set udg_ICol__DelayMax[udg_ICol__Count] = ICol__MaxDelay(udg_ICol__Level[udg_ICol__Count])
                set udg_ICol__Delay[udg_ICol__Count] = GetRandomReal(udg_ICol__DelayMin[udg_ICol__Count], udg_ICol__DelayMax[udg_ICol__Count])
                
                if udg_ICol__Count == 1 then
                    call TimerStart(udg_ICol__Timer, ICol__Interval(), true, function ICol__periodic)
                endif
                
                // Use hashtable to avoid casting collision (if channeling)
                if ICol__Channeling() then
                    set h = GetHandleId(udg_ICol__Caster[udg_ICol__Count])
                    if HaveSavedInteger(udg_ICol__Hashtable, h, 0) then
                        set udg_ICol__Dispose[LoadInteger(udg_ICol__Hashtable, h, 0)] = true
                    endif
                    call SaveInteger(udg_ICol__Hashtable, h, 0, udg_ICol__Count)
                endif
            endif
            
            return false
        endfunction
        
    // Initialization
        function InitTrig_Infernal_Collapse takes nothing returns nothing
            
            if ICol__Channeling() then
                set udg_ICol__Hashtable = InitHashtable()
            endif
            
            set udg_ICol__Timer = CreateTimer()
            set udg_ICol__Orb__Timer = CreateTimer()
            set udg_ICol__TempGroup = CreateGroup()
            set udg_ICol__TempLoc = Location(0, 0)
            
            set gg_trg_Infernal_Collapse = CreateTrigger()
            call TriggerRegisterAnyUnitEventBJ(gg_trg_Infernal_Collapse, EVENT_PLAYER_UNIT_SPELL_EFFECT)
            call TriggerAddCondition(gg_trg_Infernal_Collapse, Condition(function ICol__onCast))
            
        endfunction
Credits
  • BTNEvaporate By M0rbid
  • Explosion.mdx By JetFangInferno
  • ExplosiveTornado.mdx By JetFangInferno
  • EMPBomb.mdx By WILL THE ALMIGHTY
  • Fire Low.mdx By Pyritie
  • LightningSphere_FX.mdx By PeeKay
  • Shockwave.mdx By Vestras
  • dummy.mdx By Vexorian

Keywords:
Infernal, Collapse
Contents

Infernal Collapse (Map)

Reviews
Infernal Collapse v1.2 | Reviewed by BPower | 02.07.2015 Concept[/COLOR]] Ultimately a meteor type spell. The effect models are very well chosen and fit to the spell desciption. The spell itself is very configurable and the fun to cast...

Moderator

M

Moderator


Infernal Collapse v1.2 | Reviewed by BPower | 02.07.2015

[COLOR="gray"

[COLOR="gray"

[COLOR="gray"

[COLOR="gray"

[COLOR="gray"

Concept[/COLOR]]
126248-albums6177-picture66521.png
Ultimately a meteor type spell.
The effect models are very well chosen and fit to the spell desciption.
The spell itself is very configurable and the fun to cast.

Good job!
Code[/COLOR]]
126248-albums6177-picture66521.png
  • The code is MUI, leakless and working.
  • The documentation is very good.
126248-albums6177-picture66523.png
  • For 3D collision you have to take the orbs terrainZ and
    the hit unit terrainZ into account. Ofc also their fly height.
Objects[/COLOR]]
126248-albums6177-picture66523.png
  • Object editor data is good.
Effects[/COLOR]]
126248-albums6177-picture66521.png
  • The effect models are well chosen and fit to the spell description.
Rating[/COLOR]]
CONCEPTCODEOBJECTSEFFECTSRATINGSTATUS
4/5
4/5
5/5
4.5/5
4/5
APPROVED
 
Level 19
Joined
Mar 18, 2012
Messages
1,716
Thread set to open.

Towards your previous question:
The map can be opened, I didn't have recieve fatal error.

You deindex the main part of the spell not in dependency of your orbs,
but there is backwards reference i.e udg_ICol__Caster[udg_ICol__Orb__Source[i]]
As conclusion your data may be incorrect ( wrong caster unit ).
Also you never null the caster in case only one instance is allocated.


This jumped now into my eye and might also be wrong in your other submission.
I have to double check that code again.
Edit: Yes same problem, I was too fast approving your spell. Set back to Need Fix until further updates. :(

I recommend to use spell effect event over call TriggerRegisterAnyUnitEventBJ(gg_trg_Infernal_Collapse, EVENT_PLAYER_UNIT_SPELL_CAST) as it fires after mana is used.

It's a welcome bonus that hastables return 0, if nothing is stored a key.
However I would like to recommend to you the usage of HaveSavedInteger
as 0 is also a value which you can save on a child key.

You skip array index 0 and start off at 1. Not a big deal.
 
Last edited:

Kazeon

Hosted Project: EC
Level 33
Joined
Oct 12, 2011
Messages
3,449
Thread set to open.

Towards your previous question:
The map can be opened, I didn't have recieve fatal error.

You deindex the main part of the spell not in dependency of your orbs,
but there is backwards reference i.e udg_ICol__Caster[udg_ICol__Orb__Source[i]]
As conclusion your data may be incorrect ( wrong caster unit ).
Also you never null the caster in case only one instance is allocated.


This jumped now into my eye and might also be wrong in your other submission.
I have to double check that code again.
Edit: Yes same problem, I was too fast approving your spell. Set back to Need Fix until further updates. :(

I recommend to use spell effect event over call TriggerRegisterAnyUnitEventBJ(gg_trg_Infernal_Collapse, EVENT_PLAYER_UNIT_SPELL_CAST) as it fires after mana is used.

It's a welcome bonus that hastables return 0, if nothing is stored a key.
However I would like to recommend to you the usage of HaveSavedInteger
as 0 is also a value which you can save on a child key.

You skip array index 0 and start off at 1. Not a big deal.

Nice catch. I didn't realize even after making this one. I gonna fix it soon.


EDIT:
I recommend to use spell effect event over call TriggerRegisterAnyUnitEventBJ(gg_trg_Infernal_Collapse, EVENT_PLAYER_UNIT_SPELL_CAST) as it fires after mana is used.
What's their difference? Except if by saying spell effect event you want me to use vJass library, then I will say absolute no.

EDIT 2:
Ah wait a sec, it's my mistake to use spell cast event. I didn't notice it. It's just in this spell right? Gonna check the other one.

Woop, it has the same mistake as well.
 
Last edited:

Kazeon

Hosted Project: EC
Level 33
Joined
Oct 12, 2011
Messages
3,449
How do i configure the spell? I copied as you said but nothing happens when i cast it.

Have you configured the spell correctly (this is a common mistake)? Like setting the spell id and dummy id? You can find those at this part:
JASS:
    // ********************************************************
    // *    
    // *                   Configuration
    // *    
    // *    1. Dummy unit's raw code at object editor
            constant function ICol__DummyID takes nothing returns integer
                return 'h000'
            endfunction
    // *    
    // *    2. Main ability's raw code at object editor
            constant function ICol__SpellID takes nothing returns integer
                return 'A000'
            endfunction

By id it means "raw code". You can find those in object editor by pressing CTRL+D.
 
Level 4
Joined
Dec 3, 2014
Messages
64
Hey Quilnez, happend after your help is: i tried to add everything to a clean new map. it worked. But changing the jazz code to the raw data dependent on my map didn't work.
 

Kazeon

Hosted Project: EC
Level 33
Joined
Oct 12, 2011
Messages
3,449
I changed my review according to your changes. The 3D cloosion only works if you
consider both unit and orb terrainZ. Fly height is really not easy to manage in wc3.

I already did it:
JASS:
set z = udg_ICol__Orb__Z[i]-(ICol__getZ(x, y)+GetUnitFlyHeight(u))
But there is still bug with explode effects height. Will fix it asap.

Hey Quilnez, happend after your help is: i tried to add everything to a clean new map. it worked. But changing the jazz code to the raw data dependent on my map didn't work.

Have you imported the dummy.mdx and other effect files and set them correctly both in object editor and trigger editor? Or maybe you can upload your map?
 
Level 4
Joined
Dec 3, 2014
Messages
64
Hello again Quilnez i deleted the spell in my map and readded everything and now it works (also visiual) just a final last qustion, how i can or where (in which row) i can/could change number of the orbs or the their damage? Thanks for everything and this really cool.. no its hot spell!
 

Kazeon

Hosted Project: EC
Level 33
Joined
Oct 12, 2011
Messages
3,449
Hello again Quilnez i deleted the spell in my map and readded everything and now it works (also visiual) just a final last qustion, how i can or where (in which row) i can/could change number of the orbs or the their damage? Thanks for everything and this really cool.. no its hot spell!

In the configuration part, just read the documentation (texts above every function).

I'm glad you like it.
 
Level 6
Joined
Aug 5, 2015
Messages
202
good spell sir but i have prob the moment i add this spell to my map
your spell is worked, but one of my spell not worked anymore after i using your spell
this is my bugged spell:

  • carrion splash
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • (Ability being cast) Equal to Carrion Splash Active
    • Actions
      • Set Position_SpellsFire[2] = (Position of (Triggering unit))
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
        • Then - Actions
          • For each (Integer A) from 1 to 20, do (Actions)
            • Loop - Actions
              • Unit - Create 1 ILLIDAN CARRION SWARM for (Owner of (Triggering unit)) at Position_SpellsFire[2] facing ((Real((Integer A))) x 18.00) degrees
              • Set Loc_SpellsFire = (Position of (Last created unit))
              • Set Position_SpellsFire[4] = (Loc_SpellsFire offset by 0.00 towards ((Real((Integer A))) x 18.00) degrees)
              • Unit - Order (Last created unit) to Undead Dreadlord - Carrion Swarm Position_SpellsFire[4]
              • Custom script: call RemoveLocation (udg_Position_SpellsFire[4])
        • Else - Actions
      • Custom script: call RemoveLocation (udg_Position_SpellsFire[2])
      • Custom script: call RemoveLocation (udg_Loc_SpellsFire)
      • Custom script: call RemoveLocation (udg_Position_SpellsFire[4])
my spell base ability is warstomp , then create dummy around caster and shoot carrion swarm, your spell base id is carrion swarm
i use my spell on hero A, and use infernal collapse on hero B
but somehow my spell didnt worked anymore (as if the trigger not running)

but after i change channel order id infernal collapse from carrion swarm into shockwave, my spell is worked again

why is that? and i just worried there's possibility your spell making my specific basic spell not worked anymore (depend on infernal collapse order id), any clue?
 

Kazeon

Hosted Project: EC
Level 33
Joined
Oct 12, 2011
Messages
3,449
No idea. Probably caused by order id collision. But good thing it works for you eventually. And thanks for using. Good luck with the project.

Just a hint, there is still a bug regarding to cliff levels which I'm still too lazy to fix. But as long as you don't have multiple cliff levels in your map, there's nothing to worry about.
 
Top