1. Are you planning to upload your awesome spell or system to Hive? Please review the rules here.
    Dismiss Notice
  2. Updated Resource Submission Rules: All model & skin resource submissions must now include an in-game screenshot. This is to help speed up the moderation process and to show how the model and/or texture looks like from the in-game camera.
    Dismiss Notice
  3. DID YOU KNOW - That you can unlock new rank icons by posting on the forums or winning contests? Click here to customize your rank or read our User Rank Policy to see a list of ranks that you can unlock. Have you won a contest and still havn't received your rank award? Then please contact the administration.
    Dismiss Notice
  4. Travel to distant realms and encounter scenes unknown to the common folk. The Greatest of Adventures is upon us with the 8th Cinematic Contest. Join in on a fun ride.
    Dismiss Notice
  5. The 18th Icon Contest is ON! Choose any ingame unit and give him/her Hero abilities. Good luck to all.
    Dismiss Notice
  6. The Secrets of Warcraft 3 have revealed interesting works. The RESULTS for Abelhawk's Mini-Mapping Contest #15 have come out!
    Dismiss Notice
  7. Contestants are to create a scene set in the Stone Age. Come and see what you can come up with. We wish you the best of luck!
    Dismiss Notice
  8. Colour outside the lines! Techtree Contest #13 is a go. The contest is optionally paired.
    Dismiss Notice
  9. Night Rider gained several songs for his journey. The poll for the 12th Music Contest has started. Check it out!
    Dismiss Notice
  10. Greetings cerebrates, our Swarm needs new spawners that will have numerous children. Join the HIVE's 31st Modeling Contest - Spawners and Spawned! The contest is optionally paired.
    Dismiss Notice
  11. Check out the Staff job openings thread.
    Dismiss Notice
Dismiss Notice
60,000 passwords have been reset on July 8, 2019. If you cannot login, read this.

Spell - Shimmering Portal v4.2

Submitted by Dark_Dragon
This bundle is marked as approved. It works and satisfies the submission rules.

Description

Converted 'Shimmering Portal' from Frozen Throne campaign.

Teleports any unit that pass through the portal to targeted portals location.



System

Creates an portal near caster and one at targeted point! channels until portal is created.
If caster moves (stops channeling the spell) portals will be destroyed. First portal faces angle between caster and target point, while second portal faces approximately angle of caster upon casting



Spell is recoded in Warcraft 3 v1.30 and does not require JNGP!


Additional Info:

To install spell go to trigger editor and read coments at the top code of the spell on how to install it to your map.

However spell is editable through globals just at beginning of the code (comments expalin what you need to do and how to make an specific change in spell)


If you need any future help feel free to comment here:


Changelog

Version 1.0 - Release

Version 1.1 - Now portal sides have a visibility trigger action which expires when portals close and event is changed to spell effect ability not begins casing... that fixes some bugs.

Version 2.0 - Mass update to my spell! Spell is MUI, most GUI, has custom script, header code + GUI triggers, i as well added readme for this who are completely new to Warcraft can install this spell in there map... well ofc you need to know english. Spell does not leak event filters or any other game objects!

Version 3.0 - Final update spell is fully recoded in vJass. Fixed 'Handle Stack Corruption' this was the only my spell remaining effected by that corruption...
And well since its in vjass its faster, MUI (any amount of portals at same time is allowed), does not cause/create memory leaks and is compatible with any version of warcraft since user can change that in users setup part!

