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

Meteorites fall v1.7

  • Like
Reactions: Doomlord
-------------------------------------------
M E T E O R F A L L

I/ Spell Information:
untitl44.jpg

II/ Spell Code:
JASS:
//*************************************************************************************
//*************************************************************************************
//*************************************************************************************
//*************************************************************************************
//          M E T E O R  F A L L
//                                  - Spell Create By:
//                                                      + Elphis
//*************************************************************************************
library MeteoritesFall /*                   
*/                                      requires /*
//                                              -*/ DelFX /* http://www.hiveworkshop.com/forums/spells-569/delfx-delayed-effects-1-4-2-a-116064/?prev=search%3DDel%2520Effect%26d%3Dlist%26r%3D20%26c%3D112
//                                              -*/ TimerUtils /* http://www.wc3c.net/showthread.php?t=101322
//                                              -*/ IsTerrainWalkable /* I can't found this link of the library, so credits by Maker,anitarf
//                                              -*/ SpellEffectEvent /* http://www.hiveworkshop.com/forums/jass-resources-412/snippet-spelleffectevent-187193/
//                                              -*/ RegisterPlayerUnitEvent /* http://www.hiveworkshop.com/forums/jass-resources-412/snippet-registerplayerunitevent-203338/
//                                              -*/ xedamage /* http://www.wc3c.net/showthread.php?t=101150
//                                              -*/ SimError /* http://www.wc3c.net/showthread.php?t=101260 
//                                              -*/ JumpTargetDamage /* Spell Staus Library */
//*************************************************************************************
//          - Spell Information:
//                              - Calling a big meteor in sky falling ground
//                              when it hit a ground. This meteor will explore and deals 75/150/225/300
//                              damage in 300 AOE and radiating mini meteor in 500 AOE
//                              deals 20/40/60/80 damage.
//                              
//*************************************************************************************
//          - Installation:
//                                - Import/copy the required libraries and Meteor Fall code to your map
//                                - Import/copy the custom ability and unit to your map and change the SPELL_ID and FIRE_ID if needed
//                                - You may view the raw ID of the objects by pressing CTRL+D in the object editor
//                                - You may play with the configurables below
//*************************************************************************************
    //
    globals
        //==================================CONFIGURABLES=============================================//
        //Spell rawcode, change if needed
        private     constant        integer     SPELL_ID               =       'A000'
        //Ability allow unit fly
        private     constant        integer     ABI_FLY                =       'Amrf'
        //Mini Meteor count
        private     constant        integer     MINI_METEOR_C          =       20
        //Meteor Model
        private     constant        string      METEOR_MODEL           =       "Abilities\\Weapons\\DemonHunterMissile\\DemonHunterMissile.mdl"
        //Meteor explore
        private     constant        string      METEOR_EXPLORE         =       "Objects\\Spawnmodels\\Other\\NeutralBuildingExplosion\\NeutralBuildingExplosion.mdl"
        //Model attach from Meteor, Good = origin
        private     constant        string      METEOR_ATTACHMENT      =       "origin"
        //Displayed messages when you can't caller meteor
        private     constant        string      ERROR                  =       "Can't call Meteor here"
        //Timer calling func every time
        private     constant        real        PERIODIC               =       0.031250000
        //Meteor duration
        private     constant        real        METEOR_DURATION        =       3.
        //Damage when exploring on center Big Meteor
        private     constant        real        METEOR_DAMAGE          =       75.
        //Damage when exploring on mini meteor
        private     constant        real        METEOR_MINI_DAMAGE     =       20.
        //Max height of Meteor
        private     constant        real        METEOR_HEIGHT          =       1000.
        //Meteor fall speed
        private     constant        real        METEOR_FALL_SPEED      =       30.
        //Mini meteor explore speed
        private     constant        real        METEOR_MINI_EX_SPEED   =       20.
        //Mini meteor create angle
        private     constant        real        METEOR_MINI_ANGLE      =       36.
        //Min distance mini meteor called
        private     constant        real        METEOR_MINI_MIN        =       150.
        //Max distance mini meteor called
        private     constant        real        METEOR_MINI_MAX        =       500.
        //Damage radius of Big meteor
        private     constant        real        DAMAGE_RADIUS          =       400.
        //Damage radius of mini meteor
        private     constant        real        DAMAGE_RADIUS_MINI     =       200.
        //Big meteor Size
        private     constant        real        BIG_METEOR_SIZE        =       5.
        //Mini meteor Size
        private     constant        real        MINI_METEOR_SIZE       =       1.
        //Big meteor fall out speed
        private     constant        real        METEOR_SPEED           =       20.
        //Allow damage to tree
        private     constant        boolean     DAMAGE_TREE            =       true
        //
        private     constant        attacktype  ATTACKTYPE             =       ATTACK_TYPE_HERO
        private     constant        damagetype  DAMAGETYPE             =       DAMAGE_TYPE_COLD
        private     constant        weapontype  WEAPONTYPE             =       WEAPON_TYPE_METAL_HEAVY_BASH
        //
        private                     xedamage    xe
        //==================================CONFIGURABLES=============================================//
        //
    endglobals
    //
    private struct MeteoritesFall
    //
    unit caster = null
    unit dummy = null
    real ff
    real h = METEOR_HEIGHT
    real f
    real cos
    real sin
    integer level
    player p = null
            //Check this area can casting spell
            static method terrainCheck takes nothing returns nothing
                local unit caster
                if GetSpellAbilityId() != SPELL_ID then
                    set caster = null
                    return
                endif
                //
                set caster = GetTriggerUnit()
                //
                if not IsTerrainWalkable(GetSpellTargetX(),GetSpellTargetY()) then
                    call PauseUnit(caster, true)
                    call IssueImmediateOrderById(caster, 851972)
                    call PauseUnit(caster, false)
                    call SimError(GetTriggerPlayer(), ERROR)
                endif
                set caster = null
            endmethod
            //
            static method onDamage takes unit caster returns real
                return METEOR_DAMAGE //Damage of Big Meteor
            endmethod
            //
            static method onDamageMiniMeteor takes unit caster returns real
                return METEOR_MINI_DAMAGE //Damage of mini Meteor
            endmethod
            //Loop calling every time
            static method onPeriodic takes nothing returns nothing
                local timer t = GetExpiredTimer()
                local thistype this = GetTimerData(t)
                local integer i = MINI_METEOR_C
                local unit d
                local real x
                local real y
                if h > 0. then
                    set h = h - METEOR_SPEED
                    //
                    call SetUnitFlyHeight(dummy,h,METEOR_HEIGHT/.1)
                    //
                    set x = GetWidgetX(dummy) + cos
                    set y = GetWidgetY(dummy) + sin
                    //
                    call SetUnitX(dummy,x)
                    call SetUnitY(dummy,y)
                else
                    call ReleaseTimer(t)
                    //
                    set f = GetWidgetX(dummy)
                    set ff = GetWidgetY(dummy)
                    call RemoveUnit(dummy)
                    //
                    loop
                    //
                    exitwhen i == 0
                    //
                        //
                        set cos = Cos(i*METEOR_MINI_ANGLE*0.01747)
                        set sin = Sin(i*METEOR_MINI_ANGLE*0.01747)
                        //
                        set x = f + METEOR_MINI_MIN * cos
                        set y = ff + METEOR_MINI_MIN * sin
                        //Calling mini meteor
                        set d = CreateUnit(p,XE_DUMMY_UNITID,x,y,0.)
                        call SetUnitScale(d,MINI_METEOR_SIZE,0,0)
                        call CreateDelayedEffectTarget(METEOR_MODEL,d,METEOR_ATTACHMENT,0.,METEOR_DURATION)
                        set x = GetWidgetX(dummy) + METEOR_MINI_MAX * cos
                        set y = GetWidgetY(dummy) + METEOR_MINI_MAX * sin
                        call Jump.JumpTarget(d,x,y,METEOR_MINI_EX_SPEED,METEOR_EXPLORE,METEOR_EXPLORE,true,false,ATTACKTYPE,DAMAGETYPE,WEAPONTYPE,DAMAGE_RADIUS_MINI,DAMAGE_TREE,caster,onDamageMiniMeteor(caster)*level)
                    //
                    set i = i - 1
                    //
                    endloop
                    //Deals damage to enemy
                    call xe.damageAOE(caster,f,ff,DAMAGE_RADIUS,onDamage(caster)*level)
                    //Remove Leaks
                    call RemoveUnit(dummy)
                    set d = null
                    set caster = null
                    set dummy = null
                    call destroy()
                endif
                //
                set t = null
                //
            endmethod
            //Setup spell if any unit casting this ability
            static method onCast takes nothing returns nothing
                local thistype this = allocate()
                local real x
                local real y
                local real o = GetSpellTargetX()
                local real z = GetSpellTargetY()
                local real m = 0.
                //Other config
                set caster = GetTriggerUnit()
                //Level of Ability
                set level = GetUnitAbilityLevel(caster,SPELL_ID)
                //
                set p = GetTriggerPlayer()
                set x = GetWidgetX(caster)
                set y = GetWidgetY(caster)
                set f = Angle(x,y,o,z)  
                set m = Distance(x,y,o,z)
                //*****************************************************
                //Creating Big Meteor
                set dummy = CreateUnit(p,XE_DUMMY_UNITID,x,y,f)
                call SetUnitScale(dummy,BIG_METEOR_SIZE,0.,0.) //Set meteor size
                call CreateDelayedEffectTarget(METEOR_MODEL,dummy,METEOR_ATTACHMENT,0.,METEOR_DURATION)
                if UnitAddAbility(dummy,ABI_FLY) then
                    call ShowUnit(dummy,false)
                    call UnitRemoveAbility(dummy,ABI_FLY)
                    call SetUnitFlyHeight(dummy,METEOR_HEIGHT,0.)
                    call ShowUnit(dummy,true)
                endif
                //
                set ff = m/METEOR_HEIGHT*METEOR_SPEED
                //
                set cos = ff * Cos(f*0.01747)
                set sin = ff * Sin(f*0.01747)
                //**********************************************
                //
                call TimerStart(NewTimerEx(this),PERIODIC,true,function thistype.onPeriodic)
            endmethod
            //
            static method onInit takes nothing returns nothing
                //This event use for check terrain cast :)
                call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_SPELL_CAST,function thistype.terrainCheck)
                //==========================================================================================
                call RegisterSpellEffectEvent(SPELL_ID,function thistype.onCast)
                //
                //Damage config
                set xe = xedamage.create()
                set xe.dtype = DAMAGETYPE
                set xe.atype = ATTACKTYPE
                set xe.wtype = WEAPONTYPE
                set xe.damageEnemies = true
                set xe.damageTrees   = DAMAGE_TREE
            endmethod
        //
        endstruct
