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

Zephyr Contest #10 - What lies on the other side

Status
Not open for further replies.
Here we go, I have a gif of the spell now, though it's a little jolty in places because recording software herp derp takes up a lot of processing for my poor computer, but it'll give you guys a better idea of what it looks like (just imagine it a lot smoother XD)
 

Attachments

  • Chaos-Envoy.gif
    Chaos-Envoy.gif
    2.4 MB · Views: 4,061
Chaos Envoy Entry

Right, making my entry post, any updates will be done on this post:

Spell: Chaos Envoy

Description:
Chaos Envoy
The caster reaches out to the heart of the twisting nether, creating a portal leaking chaotic entities and pulling nearby enemy units violently towards it; damaging them with crushing force. When the portal closes, all affected units and entities fall back to the ground.

Level 1 - 250 Crush damage, 70 Entity damage
Level 2 - 350 Crush damage, 90 Entity damage
Level 3 - 450 Crush damage, 110 Entity damage


JASS:
////////////////////////////////////////////////////////////////////
//                    CHAOS ENVOY V1.00                           //
//                                                                //
//  Author: Tank-Commander                                        //
//  Requires: Dummy.mdl                                           //
//  Purpose: Hero Ultimate, very powerful manipulation ability    //
//                                                                //
//  Notes:                                                        //
//    -  It's a channeling spell                                  //
//    -  Read the readme before you try modifying the config      //
//    -  Use the "Helpful files" to help you import the spell     //
//                                                                //
//  Credits:                                                      //
//    -  (Dummy.mdl) Vexorian                                     //
////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////
//  Chaos Envoy README                                            //
//                                                                //
//  This spell has a lot to configure so this readme will help    //
//  you set up your own Chaos Envoy spell to your liking          //
//  please read this through -fully- before attempting to change  //
//  the configuration                                             //
//                                                                //
//  If your editor does not automatically create variables for    //
//  JASS resources, please enable "automatically create unknown   //
//  variables while pasting trigger data" in the following path:  //
//  File -> Preferences ->  General                               //
//                                                                //
//  Once that is enabled, paste in the Variable Creator           //
//  (it can be deleted afterwards, it's just to create variables  //
//  and serves no other purpose)                                  //
//                                                                //
//  Contents:                                                     //
//                                                                //
//    1-- Setting SpellID and DummyID                             //
//    2-- Timer and Order                                         //
//    3-- AOE                                                     //
//    4-- Magnetism                                               //
//    5-- Aesthetics                                              //
//    6-- Main Damage                                             //
//    7-- Chaos Entity control                                    //
//    8-- Chais Entity damage                                     //
//    9-- Gravity, terrain and units                              //
//   10-- Attack, Damage, and weapon types                        //
//   11-- Unit Indexers                                           //
//                                                                //
//-------------------------------1--------------------------------//
//  Setting SpellID and DummyID:                                  //
//    To do this, find the spell you wish to set as the dummy     //
//    (or unit) then, find the data value of the spell/unit       //
//    if your editor is not already displaying data values then   //
//    you can enable the display by pressing Ctrl + D             //
//    before you panic, pressing Ctrl + D again, will revert the  //
//    the data value you're looking for will be in the unit       //
//    box in the object editor it should look like something      //
//    like this: u000                                             //
//                                                                //
//    there may be something after that like :uloc and then the   //
//    actual name in brackets, but you want this four character   //
//    code. To set it remeber the code and put it between         //
//    these two characters: ' '                                   //
//    e.g.:                                                       //
//      'u000'                                                    //
//                                                                //
//    Now, you can take that, and place it in the respective ID   //
//    return function the line should look like this:             //
//      return 'u000'                                             //
//                                                                //
//    When you have completed this you are ready to move on to    //
//    the next part.                                              //
//                                                                //
//-------------------------------2--------------------------------//
//  Timer and Order:                                              //
//    This spell has two timers and one order, one of the timers  //
//    is for how fast the loop runs, the other, is how long       //
//    after a unit is removed, is the instance recycled           //
//    (it has a timer so that death effects can play)             //
//                                                                //
//    The first timer, will need to be set to something low       //
//    but not below 0.03 to prevent lag, setting it to            //
//    something high (above 0.05) may remove some of the          //
//    smoothness of the effects, it's recommended that you leave  //
//    the value at 0.03, but you may wish to change it            //
//                                                                //
//    The second timer, can technically be any number you like    //
//    and in most cases, it won't make any difference provided    //
//    it's over a second, and if not, the only change is that     //
//    some effects to not display properly due to the unit being  //
//    removed before they finish playing, it is in seconds        //
//    so 1.00 == 1 second, pretty simple and straightforward      //
//                                                                //
//    The order: This is a bit more complex though still fairly   //
//    straightforward, find your spell in the object editor       //
//    you're looking for "Text - Order string - Use/turn on"      //
//    in most cases this should be "channel" because the spell    //
//    needs to be channeled to word, but if you want to change    //
//    it you can, though it's not recommended                     //
//                                                                //
//-------------------------------3--------------------------------//
//  AOE:                                                          //
//    The AOE configurables essentially control the area of the   //
//    magnetism, rather than the spread of the projectiles        //
//    as for the projectiles, that will be covered later          //
//    for now, this section will focus on the magnetism AOE       //
//                                                                //
//    The AOE controls how far away from the portal you can be    //
//    and still be affected by it's AOE, if a unit leaves the     //
//    portal AOE, then it will be dropped by the portal           //
//    The AOE variables ought to manage to keep the projectiles   //
//    within the portal, if it is too small in relation to the    //
//    other factors, the entities will also fall out, as well as  //
//    any units which were taken for the ride                     //
//                                                                //
//    "AOE Central" referrs to the boarders and how far they are  //
//    from the middle of the portal (also how far the entities    //
//    are created from the middle) experimenting with that may    //
//    give some interesting results, but remember the default     //
//    value of 100.00                                             //
//                                                                //
//-------------------------------4--------------------------------//
//  Magnetism:                                                    //
//    The Magnetism values need to be high,the base value should  //
//    be at least 10000.00 for it work correctly, having too      //
//    much magnetism (80000+) may cause some unforseen effects    //
//    Like units flying out of the top of the Map Z height, so    //
//    it's not really recommended (though you never know)         //
//    the increment can be anything really, the magnetism itself  //
//    will however alter the spread of the projectiles and units  //
//    if it is changed, if you want a maintained (or roughly      //
//    maintained pattern) I suggest an increment under 10000.00   //
//                                                                //
//    Magnetism Decay: this works a little differently, unlike    //
//    normal gravity where it is stronger the closer to the       //
//    center, this spell has an inverted gravity, it's stronger   //
//    the further away a unit is, and weaker in the center        //
//    the decay controls how the distance from the target is      //
//    divided up, i.e. the default value is 400                   //
//    say a unit 1200 points apart is in range, the strength of   //
//    the magnetism they experience is:                           //
//      MagnetismStrength * (1200/400) = MagnetismStrength * 3    //
//                                                                //
//    So they experience 3x the normal magnetism strength where   //
//    as if they were at range 400, they'd experience normal      //
//    magnetism, and less if they were even closer than that      //
//                                                                //
//-------------------------------5--------------------------------//
//  Aesthetics:                                                   //
//    There's a large number of aesthetic options available in    //
//    this spell, designed to give the user, the maximum amount   //
//    of options                                                  //
//                                                                //
//    Portal Angle: Controls the pitch angle of the portal, 90    //
//    is the upright position, 0 is on it's side                  //
//    and so on                                                   //
//                                                                //
//    Portal scale: Controls the size of the portal, growing      //
//    rates should be 0.00(i) i.e. 0.005 as to not make the       //
//    the portal grow too large 1 == 100%, 0.001 = 1%             //
//                                                                //
//    Portal Height: Controls how high from the terrain height    //
//    the portal is placed, having a low value here will cause    //
//    projectiles to instantly/quickly hit the ground, and units  //
//    will have lower(or possibly no) arc, will also mean more    //
//    units will be successfully caught by the terrain and not    //
//    pulled if you have TerrainMatters set to true, will also    //
//    effect the AOE of the projectiles (lower to the ground      //
//    means tighter spread, higher up means further apart)        //
//                                                                //
//    Portal/Boarder models: Set these to the model paths of the  //
//    models you desire, if you are getting them from the object  //
//    editor, remember to add a "\" to the pathname everywhere    //
//    there is already one, i.e. "path\path\path.mdl"             //
//    needs to be changed to "path\\path\\path.mdl"               //
//                                                                //
//    Boarder scale works the same way the portal scale does      //
//    so just follow the same steps, 0.25 to 0.50 works well for  //
//    boarders                                                    //
//                                                                //
//    the space taken per segment works in a way that 6.00 means  //
//    you will have 6 boarder pieces, setting to something like   //
//    100.00 will mean 100 segments, a number between 5 and 10    //
//    works well here (as to not flood with effects) keep it      //
//    relative to the scale you set up                            //
//                                                                //
//    Boarder height, again, works in the same way as a portal    //
//    height, should be roughly portal height + 50, but, if it    //
//    better suits your portal model, it can theoretically be     //
//    anything without having any impact to the rest of the       //
//    spell                                                       //
//                                                                //
//    Chaos Entity model: same as the other model sets, with      //
//    the filepaths, also consider that this is a projectile so   //
//    you ought to set it to something which'd work as a          //
//    projectile, like prehaps nether drakes, locusts, rockets    //
//    anything really which isn't a building or a ground unit     //
//                                                                //
//    Chaos Entity scale neednot explain how this works a third   //
//    time                                                        //
//                                                                //
//    Chaos Entity Z control, determines how much Z Velocity      //
//    each entity starts with, this in turn controls how far      //
//    out from the middle it goes and respectively how much       //
//    lower from the middle the projectiles go, setting this to   //
//    0 will mean they maintain their height throughout and do    //
//    not go up/down as normal, default is 6.00, playing around   //
//    with this can have unexpected results, to invert the flow   //
//    use a negative value                                        //
//-------------------------------6--------------------------------//
//  Main Damage:                                                  //
//    These controllers are all for the crush damage dealt by     //
//    units being thrown around by the spell, they do -not-       //
//    effect how much damage each entity does.                    //
//                                                                //
//    All of these are relatively self-explanatory, you can deal  //
//    both health and mana damage with these configurables        //
//    damagetypes/weapontypes/attacktypes are set later which     //
//    will control the multiplyers of all these things            //
//                                                                //
//-------------------------------7--------------------------------//
//  Chaos Entity Control:                                         //
//    These controllers are primarily for controlling the number  //
//    of chaos entities and how fast they appear                  //
//                                                                //
//    ChaosEntityCount: these controllers determine how many      //
//    leak through the portal each cycle of creation, having      //
//    a number higher than 45 at the max level as that will       //
//    cause lag on most machines (especially if multicasted       //
//    or other similar spells are around) 15 is the default at    //
//    level 3, anything under 30 is a relatively safe number      //
//                                                                //
//    ChaosEntityAOE: Controls how much area each missile covers  //
//    upon impact, anywhere from 50-120 is realistic, try to      //
//    keep it relative to the missile size (if it's large         //
//    150-200 may be more appropriate)                            //
//                                                                //
//    ChaosEntityRate: How long (in seconds) there is between     //
//    cycles of ChaosEntity leaks, 1-2 seconds works pretty well  //
//    remember to change the channelling duration of the spell    //
//    to match this (the longer the duration, the more cycled     //
//    leaks)                                                      //
//                                                                //
//-------------------------------8--------------------------------//
//  Chaos Entity Damage:                                          //
//     Like the other fairly straight forward, health and mana    //
//     damage, base and per level values, does not effect the     //
//     main damage (unit throwing around damage) at all, each     //
//     projectile individually will have this damage, it is not   //
//     relative to the distance from the projectile               //
//                                                                //
//-------------------------------9--------------------------------//
//  Gravity, terrain and units:                                   //
//    These control optional features and projectile fall arcs    //
//                                                                //
//    Gravity: This is the strength of the terrain gravity which  //
//    causes entities and units to fall at a given rate, higher   //
//    means a stronger gravity and the faster projectiles come    //
//    back down, 20 is Low gravity, negative numbers are          //
//    Antigrav (you will crash the map doing this, so don't)      //
//    60+ is high gravity, as such these will alter the spread    //
//    and AOE of your projectiles, as this is what determines     //
//    how fast they come back down                                //
//                                                                //
//    TerrainMatters: This function poses a question, do you      //
//    want terrain to matter, or do you want units pulled from    //
//    wherever they are, regardless of the terrain height they    //
//    at it by relativity, changing this to true or false will    //
//    not alter projectile destruction when falling, though will  //
//    when they're in the portal (none will be destroyed until    //
//    they start falling) true will let units brace against the   //
//    ground to prevent being pulled, false will mean they can't  //
//                                                                //
//    EffectsUnits: This function poses a different question, do  //
//    you want units effected at all, or do you just want your    //
//    flurry of projectiles to be the only means of damage, if    //
//    you don't want units to be effected, it's suggested you     //
//    lower the projectile interval time (or increase the         //
//    channeling time) and increase the damage &/or AOE of your   //
//    spell to still give it that ultimate-level power, except    //
//    if you don't intend to use this ability as an ultimate      //
//                                                                //
//------------------------------10--------------------------------//
//  Attack, Damage, and Weapon types:                             //
//    These features will determine your spells damage            //
//    multiplyers, you have controls for all three of these       //
//    things                                                      //
//                                                                //
//    However, knowing all of these different types takes quite   //
//    a bit of knowledge, however they are listed here to make    //
//    it easier:                                                  //
//                                                                //
//    Attack types all start with "ATTACK_TYPE_"                  //
//    CHAOS, HERO, MAGIC, MELEE, NORMAL, PIERCE, SIEGE            //
//                                                                //
//    Damage types all start with "DAMAGE_TYPE_"                  //
//    ACID, COLD, DEATH, DEFENSIVE, DEMOLITION, DISEASE, DIVINE   //
//    ENHANCED, FIRE, FORCE, LIGHTNING, MAGIC, MIND, NORMAL       //
//    PLANT, POSION, SHADOW_STRIKE, SLOW_POISON, SONIC            //
//    SPIRIT_LINK, UNIVERSAL, UNKNOWN                             //
//                                                                //
//    Weapon types all start with "WEAPON_TYPE_"                  //
//    Then add one of the following types:                        //
//    AXE, CLAW, METAL, ROCK, WOOD.                               //
//    Then add one of the classifications (note, some  types do   //
//    not have any of these)                                      //
//    HEAVY, MEDIUM, LIGHT                                        //
//    Then add one of these:                                      //
//    CHOP, SLICE, BASH, STAB                                     //
//                                                                //
//    Remember to include underscores "_" between each word       //
//    and if you don't care for weapon types, you can always use  //
//    WEAPON_TYPE_WHOKNOWS, or even better: null                  //
//                                                                //
//-------------------------------11-------------------------------//
//  Unit Indexers:                                                //
//    general unit indexers, neednot include any of the units     //
//    created by this spell, also, due to the high number of      //
//    entities created, intentionally excluding them, may be      //
//    benefiticial to your map.                                   //
//    to disclude these units from any unit indexer you may have  //
//    you can add this condition:                                 //
//                                                                //
//    and (GetUnitTypeId([unit variable]) != CE_DummyId()) then   //
//                                                                //
//    Adding that line to the end of your selection if statement  //
//    should prevent any of these units being added, remember to  //
//    change "[unit variable]" to match whatever variable you     //
//    stored the unit in i.e. TempUnit, Unit, u, U, etc.          //
//    (disclude the square brackets as well)                      //
//                                                                //
//    if you are using this with a GUI unit indexer, then you     //
//    will need to add some additional lines for this to work:    //
//                                                                //
//    Custom Script: set [variable] = CE_DummyId()                //
//    Custom Script: set [variable2] = GetUnitTypeId(unit)        //
//                                                                //
//    then if your if statement, check that those two variables   //
//    are not the same (also, both variables are integers)        //
//                                                                //
//----------------------------------------------------------------//
//                                                                //
//  That concludes the readme for the CHAOS ENVOY spell           //
//  thank you for reading and enjoy the spell                     //
//                                                                //
////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////
//  Configuration of the spell can be done here, consult the      //
//  readme for more information on how to do this                 //
////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////
//  Controller for the spell to be used as the  //
//  dummy ability and unit as the dummy unit    //
//////////////////////////////////////////////////
constant function CE_SpellID takes nothing returns integer
    return 'A001'
endfunction

constant function CE_DummyID takes nothing returns integer
    return 'u000'
endfunction

//////////////////////////////////////////////////
//  Controller for the timer speed (0.03 is     //
//  the standard timeout)                       //
//////////////////////////////////////////////////
constant function CE_TimerSpeed takes nothing returns real
    return 0.03
endfunction

//////////////////////////////////////////////////
//  Controller for how long a unit lasts        //
//  after it's usefulness has expired           //
//  (mostly for effects to play)                //
//////////////////////////////////////////////////
constant function CE_DeathTimer takes nothing returns real
    return 2.00
endfunction

//////////////////////////////////////////////////
//  Controller for the order attached to the    //
//  Dummy ability                               //
//////////////////////////////////////////////////
constant function CE_Order takes nothing returns integer
    return OrderId("channel")
endfunction

//////////////////////////////////////////////////
//  Controllers for the Portal AOE (magnetism)  //
//  projectiles will ignore this AOE other      //
//  than for staying attached to the portal     //
//  until it disappates, if this value is       //
//  too small, projectiles will "fall out"      //
//////////////////////////////////////////////////
constant function CE_AOEBase takes nothing returns real
    return 250.00
endfunction

constant function CE_AOEPerLevel takes nothing returns real
    return 100.00
endfunction

//////////////////////////////////////////////////
// Controllers for the centre of the portal     //
//////////////////////////////////////////////////
constant function CE_AOECentral takes nothing returns real
    return 100.00
endfunction
//////////////////////////////////////////////////
//  Controllers for the magnetism strength      //
//  of the portal (playing around may give      //
//  odd results)                                //
//////////////////////////////////////////////////
constant function CE_MagnetismBase takes nothing returns real
    return 30000.00
endfunction

constant function CE_MagnetismPerLevel takes nothing returns real
    return 7500.00
endfunction

//////////////////////////////////////////////////
//  Controllerfor the Magnetism decay, this is  //
//  how far from the portal, until a larger     //
//  proportion of magnetism is used             //
//  (exponential)                               //
//////////////////////////////////////////////////
constant function CE_MagnetismDecay takes nothing returns real
    return 400.00
endfunction

//////////////////////////////////////////////////
//  Constrollers for the portal aesthetics      //
//////////////////////////////////////////////////

//////////////////////////////////////////////////
//  Constroller for the angle of the model      //
//  (90 is upright)                             //
//////////////////////////////////////////////////
constant function CE_PortalAngle takes nothing returns integer
    return 90
endfunction

//////////////////////////////////////////////////
//  Controllers for the scale of the portal     //
//////////////////////////////////////////////////
constant function CE_PortalStartScale takes nothing returns real
    return 2.00
endfunction

constant function CE_PortalGrowthRateBase takes nothing returns real
    return 0.003
endfunction

constant function CE_PortalGrowthRatePerLevel takes nothing returns real
    return 0.002
endfunction

//////////////////////////////////////////////////
//  Controller for how heigh up the portal is   //
//  (will change how units/projectiles behave   //
//  with the portal)                            //
//////////////////////////////////////////////////
constant function CE_PortalHeight takes nothing returns real
    return 400.00
endfunction

//////////////////////////////////////////////////
//  Controllers for the models used for the     //
//  portal and it's boarders                    //
//////////////////////////////////////////////////
constant function CE_PortalModel takes nothing returns string
    return "Abilities\\Spells\\Undead\\Possession\\PossessionCaster.mdl"
endfunction

constant function CE_PortalBoarderModel takes nothing returns string
    return "Abilities\\Spells\\Undead\\AntiMagicShell\\AntiMagicShell.mdl"
endfunction

//////////////////////////////////////////////////
//  Controller for the size of the boarders     //
//////////////////////////////////////////////////
constant function CE_PortalBoarderScale takes nothing returns real
    return 0.25
endfunction

//////////////////////////////////////////////////
//  Controller for how many boarder segments    //
//  the spell has (6.00 gives 6 boarders)       //
//////////////////////////////////////////////////
constant function CE_PortalBoarderSpaceTakenPerSegment takes nothing returns real
    return 6.00
endfunction

//////////////////////////////////////////////////
//  Controller for how heigh the boarders of    //
//  the portal are set (should be about the     //
//  height of the poral + 50)                   //
//////////////////////////////////////////////////
constant function CE_PortalBoarderHeight takes nothing returns real
    return 450.00
endfunction

//////////////////////////////////////////////////
//  Controllers for the size of the projectiles //
//////////////////////////////////////////////////
constant function CE_ChaosEntityScaleBase takes nothing returns real
    return 0.75
endfunction

constant function CE_ChaosEntityScalePerLevel takes nothing returns real
    return 0.00
endfunction

//////////////////////////////////////////////////
//  Controller for the models of the            //
//  projectiles                                 //
//////////////////////////////////////////////////
constant function CE_ChaosEntityModel takes nothing returns string
    return "Abilities\\Spells\\Undead\\OrbOfDeath\\AnnihilationMissile.mdl"
endfunction

//////////////////////////////////////////////////
//  Controller for the initial z velocity of    //
//  chaos entities, changes the aesthetic look  //
//  and the damage spread of the spell          //
//////////////////////////////////////////////////
constant function CE_ChaosEntityZControl takes nothing returns real
    return 6.00
endfunction

//////////////////////////////////////////////////
//  End of the aesthetics configuration         //
//////////////////////////////////////////////////

//////////////////////////////////////////////////
//  Controllers for spell damage                //
//  (Non projectile)                            //
//////////////////////////////////////////////////
constant function CE_HealthDamageBase takes nothing returns real
    return 200.00
endfunction

constant function CE_HealthDamagePerLevel takes nothing returns real
    return 50.00
endfunction

constant function CE_ManaDamageBase takes nothing returns real
    return 0.00
endfunction

constant function CE_ManaDamagePerLevel takes nothing returns real
    return 0.00
endfunction

//////////////////////////////////////////////////
//  Controllers for the number of projectiles   //
//  generated by the spell per cycle            //
//////////////////////////////////////////////////
constant function CE_ChaosEntityCountBase takes nothing returns integer
    return 0
endfunction

constant function CE_ChaosEntityCountPerLevel takes nothing returns integer
    return 5
endfunction

//////////////////////////////////////////////////
//  Controller for the AOE of the chaos         //
//  entities                                    //
//////////////////////////////////////////////////
constant function CE_ChaosEntityAOE takes nothing returns real
    return 125.00
endfunction

//////////////////////////////////////////////////
//  Controller for the Chaos entity creation    //
//  rate (in seconds)                           //
//////////////////////////////////////////////////

constant function CE_ChaosEntityRate takes nothing returns real
    return 1.50
endfunction

//////////////////////////////////////////////////
//  Controllers for the damage dealt by the     //
//  Projectiles                                 //
//////////////////////////////////////////////////
constant function CE_ChaosEntityHealthDamageBase takes nothing returns real
    return 50.00
endfunction

constant function CE_ChaosEntityHealthDamagePerLevel takes nothing returns real
    return 20.00
endfunction

constant function CE_ChaosEntityManaDamageBase takes nothing returns real
    return 0.00
endfunction