Version 3.0b - Additional update to 3.0!
* Fixed bug with timed life starting at time when you start channeling portal insted of starting once portal is summoned.
* Made portal (unit more like dummy portal should be)
* Added 2 triggers insted of one (users now pick which trigger they want, insted of having hard time removing/adding //! novjass preprocessors)
* Added script externals, which will install my spell through jass code in your map (once you save your map) so no need for rawcodes and copy and pasting abilities...
* Minor script change

Version 4.0 - Shimmering Portal Remasterd
* Totally recoded in zinc
* Now is MUI
* Has a lot of extra details when units are teleported, camera pan, selection...
* Now has extra features for spell leveling up (cooldown, mana cost, portal duration, transition time and n units to be ported)
* Now uses recycle engine and my new mini library
* Was one of hardest spells to make

Version 4.1
* Fixed bug where map fails to compile because of lua script.

Version 4.2
* Added some hints and explanations on how portals work
* Compiled in Warcraft 3 v1.30, no longer requires JNGP








Code

DD Library
Code (vJASS):

//==========================================================================
//                  Dark Dragon Library Code v1.3
//
//      * Made on Warcraft III v1.30.4
//
//  Installation:
//                  
//                  1) Export instantdummy.mdx from this map and import it to your map, leave path at "war3mapImported/instantdummy.mdx"
//                  2) Copy this trigger to your map, save your map and then change below line "// external ... " or copy "DD Dummy" and paste it in your map
//     3) Copy and paste "Unit Chill" ability from this map to your map
//     4) Match the rawcodes below to your map or use same ones as below
//
// Credits:
//          ('Vexorian' - dummy.mdx)
//============================================================================

// *** Change "// external" to "//! external", save your map, close map, change back from "//!" to "//" and save map again.
// *** This will create dummy in your map
//
// ==================================
// external ObjectMerger w3u ushd dumy uabi "Aloc,Amrf" uble 0 ucbs 0 ucpt 0 umxp 0 umxr 0 umdl "war3mapImported\instantdummy.mdx" ushu "None" umvh 0 umvs 1 umas 1 umis 1 ucol 0 ufoo 0 uhom 1 umpi 10000 umpm 10000 usid 1 usin 1 unam "DD Dummy"
// ==================================


//! zinc

library DDLib requires optional TimerUtils, optional GroupUtils
{
   
    // -----------------------------------------------------------------------
    // -----------------------------------------------------------------------
    // *** Lib constants ***
    public {
       
  // ----------------------------------------------------------------------
  // * Start modify/match rawcodes to your map
        constant        integer     DD_DUMMYCODE       = 'dumy';
        constant        integer     DD_ABILITY_CROWN_FORM     = 'Amrf';
  constant   integer  DD_CHILL     = 'Achl';
  constant   integer  DD_CHILL_BUFF    = 'Bfro';
  // * End modify
  // ----------------------------------------------------------------------
 
 
  constant        integer     p_null             = (0x0);
        constant        real        DD_INTERVAL       = .017;
       
                        // map min and max coords
                        real        DDMinX             = 0.;
                        real        DDMinY             = 0.;
                        real        DDMaxX             = 0.;
                        real        DDMaxY             = 0.;
    }
 
 private {
  constant   integer  HARVEST_ID     = 'Ahrl';
  constant  real  TRIGGER_REFRESH_RATE  = (60.)*3.; /// damage detection trigger
                       
                        unit   TreeChecker              = null;
      trigger  TempTrig      = null;
      integer  NTrig       = 0;
      trigger  DmgTrig[];
      p_real   EnumVec      = p_null;
      boolexpr  EnumFilter      = null;
      sound  ErrorSound     = null;
      timer  GameElapsedTimer   = null;
  constant   integer  RND_INT_MAX_ARRAY_N   = 100;
      integer  RndInt[], RndIntWriteN = 00, RndIntReadN = 00;
      trigger  TrigMouseEvent     = null;
      force   RndGenForce     = null;
      real   RndElapsedTime     = 0.;
 }
    // -----------------------------------------------------------------------
    // -----------------------------------------------------------------------
    // -----------------------------------------------------------------------
   
    // * types
    public {
       
        // *** pointer to list of data ***
        type    p_integer           extends     integer[8];
        type    p_real              extends     real[8];
        type    p_unit              extends     unit[8];
       
  function H2ID(handle h) -> integer {
   return GetHandleId(h) - 0x100000;
  }
 
        function New_pInteger(integer i) -> p_integer
        { p_integer p = p_integer.create(); p[0] = i; return p; }
        function New_pReal(real r) -> p_real
  { p_real p = p_real.create(); p[0] = r; return p; }
        function New_pUnit(unit u) -> p_unit
  { p_unit p = p_unit.create(); p[0] = u; return p; }
       
  function pVector(real x, real y, real z) -> p_real {
   p_real v = p_real.create();
   v[0] = x; v[1] = y; v[2] = z;
   return v;
  }
 
  // --------------------------------------------------------------------------------------
 
  function DDMsg(string str) {
   DisplayTimedTextFromPlayer(GetLocalPlayer(), 0., 0., 30., str);
  }
 
  // --------------------------------------------------------------------------------------
 
  function DisplayErrorMsgPlayer(player p, real dur, string msg) {
   if (GetLocalPlayer() == p) {
    StartSound(ErrorSound);
    DisplayTimedTextFromPlayer(p, 0., 0., dur, "|cffffcc00"+ msg +"|r");
   }
  }

    }
   
    // -----------------------------------------------------------------------
    // ->           ***** private globals *****
    // -----------------------------------------------------------------------
    private {
        location    TempLoc         = Location(0., 0.);
        timer       TimerStack[];
        integer     TimN            = 0;
        group       GroupStack[];
        integer     GrpN            = 0;
        unit        DummyStack[];
        integer     DumN            = 0;
  integer  TimTicks[];
  integer  TimData[];
  timer  TimTim1[];
  timer  TimTim2[];
 
 
  integer  UnitStackData = 0;
  unit  UnitStack[];
  integer  US_N   = 0;
       
        public hashtable   DDHT            = InitHashtable();
    }
    // -----------------------------------------------------------------------
   
   public {
   
        // *** Global funcs
       
        function Pw_2(real x) -> real {
            return x*x;
        }
 
  function DDHypot(real x, real y) -> real {
   return (x*x) + (y*y);
  }
       
        function DDTerrZ(real x, real y) -> real {
            MoveLocation(TempLoc, x, y);
            return GetLocationZ(TempLoc);
        }
       
        function DDWidgetTerrZ(widget w) -> real {
   MoveLocation(TempLoc, GetWidgetX(w), GetWidgetY(w));
            return GetLocationZ(TempLoc);
        }
 
  function DDEffectTerrZ(effect e) -> real {
   MoveLocation(TempLoc, BlzGetLocalSpecialEffectX(e), BlzGetLocalSpecialEffectY(e));
            return GetLocationZ(TempLoc);
  }
 
  function DDGetUnitZ(unit u) -> real {
   return BlzGetUnitZ(u) + GetUnitFlyHeight(u);
  }
       
        // =================================================================
        //              *** Save Handle data ****
        // =================================================================
       
        function DDSet(handle h, integer id, integer val) {
            SaveInteger(DDHT, id+1, GetHandleId(h), val);
        }
       
        function DDGet(handle h, integer id) -> integer {
            return LoadInteger(DDHT, id+1, GetHandleId(h));
        }
 
  function DDHas(handle h, integer id) -> boolean {
   return HaveSavedInteger(DDHT, id+1, GetHandleId(h));
  }
 
  function DDFlush(integer id) {
   FlushChildHashtable(DDHT, id+1);
  }
       
        // =================================================================
        //              *** Timer Handling ****
        // =================================================================
 
  // -> check if timer is recycled
  function DDIsTimRecycled(timer t) -> boolean {
   integer i;
   for(i=TimN-01; i >= 00; i-=01)
    if (TimerStack[i] == t)
     return true;
   return false;
  }
 
        // -> Load timer for recycling
        function DDLoadTim() -> timer {
            static if (LIBRARY_TimerUtils) { return NewTimer(); }
            else {
                if (TimN > 0) {
                    TimN -= 1;
                    return TimerStack[TimN];
                }
                return CreateTimer();
            }
        }
       
        // -> recycle loaded timer
        function DDRecycleTim(timer t) {
            static if (LIBRARY_TimerUtils) { ReleaseTimer(t); }
            else {
    static if (DEBUG_MODE)
     if (DDIsTimRecycled(t)) {
      DDMsg("Multiple recycle of timer!");
      return;
     }
                TimerStack[TimN] = t;
                TimN += 1;
            }
        }
       
        // ** Get data stored on expired timer
        function DDTimData() -> integer {
            return TimData[H2ID(GetExpiredTimer())];
        }
 
  // *** Custom timer tick
        function DDCTimTick(timer t) -> integer {
            return TimTicks[H2ID(t)];
        }
 
  // *** Gets current tick and adds next one ***
        function DDTimTick() -> integer {
   integer id = H2ID(GetExpiredTimer());
   TimTicks[id] += 01;
            return TimTicks[id];
        }
       
        // ** start timer with data storage
        function DDStartTim(real secs, boolean looping, integer pdata, code func) -> timer {
            timer t = DDLoadTim();
   
   TimData[H2ID(t)] = pdata;
            TimerStart(t, secs, looping, func);
            return t;
        }
       
        // ** start timer with data storage, and launches it instantly
        function DDStartTimInst(real secs, boolean looping, integer pdata, code func) -> timer {
            timer t1 = DDLoadTim(), t2 = DDLoadTim(), t3 = DDLoadTim();
           
   TimData[H2ID(t2)] = pdata;
            TimerStart(t2, 0., false, func);
   
   TimTim1[H2ID(t3)] = t1;
   TimTim2[H2ID(t3)] = t2;
   TimerStart(t3, .005, false, function() {
    timer t = GetExpiredTimer();
    integer id = H2ID(t);
   
    PauseTimer(t);
    static if (LIBRARY_TimerUtils)
     ReleaseTimer(t);
    else {
     TimerStack[TimN] = t;
     TimN += 1;
    }
   
    t = TimTim2[id];
    if (DDIsTimRecycled(t))
     t = TimTim1[id];
    TimTicks[H2ID(t)] = 00;
    PauseTimer(t);
    static if (LIBRARY_TimerUtils)
     ReleaseTimer(t);
    else {
     TimerStack[TimN] = t;
     TimN += 1;
    }
   });
   
   TimData[H2ID(t1)] = pdata;
            TimerStart(t1, secs, looping, func);
           
            return t1;
        }
       
        // *** Quit expired timer ***
        function DDQuitTim() {
   timer t = GetExpiredTimer();
   TimTicks[H2ID(t)] = 00;
            PauseTimer(t);
   static if (LIBRARY_TimerUtils)
    ReleaseTimer(t);
            else {
                TimerStack[TimN] = t;
                TimN += 1;
            }
        }
 
  function DDQuitTimEx(timer t) {
   TimTicks[H2ID(t)] = 00;
            PauseTimer(t);
   static if (LIBRARY_TimerUtils)
    ReleaseTimer(t);
            else {
                TimerStack[TimN] = t;
                TimN += 1;
            }
        }
       
        // =================================================================
        //              *** Group Handling ****
        // =================================================================
       
        // -> Load timer for recycling
        function DDLoadGroup() -> group {
            static if (LIBRARY_GroupUtils) { return NewGroup(); }
            else {
                if (GrpN > 0) {
                    GrpN -= 1;
                    return GroupStack[GrpN];
                }
                return CreateGroup();
            }
        }
       
        // -> Recycle group
        function DDRecycleGroup(group g) {
            static if (LIBRARY_GroupUtils) { ReleaseGroup(g); }
            else {
    GroupClear(g);
                GroupStack[GrpN] = g;
                GrpN += 1;
            }
        }
       
        // --------------------------------------------------------
        // -- Quick filter area
  private integer GroupFilterData = 00;
 
        function DDGroupFilterArea(real x, real y, real radius, integer data, code func) {
            group g = DDLoadGroup();
   GroupFilterData = data;
            GroupEnumUnitsInRange(g, x, y, radius, Filter(func));
            DDRecycleGroup(g);
        }
       
        // --------------------------------------------------------
        // -- Quick filter rect
        function DDGroupFilterRect(rect r, integer data, code func) {
            group g = DDLoadGroup();
   GroupFilterData = data;
            GroupEnumUnitsInRect(g, r, Filter(func));
            DDRecycleGroup(g);
        }
       
  function DDGFilterData() -> integer {
   return GroupFilterData;
  }
 
  function DDGFilterDataSet(integer data) {
   GroupFilterData = data;
  }
 
  // --------------------------------------------------------
        // *** Filtrates and fills units in to memory
        function DDGroupFillMemArea(real x, real y, real radius, integer data, code filter) {
   group g = DDLoadGroup();
   boolexpr exp = And(Filter(filter), Filter(function() -> boolean {
    UnitStack[US_N] = GetFilterUnit();
    US_N += 1;
    return false;
   }));
   US_N = 0;
   UnitStack[0] = null;
   UnitStackData = data;
   GroupEnumUnitsInRange(g, x, y, radius, exp);
   DDRecycleGroup(g);
   DestroyBoolExpr(exp);
   exp = null;
  }
 
  function DDGroupFillMemRect(rect r, integer data, code filter) {
   group g = DDLoadGroup();
   boolexpr exp = And(Filter(filter), Filter(function() -> boolean {
    UnitStack[US_N] = GetFilterUnit();
    US_N += 1;
    return false;
   }));
   US_N = 0;
   UnitStack[0] = null;
   UnitStackData = data;
   GroupEnumUnitsInRect(g, r, exp);
   DDRecycleGroup(g);
   DestroyBoolExpr(exp);
   exp = null;
  }
 
  function DDMemUnitN() -> integer { return US_N; }
  function DDMemUnitData() -> integer { return UnitStackData; }
 
  function DDMemUnit(integer index) -> unit {
   if (US_N == 0) return null;
   debug {
    if (index < 0) {
     BJDebugMsg("DDMemUnit: index less than 0");
     index = 0;
    } else if (index >= US_N) {
     BJDebugMsg("DDMemUnit: index greater than units alloc size");
     index = 0;
    }
   }
   return UnitStack[index];
  }
  // --------------------------------------------------------
 
  // --------------------------------------------------------
  // ***
       
        // =================================================================
        //              *** Dummy Handling ****
        // =================================================================
       
        // -> Load dummy for recycling
        function DDLoadDummy() -> unit {
            if (DumN > 0) {
                DumN -= 1;
                PauseUnit(DummyStack[DumN], false);
                return DummyStack[DumN];
            }
            return CreateUnit(Player(0xF), DD_DUMMYCODE, DDMaxX, DDMaxY, 0.);
        }
       
        // *** prepares/setups dummy for spell casting
        function DDLoadSpellDummy(player owner, real x, real y, integer abil, integer abilLevel) -> unit {
            unit dummy = DDLoadDummy();
            SetUnitOwner(dummy, owner, false);
            SetUnitX(dummy, x);
            SetUnitY(dummy, y);
            if (abil != p_null) {
                UnitAddAbility(dummy, abil);
                SetUnitAbilityLevel(dummy, abil, abilLevel);
            }
            return dummy;
        }
       
        // -> Recycle dummy
        function DDRecycleDummy(unit u) {
            PauseUnit(u, true);
            DummyStack[DumN] = u;
            DumN += 1;
        }
       
        // -> Recycle dummy timed
        function DDRecycleDummyTimed(unit u, real secs) {
            DDStartTim(secs, false, New_pUnit(u), function() {
                DDRecycleDummy(p_unit(DDTimData())[0]);
                p_unit(DDTimData()).destroy();
                DDQuitTim();
            });
        }
       
        // *** shares vision for timed amount, usually for dummy casting
        function DDUnitShareVisionTimed(unit u, player toP, real secs) {
            p_integer pi = p_integer.create();
           
            pi[0] = New_pUnit(u);
            pi[1] = GetPlayerId(toP);
            UnitShareVision(u, toP, true);
            DDStartTim(secs, false, pi, function() {
                p_integer pi = DDTimData();
               
                UnitShareVision(p_unit(pi[0])[0], Player(pi[1]), false);
                p_unit(pi[0])[0] = null;
                p_unit(pi[0]).destroy();
                pi.destroy();
                DDQuitTim();
            });
           
        }
 
        // *** Remove ability timed ***
        private struct uratimed {
            private {
                unit u;
                integer abil;
            }
           
            static method create(unit whichUnit, integer id, real time) -> uratimed {
                thistype this = allocate();
               
                u = whichUnit;
                abil = id;
                DDStartTim(time, false, this, function() {
                    thistype this = DDTimData();
                    UnitRemoveAbility(u, abil);
                    DDQuitTim();
                    deallocate();
                });
               
                return 0;
            }
        }
        function DDRemoveAbilityTimed(unit u, integer abil, real secs) { uratimed.create(u, abil, secs); }
       
  function DDSpellDamage(unit u, unit v, real dmg) {
   real life = GetWidgetLife(v);
   real dmgfactor = 1.;
   
   if (IsUnitType(v, UNIT_TYPE_HERO)) {
    if (UnitHasItemOfTypeBJ(v, 'brac'))
     dmgfactor = .5;
    else
     dmgfactor = .75;
   }
   
   if (life > dmg*dmgfactor) {
    SetWidgetLife(v, life-(dmg*dmgfactor));
   } else
    UnitDamageTarget(u, v, 99999., false, true, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_NORMAL, WEAPON_TYPE_WHOKNOWS);
  }
 
  // -------------------------------------------------------------------------------------
  // *** Chills target unit
  private struct chill {
   unit u, dmy;
   real dur;
   
   static chill Data[];
   //static key CHILL_KEY;
  }
 
  function DDUnitChill(player p, unit u, real dur) -> boolean {
   //chill c = DDGet(u, chill.CHILL_KEY);
   chill c = chill.Data[H2ID(u)];
   unit d;
   real rad;
   
   
   if (c == p_null) {
    c = chill.create();
    c.u = u; c.dur = dur;
    chill.Data[H2ID(u)] = c;
    //DDSet(u, chill.CHILL_KEY, c);
   
    d = DDLoadDummy();
    c.dmy = d;
    rad = GetUnitFacing(d) * bj_DEGTORAD;
    SetUnitOwner(d, p, false);
    UnitAddAbility(d, DD_CHILL);
    SetUnitX(d, GetUnitX(u) - 20.*Cos(rad));
    SetUnitY(d, GetUnitY(u) - 20.*Sin(rad));
   
    if (IssueTargetOrder(d, "frostnova", u)) {
     DDStartTim(.1, true, c, function() {
      chill c = DDTimData();
     
      c.dur -= .1;
      if (c.dur <= 0. || GetUnitAbilityLevel(c.u, DD_CHILL_BUFF) == 00) {
       UnitRemoveAbility(c.u, DD_CHILL_BUFF);
       UnitRemoveAbility(c.dmy, DD_CHILL);
       DDRecycleDummy(c.dmy);
       chill.Data[H2ID(c.u)] = p_null;
       //DDSet(c.u, chill.CHILL_KEY, p_null);
       c.u = null;
       c.destroy();
       DDQuitTim();
      }
     });
     return true;
    }
   
    return false;
   }
   
   c.dur = dur;
   
   return true;
  }
 
  // ------------------------------------------------------------------------------------------------
 
  struct fade {
   unit u;
   real trans;
   real rate, e_trans, dur;
   
   static constant real INTERVAL = .1;
   
   static method create(unit u, real dur, real s_trans, real e_trans) -> fade {
    fade this = allocate();
   
    this.u = u;
    this.trans = s_trans;
    this.rate = ((e_trans-s_trans)/dur)*fade.INTERVAL;
    this.e_trans = e_trans;
    this.dur = dur;
   
    return this;
   }
  }
 
  // *** Fades unit over time ***
  public function DDFadeUnit(unit u, integer from_alpha, integer to_alpha, real duration) {
   fade f = fade.create(u,
         duration,
         from_alpha/2.55,
         to_alpha/2.55);
   
   SetUnitVertexColor(u, 255, 255, 255, from_alpha);
   // --- Start thread ---
   DDStartTim(fade.INTERVAL, true, f, function() {
    fade f = DDTimData();
   
    f.trans += f.rate;
    f.dur -= fade.INTERVAL;
    SetUnitVertexColor(f.u, 255, 255, 255, R2I(f.trans*2.55));
   
    if (f.dur < 0.) {
     SetUnitVertexColor(f.u, 255, 255, 255, R2I(f.e_trans*2.55));
     f.u = null;
     f.destroy();
     DDQuitTim();
    }
   });
       
  }
 
  // ------------------------------------------------------------------------------------------------
 
        // Check if unit is invulnerable
        function DDIsUnitInvulnerable(unit u) -> boolean {
            unit d = DDLoadDummy();
            real hp = GetWidgetLife(u);
            boolean flag;
           
            UnitDamageTarget(d, u, 1., true, false, null, null, null);
            flag = GetWidgetLife(u) == hp;
            SetWidgetLife(u, hp);
            DDRecycleDummy(d);
           
            return flag;
        }
       
        // *** check if unit is ward
        function DDIsUnitWard(unit whichUnit) -> boolean {
            return GetUnitDefaultMoveSpeed(whichUnit) == 0.;
        }
 
        // =================================================================
        //              *** Effect Handling ****
        // =================================================================
       
        // -----------------------------------------------
        // *** Define movable effect
        struct ddeffect {
            private {
                effect e;
                real fac; // facing angle in radians
                real effZ; // pitch in radians
                real decay;
    real stepTrans, cTrans, eTrans;
               
                static constant real        EFFECT_DECAY        = 5.;
            }
           
            // =========================================================================================
            // =========================================================================================
            static method create(string mdl, real x, real y, real facRad, real size) -> ddeffect {
                ddeffect this = allocate();
               
                this.e   = AddSpecialEffect(mdl, x, y);
    this.fac  = facRad;
    this.effZ = 0.;
                BlzSetSpecialEffectRoll(this.e, facRad);
    BlzSetSpecialEffectScale(this.e, size);
               
                return this;
            }
   
   static method createZ(string mdl, real x, real y, real z, real facRad, real size) -> ddeffect {
                ddeffect this = allocate();
               
                this.e   = AddSpecialEffect(mdl, x, y);
    this.fac  = facRad;
    this.effZ = z-DDTerrZ(x, y);
                BlzSetSpecialEffectRoll(this.e, facRad);
    BlzSetSpecialEffectScale(this.e, size);
    BlzSetSpecialEffectZ(this.e, z);
               
                return this;
            }
           
            // -----------------
            method destroy() {
                DestroyEffect(this.e);
                this.e = null;
                deallocate();
            }
           
            // *** destroys effect timed
            method destroyx(real decayTime) {
                DDStartTim(decayTime, false, this, function() {
     ddeffect se = DDTimData();
     BlzSetSpecialEffectPosition(se.e, DDMaxX, DDMaxY, 0.);
                    DestroyEffect(se.e);
     se.e = null;
     se.deallocate();
                    DDQuitTim();
                });
            }
            // =========================================================================================
            // =========================================================================================
           
   
           
   method operator Z=(real z)     { BlzSetSpecialEffectZ(this.e, z); }
   
            method operator X() -> real                 { return BlzGetLocalSpecialEffectX(this.e); }
            method operator Y() -> real                 { return BlzGetLocalSpecialEffectY(this.e); }
            method operator Z() -> real                 { return BlzGetLocalSpecialEffectZ(this.e); }
            method operator WZ() -> real                { return DDEffectTerrZ(this.e); }
            method operator Height() -> real            { return this.Z-this.WZ; }
           
            method operator Facing=(real facRad)        { BlzSetSpecialEffectRoll(this.e, facRad); this.fac = facRad; }
            method operator Facing() -> real            { return this.fac; }
   
   method Position(real x, real y)    { BlzSetSpecialEffectPosition(this.e, x, y, this.effZ+this.WZ); }
   method PositionZ(real x, real y, real z) { BlzSetSpecialEffectPosition(this.e, x, y, z); }
   method Animation(animtype at)    { BlzPlaySpecialEffect(this.e, at); }
   method AnimationSpeed(real animSpeed)  { BlzSetSpecialEffectTimeScale(this.e, animSpeed/100.); }
   
   //method operator Pitch=(integer pitch)  { SetUnitAnimationByIndex(u, pitch); }
           
            //method Face(widget w) { Facing = Atan2(GetWidgetY(w)-Y, GetWidgetX(w)-X)*bj_RADTODEG; }
   
   method Fade(real startTransparency, real endTransparency, real duration) {
    this.cTrans = startTransparency;
    this.eTrans = endTransparency;
    this.stepTrans = .1*(endTransparency-startTransparency) / duration;
   
    BlzSetSpecialEffectAlpha(this.e, R2I(startTransparency*2.55));
   
    DDStartTim(.1, true, this, function() {
     ddeffect dde = DDTimData();
     
     dde.cTrans += dde.stepTrans;
     if (dde.stepTrans > 0.)
      if (dde.cTrans >= dde.eTrans) {
       BlzSetSpecialEffectAlpha(dde.e, R2I(dde.eTrans*2.55));
       DDQuitTim();
       return;
      }
     else
      if (dde.cTrans <= dde.eTrans) {
       BlzSetSpecialEffectAlpha(dde.e, R2I(dde.eTrans*2.55));
       DDQuitTim();
       return;
      }
     BlzSetSpecialEffectAlpha(dde.e, R2I(dde.cTrans*2.55));
    });
   }
   
        }
       
  private type timedeffect extends effect[01];
 
  function DDDestroyEffectTimed(effect e, real secs) {
   timedeffect te = timedeffect.create();
   te[00] = e;
   DDStartTim(secs, true, te, function() {
    timedeffect te = DDTimData();
    DestroyEffect(te[00]);
    te.destroy();
    DDQuitTim();
   });
  }
    }
 
 // ----------------------------------------------------------------------------
    // *** Main damage detection function, registers any damage dealt to units ***
    public function DDTriggerRegisterAnyUnitDamaged(trigger t) {
        DmgTrig[NTrig] = t;
        NTrig += 1;
    }
   
    function InitDamageDetection() {
  code c = function() {
   if (TempTrig != null)
    DestroyTrigger(TempTrig);
   
   TempTrig = CreateTrigger();
   TriggerRegisterEnterRectSimple(TempTrig, bj_mapInitialPlayableArea);
   TriggerAddCondition(TempTrig, function() -> boolean {
    integer i;
   
    // *** Check if we need to exec triggers or register an unit ***
    if (GetTriggerEventId() == EVENT_UNIT_DAMAGED) {
     for(i=0; i < NTrig; i+=1)
      if (IsTriggerEnabled(DmgTrig[i]))
       if (TriggerEvaluate(DmgTrig[i]))
        TriggerExecute(DmgTrig[i]);
    }
    else
     // *** Register new unit ***
     TriggerRegisterUnitEvent(GetTriggeringTrigger(),
            GetTriggerUnit(),
            EVENT_UNIT_DAMAGED);
   
    return false;
   });
   
   DDGroupFilterRect(bj_mapInitialPlayableArea, 00, function() -> boolean {
    TriggerRegisterUnitEvent(TempTrig, GetFilterUnit(), EVENT_UNIT_DAMAGED);
    return false;
   });
  };
  trigger t = CreateTrigger();
 
  TriggerAddAction(t, c);
  TriggerExecute(t);
  DestroyTrigger(t);
  TimerStart(CreateTimer(), TRIGGER_REFRESH_RATE, true, c);
  t = null;
    }
 
 // ---------------------------------------------------------------------------------
 
 // *** Main enum dests in range function ***
    public function DDEnumDestsInRange(p_real vec, real radius, boolexpr filter, code pfunc) {
        rect r = Rect(vec[0]-radius, vec[1]-radius, vec[0]+radius, vec[1]+radius);
 
   EnumVec[0] = vec[0];
   EnumVec[1] = vec[1];
   EnumVec[2] = radius;
           
        if (filter != null) filter = And(EnumFilter, filter);
        else filter = EnumFilter;
        EnumDestructablesInRect(r, filter, pfunc);
 
        if (filter != EnumFilter) { DestroyBoolExpr(filter); filter = null; }
  RemoveRect(r);
  r = null;
    }
       
    function InitEnumDests() {
        EnumVec = p_real.create();
        EnumFilter = Filter(function() -> boolean {
            return Pw_2(EnumVec[0]-GetDestructableX(GetFilterDestructable())) + Pw_2(EnumVec[1]-GetDestructableY(GetFilterDestructable())) < Pw_2(EnumVec[2]);
        });
    }
   
 // --------------------------------------------------------------------------------------
 
 // *** checks is destruct tree ***
    public function DDIsDestructableTree(destructable d) -> boolean {
        if (d != null) {
            PauseUnit(TreeChecker, false);
            if (IssueTargetOrder(TreeChecker, "harvest", d)) {
                PauseUnit(TreeChecker, true);
                return true;
            }
            PauseUnit(TreeChecker, true);
        }
        return false;
    }

    function InitDestTreeCheck() {
        TreeChecker = CreateUnit(Player(bj_PLAYER_NEUTRAL_EXTRA), DD_DUMMYCODE, DDMaxX, DDMaxY, 0.);
        UnitAddAbility(TreeChecker, HARVEST_ID);
        PauseUnit(TreeChecker, true);
    }
 
 // --------------------------------------------------------------------------------------
   
 public function DDNewTextTagUnit(unit whichUnit, string text, real dur, real red, real green, real blue, real transparency) {
  CreateTextTagUnitBJ( text, whichUnit, 0., 11.00, red, green, blue, transparency );
  SetTextTagPermanentBJ( bj_lastCreatedTextTag, false );
  SetTextTagVelocityBJ( bj_lastCreatedTextTag, 48.00, 90 );
  SetTextTagFadepointBJ( bj_lastCreatedTextTag, dur-1.25 );
  SetTextTagLifespanBJ( bj_lastCreatedTextTag, dur );
 }
 
 // --------------------------------------------------------------------------------------
 
 struct cameranoisedata {
  player p[12];
  integer n=00;
 }
 
 public function DDCameraSetSourceNoiseForPlayers(real x, real y, real mag, real vel, real maxDist, real duration) {
  integer i;
  real d;
  cameranoisedata cnd = cameranoisedata.create();
 
  for (i=00; i < bj_MAX_PLAYERS; i+=01) {
   if (GetLocalPlayer() == Player(i)) {
    d = SquareRoot( Pw_2(GetCameraTargetPositionX()-x) + Pw_2(GetCameraTargetPositionY()-y) );
    if (d < maxDist) {
     cnd.p[cnd.n] = Player(i);
     CameraSetSourceNoise(mag-(d*(mag/maxDist)), vel-(d*(vel/maxDist)));
     CameraSetTargetNoise(mag-(d*(mag/maxDist)), vel-(d*(vel/maxDist)));
     cnd.n += 01;
    }
   }
  }
 
  DDStartTim(duration, false, cnd, function() {
   cameranoisedata cnd = DDTimData();
   
   while(cnd.n != 00) {
    cnd.n -= 01;
    if (GetLocalPlayer() == cnd.p[cnd.n])
     CameraSetSourceNoise(0., 0.);
     CameraSetTargetNoise(0., 0.);
   }
   
   cnd.destroy();
   DDQuitTim();
  });
 }
 
 // --------------------------------------------------------------------------------------
   
 hashtable GenSndTable = null;
 
    public function DDGenericSound(string file, real vol, real x, real y, real mxDist, real pitch) {
  sound s;
  real d;
  integer i;
  integer snd_n, sh;
       
  // Play sound and shake camera for players within spell cast range
  for (i=00; i < bj_MAX_PLAYERS; i+=01) {
   if (GetLocalPlayer() == Player(i)) {
    d = SquareRoot( Pw_2(GetCameraTargetPositionX()-x) + Pw_2(GetCameraTargetPositionY()-y) );
    if (d < mxDist) {
     sh = StringHash(file);
     snd_n = LoadInteger(GenSndTable, sh, 04);
     s = LoadSoundHandle(GenSndTable, sh, snd_n);
     if (s == null) {
      s = CreateSound(file, false, false, false, 10, 10, "");
      SaveSoundHandle(GenSndTable, sh, snd_n, s);
     } else if (GetSoundIsPlaying(s)) {
      StopSound(s, false, false);
     }
     SetSoundPitch(s, pitch);
     SetSoundVolume(s, R2I((vol-d*(vol/mxDist))*1.27));
     StartSound(s);
     snd_n += 01;
     if (snd_n == 04)
      snd_n = 00;
     SaveInteger(GenSndTable, sh, 04, snd_n);
    }
   }
  }
    }
 
 public function DDGetGameElapsedTime() -> real {
  return TimerGetElapsed(GameElapsedTimer);
 }
 
 public function DDGetRndReal(real min, real max) -> real {
  real rnd = ((max-min)/1000000.)*I2R(RndInt[RndIntReadN]);
  debug if (max > 1000000.)
   DDMsg("ERROR: \"DDGetRndNumber\" - 'max' variable is greater than 1000000!");
  RndIntReadN += 01; if (RndIntReadN == RND_INT_MAX_ARRAY_N) RndIntReadN = 00;
  return min + rnd;
 }
 
 public function DDGetRndInt(integer min, integer max) -> integer {
  return R2I( DDGetRndReal(I2R(min), I2R(max)) );
 }
 
 // ====================================================================
    function onInit() {
  InitDamageDetection();
  InitDestTreeCheck();
  InitEnumDests();
 
        DDMinX = GetRectMinX(bj_mapInitialPlayableArea);
        DDMinY = GetRectMinY(bj_mapInitialPlayableArea);
        DDMaxX = GetRectMaxX(bj_mapInitialPlayableArea);
        DDMaxY = GetRectMaxY(bj_mapInitialPlayableArea);
 
  GenSndTable = InitHashtable();
 
  ErrorSound = CreateSound( "Sound\\Interface\\Error.wav", false, false, false, 10, 10, "" );
  SetSoundParamsFromLabel( ErrorSound, "InterfaceError" );
  SetSoundDuration( ErrorSound, 614 );
  SetSoundVolume(ErrorSound, 127);
 
  GameElapsedTimer = CreateTimer();
  TimerStart(GameElapsedTimer, 10800., false, null);
 
  for(RndIntWriteN=00; RndIntWriteN < RND_INT_MAX_ARRAY_N; RndIntWriteN+=01)
   RndInt[RndIntWriteN] = GetRandomInt(00, 1000000);
 
  RndIntWriteN = 00;
  RndGenForce = CreateForce();
  TrigMouseEvent = CreateTrigger();
  ForForce(bj_FORCE_ALL_PLAYERS, function() {
   if (GetPlayerController(GetEnumPlayer()) == MAP_CONTROL_USER)
    TriggerRegisterPlayerEvent(TrigMouseEvent, GetEnumPlayer(), EVENT_PLAYER_MOUSE_MOVE);
  });
  TriggerAddCondition(TrigMouseEvent, Condition(function() -> boolean {
   real mouseN;
   boolean xFirst = GetRandomInt(00, 01) == 01;
   
   if (!IsPlayerInForce(GetTriggerPlayer(), RndGenForce)) {
    // example: input x = 578.4571496
    //   output rnd n = 4571498
    if (xFirst)
     mouseN = RAbsBJ(BlzGetTriggerPlayerMouseX()) * 100.;
    else
     mouseN = RAbsBJ(BlzGetTriggerPlayerMouseY()) * 100.;
    if (mouseN == 0.)
     return false;
    //mouseN *= 100.;
    RndInt[RndIntWriteN] = R2I((mouseN - I2R(R2I(mouseN))) * 1000.);
    //DDMsg(I2S(RndInt[RndIntWriteN]));
    //RndIntWriteN += 01; if (RndIntWriteN == RND_INT_MAX_ARRAY_N) RndIntWriteN = 00;
   
    if (xFirst)
     mouseN = RAbsBJ(BlzGetTriggerPlayerMouseY()) * 100.;
    else
     mouseN = RAbsBJ(BlzGetTriggerPlayerMouseX()) * 100.;
    RndInt[RndIntWriteN] += R2I((mouseN - I2R(R2I(mouseN))) * 1000.)*1000;
    //DDMsg(I2S(RndInt[RndIntWriteN]));
    RndIntWriteN += 01; if (RndIntWriteN == RND_INT_MAX_ARRAY_N) RndIntWriteN = 00;
    ForceAddPlayer(RndGenForce, GetTriggerPlayer());
   }
   
   if (DDGetGameElapsedTime()-RndElapsedTime > .125) {
    ForceClear(RndGenForce);
    RndElapsedTime = DDGetGameElapsedTime();
   }
   
   return false;
  }));
    }
   
}

//! endzinc


 

======================================

Shimmering Portal
Code (vJASS):

//TESH.scrollpos=0
//TESH.alwaysfold=0
// =====================================================================================================
//       * Spell - Shimmering Portal
//         by Dark Dragon
//
//
// Installation:
//
// (1) Install "DD Library" to your map if you have not done so already from my previous spells
// (2) Copy "Shimmering Portal" trigger to your map
// (3) Copy "Shimmering Portal" and "Portal (Dummy)" to your map
// (4) Edit spell to your will in object editor and here below in trigger editor
// (5) Enjoy!
// =====================================================================================================


//! zinc
library ShimmeringPortal requires DDLib
{

 
 // =============================================================
 //   *** Spell editable constants ***
 // =============================================================
 
 // ==========================================================================
 //
 //      *** Primary Spell Constants ***
 //
 // ==========================================================================
 
 // ----------------------------------------------------------------
 // *** The id of shimmering portal spell
 constant  integer      SPELL_ID      = 'SPrt';
 
 // ----------------------------------------------------------------
 // *** The id of shimmering portal dummy
 constant  integer      PORTAL_ID      = 'port';
 
 // ----------------------------------------------------------------
 // *** The length of portal, shrinking the value will force units to enter closer to center of portal
 constant  real      PORTAL_LENGTH     = 450.;
 
 // ----------------------------------------------------------------
 // *** Width of portal, units will enter the portal more far away if value is increased,
 //     decreassing this value too much can make unit pass portal faster than check interval can scan, thous causing spell to bug
 constant  real      PORTAL_WIDTH     = 110.;
 
 // ----------------------------------------------------------------
 // *** Units that are teleported to target portal, will walk away from there position offseted by random value between this (min and max)
 constant  real      UNIT_PORT_WALK_OFFSET_MIN  = 200.;
 constant  real      UNIT_PORT_WALK_OFFSET_MAX  = 350.;
 
 // ----------------------------------------------------------------
 // *** The offset of first portal near caster
 constant  real      FIRST_PORTAL_OFFSET    = 300.;
 
 // ----------------------------------------------------------------
 // *** The minimum casting range for shimmering portal spell
 constant  real      SECOND_PORTAL_MIN_RANGE   = 1000.;
 
 // ----------------------------------------------------------------
 // *** Time it takes to destroy portal after it expires or last unit exits
 constant  real      DESTROY_PORTAL_DELAY   = .7;
 
 // ----------------------------------------------------------------
 // *** The warning message, displayed in red color, and sound played with it, volume is in percentage
 constant  string      PORTAL_WARNING_MESSAGE   = "Warning: Too close cast of Shimmering portal!";
 constant  string      PORTAL_WARNING_SOUND_FILE  = "Sound\\Interface\\Error.wav";
 constant  real      PORTAL_WARNING_SOUND_VOLUME  = 90.;
 
 // ----------------------------------------------------------------
 // *** The duration of warning message
 constant  real      PORTAL_WARNING_MESSAGE_DURATION = 5.;
 
 // ----------------------------------------------------------------
 // *** This is animation of dummy portal, birth duration must be equeal to spell channel time
 constant  string      PORTAL_ANIM_BIRTH    = "birth";
 constant  string      PORTAL_ANIM_DEATH    = "death";
 constant  string      PORTAL_ANIM_STAND    = "stand";
 constant  real      PORTAL_ANIM_BIRTH_DURATION  = 7.5;
 
 // ----------------------------------------------------------------
 // *** How often to scan for units entry, greater value slows down CPU, while too low can cause units entered to not be registerd
 constant  real      PORT_CHECK_INTERVAL    = .1;
 
 // ----------------------------------------------------------------
 // *** Prevents units that are teleported to target portal to be teleported back, causing infinite loop of teleporting,
 //     this timing says that any unit will not be able to use any portals (MUI included)
 constant  real      UNIT_NEXT_PORT_DELAY   = 2.;
 
 // ----------------------------------------------------------------
 // *** Portal custom sounds files and volume in percentage
 constant  real      SOUND_MAX_DISTANCE    = 3500.;
 constant  string      PORTAL_BIRTH_SOUND_FILE   = "Sound\\Ambient\\DoodadEffects\\ShimmeringPortalBirth.wav";
 constant  real      PORTAL_BIRTH_SOUND_VOLUME  = 95.;
 constant  string      PORTAL_DEATH_SOUND_FILE   = "Sound\\Ambient\\DoodadEffects\\ShimmeringPortalDeath.wav";
 constant  real      PORTAL_DEATH_SOUND_VOLUME  = 95.;
 constant  string      PORTAL_ENTRANCE_SOUND_FILE  = "Sound\\Ambient\\DoodadEffects\\ShimmeringPortalEntrance.wav";
 constant  real      PORTAL_ENTRANCE_SOUND_VOLUME = 95.;
 constant  string      PORTAL_AMBIENCE_SOUND_FILE  = "Sound\\Ambient\\DoodadEffects\\CityScapeMagicRunesLoop1.wav";
 constant  real      PORTAL_AMBIENCE_SOUND_VOLUME = 100.;
 
 
 // ==========================================================================
 //
 //      *** Minimap Ping Constants ***
 //
 // ==========================================================================
 
 // ----------------------------------------------------------------
 // *** Do use minimap ping system for portals?
 constant  boolean      PORTAL_USE_MINIMAP_PING   = true;
 
 // ----------------------------------------------------------------
 // *** How often to ping minimap
 constant  real      PORTAL_MINIMAP_PING_INTERVAL = 4.5;
 
 // ----------------------------------------------------------------
 // *** How long to ping minimap
 constant  real      PORTAL_MINIMAP_PING_DURATION = 3.;
 
 // ----------------------------------------------------------------
 // *** The color of minimap ping
 constant  integer      PORTAL_MINIMAP_PING_RED   = 180;
 constant  integer      PORTAL_MINIMAP_PING_GREEN  = 23;
 constant  integer      PORTAL_MINIMAP_PING_BLUE  = 240;
 
 // ==========================================================================
 //
 //      *** Camera pan Constants ***
 //
 // ==========================================================================
 
 
 // ----------------------------------------------------------------
 // *** Camera pan is triggered when there are no more player units in area around source portal
 constant  boolean      DO_CAMERA_PAN     = true;
 
 // ----------------------------------------------------------------
 // *** This is the radius of camera scanning, where it will search for player units
 constant  real      CAMERA_PAN_AREA_SCAN   = 700.;
 
 // ----------------------------------------------------------------
 // *** The time it takes after last unit enters the portal to pan the camera
 constant  real      CAMERA_PAN_DELAY    = 1.5;
 
 
 // ==========================================================================
 //
 //      *** After Image Constants ***
 //
 // ==========================================================================
 
 // ----------------------------------------------------------------
 // *** Do use after imaging, will show transparent unit entering the portal
 constant  boolean      USE_UNIT_AFTER_IMAGING   = true;
 
 // ----------------------------------------------------------------
 // *** The time image lasts
 constant  real      UNIT_AFTER_IMAGE_DURATION  = .85;
 
 // ----------------------------------------------------------------
 // *** Animation speed of image, 1. is 100. percent
 constant  real      UNIT_AFTER_IMAGE_TIMESCALE  = .5;
 
 // ----------------------------------------------------------------
 // *** The color of image
 constant  integer      UNIT_AFTER_IMAGE_RED   = 128;
 constant  integer      UNIT_AFTER_IMAGE_GREEN   = 128;
 constant  integer      UNIT_AFTER_IMAGE_BLUE   = 128;
 // ----------------------------------------------------------------
 // *** The starting transparency in percentage of image, 100. is fully visible
 constant  real      UNIT_AFTER_IMAGE_TRANSPARENCY_MIN = 60.;
 constant  real      UNIT_AFTER_IMAGE_TRANSPARENCY_MAX = 70.;
 
 // =================================================================================
 //  
 //    *** Enable custom selection, units that are teleported to target portal get
 //        selected by owning player if they where selected when they entered source portal
 constant  boolean      DO_UNIT_SELECTION_JOB   = true;
 
 // ----------------------------------------------------------------
 // *** How often to check should units be selected, that is did all units enter source portal
 constant  real      SELECTION_CHECK_INTERVAL  = .5;
 
 // ----------------------------------------------------------------
 // *** non-Editable, do not change ***
 //constant  integer      BLIZZARD_MAX_SOUND_INSTANCES = 4;
 constant  key       CASTER_FACING_KEY;
 constant  key       UNIT_PORT_KEY;
 constant  key       CASTER_PORTS_KEY;
 constant  key       UNIT_SELECTED_KEY;
 constant  key       UNIT_SELECTION_GROUPING_KEY;
 
 
 
 // -------------------------------------------
 // *** Portal level constants
 // -------------------------------------------
 
 // Portal duration in seconds
 function PORTAL_DURATION(integer level) -> real {
  real dur[];
 
  dur[1] = 10.;
  dur[2] = 15.;
  dur[3] = 20.;
 
  return dur[level];
 }
 
 // Portal units transition time in seconds
 function PORTAL_TRANSITION_TIME(integer level) -> real {
  real trans_tim[];
 
  trans_tim[1] = 5.;
  trans_tim[2] = 4.;
  trans_tim[3] = 2.;
 
  return trans_tim[level];
 }
 
 // Portal max units pass
 function PORTAL_MAX_PASS(integer level) -> integer {
  integer max_pass[];
 
  max_pass[1] = 3;
  max_pass[2] = 7;
  max_pass[3] = 15;
 
  return max_pass[level];
 }
 
 // ----------------------------------------
 // **** Unit filter for portal
 function PortFilter(unit filter_unit, player cast_player) -> boolean {
  return  !IsUnitType(filter_unit, UNIT_TYPE_DEAD)    &&
    !IsUnitType(filter_unit, UNIT_TYPE_STRUCTURE)  &&
    !IsUnitType(filter_unit, UNIT_TYPE_ANCIENT)   &&
    !IsUnitType(filter_unit, UNIT_TYPE_POLYMORPHED)  &&
    !IsUnitType(filter_unit, UNIT_TYPE_FLYING)   &&
    !DDIsUnitWard(filter_unit)       &&
    IsUnitAlly(filter_unit, cast_player);
 }
 
 
 // ==================================================================================================
 //   --------------            --------------
 //     *** End constant spell modification, start spell code ***
 //   --------------            --------------
 // ==================================================================================================
 
 
 
 /// Check if target unit is in rectangle, x, y and degrees depend on portal, while length and width are constants
 function IsUnitInRectangle(unit u, real x, real y, real degrees) -> boolean {
  real ux = GetUnitX(u), uy = GetUnitY(u);
 
  real minx = x-(PORTAL_LENGTH*.5), miny = y-(PORTAL_WIDTH*.5); // Min and max x,y from normal rect
  real maxx = x+(PORTAL_LENGTH*.5), maxy = y+(PORTAL_WIDTH*.5);
 
  real range   = SquareRoot(Pw_2(x-ux) + Pw_2(y-uy)); // Distance between center of rect and target unit
  real radians  = Atan2(uy-y, ux-x); // Angle between center of rect and target unit
 
  /// convert unit angle to rect normal
  ux = x + range * Cos(radians-(degrees*bj_DEGTORAD));
  uy = y + range * Sin(radians-(degrees*bj_DEGTORAD));
 
  return (ux > minx && ux < maxx) && (uy > miny && uy < maxy);
 }
 
 // --------------------------------------------------------
 // Since portals are rects under angle, proper movement/teleportation from one portal to another has to be calculated
 // sx = source rectangle x
 // tx = target rectangle x
 function TranslateUnitFromRectangleToRectangle( unit u,
             real sx, real sy, real sdegrees,
             real tx, real ty, real tdegrees)
 {
 
  real ux = GetUnitX(u), uy = GetUnitY(u);
  real range = SquareRoot(Pw_2(sx-ux) + Pw_2(sy-uy)); // Distance between center of source rect and target unit
  real tradians_shift = -Atan2(uy-sy, ux-sx) + (tdegrees+sdegrees+180.)*bj_DEGTORAD; // Target angle between center of source rect and target unit shifted to target rect
 
  /*
  BJDebugMsg(R2S(sdegrees));
  BJDebugMsg(R2S(tdegrees));
  BJDebugMsg(R2S(-Atan2(uy-sy, ux-sx)*bj_RADTODEG));
  BJDebugMsg(R2S(tradians_shift*bj_RADTODEG));
  */

 
  /// convert unit to target rect
  ux = tx + range * Cos(tradians_shift);
  uy = ty + range * Sin(tradians_shift);
 
  // ** Set unit position and shift his angle to cause portal unit shattering, so that units are more organised
  // * Unit will continue moving in direction of his shift facing when ported
  SetUnitX(u, ux); SetUnitY(u, uy);
  SetUnitFacing(u, -GetUnitFacing(u) + (tdegrees+sdegrees));
 }
 
 // ========================================================================
 // *** After imaging code
 struct unitimage {
  private {
   unit u;
   real trans;
   real t_spd;
   
   static  constant  player   IMAGE_OWNER    = Player(15);
  }
 
  public static method CreateAfterImage(unit target, real x, real y) {
   thistype this = allocate();
   real fac = GetUnitFacing(target);
 
   u = CreateUnit(IMAGE_OWNER, GetUnitTypeId(target), 0., 0., fac);
   UnitAddAbility(u, 'Aloc');
   SetUnitPathing(u, false);
   //PauseUnit(u, true);
   SetUnitTimeScale(u, UNIT_AFTER_IMAGE_TIMESCALE);
   SetUnitX(u, x - 90. * Cos(fac*bj_DEGTORAD)); SetUnitY(u, y - 90. * Sin(fac*bj_DEGTORAD));
   SetUnitVertexColor(u, UNIT_AFTER_IMAGE_RED, UNIT_AFTER_IMAGE_GREEN, UNIT_AFTER_IMAGE_BLUE, 255);
   //SetUnitAnimation(u, UNIT_AFTER_IMAGE_ANIMATION);
   //QueueUnitAnimation(u, UNIT_AFTER_IMAGE_ANIMATION);
   SetUnitMoveSpeed(u, 1.);
   IssuePointOrder(u, "move", x + 100. * Cos(fac*bj_DEGTORAD), y + 100. * Sin(fac*bj_DEGTORAD));
   SetUnitColor(u, GetPlayerColor(GetOwningPlayer(target)));
   
   trans = GetRandomReal(UNIT_AFTER_IMAGE_TRANSPARENCY_MIN, UNIT_AFTER_IMAGE_TRANSPARENCY_MAX);
   t_spd = DD_INTERVAL*trans/UNIT_AFTER_IMAGE_DURATION;
   DDStartTim(DD_INTERVAL, true, this, function() {
    thistype this = DDTimData();
   
    trans -= t_spd;
    SetUnitVertexColor(u, UNIT_AFTER_IMAGE_RED, UNIT_AFTER_IMAGE_GREEN, UNIT_AFTER_IMAGE_BLUE, R2I(trans*2.55));
   
    if (trans <= 0.) {
     RemoveUnit(u);
     u = null;
     destroy();
     DDQuitTim();
    }
   });
  }
 }
 
 // ========================================================================
 // *** Primary portal code
 struct portal {
  private {
   unit   p;
   real   x, y, degrees;
   real   tx, ty, tdegrees;
   integer  lvl;
   integer  cpass; // current unit passed through portal
   timer   t;
   rect   pr;  // pick rect
   portal   lnk;
   sound  amb;
   integer  trans_units; // number of units being transiting at a time
   real  cpass_timeout;
   
   
   static constant  real  DIAGONAL   = SquareRoot((PORTAL_LENGTH*PORTAL_LENGTH) + (PORTAL_WIDTH*PORTAL_WIDTH));
   static constant  real  ALPHA    = Atan(PORTAL_WIDTH/PORTAL_LENGTH);
   
   //static    sound  SList[];
   //static    integer  SN     = 0;
   
   //static    player  TempP   = null;
   static    boolean  TempBool  = false;
   
   // *** selection vars ***
   static    group  SctG   = CreateGroup();
   static    timer  SctT   = CreateTimer();
  }
 
  private static method Min4x(real a, real b, real c, real d) -> real {
   if (a < b && a < c && a < d)
    return a;
   else if (b < c && b < d)
    return b;
   else if (c < d)
    return c;
   return d;
  }
 
  private static method Max4x(real a, real b, real c, real d) -> real {
   if (a > b && a > c && a > d)
    return a;
   else if (b > c && b > d)
    return b;
   else if (c > d)
    return c;
   return d;
  }
 
  private static method RectangleToRect(real x, real y, real rrad) -> rect {
   
   real x1 = x + (DIAGONAL * Cos(rrad+ALPHA)*.5),
     x2 = x + (DIAGONAL * Cos(rrad-ALPHA)*.5),
     x3 = x + (DIAGONAL * Cos(rrad+bj_PI+ALPHA)*.5),
     x4 = x + (DIAGONAL * Cos(rrad+bj_PI-ALPHA)*.5);
   
   real y1 = y + (DIAGONAL * Sin(rrad+ALPHA)*.5),
     y2 = y + (DIAGONAL * Sin(rrad-ALPHA)*.5),
     y3 = y + (DIAGONAL * Sin(rrad+bj_PI+ALPHA)*.5),
     y4 = y + (DIAGONAL * Sin(rrad+bj_PI-ALPHA)*.5);
     
   return Rect(Min4x(x1, x2, x3, x4), Min4x(y1, y2, y3, y4),
      Max4x(x1, x2, x3, x4), Max4x(y1, y2, y3, y4));
  }
 
  // ----------------------------------
  // * Constructor
  static method create(player p, integer lvl, real x, real y, real degrees, real tx, real ty, real tdegrees) -> thistype {
   thistype this = allocate();
   
   this.p = CreateUnit(p, PORTAL_ID, x, y, degrees+90.);
   PauseUnit(this.p, true);
   SetUnitAnimation(this.p, PORTAL_ANIM_BIRTH);
   QueueUnitAnimation(this.p, PORTAL_ANIM_STAND);
   
   this.x     = x;
   this.y     = y;
   this.degrees   = degrees;
   this.tx    = tx;
   this.ty    = ty;
   this.tdegrees   = tdegrees;
   this.lvl    = lvl;
   this.cpass    = 0;
   this.trans_units  = 0;
   this.pr    = RectangleToRect(x, y, bj_DEGTORAD*degrees);
   this.cpass_timeout  = PORTAL_TRANSITION_TIME(lvl);
   
   //test();
   
   return this;
  }
 
  // ----------------------------------
  // * Destructor
  method destroy() {
   if (t != null) {
    PauseTimer(t);
    DDRecycleTim(t);
    t = null;
   }
   StopSound(amb, true, true);
   KillUnit(p);
   RemoveRect(pr);
   p = null;
   pr = null;
   amb = null;
   deallocate();
  }
 
  // ------------------------------------------
  private method PlayPortalEntranceSound() {
   DDGenericSound(PORTAL_ENTRANCE_SOUND_FILE, PORTAL_ENTRANCE_SOUND_VOLUME, x, y, SOUND_MAX_DISTANCE, 1.);
   /*if (GetSoundIsPlaying(SList[SN]))
    StopSound(SList[SN], true, false);
   SList[SN] = CreateSound(PORTAL_ENTRANCE_SOUND_FILE, false, true, true, 10, 10, "DefaultEAXON");
   SetSoundVolume(SList[SN], R2I(PORTAL_ENTRANCE_SOUND_VOLUME*1.27));
   SetSoundPosition(SList[SN], x, y, 0.);
   StartSound(SList[SN]);
   KillSoundWhenDone(SList[SN]);
   
   SN = ModuloInteger(SN + 1, BLIZZARD_MAX_SOUND_INSTANCES);*/

  }
 
  // ------------------------------------------
  public method PlayPortalDeathSound() {
   DDGenericSound(PORTAL_DEATH_SOUND_FILE, PORTAL_DEATH_SOUND_VOLUME, x, y, SOUND_MAX_DISTANCE, 1.);
   //PlayBasicSound.evaluate(PORTAL_DEATH_SOUND_FILE, true, PORTAL_DEATH_SOUND_VOLUME, x, y, null);
  }
 
  // ------------------------------------------
  private method PlayPortalAmbienceSound() {
   if (amb == null) {
    amb = CreateSound(PORTAL_AMBIENCE_SOUND_FILE, true, true, true, 10, 10, "DoodadsEAX");
    SetSoundVolume(amb, R2I(PORTAL_AMBIENCE_SOUND_VOLUME*1.27));
    SetSoundPosition(amb, x, y, 0.);
    SetSoundDistanceCutoff(amb, 3500.);
    StartSound(amb);
   }
  }
 
  // *** Checks if player units are around source portal
  private method IsSrcPortalClear(player p) -> boolean {
   //TempP   = p;
   TempBool  = false;
   
   // *** Check if there are any remaining units
   DDGroupFilterArea(x, y, CAMERA_PAN_AREA_SCAN, GetPlayerId(p), function() -> boolean {
    TempBool = TempBool || (GetUnitAbilityLevel(GetFilterUnit(), 'Aloc') == 0  && PortFilter(GetFilterUnit(), Player(DDGFilterData())));
    return false;
   });
   
   return !TempBool;
  }
 
  // ------------------------------------------
  private method DoSelectJob(unit u, boolean select) {
   player p = GetOwningPlayer(u);
   
   if (!select) {
    DDSet(u, UNIT_SELECTED_KEY, 0);
    if (IsUnitSelected(u, p)) {
     DDSet(u, UNIT_SELECTED_KEY, 1);
     SelectUnit(u, false);
     if (IsUnitInGroup(u, SctG))
      GroupRemoveUnit(SctG, u);
    }
   } else {
    if (DDGet(u, UNIT_SELECTED_KEY) == 1) {
     if (IsSrcPortalClear(p)) {
      if (GetLocalPlayer() == p)
       SelectUnit(u, true);
     } else {
      // *** more units are awaiting to be ported delay the selection
      //BJDebugMsg(GetUnitName(FirstOfGroup(SctG)));
      if (FirstOfGroup(SctG) == null) {
       TimerStart(SctT, SELECTION_CHECK_INTERVAL, true, function() {
        //integer i;

        // ------------------------------------
        // *** reset player portal clear vars
        //for(i=0; i < 0xD; i+=1)
        // SctPClr[i] = 0;
       
        // ------------------------------------
        // *** loop through units ***
        ForGroup(SctG, function() {
         unit u = GetEnumUnit();
         player p = GetOwningPlayer(u);
         portal pt = DDGet(u, UNIT_SELECTION_GROUPING_KEY);
         //integer pid = GetPlayerId(p);
         
         // *** here we do not use just 0 and 1, but 0, 1 and 2, to optimize the code
         // *** requiering only min calls of "IsSrcPortalClear"
         /*
         if (SctPClr[pid] == 0) {
          SctPClr[pid] = 1;
          if (IsSrcPortalClear(p))
           SctPClr[pid] = 2;
         }
         */

         
         // *** if portal is clear, do selection now
         if (pt.IsSrcPortalClear(p) || IsUnitType(pt.p, UNIT_TYPE_DEAD)) {
          if (GetLocalPlayer() == p)
           SelectUnit(u, true);
          GroupRemoveUnit(SctG, u);
         }
         
         u = null;
        });
       
        // *** pause timer???
        if (FirstOfGroup(SctG) == null) {
         PauseTimer(SctT);
        }
       });
      }
      DDSet(u, UNIT_SELECTION_GROUPING_KEY, this);
      GroupAddUnit(SctG, u);
     }
    }
   }
  }
 
  // ------------------------------------------
  private method AttemptCameraPan(player p) {
   p_integer pi;
   
   // *** If no more units remains do pan camera
   if (IsSrcPortalClear(p)) {
    pi = p_integer.create();
    pi[0] = lnk;
    pi[1] = GetPlayerId(p);
   
    DDStartTim(CAMERA_PAN_DELAY, false, pi, function() {
     p_integer pi = DDTimData();
     
     if (GetLocalPlayer() == Player(pi[1]))
      SetCameraPosition(portal(pi[0]).x, portal(pi[0]).y);
     
     pi.destroy();
    });
   }
  }
 
  // --------------------------------------------
  // *** Periodic port timer system
  //
  public method StartPortSys() {
   t = DDStartTim(PORT_CHECK_INTERVAL, true, this, static method()
   {
    thistype   this     = DDTimData();
    real    elapsed    = DDTimTick()*PORT_CHECK_INTERVAL;
    integer   i     = 0;
   
    real    dur     = PORTAL_DURATION(lvl);
    real    trans_time    = PORTAL_TRANSITION_TIME(lvl);
    integer   max_pass    = PORTAL_MAX_PASS(lvl);
   
    p_integer   pi;
   
    // ------------------------------------------------------
    // *** Add the code for minimap ping if wanted
    static if (PORTAL_USE_MINIMAP_PING) {
     if (ModuloInteger(R2I(elapsed*10.), R2I(PORTAL_MINIMAP_PING_INTERVAL*10.)) == 1)
      if (GetLocalPlayer() == GetOwningPlayer(p)) {
       PingMinimapEx(x, y, PORTAL_MINIMAP_PING_DURATION, PORTAL_MINIMAP_PING_RED, PORTAL_MINIMAP_PING_GREEN, PORTAL_MINIMAP_PING_BLUE, false);
       PingMinimapEx(tx, ty, PORTAL_MINIMAP_PING_DURATION, PORTAL_MINIMAP_PING_RED, PORTAL_MINIMAP_PING_GREEN, PORTAL_MINIMAP_PING_BLUE, false);
      }
    }
    // ------------------------------------------------------
   
    // --------------------
    // *** Can port?, elapsed must be between bortal finish birth and from that point + portal duration
    // *** number of passed units between linked portals must be lower than constant specifies depending on level
    if (elapsed > PORTAL_ANIM_BIRTH_DURATION && elapsed < dur+PORTAL_ANIM_BIRTH_DURATION    &&
     cpass+lnk.cpass < max_pass)
    {
     PlayPortalAmbienceSound();
     
     // --------------------------------------------------
     // *** pick all units to be ported ***
     DDGroupFillMemRect(pr, this, static method() -> boolean {
      portal this = DDMemUnitData();
      // *** Unit is in rectangle and whas not ported reacently
      if (IsUnitInRectangle(GetFilterUnit(), x, y, degrees) && DDGet(GetFilterUnit(), UNIT_PORT_KEY) == 0)
       return PortFilter(GetFilterUnit(), GetOwningPlayer(p));
      return false;
     });
     
     // --------------------------------------------------
     // *** Port all units in portal area ***
     while(i < DDMemUnitN()) {
     
      if (!IssueImmediateOrder(DDMemUnit(i), "stop"))
       debug BJDebugMsg("Portal: Fail to stop unit!");
     
      static if (DO_UNIT_SELECTION_JOB)
       DoSelectJob(DDMemUnit(i), false);
       
      static if (USE_UNIT_AFTER_IMAGING)
       unitimage.CreateAfterImage(DDMemUnit(i), GetUnitX(DDMemUnit(i)), GetUnitY(DDMemUnit(i)));

      TranslateUnitFromRectangleToRectangle(DDMemUnit(i), x, y, degrees, tx, ty, tdegrees);
      ShowUnit(DDMemUnit(i), false);
      PlayPortalEntranceSound();
      trans_units += 1;
      lnk.trans_units += 1;
     
      static if (DO_CAMERA_PAN)
       AttemptCameraPan(GetOwningPlayer(DDMemUnit(i)));
     
      DDSet(DDMemUnit(i), UNIT_PORT_KEY, 1);
     
      // ---------------------------------------------------------
      // *** Transition time
      pi = p_integer.create();
      pi[0] = New_pUnit(DDMemUnit(i));
      pi[1] = this.lnk;
      pi[2] = this;
      DDStartTim(trans_time, false, pi, static method() {
       p_integer pi  = DDTimData();
       p_unit   pu   = pi[0];
       real   dist  = GetRandomReal(UNIT_PORT_WALK_OFFSET_MIN, UNIT_PORT_WALK_OFFSET_MAX);
       real   fac  = GetUnitFacing(pu[0]);
       
       portal(pi[1]).trans_units -= 1;
       portal(pi[2]).trans_units -= 1;
       portal(pi[1]).PlayPortalEntranceSound();
       ShowUnit(pu[0], true);
       IssuePointOrder(pu[0], "move",  GetUnitX(pu[0]) + dist * Cos(fac*bj_DEGTORAD),
               GetUnitY(pu[0]) + dist * Sin(fac*bj_DEGTORAD));
       
       
       // *** Make unit to be able to port again ***
       TimerStart(GetExpiredTimer(), UNIT_NEXT_PORT_DELAY, false, static method() {
        p_integer pi  = DDTimData();
        p_unit   pu   = pi[0];
        DDSet(pu[0], UNIT_PORT_KEY, 0);
        pi.destroy();
        pu.destroy();
        DDQuitTim();
       });
       
       static if (DO_UNIT_SELECTION_JOB) {
        thistype(pi[2]).DoSelectJob(p_unit(pi[0])[0], true);
       }
      });
      // ---------------------------------------------------------
     
      cpass += 1;
      i += 1;
     }
    }
   
    // *** Portal end if max pass reached or
    if ((elapsed > PORTAL_ANIM_BIRTH_DURATION + dur /*+ trans_time*/) || (cpass + lnk.cpass >= max_pass)) {
     /*
     if (cpass + lnk.cpass >= max_pass)
      cpass_timeout -= PORT_CHECK_INTERVAL;
     else
      cpass_timeout = 0.;
     */

     //debug BJDebugMsg(I2S(trans_units));
     if (/*cpass_timeout <= 0. ||*/ trans_units == 0) {
      DDStartTim(DESTROY_PORTAL_DELAY, false, this, function() {
       portal this = DDTimData();
       
       PlayPortalDeathSound();
       t = null;
       this.destroy();
       DDQuitTim();
      });
      DDQuitTim();
     }
    }
   
   });
  }
 
  // *** links with other portal
  method operator  link=(portal p)    { lnk = p; }
  method operator  Elapsed() -> real    { return DDCTimTick(t)*PORT_CHECK_INTERVAL; }
 
 }
 
 
 // ================================================================================
 //
 //      *** Extra spell functions ***
 //
 // ================================================================================
 
 
 // ------------------------------------------
 // *** Rounds positive integer
 function Round(real x) -> integer {
  if (x-I2R(R2I(x)) > .5)
   return R2I(x)+1;
  return R2I(x);
 }
 

 function onInit() {
  trigger t = CreateTrigger();
 
  TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_CAST);
  TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT);
  TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_ENDCAST);
  TriggerAddCondition(t, function() -> boolean {
   // ----------------------------------------
   // *** Locals ***
   unit   u;
   sound  s;
   player   p;
   integer  lvl;
   real  ux, uy;
   real  tx, ty;
   real  x, y, rads;
   p_real  fac;
   p_integer pt;
   
   // ----------------------------------------
   // *** Condition ***
   if (GetSpellAbilityId() != SPELL_ID)
    return false;
   
   // ----------------------------------------
   // *** Actions ***
   
   
   // ====================================================================
   // *** Start cast event ***
   // ====================================================================
   if (GetTriggerEventId() == EVENT_PLAYER_UNIT_SPELL_CAST) {
    u = GetTriggerUnit();
    if (IsUnitInRangeXY(u, GetSpellTargetX(), GetSpellTargetY(), SECOND_PORTAL_MIN_RANGE)) {
     IssuePointOrder(u, "move", GetUnitX(u) + 50. * Cos(GetUnitFacing(u)*bj_DEGTORAD), GetUnitY(u) + 50. * Sin(GetUnitFacing(u)*bj_DEGTORAD));
     DisplayTimedTextFromPlayer(GetOwningPlayer(u), 0., 0., PORTAL_WARNING_MESSAGE_DURATION, "|cffff0020"+PORTAL_WARNING_MESSAGE+"|r");
     if (GetLocalPlayer() == GetOwningPlayer(u)) {
      s = CreateSound(PORTAL_WARNING_SOUND_FILE, false, false, false, 10, 10, "");
      SetSoundVolume(s, R2I(PORTAL_WARNING_SOUND_VOLUME*1.27));
      StartSound(s);
      KillSoundWhenDone(s);
      s = null;
     }
     //PlayBasicSound(PORTAL_WARNING_SOUND_FILE, false, PORTAL_WARNING_SOUND_VOLUME, 0., 0., GetOwningPlayer(u));
     DDSet(u, CASTER_FACING_KEY, 0);
    } else
     DDSet(u, CASTER_FACING_KEY, New_pReal(GetUnitFacing(u)));
   
    u = null;
    return false;
   }
   
   
   // ====================================================================
   // *** End cast event ***
   // ====================================================================
   if (GetTriggerEventId() == EVENT_PLAYER_UNIT_SPELL_ENDCAST) {
    u = GetTriggerUnit();
   
    // *** Fail to cast spell?
    pt = DDGet(u, CASTER_PORTS_KEY);
    if (pt == 00) {
     u = null;
     return false;
    }
   
   
   
    // *** End spell if portal whas not channeled fully
    // * Use round and increase precission by 10x, meaning that cast times like 7.64 will be 7.6, as real values are unsafe to be compared
    if (Round(portal(pt[0]).Elapsed*10.) < Round(PORTAL_ANIM_BIRTH_DURATION*10.)) {
     portal(pt[0]).PlayPortalDeathSound();
     portal(pt[1]).PlayPortalDeathSound();
     portal(pt[0]).destroy();
     portal(pt[1]).destroy();
    }
    pt.destroy();
   
    u = null;
    return false;
   }
   
   // ====================================================================
   
   
   
   // ====================================================================
   // *** Start cast effect event ***
   // ====================================================================
   u   = GetTriggerUnit();
   p   = GetOwningPlayer(u);
   lvl  = GetUnitAbilityLevel(u, SPELL_ID);
   fac  = DDGet(u, CASTER_FACING_KEY);
   
   ux = GetUnitX(u); uy = GetUnitY(u);
   tx = GetSpellTargetX(); ty = GetSpellTargetY();
   rads = Atan2(-uy+ty, -ux+tx);
   x = ux + FIRST_PORTAL_OFFSET * Cos(rads);
   y = uy + FIRST_PORTAL_OFFSET * Sin(rads);
   
   pt = p_integer.create();
   pt[0] = portal.create(p, lvl, x, y, (rads*bj_RADTODEG)+90., tx, ty, fac[0]-90.);
   pt[1] = portal.create(p, lvl, tx, ty, fac[0]-90., x, y, (rads*bj_RADTODEG)+90.);
   
   portal(pt[0]).link = pt[1];
   portal(pt[1]).link = pt[0];
   
   portal(pt[0]).StartPortSys();
   portal(pt[1]).StartPortSys();
   
   DDSet(u, CASTER_PORTS_KEY, pt);
   
   DDGenericSound(PORTAL_BIRTH_SOUND_FILE, PORTAL_BIRTH_SOUND_VOLUME, x, y, SOUND_MAX_DISTANCE, 1.);
   DDGenericSound(PORTAL_BIRTH_SOUND_FILE, PORTAL_BIRTH_SOUND_VOLUME, tx, ty, SOUND_MAX_DISTANCE, 1.);
   
   
   fac.destroy();
   u = null;
   return false;
  });
 }

}
//! endzinc



