• 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.

Devil Black Hole v1.0

Spell Information
untit110.jpg


JASS:
//*******************************************************************
//******************D*E*V*I*L**B*L*A*C*K**H*O*L*E********************
//*****************Requires:
//                          - SimpleJumpSystem
//                          - UnitScale
//                          - xebasic - http://www.wc3c.net/showthread.php?t=101150
//                          - TimerUtils - http://www.wc3c.net/showthread.php?t=101322
//                          - DelDX - 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
//*****************Optional:                   
//                          - xebasic - http://www.wc3c.net/showthread.php?t=101150
//                          - SpellEffectEvent - http://www.hiveworkshop.com/forums/jass-resources-412/snippet-spelleffectevent-187193/                               
//**********Spell Create By:
//                          - Elphis
//********Spell Information:
//                          - Pull all enemies into devil black hole, enemies can go inside black hole but can't not run out of black hole
//                            and it call some black/fire missle slash to that enemies.
//                          - Level 1: Deals 4 damage/slash and hole will destroy when size = 4
//                          - Level 2: Deals 6 damage/slash and hole will destroy when size = 5
//                          - Level 3: Deals 8 damage/slash and hole will destroy when size = 6
//                          - Level 4: Deals 10 damage/slash and hole will destroy when size = 7
//*************Installation:
//                          - Import/copy the required libraries and Black Hole code to your map
//                          - Import/copy the custom ability and unit to your map and change the SPELL_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
//*******************************************************************
//*******************************************************************
//*******************************************************************
library DevilBlackHole uses SJS,UnitScale,AaD,TimerUtils,DelFX optional xebasic,SpellEffectEvent

    globals
        //============================CONFIGURABLES============================================================//
        //Missle slash count
        private             constant             integer            COUNT_BLACK_MISSLE           = 6
        //Rawcode of spell
        private             constant             integer            SPELL_ID                     = 'A000'
        //Time of every timer run
        private             constant             real               LOOP_TIMER                   = .05
        //Base limit size of Black hole
        private             constant             real               SIZE_EXPLORE                 = 3.
        //Area of Effect
        private             constant             real               AOE                          = 2000.
        //Range of Block unit pass through
        private             constant             real               BLOCK_UNIT_AOE               = 300.
        //Size of black hole increase every timer runing
        private             constant             real               SIZE_INCREASE                = .05
        //Pull speed
        private             constant             real               PULL_SPEED                   = 10.
        //Damage radius every missle slashed
        private             constant             real               DAMAGE_RADIUS                = 100.
        //Speed of missle slash
        private             constant             real               SPEED_AROUND                 = 15.
        //Base damage deals to enemy every missle slashed
        private             constant             real               BASE_DAMAGE                  = 2.
        //Explore all unit in AOE speed
        private             constant             real               SPEED_EXPLORE_AOE            = 50.
        //This value is optional of missle slash
        private             constant             real               SAFE_HOLE                    = 1.
        //Distance explore when black hole destroyed
        private             constant             real               EXPLORE_UNIT_AOE             = 600.
        //Hole destroying speed
        private             constant             real               HOLE_DESTROY                 = 15.
        //Black Hole model
        private             constant             string             HOLE                         = "BlackHOLE.mdl"
        //Effect of black hole combine
        private             constant             string             HOLE_EFFECT                  = "Abilities\\Spells\\Human\\FlameStrike\\FlameStrikeTarget.mdl"
        //Missle slash Model
        private             constant             string             BLACK_MISSLE                 = "Abilities\\Weapons\\AvengerMissile\\AvengerMissile.mdl"
        //Explore Effect
        private             constant             string             EXPLORE                      = "Abilities\\Spells\\Human\\Thunderclap\\ThunderClapCaster.mdl"
        //Fire effect when missle slash every time
        private             constant             string             EXPLORE_FIRE                 = "Abilities\\Spells\\Other\\Incinerate\\FireLordDeathExplode.mdl"
        //Attachment effect of dummy
        private             constant             string             ATTACHMENT                   = "chest"
        //Non - Configurables
        private                                  group              GROUP                        = CreateGroup()
        //============================CONFIGURABLES============================================================//
    endglobals
    //
    //==================================DO NOT EDIT ANYTHING BELOW=======================================================//
    private struct DevilBlackHole
        //
        unit caster
        unit dummy
        unit dumm
        real size
        real xx
        real yy
        real maxsize
        //
        static method onDamage takes unit u returns real
            return BASE_DAMAGE*GetUnitAbilityLevel(u,SPELL_ID) //Damage when slashed
        endmethod
        
        static method sizeLimit takes unit u returns real
            return SIZE_EXPLORE+I2R(GetUnitAbilityLevel(u,SPELL_ID)) // Size of Hole Limited
        endmethod
        
        static method filterUnit takes unit caster, unit u returns boolean
        return /*
        
        */ IsUnitEnemy(u, GetTriggerPlayer()) and /* Target is an enemy of caster
        */ not IsUnitType(u, UNIT_TYPE_DEAD) and GetUnitTypeId(u) != 0 and /* Target is alive
        */ not IsUnitType(u, UNIT_TYPE_STRUCTURE) /* Target is not a structure
        */
        endmethod
        
        static method onPeriodic takes nothing returns nothing
            local thistype this = GetTimerData(GetExpiredTimer())
            local unit f
            local real ang
            local real x
            local real y
            //
            call GroupEnumUnitsInRange(GROUP,xx,yy,AOE,null)
            loop
                set f = FirstOfGroup(GROUP)
                exitwhen f == null
                //
                if filterUnit(caster,f) and IsUnitInRange(caster,f,BLOCK_UNIT_AOE) != true then
                    set ang = Angle(GetUnitX(f),GetUnitY(f),xx,yy)
                    set x = GetUnitX(f) + PULL_SPEED * Cos(ang*0.01747)
                    set y = GetUnitY(f) + PULL_SPEED * Sin(ang*0.01747)
                    call SetUnitX(f,x)
                    call SetUnitY(f,y)
                endif
                //
                if filterUnit(caster,f) then
                    if size >= maxsize then
                        set ang = Angle(xx,yy,GetUnitX(f),GetUnitY(f))
                        set x = GetUnitX(f) + EXPLORE_UNIT_AOE * Cos(ang*0.01747)
                        set y = GetUnitY(f) + EXPLORE_UNIT_AOE * Sin(ang*0.01747)
                        call J.JumpTarget(f,x,y,SPEED_EXPLORE_AOE,EXPLORE,EXPLORE,false,false,0.)
                    endif
                endif
                //
                call GroupRemoveUnit(GROUP,f)
                //
            endloop
            //
            set size = size + SIZE_INCREASE
            call SetUnitScale(dummy,size,0,0)
            //
            if size >= maxsize then
                call ReleaseTimer(GetExpiredTimer())
                call USC.USCS(0.,dummy,maxsize*100,0.,HOLE_DESTROY,true,false,true,0.)
                call RemoveUnit(dumm)
                set dumm = null
                set dummy = null
                set caster = null
                call destroy()
            endif
            //
        endmethod
        
        static method onCast takes nothing returns nothing
            local thistype this = allocate()
            local integer i = COUNT_BLACK_MISSLE
            local unit d
            local real temp = -100
            local real x = GetSpellTargetX()
            local real y = GetSpellTargetY()
            local player p = GetTriggerPlayer()
            set caster = GetTriggerUnit()
            set dumm = CreateUnit(p,XE_DUMMY_UNITID,x,y,0.)
            set maxsize = sizeLimit(caster)
            loop
                exitwhen i == 0
                set temp = temp + 100.
                set d = CreateUnit(p,XE_DUMMY_UNITID,x,y,0.)
                call CreateDelayedEffectTarget(BLACK_MISSLE,d,ATTACHMENT,0.,maxsize)
                call Effect.Around(0.,dumm,d,temp,DAMAGE_RADIUS,-SPEED_AROUND,maxsize,true,true,onDamage(caster),EXPLORE_FIRE,0.1,"")
                set i = i - 1
            endloop
            //
            set dummy = CreateUnit(Player(15),XE_DUMMY_UNITID,x,y,0.)
            set xx = GetUnitX(dummy)
            set yy = GetUnitY(dummy)
            call CreateDelayedEffectTarget(HOLE,dummy,ATTACHMENT,0.,maxsize)
            call CreateDelayedEffectTarget(HOLE_EFFECT,dummy,ATTACHMENT,0.,maxsize)
            call SetUnitScale(dummy,0,0,0)
            set size = 0.
            set d = null
            //
            call TimerStart(NewTimerEx(this),LOOP_TIMER,true,function thistype.onPeriodic)
            //
        endmethod
        
        static method onInit takes nothing returns nothing
            call RegisterSpellEffectEvent(SPELL_ID,function thistype.onCast)
        endmethod
    endstruct