constant function CE_ChaosEntityManaDamagePerLevel takes nothing returns real
    return 0.00
endfunction

//////////////////////////////////////////////////
//  Controller for how strong the terrain       //
//  gravity is (makes units return to the       //
//  ground when the rip ends)                   //
//////////////////////////////////////////////////
constant function CE_Gravity takes nothing returns real
    return 40.00 * CE_TimerSpeed()
endfunction

//////////////////////////////////////////////////
//  Controller for whether or not the terrain   //
//  heights effect the spell (arcs hitting      //
//  into it and such)                           //
//////////////////////////////////////////////////
constant function CE_TerrainMatters takes nothing returns boolean
    return true
endfunction

//////////////////////////////////////////////////
//  Controller for whether or not units are     //
//  pulled into the Portal                      //
//////////////////////////////////////////////////
constant function CE_EffectsUnits takes nothing returns boolean
    return true
endfunction

//////////////////////////////////////////////////
//  Controllers for the damage types and such   //
//////////////////////////////////////////////////
constant function CE_MainDamageType takes nothing returns damagetype
    return DAMAGE_TYPE_MAGIC
endfunction

constant function CE_ChaosEntityDamageType takes nothing returns damagetype
    return DAMAGE_TYPE_NORMAL
endfunction

constant function CE_MainAttackType takes nothing returns attacktype
    return ATTACK_TYPE_MAGIC
endfunction

constant function CE_ChaosEntityAttackType takes nothing returns attacktype
    return ATTACK_TYPE_NORMAL
endfunction

constant function CE_MainWeaponType takes nothing returns weapontype
    return null
endfunction

constant function CE_ChaosEntityWeaponType takes nothing returns weapontype
    return null
endfunction

////////////////////////////////////////////////////////////////////
//  End of the configuration of the spell, beyond this is the     //
//  programming used to run the spell, if you do not understand   //
//  JASS, then it is not recommended that you scroll any further  //
////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////
//  Function used to identify targets for the magnetism or        //
//  damage of the spell depanding on what the current stage is    //
////////////////////////////////////////////////////////////////////
function CE_TargetFilter takes unit u, player pl returns nothing

    //Checks if the unit can be used as a target
    if (IsUnitType(u, UNIT_TYPE_GROUND)) and (not IsUnitType(u, UNIT_TYPE_STRUCTURE)) and (not IsUnitType(u, UNIT_TYPE_MAGIC_IMMUNE)) and (IsUnitEnemy(u, pl)) and (GetUnitTypeId(u) != CE_DummyID()) and (not IsUnitInGroup(u, udg_CE_EffectedUnits)) and (not IsUnitType(u, UNIT_TYPE_DEAD)) then
        call GroupAddUnit(udg_CE_TempGroup, u)
    endif
   
    //Nulling variables
    set u = null
    set pl = null

endfunction

////////////////////////////////////////////////////////////////////
//  Function used to move units currently affected by a portal    //
//  while not allowing them outside of map bounds                 //
////////////////////////////////////////////////////////////////////
function CE_GravityMove takes real Magnetism, real Radian, real Angle, real Angle2, real x, real y, real x2, real y2, real z, integer index returns nothing
    //Creates locals
    local location p
   
    //Setting the new locations X and Y for this instance
    set x2 = x + udg_CE_XVelocity[index]
    set y2 = y + udg_CE_YVelocity[index]
    set p = Location(x2,y2)
    //Calculating the new velocities (will be used next time this runs)
    set udg_CE_ZVelocity[index] = udg_CE_ZVelocity[index] + ((Magnetism / Radian) * CE_TimerSpeed()) * Sin(Angle2)
    set udg_CE_XVelocity[index] = udg_CE_XVelocity[index] + ((Magnetism / Radian) * CE_TimerSpeed()) * Cos(Angle) * Cos(Angle2)
    set udg_CE_YVelocity[index] = udg_CE_YVelocity[index] + ((Magnetism / Radian) * CE_TimerSpeed()) * Sin(Angle) * Cos(Angle2)
   
    //Makes sure the new location is within the map bounds
    if ((GetRectMinX(bj_mapInitialPlayableArea) <= GetLocationX(p)) and (GetLocationX(p) <= GetRectMaxX(bj_mapInitialPlayableArea)) and (GetRectMinY(bj_mapInitialPlayableArea) <= GetLocationY(p)) and (GetLocationY(p) <= GetRectMaxY(bj_mapInitialPlayableArea))) then
        call SetUnitX(udg_CE_UnitIndex[index], x2)
        call SetUnitY(udg_CE_UnitIndex[index], y2)
    endif
    //Removes the location
    call RemoveLocation(p)
    //Sets the correct fly height
    call SetUnitFlyHeight(udg_CE_UnitIndex[index], udg_CE_CurrentZ[index] - z, 0.00)
   
    //Nulling the variable
    set p = null
   
endfunction

////////////////////////////////////////////////////////////////////
//  Function used to detect if projectiles have crashed into      //
//  the ground and therefore need to either deal damage or be     //
//  damaged depending on what type of unit they are (unit or      //
//  chaos entity)                                                 //
////////////////////////////////////////////////////////////////////
function CE_ProjectileImpactDetection takes real z, real x, real y, integer index returns nothing
    //Creates locals
    local unit u
    local player pl
   
    //Checks if there has been a crash
    if (udg_CE_CurrentZ[index] - z < 5.00) then
        //Yes it crashed, deassociating the unit
        set udg_CE_StageID[index] = 4
        set udg_CE_Portal[index] = null
        set pl = GetOwningPlayer(udg_CE_OriginalCaster[index])
       
        if (GetUnitTypeId(udg_CE_UnitIndex[index]) == CE_DummyID()) then
            call DestroyEffect(udg_CE_CurrentEffect[index])
            //Select Units to damage
            call GroupEnumUnitsInRange(udg_CE_TempGroup2, x, y, CE_ChaosEntityAOE(), null)              
               
            loop
                //Scanning through
                set u = FirstOfGroup(udg_CE_TempGroup2)
                exitwhen u == null
                call CE_TargetFilter(u, pl)
                call GroupRemoveUnit(udg_CE_TempGroup2, u)
                   
                //Select all the units which are to be damaged
                if (IsUnitInGroup(u, udg_CE_TempGroup)) then
                    //Dealing health and mana damage
                    call UnitDamageTarget(udg_CE_OriginalCaster[index], u, udg_CE_HealthDamage[index], true, false, CE_ChaosEntityAttackType(), CE_ChaosEntityDamageType(), CE_ChaosEntityWeaponType())
                    call SetUnitState(u, UNIT_STATE_MANA, (GetUnitState(u,UNIT_STATE_MANA) - udg_CE_ManaDamage[index]))
                    call GroupRemoveUnit(udg_CE_TempGroup, u)
                endif
                   
            endloop
                   
            //Removes the projectile
            call KillUnit(udg_CE_UnitIndex[index])                
        else
            //Dealing health and mana damage
            call UnitDamageTarget(udg_CE_OriginalCaster[index], udg_CE_UnitIndex[index], udg_CE_HealthDamage[index], true, false, CE_MainAttackType(), CE_MainDamageType(), CE_MainWeaponType())
            call SetUnitState(udg_CE_UnitIndex[index], UNIT_STATE_MANA, (GetUnitState(udg_CE_UnitIndex[index],UNIT_STATE_MANA) - udg_CE_ManaDamage[index]))
            //Allowing the unit to be reselected as a target for another instance
            call GroupRemoveUnit(udg_CE_EffectedUnits, udg_CE_UnitIndex[index])
            //Enabling the unit's pathing again
            call SetUnitPathing(udg_CE_UnitIndex[index], true )
        endif
               
    endif
    
    //Nulls variables 
    set u = null
    set pl = null      
endfunction

////////////////////////////////////////////////////////////////////
//  Function used to clear instances of portals (when a portal    //
//  ends or if a new instance is casted when one is already       //
//  active, unit moves, etc.)                                     //
////////////////////////////////////////////////////////////////////
function CE_EndPortal takes unit u returns nothing
    //Creating local
    local integer index = 0
    //Deassociating all the units involves with this unit (will allow units and projectiles to fall)
    loop
        set index = index + 1
        exitwhen index > udg_CE_MaxIndex
            
        //Finds units with association to the eliminator unit (either the caster or the portal)
        if (udg_CE_OriginalCaster[index] == u) then
            set udg_CE_Portal[index] = null
            
            //Finds portal edges
            if (udg_CE_StageID[index] == 7) then
                //Removes those edges
                set udg_CE_StageID[index] = 4
                call DestroyEffect(udg_CE_CurrentEffect[index])
            elseif (udg_CE_StageID[index] != 4) then
                //Everything else
                set udg_CE_StageID[index] = 3
            endif
               
        endif
               
    endloop
  
    //Nulling variables
    set u = null
endfunction

////////////////////////////////////////////////////////////////////
//  Function used to register new units (projectiles and          //
//  affected units) into the array so that the behave properly    //
////////////////////////////////////////////////////////////////////
function CE_RegisterUnit takes integer index, real z, real x2, real y2, unit u, real YVel, real XVel, real ZVel returns nothing
    //Sets up data for the next magnetised unit
    local location p2
    set p2 = Location(x2, y2)
    set udg_CE_LaunchZ[udg_CE_MaxIndex] = GetLocationZ(p2)
    set udg_CE_TargetZ[udg_CE_MaxIndex] = z
    call RemoveLocation(p2)
   
    //Sets up data for caster and portal it's being pulled into
    set udg_CE_OriginalCaster[udg_CE_MaxIndex] = udg_CE_OriginalCaster[index]
    set udg_CE_Portal[udg_CE_MaxIndex] = udg_CE_UnitIndex[index]
    set udg_CE_AOE[udg_CE_MaxIndex] = udg_CE_AOE[index]
    set udg_CE_CasterX[udg_CE_MaxIndex] = udg_CE_CasterX[index]
    set udg_CE_CasterY[udg_CE_MaxIndex] = udg_CE_CasterY[index]
                       
    //Sets up the magnetism
    set udg_CE_MagnetismStrength[udg_CE_MaxIndex] = udg_CE_MagnetismStrength[index]
    set udg_CE_CurrentZ[udg_CE_MaxIndex] = GetUnitFlyHeight(u) + udg_CE_LaunchZ[udg_CE_MaxIndex]
    set udg_CE_YVelocity[udg_CE_MaxIndex] = YVel                      
    set udg_CE_XVelocity[udg_CE_MaxIndex] = XVel
    set udg_CE_ZVelocity[udg_CE_MaxIndex] = ZVel
   
    //Nulls variables
    set u = null
    set p2 = null
   
endfunction

////////////////////////////////////////////////////////////////////
//  Main looping function, controls things from the magnetism     //
//  of the portal to the damage and projectile control within     //
//  the Chaos Rip                                                 //
////////////////////////////////////////////////////////////////////
function CE_Loop takes nothing returns nothing
    //Setting up the local variables
    local integer index = 0
    local integer secondaryindex = 0
    local real x
    local real x2
    local real y
    local real y2
    local real z
    local real z2
    local real dx
    local real dy
    local real Dist
    local real Angle
    local real Angle2
    local real Magnetism
    local real Radian
    local player pl
    local unit u
    local location p
   
    //Loops through all the units within the system
    loop
        set index = index + 1
        exitwhen index > udg_CE_MaxIndex
        set x = GetUnitX(udg_CE_UnitIndex[index])
        set y = GetUnitY(udg_CE_UnitIndex[index])
         
        //Note: Stages are arranged in order of most used (for efficiency)
        //      They are numbered in order of appearence in an instance
        //Finds units which are to be effected by the magnetism
        if (udg_CE_StageID[index] == 2) then
            //Initialises Magnetism factors
            set x2 = GetUnitX(udg_CE_Portal[index])
            set y2 = GetUnitY(udg_CE_Portal[index])
            //Sets up this instance of the movement
            set udg_CE_CurrentZ[index] = udg_CE_CurrentZ[index] + udg_CE_ZVelocity[index]
           
            //Sets up calculating the next movement
            set p = Location(x, y)
            set z = GetLocationZ(p)
            call RemoveLocation(p)
            set dy = y2 - y
            set dx = x2 - x
            set Dist = SquareRoot(dx * dx + dy * dy)
            set Angle = Atan2(dy, dx)
            set Angle2 = Atan2(udg_CE_TargetZ[index] - udg_CE_CurrentZ[index], Dist)
            set Radian = SquareRoot((dx * dx) + (dy * dy) + (udg_CE_TargetZ[index] - udg_CE_CurrentZ[index]) * (udg_CE_TargetZ[index] - udg_CE_CurrentZ[index]))
            //Calculates the magnetism strength for this instance
            set Magnetism = udg_CE_MagnetismStrength[index] * (Dist / CE_MagnetismDecay())

            if (Dist > udg_CE_AOE[index]) or (GetUnitCurrentOrder(udg_CE_OriginalCaster[index]) != CE_Order()) or (GetUnitX(udg_CE_OriginalCaster[index]) != udg_CE_CasterX[index]) or (GetUnitY(udg_CE_OriginalCaster[index]) != udg_CE_CasterY[index]) then
                set udg_CE_StageID[index] = 3
            endif
           
            //Checks if the unit or entity have crashed
            call CE_ProjectileImpactDetection(z, x, y, index)
            
            //Moves the unit or entity around the Portal
            call CE_GravityMove(Magnetism, Radian, Angle, Angle2, x, y, x2, y2, z, index)

            //Checks if the unit is an entity - if it is, then setting its animation and facing direction
            if (GetUnitTypeId(udg_CE_UnitIndex[index]) == CE_DummyID()) then
                call SetUnitAnimationByIndex(udg_CE_UnitIndex[index], R2I(Atan2(udg_CE_ZVelocity[index], SquareRoot((udg_CE_XVelocity[index] * udg_CE_XVelocity[index]) + (udg_CE_YVelocity[index] * udg_CE_YVelocity[index]))) * bj_RADTODEG + 0.5) + 90)
                call SetUnitFacing(udg_CE_UnitIndex[index], Angle * bj_RADTODEG)
            endif

        //Finds units which are falling out of the sky
        elseif (udg_CE_StageID[index] == 3) then
            set p = Location(x, y)
            set z = GetLocationZ(p)
            set x2 = x + udg_CE_XVelocity[index]
            set y2 = y + udg_CE_YVelocity[index]  
            set udg_CE_ZVelocity[index] = udg_CE_ZVelocity[index] - CE_Gravity()
            set udg_CE_CurrentZ[index] = udg_CE_CurrentZ[index] + udg_CE_ZVelocity[index]

            //Makes sure the projectile or unit does not leave the map bounds (may look a bit odd but is necessary)
            if ((GetRectMinX(bj_mapInitialPlayableArea) <= GetLocationX(p)) and (GetLocationX(p) <= GetRectMaxX(bj_mapInitialPlayableArea)) and (GetRectMinY(bj_mapInitialPlayableArea) <= GetLocationY(p)) and (GetLocationY(p) <= GetRectMaxY(bj_mapInitialPlayableArea))) then
                call SetUnitX(udg_CE_UnitIndex[index], x2)
                call SetUnitY(udg_CE_UnitIndex[index], y2)
            endif
           
            call RemoveLocation(p)
            call SetUnitFlyHeight(udg_CE_UnitIndex[index],  udg_CE_CurrentZ[index] - z, 0.00)
   
            call CE_ProjectileImpactDetection(z, x, y, index)

            set Angle = Atan2(y2 - y, x2 - x)
            if (GetUnitTypeId(udg_CE_UnitIndex[index]) == CE_DummyID()) then
                call SetUnitAnimationByIndex(udg_CE_UnitIndex[index], R2I(Atan2(udg_CE_ZVelocity[index], SquareRoot((udg_CE_XVelocity[index] * udg_CE_XVelocity[index]) + (udg_CE_YVelocity[index] * udg_CE_YVelocity[index]))) * bj_RADTODEG + 0.5) + 90)
                call SetUnitFacing(udg_CE_UnitIndex[index], Angle * bj_RADTODEG)
            endif

       //Finds units which are initial portals of an instance
        elseif (udg_CE_StageID[index] == 1) then
            if (GetUnitCurrentOrder(udg_CE_OriginalCaster[index]) != CE_Order())  or (GetUnitX(udg_CE_OriginalCaster[index]) != udg_CE_CasterX[index]) or (GetUnitY(udg_CE_OriginalCaster[index]) != udg_CE_CasterY[index]) then
                set udg_CE_StageID[index] = 4
                call DestroyEffect(udg_CE_CurrentEffect[index])
                call CE_EndPortal(udg_CE_OriginalCaster[index])
            else
                //Initialising data and increasing the portal size
                set p = Location(x, y)
                set z = GetLocationZ(p) + CE_PortalHeight()
                set u = udg_CE_UnitIndex[index]
                call RemoveLocation (p)
                set udg_CE_CurrentSize[index] = udg_CE_CurrentSize[index] + udg_CE_GrowthRate[index]
                set pl = GetOwningPlayer(udg_CE_OriginalCaster[index])
                call SetUnitScale(udg_CE_UnitIndex[index], udg_CE_CurrentSize[index], 0.00, 0.00)


                if (udg_CE_CurrentProjectileDelay[index] > CE_ChaosEntityRate()) then
                    //Creating New projectile wave
                    set Angle = 0
                    //Reset the delay timer
                    set udg_CE_CurrentProjectileDelay[index] = 0.00

                    loop
                        //Calculating position and initialising
                        set Angle = Angle + (360.00 / udg_CE_ChaosEntityCount[index])
                        set secondaryindex = secondaryindex + 1
                        set x2 = x + CE_AOECentral() * Cos(Angle * bj_DEGTORAD)
                        set y2 = y + CE_AOECentral() * Sin(Angle * bj_DEGTORAD)
                        set udg_CE_MaxIndex = udg_CE_MaxIndex + 1
                        set udg_CE_UnitIndex[udg_CE_MaxIndex] = CreateUnit(Player(14), CE_DummyID(), x2, y2, Angle)
                        set udg_CE_CurrentEffect[udg_CE_MaxIndex] = AddSpecialEffectTarget(CE_ChaosEntityModel(), udg_CE_UnitIndex[udg_CE_MaxIndex], "origin")
                        set udg_CE_HealthDamage[udg_CE_MaxIndex] = CE_ChaosEntityHealthDamageBase() + (CE_ChaosEntityHealthDamagePerLevel() * udg_CE_rLevel[index])
                        set udg_CE_ManaDamage[udg_CE_MaxIndex] = CE_ChaosEntityManaDamageBase() + (CE_ChaosEntityManaDamagePerLevel() * udg_CE_rLevel[index])
                        set udg_CE_CurrentDeathTimer[udg_CE_MaxIndex] = 0.00
                        set udg_CE_StageID[udg_CE_MaxIndex] = 2
                        set udg_CE_Portal[udg_CE_MaxIndex] = u
                        //Makes terrain height changing possible if not already
                        if UnitAddAbility(udg_CE_UnitIndex[udg_CE_MaxIndex], 'Amrf') and UnitRemoveAbility(udg_CE_UnitIndex[udg_CE_MaxIndex], 'Amrf') then
                        endif
                           
                        //Setting up data of the new magnetised unit
                        call CE_RegisterUnit(index, z, x2, y2, u, 0.00, 0.00, CE_ChaosEntityZControl())
           
                        //Applying Aesthetics
                        call SetUnitScale(udg_CE_UnitIndex[udg_CE_MaxIndex],  CE_ChaosEntityScaleBase() + (CE_ChaosEntityScalePerLevel() * udg_CE_rLevel[index]), 0.00, 0.00)
                        call SetUnitFlyHeight(udg_CE_UnitIndex[udg_CE_MaxIndex], CE_PortalHeight(), 0.00)
                        call SetUnitAnimationByIndex(udg_CE_UnitIndex[udg_CE_MaxIndex], CE_PortalAngle())

                        call GroupAddUnit(udg_CE_EffectedUnits, udg_CE_UnitIndex[index])
           
                        exitwhen secondaryindex == udg_CE_ChaosEntityCount[index]
                    endloop
                   
                    set secondaryindex = 0
                else
                    //Increase the delay timer on the projectiles
                    set udg_CE_CurrentProjectileDelay[index] = udg_CE_CurrentProjectileDelay[index] + CE_TimerSpeed()
                endif

                if (CE_EffectsUnits()) then
                    call GroupEnumUnitsInRange(udg_CE_TempGroup2, x, y, udg_CE_AOE[index], null)              

                    //Filters through all the units within the range of the portal which can be used as targets
                    loop
                        set u = FirstOfGroup(udg_CE_TempGroup2)
                        exitwhen u == null
                        call CE_TargetFilter(u, pl)
                        call GroupRemoveUnit(udg_CE_TempGroup2, u)
                   
                        //Actions for units which have been found to be viable targets
                        if (IsUnitInGroup(u, udg_CE_TempGroup)) and (not IsUnitInGroup(u, udg_CE_EffectedUnits)) then
                            //Data initialisation
                            set x2 = GetUnitX(u)
                            set y2 = GetUnitY(u)
                            set dx = x2 - x
                            set dy = y2 - y
                            set Angle = Atan2(dy, dx)
                            set Dist = SquareRoot(dx * dx + dy * dy)
                            set udg_CE_MaxIndex = udg_CE_MaxIndex + 1
                            set udg_CE_UnitIndex[udg_CE_MaxIndex] = u
                            set udg_CE_CurrentDeathTimer[udg_CE_MaxIndex] = 0.00
                            set udg_CE_HealthDamage[udg_CE_MaxIndex] = udg_CE_HealthDamage[index]
                            set udg_CE_ManaDamage[udg_CE_MaxIndex] = udg_CE_ManaDamage[index]
                       
                            //Makes terrain height changing possible if not already
                            if UnitAddAbility(udg_CE_UnitIndex[udg_CE_MaxIndex], 'Amrf') and UnitRemoveAbility(udg_CE_UnitIndex[udg_CE_MaxIndex], 'Amrf') then
                            endif
                           
                            call SetUnitPathing(u, false )
                            set udg_CE_StageID[udg_CE_MaxIndex] = 2
                            //Sets up data for the next magnetised unit
                            call CE_RegisterUnit(index, z, x2, y2, u, 0.00, 0.00, 6.00)

                            //Makes this unit unselectable as a target until the end of this spell instance
                            call GroupAddUnit(udg_CE_EffectedUnits, u)
                            call GroupRemoveUnit(udg_CE_TempGroup, u)
                        endif

                    endloop
                   
                endif        

            endif
           
        //Finds units which need to be recycled
        elseif (udg_CE_StageID[index] == 4) then
       
            //Checks if the death timer has expired
            if (udg_CE_CurrentDeathTimer[index] >= CE_DeathTimer()) then
           
                set udg_CE_CurrentDeathTimer[index] = 0.00
               
                //Removing projectiles from the game
                if (GetUnitTypeId(udg_CE_UnitIndex[index]) == CE_DummyID()) then
                    call RemoveUnit(udg_CE_UnitIndex[index])
                endif  
               
                //Recycling the instance of the spell
                set udg_CE_AOE[index] = udg_CE_AOE[udg_CE_MaxIndex]
                set udg_CE_CasterX[index] = udg_CE_CasterX[udg_CE_MaxIndex]
                set udg_CE_CasterY[index] = udg_CE_CasterY[udg_CE_MaxIndex]
                set udg_CE_ChaosEntityCount[index] = udg_CE_ChaosEntityCount[udg_CE_MaxIndex]
                set udg_CE_CurrentDeathTimer[index] = udg_CE_CurrentDeathTimer[udg_CE_MaxIndex]
                set udg_CE_CurrentEffect[index] = udg_CE_CurrentEffect[udg_CE_MaxIndex]
                set udg_CE_CurrentProjectileDelay[index] = udg_CE_CurrentProjectileDelay[udg_CE_MaxIndex]
                set udg_CE_CurrentSize[index] = udg_CE_CurrentSize[udg_CE_MaxIndex]
                set udg_CE_CurrentZ[index] = udg_CE_CurrentZ[udg_CE_MaxIndex]
                set udg_CE_GrowthRate[index] = udg_CE_GrowthRate[udg_CE_MaxIndex]
                set udg_CE_HealthDamage[index] = udg_CE_HealthDamage[udg_CE_MaxIndex]
                set udg_CE_LaunchZ[index] = udg_CE_LaunchZ[udg_CE_MaxIndex]
                set udg_CE_MagnetismStrength[index] = udg_CE_MagnetismStrength[udg_CE_MaxIndex]
                set udg_CE_ManaDamage[index] = udg_CE_ManaDamage[udg_CE_MaxIndex]
                set udg_CE_OriginalCaster[index] = udg_CE_OriginalCaster[udg_CE_MaxIndex]
                set udg_CE_Portal[index] = udg_CE_Portal[udg_CE_MaxIndex]
                set udg_CE_StageID[index] = udg_CE_StageID[udg_CE_MaxIndex]
                set udg_CE_TargetZ[index] = udg_CE_TargetZ[udg_CE_MaxIndex]
                set udg_CE_UnitIndex[index] = udg_CE_UnitIndex[udg_CE_MaxIndex]
                set udg_CE_XVelocity[index] = udg_CE_XVelocity[udg_CE_MaxIndex]
                set udg_CE_YVelocity[index] = udg_CE_YVelocity[udg_CE_MaxIndex]
                set udg_CE_ZVelocity[index] = udg_CE_ZVelocity[udg_CE_MaxIndex]
                set udg_CE_iLevel[index] = udg_CE_iLevel[udg_CE_MaxIndex]
                set udg_CE_rLevel[index] = udg_CE_rLevel[udg_CE_MaxIndex]
                set udg_CE_MaxIndex = udg_CE_MaxIndex - 1
                set index = index - 1
               
                //Stopping the timer if there are no more instances to run
                if (udg_CE_MaxIndex == 0) then
                    call DestroyTimer(GetExpiredTimer())
                endif

            else
                //If the death timer has not expired, increase how long it's been running
                set udg_CE_CurrentDeathTimer[index] = udg_CE_CurrentDeathTimer[index] + CE_TimerSpeed()
            endif
           
        endif
       
    endloop
   
    //Nulls variables
    set u = null
    set p = null
   