endlibrary
[/HIDDEN]
JASS:
//! zinc
//
library DummRemove requires TimerUtils
{
    public struct Dum
    {
        unit u;
        //
        static method Loop()
        {
            thistype this = GetTimerData(GetExpiredTimer());
            RemoveUnit(u);
            u = null;
            ReleaseTimer(GetExpiredTimer());
            destroy();
        }
        //
        static method Remove(unit whatunit,real dura) -> unit
        {
            thistype this = allocate();
            u = whatunit;
            TimerStart(NewTimerEx(this),dura,false,function thistype.Loop);
            return whatunit;
        }
    }
}
//
library JumpTargetDamage requires TimerUtils,AaD
{
        constant                real                            time            =           .0325;
        //
        public struct Jump
        {
            real Reach;
            real Fly;
            real Dis;
            real Angle;
            real sp;
            boolean kill;
            unit U;
            unit C;
            real High;
            real d;
            real Highsettings;
            real Timer;
            real ag;
            boolean Jumpag;
            boolean rem;
            string EfEnd;
            real radi;
            real damage;
            xedamage xe;
//
    static method onPeriodic()
    {
        real x;
        real y;
        thistype this = GetTimerData(GetExpiredTimer());
        if(!IsUnitType(U,UNIT_TYPE_DEAD) && GetUnitTypeId(U) != 0)
        {
            if (Reach < Dis)
            {
                     x = GetWidgetX(U) + sp * Cos(Angle * 0.01747);
                     y = GetWidgetY(U) + sp * Sin(Angle * 0.01747);
                     SetUnitX(U,x);
                     SetUnitY(U,y);
                     Reach = Reach + sp;
                     Timer = Timer + 180/(Dis / sp);
                     Fly   = Sin(Timer*0.01747)*Highsettings*1.3;
                     SetUnitFlyHeight(U,Fly,0.);
            }
                else
                {
                     if(kill && !rem)
                        KillUnit(U);
                     if(!kill && rem)
                        RemoveUnit(U);
                     xe.damageAOE(C,GetWidgetX(U),GetWidgetY(U),radi,damage);
                     xe.destroy();
                     DestroyEffect(AddSpecialEffect(EfEnd,GetWidgetX(U),GetWidgetY(U)));
                     SetUnitPathing(U,true);
                     UnitAddAbility(U,'Amrf');
                     UnitRemoveAbility(U,'Amrf');
                     SetUnitFlyHeight(U,0.,GetUnitDefaultFlyHeight(U));
                     if(rem)
                        RemoveUnit(U);
                     EfEnd = null;
                     ReleaseTimer(GetExpiredTimer());
                     U = null;
                     destroy();
                }
        }
                else
                {
                     if(kill && !rem)
                        KillUnit(U);
                     if(!kill && rem)
                        RemoveUnit(U);
                     SetUnitPathing(U,true);
                     if (UnitAddAbility(U,'Amrf'))
                        UnitRemoveAbility(U,'Amrf');
                     SetUnitFlyHeight(U,0.,GetUnitDefaultFlyHeight(U));
                     if(rem)
                        RemoveUnit(U);
                     EfEnd = null;
                     xe.destroy();
                     ReleaseTimer(GetExpiredTimer());
                     U = null;
                     destroy();
                }
    }
        static method JumpTarget(unit whatunit,real xj,real yj,real speed,string XJ,string EJ,boolean rems,boolean kills,attacktype att,damagetype damt,weapontype wea,real radius,boolean damat,unit caster,real dam) 
        {
             thistype this;
             if(!IsUnitType(whatunit,UNIT_TYPE_DEAD) && GetUnitTypeId(whatunit) != 0)
             {
                 this = allocate();
                 U = whatunit;
                 Reach = 0.;
                 xe = xedamage.create();
                 xe.dtype = damt;
                 xe.atype = att;
                 xe.wtype = wea;
                 xe.damageEnemies = true;
                 xe.damageTrees   = damat;
                 damage = dam;
                 radi = radius;
                 Timer = 0.;
                 C = caster;
                 rem = rems;
                 kill = kills;
                 rem = rems;
                 sp = speed;
                 Fly = 0.;
                 EfEnd = EJ;
                 Dis = Distance(GetWidgetX(whatunit),GetWidgetY(whatunit),xj,yj);
                 Angle = Angle(GetWidgetX(whatunit),GetWidgetY(whatunit),xj,yj);
                 High = .35;
                 Highsettings = Dis*High;
                 DestroyEffect(AddSpecialEffect(XJ,GetWidgetX(U),GetWidgetY(U)));
                 SetUnitPathing(U,false);
                 UnitAddAbility(U,'Amrf');
                 UnitRemoveAbility(U,'Amrf');
                 TimerStart(NewTimerEx(this),time,true,function thistype.onPeriodic);
            }
        }
            
    }
}
//
library AaD
{
    public function Distance(real xa,real ya,real xb,real yb) -> real
    {
        real dx = xb - xa;
        real dy = yb - ya;
        return SquareRoot(dx * dx + dy * dy);
    }
    //
    public function Angle(real xa,real ya,real xb,real yb) -> real
    {
        return bj_RADTODEG * Atan2(yb - ya, xb - xa);
    }
}
//! endzinc
[/HIDDEN]
III/ Spell Look Like:

untitl45.jpg

untitl46.jpg

untitl47.jpg


IV/ Credits:
Click to view library DelFX
Click to view library Ability Preload
Click to view Timer Utils
Click to view library SpellEffectEvent
Click to view RegisterPlayerUnitEvent
Click to view library xedamage
Click to view library SimError
-------------------------------------------


v1.0: First release version
v1.1: Fix bugs.
v1.2: Fix bugs, remove some stuff, optimized !
v1.3: Optimized.
v1.4: Optimized.
v1.5: Optimized.
v1.6: Optimized.
v1.7: Optimized


Keywords:
fire,meteor,fall,,explore
Contents

Meteor Fall (Map)

Reviews
Meteorites fall v1.6 | Reviewed by Maker | 6th Oct 2013 APPROVED The spell is leakless and MUI You could set the meteor to max flying height when it is created When the spell is cast near the caster, the meteor...

Moderator

M

Moderator


Meteorites fall v1.6 | Reviewed by Maker | 6th Oct 2013
APPROVED


126248-albums6177-picture66521.png


  • The spell is leakless and MUI
126248-albums6177-picture66523.png


  • You could set the meteor to max flying height when it is created
  • When the spell is cast near the caster, the meteor instantly explodes
[tr]



Meteorites fall v1.4 | Reviewed by Maker | 27th Sep 2013
NEEDS FIX