// ============================================================================================
// Change me from /* to // and then back to /* after saving and reopening the map
    // |
    // ˇ
      /*
     
// Credits: PurgeandFire for lua tutorial
//! externalblock extension=lua ObjectMerger $FILENAME$
 //! i -- =========================================================
 
 //! i SHIMMERING_PORTAL_ABIL_ID     = "SPrt"
 //! i SHIMMERING_PORTAL_DUMMY_ID    = "port"
 
 //! i -- =========================================================


     //! i -- -----------------------------------------------
     //! i --Ability Create Code
     //! i setobjecttype("abilities")
     //! i createobject("ANto", SHIMMERING_PORTAL_ABIL_ID)
     //! i makechange(current,"anam", "Shimmering Portal")
     //! i makechange(current,"aart", "ReplaceableTextures\\CommandButtons\\BTNPortal.blp")
     //! i makechange(current,"arar", "ReplaceableTextures\\CommandButtons\\BTNPortal.blp")
     //! i makechange(current,"aani", "channel")
     //! i makechange(current,"alev", "3")
     //! i makechange(current,"arlv", "1")
     //! i makechange(current,"ahky", "H")
     //! i makechange(current,"arhk", "H")
     //! i makechange(current,"aret", "Learn S|cff8000ffh|rimmering Portal - [|cffffcc00Level ".. string.char(37) .."d|r]")
     //! i makechange(current,"arut", "|cffb300b3Opens portal allowing any ground unit to pass through.|n|r|n|cff408080[Level 1]|r - Portal lasts 10 seconds, up to 3 units can pass, 5 seconds transition time, cooldown 30 seconds.|n|cff408080[Level 2]|r - Portal lasts 15 seconds, up to 7 units can pass, 4 seconds transition time, cooldown 20 seconds.|n|cff408080[Level 3]|r - Portal lasts 20 seconds, up to 12 units can pass, 2 seconds transition time, cooldown 10 seconds.|n|n|cffb00000Channeling|r")
     //! i makechange(current,"aub1","1","|cffb300b3Portal lasts 10 seconds, up to 3 units can pass, 5 seconds transition time, cooldown 30 seconds.|r")
     //! i makechange(current,"aub1","2","|cffb300b3Portal lasts 15 seconds, up to 7 units can pass, 4 seconds transition time, cooldown 20 seconds.|r")
     //! i makechange(current,"aub1","3","|cffb300b3Portal lasts 20 seconds, up to 12 units can pass, 2 seconds transition time, cooldown 10 seconds.|r")
     
     //! i local i = 0
     //! i for i=1, 3 do
        //! i local si = tostring(i)
        //! i makechange(current,"Ntou",si,"")
        //! i makechange(current,"aran",si,"99999.")
        //! i makechange(current,"acdn",si,tostring(10*(4-i)))
        //! i makechange(current,"adur",si,"7.5")
        //! i makechange(current,"ahdu",si,"7.5")
        //! i makechange(current,"amcs",si,"100")
        //! i makechange(current,"atp1",si,"S|cff8000ffh|rimmering Portal - [|cffffcc00Level ".. si .."|r]")
     //! i end
     
     //! i -- -----------------------------------------------
     //! i --Dummy Create Code
     //! i setobjecttype("units")
     //! i createobject("hpea", SHIMMERING_PORTAL_DUMMY_ID)
     //! i makechange(current, "uabi", "Avul,Aloc")
     //! i makechange(current, "udtm", "5.77")
     //! i makechange(current, "uico", "ReplaceableTextures\\CommandButtons\\BTNPortal.blp")
     //! i makechange(current, "umdl", "Doodads\\Cinematic\\ShimmeringPortal\\ShimmeringPortal.mdl")
     //! i makechange(current, "umxp", "0.")
     //! i makechange(current, "umxr", "0.")
     //! i makechange(current, "ushu", "")
     //! i makechange(current, "ua1t", "")
     //! i makechange(current, "udea", string.char(2))
     //! i makechange(current, "umvt", "")
     //! i makechange(current, "ucol", "0.")
     //! i makechange(current, "ufoo", "0")
     //! i makechange(current, "usid", "1200")
     //! i makechange(current, "usin", "1200")
     //! i makechange(current, "unam", "Portal")
     //! i makechange(current, "unsf", " (Dummy)")
     
//! endexternalblock

       */

    // ^
    // |