endfunction

////////////////////////////////////////////////////////////////////
//  Function ran to create a new instance of the spell, inits a   //
//  portal, giving it the starting information it requires        //
////////////////////////////////////////////////////////////////////
function TrigCE_AllocateData takes nothing returns boolean
    // Sets up the variables required for creating units
    local unit u
    local integer index
    local integer iLevel
    local real rLevel
    local real x
    local real x2
    local real y
    local real y2
    local real Angle
   
    // Checks if the ability casted was the correct one
    if (GetSpellAbilityId() == CE_SpellID()) then
        //Assigning data to locals
        set u = GetTriggerUnit()
        set iLevel = GetUnitAbilityLevel(u, CE_SpellID())
        set rLevel = R2I(iLevel)
        set x = GetSpellTargetX()
        set x2 = GetUnitX(u)
        set y = GetSpellTargetY()
        set y2 = GetUnitY(u)
        set Angle = 0.00
         
        //Ends all previous instances of the spell associated with the unit                
        call CE_EndPortal(u)

        // Initialises  new spell instance
        set udg_CE_MaxIndex = udg_CE_MaxIndex + 1
        set udg_CE_UnitIndex[udg_CE_MaxIndex] = CreateUnit(Player(14), CE_DummyID(), x, y, Atan2(y - y2, x - x2))
        set udg_CE_AOE[udg_CE_MaxIndex] = CE_AOEBase() + (CE_AOEPerLevel() * rLevel)
        set udg_CE_CurrentEffect[udg_CE_MaxIndex] = AddSpecialEffectTarget(CE_PortalModel(), udg_CE_UnitIndex[udg_CE_MaxIndex], "origin")
        set udg_CE_MagnetismStrength[udg_CE_MaxIndex] = CE_MagnetismBase() + (CE_MagnetismPerLevel() * rLevel)
        set udg_CE_GrowthRate[udg_CE_MaxIndex] = CE_PortalGrowthRateBase() + (CE_PortalGrowthRatePerLevel() * rLevel)
        set udg_CE_ChaosEntityCount[udg_CE_MaxIndex] = CE_ChaosEntityCountBase() + (CE_ChaosEntityCountPerLevel() * iLevel)
        set udg_CE_CurrentSize[udg_CE_MaxIndex]= CE_PortalStartScale()
        set udg_CE_CurrentProjectileDelay[udg_CE_MaxIndex] = 0.00
        set udg_CE_CurrentDeathTimer[udg_CE_MaxIndex] = 0.00
        set udg_CE_OriginalCaster[udg_CE_MaxIndex] = u
        set udg_CE_CasterX[udg_CE_MaxIndex] = x2
        set udg_CE_CasterY[udg_CE_MaxIndex] = y2
        set udg_CE_Portal[udg_CE_MaxIndex] = null
        set udg_CE_iLevel[udg_CE_MaxIndex] = iLevel
        set udg_CE_rLevel[udg_CE_MaxIndex] = rLevel
        set udg_CE_StageID[udg_CE_MaxIndex] = 1
        set udg_CE_HealthDamage[udg_CE_MaxIndex] = CE_HealthDamageBase() + (CE_HealthDamagePerLevel() * rLevel)
        set udg_CE_ManaDamage[udg_CE_MaxIndex] = CE_ManaDamageBase() + (CE_ManaDamagePerLevel() * rLevel)
       
        //Makes terrain height changing possible if not already
        if UnitAddAbility(udg_CE_UnitIndex[udg_CE_MaxIndex], 'Amrf') and UnitRemoveAbility(udg_CE_UnitIndex[udg_CE_MaxIndex], 'Amrf') then
        endif
       
        //Sets up the aesthetics of the portal
        call SetUnitScale(udg_CE_UnitIndex[udg_CE_MaxIndex], udg_CE_CurrentSize[udg_CE_MaxIndex], 0.00, 0.00)
        call SetUnitFlyHeight(udg_CE_UnitIndex[udg_CE_MaxIndex], CE_PortalHeight(), 0.00)
        call SetUnitAnimationByIndex(udg_CE_UnitIndex[udg_CE_MaxIndex], CE_PortalAngle())
       
        //If no timer is currently running (Max Index was 0 before this) create a new one
        if (udg_CE_MaxIndex == 1) then
            call TimerStart(CreateTimer(), CE_TimerSpeed(), true, function CE_Loop)
        endif
       
        set u = udg_CE_UnitIndex[udg_CE_MaxIndex]
       
        //Creating Aesthetic portal boarder
        loop
            //Calculating position and initialising
            set Angle = Angle + (360.00 / CE_PortalBoarderSpaceTakenPerSegment())
            set x2 = x + CE_AOECentral() * Cos(Angle * bj_DEGTORAD)
            set y2 = y + CE_AOECentral() * Sin(Angle * bj_DEGTORAD)
            set udg_CE_MaxIndex = udg_CE_MaxIndex + 1
            set udg_CE_UnitIndex[udg_CE_MaxIndex] = CreateUnit(Player(14), CE_DummyID(), x2, y2, Angle)
            set udg_CE_CurrentEffect[udg_CE_MaxIndex] = AddSpecialEffectTarget(CE_PortalBoarderModel(), udg_CE_UnitIndex[udg_CE_MaxIndex], "origin")
            set udg_CE_OriginalCaster[udg_CE_MaxIndex] = GetTriggerUnit()
            set udg_CE_CurrentDeathTimer[udg_CE_MaxIndex] = 0.00
            set udg_CE_StageID[udg_CE_MaxIndex] = 7
            set udg_CE_Portal[udg_CE_MaxIndex] = u

            //Makes terrain height changing possible if not already
            if UnitAddAbility(udg_CE_UnitIndex[udg_CE_MaxIndex], 'Amrf') and UnitRemoveAbility(udg_CE_UnitIndex[udg_CE_MaxIndex], 'Amrf') then
            endif
           
            //Applying Aesthetics
            call SetUnitScale(udg_CE_UnitIndex[udg_CE_MaxIndex],  CE_PortalBoarderScale(), 0.00, 0.00)
            call SetUnitFlyHeight(udg_CE_UnitIndex[udg_CE_MaxIndex], CE_PortalBoarderHeight(), 0.00)
            call SetUnitAnimationByIndex(udg_CE_UnitIndex[udg_CE_MaxIndex], CE_PortalAngle())
           
            exitwhen Angle >= 360.00
        endloop
       
    endif
   
    //Nulls variables
    set u = null
    return false
   
endfunction

////////////////////////////////////////////////////////////////////
//  Function used to start up the spell, initialises events       //
//  and conditions needed for the spell to run correctly          //
////////////////////////////////////////////////////////////////////
function InitTrig_CE_ChaosEnvoy takes nothing returns nothing
    local trigger CE = CreateTrigger()
    local integer index = 0

    //Initialise the event for every player
    loop
        call TriggerRegisterPlayerUnitEvent(CE, Player(index), EVENT_PLAYER_UNIT_SPELL_EFFECT, null)
        set index = index + 1
        exitwhen index == bj_MAX_PLAYER_SLOTS
    endloop
   
    call TriggerAddCondition(CE, Condition(function TrigCE_AllocateData))
   
    //Nulls variables
    set CE = null
   
endfunction


Information:
Pure JASS ~ 1200 lines (including readme and configuration)
Runs on standard World Editor without compile errors on saving
Large configuration to modify pretty much every attribute involved with the spell.
Physics galore
Fully MUI, Recycles correctly

Incase anybody is wondering/thinks it's a mistake: having a differnet look (different spread over terrain, etc.) when casted on uneven terrain is an -intended feature- of the spell, which I deeply adore for the spice and fun little patterns it creates

Comes with a variable creator to help with importing to standard world editors


  • Variable Creator
    • Events
    • Conditions
    • Actions
      • Set CE_AOE[0] = 0.00
      • Set CE_CasterX[0] = 0.00
      • Set CE_CasterY[0] = 0.00
      • Set CE_ChaosEntityCount[0] = 0
      • Set CE_CurrentDeathTimer[0] = 0.00
      • Set CE_CurrentEffect[0] = CE_CurrentEffect[0]
      • Set CE_CurrentProjectileDelay[0] = 0.00
      • Set CE_CurrentSize[0] = 0.00
      • Set CE_CurrentZ[0] = 0.00
      • Set CE_EffectedUnits = CE_EffectedUnits
      • Set CE_GrowthRate[0] = 0.00
      • Set CE_HealthDamage[0] = 0.00
      • Set CE_LaunchZ[0] = 0.00
      • Set CE_MagnetismStrength[0] = 0.00
      • Set CE_ManaDamage[0] = 0.00
      • Set CE_MaxIndex = 0
      • Set CE_OriginalCaster[0] = CE_OriginalCaster[0]
      • Set CE_Portal[0] = CE_Portal[0]
      • Set CE_StageID[0] = 0
      • Set CE_TargetZ[0] = 0.00
      • Set CE_TempGroup = CE_TempGroup
      • Set CE_TempGroup2 = CE_TempGroup2
      • Set CE_UnitIndex[0] = CE_UnitIndex[0]
      • Set CE_XVelocity[0] = 0.00
      • Set CE_YVelocity[0] = 0.00
      • Set CE_ZVelocity[0] = 0.00
      • Set CE_iLevel[0] = 0
      • Set CE_rLevel[0] = 0.00


WIPS:
http://www.hiveworkshop.com/forums/...t-10-what-lies-other-side-233773/#post2328013
http://www.hiveworkshop.com/forums/...ies-other-side-233773/index3.html#post2328512
http://www.hiveworkshop.com/forums/...ies-other-side-233773/index5.html#post2329215
http://www.hiveworkshop.com/forums/...ies-other-side-233773/index5.html#post2329389
http://www.hiveworkshop.com/forums/...ies-other-side-233773/index6.html#post2329748
http://www.hiveworkshop.com/forums/...ies-other-side-233773/index7.html#post2329904

Screenshots (and a slightly jolty GIF)



 

Attachments

  • Chaos Envoy V1.00.w3x
    101 KB · Views: 89
Last edited:
Level 20
Joined
Apr 14, 2012
Messages
2,901
Right, making my entry post, any updates will be done on this post:

Spell: Chaos Envoy

Description:
Chaos Envoy
The caster reaches out to the heart of the twisting nether, creating a portal leaking chaotic entities and pulling nearby enemy units violently towards it; damaging them with crushing force. When the portal closes, all affected units and entities fall back to the ground.

Level 1 - 250 Crush damage, 70 Entity damage
Level 2 - 350 Crush damage, 90 Entity damage
Level 3 - 450 Crush damage, 110 Entity damage


JASS:
////////////////////////////////////////////////////////////////////
//                    CHAOS ENVOY V1.00                           //
//                                                                //
//  Author: Tank-Commander                                        //
//  Requires: Dummy.mdl                                           //
//  Purpose: Hero Ultimate, very powerful manipulation ability    //
//                                                                //
//  Notes:                                                        //
//    -  It's a channeling spell                                  //
//    -  Read the readme before you try modifying the config      //
//    -  Use the "Helpful files" to help you import the spell     //
//                                                                //
//  Credits:                                                      //
//    -  (Dummy.mdl) Vexorian                                     //    
////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////
//  Chaos Envoy README                                            //
//                                                                //
//  This spell has a lot to configure so this readme will help    //
//  you set up your own Chaos Envoy spell to your liking          //
//  please read this through -fully- before attempting to change  //
//  the configuration                                             //
//                                                                //
//  If your editor does not automatically create variables for    //
//  JASS resources, please enable "automatically create unknown   //
//  variables while pasting trigger data" in the following path:  //
//  File -> Preferences ->  General                               //
//                                                                //
//  Once that is enabled, paste in the Variable Creator           //
//  (it can be deleted afterwards, it's just to create variables  //
//  and serves no other purpose)                                  //
//                                                                //
//  Contents:                                                      //
//                                                                //
//    1-- Setting SpellID and DummyID                             //
//    2-- Timer and Order                                         //
//    3-- AOE                                                     //
//    4-- Magnetism                                               //
//    5-- Aesthetics                                              //
//    6-- Main Damage                                             //
//    7-- Chaos Entity control                                    //
//    8-- Chais Entity damage                                     //
//    9-- Gravity, terrain and units                              //
//   10-- Attack, Damage, and weapon types                        //
//                                                                //
//                                                                //
//-------------------------------1--------------------------------//
//  Setting SpellID and DummyID:                                  //
//    To do this, find the spell you wish to set as the dummy     //
//    (or unit) then, find the data value of the spell/unit       //
//    if your editor is not already displaying data values then   //
//    you can enable the display by pressing Ctrl + D             //
//    before you panic, pressing Ctrl + D again, will revert the  //
//    the data value you're looking for will be in the unit       //
//    box in the object editor it should look like something      //
//    like this: u000                                             //
//                                                                //
//    there may be something after that like :uloc and then the   //
//    actual name in brackets, but you want this four character   //
//    code. To set it remeber the code and put it between         //
//    these two characters: ' '                                   //
//    e.g.:                                                       //
//      'u000'                                                    //
//                                                                //
//    Now, you can take that, and place it in the respective ID   //
//    return function the line should look like this:             //
//      return 'u000'                                             //
//                                                                //
//    When you have completed this you are ready to move on to    //
//    the next part.                                              //
//                                                                //
//-------------------------------2--------------------------------//
//  Timer and Order:                                              //
//    This spell has two timers and one order, one of the timers  //
//    is for how fast the loop runs, the other, is how long       //
//    after a unit is removed, is the instance recycled           //
//    (it has a timer so that death effects can play)             //
//                                                                //
//    The first timer, will need to be set to something low       //
//    but not below 0.03 to prevent lag, setting it to            //
//    something high (above 0.05) may remove some of the          //
//    smoothness of the effects, it's recommended that you leave  //
//    the value at 0.03, but you may wish to change it            //
//                                                                //
//    The second timer, can technically be any number you like    //
//    and in most cases, it won't make any difference provided    //
//    it's over a second, and if not, the only change is that     //
//    some effects to not display properly due to the unit being  //
//    removed before they finish playing, it is in seconds        //
//    so 1.00 == 1 second, pretty simple and straightforward      //
//                                                                //
//    The order: This is a bit more complex though still fairly   //
//    straightforward, find your spell in the object editor       //
//    you're looking for "Text - Order string - Use/turn on"      //
//    in most cases this should be "channel" because the spell    //
//    needs to be channeled to word, but if you want to change    //
//    it you can, though it's not recommended                     //
//                                                                //
//-------------------------------3--------------------------------//
//  AOE:                                                          //
//    The AOE configurables essentially control the area of the   //
//    magnetism, rather than the spread of the projectiles        //
//    as for the projectiles, that will be covered later          //
//    for now, this section will focus on the magnetism AOE       //
//                                                                //
//    The AOE controls how far away from the portal you can be    //
//    and still be affected by it's AOE, if a unit leaves the     //
//    portal AOE, then it will be dropped by the portal           //
//    The AOE variables ought to manage to keep the projectiles   //
//    within the portal, if it is too small in relation to the    //
//    other factors, the entities will also fall out, as well as  //
//    any units which were taken for the ride                     //
//                                                                //
//    "AOE Central" referrs to the boarders and how far they are  //
//    from the middle of the portal (also how far the entities    //
//    are created from the middle) experimenting with that may    //
//    give some interesting results, but remember the default     //
//    value of 100.00                                             //
//                                                                //
//-------------------------------4--------------------------------//
//  Magnetism:                                                    //
//    The Magnetism values need to be high,the base value should  //
//    be at least 10000.00 for it work correctly, having too      //
//    much magnetism (80000+) may cause some unforseen effects    //
//    Like units flying out of the top of the Map Z height, so    //
//    it's not really recommended (though you never know)         //
//    the increment can be anything really, the magnetism itself  //
//    will however alter the spread of the projectiles and units  //
//    if it is changed, if you want a maintained (or roughly      //
//    maintained pattern) I suggest an increment under 10000.00   //
//                                                                //
//    Magnetism Decay: this works a little differently, unlike    //
//    normal gravity where it is stronger the closer to the       //
//    center, this spell has an inverted gravity, it's stronger   //
//    the further away a unit is, and weaker in the center        //
//    the decay controls how the distance from the target is      //
//    divided up, i.e. the default value is 400                   //
//    say a unit 1200 points apart is in range, the strength of   //
//    the magnetism they experience is:                           //
//      MagnetismStrength * (1200/400) = MagnetismStrength * 3    //
//                                                                //
//    So they experience 3x the normal magnetism strength where   //
//    as if they were at range 400, they'd experience normal      //
//    magnetism, and less if they were even closer than that      //
//                                                                //
//-------------------------------5--------------------------------//
//  Aesthetics:                                                   //
//    There's a large number of aesthetic options available in    //
//    this spell, designed to give the user, the maximum amount   //
//    of options                                                  //
//                                                                //
//    Portal Angle: Controls the pitch angle of the portal, 90    //
//    is the upright position, 0 is on it's side                  //
//    and so on                                                   //
//                                                                //
//    Portal scale: Controls the size of the portal, growing      //
//    rates should be 0.00(i) i.e. 0.005 as to not make the       //
//    the portal grow too large 1 == 100%, 0.001 = 1%             //
//                                                                //
//    Portal Height: Controls how high from the terrain height    //
//    the portal is placed, having a low value here will cause    //
//    projectiles to instantly/quickly hit the ground, and units  //
//    will have lower(or possibly no) arc, will also mean more    //
//    units will be successfully caught by the terrain and not    //
//    pulled if you have TerrainMatters set to true, will also    //
//    effect the AOE of the projectiles (lower to the ground      //
//    means tighter spread, higher up means further apart)        //
//                                                                //
//    Portal/Boarder models: Set these to the model paths of the  //
//    models you desire, if you are getting them from the object  //
//    editor, remember to add a "\" to the pathname everywhere    //
//    there is already one, i.e. "path\path\path.mdl"             //
//    needs to be changed to "path\\path\\path.mdl"               //
//                                                                //
//    Boarder scale works the same way the portal scale does      //
//    so just follow the same steps, 0.25 to 0.50 works well for  //
//    boarders                                                    //
//                                                                //
//    the space taken per segment works in a way that 6.00 means  //
//    you will have 6 boarder pieces, setting to something like   //
//    100.00 will mean 100 segments, a number between 5 and 10    //
//    works well here (as to not flood with effects) keep it      //
//    relative to the scale you set up                            //
//                                                                //
//    Boarder height, again, works in the same way as a portal    //
//    height, should be roughly portal height + 50, but, if it    //
//    better suits your portal model, it can theoretically be     //
//    anything without having any impact to the rest of the       //
//    spell                                                       //
//                                                                //
//    Chaos Entity model: same as the other model sets, with      //
//    the filepaths, also consider that this is a projectile so   //
//    you ought to set it to something which'd work as a          //
//    projectile, like prehaps nether drakes, locusts, rockets    //
//    anything really which isn't a building or a ground unit     //
//                                                                //
//    Chaos Entity scale neednot explain how this works a third   //
//    time                                                        //
//                                                                //
//    Chaos Entity Z control, determines how much Z Velocity      //
//    each entity starts with, this in turn controls how far      //
//    out from the middle it goes and respectively how much       //
//    lower from the middle the projectiles go, setting this to   //
//    0 will mean they maintain their height throughout and do    //
//    not go up/down as normal, default is 6.00, playing around   //
//    with this can have unexpected results, to invert the flow   //
//    use a negative value                                        //
//-------------------------------6--------------------------------//
//  Main Damage:                                                  //
//    These controllers are all for the crush damage dealt by     //
//    units being thrown around by the spell, they do -not-       //
//    effect how much damage each entity does.                    //
//                                                                //
//    All of these are relatively self-explanatory, you can deal  //
//    both health and mana damage with these configurables        //
//    damagetypes/weapontypes/attacktypes are set later which     //
//    will control the multiplyers of all these things            //
//                                                                //
//-------------------------------7--------------------------------// 
//  Chaos Entity Control:                                         //
//    These controllers are primarily for controlling the number  //
//    of chaos entities and how fast they appear                  //
//                                                                //
//    ChaosEntityCount: these controllers determine how many      //
//    leak through the portal each cycle of creation, having      //
//    a number higher than 45 at the max level as that will       //
//    cause lag on most machines (especially if multicasted       //
//    or other similar spells are around) 15 is the default at    //
//    level 3, anything under 30 is a relatively safe number      //
//                                                                //
//    ChaosEntityAOE: Controls how much area each missile covers  //
//    upon impact, anywhere from 50-120 is realistic, try to      //
//    keep it relative to the missile size (if it's large         //
//    150-200 may be more appropriate)                            //
//                                                                //
//    ChaosEntityRate: How long (in seconds) there is between     //
//    cycles of ChaosEntity leaks, 1-2 seconds works pretty well  //
//    remember to change the channelling duration of the spell    //
//    to match this (the longer the duration, the more cycled     //
//    leaks)                                                      //
//                                                                //
//-------------------------------8--------------------------------//
//  Chaos Entity Damage:                                          //
//     Like the other fairly straight forward, health and mana    //
//     damage, base and per level values, does not effect the     //
//     main damage (unit throwing around damage) at all, each     //
//     projectile individually will have this damage, it is not   //
//     relative to the distance from the projectile               //
//                                                                //
//-------------------------------9--------------------------------//
//  Gravity, terrain and units:                                   //
//    These control optional features and projectile fall arcs    //
//                                                                //
//    Gravity: This is the strength of the terrain gravity which  //
//    causes entities and units to fall at a given rate, higher   //
//    means a stronger gravity and the faster projectiles come    //
//    back down, 20 is Low gravity, negative numbers are          //
//    Antigrav (you will crash the map doing this, so don't)      //
//    60+ is high gravity, as such these will alter the spread    //
//    and AOE of your projectiles, as this is what determines     //
//    how fast they come back down                                //
//                                                                //
//    TerrainMatters: This function poses a question, do you      //
//    want terrain to matter, or do you want units pulled from    //
//    wherever they are, regardless of the terrain height they    //
//    at it by relativity, changing this to true or false will    //
//    not alter projectile destruction when falling, though will  //
//    when they're in the portal (none will be destroyed until    //
//    they start falling) true will let units brace against the   //
//    ground to prevent being pulled, false will mean they can't  //
//                                                                //
//    EffectsUnits: This function poses a different question, do  //
//    you want units effected at all, or do you just want your    //
//    flurry of projectiles to be the only means of damage, if    //
//    you don't want units to be effected, it's suggested you     //
//    lower the projectile interval time (or increase the         //
//    channeling time) and increase the damage &/or AOE of your   //
//    spell to still give it that ultimate-level power, except    //
//    if you don't intend to use this ability as an ultimate      //
//                                                                //
//------------------------------10--------------------------------//
//  Attack, Damage, and Weapon types:                             //
//    These features will determine your spells damage            //
//    multiplyers, you have controls for all three of these       //
//    things                                                      //
//                                                                //
//    However, knowing all of these different types takes quite   //
//    a bit of knowledge, however they are listed here to make    //
//    it easier:                                                  //
//                                                                //
//    Attack types all start with "ATTACK_TYPE_"                  //
//    CHAOS, HERO, MAGIC, MELEE, NORMAL, PIERCE, SIEGE            //
//                                                                //
//    Damage types all start with "DAMAGE_TYPE_"                  //
//    ACID, COLD, DEATH, DEFENSIVE, DEMOLITION, DISEASE, DIVINE   //
//    ENHANCED, FIRE, FORCE, LIGHTNING, MAGIC, MIND, NORMAL       //
//    PLANT, POSION, SHADOW_STRIKE, SLOW_POISON, SONIC            //
//    SPIRIT_LINK, UNIVERSAL, UNKNOWN                             //
//                                                                //
//    Weapon types all start with "WEAPON_TYPE_"                  //
//    Then add one of the following types:                        //
//    AXE, CLAW, METAL, ROCK, WOOD.                               //
//    Then add one of the classifications (note, some  types do   //
//    not have any of these)                                      //
//    HEAVY, MEDIUM, LIGHT                                        //
//    Then add one of these:                                      //
//    CHOP, SLICE, BASH, STAB                                     //
//                                                                //
//    Remember to include underscores "_" between each word       //
//    and if you don't care for weapon types, you can always use  //
//    WEAPON_TYPE_WHOKNOWS, or even better: null                  //
//                                                                //
//----------------------------------------------------------------//
//  That concludes the readme for the CHAOS ENVOY spell           //
//  thank you for reading and enjoy the spell                     //
////////////////////////////////////////////////////////////////////
//  Configuration of the spell can be done here, consult the      //
//  readme for more information on how to do this                 //
////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////
//  Controller for the spell to be used as the  //
//  dummy ability and unit as the dummy unit    //
//////////////////////////////////////////////////
constant function CE_SpellID takes nothing returns integer
    return 'A001'