endlibrary
[/HIDDEN]

JASS:
//I Created xe dummy by Vexorian in your Object, Just create trigger and copy this in your trigger: //! runtextmacro RunXeUnit()
//! textmacro RunXeUnit
//! external ObjectMerger w3u ewsp xeca unam "xe unit" uhpm 1 uabi Aloc,Aeth, umdl "war3mapImported\dummy.mdx" uico "ReplaceableTextures\CommandButtons\BTNtemp.blp" usid 1 usin 1 unsf "(Caster System?)" uble 0.00 ucbs 0.00 umxp 0.00 umxr 0.00 uimz 0.00 ulpz 0.00 uprw 1.00 uspa "" udty Divine umvs 522 ucol 0.00 ufoo 0 uhom 1 umpi 1000 umpm 1000 umpr 1.00 urac Commoner utyp "" ubui "" upgr "" utub "http://wc3campaigns.net/vexorian-External By Elphis" utip ""
//! endtextmacro
//---------------------------------------------
//
//
//! zinc
//
//
//---------------------------------------------
//
library SJS requires TimerUtils,AaD
{
        constant                real                            time            =           .032;
        //
        public struct J
        {
            real Reach;
            real Fly;
            real Dis;
            real Angle;
            real sp;
            real ins;
            boolean kill;
            unit U;
            real High;
            real d;
            real Highsettings;
            real Timer;
            boolean B;
            boolean Ag;
            real ag;
            boolean Jumpag;
            boolean rem;
            string EfEnd;
//
    static method onLoop()
    {
        real x;
        real y;
        thistype this = GetTimerData(GetExpiredTimer());
        if(!IsUnitType(U, UNIT_TYPE_DEAD) && GetUnitTypeId(U) != 0)
        {
            if (Reach < Dis)
            {
                     x = GetUnitX(U) + sp * Cos(Angle * bj_DEGTORAD);
                     y = GetUnitY(U) + sp * Sin(Angle * bj_DEGTORAD);
                     SetUnitPosition(U,x,y);
                     Reach = Reach + sp;
                     Timer = Timer + 180/(Dis / sp);
                     Fly   = Sin(Timer*bj_DEGTORAD)*Highsettings*1.3;
                     SetUnitFlyHeight(U,Fly,0.);
            }
                else
                {
                     if(kill && !rem)
                        KillUnit(U);
                     if(!kill && rem && ins <= 0)
                        RemoveUnit(U);
                     if(!kill && rem && ins > 0)
                        Dum.Remove(U,ins);
                     DestroyEffect(AddSpecialEffect(EfEnd,GetUnitX(U),GetUnitY(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 && ins <= 0)
                        RemoveUnit(U);
                     if(!kill && rem && ins > 0)
                        Dum.Remove(U,ins);
                     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();
                }
    }
        static method JumpTarget(unit whatunit,real xj,real yj,real speed,string XJ,string EJ,boolean rems,boolean kills,real inss) 
        {
             thistype this;
             if(!IsUnitType(U, UNIT_TYPE_DEAD) && GetUnitTypeId(U) != 0)
             {
                 this = allocate();
                 U = whatunit;
                 Reach = 0.;
                 Timer = 0.;
                 ins = inss;
                 rem = rems;
                 kill = kills;
                 rem = rems;
                 sp = speed;
                 Fly = 0.;
                 EfEnd = EJ;
                 Dis = Distance(GetUnitX(whatunit),GetUnitY(whatunit),xj,yj);
                 Angle = Angle(GetUnitX(whatunit),GetUnitY(whatunit),xj,yj);
                 High = .35;
                 Highsettings = Dis*High;
                 DestroyEffect(AddSpecialEffect(XJ,GetUnitX(U),GetUnitY(U)));
                 SetUnitPathing(U,false);
                 UnitAddAbility(U,'Amrf');
                 UnitRemoveAbility(U,'Amrf');
                 TimerStart(NewTimerEx(this),time,true,function thistype.onLoop);
            }
        }
    }
}
//
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);
    }
}
//
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 UnitScale requires TimerUtils
{
    public struct USC
    {
        unit u;
        real s;
        real sta;
        real end;
        real time;
        boolean fade;
        boolean rem;
        boolean kill;
        real ins;
        //
        static method Loop()
        {
            thistype this = GetTimerData(GetExpiredTimer());    
            if(time > 0)
                time = time - .04;
            else
            {
                SetUnitScale(u,sta*0.01,sta*0.01,sta*0.01);
                if(fade)
                {
                    sta = sta - s;
                        if(sta <= end)
                        {
                            if(kill && !rem)
                                KillUnit(u);
                            if(!kill && rem && ins <= 0)
                                RemoveUnit(u);
                            if(!kill && rem && ins > 0)
                                Dum.Remove(u,ins);
                            ReleaseTimer(GetExpiredTimer());
                            u = null;
                            destroy();
                        }
                }
                else
                {
                    sta = sta + s;
                    if(sta > end)
                        {
                            if(kill && !rem)
                                KillUnit(u);
                            if(!kill && rem && ins <= 0)
                                RemoveUnit(u);
                            if(!kill && rem && ins > 0)
                                Dum.Remove(u,ins);
                            ReleaseTimer(GetExpiredTimer());
                            u = null;
                            destroy();
                        }
                }
            }
        }
        //
        static method USCS(real waits,unit us,real stas,real ends,real ss,boolean fades,boolean kills,boolean rems,real inss)
        {
            thistype this;
            //fade <=> true = >
            //fade <=> false = <     
            if(fades)
            {
                if(stas > ends)
                {
                    this = allocate();
                    u = us;
                    time = waits;
                    sta = stas;
                    kill = kills;
                    ins = inss;
                    end = ends;
                    fade = fades;
                    s = ss;
                    rem = rems;
                    TimerStart(NewTimerEx(this),.04,true,function thistype.Loop);
                }
                else
                    BJDebugMsg("Start value must > end value");
            }
            else
                if(stas < ends)
                {
                    this = allocate();
                    u = us;
                    time = waits;
                    sta = stas;
                    kill = kills;
                    ins = inss;
                    end = ends;
                    fade = fades;
                    s = ss;
                    rem = rems;
                    TimerStart(NewTimerEx(this),.04,true,function thistype.Loop);
                }
                else
                    BJDebugMsg("Start value must < end value");
        }
    }
}
//
library SpecialEffect requires TimerUtils,DummRemove,xedamage
{
    public struct Effect
    {
        unit u;
        unit tg;
        string ef;
        real dura;
        effect E;
        real a;
        real Area;
        real Dl;
        real run;
        string w;
        real wai;
        real dma;
        boolean RM;
        boolean dmg;
        real within;
        real sp;
        string whentaken;
        xedamage dam;
        //
        static method ArLoop()
        {
            thistype this = GetTimerData(GetExpiredTimer());
            real x;
            real y;
            group g;
            unit f;
            if(!IsUnitType(u, UNIT_TYPE_DEAD) && !IsUnitType(tg, UNIT_TYPE_DEAD) && GetUnitTypeId(u) != 0 && GetUnitTypeId(tg) != 0)
            {
                if(wai > 0)
                    wai = wai - .03250000;
                else
                {
                    a = a + sp;
                    x = GetUnitX(u) + Area * Cos(a*bj_DEGTORAD);
                    y = GetUnitY(u) + Area * Sin(a*bj_DEGTORAD);
                    SetUnitX(tg,x);
                    SetUnitY(tg,y);
                    if(run < Dl)
                        run = run + .032500000;
                    else
                    {
                        run = 0.;
                        DestroyEffect(AddSpecialEffect(ef,GetUnitX(tg),GetUnitY(tg)));
                    }
                    if(dmg)
                        {
                            dam.useSpecialEffect(whentaken,"chest");
                            dam.damageAOE(u,x,y,within,dma);
                        }
                    if(dura > 0)
                        dura = dura - .03250000;
                    if(dura <= 0 || GetWidgetLife(tg) < 0.425 || GetWidgetLife(u) < 0.425)
                    {
                        if(RM)
                            RemoveUnit(tg);
                        ReleaseTimer(GetExpiredTimer());
                        u = null;
                        tg = null;
                        destroy();
                    }
                }
            }
            else
            {
                if(RM)
                    RemoveUnit(tg);
                ReleaseTimer(GetExpiredTimer());
                u = null;
                tg = null;
                destroy();
            }
        }
        //
        static method Around(real wait,unit aro,unit tgs,real AOE,real withinn,real speed,real dur,boolean rms,boolean DMGs,real dmgg,string effe,real Delay,string effwhentaken) 
        {
            thistype this;
            if(!IsUnitType(tgs, UNIT_TYPE_DEAD) && !IsUnitType(aro, UNIT_TYPE_DEAD) && GetUnitTypeId(tgs) != 0 && GetUnitTypeId(aro) != 0)
            {
                this = allocate();
                u = aro;
                whentaken = effwhentaken;
                tg = tgs;
                wai = wait;
                dura = dur;
                ef = effe;
                dma = dmgg;
                within = withinn;
                dmg = DMGs;
                a = 0.;
                run = 0.;
                Dl = Delay;
                RM = rms;
                sp = speed;
                Area = AOE;
                dam = xedamage.create();   
                dam.dtype = DAMAGE_TYPE_FIRE;
                dam.atype = ATTACK_TYPE_NORMAL;
                dam.damageEnemies = true;
                dam.damageTrees   = false;
                TimerStart(NewTimerEx(this),.0325000,true,function thistype.ArLoop);
            }
            
        }
    }
}
//! endzinc