126248-albums6177-picture66522.png


  • Xedamage throws a debugging error message, you have some
    indexing issue
126248-albums6177-picture66523.png


  • In onPeriodic the meteor can hit the ground and then be
    destroyed during the next loop.
    I think you should calculate the new height and then check if h > 0
  • Your period is 0.03125 so it would be better to use a single timer
    to cover all instances
  • Calculate METEOR_SPEED into cos and sin struct members
  • METEOR_MINI_ANGLE*0.01747 could be precalculated
  • You should use the ability level at the time of casting
  • In terrainCheck, set caster only if you need to pause the unit
  • The grammar in the learn tooltip could be improved, and the text doesn't
    say the level of the ability
  • The arc of the meteor does not look smooth
  • The order aborting should be done when the unit is ordered to cast the ability
[tr]
 
Level 4
Joined
Aug 7, 2013
Messages
106
ohhhhh 1st Screenshot: Giant Infernal 2st Screenshot: Baby Infernals 3st Screenshot: Dead Baby Infernals
 
Meteorites Fall v1.3 review

The fiery spells are what I love the most. How wide the fantasy can be with fire? Lots of magma, molten lava, exploding meteors or deadly volcanoes? The choice is yours!
This fire spell called Meteorites Fall is made by nhocklanhox6 and it will now be reviewed.