endfunction

constant function CE_DummyID takes nothing returns integer
    return 'u000'
endfunction

//////////////////////////////////////////////////
//  Controller for the timer speed (0.03 is     //
//  the standard timeout)                       //
//////////////////////////////////////////////////
constant function CE_TimerSpeed takes nothing returns real
    return 0.03
endfunction

//////////////////////////////////////////////////
//  Controller for how long a unit lasts        //
//  after it's usefulness has expired           //
//  (mostly for effects to play)                //
//////////////////////////////////////////////////
constant function CE_DeathTimer takes nothing returns real
    return 2.00
endfunction

//////////////////////////////////////////////////
//  Controller for the order attached to the    //
//  Dummy ability                               //
//////////////////////////////////////////////////
constant function CE_Order takes nothing returns integer
    return OrderId("channel")
endfunction

//////////////////////////////////////////////////
//  Controllers for the Portal AOE (magnetism)  //
//  projectiles will ignore this AOE other      //
//  than for staying attached to the portal     //
//  until it disappates, if this value is       //
//  too small, projectiles will "fall out"      //
//////////////////////////////////////////////////
constant function CE_AOEBase takes nothing returns real
    return 250.00
endfunction

constant function CE_AOEPerLevel takes nothing returns real
    return 100.00
endfunction

//////////////////////////////////////////////////
// Controllers for the centre of the portal     //
//////////////////////////////////////////////////
constant function CE_AOECentral takes nothing returns real
    return 100.00
endfunction
//////////////////////////////////////////////////
//  Controllers for the magnetism strength      //
//  of the portal (playing around may give      //
//  odd results)                                //
//////////////////////////////////////////////////
constant function CE_MagnetismBase takes nothing returns real
    return 30000.00
endfunction

constant function CE_MagnetismPerLevel takes nothing returns real
    return 7500.00
endfunction

//////////////////////////////////////////////////
//  Controllerfor the Magnetism decay, this is  //
//  how far from the portal, until a larger     //
//  proportion of magnetism is used             //
//  (exponential)                               //
//////////////////////////////////////////////////
constant function CE_MagnetismDecay takes nothing returns real
    return 400.00
endfunction

//////////////////////////////////////////////////
//  Constrollers for the portal aesthetics      //
//////////////////////////////////////////////////

//////////////////////////////////////////////////
//  Constroller for the angle of the model      //
//  (90 is upright)                             //
//////////////////////////////////////////////////
constant function CE_PortalAngle takes nothing returns integer
    return 90
endfunction

//////////////////////////////////////////////////
//  Controllers for the scale of the portal     //
//////////////////////////////////////////////////
constant function CE_PortalStartScale takes nothing returns real
    return 2.00
endfunction

constant function CE_PortalGrowthRateBase takes nothing returns real
    return 0.003
endfunction

constant function CE_PortalGrowthRatePerLevel takes nothing returns real
    return 0.002
endfunction

//////////////////////////////////////////////////
//  Controller for how heigh up the portal is   //
//  (will change how units/projectiles behave   //
//  with the portal)                            //
//////////////////////////////////////////////////
constant function CE_PortalHeight takes nothing returns real
    return 400.00
endfunction

//////////////////////////////////////////////////
//  Controllers for the models used for the     //
//  portal and it's boarders                    //
//////////////////////////////////////////////////
constant function CE_PortalModel takes nothing returns string
    return "Abilities\\Spells\\Undead\\Possession\\PossessionCaster.mdl"
endfunction

constant function CE_PortalBoarderModel takes nothing returns string
    return "Abilities\\Spells\\Undead\\AntiMagicShell\\AntiMagicShell.mdl"
endfunction

//////////////////////////////////////////////////
//  Controller for the size of the boarders     //
//////////////////////////////////////////////////
constant function CE_PortalBoarderScale takes nothing returns real
    return 0.25
endfunction

//////////////////////////////////////////////////
//  Controller for how many boarder segments    //
//  the spell has (6.00 gives 6 boarders)       //
//////////////////////////////////////////////////
constant function CE_PortalBoarderSpaceTakenPerSegment takes nothing returns real
    return 6.00
endfunction

//////////////////////////////////////////////////
//  Controller for how heigh the boarders of    //
//  the portal are set (should be about the     //
//  height of the poral + 50)                   //
//////////////////////////////////////////////////
constant function CE_PortalBoarderHeight takes nothing returns real
    return 450.00
endfunction

//////////////////////////////////////////////////
//  Controllers for the size of the projectiles //
//////////////////////////////////////////////////
constant function CE_ChaosEntityScaleBase takes nothing returns real
    return 0.75
endfunction

constant function CE_ChaosEntityScalePerLevel takes nothing returns real
    return 0.00
endfunction

//////////////////////////////////////////////////
//  Controller for the models of the            //
//  projectiles                                 //
//////////////////////////////////////////////////
constant function CE_ChaosEntityModel takes nothing returns string
    return "Abilities\\Spells\\Undead\\OrbOfDeath\\AnnihilationMissile.mdl"
endfunction

//////////////////////////////////////////////////
//  Controller for the initial z velocity of    //
//  chaos entities, changes the aesthetic look  //
//  and the damage spread of the spell          //
//////////////////////////////////////////////////
constant function CE_ChaosEntityZControl takes nothing returns real
    return 6.00
endfunction

//////////////////////////////////////////////////
//  End of the aesthetics configuration         //
//////////////////////////////////////////////////

//////////////////////////////////////////////////
//  Controllers for spell damage                //
//  (Non projectile)                            //
//////////////////////////////////////////////////
constant function CE_HealthDamageBase takes nothing returns real
    return 200.00
endfunction

constant function CE_HealthDamagePerLevel takes nothing returns real
    return 50.00
endfunction

constant function CE_ManaDamageBase takes nothing returns real
    return 0.00
endfunction

constant function CE_ManaDamagePerLevel takes nothing returns real
    return 0.00
endfunction

//////////////////////////////////////////////////
//  Controllers for the number of projectiles   //
//  generated by the spell per cycle            //
//////////////////////////////////////////////////
constant function CE_ChaosEntityCountBase takes nothing returns integer
    return 0
endfunction

constant function CE_ChaosEntityCountPerLevel takes nothing returns integer
    return 5
endfunction

//////////////////////////////////////////////////
//  Controller for the AOE of the chaos         //
//  entities                                    //
//////////////////////////////////////////////////
constant function CE_ChaosEntityAOE takes nothing returns real
    return 125.00
endfunction

//////////////////////////////////////////////////
//  Controller for the Chaos entity creation    //
//  rate (in seconds)                           //
//////////////////////////////////////////////////

constant function CE_ChaosEntityRate takes nothing returns real
    return 1.50
endfunction

//////////////////////////////////////////////////
//  Controllers for the damage dealt by the     //
//  Projectiles                                 //
//////////////////////////////////////////////////
constant function CE_ChaosEntityHealthDamageBase takes nothing returns real
    return 50.00
endfunction

constant function CE_ChaosEntityHealthDamagePerLevel takes nothing returns real
    return 20.00
endfunction

constant function CE_ChaosEntityManaDamageBase takes nothing returns real
    return 0.00
endfunction

constant function CE_ChaosEntityManaDamagePerLevel takes nothing returns real
    return 0.00
endfunction

//////////////////////////////////////////////////
//  Controller for how strong the terrain       //
//  gravity is (makes units return to the       //
//  ground when the rip ends)                   //
//////////////////////////////////////////////////
constant function CE_Gravity takes nothing returns real
    return 40.00 * CE_TimerSpeed()
endfunction

//////////////////////////////////////////////////
//  Controller for whether or not the terrain   //
//  heights effect the spell (arcs hitting      //
//  into it and such)                           //
//////////////////////////////////////////////////
constant function CE_TerrainMatters takes nothing returns boolean
    return true
endfunction

//////////////////////////////////////////////////
//  Controller for whether or not units are     //
//  pulled into the Portal                      //
//////////////////////////////////////////////////
constant function CE_EffectsUnits takes nothing returns boolean
    return true
endfunction

//////////////////////////////////////////////////
//  Controllers for the damage types and such   //
//////////////////////////////////////////////////
constant function CE_MainDamageType takes nothing returns damagetype
    return DAMAGE_TYPE_MAGIC
endfunction

constant function CE_ChaosEntityDamageType takes nothing returns damagetype
    return DAMAGE_TYPE_NORMAL
endfunction

constant function CE_MainAttackType takes nothing returns attacktype
    return ATTACK_TYPE_MAGIC
endfunction

constant function CE_ChaosEntityAttackType takes nothing returns attacktype
    return ATTACK_TYPE_NORMAL
endfunction

constant function CE_MainWeaponType takes nothing returns weapontype
    return null
endfunction

constant function CE_ChaosEntityWeaponType takes nothing returns weapontype
    return null
endfunction

////////////////////////////////////////////////////////////////////
//  End of the configuration of the spell, beyond this is the     //
//  programming used to run the spell, if you do not understand   //
//  JASS, then it is not recommended that you scroll any further  //
////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////
//  Function used to identify targets for the magnetism or        //
//  damage of the spell depanding on what the current stage is    //
////////////////////////////////////////////////////////////////////
function CE_TargetFilter takes unit u, player pl returns nothing

    //Checks if the unit can be used as a target
    if (IsUnitType(u, UNIT_TYPE_GROUND)) and (not IsUnitType(u, UNIT_TYPE_STRUCTURE)) and (not IsUnitType(u, UNIT_TYPE_MAGIC_IMMUNE)) and (IsUnitEnemy(u, pl)) and (GetUnitTypeId(u) != CE_DummyID()) and (not IsUnitInGroup(u, udg_CE_EffectedUnits)) and (not IsUnitType(u, UNIT_TYPE_DEAD)) then
        call GroupAddUnit(udg_CE_TempGroup, u)
    endif
    
    //Nulling variables
    set u = null
    set pl = null

endfunction

function CE_GravityMove takes real Magnetism, real Radian, real Angle, real Angle2, real x, real y, real x2, real y2, real z, integer index returns nothing
    local location p
    
    //Setting the new locations X and Y for this instance
    set x2 = x + udg_CE_XVelocity[index]
    set y2 = y + udg_CE_YVelocity[index]
    set p = Location(x2,y2)
    //Calculating the new velocities (will be used next time this runs)
    set udg_CE_ZVelocity[index] = udg_CE_ZVelocity[index] + ((Magnetism / Radian) * CE_TimerSpeed()) * Sin(Angle2)
    set udg_CE_XVelocity[index] = udg_CE_XVelocity[index] + ((Magnetism / Radian) * CE_TimerSpeed()) * Cos(Angle) * Cos(Angle2)
    set udg_CE_YVelocity[index] = udg_CE_YVelocity[index] + ((Magnetism / Radian) * CE_TimerSpeed()) * Sin(Angle) * Cos(Angle2)
    
    //Makes sure the new location is within the map bounds
    if ((GetRectMinX(bj_mapInitialPlayableArea) <= GetLocationX(p)) and (GetLocationX(p) <= GetRectMaxX(bj_mapInitialPlayableArea)) and (GetRectMinY(bj_mapInitialPlayableArea) <= GetLocationY(p)) and (GetLocationY(p) <= GetRectMaxY(bj_mapInitialPlayableArea))) then
        call SetUnitX(udg_CE_UnitIndex[index], x2)
        call SetUnitY(udg_CE_UnitIndex[index], y2)
    endif
    //Removes the location
    call RemoveLocation(p)
    //Sets the correct fly height
    call SetUnitFlyHeight(udg_CE_UnitIndex[index], udg_CE_CurrentZ[index] - z, 0.00)
    
    //Nulling the variable
    set p = null
    
endfunction

function CE_ProjectileImpactDetection takes real z, real x, real y, integer index returns nothing
    local unit u
    local player pl
    
    //Checks if there has been a crash
    if (udg_CE_CurrentZ[index] - z < 5.00) then
        //Yes it crashed, deassociating the unit
        set udg_CE_StageID[index] = 4
        set udg_CE_Portal[index] = null
        set pl = GetOwningPlayer(udg_CE_OriginalCaster[index])
        
        if (GetUnitTypeId(udg_CE_UnitIndex[index]) == CE_DummyID()) then
            call DestroyEffect(udg_CE_CurrentEffect[index])
            //Select Units to damage
            call GroupEnumUnitsInRange(udg_CE_TempGroup2, x, y, CE_ChaosEntityAOE(), null)              
                
            loop
                //Scanning through
                set u = FirstOfGroup(udg_CE_TempGroup2)
                exitwhen u == null
                call CE_TargetFilter(u, pl)
                call GroupRemoveUnit(udg_CE_TempGroup2, u)
                    
                //Select all the units which are to be damaged
                if (IsUnitInGroup(u, udg_CE_TempGroup)) then
                    //Dealing health and mana damage
                    call UnitDamageTarget(udg_CE_OriginalCaster[index], u, udg_CE_HealthDamage[index], true, false, CE_ChaosEntityAttackType(), CE_ChaosEntityDamageType(), CE_ChaosEntityWeaponType())
                    call SetUnitState(u, UNIT_STATE_MANA, (GetUnitState(u,UNIT_STATE_MANA) - udg_CE_ManaDamage[index]))
                    call GroupRemoveUnit(udg_CE_TempGroup, u)
                endif
                    
            endloop
                    
            //Removes the projectile
            call KillUnit(udg_CE_UnitIndex[index])                
        else
            //Dealing health and mana damage
            call UnitDamageTarget(udg_CE_OriginalCaster[index], udg_CE_UnitIndex[index], udg_CE_HealthDamage[index], true, false, CE_MainAttackType(), CE_MainDamageType(), CE_MainWeaponType())
            call SetUnitState(udg_CE_UnitIndex[index], UNIT_STATE_MANA, (GetUnitState(udg_CE_UnitIndex[index],UNIT_STATE_MANA) - udg_CE_ManaDamage[index]))
            //Allowing the unit to be reselected as a target for another instance
            call GroupRemoveUnit(udg_CE_EffectedUnits, udg_CE_UnitIndex[index])
            //Enabling the unit's pathing again
            call SetUnitPathing(udg_CE_UnitIndex[index], true )
        endif
                
    endif
            
endfunction
 
function CE_RegisterUnit takes integer index, real z, real x2, real y2, unit u, real YVel, real XVel, real ZVel returns nothing
    //Sets up data for the next magnetised unit
    local location p2
    set p2 = Location(x2, y2)
    set udg_CE_LaunchZ[udg_CE_MaxIndex] = GetLocationZ(p2)
    set udg_CE_TargetZ[udg_CE_MaxIndex] = z
    call RemoveLocation(p2)
    
    //Sets up data for caster and portal it's being pulled into
    set udg_CE_OriginalCaster[udg_CE_MaxIndex] = udg_CE_OriginalCaster[index]
    set udg_CE_Portal[udg_CE_MaxIndex] = udg_CE_UnitIndex[index]
    set udg_CE_AOE[udg_CE_MaxIndex] = udg_CE_AOE[index]
                        
    //Sets up the magnetism
    set udg_CE_MagnetismStrength[udg_CE_MaxIndex] = udg_CE_MagnetismStrength[index]
    set udg_CE_CurrentZ[udg_CE_MaxIndex] = GetUnitFlyHeight(u) + udg_CE_LaunchZ[udg_CE_MaxIndex]
    set udg_CE_YVelocity[udg_CE_MaxIndex] = YVel                      
    set udg_CE_XVelocity[udg_CE_MaxIndex] = XVel
    set udg_CE_ZVelocity[udg_CE_MaxIndex] = ZVel
    
    //Nulls variables
    set u = null
    set p2 = null
    
endfunction