[/HIDDEN]

Keywords:
hole,black,devil
Contents

Just another Warcraft III map (Map)

Reviews
23:35, 7th Aug 2013 PurgeandFire: Approved and recommended! Very pretty, eye-catching spell.

Moderator

M

Moderator

23:35, 7th Aug 2013
PurgeandFire: Approved and recommended! Very pretty, eye-catching spell.
 
I think GroupUtils is useless.

In the On Cast function, cache first GetSpellAbilityUnit() then use it in the parameters of the functions that use it, because currently, you are calling it 3 times :(

Make the attachment for the effect configurable.

Use Dummy by Nes perhaps?

When naming constants, make sure to put "_" in between words. Do SIZEINCREASE and COUNTBLACKMISSILES and more look readable?

call SetUnitScale(dummy,size,size,size) - > call SetUnitScale(dummy, size, 0, 0)

You can remove the "BlackHole" in the struct methods
 
Level 16
Joined
Dec 15, 2011
Messages
1,423
Here is another review from yours truly but with something entirely different.... now it has a template :D

REVIEW
rating_none.gif


Resource Status: Needs Fix
GENERAL
  • Links to required libraries are missing.
  • Credit is missing in the description.
PROS
  • The effect is splendid. Good job.
  • Global block is lined up beautifully.
  • Configuration is decent.
  • You are using a struct <3
  • The code seems to be well-executed with the use of helper libraries.
CONS
  • There should be a filter function for users to configure. It is something alone this line
    JASS:
        // Filter targets
        private function filterUnit takes unit caster, unit u returns boolean
            return /*
            
            */ IsUnitEnemy(u, GetOwningPlayer(caster)) and /* Target is an enemy of caster
            */ not IsUnitType(u, UNIT_TYPE_DEAD) and /* Target is alive
            */ not IsUnitType(u, UNIT_TYPE_STRUCTURE) /* Target is not a structure
            */
        endfunction
  • The library requires GroupUtils, TimerUtils and SpellEffectEvent. You can make GroupUtils optional though.
  • You are missing importing instructions.
  • USER EDIT should be CONFIGURABLES. Sorry for being OCD though ;__;
  • Global block is not indented correctly. Please reread my review for your other resource on how to indent properly.
  • All methods should be private. And they are namedLikeThis, not NamedLikeThis. Check out the JPAG page.
  • Cast and Loop should be onCast and onPeriodic. It is more or less a convention here to name methods like that.
  • dumm is a bit weird for a variable name. Use dummy2 or something.
  • There should be 2 or more heroes for MUI testing.
[/TD][/tr]
That is all I can see for now. Feel free to speak up if you feel like I misread your code somewhere :)
 
Last edited:
Top