// Change me from */ to // and then back to */ after saving and reopening the map
// ============================================================================================
 


If you need any extra help/info fell free to comment!

Enjoy!
~Dark Dragon

Keywords:
Frozen Throne, campaign, cinematic, portal, teleport, shimmering portal, spell, other
Contents

Spell Shimmering Portal (Map)

Reviews
Moderator
PurplePoot: Good enough, then, I s'pose. (I'll let you off on the MPI) ~approved~
  1. PurplePoot: Good enough, then, I s'pose. (I'll let you off on the MPI)

    ~approved~
     
  2. IamMclovin

    IamMclovin

    Joined:
    Aug 23, 2007
    Messages:
    38
    Resources:
    3
    Models:
    3
    Resources:
    3
    So what makes this system any different or better than a regular teleportation trigger? Please respond. Thanks.
     
  3. Dark_Dragon

    Dark_Dragon

    Joined:
    Jul 19, 2007
    Messages:
    591
    Resources:
    8
    Tools:
    1
    Spells:
    7
    Resources:
    8
    Well only because its a spell and you need to channel to open portal and that pass. I dont have any idea why else it shuld be different but i gues i answer on your question.
     
  4. UnDeatheater

    UnDeatheater

    Joined:
    Aug 8, 2007
    Messages:
    3
    Resources:
    0
    Resources:
    0
    Good job, only thing i think should be added is a visible timer for the portals, like when an archmage summons his elementals. I love the 'walk-through' feeling of it, instead of the teleportation feeling of the waygate ability that's often been used. 4/5, keep it up!
     
  5. Dark_Dragon

    Dark_Dragon

    Joined:
    Jul 19, 2007
    Messages:
    591
    Resources:
    8
    Tools:
    1
    Spells:
    7
    Resources:
    8
    Thank you for your suggestion ^^
     
  6. Dark_Dragon

    Dark_Dragon

    Joined:
    Jul 19, 2007
    Messages:
    591
    Resources:
    8
    Tools:
    1
    Spells:
    7
    Resources:
    8
    but because of new trigger timer it is inposible to make this spell work when many players casts this spell in same time. But othervise it works well, btw its an campaign spell right? ^^
     
  7. Dotoriton

    Dotoriton

    Joined:
    Dec 30, 2007
    Messages:
    36
    Resources:
    0
    Resources:
    0
    how can i expot it for my map ????
     
  8. Dark_Dragon

    Dark_Dragon

    Joined:
    Jul 19, 2007
    Messages:
    591
    Resources:
    8
    Tools:
    1
    Spells:
    7
    Resources:
    8
    If you know triggering at last GUI than open trigger editor or press (F4), and copy triggers in your map, that should do it.
     
  9. ShaDowPoWeR

    ShaDowPoWeR

    Joined:
    Nov 18, 2007
    Messages:
    48
    Resources:
    0
    Resources:
    0
    some of the portal stay there but you can't use it ... sucks
     
  10. BlackEnvyX

    BlackEnvyX

    Joined:
    Mar 27, 2008
    Messages:
    848
    Resources:
    2
    Maps:
    2
    Resources:
    2
    its an interesting concept, it would only work for campaigns like you said. gj ^_^
     
  11. Dark_Dragon

    Dark_Dragon

    Joined:
    Jul 19, 2007
    Messages:
    591
    Resources:
    8
    Tools:
    1
    Spells:
    7
    Resources:
    8
    Yes its only working for campaigns, better to say its not MUI . . .
     
  12. Statharas

    Statharas

    Joined:
    Jul 9, 2008
    Messages:
    2,337
    Resources:
    14
    Tools:
    1
    StarCraft II Resources:
    5
    Tutorials:
    8
    Resources:
    14
    The portal Spell Illidan uses is:pass through portal
    Delete unit:Illidan
    Pass Maiev and troops
    Delete Maeiv and Troops
    Delete Portal

    So that's why it is campaign spell...
    Try using Waygate effect on it....would work prety well...
    or try remodeling the archmage Mass Teleport...Making all units pass through it and then delete...would work :)
     
  13. aaron

    aaron

    Joined:
    Oct 18, 2008
    Messages:
    512
    Resources:
    6
    Maps:
    2
    Spells:
    4
    Resources:
    6
    nice ;0
     
  14. Dark_Dragon

    Dark_Dragon

    Joined:
    Jul 19, 2007
    Messages:
    591
    Resources:
    8
    Tools:
    1
    Spells:
    7
    Resources:
    8
    glade you like it!
     
  15. Deuterium

    Deuterium

    Joined:
    Mar 17, 2009
    Messages:
    1,301
    Resources:
    2
    Spells:
    1
    Tutorials:
    1
    Resources:
    2
    Umm DD released something :p ukhh once I re-charge my net account at home I'll be definitely checking this =) but I'm sure it's a job well done!
     
  16. Dark_Dragon

    Dark_Dragon

    Joined:
    Jul 19, 2007
    Messages:
    591
    Resources:
    8
    Tools:
    1
    Spells:
    7
    Resources:
    8
    thanks and i hope u enjoy the spell ;)
    Greets!
    ~Dark Dragon
     
  17. gunggang777

    gunggang777

    Joined:
    Jul 27, 2008
    Messages:
    110
    Resources:
    0
    Resources:
    0
    1300 downloads !?!?!?
     
  18. Kazemaru

    Kazemaru

    Joined:
    May 27, 2008
    Messages:
    55
    Resources:
    0
    Resources:
    0
    I have seen spell like this in hive. I think that you havent copied it becouse it has been maded long time ago. Still its very nice spell and you have done great job! ^^
     
  19. Dark_Dragon

    Dark_Dragon

    Joined:
    Jul 19, 2007
    Messages:
    591
    Resources:
    8
    Tools:
    1
    Spells:
    7
    Resources:
    8
    copied? ofc i did! its from frozen throne campaign and i give credits to blizzard for that and making the game ofc :D

    well there are some other people who tried to make such a spell but in the end i did not found any which can be called realy great... this is one of my first spells and its for some time on hive now and if you checked changelog you will see that i was few times updating it but still i was not so pro at that time. since this was my only spell which was causing HSC i decided to fix it since well i would need to fix it since it would not work for 1.24...

    Anyway ty for comment and greets!
    ~Dark Dragon