////////////////////////////////////////////////////////////////////
//  Main looping function, controls things from the magnetism     //
//  of the portal to the damage and projectile control within     //
//  the Chaos Rip                                                 //
////////////////////////////////////////////////////////////////////
function CE_Loop takes nothing returns nothing
    //Setting up the local variables
    local integer index = 0
    local integer secondaryindex = 0
    local real x
    local real x2
    local real y
    local real y2
    local real z
    local real z2
    local real dx
    local real dy
    local real Dist
    local real Angle
    local real Angle2
    local real Magnetism
    local real Radian
    local player pl
    local unit u
    local location p
    
    //Loops through all the units within the system
    loop
        set index = index + 1
        exitwhen index > udg_CE_MaxIndex
        set x = GetUnitX(udg_CE_UnitIndex[index])
        set y = GetUnitY(udg_CE_UnitIndex[index])
         
        //Finds units which are initial portals of an instance
        if (udg_CE_StageID[index] == 1) then
            if (GetUnitCurrentOrder(udg_CE_OriginalCaster[index]) != CE_Order()) then
                set udg_CE_StageID[index] = 4
                call DestroyEffect(udg_CE_CurrentEffect[index]) 
                
                //Deassociating all the units involves with this porta (will allow units and projectiles to fall)
                loop
                    set secondaryindex = secondaryindex + 1
                    
                    if (udg_CE_Portal[secondaryindex] == udg_CE_UnitIndex[index]) then
                        set udg_CE_Portal[secondaryindex] = null
                        
                        if (udg_CE_StageID[secondaryindex] == 7) then
                            set udg_CE_StageID[secondaryindex] = 4
                            call DestroyEffect(udg_CE_CurrentEffect[secondaryindex])
                        else
                            set udg_CE_StageID[secondaryindex] = 3
                        endif
                    
                    endif
                    
                    exitwhen secondaryindex > udg_CE_MaxIndex
                endloop
                
                set secondaryindex = 0
            else
                //Initialising data and increasing the portal size
                set p = Location(x, y)
                set z = GetLocationZ(p) + CE_PortalHeight()
                set u = udg_CE_UnitIndex[index]
                call RemoveLocation (p)
                set udg_CE_CurrentSize[index] = udg_CE_CurrentSize[index] + udg_CE_GrowthRate[index]
                set pl = GetOwningPlayer(udg_CE_OriginalCaster[index])
                call SetUnitScale(udg_CE_UnitIndex[index], udg_CE_CurrentSize[index], 0.00, 0.00)


                if (udg_CE_CurrentProjectileDelay[index] > CE_ChaosEntityRate()) then
                    //Creating New projectile wave
                    set Angle = 0
                    //Reset the delay timer
                    set udg_CE_CurrentProjectileDelay[index] = 0.00

                    loop
                        //Calculating position and initialising
                        set Angle = Angle + (360.00 / udg_CE_ChaosEntityCount[index])
                        set secondaryindex = secondaryindex + 1
                        set x2 = x + CE_AOECentral() * Cos(Angle * bj_DEGTORAD)
                        set y2 = y + CE_AOECentral() * Sin(Angle * bj_DEGTORAD)
                        set udg_CE_MaxIndex = udg_CE_MaxIndex + 1
                        set udg_CE_UnitIndex[udg_CE_MaxIndex] = CreateUnit(Player(14), CE_DummyID(), x2, y2, Angle)
                        set udg_CE_CurrentEffect[udg_CE_MaxIndex] = AddSpecialEffectTarget(CE_ChaosEntityModel(), udg_CE_UnitIndex[udg_CE_MaxIndex], "origin")
                        set udg_CE_HealthDamage[udg_CE_MaxIndex] = CE_ChaosEntityHealthDamageBase() + (CE_ChaosEntityHealthDamagePerLevel() * udg_CE_rLevel[index])
                        set udg_CE_ManaDamage[udg_CE_MaxIndex] = CE_ChaosEntityManaDamageBase() + (CE_ChaosEntityManaDamagePerLevel() * udg_CE_rLevel[index])
                        set udg_CE_CurrentDeathTimer[udg_CE_MaxIndex] = 0.00
                        set udg_CE_StageID[udg_CE_MaxIndex] = 2
                        set udg_CE_Portal[udg_CE_MaxIndex] = u
                        //Makes terrain height changing possible if not already
                        if UnitAddAbility(udg_CE_UnitIndex[udg_CE_MaxIndex], 'Amrf') and UnitRemoveAbility(udg_CE_UnitIndex[udg_CE_MaxIndex], 'Amrf') then
                        endif
                            
                        //Setting up data of the new magnetised unit
                        call CE_RegisterUnit(index, z, x2, y2, u, 0.00, 0.00, CE_ChaosEntityZControl())
            
                        //Applying Aesthetics
                        call SetUnitScale(udg_CE_UnitIndex[udg_CE_MaxIndex],  CE_ChaosEntityScaleBase() + (CE_ChaosEntityScalePerLevel() * udg_CE_rLevel[index]), 0.00, 0.00)
                        call SetUnitFlyHeight(udg_CE_UnitIndex[udg_CE_MaxIndex], CE_PortalHeight(), 0.00)
                        call SetUnitAnimationByIndex(udg_CE_UnitIndex[udg_CE_MaxIndex], CE_PortalAngle())

                        call GroupAddUnit(udg_CE_EffectedUnits, udg_CE_UnitIndex[index])
            
                        exitwhen secondaryindex == udg_CE_ChaosEntityCount[index]
                    endloop
                    
                    set secondaryindex = 0
                else
                    //Increase the delay timer on the projectiles
                    set udg_CE_CurrentProjectileDelay[index] = udg_CE_CurrentProjectileDelay[index] + CE_TimerSpeed()
                endif

                if (CE_EffectsUnits()) then
                    call GroupEnumUnitsInRange(udg_CE_TempGroup2, x, y, udg_CE_AOE[index], null)              

                    //Filters through all the units within the range of the portal which can be used as targets
                    loop
                        set u = FirstOfGroup(udg_CE_TempGroup2)
                        exitwhen u == null
                        call CE_TargetFilter(u, pl)
                        call GroupRemoveUnit(udg_CE_TempGroup2, u)
                    
                        //Actions for units which have been found to be viable targets
                        if (IsUnitInGroup(u, udg_CE_TempGroup)) and (not IsUnitInGroup(u, udg_CE_EffectedUnits)) then
                            //Data initialisation
                            set x2 = GetUnitX(u)
                            set y2 = GetUnitY(u)
                            set dx = x2 - x
                            set dy = y2 - y
                            set Angle = Atan2(dy, dx)
                            set Dist = SquareRoot(dx * dx + dy * dy)
                            set udg_CE_MaxIndex = udg_CE_MaxIndex + 1
                            set udg_CE_UnitIndex[udg_CE_MaxIndex] = u
                            set udg_CE_CurrentDeathTimer[udg_CE_MaxIndex] = 0.00
                            set udg_CE_HealthDamage[udg_CE_MaxIndex] = udg_CE_HealthDamage[index]
                            set udg_CE_ManaDamage[udg_CE_MaxIndex] = udg_CE_ManaDamage[index]
                       
                            //Makes terrain height changing possible if not already
                            if UnitAddAbility(udg_CE_UnitIndex[udg_CE_MaxIndex], 'Amrf') and UnitRemoveAbility(udg_CE_UnitIndex[udg_CE_MaxIndex], 'Amrf') then
                            endif
                            
                            call SetUnitPathing(u, false ) 
                            set udg_CE_StageID[udg_CE_MaxIndex] = 2
                            //Sets up data for the next magnetised unit
                            call CE_RegisterUnit(index, z, x2, y2, u, 0.00, 0.00, 6.00)

                            //Makes this unit unselectable as a target until the end of this spell instance
                            call GroupAddUnit(udg_CE_EffectedUnits, u)
                            call GroupRemoveUnit(udg_CE_TempGroup, u)
                        endif

                    endloop
                    
                endif         

            endif

        //Finds units which are to be effected by the magnetism
        elseif (udg_CE_StageID[index] == 2) then
            //Initialises Magnetism factors
            set x2 = GetUnitX(udg_CE_Portal[index])
            set y2 = GetUnitY(udg_CE_Portal[index])
            //Sets up this instance of the movement
            set udg_CE_CurrentZ[index] = udg_CE_CurrentZ[index] + udg_CE_ZVelocity[index]
            
            //Sets up calculating the next movement
            set p = Location(x, y)
            set z = GetLocationZ(p)
            call RemoveLocation(p)
            set dy = y2 - y
            set dx = x2 - x
            set Dist = SquareRoot(dx * dx + dy * dy)
            set Angle = Atan2(dy, dx)
            set Angle2 = Atan2(udg_CE_TargetZ[index] - udg_CE_CurrentZ[index], Dist)
            set Radian = SquareRoot((dx * dx) + (dy * dy) + (udg_CE_TargetZ[index] - udg_CE_CurrentZ[index]) * (udg_CE_TargetZ[index] - udg_CE_CurrentZ[index]))
            //Calculates the magnetism strength for this instance
            set Magnetism = udg_CE_MagnetismStrength[index] * (Dist / CE_MagnetismDecay())

            if (Dist > udg_CE_AOE[index]) then
                set udg_CE_StageID[index] = 3
            endif
            
            //Checks if the unit or entity have crashed
            call CE_ProjectileImpactDetection(z, x, y, index)
            
            //Moves the unit or entity around the Portal
            call CE_GravityMove(Magnetism, Radian, Angle, Angle2, x, y, x2, y2, z, index)

            //Checks if the unit is an entity - if it is, then setting its animation and facing direction
            if (GetUnitTypeId(udg_CE_UnitIndex[index]) == CE_DummyID()) then
                call SetUnitAnimationByIndex(udg_CE_UnitIndex[index], R2I(Atan2(udg_CE_ZVelocity[index], SquareRoot((udg_CE_XVelocity[index] * udg_CE_XVelocity[index]) + (udg_CE_YVelocity[index] * udg_CE_YVelocity[index]))) * bj_RADTODEG + 0.5) + 90)
                call SetUnitFacing(udg_CE_UnitIndex[index], Angle * bj_RADTODEG)
            endif

        //Finds units which are falling out of the sky
        elseif (udg_CE_StageID[index] == 3) then
            set p = Location(x, y)
            set z = GetLocationZ(p)
            set x2 = x + udg_CE_XVelocity[index]
            set y2 = y + udg_CE_YVelocity[index]  
            set udg_CE_ZVelocity[index] = udg_CE_ZVelocity[index] - CE_Gravity()
            set udg_CE_CurrentZ[index] = udg_CE_CurrentZ[index] + udg_CE_ZVelocity[index] 

            //Makes sure the projectile or unit does not leave the map bounds (may look a bit odd but is necessary)
            if ((GetRectMinX(bj_mapInitialPlayableArea) <= GetLocationX(p)) and (GetLocationX(p) <= GetRectMaxX(bj_mapInitialPlayableArea)) and (GetRectMinY(bj_mapInitialPlayableArea) <= GetLocationY(p)) and (GetLocationY(p) <= GetRectMaxY(bj_mapInitialPlayableArea))) then
                call SetUnitX(udg_CE_UnitIndex[index], x2)
                call SetUnitY(udg_CE_UnitIndex[index], y2)
            endif
            
            call RemoveLocation(p)
            call SetUnitFlyHeight(udg_CE_UnitIndex[index],  udg_CE_CurrentZ[index] - z, 0.00)
    
            call CE_ProjectileImpactDetection(z, x, y, index)

            set Angle = Atan2(y2 - y, x2 - x)
            if (GetUnitTypeId(udg_CE_UnitIndex[index]) == CE_DummyID()) then
                call SetUnitAnimationByIndex(udg_CE_UnitIndex[index], R2I(Atan2(udg_CE_ZVelocity[index], SquareRoot((udg_CE_XVelocity[index] * udg_CE_XVelocity[index]) + (udg_CE_YVelocity[index] * udg_CE_YVelocity[index]))) * bj_RADTODEG + 0.5) + 90)
                call SetUnitFacing(udg_CE_UnitIndex[index], Angle * bj_RADTODEG)
            endif
            
        //Finds units which need to be recycled
        elseif (udg_CE_StageID[index] == 4) then
        
            //Checks if the death timer has expired
            if (udg_CE_CurrentDeathTimer[index] >= CE_DeathTimer()) then
            
                set udg_CE_CurrentDeathTimer[index] = 0.00
                
                //Removing projectiles from the game
                if (GetUnitTypeId(udg_CE_UnitIndex[index]) == CE_DummyID()) then
                    call RemoveUnit(udg_CE_UnitIndex[index])
                endif  
                
                //Recycling the instance of the spell
                set udg_CE_AOE[index] = udg_CE_AOE[udg_CE_MaxIndex]
                set udg_CE_ChaosEntityCount[index] = udg_CE_ChaosEntityCount[udg_CE_MaxIndex]
                set udg_CE_CurrentDeathTimer[index] = udg_CE_CurrentDeathTimer[udg_CE_MaxIndex]
                set udg_CE_CurrentEffect[index] = udg_CE_CurrentEffect[udg_CE_MaxIndex]
                set udg_CE_CurrentSize[index] = udg_CE_CurrentSize[udg_CE_MaxIndex]
                set udg_CE_CurrentZ[index] = udg_CE_CurrentZ[udg_CE_MaxIndex]
                set udg_CE_GrowthRate[index] = udg_CE_GrowthRate[udg_CE_MaxIndex]
                set udg_CE_HealthDamage[index] = udg_CE_HealthDamage[udg_CE_MaxIndex]
                set udg_CE_LaunchZ[index] = udg_CE_LaunchZ[udg_CE_MaxIndex]
                set udg_CE_MagnetismStrength[index] = udg_CE_MagnetismStrength[udg_CE_MaxIndex]
                set udg_CE_ManaDamage[index] = udg_CE_ManaDamage[udg_CE_MaxIndex]
                set udg_CE_OriginalCaster[index] = udg_CE_OriginalCaster[udg_CE_MaxIndex]
                set udg_CE_Portal[index] = udg_CE_Portal[udg_CE_MaxIndex]
                set udg_CE_StageID[index] = udg_CE_StageID[udg_CE_MaxIndex]
                set udg_CE_TargetZ[index] = udg_CE_TargetZ[udg_CE_MaxIndex]
                set udg_CE_UnitIndex[index] = udg_CE_UnitIndex[udg_CE_MaxIndex]
                set udg_CE_XVelocity[index] = udg_CE_XVelocity[udg_CE_MaxIndex]
                set udg_CE_YVelocity[index] = udg_CE_YVelocity[udg_CE_MaxIndex]
                set udg_CE_ZVelocity[index] = udg_CE_ZVelocity[udg_CE_MaxIndex]
                set udg_CE_iLevel[index] = udg_CE_iLevel[udg_CE_MaxIndex]
                set udg_CE_rLevel[index] = udg_CE_rLevel[udg_CE_MaxIndex]
                set udg_CE_MaxIndex = udg_CE_MaxIndex - 1
                set index = index - 1
                
                //Stopping the timer if there are no more instances to run
                if (udg_CE_MaxIndex == 0) then
                    call DestroyTimer(GetExpiredTimer())
                endif

            else
                //If the death timer has not expired, increase how long it's been running
                set udg_CE_CurrentDeathTimer[index] = udg_CE_CurrentDeathTimer[index] + CE_TimerSpeed()
            endif
            
        endif
        
    endloop
    
    //Nulls variables
    set u = null
    set p = null
    
endfunction

////////////////////////////////////////////////////////////////////
//  Function ran to create a new instance of the spell, inits a   //
//  portal, giving it the starting information it requires        //
////////////////////////////////////////////////////////////////////
function TrigCE_AllocateData takes nothing returns boolean
    // Sets up the variables required for creating units
    local unit u = GetTriggerUnit()
    local integer iLevel = GetUnitAbilityLevel(u, CE_SpellID())
    local real rLevel = I2R(iLevel)
    local real x = GetSpellTargetX()
    local real x2 = GetUnitX(u)
    local real y = GetSpellTargetY()
    local real y2 = GetUnitY(u)
    local real Angle = 0.00
    
    // Checks if the ability casted was the correct one
    if (GetSpellAbilityId() == CE_SpellID()) then
        // Initialises  new spell instance
        set udg_CE_MaxIndex = udg_CE_MaxIndex + 1
        set udg_CE_UnitIndex[udg_CE_MaxIndex] = CreateUnit(Player(14), CE_DummyID(), x, y, Atan2(y - y2, x - x2))
        set udg_CE_AOE[udg_CE_MaxIndex] = CE_AOEBase() + (CE_AOEPerLevel() * rLevel)
        set udg_CE_CurrentEffect[udg_CE_MaxIndex] = AddSpecialEffectTarget(CE_PortalModel(), udg_CE_UnitIndex[udg_CE_MaxIndex], "origin")
        set udg_CE_MagnetismStrength[udg_CE_MaxIndex] = CE_MagnetismBase() + (CE_MagnetismPerLevel() * rLevel)
        set udg_CE_GrowthRate[udg_CE_MaxIndex] = CE_PortalGrowthRateBase() + (CE_PortalGrowthRatePerLevel() * rLevel)
        set udg_CE_ChaosEntityCount[udg_CE_MaxIndex] = CE_ChaosEntityCountBase() + (CE_ChaosEntityCountPerLevel() * iLevel)
        set udg_CE_CurrentSize[udg_CE_MaxIndex]= CE_PortalStartScale()
        set udg_CE_CurrentProjectileDelay[udg_CE_MaxIndex] = 0.00
        set udg_CE_CurrentDeathTimer[udg_CE_MaxIndex] = 0.00
        set udg_CE_OriginalCaster[udg_CE_MaxIndex] = u
        set udg_CE_Portal[udg_CE_MaxIndex] = null
        set udg_CE_iLevel[udg_CE_MaxIndex] = iLevel
        set udg_CE_rLevel[udg_CE_MaxIndex] = rLevel
        set udg_CE_StageID[udg_CE_MaxIndex] = 1
        set udg_CE_HealthDamage[udg_CE_MaxIndex] = CE_HealthDamageBase() + (CE_HealthDamagePerLevel() * rLevel)
        set udg_CE_ManaDamage[udg_CE_MaxIndex] = CE_ManaDamageBase() + (CE_ManaDamagePerLevel() * rLevel)
        
        //Makes terrain height changing possible if not already
        if UnitAddAbility(udg_CE_UnitIndex[udg_CE_MaxIndex], 'Amrf') and UnitRemoveAbility(udg_CE_UnitIndex[udg_CE_MaxIndex], 'Amrf') then
        endif
        
        //Sets up the aesthetics of the portal
        call SetUnitScale(udg_CE_UnitIndex[udg_CE_MaxIndex], udg_CE_CurrentSize[udg_CE_MaxIndex], 0.00, 0.00)
        call SetUnitFlyHeight(udg_CE_UnitIndex[udg_CE_MaxIndex], CE_PortalHeight(), 0.00)
        call SetUnitAnimationByIndex(udg_CE_UnitIndex[udg_CE_MaxIndex], CE_PortalAngle())
        
        //If no timer is currently running (Max Index was 0 before this) create a new one
        if (udg_CE_MaxIndex == 1) then
            call TimerStart(CreateTimer(), CE_TimerSpeed(), true, function CE_Loop)
        endif
        
        set u = udg_CE_UnitIndex[udg_CE_MaxIndex]
        
        //Creating Aesthetic portal boarder
        loop
            //Calculating position and initialising
            set Angle = Angle + (360.00 / CE_PortalBoarderSpaceTakenPerSegment())
            set x2 = x + CE_AOECentral() * Cos(Angle * bj_DEGTORAD)
            set y2 = y + CE_AOECentral() * Sin(Angle * bj_DEGTORAD)
            set udg_CE_MaxIndex = udg_CE_MaxIndex + 1
            set udg_CE_UnitIndex[udg_CE_MaxIndex] = CreateUnit(Player(14), CE_DummyID(), x2, y2, Angle)
            set udg_CE_CurrentEffect[udg_CE_MaxIndex] = AddSpecialEffectTarget(CE_PortalBoarderModel(), udg_CE_UnitIndex[udg_CE_MaxIndex], "origin")
            set udg_CE_CurrentDeathTimer[udg_CE_MaxIndex] = 0.00
            set udg_CE_StageID[udg_CE_MaxIndex] = 7
            set udg_CE_Portal[udg_CE_MaxIndex] = u

            //Makes terrain height changing possible if not already
            if UnitAddAbility(udg_CE_UnitIndex[udg_CE_MaxIndex], 'Amrf') and UnitRemoveAbility(udg_CE_UnitIndex[udg_CE_MaxIndex], 'Amrf') then
            endif
            
            //Applying Aesthetics
            call SetUnitScale(udg_CE_UnitIndex[udg_CE_MaxIndex],  CE_PortalBoarderScale(), 0.00, 0.00)
            call SetUnitFlyHeight(udg_CE_UnitIndex[udg_CE_MaxIndex], CE_PortalBoarderHeight(), 0.00)
            call SetUnitAnimationByIndex(udg_CE_UnitIndex[udg_CE_MaxIndex], CE_PortalAngle())
            
            exitwhen Angle >= 360.00
        endloop
        
    endif
    
    //Nulls variables
    set u = null
    return false
    
endfunction

////////////////////////////////////////////////////////////////////
//  Function used to start up the spell, initialises events       //
//  and conditions needed for the spell to run correctly          //
////////////////////////////////////////////////////////////////////
function InitTrig_CE_ChaosEnvoy takes nothing returns nothing
    local trigger CE = CreateTrigger()
    local integer index = 0

    //Initialise the event for every player
    loop
        call TriggerRegisterPlayerUnitEvent(CE, Player(index), EVENT_PLAYER_UNIT_SPELL_EFFECT, null)
        set index = index + 1
        exitwhen index == bj_MAX_PLAYER_SLOTS
    endloop
    
    call TriggerAddCondition(CE, Condition(function TrigCE_AllocateData))
    
    //Nulls variables
    set CE = null
    
endfunction


Information:
Pure JASS ~ 1200 lines (including readme and configuration)
Runs on standard World Editor without compile errors on saving
Large configuration to modify pretty much every attribute involved with the spell.
Physics galore
Fully MUI, Recycles correctly

Comes with a variable creator to help with importing to standard world editors


  • Variable Creator
    • Events
    • Conditions
    • Actions
      • Set CE_AOE[0] = 0.00
      • Set CE_ChaosEntityCount[0] = 0
      • Set CE_CurrentDeathTimer[0] = 0.00
      • Set CE_CurrentEffect[0] = CE_CurrentEffect[0]
      • Set CE_CurrentProjectileDelay[0] = 0.00
      • Set CE_CurrentSize[0] = 0.00
      • Set CE_CurrentZ[0] = 0.00
      • Set CE_EffectedUnits = CE_EffectedUnits
      • Set CE_GrowthRate[0] = 0.00
      • Set CE_HealthDamage[0] = 0.00
      • Set CE_LaunchZ[0] = 0.00
      • Set CE_MagnetismStrength[0] = 0.00
      • Set CE_ManaDamage[0] = 0.00
      • Set CE_MaxIndex = 0
      • Set CE_OriginalCaster[0] = CE_OriginalCaster[0]
      • Set CE_Portal[0] = CE_Portal[0]
      • Set CE_StageID[0] = 0
      • Set CE_TargetZ[0] = 0.00
      • Set CE_TempGroup = CE_TempGroup
      • Set CE_TempGroup2 = CE_TempGroup2
      • Set CE_UnitIndex[0] = CE_UnitIndex[0]
      • Set CE_XVelocity[0] = 0.00
      • Set CE_YVelocity[0] = 0.00
      • Set CE_ZVelocity[0] = 0.00
      • Set CE_iLevel[0] = 0
      • Set CE_rLevel[0] = 0.00


WIPS:
http://www.hiveworkshop.com/forums/...t-10-what-lies-other-side-233773/#post2328013
http://www.hiveworkshop.com/forums/...ies-other-side-233773/index3.html#post2328512
http://www.hiveworkshop.com/forums/...ies-other-side-233773/index5.html#post2329215
http://www.hiveworkshop.com/forums/...ies-other-side-233773/index5.html#post2329389
http://www.hiveworkshop.com/forums/...ies-other-side-233773/index6.html#post2329748
http://www.hiveworkshop.com/forums/...ies-other-side-233773/index7.html#post2329904

Screenshots (and a slightly jolty GIF)




Awesome spell TC! You should upload this in the Spells section =)
 