Originality: 3.5/5. The meteorites are kind of lovely idea but, for example, Invoker in DotA uses something really similar, Earth Mage in OaD had something similar in 2010 year. Also, some more examples of similar spells here on the Hive:
Execution: 4/5. Once again, many small but actually not serious mistakes to point out.
  • IsUnitType(whatunit,UNIT_TYPE_DEAD) == false is a lot more slower than not IsUnitType(whatunit,UNIT_TYPE_DEAD). Same thing with IsTerrainWalkable(GetSpellTargetX(),GetSpellTargetY()) == false and other == false things.
  • Once again, bad variable naming. Qt Coding Style is really good example on how to name the variables right. So, according to one of the postulates of Qt, you must name variables depending on for what they are created. unit u is a bad example because we can't deduct what this variable does. unit abilityCaster or unit caster are some good examples of correct variable naming. Please note that, to avoid messing up, local variables must be named from a lowercase letter and global variables must be named from the uppercase letter. For example, unit Caster is a perfect name for a global variable and unit caster is a perfect name for a local variable. But still, you can use local integer i for loops since this abbreviation is very popular.
  • call SetUnitFlyHeight(dummy,h,0.). It's not really good since it's more code executed. Please try to make use of rates. Rate is the height amount that is passed every second before it hits max height. I will try to show that one in my next spell, it has really solid example.
  • JASS:
                    set x = GetWidgetX(caster) + 0. * cos
                    set y = GetWidgetY(caster) + 0. * sin
    These lines are really stupid since 0. * cos = 0.
  • set f = GetUnitFacing(caster) - bad way to catch the angle between the caster and the target point. It might bug sometimes because of facing nature. I recommend to use angle between coords formula (Atan2 one).
  • EVENT_PLAYER_UNIT_SPELL_CAST is a bad event. EVENT_PLAYER_UNIT_SPELL_EFFECT is better because it will trigger only when the spell is fully casted.
  • set dummy = CreateUnit(p,XE_DUMMY_UNITID,x,y,GetUnitFacing(caster)). Another stupid thing to do. You already have set f = GetUnitFacing(caster) and later you're calling the function again instead of placing a variable there.
  • JASS:
        unit caster
        unit dummy
        real ff
        real h
        real f
        real cos
        real sin
        player p
        xedamage xe
    Preinit them here when possible. That can solve some problems that can be.