Second WIP:
JASS:
library ArcanceWormholes /* v1.0
*************************************************************************************
*
*    Arcane Wormholes
*       ~ Almia
*
*    --------------------------------------------------------------------------
*
*        Description
*
*        ------------------------------------------
*
*    --------------------------------------------------------------------------
*
*        */ requires /*
*
*        ------------------------------------------
*
*            */ Table /*       [url]www.hiveworkshop.com/forums/jass-resources-412/snippet-new-table-188084/[/url]
*            */ MapBounds /*   [url]www.hiveworkshop.com/forums/jass-resources-412/snippet-worldbounds-180494/[/url]
*            */ WorldBounds /* [url]www.hiveworkshop.com/forums/jass-resources-412/snippet-mapbounds-222870/[/url]
*
*    --------------------------------------------------------------------------
*
*        Credits
*
*        ------------------------------------------
*
*            Nestharus
*            Bribe
*            Adiktuz
*
*************************************************************************************/
    globals
        /*
           Ability main constants
        */
        private constant real TIMEOUT = 0.031250000
        /*
            Main Ability Raw Code
        */
        private constant integer MAIN = 'A000'
        /*
            Sub Ability Raw Code
        */
        private constant integer SUB = 'A001'
        /*
            Dummy Raw Code
        */
        private constant integer DUMMY = 'h000'
        /*
            Max Spell Charges
        */
        private constant integer SPELL_CHARGES = 3
        
        /*
            Caster Orbs
        */
        
        /*
            Number of orbs spinning around the caster
        */
        private constant integer CASTER_ORB_NUMBER = 3
        /*
            How far are they from the caster
        */
        private constant real CASTER_ORB_DIST = 150.
        /*
            How fast the orbs spins around by angle
        */
        private constant real CASTER_ORB_SPIN_SPEED = 90.
        /*
            Model Path of the caster orbs
        */
        private constant string CASTER_ORB_MDL = "Abilities\\Weapons\\SpiritOfVengeanceMissile\\SpiritOfVengeanceMissile.mdl"
        /*
            Orb Model Size
        */
        private constant real CASTER_ORB_SIZE = 1.
        /*
            Orb Caster Height
        */
        private constant real CASTER_ORB_Z = 50.
        
        /*
            Orb Missile
        */
        
        /*
            Missile Speed
        */
        private constant real ORB_MISSILE_SPEED = 500.
        /*
            Missile Model
        */
        private constant string ORB_MISSILE_MDL = "Abilities\\Weapons\\SpiritOfVengeanceMissile\\SpiritOfVengeanceMissile.mdl"
        /*
            Missile Size
        */
        private constant real ORB_MISSILE_SIZE = 1.
        
        /*
            Missile Height
        */
        private constant real ORB_MISSILE_Z = 50.
        /*
            Missile Impact Effect
        */
        private constant string ORB_IMPACT_EFFECt =  "Objects\\Spawnmodels\\NightElf\\NECancelDeath\\NECancelDeath.mdl"
        
        /*
            Portal
        */
        
        /*
            Portal Model
        */
        private constant string PORTAL_MDL = "units\\nightelf\\Wisp\\Wisp.mdl"
        /*
            Portal Size
        */
        private constant real PORTAL_SIZE = 1.
        /*
            Portal Height
        */
        private constant real PORTAL_Z = 50.
        /*
            Portal Duration
        */
        private constant real PORTAL_DURATION = 60.
        /*
            Portal Death Effect
        */
        private constant string PORTAL_DEATH_SFX = "Objects\\Spawnmodels\\NightElf\\NECancelDeath\\NECancelDeath.mdl"
        
        /*
            Portal Orbs
        */
        
        /*
            Number of orbs spinning around the portal
        */
        private constant real PORTAL_ORB_NUMBER = 3
        /*
            How far the orbs are from the portal
        */
        private constant real PORTAL_ORB_DIST = 150.
        /*
            Portal Orb Spin Speed
        */
        private constant real PORTAL_ORB_SPIN_SPEED = 90.
        /*
            Portal Orb Model
        */
        private constant string PORTAL_ORB_MDL = "Abilities\\Weapons\\SpiritOfVengeanceMissile\\SpiritOfVengeanceMissile.mdl"
        /*
            Portal Orb Scale
        */
        private constant real PORTAL_ORB_SIZE = 1.
        /*
           Portal Orb Z
        */
        private constant real PORTAL_ORB_Z = 75.
        
        /*
            Teleportation Constants
        */
        
        /*
            Radius of units that will be also teleported
        */
        private constant real TELEPORT_RADIUS = 500.
        /*
            Teleportation Delay
        */
        private constant real TELEPORT_DELAY = 5.
        /*
            Teleportation On Cast Effect
        */
        private constant string TELEPORT_CAST_SFX = "Abilities\\Spells\\Other\\Charm\\CharmTarget.mdl"
        /*
            Channeling Effect on Caster
        */
        private constant string TELEPORT_CHANNEL_SFX = "Abilities\\Spells\\Other\\Drain\\ManaDrainTarget.mdl"
        /*
            Random Effect Channel
        */
        private constant string TELEPORT_RANDOM_SFX = "Abilities\\Spells\\Undead\\AbsorbMana\\AbsorbManaBirthMissile.mdl"
        /*
            Teleportation Success Effect
        */
        private constant string TELEPORT_END_SFX = "Objects\\Spawnmodels\\NightElf\\NECancelDeath\\NECancelDeath.mdl"
        /*
            Teleportation Impact Effect
        */
        private constant string TELEPORT_IMPACT_SFX ="Abilities\\Spells\\Orc\\WarStomp\\WarStompCaster.mdl"
        /*
            Teleportation Damage and Mana Burn Radius
        */
        private constant real TELEPORT_IMPACT_RADIUS = 400. // Base value
        /*
            Teleportation Damage value
        */
        private constant real TELEPORT_IMPACT_DAMAGE = 25. // Base Value
        /*
            Teleportation Mana Burn Value
        */
        private constant real TELEPORT_IMPACT_BURN = 25. // Base Value
        /*
            Teleportation Mana Burn and Damage SFX
        */
        private constant string TELEPORT_DMB_SFX = "Abilities\\Spells\\Human\\Feedback\\ArcaneTowerAttack.mdl"
        private constant string TELEPORT_DMB_ATTACH = "chest"
        
        /*
            Teleportation Orbs
        */
        
        /*
            Number of orbs spinning around the caster
        */
        private constant real TELEPORT_ORB_NUMBER = 6
        /*
            How far the orbs are from the portal
        */
        private constant real TELEPORT_ORB_DIST = TELEPORT_RADIUS
        /*
            Portal Orb Spin Speed
        */
        private constant real TELEPORT_ORB_SPIN_SPEED = 90.
        /*
            Portal Orb Model
        */
        private constant string TELEPORT_ORB_MDL = "Abilities\\Weapons\\SpiritOfVengeanceMissile\\SpiritOfVengeanceMissile.mdl"
        /*
            Portal Orb Scale
        */
        private constant real TELEPORT_ORB_SIZE = 1.
        /*
           Portal Orb Z
        */
        private constant real TELEPORT_ORB_Z = 75.
        /*
            Effect created while orbs are moving
        */
        private constant string TELEPORT_ORB_SFX = "Abilities\\Spells\\Human\\Feedback\\ArcaneTowerAttack.mdl"
        
        /*
            Teleportation Impact Orbs
        */
        
        /*
            Number of orbs released
        */
        private constant integer SHARD_NUMBER = 12
        /*
            Distance of orbs released
        */
        private constant real SHARD_DIST = TELEPORT_IMPACT_RADIUS // Base Value
        /*
            Height
        */
        private constant real SHARD_ARC_Z = 0.5
        /*
            Effect when orbs die
        */
        private constant string SHARD_SFX = "Abilities\\Spells\\Human\\Feedback\\ArcaneTowerAttack.mdl"
        /*
            Misc Globals
        */
        private Table dtb 
        private timer t = CreateTimer()
        private group g = CreateGroup()
    endglobals
    
    /*
        Dummy Struct
    */
    private struct Dummy extends array
        static integer c
        static Dummy array r
         
        static unit array u
        static unit array ru

        method move takes real x, real y returns nothing
            call SetUnitX(u[this], GetBoundedX(x))
            call SetUnitY(u[this], GetBoundedY(y))
        endmethod
        
        static method create takes player p, real x, real y, real z returns Dummy
            local Dummy this = r[0]
            if 0 == this then
                set this = c + 1
                set c = this
                set u[this] = CreateUnit(p, DUMMY, x, y, 0)
                if UnitAddAbility(u[this], 'Amrf') and UnitRemoveAbility(u[this], 'Amrf') then
                endif
            else
                set u[this] = ru[this]
                set r[0] = r[this]
                call this.move(x, y)
            endif
            call SetUnitFlyHeight(u[this], z, 0)
            return this
        endmethod
        
        method destroy takes nothing returns nothing
            set ru[this] = u[this]
            set u[this] = null
            set r[this] = r[0]
            set r[0] = this
            call this.move(WorldBounds.minX, WorldBounds.minY)
        endmethod
    endstruct
    
    private struct Portal extends array
    endstruct
    
    private struct OrbMissile extends array
    endstruct
    
    private struct Orb extends array
    endstruct
    
    private struct ShardOrbs extends array
    endstruct 
    
    private struct Spell extends array
    endstruct
endlibrary

So many constants, wrote my own dummy system, linked to libs.
 
because I looked at his trigger and saw that he was already doing that thing...
JASS:
function TrigCE_AllocateData takes nothing returns boolean
    // Sets up the variables required for creating units
    local unit u = GetTriggerUnit()
    local integer iLevel = GetUnitAbilityLevel(u, CE_SpellID())
    local real rLevel = I2R(iLevel)
    local real x = GetSpellTargetX()
    local real x2 = GetUnitX(u)
    local real y = GetSpellTargetY()
    local real y2 = GetUnitY(u)
    local real Angle = 0.00
    
    // Checks if the ability casted was the correct one
    if (GetSpellAbilityId() == CE_SpellID()) then
        // Initialises  new spell instance
 

Cokemonkey11

Code Reviewer
Level 29
Joined
May 9, 2006
Messages
3,522
because I looked at his trigger and saw that he was already doing that thing...
JASS:
function TrigCE_AllocateData takes nothing returns boolean
    // Sets up the variables required for creating units
    local unit u = GetTriggerUnit()
    local integer iLevel = GetUnitAbilityLevel(u, CE_SpellID())
    local real rLevel = I2R(iLevel)
    local real x = GetSpellTargetX()
    local real x2 = GetUnitX(u)
    local real y = GetSpellTargetY()
    local real y2 = GetUnitY(u)
    local real Angle = 0.00
    
    // Checks if the ability casted was the correct one
    if (GetSpellAbilityId() == CE_SpellID()) then
        // Initialises  new spell instance

He is suggesting that he do this:

JASS:
function TrigCE_AllocateData takes nothing returns boolean
    // Sets up the variables required for creating units
    local unit u
    local integer iLevel
    local real rLevel
    local real x
    local real x2
    local real y
    local real y2
    local real Angle = 0.00
    // Checks if the ability casted was the correct one
    if (GetSpellAbilityId() == CE_SpellID()) then
        set u=GetTriggerUnit()
        set iLevel=GetUnitAbilityLevel(u,CE_SpellID())
        set rLevel = I2R(iLevel)
        set x = GetSpellTargetX()
        set x2 = GetUnitX(u)
        set y = GetSpellTargetY()
        set y2 = GetUnitY(u)
        // Initialises  new spell instance

Which would prevent 7 native calls from being executed after every spell effect
 

Bannar

Code Reviewer
Level 26
Joined
Mar 19, 2008
Messages
3,140
First and foremost: don't talk about others code since it's not fair for some that one gets help while he does not. Great part of points you get is code efficiency/readability and such.
You can talk about improvements later. Yes, I've mentioned indexing for tank-commander too, but since he creates ton of units it could crash thread in some circumstances (multiple casts + map's set of units).
 

Cokemonkey11

Code Reviewer
Level 29
Joined
May 9, 2006
Messages
3,522
Here's a WIP for a lib I need -

JASS:
library DummyUnitStack
    struct DummyUnitStack
        private static constant integer DUMMY_UNIT_ID='u000'
        private static constant integer MIN_PRELOAD_BLOCK_SIZE=10 //How many units to preload when the preloading algorithm turns on, at a minimum?
        
        private static constant integer PRELOAD_INIT_COUNT=2000 //How many units to preload during initialization (set to 0 to disable)
        private static constant boolean DO_PIC=true
        
        private static constant integer DYNAMIC_DEFERRED_PRELOAD_COUNT=100 //How many units should DummyUnitStack keep preloaded at a minimum?
        private static constant boolean DO_DDPC=true
        
        private static constant integer INITIAL_DEFERRED_PRELOAD_COUNT=2000 //How many units should be queued on the preloader on map start?
        private static constant boolean DO_IDPC=true
        
        private static constant integer MAX_PRELOADED_UNITS=5000
        private static constant boolean DO_MPU=true
        
        private static constant real SAFE_LOC_X=2460.
        private static constant real SAFE_LOC_Y=2210.
        private static constant real CLOCK_PERIOD=1./60.
        private static unit array dummyStack
        private static integer stackIndex=-1
        private static integer deferredTodoCount=0
        private static timer clock=CreateTimer()
        
        private static method add takes boolean preloading returns unit
            local unit u=CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE),thistype.DUMMY_UNIT_ID,thistype.SAFE_LOC_X,thistype.SAFE_LOC_Y,0.)
            call UnitAddAbility(u,'Aloc')
            call UnitAddAbility(u,'Arav')
            if preloading then
                set thistype.stackIndex=thistype.stackIndex+1
                set thistype.dummyStack[thistype.stackIndex]=u
            else
                return u
            endif
            return null
        endmethod
        
        public static method deferredPreloader takes nothing returns nothing
            set thistype.deferredTodoCount=thistype.deferredTodoCount-1
            call thistype.add(true)
            if thistype.deferredTodoCount<1 then
                call PauseTimer(thistype.clock)
            endif
        endmethod
        
        public static method get takes nothing returns unit
            local unit result
            if thistype.stackIndex!=-1 then
                set thistype.stackIndex=thistype.stackIndex-1
                set result=thistype.dummyStack[thistype.stackIndex+1]
            else
                set result=thistype.add(false)
            endif
            static if DO_DDPC then
                if thistype.stackIndex<(thistype.DYNAMIC_DEFERRED_PRELOAD_COUNT-1) and thistype.deferredTodoCount<1 then
                    set thistype.deferredTodoCount=thistype.MIN_PRELOAD_BLOCK_SIZE
                    call TimerStart(thistype.clock,thistype.CLOCK_PERIOD,true,function thistype.deferredPreloader)
                endif
            endif
            return result
        endmethod
        
        public static method release takes unit u returns nothing
            static if DO_MPU then
                if thistype.stackIndex>=thistype.MAX_PRELOADED_UNITS then
                    call RemoveUnit(u)
                    return
                endif
            endif
            call SetUnitOwner(u,Player(PLAYER_NEUTRAL_PASSIVE),true)
            call SetUnitX(u,thistype.SAFE_LOC_X)
            call SetUnitY(u,thistype.SAFE_LOC_Y)
            set thistype.stackIndex=thistype.stackIndex+1
            set thistype.dummyStack[thistype.stackIndex]=u
        endmethod
        
        private static method onInit takes nothing returns nothing
            local integer index=1
            static if DO_PIC then
                loop
                    exitwhen index>thistype.PRELOAD_INIT_COUNT
                    call thistype.add(true)
                    set index=index+1
                endloop
            endif
            static if DO_IDPC then
                set thistype.deferredTodoCount=thistype.INITIAL_DEFERRED_PRELOAD_COUNT
                call TimerStart(thistype.clock,thistype.CLOCK_PERIOD,true,function thistype.deferredPreloader)
            endif
        endmethod
    endstruct
endlibrary

Let the effect spam commence \m/
 
3rd WIP:
JASS:
library ArcanceWormholes /* v1.0
*************************************************************************************
*
*    Arcane Wormholes
*       ~ Almia
*
*    --------------------------------------------------------------------------
*
*        Description
*
*        ------------------------------------------
*
*    --------------------------------------------------------------------------
*
*        */ requires /*
*
*        ------------------------------------------
*
*            */ Table /*       [url]www.hiveworkshop.com/forums/jass-resources-412/snippet-new-table-188084/[/url]
*            */ WorldBounds /*   [url]www.hiveworkshop.com/forums/jass-resources-412/snippet-worldbounds-180494/[/url]
*            */ MapBounds /* [url]www.hiveworkshop.com/forums/jass-resources-412/snippet-mapbounds-222870/[/url]
*
*    --------------------------------------------------------------------------
*
*        Credits
*
*        ------------------------------------------
*
*            Nestharus
*            Bribe
*            Adiktuz
*
*************************************************************************************/
    globals
        /*
           Ability main constants
        */
        private constant real TIMEOUT = 0.031250000
        /*
            Main Ability Raw Code
        */
        private constant integer MAIN = 'A000'
        /*
            Sub Ability Raw Code
        */
        private constant integer SUB = 'A001'
        /*
            Dummy Raw Code
        */
        private constant integer DUMMY = 'h000'
        /*
            Max Spell Charges
        */
        private constant integer SPELL_CHARGES = 3
        
        /*
            Caster Orbs
        */
        
        /*
            Number of orbs spinning around the caster
        */
        private constant integer CASTER_ORB_NUMBER = 3
        /*
            How far are they from the caster
        */
        private constant real CASTER_ORB_DIST = 150.
        /*
            How fast the orbs spins around by angle
        */
        private constant real CASTER_ORB_SPIN_SPEED = 90.
        /*
            Model Path of the caster orbs
        */
        private constant string CASTER_ORB_MDL = "Abilities\\Weapons\\SpiritOfVengeanceMissile\\SpiritOfVengeanceMissile.mdl"
        /*
            Orb Model Size
        */
        private constant real CASTER_ORB_SIZE = 1.
        /*
            Orb Caster Height
        */
        private constant real CASTER_ORB_Z = 50.
        
        /*
            Orb Missile
        */
        
        /*
            Missile Speed
        */
        private constant real ORB_MISSILE_SPEED = 500.
        /*
            Missile Model
        */
        private constant string ORB_MISSILE_MDL = "Abilities\\Weapons\\SpiritOfVengeanceMissile\\SpiritOfVengeanceMissile.mdl"
        /*
            Missile Size
        */
        private constant real ORB_MISSILE_SIZE = 1.
        
        /*
            Missile Height
        */
        private constant real ORB_MISSILE_Z = 50.
        /*
            Missile Impact Effect
        */
        private constant string ORB_IMPACT_EFFECt =  "Objects\\Spawnmodels\\NightElf\\NECancelDeath\\NECancelDeath.mdl"
        
        /*
            Portal
        */
        
        /*
            Portal Model
        */
        private constant string PORTAL_MDL = "units\\nightelf\\Wisp\\Wisp.mdl"
        /*
            Portal Size
        */
        private constant real PORTAL_SIZE = 1.
        /*
            Portal Height
        */
        private constant real PORTAL_Z = 50.
        /*
            Portal Duration
        */
        private constant real PORTAL_DURATION = 60.
        /*
            Portal Death Effect
        */
        private constant string PORTAL_DEATH_SFX = "Objects\\Spawnmodels\\NightElf\\NECancelDeath\\NECancelDeath.mdl"
        
        /*
            Portal Orbs
        */
        
        /*
            Number of orbs spinning around the portal
        */
        private constant real PORTAL_ORB_NUMBER = 3
        /*
            How far the orbs are from the portal
        */
        private constant real PORTAL_ORB_DIST = 150.
        /*
            Portal Orb Spin Speed
        */
        private constant real PORTAL_ORB_SPIN_SPEED = 90.
        /*
            Portal Orb Model
        */
        private constant string PORTAL_ORB_MDL = "Abilities\\Weapons\\SpiritOfVengeanceMissile\\SpiritOfVengeanceMissile.mdl"
        /*
            Portal Orb Scale
        */
        private constant real PORTAL_ORB_SIZE = 1.
        /*
           Portal Orb Z
        */
        private constant real PORTAL_ORB_Z = 75.
        
        /*
            Teleportation Constants
        */
        
        /*
            Radius of units that will be also teleported
        */
        private constant real TELEPORT_RADIUS = 500.
        /*
            Teleportation Delay
        */
        private constant real TELEPORT_DELAY = 5.
        /*
            Teleportation On Cast Effect
        */
        private constant string TELEPORT_CAST_SFX = "Abilities\\Spells\\Other\\Charm\\CharmTarget.mdl"
        private constant string TELEPORT_CAST_ATTACH = "overhead"
        /*
            Channeling Effect on Caster
        */
        private constant string TELEPORT_CHANNEL_SFX = "Abilities\\Spells\\Other\\Drain\\ManaDrainTarget.mdl"
        private constant string TELEPORT_CHANNEL_ATTACH = "origin"
        /*
            Random Effect Channel
        */
        private constant string TELEPORT_RANDOM_SFX = "Abilities\\Spells\\Undead\\AbsorbMana\\AbsorbManaBirthMissile.mdl"
        /*
            Teleportation Success Effect
        */
        private constant string TELEPORT_END_SFX = "Objects\\Spawnmodels\\NightElf\\NECancelDeath\\NECancelDeath.mdl"
        /*
            Teleportation Impact Effect
        */
        private constant string TELEPORT_IMPACT_SFX ="Abilities\\Spells\\Orc\\WarStomp\\WarStompCaster.mdl"
        /*
            Teleportation Damage and Mana Burn Radius
        */
        private constant real TELEPORT_IMPACT_RADIUS = 400. // Base value
        /*
            Teleportation Damage value
        */
        private constant real TELEPORT_IMPACT_DAMAGE = 25. // Base Value
        /*
            Teleportation Mana Burn Value
        */
        private constant real TELEPORT_IMPACT_BURN = 25. // Base Value
        /*
            Teleportation Mana Burn and Damage SFX
        */
        private constant string TELEPORT_DMB_SFX = "Abilities\\Spells\\Human\\Feedback\\ArcaneTowerAttack.mdl"
        private constant string TELEPORT_DMB_ATTACH = "chest"
        
        /*
            Teleportation Orbs
        */
        
        /*
            Number of orbs spinning around the caster
        */
        private constant real TELEPORT_ORB_NUMBER = 6
        /*
            How far the orbs are from the portal
        */
        private constant real TELEPORT_ORB_DIST = TELEPORT_RADIUS
        /*
            Portal Orb Spin Speed
        */
        private constant real TELEPORT_ORB_SPIN_SPEED = 90.
        /*
            Portal Orb Model
        */
        private constant string TELEPORT_ORB_MDL = "Abilities\\Weapons\\SpiritOfVengeanceMissile\\SpiritOfVengeanceMissile.mdl"
        /*
            Portal Orb Scale
        */
        private constant real TELEPORT_ORB_SIZE = 1.
        /*
           Portal Orb Z
        */
        private constant real TELEPORT_ORB_Z = 75.
        /*
            Effect created while orbs are moving
        */
        private constant string TELEPORT_ORB_SFX = "Abilities\\Spells\\Human\\Feedback\\ArcaneTowerAttack.mdl"
        
        /*
            Teleportation Impact Orbs
        */
        
        /*
            Number of orbs released
        */
        private constant integer SHARD_NUMBER = 12
        /*
            Distance of orbs released
        */
        private constant real SHARD_DIST = TELEPORT_IMPACT_RADIUS // Base Value
        /*
            Height
        */
        private constant real SHARD_ARC_Z = 0.5
        /*
            Effect when orbs die
        */
        private constant string SHARD_SFX = "Abilities\\Spells\\Human\\Feedback\\ArcaneTowerAttack.mdl"
        /*
            Misc Globals
        */
        private Table dtb 
        private timer pt = CreateTimer()
        private timer st = CreateTimer()
        private timer ot = CreateTimer()
        private timer mt = CreateTimer()
        private timer ct = CreateTimer()
        private group g = CreateGroup()
    endglobals

    /*
        List
    */
    module List
        static integer array n
        static integer array p
        static integer array r
        static integer c = 0
        static integer ic = 0
        
        static method add takes nothing returns thistype
            local thistype this = r[0]
            if 0 == this then
                set ic = ic + 1
                set this = ic
            else
                set r[0] = r[this]
            endif
            set n[this] = 0
            set p[this] = 0
            set n[p[0]] = this
            set p[0] = this
            return this
        endmethod
        
        method remove takes nothing returns nothing
            set n[p[this]] = n[this]
            set p[n[this]] = p[this]
                    
            set r[this] = r[0]
            set r[0] = this
        endmethod
        
    endmodule
    
    /*
        Dummy Struct
        
        For spell dummies
    */    
    private struct Dummy extends array
        static integer c = 0
        static Dummy array r
         
        static unit array u
        static effect array e
        
        method move takes real x, real y returns nothing
            call SetUnitX(u[this], GetBoundedX(x))
            call SetUnitY(u[this], GetBoundedY(y))
        endmethod
        
        static method create takes player p, real x, real y, real z, real face, string mdl, real scale returns Dummy
            local Dummy this = r[0]
            if 0 == this then
                set this = c + 1
                set c = this
                set u[this] = CreateUnit(p, DUMMY, x, y, face)
                if UnitAddAbility(u[this], 'Amrf') and UnitRemoveAbility(u[this], 'Amrf') then
                endif
            else
                set r[0] = r[this]
                call this.move(x, y)
                call SetUnitOwner(u[this], p, false)
                call SetUnitFacing(u[this], face)
            endif
            set e[this] = AddSpecialEffectTarget(mdl, u[this], "origin")
            call SetUnitFlyHeight(u[this], z, 0)
            call SetUnitScale(u[this], scale, 0, 0)
            return this
        endmethod
        
        method destroy takes nothing returns nothing
            call DestroyEffect(e[this])
            set e[this] = null
            set r[this] = r[0]
            set r[0] = this
            call SetUnitOwner(u[this], Player(15), false)
            call this.move(WorldBounds.minX, WorldBounds.minY)
        endmethod
    endstruct
    
    private struct OrbMissile extends array
    endstruct
    
    /*
       Orb
       Spinning dummies
    */
    private struct Orb extends array
        implement List
        
        static Dummy array d
        static real array dur
        static real array speed
        static real array dist
        static real array angle
        static unit array org
        
        static method periodic takes nothing returns nothing
            local Orb this = n[0]
            local real x
            local real y
            loop
                exitwhen 0 == this
                if 0 < dur[this] then
                    set dur[this] = dur[this] - TIMEOUT
                    set angle[this] = angle[this] + speed[this]
                    set x = GetUnitX(org[this]) + dist[this] * Cos(angle[this] * bj_DEGTORAD)
                    set y = GetUnitY(org[this]) + dist[this] * Sin(angle[this] * bj_DEGTORAD)
                    
                    call d[this].move(x, y)
                else
                    call d[this].destroy()
                    set d[this] = 0
                    set dur[this] = 0
                    set speed[this] = 0
                    set dist[this] = 0
                    set org[this] = null
                    set angle[this] = 0
                    
                    call this.remove()
                    set c = c - 1
                    if 0 == c then
                        call PauseTimer(ot)
                    endif
                endif
                
                set this = n[this]
            endloop
        endmethod
        
        static method create takes string mdl, player p, unit o, real z, real sc, real ds, real s, real time, real a returns Orb
            local Orb this = Orb.add()
            set d[this] = Dummy.create(p, GetUnitX(o), GetUnitY(o), z, a, mdl, sc)
            set speed[this] = s * TIMEOUT
            set dist[this] = ds
            set dur[this] = time
            set angle[this] = a
            set org[this] = o
            set c = c + 1
            if 1 == c then
                call TimerStart(ot, TIMEOUT, true, function Orb.periodic)
            endif
            return this
        endmethod
        
    endstruct

    private struct Portal extends array
        implement List
        
        static real array dur
        static Dummy array pt
        
        static method periodic takes nothing returns nothing
            local integer i = n[0]
            loop
                exitwhen 0 == i
                set i = n[i]
            endloop
        endmethod
        
        static method create takes player pl, unit owner, real x, real y returns Portal
            local Portal this = r[0]
            if 0 == this then
                set ic = ic + 1
                set this = ic
            else
                set r[0] = r[this]
            endif
            set pt[this] = Dummy.create(pl, x, y, PORTAL_Z, 0, PORTAL_MDL, PORTAL_SIZE)
            set n[this] = 0
            set p[this] = 0
            set n[p[0]] = this
            set p[0] = this
            
            set c = c + 1
            if 1 == c then
            endif
            return this
        endmethod
    endstruct
    
    private struct ShardOrbs extends array
        implement List
    endstruct 
    
    private struct Spell extends array
        implement List
    endstruct
endlibrary
 

Attachments

  • ZC 10 Entry - Almia.w3x
    41.7 KB · Views: 38
Last edited:
Level 30
Joined
Nov 29, 2012
Messages
6,637
Here's my WiP 1. The skill is named as Nether Gate.

Nether Gate

1 Level

Description:
Summons a nether gate at the targeted point. After 5 seconds, it will unleash force summoning 3 Avatars namely: Avatar of Chaos, Void, and Hell. The Avatars lasts for 25 seconds and when they disappear they will bring forth explosion, dealing damage to the enemies around the Avatars. As the Avatars disappear, the portal disappears as well.


attachment.php


attachment.php


attachment.php




  • Nether Gate Cast
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • (Ability being cast) Equal to Nether Gate
    • Actions
      • Set Target_Point[0] = (Target point of ability being cast)
      • Unit - Create 1 Hell Gate for Player 1 (Red) at Target_Point[0] facing 270.00 degrees
      • Set LastCreated_Unit[1] = (Last created unit)
      • Animation - Play LastCreated_Unit[1]'s birth animation
      • Wait 5.00 seconds
      • Set Target_Point[1] = (Target_Point[0] offset by (-200.00, -100.00))
      • Unit - Create 1 Avatar of the Hell for Player 1 (Red) at Target_Point[1] facing 270.00 degrees
      • Set LastCreated_Unit[2] = (Last created unit)
      • Set Target_Point[2] = (Target_Point[0] offset by (0.00, -100.00))
      • Special Effect - Create a special effect at Target_Point[0] using Abilities\Spells\Orc\WarStomp\WarStompCaster.mdl
      • Unit - Create 1 Avatar of the Void for Player 1 (Red) at Target_Point[2] facing Default building facing degrees
      • Set LastCreated_Unit[3] = (Last created unit)
      • Set Target_Point[3] = (Target_Point[0] offset by (200.00, -100.00))
      • Special Effect - Create a special effect at Target_Point[0] using Abilities\Spells\Orc\WarStomp\WarStompCaster.mdl
      • Unit - Create 1 Avatar of the Chaos for Player 1 (Red) at Target_Point[3] facing Default building facing degrees
      • Set LastCreated_Unit[4] = (Last created unit)
      • Special Effect - Create a special effect at Target_Point[0] using Abilities\Spells\Orc\WarStomp\WarStompCaster.mdl
      • Custom script: call RemoveLocation( udg_Target_Point[0] )
      • Custom script: call RemoveLocation( udg_Target_Point[1] )
      • Custom script: call RemoveLocation( udg_Target_Point[2] )
      • Custom script: call RemoveLocation( udg_Target_Point[3] )

Sorry if no terrain yet just doing the skill for now and also the skill is not yet complete. Still gonna add a Duration for the Avatar's and Portal's life, 25 Seconds and also the damage dealth when the Avatar's disappear with the explosion.

And yes, I am a noob!
 

Attachments

  • WiP # 1 Screenshot 2.jpg
    WiP # 1 Screenshot 2.jpg
    117.2 KB · Views: 146
  • WiP # 1 Screenshot 3.jpg
    WiP # 1 Screenshot 3.jpg
    130.4 KB · Views: 145
  • WiP # 1 Screenshot 1.jpg
    WiP # 1 Screenshot 1.jpg
    122.5 KB · Views: 154

Cokemonkey11

Code Reviewer
Level 29
Joined
May 9, 2006
Messages
3,522
Here are the tooltips for my summoned unit's abilities.

Once again, since the contest judging is meant to be for one ability and one sub ability, these can be ignored for the judging criteria (!)
 

Attachments

  • 1.png
    1.png
    232.4 KB · Views: 207
  • 2.png
    2.png
    236.7 KB · Views: 128
  • 3.png
    3.png
    272.2 KB · Views: 145
  • 4.png
    4.png
    278.5 KB · Views: 116
Level 30
Joined
Nov 29, 2012
Messages
6,637
Here are the tooltips for my summoned unit's abilities.

Once again, since the contest judging is meant to be for one ability and one sub ability, these can be ignored for the judging criteria (!)

Wow, those skills are great. What I really love is that you triggered those wc3skills to be a bit better. Still staying with the wc3's abilities but improved by you! +3 REP!

Accidentaly typed +2...lol! My bad.. sorry CM.
 


Me has the same missiles too :D
Gonna code it now XD

edit
4th WIP:
JASS:
library ArcanceWormholes /* v1.0
*************************************************************************************
*
*    Arcane Wormholes
*       ~ Almia
*
*    --------------------------------------------------------------------------
*
*        Description
*
*        ------------------------------------------
*
*    --------------------------------------------------------------------------
*
*        */ requires /*
*
*        ------------------------------------------
*
*            */ SpellEffectEvent /*    
*                hiveworkshop.com/forums/jass-resources-412/snippet-spelleffectevent-187193/     
*            */ WorldBounds /*         
*                hiveworkshop.com/forums/jass-resources-412/snippet-worldbounds-180494/
*            */ MapBounds /*           
*                hiveworkshop.com/forums/jass-resources-412/snippet-mapbounds-222870/
*
*    --------------------------------------------------------------------------
*
*        Credits
*
*        ------------------------------------------
*
*            Nestharus
*            Bribe
*            Adiktuz
*
*************************************************************************************/
    globals
        /*
           Ability main constants
        */
        private constant real TIMEOUT = 0.031250000
        /*
            Main Ability Raw Code
        */
        private constant integer MAIN = 'A000'
        /*
            Sub Ability Raw Code
        */
        private constant integer SUB = 'A001'
        /*
            Dummy Raw Code
        */
        private constant integer DUMMY = 'h000'
        /*
            Max Spell Charges
        */
        private constant integer SPELL_CHARGES = 3
        
        /*
           Effects created of all orbs
        */
        private constant string ORB_SFX = "Abilities\\Spells\\Human\\Feedback\\ArcaneTowerAttack.mdl"
        
        /*
            Caster Orbs
        */
        
        /*
            Number of orbs spinning around the caster
        */
        private constant integer CASTER_ORB_NUMBER = 3
        /*
            How far are they from the caster
        */
        private constant real CASTER_ORB_DIST = 150.
        /*
            How fast the orbs spins around by angle
        */
        private constant real CASTER_ORB_SPIN_SPEED = 90.
        /*
            Model Path of the caster orbs
        */
        private constant string CASTER_ORB_MDL = "Abilities\\Weapons\\SpiritOfVengeanceMissile\\SpiritOfVengeanceMissile.mdl"
        /*
            Orb Model Size
        */
        private constant real CASTER_ORB_SIZE = 1.
        /*
            Orb Caster Height
        */
        private constant real CASTER_ORB_Z = 50.
        
        /*
            Orb Missile
        */
        
        /*
            Missile Speed
        */
        private constant real ORB_MISSILE_SPEED = 500.
        /*
            Missile Model
        */
        private constant string ORB_MISSILE_MDL = "Abilities\\Weapons\\SpiritOfVengeanceMissile\\SpiritOfVengeanceMissile.mdl"
        /*
            Missile Size
        */
        private constant real ORB_MISSILE_SIZE = 1.
        
        /*
            Missile Height
        */
        private constant real ORB_MISSILE_Z = 50.
        /*
            Missile Impact Effect
        */
        private constant string ORB_IMPACT_EFFECt =  "Objects\\Spawnmodels\\NightElf\\NECancelDeath\\NECancelDeath.mdl"
        
        /*
            Portal
        */
        
        /*
            Portal Model
        */
        private constant string PORTAL_MDL = "units\\nightelf\\Wisp\\Wisp.mdl"
        /*
            Portal Size
        */
        private constant real PORTAL_SIZE = 1.
        /*
            Portal Height
        */
        private constant real PORTAL_Z = 50.
        /*
            Portal Duration
        */
        private constant real PORTAL_DURATION = 60.
        /*
            Portal Death Effect
        */
        private constant string PORTAL_DEATH_SFX = "Objects\\Spawnmodels\\NightElf\\NECancelDeath\\NECancelDeath.mdl"
        
        /*
            Portal Orbs
        */
        
        /*
            Number of orbs spinning around the portal
        */
        private constant real PORTAL_ORB_NUMBER = 3
        /*
            How far the orbs are from the portal
        */
        private constant real PORTAL_ORB_DIST = 150.
        /*
            Portal Orb Spin Speed
        */
        private constant real PORTAL_ORB_SPIN_SPEED = 90.
        /*
            Portal Orb Model
        */
        private constant string PORTAL_ORB_MDL = "Abilities\\Weapons\\SpiritOfVengeanceMissile\\SpiritOfVengeanceMissile.mdl"
        /*
            Portal Orb Scale
        */
        private constant real PORTAL_ORB_SIZE = 1.
        /*
           Portal Orb Z
        */
        private constant real PORTAL_ORB_Z = 75.
        
        /*
            Teleportation Constants
        */
        
        /*
            Radius of units that will be also teleported
        */
        private constant real TELEPORT_RADIUS = 500.
        /*
            Teleportation Delay
        */
        private constant real TELEPORT_DELAY = 5.
        /*
            Teleportation On Cast Effect
        */
        private constant string TELEPORT_CAST_SFX = "Abilities\\Spells\\Other\\Charm\\CharmTarget.mdl"
        private constant string TELEPORT_CAST_ATTACH = "overhead"
        /*
            Channeling Effect on Caster
        */
        private constant string TELEPORT_CHANNEL_SFX = "Abilities\\Spells\\Other\\Drain\\ManaDrainTarget.mdl"
        private constant string TELEPORT_CHANNEL_ATTACH = "origin"
        /*
            Random Effect Channel
        */
        private constant string TELEPORT_RANDOM_SFX = "Abilities\\Spells\\Undead\\AbsorbMana\\AbsorbManaBirthMissile.mdl"
        /*
            Teleportation Success Effect
        */
        private constant string TELEPORT_END_SFX = "Objects\\Spawnmodels\\NightElf\\NECancelDeath\\NECancelDeath.mdl"
        /*
            Teleportation Impact Effect
        */
        private constant string TELEPORT_IMPACT_SFX ="Abilities\\Spells\\Orc\\WarStomp\\WarStompCaster.mdl"
        /*
            Teleportation Damage and Mana Burn Radius
        */
        private constant real TELEPORT_IMPACT_RADIUS = 400. // Base value
        /*
            Teleportation Damage value
        */
        private constant real TELEPORT_IMPACT_DAMAGE = 25. // Base Value
        /*
            Teleportation Mana Burn Value
        */
        private constant real TELEPORT_IMPACT_BURN = 25. // Base Value
        /*
            Teleportation Mana Burn and Damage SFX
        */
        private constant string TELEPORT_DMB_SFX = "Abilities\\Spells\\Human\\Feedback\\ArcaneTowerAttack.mdl"
        private constant string TELEPORT_DMB_ATTACH = "chest"
        
        /*
            Teleportation Orbs
        */
        
        /*
            Number of orbs spinning around the caster
        */
        private constant real TELEPORT_ORB_NUMBER = 6
        /*
            How far the orbs are from the portal
        */
        private constant real TELEPORT_ORB_DIST = TELEPORT_RADIUS
        /*
            Portal Orb Spin Speed
        */
        private constant real TELEPORT_ORB_SPIN_SPEED = 90.
        /*
            Portal Orb Model
        */
        private constant string TELEPORT_ORB_MDL = "Abilities\\Weapons\\SpiritOfVengeanceMissile\\SpiritOfVengeanceMissile.mdl"
        /*
            Portal Orb Scale
        */
        private constant real TELEPORT_ORB_SIZE = 1.
        /*
           Portal Orb Z
        */
        private constant real TELEPORT_ORB_Z = 75. 
        
        /*
            Teleportation Impact Orbs
        */
        
        /*
            Number of orbs released
        */
        private constant integer SHARD_NUMBER = 12
        /*
            Distance of orbs released
        */
        private constant real SHARD_DIST = TELEPORT_IMPACT_RADIUS // Base Value
        /*
            Height
        */
        private constant real SHARD_ARC_Z = 0.5
        /*
            Effect when orbs die
        */
        private constant string SHARD_SFX = "Abilities\\Spells\\Human\\Feedback\\ArcaneTowerAttack.mdl"
        /*
            Misc Globals
        */
        private hashtable ht
        private timer pt = CreateTimer()
        private timer st = CreateTimer()
        private timer ot = CreateTimer()
        private timer mt = CreateTimer()
        private timer ct = CreateTimer()
        private group g = CreateGroup()
    endglobals

    /*
        List
    */
    private module List
        static integer array n
        static integer array p
        static integer array r
        static integer c = 0
        static integer ic = 0
        
        static method add takes nothing returns thistype
            local thistype this = r[0]
            if 0 == this then
                set ic = ic + 1
                set this = ic
            else
                set r[0] = r[this]
            endif
            set n[this] = 0
            set p[this] = 0
            set n[p[0]] = this
            set p[0] = this
            return this
        endmethod
        
        method remove takes nothing returns nothing
            set n[p[this]] = n[this]
            set p[n[this]] = p[this]
                    
            set r[this] = r[0]
            set r[0] = this
        endmethod
        
    endmodule
    
    /*
        Dummy Struct
        
        For spell dummies
    */    
    private struct Dummy extends array
        static integer c = 0
        static Dummy array r
         
        static unit array u
        static effect array e
        static boolean array dead
        static real array tx
        static real array ty
        
        method operator angle= takes real a returns nothing
            call SetUnitFacing(u[this], a)
        endmethod
        
        method operator isDead takes nothing returns boolean
            return dead[this]
        endmethod
        
        method operator x takes nothing returns real
            return tx[this]
        endmethod
        
        method operator y takes nothing returns real
            return ty[this]
        endmethod
        
        method move takes real tmx, real tmy returns nothing
            call SetUnitX(u[this], GetBoundedX(tmx))
            call SetUnitY(u[this], GetBoundedY(tmy))
            set tx[this] = tmx
            set ty[this] = tmy
        endmethod
        
        static method create takes player p, real tmx, real tmy, real z, real face, string mdl, real scale returns Dummy
            local Dummy this = r[0]
            if 0 == this then
                set this = c + 1
                set c = this
                set u[this] = CreateUnit(p, DUMMY, tmx, tmy, face)
                if UnitAddAbility(u[this], 'Amrf') and UnitRemoveAbility(u[this], 'Amrf') then
                endif
                set tx[this] = tmx
                set ty[this] = tmy
            else
                set r[0] = r[this]
                call this.move(tmx, tmy)
                call SetUnitOwner(u[this], p, false)
                call SetUnitFacing(u[this], face)
            endif
            set dead[this] = false
            set e[this] = AddSpecialEffectTarget(mdl, u[this], "origin")
            call SetUnitFlyHeight(u[this], z, 0)
            call SetUnitScale(u[this], scale, 0, 0)
            return this
        endmethod
        
        method destroy takes nothing returns nothing
            call DestroyEffect(e[this])
            set dead[this] = true
            set e[this] = null
            set r[this] = r[0]
            set r[0] = this
            call SetUnitOwner(u[this], Player(15), false)
            call this.move(WorldBounds.minX, WorldBounds.minY)
        endmethod
    endstruct
    
    /************************
    *  
    *    Orb  Struct
    *    Spinning dummies
    *
    *************************/
    private struct Orb extends array
        implement List
        
        static Dummy array d
        static real array dur
        static real array speed
        static real array dist
        static real array angle
        static unit array org
        
        static method periodic takes nothing returns nothing
            local Orb this = n[0]
            local real x
            local real y
            loop
                exitwhen 0 == this
                if 0 < dur[this] then
                    set dur[this] = dur[this] - TIMEOUT
                    set angle[this] = angle[this] + speed[this]
                    set x = GetUnitX(org[this]) + dist[this] * Cos(angle[this] * bj_DEGTORAD)
                    set y = GetUnitY(org[this]) + dist[this] * Sin(angle[this] * bj_DEGTORAD)
                    set d[this].angle = angle[this]
                    call DestroyEffect(AddSpecialEffect(ORB_SFX, x, y))
                    call d[this].move(x, y)
                else
                    call d[this].destroy()
                    set d[this] = 0
                    set dur[this] = 0
                    set speed[this] = 0
                    set dist[this] = 0
                    set org[this] = null
                    set angle[this] = 0
                    
                    call this.remove()
                    set c = c - 1
                    if 0 == c then
                        call PauseTimer(ot)
                    endif
                endif
                
                set this = n[this]
            endloop
        endmethod
        
        static method create takes string mdl, player p, unit o, real z, real sc, real ds, real s, real time, real a returns Orb
            local Orb this = Orb.add()
            set d[this] = Dummy.create(p, GetUnitX(o), GetUnitY(o), z, a, mdl, sc)
            set speed[this] = s * TIMEOUT
            set dist[this] = ds
            set dur[this] = time
            set angle[this] = a
            set org[this] = o
            set c = c + 1
            if 1 == c then
                call TimerStart(ot, TIMEOUT, true, function Orb.periodic)
            endif
            return this
        endmethod
    endstruct

    /*******************************
    *
    *    Portal Struct
    *
    *******************************/
    private struct Portal extends array
        implement List
        
        static real array dur
        static Dummy array po
        static unit array o
        
        static method periodic takes nothing returns nothing
            local Portal this = n[0]
            local integer id
            local integer i
            loop
                exitwhen 0 == this
                if 0 < dur[this] then
                    set dur[this] = dur[this] - TIMEOUT
                else
                    call this.remove()
                    set id = GetHandleId(o[this])
                    set i = LoadInteger(ht, id, 0)
                    if i < SPELL_CHARGES then
                        call SaveInteger(ht, id, 0, i + 1)
                    endif
                    call po[this].destroy()
                    set po[this] = 0
                    set dur[this] = 0
                endif
                set this = n[this]
            endloop
        endmethod
        
        static method create takes player pl, unit owner, real x, real y returns Portal
            local Portal this = Portal.add()
            local integer i = 0
            set po[this] = Dummy.create(pl, x, y, PORTAL_Z, 0, PORTAL_MDL, PORTAL_SIZE)
            set o[this] = owner
            loop
                exitwhen i == PORTAL_ORB_NUMBER
                set i = i + 1
                call Orb.create(PORTAL_ORB_MDL, pl, owner, PORTAL_ORB_Z, PORTAL_ORB_SIZE, PORTAL_ORB_DIST, PORTAL_ORB_SPIN_SPEED, PORTAL_DURATION, i * (360./ PORTAL_ORB_NUMBER))
            endloop
            set c = c + 1
            if 1 == c then
                call TimerStart(pt, TIMEOUT, true, function Portal.periodic)
            endif
            return this
        endmethod
    endstruct
    
    private struct OrbMissile extends array
        implement List
        
        static Dummy array d
        static unit array o
        static real array di
        static real array a
        
        static method periodic takes nothing returns nothing
            local OrbMissile this = n[0]
            local real x
            local real y
            loop
                exitwhen 0 == this
                if 0 < di[this] then
                    set di[this] = di[this] + (ORB_MISSILE_SPEED * TIMEOUT)
                    set x = d[this].x + di[this] * Cos(a[this] * bj_DEGTORAD)
                    set y = d[this].y + di[this] * Sin(a[this] * bj_DEGTORAD)
                    call d[this].move(x, y)
                    set d[this].angle = a[this]
                    call DestroyEffect(AddSpecialEffect(ORB_SFX, x, y))
                else
                    call d[this].destroy()
                    call Portal.create(GetOwningPlayer(o[this]), o[this], d[this].x, d[this].y)
                    set d[this] = 0
                    set di[this] = 0
                    set a[this] = 0
                    set o[this] = null
                    
                    set c = c - 1
                    if 0 == c then
                        call PauseTimer(mt)
                    endif
                endif
                set this = n[this]
            endloop
        endmethod
        
        static method create takes player p, unit owner, real dist, real angle returns OrbMissile
            local OrbMissile this = OrbMissile.add()
            local real x = GetUnitX(owner)
            local real y = GetUnitX(owner)
            set d[this] = Dummy.create(p, x, y, ORB_MISSILE_Z, angle, ORB_MISSILE_MDL, ORB_MISSILE_SIZE)
            set a[this] = angle
            set o[this] = owner
            set di[this] = dist
            return this
        endmethod
    endstruct
    
    private struct ShardOrbs extends array
        implement List
    endstruct 
    
    private struct Spell extends array
        implement List
    endstruct
endlibrary

Wrote OrbMissile and Portal structs complete. I have added dummy operators.
 

Attachments

  • ZC 10 Entry - Almia.w3x
    36.2 KB · Views: 43
Last edited:

Cokemonkey11

Code Reviewer
Level 29
Joined
May 9, 2006
Messages
3,522
I'm going to go ahead and submit my (final?) entry now. I should be spending my time on other things anyway.