Effects: 2.7/5. That's more similar to the effect spam, as for me. Effect spam never was good.

Overall: (3.5+4+2.7/3) = 3.4 = 3/5. That's what the spell can get. With better coding, the rating can be improved. Revising the spell's effects can improve the rating even more.

3/5: Useful
 
The fiery spells are what I love the most. How wide the fantasy can be with fire? Lots of magma, molten lava, exploding meteors or deadly volcanoes? The choice is yours!
This fire spell called Meteorites Fall is made by nhocklanhox6 and it will now be reviewed.

Originality: 3.5/5. The meteorites are kind of lovely idea but, for example, Invoker in DotA uses something really similar, Earth Mage in OaD had something similar in 2010 year. Also, some more examples of similar spells here on the Hive:
Execution: 4/5. Once again, many small but actually not serious mistakes to point out.
  • IsUnitType(whatunit,UNIT_TYPE_DEAD) == false is a lot more slower than not IsUnitType(whatunit,UNIT_TYPE_DEAD). Same thing with IsTerrainWalkable(GetSpellTargetX(),GetSpellTargetY()) == false and other == false things.
  • Once again, bad variable naming. Qt Coding Style is really good example on how to name the variables right. So, according to one of the postulates of Qt, you must name variables depending on for what they are created. unit u is a bad example because we can't deduct what this variable does. unit abilityCaster or unit caster are some good examples of correct variable naming. Please note that, to avoid messing up, local variables must be named from a lowercase letter and global variables must be named from the uppercase letter. For example, unit Caster is a perfect name for a global variable and unit caster is a perfect name for a local variable. But still, you can use local integer i for loops since this abbreviation is very popular.
  • call SetUnitFlyHeight(dummy,h,0.). It's not really good since it's more code executed. Please try to make use of rates. Rate is the height amount that is passed every second before it hits max height. I will try to show that one in my next spell, it has really solid example.
  • JASS:
                    set x = GetWidgetX(caster) + 0. * cos
                    set y = GetWidgetY(caster) + 0. * sin
    These lines are really stupid since 0. * cos = 0.
  • set f = GetUnitFacing(caster) - bad way to catch the angle between the caster and the target point. It might bug sometimes because of facing nature. I recommend to use angle between coords formula (Atan2 one).
  • EVENT_PLAYER_UNIT_SPELL_CAST is a bad event. EVENT_PLAYER_UNIT_SPELL_EFFECT is better because it will trigger only when the spell is fully casted.
  • set dummy = CreateUnit(p,XE_DUMMY_UNITID,x,y,GetUnitFacing(caster)). Another stupid thing to do. You already have set f = GetUnitFacing(caster) and later you're calling the function again instead of placing a variable there.
  • JASS:
        unit caster
        unit dummy
        real ff
        real h
        real f
        real cos
        real sin
        player p
        xedamage xe
    Preinit them here when possible. That can solve some problems that can be.

Effects: 2.7/5. That's more similar to the effect spam, as for me. Effect spam never was good.

Overall: (3.5+4+2.7/3) = 3.4 = 3/5. That's what the spell can get. With better coding, the rating can be improved. Revising the spell's effects can improve the rating even more.

3/5: Useful

Spell Updated!

EVENT_PLAYER_UNIT_SPELL_CAST
I use this event for check terrain :)
 
Top