Item Description 1: http://www.hiveworkshop.com/forums/...r-contest-10-what-lies-other-side-screen1.png
Item Description 2: http://www.hiveworkshop.com/forums/...r-contest-10-what-lies-other-side-screen2.png
Spell Description 1: http://www.hiveworkshop.com/forums/...-zephyr-contest-10-what-lies-other-side-1.png
Spell Description 2: http://www.hiveworkshop.com/forums/...-zephyr-contest-10-what-lies-other-side-2.png
Spell Description 3: http://www.hiveworkshop.com/forums/...-zephyr-contest-10-what-lies-other-side-3.png
Spell Description 4: http://www.hiveworkshop.com/forums/...-zephyr-contest-10-what-lies-other-side-4.png
Summoning Video: http://www.youtube.com/watch?feature=player_embedded&v=jppEcHvpY1E

Please note that the summon is MUI but that doesn't mean you should do it 10 times in the same field of view. (The effect spamz are strong in this one). That being said, I can't forbid you to try it!

Note also one more time that since the contest is for judging at most 2 abilities, my summoned unit's abilities can be ignored for judging.

Good luck to everyone else in the contest.
 

Attachments

  • (1)ZephyrMedusasHead100.w3x
    207.3 KB · Views: 96
Last edited:

Cokemonkey11

Code Reviewer
Level 29
Joined
May 9, 2006
Messages
3,522
Curious, I take it those skulls mark the edge of the area medusa can stay within? I'm a bit concerned about sfx spam on that one (since it seems even more spammy than mine XD) but it looks great nonetheless ^^

Yes, these skulls move to the nearest edge from the item fx to medusa.

Actually, these effects are quite efficient. They're handled in an array and only allocated/deallocated once per cast.

Also, my entire spell technically only creates one unit!
 
Level 29
Joined
Mar 10, 2009
Messages
5,016
Now comes my WIP:
SwirlingPortal:
Creates a portal vortex that sucks enemy ground units at the center, the portal has a chance to call random skeleton warriors for the caster.
When portal finally comes to an end, a random powerful demon will emerge, throwing all sucked units in the air.

Level 1 - 10% that can summon a maximum of 3 skeleton warriors.
Level 2 - 20% that can summon a maximum of 6 skeleton warriors.
Level 3 - 30% that can summon a maximum of 9 skeleton warriors.

JASS:
/*
Spell Name: Swirling Portal
Created by: mckill2009 (entry for Zephyr Contest #10 ~ What lies on the other side)

REQUIRED LIBRARIES and CREDITS:
- CTL by Nesthaurus
- Table by Bribe
- RegisterPlayerUnitEvent by Magtheridon96
- SpellEffectEvent by Bribe
- IsUnitChanneling by Magtheridon96
- GroupUtils by Rising Dusk

*/



scope SwirlingPortal

globals
    //Configurable Block
    private constant integer SPELL_ID = 'A000' //based on Rain of Fire
    private constant integer DUMMY_ID = 'h003'
    private constant integer MISSILE_ID = 'h000'
    private constant real PULL_TOLERANCE = 4 //recommended, pull from center
    private constant real PORTAL_SHAPE = 6 //changes the 'shape' of the portal, recommended setting 1-7
    private constant real OFFSET_SPEED = 1.5 //this affects PORTAL_SHAPE, recommemded setting 1.5
    private constant real AOE = 400 //This should synchronize with the AOE from object editor
    private constant real SKELETON_LIFE = 15
    private constant string MOONSOON = "Abilities\\Spells\\Other\\Monsoon\\MonsoonBoltTarget.mdl"
    private constant string STAR = "Abilities\\Spells\\NightElf\\Starfall\\StarfallCaster.mdl"
    private constant string SUMMON_SKELETONS = "Abilities\\Spells\\Undead\\RaiseSkeletonWarrior\\RaiseSkeleton.mdl"
    private constant boolean ENABLE_CHANCE = true
    //Non-configurable Block
    private Table c
    private group g = CreateGroup()    
    private integer array monsterId
    private integer array skeletonId
    private real PartAoe
    private integer Count = 0
endglobals

//===Configurable Block
private function GetChance takes integer i returns integer
    return 10 * i
endfunction

private function GetCountSkeletons takes integer i returns integer
    return 3 * i
endfunction

//===Non-configurable Block
private function UnitAlive takes unit u returns boolean
    return not IsUnitType(u, UNIT_TYPE_DEAD)
endfunction

private function Pull takes unit caster, real xCenter, real yCenter, real aoe returns nothing
    local unit first
    local real angle
    local real x
    local real y
    call GroupEnumUnitsInRange(g, xCenter, yCenter, aoe, null)
    loop
        set first = FirstOfGroup(g)
        exitwhen first==null
        if UnitAlive(first) and IsUnitEnemy(caster, GetOwningPlayer(first)) and not IsUnitType(first, UNIT_TYPE_STRUCTURE) and not IsUnitType(first, UNIT_TYPE_FLYING) then
            set x = GetUnitX(first)
            set y = GetUnitY(first)
            set angle = Atan2(yCenter-y, xCenter-x)
            call SetUnitX(first, x+PULL_TOLERANCE*Cos(angle))
            call SetUnitY(first, y+PULL_TOLERANCE*Sin(angle))          
        endif
        call GroupRemoveUnit(g, first)
    endloop
endfunction

private function CountUnits takes nothing returns nothing
    local unit u = GetEnumUnit()
    if UnitAlive(u) then
        set Count = Count + 1
    endif 
endfunction
//=====================================================

private struct Fire extends array
    unit missile
    real angle
    real xDist
    real yDist
    real distance
    integer casterId

    implement CTLExpire
        if .distance > 0 then
            set .distance = .distance - OFFSET_SPEED
            call SetUnitX(.missile, .xDist+.distance * Cos(.angle))
            call SetUnitY(.missile, .yDist+.distance * Sin(.angle))
        else
            set c[.casterId] = c[.casterId]-1
            call KillUnit(.missile)
            if c[.casterId]==0 and c.boolean[casterId] then
                call DestroyEffect(AddSpecialEffect(MOONSOON, .xDist, .yDist))
                call DestroyEffect(c.effect[casterId])
                call KillUnit(c.unit[casterId])
                //DOOOOOOOOOOOOOOOOOOOOOO
            endif
            set .missile = null
            call .destroy()
        endif
    implement CTLEnd
    
    static method fire takes unit u, real angle, real xTo, real yTo, integer Id returns nothing
        local thistype this = create()
        set .missile = u
        set .angle = angle
        set .xDist = xTo
        set .yDist = yTo      
        set .distance = SquareRoot((xTo-GetUnitX(u))*(xTo-GetUnitX(u))+(yTo-GetUnitY(u))*(yTo-GetUnitY(u)))
        set .casterId = Id
    endmethod
endstruct

private struct SP extends array
    unit caster
    unit dummy
    unit monster
    real angle
    real offset
    real offsetBack
    real xSpell
    real ySpell
    real delay
    integer casterId
    integer level
    integer maxSkeletons
    boolean isChanneling
    boolean skelOn
    group skeletonG
    
    implement CTL
        local unit missile
        local unit skeleton
        local real xRandom
        local real yRandom
        local real randomAngle
    
    implement CTLExpire
        if IsUnitChanneling(.caster) and .isChanneling then
            if AOE > .offset then
                set .offset = .offset + OFFSET_SPEED
                set .angle = .angle + PORTAL_SHAPE
                call SetUnitX(.dummy, .xSpell + .offset * Cos(.angle))
                call SetUnitY(.dummy, .ySpell + .offset * Sin(.angle))
                set missile = CreateUnit(Player(15), MISSILE_ID, GetUnitX(.dummy), GetUnitY(.dummy), 0)
                set c[.casterId] = c[.casterId]+1
                call Fire.fire(missile, .angle, .xSpell, .ySpell, .casterId) 
                call Pull(.caster, .xSpell, .ySpell, .offset)
                set missile = null                
            elseif .offsetBack > 0 then
                set .offsetBack = .offsetBack - OFFSET_SPEED
                call Pull(.caster, .xSpell, .ySpell, .offsetBack)
            else         
                set .skelOn = false
                call IssueImmediateOrder(.caster, "stop")
            endif
            
            static if ENABLE_CHANCE then
                set .delay = .delay + 0.03125
                if .delay > 1 then
                    set .delay = 0
                    if (.offset > PartAoe) and (GetRandomInt(0,100) < GetChance(.level)) and .skelOn then
                        set Count = 0
                        call ForGroup(.skeletonG, function CountUnits)
                        if Count < .maxSkeletons then
                            set randomAngle = GetRandomReal(0, 6.2)
                            if AOE > .offset then
                                set xRandom = .xSpell+GetRandomReal(10, .offset)*Cos(randomAngle)
                                set yRandom = .ySpell+GetRandomReal(10, .offset)*Sin(randomAngle)
                            else
                                set xRandom = .xSpell+GetRandomReal(10, .offsetBack)*Cos(randomAngle)
                                set yRandom = .ySpell+GetRandomReal(10, .offsetBack)*Sin(randomAngle)
                            endif
                        
                            set skeleton = CreateUnit(GetOwningPlayer(.caster), skeletonId[GetRandomInt(0,1)],xRandom, yRandom, 0)
                            call UnitApplyTimedLife(skeleton, 'BTLF', SKELETON_LIFE)
                            call GroupAddUnit(.skeletonG, skeleton)
                            call DestroyEffect(AddSpecialEffect(SUMMON_SKELETONS, xRandom, yRandom))
                            set skeleton = null
                        endif
                    endif    
                endif
            endif
        else
            set c.boolean[casterId ] = false
            call KillUnit(.dummy)
            call DestroyEffect(c.effect[casterId])
            call ReleaseGroup(.skeletonG)
            set .caster = null
            set .dummy = null
            call .destroy()            
        endif
    implement CTLEnd

    static method run takes nothing returns nothing
        local thistype this = create()
        set .caster = GetTriggerUnit()
        set .xSpell = GetSpellTargetX()
        set .ySpell = GetSpellTargetY()
        set .dummy = CreateUnit(Player(15), DUMMY_ID, .xSpell, .ySpell, 0)
        set .level = GetUnitAbilityLevel(.caster, SPELL_ID)
        set .delay = 0
        set .offset = 10
        set .offsetBack = AOE
        set .angle = 0
        set .isChanneling = true
        set .skelOn = true
        set .casterId = GetHandleId(.caster)
        set .maxSkeletons = GetCountSkeletons(.level)
        set .skeletonG = NewGroup()
        set c[casterId] = 0
        set c.boolean[casterId] = true
        set c.unit[casterId] = .dummy
        set c.effect[casterId] = AddSpecialEffect(STAR, .xSpell, .ySpell)
    endmethod

    static method onInit takes nothing returns nothing
        call RegisterSpellEffectEvent(SPELL_ID, function thistype.run)  
        set c = Table.create()
        set PartAoe = AOE*0.7
        set skeletonId[0] = 'uske'
        set skeletonId[1] = 'uskm'
        //DOOOOOOOOOOOOOOOOOOOOOOOOO
        set monsterId[0] = 123
    endmethod
endstruct

endscope

PROGRESS: 50%
 
Level 29
Joined
Mar 10, 2009
Messages
5,016
OK, This is my FINAL entry until I can think of some changes and bugs...right now Im too lazy to modify...

Swirling Portal

Code

Credits


Creates a portal vortex that sucks enemy ground units at the center, the portal has a chance to call random skeleton warriors for the caster.
When portal finally comes to an end, a random powerful demon will emerge, throwing all sucked units in the air.

|cffffcc00Level 1|r - Gives 10% chance to summon a maximum of 3 skeleton warriors.
|cffffcc00Level 2|r - Gives 20% chance to summon a maximum of 6 skeleton warriors.
|cffffcc00Level 3|r - Gives 30% chance to summon a maximum of 9 skeleton warriors.

JASS:
/*
Spell Name: Swirling Portal
Created by: mckill2009 (entry for Zephyr Contest #10 ~ What lies on the other side)

REQUIRED LIBRARIES and CREDITS:
- CTL by Nesthaurus
- Table by Bribe
- SpellEffectEvent by Bribe
- IsUnitChanneling by Magtheridon96
- GroupUtils by Rising Dusk
- IsTerrainWalkable by Anitarf
- WorldBounds by Nesthaurus
- Jumper by mckill2009

HOW TO INSTALL:
- Copy all the objects (units/abilities/buffs) to your map
- Change the rawID of the SPELL_ID, DUMMY_ID and MISSILE_ID if needed
- Copy the folder 'SwirlingPortal' to your map
- Add the SwirlingPortal ability to your hero
*/

scope SwirlingPortal

globals
    //Configurable Block
    private constant integer SPELL_ID = 'A000' //based on Rain of Fire, change the rawID if necessary
    private constant integer DUMMY_ID = 'h000' //change the rawID if necessary
    private constant integer MISSILE_ID = 'h001' //change the rawID if necessary
    private constant integer MAX_MONSTER = 5 //used in randomizing the demon (see the onInit)
    private constant integer MAX_SKELETON = 2 //used in randomizing the skeletons (see the onInit)
    private constant real PULL_TOLERANCE = 4 //recommended, pull from center
    private constant real PORTAL_SHAPE = 2 //changes the 'shape' of the portal, recommended setting 1-7
    private constant real OFFSET_SPEED = 1.5 //this affects PORTAL_SHAPE, recommemded setting 1.5
    private constant real AOE = 400 //This should synchronize with the AOE from object editor
    private constant real FLY_SPEED = 10
    private constant real FLY_HEIGHT = 350
    private constant real FLY_DISTANCE = 400
    private constant real SKELETON_LIFE = 15
    private constant string MOONSOON = "Abilities\\Spells\\Other\\Monsoon\\MonsoonBoltTarget.mdl"
    private constant string STAR = "Abilities\\Spells\\NightElf\\Starfall\\StarfallCaster.mdl"
    private constant string SUMMON_SKELETONS = "Abilities\\Spells\\Undead\\RaiseSkeletonWarrior\\RaiseSkeleton.mdl"
    private constant string SUMMON_DEMON = "Abilities\\Spells\\Demon\\DarkPortal\\DarkPortalTarget.mdl"
    private constant string JUMP_SFX = "Abilities\\Spells\\Human\\Thunderclap\\ThunderClapCaster.mdl"    
    private constant boolean ENABLE_CHANCE = true
    //Non-configurable Block
    private Table c
    private group g = CreateGroup()    
    private integer array monsterId
    private integer array skeletonId
    private real PartAoe
    private integer Count = 0
endglobals

//===Configurable Block
private function GetChance takes integer i returns integer
    return 10 * i
endfunction

private function GetCountSkeletons takes integer i returns integer
    return 3 * i
endfunction

private function FilterUnits takes unit u returns boolean
    return not IsUnitType(u, UNIT_TYPE_DEAD) and not IsUnitType(u, UNIT_TYPE_STRUCTURE) and not IsUnitType(u, UNIT_TYPE_FLYING)
endfunction

//===Non-configurable Block
private function UnitAlive takes unit u returns boolean
    return not IsUnitType(u, UNIT_TYPE_DEAD)
endfunction

private function GetParabolaZ takes real h, real d, real x returns real
     return (4 * h / d) * (d - x) * (x / d)
endfunction

private function Pull takes unit caster, real xCenter, real yCenter, real aoe returns nothing
    local unit first
    local real angle
    local real x
    local real y
    call GroupEnumUnitsInRange(g, xCenter, yCenter, aoe, null)
    loop
        set first = FirstOfGroup(g)
        exitwhen first==null
        if IsUnitEnemy(caster, GetOwningPlayer(first)) and FilterUnits(first) then
            set x = GetUnitX(first)
            set y = GetUnitY(first)
            set angle = Atan2(yCenter-y, xCenter-x)
            call SetUnitX(first, x+PULL_TOLERANCE*Cos(angle))
            call SetUnitY(first, y+PULL_TOLERANCE*Sin(angle))          
        endif
        call GroupRemoveUnit(g, first)
    endloop
endfunction

private function CountUnits takes nothing returns nothing
    local unit u = GetEnumUnit()
    if UnitAlive(u) then
        set Count = Count + 1
    endif 
    set u = null
endfunction
//=====================================================

private struct Fire extends array
    unit missile
    real angle
    real xDist
    real yDist
    real distance
    integer casterId
    
    method jump takes unit monster returns nothing
        local unit first
        local real randomAngle = GetRandomReal(-bj_PI, bj_PI)
        local Jumper j
        call GroupEnumUnitsInRange(g, .xDist, .yDist, AOE, null)
        loop
            set first = FirstOfGroup(g)
            exitwhen first==null
            if IsUnitEnemy(monster, GetOwningPlayer(first)) and FilterUnits(first) then
                set j = j.jump(first)
                set j.angle = GetRandomReal(-bj_PI, bj_PI)
                set j.distance = FLY_DISTANCE  
                set j.height = FLY_HEIGHT
                set j.speed = FLY_SPEED
            endif
            call GroupRemoveUnit(g, first)
        endloop
    endmethod
    
    implement CTL
        local unit monster
        local integer hID
    implement CTLExpire
        if .distance > 0 then
            set .distance = .distance - OFFSET_SPEED
            call SetUnitX(.missile, .xDist+.distance * Cos(.angle))
            call SetUnitY(.missile, .yDist+.distance * Sin(.angle))
        else
            set c[.casterId] = c[.casterId]-1
            call KillUnit(.missile)
            if c[.casterId]==0 and c.boolean[.casterId] then
                call DestroyEffect(AddSpecialEffect(MOONSOON, .xDist, .yDist))
                call DestroyEffect(c.effect[.casterId])
                set monster = CreateUnit(GetOwningPlayer(.missile), monsterId[GetRandomInt(1, MAX_MONSTER)], .xDist, .yDist, 0)     
                call DestroyEffect(AddSpecialEffect(SUMMON_DEMON, GetUnitX(monster), GetUnitY(monster)))
                call DestroyEffect(AddSpecialEffect(JUMP_SFX, GetUnitX(monster), GetUnitY(monster)))
                call jump(monster)
                set monster = null
            endif
            set .missile = null
            call .destroy()
        endif
    implement CTLEnd
    
    static method fire takes unit u, real angle, real xTo, real yTo, integer Id returns nothing
        local thistype this = create()
        set .missile = u
        set .angle = angle
        set .xDist = xTo
        set .yDist = yTo      
        set .distance = SquareRoot((xTo-GetUnitX(u))*(xTo-GetUnitX(u))+(yTo-GetUnitY(u))*(yTo-GetUnitY(u)))
        set .casterId = Id
    endmethod
endstruct

private struct SP extends array
    unit caster
    unit dummy
    unit monster
    real angle
    real offset
    real offsetBack
    real xSpell
    real ySpell
    real delay
    integer casterId
    integer level
    integer maxSkeletons
    boolean isChanneling
    boolean skelOn
    group skeletonG
    player pl
    
    implement CTL
        local unit missile
        local unit skeleton
        local real xRandom
        local real yRandom
        local real randomAngle
    
    implement CTLExpire
        if IsUnitChanneling(.caster) and .isChanneling then
            if AOE > .offset then
                set .offset = .offset + OFFSET_SPEED
                set .angle = .angle + PORTAL_SHAPE
                call SetUnitX(.dummy, .xSpell + .offset * Cos(.angle))
                call SetUnitY(.dummy, .ySpell + .offset * Sin(.angle))
                set missile = CreateUnit(.pl, MISSILE_ID, GetUnitX(.dummy), GetUnitY(.dummy), 0)
                set c[.casterId] = c[.casterId]+1
                call Fire.fire(missile, .angle, .xSpell, .ySpell, .casterId) 
                call Pull(.caster, .xSpell, .ySpell, .offset)
                set missile = null                
            elseif .offsetBack > 0 then
                set .offsetBack = .offsetBack - OFFSET_SPEED
                call Pull(.caster, .xSpell, .ySpell, .offsetBack)
            else         
                set .skelOn = false
                call IssueImmediateOrder(.caster, "stop")
            endif
            
            static if ENABLE_CHANCE then
                set .delay = .delay + 0.03125
                if .delay > 1 then
                    set .delay = 0
                    if (.offset > PartAoe) and (GetRandomInt(0,100) < GetChance(.level)) and .skelOn then
                        set Count = 0
                        call ForGroup(.skeletonG, function CountUnits)
                        if Count < .maxSkeletons then
                            set randomAngle = GetRandomReal(-bj_PI, bj_PI)
                            if AOE > .offset then
                                set xRandom = .xSpell+GetRandomReal(10, .offset)*Cos(randomAngle)
                                set yRandom = .ySpell+GetRandomReal(10, .offset)*Sin(randomAngle)
                            else
                                set xRandom = .xSpell+GetRandomReal(10, .offsetBack)*Cos(randomAngle)
                                set yRandom = .ySpell+GetRandomReal(10, .offsetBack)*Sin(randomAngle)
                            endif
                        
                            set skeleton = CreateUnit(GetOwningPlayer(.caster), skeletonId[GetRandomInt(1,MAX_SKELETON)],xRandom, yRandom, 0)
                            call UnitApplyTimedLife(skeleton, 'BTLF', SKELETON_LIFE)
                            call GroupAddUnit(.skeletonG, skeleton)
                            call DestroyEffect(AddSpecialEffect(SUMMON_SKELETONS, xRandom, yRandom))
                            set skeleton = null
                        endif
                    endif    
                endif
            endif
        else
            set c.boolean[casterId ] = false
            call KillUnit(.dummy)
            call DestroyEffect(c.effect[casterId])
            call ReleaseGroup(.skeletonG)
            set .caster = null
            set .dummy = null
            call .destroy()            
        endif
    implement CTLEnd

    static method run takes nothing returns nothing
        local thistype this = create()
        set .caster = GetTriggerUnit()
        set .xSpell = GetSpellTargetX()
        set .ySpell = GetSpellTargetY()
        set .dummy = CreateUnit(Player(15), DUMMY_ID, .xSpell, .ySpell, 0)
        set .level = GetUnitAbilityLevel(.caster, SPELL_ID)
        set .delay = 0
        set .offset = 10
        set .offsetBack = AOE
        set .angle = 0
        set .isChanneling = true
        set .skelOn = true
        set .casterId = GetHandleId(.caster)
        set .maxSkeletons = GetCountSkeletons(.level)
        set .pl = GetTriggerPlayer()
        set .skeletonG = NewGroup()
        set c[casterId] = 0
        set c.boolean[casterId] = true
        set c.effect[casterId] = AddSpecialEffect(STAR, .xSpell, .ySpell)
    endmethod

    static method onInit takes nothing returns nothing
        call RegisterSpellEffectEvent(SPELL_ID, function thistype.run)  
        set c = Table.create()
        set PartAoe = AOE*0.7
        //uses MAX_SKELETON
        set skeletonId[1] = 'uske'
        set skeletonId[2] = 'uskm'
        //uses MAX_MONSTER
        set monsterId[1] = 'nbal'
        set monsterId[2] = 'nvde'
        set monsterId[3] = 'ndrv'
        set monsterId[4] = 'nrvd'
        set monsterId[5] = 'nerw'
    endmethod
endstruct

endscope

- CTL by Nesthaurus
- Table by Bribe
- SpellEffectEvent by Bribe
- IsUnitChanneling by Magtheridon96
- GroupUtils by Rising Dusk
- IsTerrainWalkable by Anitarf
- WorldBounds by Nesthaurus
 

Attachments

  • ZC10.w3x
    148 KB · Views: 83
Status
Not open for further replies.
Top