1. Are you planning to upload your awesome spell or system to Hive? Please review the rules here.
    Dismiss Notice
  2. Updated Resource Submission Rules: All model & skin resource submissions must now include an in-game screenshot. This is to help speed up the moderation process and to show how the model and/or texture looks like from the in-game camera.
    Dismiss Notice
  3. DID YOU KNOW - That you can unlock new rank icons by posting on the forums or winning contests? Click here to customize your rank or read our User Rank Policy to see a list of ranks that you can unlock. Have you won a contest and still haven't received your rank award? Then please contact the administration.
    Dismiss Notice
  4. Rubbed the right way, the genie is out of its lamp! The 12th Concept Art Contest Results have been announced.
    Dismiss Notice
  5. Race against the odds and Reforge, Don't Refund. The 14th Techtree Contest has begun!
    Dismiss Notice
  6. Check out the Staff job openings thread.
    Dismiss Notice
Dismiss Notice
60,000 passwords have been reset on July 8, 2019. If you cannot login, read this.

Trigger Viewer

DD Universal Pack v5.1b.w3x
Variables
Initialization
Init
Revive
Reset
Abilities vJass
--- v4d Readme ---
--- Pack v1 ---
Slash Strike
Electric Field
Dark Torture
--- Pack v2 ---
Frost Eruption old
--- Pack v3 ---
Shadow Crossing
Algid Aura old
Nature Blessing2
Water Exhausting
--- Pack v4 ---
Instinct Flash old
Terror Blade old
Black Magic
--- Universal Pack ---
DDUniversal Pack
--- Install File ---
Install DDUP
Electrolix Zap Copy
DD Library Copy
Abilities Zinc
------ DD Universal Pack v5 -----
DD Library
Electrolix Zap
Nature Blessing
Frostmourne Impale
Frost Eruption
Instinct Flash
Algid Aura
Summon Skeletons
Terror Blade
Bubble Blast
Enter map-specific custom script code below. This text will be included in the map script after variables are declared and before any trigger code.
// xternal FileExporter .\ddup\

library FogSelect initializer Init

	globals
		private trigger Trig = null
		private triggeraction TrigAct = null
		private dialog Dial = null
		private button Yes = null
	endglobals
	
	function UserSelectFog takes nothing returns nothing
		set Dial = DialogCreate()
		call DialogSetMessage(Dial, "Disable fog of war")
		set Yes = DialogAddButton(Dial, "|cffffffffY|res", 'Y')
		call DialogAddButton(Dial, "|cffffffffN|ro", 'N')
		call TriggerRegisterDialogEvent(Trig, Dial)
		call DialogDisplay(Player(0), Dial, true)
	endfunction
	
	private function onClick takes nothing returns nothing
		local button b = GetClickedButton()
		
		if (b==Yes) then
			call FogMaskEnable(false)
			call FogEnable(false)
		endif
		
		call DialogClear(Dial)
		call DialogDestroy(Dial)
		
		call TriggerRemoveAction(Trig, TrigAct)
		call DestroyTrigger(Trig)
		
		set b = null
		set Yes = null
		set Dial = null
		set Trig = null
		set TrigAct = null
	endfunction
	
	private function Init takes nothing returns nothing
		set Trig = CreateTrigger()
		set TrigAct = TriggerAddAction(Trig, function onClick)
	endfunction
	
endlibrary



//! zinc
library UnitsRevive requires DDLib
{

	public struct unitsrevivedata {
		private {
			integer 	id;
			real 		x, y;
			real 		fac;
			unit		hero=null;
			real		rev_dur;
			player		p;
			
			static thistype Units[];
		}
		
		static method create(unit u) -> thistype {
			thistype this = allocate();
			id = GetUnitTypeId(u);
			p = GetOwningPlayer(u);
			x = GetWidgetX(u); y = GetWidgetY(u);
			fac = GetUnitFacing(u);
			rev_dur = 35.;
			if (IsUnitType(u, UNIT_TYPE_HERO)) {
				hero = u;
				rev_dur = 3.5;
			}
			Units[GetHandleId(u)-0x100000] = this;
			return this;
		}
		
		static method Revive(unit u) {
			thistype this = Units[GetHandleId(u)-0x100000];
			DDStartTim(rev_dur, false, this, function() {
				thistype this = DDTimData();
				
				if (hero != null) {
					ReviveHero(hero, x, y, false);
					SetUnitFacing(hero, fac);
					SetUnitState(hero, UNIT_STATE_MANA, GetUnitState(hero, UNIT_STATE_MAX_MANA));
					SelectUnit(hero, true);
					PanCameraToTimed(x, y, .66);
				} else
					bj_lastCreatedUnit = CreateUnit(p, id, x, y, fac);
				
				Units[GetHandleId(bj_lastCreatedUnit)-0x100000] = this;
				DDQuitTim();
			});
		}
	}

}
//! endzinc











Name Type Is Array Initial Value
RndTime real No
unt unit No
Init
  Events
    Map initialization
  Conditions
  Actions
    Set VariableSet unt = Naga Sea Witch 0103 <gen>
    Custom script: call testAA(udg_unt)
    Environment - Change terrain type at (Center of (Playable map area)) to Dalaran Ruins - Rough Dirt using variation -1 in an area of size 1 and shape Circle
    Custom script: local terrtype tt = ModifieTerrainType(4000., 4185., 600., p_null)
    Unit - Change ownership of (Last created unit) to Player 1 (Red) and Change color
    -------- Dont report leaks in this trigger -- lol --------
    Game - Set the time of day to 6.01
    Game - Turn the day/night cycle Off
    Game - Display to (All players) for 30 seconds the text: Spell pack by - |CFF383838D|CFF535353a|CFF6E6E6Er|CFF898989k |CFFC0C0C0D|CFFA5A5A5r|CFF8A8A8Aa|CFF6F6F6Fg|CFF545454o|CFF383838n|r|cffff0000Please rate and comment.|r|cff32cd32Use 'Esc' key to restore your life, mana and spell cooldowns|r
    -------- --- --------
    Custom script: call DestroyEffect( AddSpecialEffect("Abilities\\Weapons\\FarseerMissile\\FarseerMissile.mdl", 0., 0.) )
    -------- --- --------
    Player - Turn Gives bounty Off for Neutral Hostile
    -------- --- --------
    Unit - Change color of Blademaster 0001 <gen> to Green
    Unit - Change color of Lightning Lord 0009 <gen> to Light Blue
    Unit - Change color of Death Knight 0008 <gen> to Maroon
    Unit - Change color of Blood Mage 0043 <gen> to Blue
    Unit - Change color of Keeper of the Grove 0075 <gen> to Dark Green
    Unit - Change color of Naga Sea Witch 0103 <gen> to Teal
    -------- Units revive initialize --------
    Unit Group - Pick every unit in (Units in (Playable map area)) and do (Actions)
      Loop - Actions
        Custom script: call unitsrevivedata.create(GetEnumUnit())
    Custom script: call E_EnableUnitReviveForPlayer( DD_p[0], 35.00, 3.50 )
    Custom script: call E_EnableUnitReviveForPlayer( DD_p[PLAYER_NEUTRAL_AGGRESSIVE], 35.00, 35.00 )
    -------- Check debug mode --------
    Custom script: if (not DEBUG_MODE) then
    Cinematic - Turn on letterbox mode (hide interface) for (All players): fade out over 0.00 seconds
    Cinematic - Fade out over 0.00 seconds using texture Black Mask and color (0%, 0%, 0%) with 0% transparency
    Wait 2.50 seconds
    Cinematic - Fade in over 2.00 seconds using texture Black Mask and color (0%, 0%, 0%) with 0% transparency
    Cinematic - Turn off letterbox mode (show interface) for (All players): fade in over 2.00 seconds
    Wait 2.00 seconds
    Custom script: call UserSelectFog()
    Custom script: else
    Visibility - Create an initially Enabled visibility modifier for Player 1 (Red) emitting Visibility across (Playable map area)
    Custom script: endif
    -------- --- --------
    Wait 10.00 seconds
    Custom script: call ModifieTerrainType(4000., 4185., 600., tt)
    Custom script: call DestroyTrigger( GetTriggeringTrigger() )
Revive
  Events
    Unit - A unit Dies
  Conditions
  Actions
    Custom script: call unitsrevivedata.Revive(GetTriggerUnit())
Reset
  Events
    Player - Player 1 (Red) skips a cinematic sequence
  Conditions
  Actions
    Custom script: set bj_wantDestroyGroup = true
    Unit Group - Pick every unit in (Units owned by Player 1 (Red) matching (((Matching unit) is A Hero) Equal to True).) and do (Actions)
      Loop - Actions
        Unit - Set life of (Picked unit) to 100%
        Unit - Set mana of (Picked unit) to 100%
        Unit - Reset ability cooldowns for (Picked unit).
        Special Effect - Create a special effect attached to the origin (attachpoint) of (Picked unit) using Abilities\Spells\Undead\DarkRitual\DarkRitualCaster.mdl
        Special Effect - Destroy (Last created special effect)
Hello and thank you for downloading my spell pack!

This spell pack works only on Warcraft - The Frozen Throne v1.24b or greater!

This spell pack requires JNGP Editor
You can get JNGP from <wc3c.net>

About spells and installation!

Before you start make sure you installed "DD Universal Pack" trigger down below to your map

In order to install this spell pack in your map! follow this steps:

1) Copy this 'Abilities' category!
2) Save this map
3) Close Map
4) Now open your map
5) Paste this "Abilities" category in your (Trigger Editor)
6) See trigger called 'Install DDUP' in "Abilities" category, enable it
7) Go to terrain editor (Main Window) and go to menu: "Extensions\Import Directory"
8) Now when you are asked to select directory u want, u need to select this one: "Path to Jass NewGen Pack\ddup\Imports" and press "Ok"
9) Restart your map
10) Delete or disable trigger "Install DDUP"
11) Add abilities to units you want, save your map and thats all!

clear memory if you want!
delete "ddup" folder from your JNGP folder. you need that folder only to save this map but not yours.

Enjoy the spells!
~Dark Dragon
//TESH.scrollpos=0
//TESH.alwaysfold=0
//**************************************************************************************
//                            Spell: Slash Strike
//                            Author: Dark Dragon
//                            Date: 14 October 2008
//
//                    Other: Spell made for fun testing vJass
//
//
//                              Installation:
//
// - 1. Make sure you have open the JassNewGen Pack editor not normal one and make sure you have last version
//      Some suggestion first read all of this then if you want to use this spell, do as it says below
// - 2. Now when you open this map in newgen the first thing you want to do is go to
//      object editor (F6) and there copy unit named Illusion Blademaster and under Abilities
//      tab copy spell named Slash Strike when you did that copy this trigger Slash Strike
// - 3. Now press Ctrl+O or click on open map icon, select your map and past all of the stuff
//      you copied, note while pasting you will be asked for raw codes, type next as i tell you
//      For Unit Illusion Blademaster type SSib and for Ability Slash Strike
//      type SStr the case matches.
// - 4. Now when you pasted this trigger again open my map and paste DDUniversal Pack trigger
//      as this trigger is used in all spells.
// - 5. Go back to my map after you paste DDUniversal Pack trigger and go to Import Manager
//      (F12) and export BTN_CR_Amultsrtike.tga and DISBTN_CR_Amultsrtike.tga icons, now
//      open your map and import this 2 icons to your map change path to as in my map
//      war3mapImported or war3campImported must be deleted and replaced to ReplaceableTextures\CommandButtons\BTN_CR_Amultsrtike.tga
//      and for other one DISBTN_CR_Amultsrtike.tga to this ReplaceableTextures\CommandButtonsDisabled\DISBTN_CR_Amultsrtike.tga
//      now save your map, go to object editor, find spell Slash Strike and change icon to
//      this new one.
//      If icon does not appear its ok, you can close my and your map then open your
//      map again and now select icon, you are done.
// - 6. Last thing you want to do is setup this spell to your style, just simple
//      go and read below on how to change spell style, down below are described all
//      values you can change, just read, and after that have fun!
//
//**************************************************************************************

// *** This is Slash Strike main library
library SlashStrike initializer SlashStrike_Main requires DDUniversalPack

// **************************************************************************
// **                         SPELL SETUP                                  **
// **                                                                      **
// ** This variables are constants and are made to easy change spell style **
// ** Define them as you like.                                             **
// **************************************************************************
globals
    // Before all you should know that this spell has limit of 128 instant casts
    // that means there cant be more than 128 casts at same time.
    // By that I mean that if by trigger or something you load 129 units and order all
    // to cast this spell it wont work!
    // Then if we know limit of jass array size which is 2^13 and limit of instant casts
    // then we know how much units can be damaged in one cast 2^13 = 2^7 * x
    // x = 2^13 / 2^7 | x = 2^6 {2^6 = 64} so 64 units can be damaged in instant cast only
    // one of casts. If this spell is cast 4 times at same time there will be 2^6 * 2^2
    // units damaged (up to max) which is 2^6 * 2^2 = 2^8 = (256) units damaged
    // If you think that the limits are not enough for you and you need more then please
    // don't use this spell.
    // Otherwise enjoy!

    // Ok! Its time to setup your new spell!
    // Follow the comments below and do what they say
   
    // This is the raw code of dummy unit (change it in DDUniversal Pack trigger)
    // Default: 'dumy'
    private constant integer DUMMY_CODE = DD_DUMMY_CODE
    // This is the raw code of Slash Strike Ability
    // Default: 'SStr'
    private constant integer ABILITY_SLASH_STRIKE = 'SStr'
    // Units (dummy) raw code image (illusion) of caster
    // Default: 'ssib'
    private constant integer SS_CASTER_IMAGE = 'ssib'
    // This is the length of blade (unit caster) with weapon, if you change caster you want
    // to change this value to.
    // Default: 220.
    private constant real SS_BLADE_WIDTH = 220.
    // This is supposed to be height of blade when blade stands horizontally
    // looking at its z coordinate (this is its height)
    // Default: 60.
    private constant real SS_BLADE_HEIGHT = 60.
    // This is the radius of circle slash the unit will pass.
    // Suggestion dont put this value more than "this spell" (maxCastRange - 200.)
    // Default: 250.
    private constant real SS_SLASH_RADIUS = 250.
    // This is duration in seconds of caster ready animation
    // Default: 1.40
    private constant real CASTER_READY_DURATION = 1.4
    // This is casters spell cast animation
    // this animation is played during cast, and
    // given animation should be looping animation
    // Default: "ready"
    private constant string CASTER_SPELL_ANIMATION = "ready"
    // This is casters ending animation (or so called)
    // reset animation, I guess that every unit reset animation
    // is stand animation 'stand_1'
    // Default: "stand"
    private constant string CASTER_RESET_ANIMATION = "stand"
    // The speed of caster during slash cast (in coordinates)
    // this speed means that it will pass x coordinates per second
    // Default: 1300.
    private constant real CASTER_MOVE_SPEED = 1300.
    // This is your unit (caster) defined collision size
    // Default: 32.
    private constant real CASTER_COLLISION_SIZE = 32.
    // How often illusions will be created
    // n Illusions per second
    // Put value of -1 to disable illusion creation
    // Default: 10
    private constant integer ILLUSION_COUNTER = 10
    // The distance from target when circling around
    // Default: 90.
    private constant real DISTANCE_FROM_TARGET = 90.
    // This is casters end animation of quick slash
    // the animation index, this anim index 8 is
    // his 'Attack - 2' animation
    // Default: 8
    private constant integer CASTER_QSLASH_ANIM_INDEX = 8
    // This is duration of animation above (indexed)
    // so this is duration of 'Attack - 2' animation
    // Default: 1.134
    private constant real CASTER_QSLASH_ANIM_DURATION = 1.134
    // This two varibles define Illusion min and
    // max animation interval
    // Default Min: 0.9
    // Default Max: 1.3
    private constant real ANIM_MIN_POS = 0.9
    private constant real ANIM_MAX_POS = 1.3
    // If enabled kills any destructable near caster
    // while he moves during spell.
    // Default: TRUE
    private constant boolean CAN_KILL_TRESS = TRUE
    // This value is used to allow users simple enable, disable
    // little physics engine in this spell which could
    // slow down this system a bit, so if you receive a
    // little of lag or (HEAVY) lag you might want to disable this.
    // Default: TRUE
    private constant boolean USE_PHYSICS_ENGINE = TRUE
    // This variables are not supposed to be touched here
    // Go down below to SlashStrike_Setup
    //{
        private integer array TreeType[32]
        private integer NTreeTypes = 0
        private real array Damage[32]
        private integer Levels = 0
        private integer array QuickSlashes[32]
    //}
endglobals

// Here edit this values to your will
private function SlashStrike_Setup takes nothing returns nothing
    // This is the number of levels spell has
    // Default: 3
    set Levels = 3

    // This is the number of different tree types in
    // your map
    // Default: 2
    set NTreeTypes = 2
   
    // This are tree types in your map
    // This tree types are used to know
    // should we play sounds or not when
    // destructable dies
    // Default 1: 'ATtr'
    // Default 2: 'ATtc'
    set TreeType[1] = 'ATtr' // Ashenvale Tree
    set TreeType[2] = 'ATtc' // Ashenvale Canopy Tree
   
    // This is the damage spell deals at each level
    // Default 1: 50.
    // Default 2: 80.
    // Default 3: 115.
    set Damage[1] = 50.
    set Damage[2] = 80.
    set Damage[3] = 115.
//  set Damage[4] = 155... for each level add your damage if changed

    // When Quick Slash is activated, caster will move n times
    // arond target unit. This is n times set.
    // Default 1: 3
    // Default 2: 3
    // Default 3: 4
    set QuickSlashes[1] = 3
    set QuickSlashes[2] = 3
    set QuickSlashes[3] = 4
//  set QuickSlashes[4] = 5
endfunction

// ****************************************************
// Dont edit below if you are not a jass programmer
// If you know jass you can edit anything you want
// ****************************************************

//--------------------------------------------------------
//                   Global Variables
//--------------------------------------------------------

globals
    // Constant variables
    //private constant real PI = 3.141592653589793
    private constant real PI_HALF = bj_PI/2.
    private constant real bj_2PI = bj_PI*2.
    private constant integer INT_NULL = 0
    private constant real REAL_NULL = 0.
    private constant location LOC_Z = Location(REAL_NULL, REAL_NULL)
    private constant real MIN_SLEEP = -1.00
    private constant sound ERROR_SOUND = CreateSound("Sound\\Interface\\Error.wav", false, false, false, 10, 10, "")
    private constant integer CROW_FORM_RAWCODE = 'Amrf'
    private constant string BLINK_CASTER_QModEL = "Abilities\\Spells\\NightElf\\Blink\\BlinkCaster.mdl"
    private constant string BLINK_TARGET_QModEL = "Abilities\\Spells\\NightElf\\Blink\\BlinkTarget.mdl"
    private constant real TIMER_MOVE_DELAY = 0.01
    private constant integer ERROR = -1
    private constant integer ABILITY_LOCUST = 'Aloc'
    private constant integer MAX_HEX_RGB = 0xFF
    private constant player PLAYER_NP = Player(PLAYER_NEUTRAL_PASSIVE)
    private constant string DUST_EFFECT = "Objects\\SpawnModels\\Undead\\ImpaleTargetDust\\ImpaleTargetDust.mdl"
    private constant string WATER_EFFECT = "Abilities\\Spells\\Other\\CrushingWave\\CrushingWaveDamage.mdl"
    private constant string BLOOD_EFFECT = "Objects\\SpawnQModels\\Human\\HumanBlood\\BloodElfSpellThiefBlood.mdl"
    private constant string ATTACH_POINT_ORIGIN = "origin"
    private constant real QSLASH_TARGET_DISTANCE = 100.
    private constant real TARGET_BLOW_SPEED = 600.
    private constant rect DEST_RECT = Rect(REAL_NULL, REAL_NULL, REAL_NULL, REAL_NULL)
   
    // Globals
    private real array TargetPosX[128]          // Position X To Where Are We Moving
    private real array TargetPosY[128]          // Position Y To Where Are We Moving
    private integer array StoredValue[128]      // The Stored Value
    private integer NCast = INT_NULL            // N'th Cast
    private unit array Caster[128]              // Main Caster Variable
    private boolean array CircleMove[128]       // Check For Circle Move
    private real array ConstSin[128]            // Constant Sine
    private real array ConstCos[128]            // Constant Cosine
    private real array BackRadians[128]         // Back Angle In Radians
    private real array CasterRadians[128]       // Casters Facing In Radians
    private real array CasterDistance[128]      // Store Caster Distance From Circle Move
    private integer array TimerExec[128]        // N'th Timer Execution
    private group array IllusionGroup[128]      // All Illusions Are Stored In This Group
    private group array BlowedUnitsGroup[128]   // All Units That Are Killed By Caster / Damaged
    private timer SSTimer = null                // This Is Main Timer
    private integer TriggerCount = INT_NULL     // This Counts First n Triggers
    private triggeraction array TAction[128]    // Stored Trigger Action
    private group array DamagedUnitsGroup[128]  // All Units That Taked Damage
    private filterfunc array DamageFilter[128]  // Rather Loade One ff Than Every timer_move_delay Seconds
    private rect array DamageRect[128]          // Damage Region
    private boolean array UnitDamaged[8191]     // This Is The Check Is Unit Damaged
    private integer array SS_SpellLevel[128]    // Spell Level During Cast
    private boolexpr array DestFilter[128]      // Destructables Filter
    private real array PhysicsUnitForce[8191]   // Force Actually Acceleration, Down, Up Ground
    private real array PhysicsBlowAngle[8191]   // This Is Blow Angle In Radians
    private real array PhysicsUnitVelocity[8191]// Velocity Or Speed Of Blowed Unit
    private real array PhysicsFloorZ[8191]      // Z Of Floor That Changes During Air Move
    private integer TempId = INT_NULL           // Temporary Variable To Store Id
    private boolean array QuickSlash[128]       // Checks If Close Combat Is Executed
    private integer array NQuickSlashes[128]    // Remaining Quick Slashes
    private unit array TargetUnit[128]          // This Is Target Unit Which Is Used In Quick Slash
    private boolean array PushTarget[128]       // Checks Is Target Unit Supposed To Be Pushed
endglobals

//xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
//x           Other Spell Used Custom Functions        x
//xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx


//************************************************************************************
//
// Returns x^2 - power of number
//

private constant function Pow2 takes real x returns real
    return (x*x)
endfunction

//************************************************************************************
//
// Converts 1D array to 2D
//

private constant function Array2D takes integer x, integer y, integer size returns integer
    return x+(size*y)+y
endfunction



//************************************************************************************
//
//                      Clears Damaged Units Variable
//                    So That They Can Be Damaged Again
//

private function FlushUnitsBoolean takes nothing returns nothing
    local integer size = 64
    set UnitDamaged[ Array2D(QMod(GetHandleId(GetEnumUnit()), size), TempId, size-1) ] = false
endfunction


//************************************************************************************
//
//                    Clears Physics Stored Values
//

private function FlushUnitsPhysics takes nothing returns nothing
    local integer size = 64
    local unit u = GetEnumUnit()
    local integer arrayx = QMod(GetHandleId(u), size)
    set PhysicsUnitForce[ Array2D(arrayx, TempId, size-1) ] = REAL_NULL
    set PhysicsBlowAngle[ Array2D(arrayx, TempId, size-1) ] = REAL_NULL
    set PhysicsUnitVelocity[ Array2D(arrayx, TempId, size-1) ] = REAL_NULL
    set PhysicsFloorZ[ Array2D(arrayx, TempId, size-1) ] = REAL_NULL
    set u = null
endfunction

//************************************************************************************
//
//                        End spell null variables action
//

private function EndSlashStrike takes nothing returns nothing
    // Ending Locals
    local trigger this = GetTriggeringTrigger()
    local integer id = StoredValue[QMod(GetHandleId(this) - 0xFFFFF, 128)]
    local unit u = Caster[id]
    local triggeraction ta = null
    local boolean cond = false
   
    // Release Unit (caster)
    call PauseUnit(u, false)
    call SetUnitTimeScale(u, 1.)
    call SetUnitAnimation(u, CASTER_RESET_ANIMATION)
    call SetUnitPathing(u, true)
    set TempId = id
    call ForGroup(DamagedUnitsGroup[id], function FlushUnitsBoolean)
    set Caster[id] = null
   
    // Sleep For Condition (when trigger can be destroyed)
    loop
    exitwhen (cond)
        call Sleep(MIN_SLEEP)
        if (USE_PHYSICS_ENGINE) then
            set cond = (FirstOfGroup(IllusionGroup[id]) == null) and (FirstOfGroup(BlowedUnitsGroup[id]) == null and not PushTarget[id])
        else
            set cond = (FirstOfGroup(IllusionGroup[id]) == null)
        endif
    endloop
   
    // All Used Objects Get Destroyed Now
    call DestroyGroup(DamagedUnitsGroup[id])
    call DestroyFilter(DamageFilter[id])
    call RemoveRect(DamageRect[id])
    set ta = TAction[id]
    if (ILLUSION_COUNTER != ERROR) then
        call DestroyGroup(IllusionGroup[id])
    endif
    if (USE_PHYSICS_ENGINE) then
        set TempId = id
        call ForGroup(BlowedUnitsGroup[id], function FlushUnitsPhysics)
        call DestroyGroup(BlowedUnitsGroup[id])
    endif
    if (CAN_KILL_TRESS) then
        call DestroyBoolExpr(DestFilter[id])
    endif
   
    // No more triggers left
    // Kill timer
    set TriggerCount = TriggerCount - 1
    if (TriggerCount == INT_NULL) then
        call PauseTimer(SSTimer)
        call DestroyTimer(SSTimer)
        set SSTimer = null
    endif
   
    // Now null all used variables
    set TargetPosX[id] = REAL_NULL
    set TargetPosY[id] = REAL_NULL
    set StoredValue[id] = INT_NULL
    set CircleMove[id] = FALSE
    set ConstSin[id] = REAL_NULL
    set ConstCos[id] = REAL_NULL
    set BackRadians[id] = REAL_NULL
    set CasterRadians[id] = REAL_NULL
    set CasterDistance[id] = REAL_NULL
    set TimerExec[id] = INT_NULL
    set IllusionGroup[id] = null
    set TAction[id] = null
    set BlowedUnitsGroup[id] = null
    set DamageFilter[id] = null
    set DamagedUnitsGroup[id] = null
    set DamageRect[id] = null
    set SS_SpellLevel[id] = INT_NULL
    set DestFilter[id] = null
    set QuickSlash[id] = FALSE
    set TargetUnit[id] = null
    set QuickSlash[id] = false
    set NQuickSlashes[id] = INT_NULL
    set PushTarget[id] = false
   
    // Finaly destroy trigger and his action
    call TriggerRemoveAction(this, ta)
    call DestroyTrigger(this)
   
    set ta = null
    set this = null
    set u = null
    // We can see that this is usles function call, but however
    // I did not wanted to make mega long code only coz this function
    // is called like 4 - 5 times...
endfunction

//---------------------------------------------------------------------
//
//                  Damaged Units Cond Filter
//

private function DamageFilterFunc takes nothing returns boolean
    local unit f = GetFilterUnit()
    local integer id = StoredValue[QMod(GetHandleId(GetTriggeringTrigger()) - 0xFFFFF, 128)]
    return (not IsUnitType(f, UNIT_TYPE_DEAD)) and (IsUnitType(f, UNIT_TYPE_GROUND)) and (not IsUnitType(f, UNIT_TYPE_STRUCTURE)) and (IsUnitEnemy(f, GetOwningPlayer(Caster[id]))) and (not IsUnitInGroup(f, DamagedUnitsGroup[id])) and (GetOwningPlayer(f) != PLAYER_NP and IsUnitVisible(f, GetOwningPlayer(Caster[id])))
    // We can see that f is not nulled however its much faster this way
    // than calling GetFilterUnit() n times
endfunction

//---------------------------------------------------------------------
//
//                      Damaged Units Action
//

private function DamageEnumUnit takes nothing returns nothing
    // Define all used locals in this func
    local unit u = GetEnumUnit()
    local unit dummy
    local real x
    local real y
    local real cx
    local real cy
    local integer id
    local real dist
    local real rad
    local real ops
    local real adj
    local real life
    local integer size = 64
    local integer arrayx = QMod(GetHandleId(u), size)
   
    set id = TempId
    // Check is unit already damaged
    if (UnitDamaged[ Array2D(arrayx, id, size-1) ]) then
        set u = null
        return
    endif
    // Unit is not damaged
    // Calculate: is unit at blade position?
    set x = GetUnitX(u)
    set y = GetUnitY(u)
    set cx = GetUnitX(Caster[id])
    set cy = GetUnitY(Caster[id])
    set dist = SquareRoot(Pow2(cx-x) + Pow2(cy-y))
    set rad = (CasterRadians[id]-PI_HALF) - Atan2(y-cy, x-cx)
   
    set ops = dist * Sin(rad)
    set adj = ops / Tan(rad)
   
    if ((ops <= SS_BLADE_HEIGHT*0.5) and (adj <= SS_BLADE_WIDTH)) then
        // Unit is at balde position, deal damage
        set UnitDamaged[ Array2D(arrayx, id, size-1) ] = true
        set life = GetUnitState(u, UNIT_STATE_LIFE)
        call UnitDamageTarget(Caster[id], u, Damage[SS_SpellLevel[id]], true, false, ATTACK_TYPE_HERO, DAMAGE_TYPE_UNIVERSAL, WEAPON_TYPE_METAL_HEAVY_SLICE)
        call DestroyEffect(AddSpecialEffectTarget(BLOOD_EFFECT, u, ATTACH_POINT_ORIGIN))
        // Error occurred while trying to damage target
        if (GetUnitState(u, UNIT_STATE_LIFE) == life) then
            set dummy = CreateUnit(GetOwningPlayer(Caster[id]), DUMMY_CODE, x, y, bj_UNIT_FACING)
            call UnitDamageTarget(dummy, u, Damage[SS_SpellLevel[id]], true, false, ATTACK_TYPE_HERO, DAMAGE_TYPE_UNIVERSAL, WEAPON_TYPE_METAL_HEAVY_SLICE)
            call RemoveUnit(dummy)
            set dummy = null
        endif
        // Now we can for sure check if unit is dead
        // And if he is we can blow him up using little physics
        // engine if enabled
        if (USE_PHYSICS_ENGINE) then
            if (not IsUnitType(u, UNIT_TYPE_DEAD)) then
                set u = null
                return
            endif
            call GroupAddUnit(BlowedUnitsGroup[id], u)
            call SetUnitPathing(u, false)
            call MoveLocation(LOC_Z, x, y)
            if (CircleMove[id]) then
                set PhysicsBlowAngle[ Array2D(arrayx, id, size-1) ] = CasterRadians[id] - (adj * (PI_HALF / SS_BLADE_WIDTH))
            else
                set PhysicsBlowAngle[ Array2D(arrayx, id, size-1) ] = CasterRadians[id]
            endif
            // We cant use damage as argument here as in some supernatural maps
            // damage could be 1000. or something and in normal maps to 150.
            // So using it will make sn maps blow unit to heaven...
            set PhysicsUnitForce[ Array2D(arrayx, id, size-1) ] = GetRandomReal(200., 290.)
            set PhysicsUnitVelocity[ Array2D(arrayx, id, size-1) ] = GetRandomReal(450., 600.)
            set PhysicsFloorZ[ Array2D(arrayx, id, size-1) ] = GetLocationZ(LOC_Z)
            call UnitAddAbility(u, CROW_FORM_RAWCODE)
            call UnitRemoveAbility(u, CROW_FORM_RAWCODE)
        endif
    endif
    set u = null
endfunction

//---------------------------------------------------------------------
//
//                  Illusions group work action
//

private function IllusionsFadeIn takes nothing returns nothing
    local unit u = GetEnumUnit()
    local integer alpha = GetUnitUserData(u)
   
    if (alpha < 128) then
        call SetUnitTimeScale(u, REAL_NULL)
    endif
   
    set alpha = alpha - 2
   
    if (alpha == INT_NULL) then
        call SetUnitUserData(u, INT_NULL)
        call GroupRemoveUnit(IllusionGroup[TempId], u)
        call RemoveUnit(u)
    else
        call SetUnitVertexColor(u, MAX_HEX_RGB, MAX_HEX_RGB, MAX_HEX_RGB, alpha)
        call SetUnitUserData(u, alpha)
    endif
    set u = null
endfunction

//---------------------------------------------------------------------
//
//       This is boolexpr filter used to check is destructable dead
//

private function IsDestAlive takes nothing returns boolean
    return (GetWidgetLife(GetFilterDestructable()) > REAL_NULL)
endfunction

//---------------------------------------------------------------------
//
//             Simple enum destructables kill func
//

private function KillEnumDestructables takes nothing returns nothing
    local boolean b = false
    local integer i = 1
    local destructable d = GetEnumDestructable()
    local sound s
    loop
        set b = (GetDestructableTypeId(d) == TreeType[i])
        set i = i + 1
        exitwhen ((b) or (i > NTreeTypes))
    endloop
    if (b) then
        set s = CreateSound("Sound\\Destructibles\\TreeFall"+I2S(GetRandomInt(1, 3))+".wav", false, true, true, 10, 10, "")
        call SetSoundPosition(s, GetDestructableX(d), GetDestructableY(d), REAL_NULL)
        call StartSound(s)
        call KillSoundWhenDone(s)
        set s = null
    endif
    call KillDestructable(d)
    set d = null
endfunction

//---------------------------------------------------------------------
//
//             Physics function which periodically
//                  moves all blowed units
//

private function PhysicsBlowUnit takes nothing returns nothing
    // Locals
    local unit u = GetEnumUnit()
    local real x = GetUnitX(u)
    local real y = GetUnitY(u)
    local real z = GetUnitFlyHeight(u)
    local integer array2d = Array2D(QMod(GetHandleId(u), 64), TempId, 63)
    local real vel = PhysicsUnitVelocity[array2d] - 25. * TIMER_MOVE_DELAY
    local real rad = PhysicsBlowAngle[array2d]
    set PhysicsUnitForce[array2d] = PhysicsUnitForce[array2d] - 850. * TIMER_MOVE_DELAY
    set PhysicsUnitVelocity[array2d] = vel
    set vel = vel * TIMER_MOVE_DELAY
   
    // Move Unit
    set x = x + vel * Cos(rad)
    set y = y + vel * Sin(rad)
    call SetUnitX(u, x)
    call SetUnitY(u, y)
    call MoveLocation(LOC_Z, x, y)
   
    // Change Height
    set z = z + (PhysicsUnitForce[array2d]*TIMER_MOVE_DELAY) + (PhysicsFloorZ[array2d]-GetLocationZ(LOC_Z))
    call SetUnitFlyHeight(u, z, REAL_NULL)
    set PhysicsFloorZ[array2d] = GetLocationZ(LOC_Z)
   
    // End When On Floor
    if (GetUnitFlyHeight(u) <= .333) then
        call SetUnitFlyHeight(u, REAL_NULL, REAL_NULL)
        call GroupRemoveUnit(BlowedUnitsGroup[TempId], u)
        if (IsTerrainPathable(x, y, PATHING_TYPE_FLOATABILITY)) then
            call DestroyEffect(AddSpecialEffect(DUST_EFFECT, x, y))
        else
            call DestroyEffect(AddSpecialEffect(WATER_EFFECT, x, y))
        endif
    endif
endfunction

//////////////////////////////////////////////////////////////////
//                 Slash Strike Main Condition                  //
//////////////////////////////////////////////////////////////////

private constant function SlashStrikeCond takes nothing returns boolean
    return ( GetSpellAbilityId() == ABILITY_SLASH_STRIKE )
endfunction

//----------------------------------------------------------------
//--                Slash Strike Periodic Action                --
//----------------------------------------------------------------

private function SlashStrikePeriodicMove takes nothing returns nothing
    // Define all local variable we will use
    local trigger this = GetTriggeringTrigger()
    local integer id = StoredValue[QMod(GetHandleId(this) - 0xFFFFF, 128)]
    local unit u = Caster[id]
    local real tx = TargetPosX[id]
    local real ty = TargetPosY[id]
    local real x = GetUnitX(u)
    local real y = GetUnitY(u)
    local real tdist = SquareRoot(Pow2(tx-x) + Pow2(ty-y))
    local real rad = CasterRadians[id]
    local fogmodifier fm = null
    local unit illusion = null
    local real minx = REAL_NULL
    local real miny = REAL_NULL
    local real maxx = REAL_NULL
    local real maxy = REAL_NULL
    local real bwx = REAL_NULL
    local real bwy = REAL_NULL
    local real ax
    local real ay
    local real bx
    local real by
    local real cx
    local real cy
    local real dx
    local real dy
    local real cos
    local real sin
   
    set TimerExec[id] = TimerExec[id] + 1
   
    // Check For Target Movement
    // Here we push target if it is blowed
    // with quick slash
    if (PushTarget[id]) then
        set tx = GetUnitX(TargetUnit[id]) + TARGET_BLOW_SPEED*TIMER_MOVE_DELAY * Cos(rad)
        set ty = GetUnitY(TargetUnit[id]) + TARGET_BLOW_SPEED*TIMER_MOVE_DELAY * Sin(rad)
        set CasterDistance[id] = CasterDistance[id] - (TARGET_BLOW_SPEED*TIMER_MOVE_DELAY)
        // Add Target Move Effects
        if (QMod(TimerExec[id], 25) == INT_NULL) then
            if (IsTerrainPathable(tx, ty, PATHING_TYPE_FLOATABILITY)) then
                call DestroyEffect(AddSpecialEffect(DUST_EFFECT, tx, ty))
            else
                call DestroyEffect(AddSpecialEffect(WATER_EFFECT, tx, ty))
            endif
        endif
        call SetUnitPosition(TargetUnit[id], tx, ty)
        // If target has no more distance left to pass
        // then end spell
        if (CasterDistance[id] <= REAL_NULL) then
            set PushTarget[id] = false
            call PauseUnit(TargetUnit[id], false)
            call SetUnitTimeScale(TargetUnit[id], 1.)
        endif
    endif
   
    // We first check is caster still alive
    if (GetUnitState(u, UNIT_STATE_LIFE) <= REAL_NULL and u != null) then
        call EndSlashStrike()
        return
    endif
   
    // Damage Deal Action
    //*****************************************
    set rad = -PI_HALF + rad
    set cos = Cos(rad)
    set sin = Sin(rad)
    set bwx = x + SS_BLADE_WIDTH * cos
    set bwy = y + SS_BLADE_WIDTH * sin
    //*****************************************
   
    set ax = x + SS_BLADE_HEIGHT*0.5 * Cos(PI_HALF+rad)
    set ay = y + SS_BLADE_HEIGHT*0.5 * Sin(PI_HALF+rad)
    set cx = ax + SS_BLADE_WIDTH * cos
    set cy = ay + SS_BLADE_WIDTH * sin
    set bx = ax + SS_BLADE_HEIGHT * Cos(-PI_HALF+rad)
    set by = ax + SS_BLADE_HEIGHT * Sin(-PI_HALF+rad)
    set dx = bx + SS_BLADE_WIDTH * cos
    set dy = by + SS_BLADE_WIDTH * sin
   
    // Now get minX, minY, maxX, maxY
    // Of course it could be done in loop but this way
    // its much faster
    set minx = ax
    set maxx = ax
    if (minx > bx) then
        set minx = bx
    endif
    if (maxx < bx) then
        set maxx = bx
    endif
    if (minx > cx) then
        set minx = cx
    endif
    if (maxx < cx) then
        set maxx = cx
    endif
    if (minx > dx) then
        set minx = dx
    endif
    if (maxx < dx) then
        set maxx = dx
    endif
   
    set miny = ay
    set maxy = ay
    if (miny > by) then
        set miny = by
    endif
    if (maxy < by) then
        set maxy = by
    endif
    if (miny > cy) then
        set miny = cy
    endif
    if (maxy < cy) then
        set maxy = cy
    endif
    if (miny > dy) then
        set miny = dy
    endif
    if (maxy < dy) then
        set maxy = dy
    endif
   
    set TempId = id
    if (NQuickSlashes[id] != ERROR) then
        call SetRect(DamageRect[id], minx, miny, maxx, maxy)
    else
        call SetRect(DamageRect[id], REAL_NULL, REAL_NULL, REAL_NULL, REAL_NULL)
    endif
    call GroupEnumUnitsInRect(DamagedUnitsGroup[id], DamageRect[id], DamageFilter[id])
    call ForGroup(DamagedUnitsGroup[id], function DamageEnumUnit)
    set rad = PI_HALF + rad
   
    // Do illusion works (actions) if wanted
    if (ILLUSION_COUNTER != ERROR) then
        // This must be loaded only if caster is not null
        if (QMod(TimerExec[id], R2I(1./TIMER_MOVE_DELAY)/ILLUSION_COUNTER) == INT_NULL and u != null and NQuickSlashes[id] != ERROR) then
            // Load new illusion
            set illusion = CreateUnit(PLAYER_NP, SS_CASTER_IMAGE, x, y, rad*bj_RADTODEG)
            call SetUnitTimeScale(illusion, GetRandomReal(ANIM_MIN_POS, ANIM_MAX_POS)/TIMER_MOVE_DELAY)
            call SetUnitAnimation(illusion, CASTER_SPELL_ANIMATION)
            call SetUnitColor(illusion, PLAYER_COLOR_LIGHT_BLUE)
            call UnitAddAbility(illusion, ABILITY_LOCUST)
            call SetUnitVertexColor(illusion, MAX_HEX_RGB, MAX_HEX_RGB, MAX_HEX_RGB, 128)
            call SetUnitUserData(illusion, 128)
            call GroupAddUnit(IllusionGroup[id], illusion)
            call SetUnitX(illusion, x)
            call SetUnitY(illusion, y)
        endif
       
        // Fade illusions
        call ForGroup(IllusionGroup[id], function IllusionsFadeIn)
    endif
   
    // If we are using physics engine then check does group
    // has any unit that is dead
    if (USE_PHYSICS_ENGINE) then
        if (FirstOfGroup(BlowedUnitsGroup[id]) != null) then
            call ForGroup(BlowedUnitsGroup[id], function PhysicsBlowUnit)
        endif
    endif
   
    // If spell has ended skip remaining actions
    if (u == null or NQuickSlashes[id] == ERROR) then
        return
    endif
   
    // If we are allowed to kill destructables then kill them
    if (CAN_KILL_TRESS) then
        call SetRect(DEST_RECT, x-100., y-100., x+100., y+100.)
        call EnumDestructablesInRect(DEST_RECT, DestFilter[id], function KillEnumDestructables)
    endif
   
    // During Move Check Terrain Type To Add Effects
    if (IsTerrainPathable(x, y, PATHING_TYPE_FLOATABILITY)) then
        if (QMod(TimerExec[id], 17) == INT_NULL) then
            call DestroyEffect(AddSpecialEffect(DUST_EFFECT, x, y))
        endif
    else
        if (QMod(TimerExec[id], 6) == INT_NULL) then
            call DestroyEffect(AddSpecialEffect(WATER_EFFECT, x, y))
        endif
    endif
   
    // We have to check is qucik slash enabled at close
    // combat and do close combat actions
    if (QuickSlash[id]) then
        if (NQuickSlashes[id] > INT_NULL) then
            set x = x + CASTER_MOVE_SPEED*TIMER_MOVE_DELAY * ConstCos[id]
            set y = y + CASTER_MOVE_SPEED*TIMER_MOVE_DELAY * ConstSin[id]
            // Check Distance
            if (SquareRoot(Pow2(tx-x) + Pow2(ty-y)) <= CASTER_MOVE_SPEED*TIMER_MOVE_DELAY or SquareRoot(Pow2(GetUnitX(id:TargetUnit)-GetUnitX(u)) + Pow2(GetUnitY(id:TargetUnit)-GetUnitY(u))) >= SS_SLASH_RADIUS*1.5) then
                debug call Msg("exec")
                // Set next line / position move
                set NQuickSlashes[id] = NQuickSlashes[id] - 1
                set tdist = GetRandomReal(SS_SLASH_RADIUS/2., SS_SLASH_RADIUS*1.5)
                set rad = GetRandomReal(REAL_NULL, bj_2PI)
                set tx = GetUnitX(TargetUnit[id])
                set ty = GetUnitY(TargetUnit[id])
                set tx = tx + tdist * Cos(rad)
                set ty = ty + tdist * Sin(rad)
                set TargetPosX[id] = tx
                set TargetPosY[id] = ty
                set CasterRadians[id] = Atan2(ty-y, tx-x)
                set ConstCos[id] = Cos(CasterRadians[id])
                set ConstSin[id] = Sin(CasterRadians[id])
                call SetUnitFacing(u, CasterRadians[id]*bj_RADTODEG)
                // We now know that caster will start to move
                // to target position
                if (NQuickSlashes[id] == INT_NULL) then
                    call SetUnitTimeScale(u, 2.)
                    call SetUnitAnimationByIndex(u, CASTER_QSLASH_ANIM_INDEX)
                endif
            endif
        elseif (NQuickSlashes[id] == INT_NULL) then
            // Move to target
            set tx = GetUnitX(TargetUnit[id])
            set ty = GetUnitY(TargetUnit[id])
            set rad = Atan2(ty-y, tx-x)
            call SetUnitFacing(u, rad*bj_RADTODEG)
            set CasterRadians[id] = rad
            set x = x + CASTER_MOVE_SPEED*TIMER_MOVE_DELAY * Cos(rad)
            set y = y + CASTER_MOVE_SPEED*TIMER_MOVE_DELAY * Sin(rad)
            // Check Disatnce (final)
            if (SquareRoot(Pow2(tx-x) + Pow2(ty-y)) <= 2.*CASTER_COLLISION_SIZE) then
                // Disable Group Damage Or Any Other
                // While Caster Is Hidden
                set NQuickSlashes[id] = ERROR
                call SetUnitInvulnerable(u, true)
                set fm = CreateFogModifierRadius(GetOwningPlayer(u), FOG_OF_WAR_VISIBLE, tx, ty, 512., true, false)
                call FogModifierStart(fm)
                call ShowUnit(u, false)
                call PauseUnit(TargetUnit[id], true)
                call SetUnitTimeScale(TargetUnit[id], REAL_NULL)
                call DestroyEffect(AddSpecialEffect(BLINK_CASTER_QModEL, x, y))
               
                call Sleep(GetRandomReal(0.5, 0.75))
               
                // Show caster and order an a attack
                // this attack blows target away
                call ShowUnit(u, true)
                set rad = GetRandomReal(REAL_NULL, bj_2PI)
                set x = tx + QSLASH_TARGET_DISTANCE * Cos(rad)
                set y = ty + QSLASH_TARGET_DISTANCE * Sin(rad)
                call SetUnitX(u, x)
                call SetUnitY(u, y)
                set rad = Atan2(ty-y, tx-x)
                call SetUnitFacing(u, rad*bj_RADTODEG)
                call DestroyEffect(AddSpecialEffect(BLINK_TARGET_QModEL, x, y))
                if (not IsUnitType(TargetUnit[id], UNIT_TYPE_DEAD)) then
                    // Target is still alive, if dies now will be pushed
                    // even if it stays alive it will be pushed
                    call SetUnitAnimationByIndex(u, CASTER_QSLASH_ANIM_INDEX)
                    call Sleep(MIN_SLEEP)
                    if (USE_PHYSICS_ENGINE) then
                        set CasterDistance[id] = 250.
                        set CasterRadians[id] = rad
                        set PushTarget[id] = true
                    endif
                    // If target already taked damage it will take once more
                    // this is only possible in quick slash on target unit
                    call UnitDamageTarget(u, TargetUnit[id], Damage[SS_SpellLevel[id]], true, false, ATTACK_TYPE_HERO, DAMAGE_TYPE_UNIVERSAL, WEAPON_TYPE_METAL_HEAVY_SLICE)
                    call DestroyEffect(AddSpecialEffectTarget(BLOOD_EFFECT, TargetUnit[id], ATTACH_POINT_ORIGIN))
                endif
                // As said before caster is invulnerable while hidden to
                // prevent possible bugs...
                call SetUnitInvulnerable(u, false)
                call SetUnitTimeScale(TargetUnit[id], 1.)
                // Select back caster as while hidden its deselected
                if (GetLocalPlayer() == GetOwningPlayer(u)) then
                    call SelectUnit(u, true)
                endif
                call Sleep(CASTER_QSLASH_ANIM_DURATION/2.-0.25)
                call FogModifierStop(fm)
                call DestroyFogModifier(fm)
                set fm = null
                // End it
                call EndSlashStrike()
                return
            endif
        endif
        // This action is executed while caster is moving
        // to target position where taregt is v (victim)
        call SetUnitPosition(u, x, y)
        return
    endif
   
    //*****************************************************************
    //            Here we know that its far normal slash cast
    //*****************************************************************
   
    // Second check do we have to change move type
    if (tdist <= 100. and not CircleMove[id]) then
        call SetUnitPosition(u, tx, ty)
        set x = tx
        set y = ty
        set rad = rad + PI_HALF
        set CircleMove[id] = true
        set TargetPosX[id] = tx + SS_SLASH_RADIUS * Cos(rad)
        set TargetPosY[id] = ty + SS_SLASH_RADIUS * Sin(rad)
        // This is end of spell
        if (CasterRadians[id] == BackRadians[id]) then
            call EndSlashStrike()
        endif
        return
    // If not do constant move
    elseif (not CircleMove[id]) then
        set x = x + CASTER_MOVE_SPEED*TIMER_MOVE_DELAY * ConstCos[id]
        set y = y + CASTER_MOVE_SPEED*TIMER_MOVE_DELAY * ConstSin[id]
        // Check can we move to new point
        if (IsTerrainPathable(x + CASTER_COLLISION_SIZE*TIMER_MOVE_DELAY * ConstCos[id], y + CASTER_COLLISION_SIZE*TIMER_MOVE_DELAY * ConstSin[id], PATHING_TYPE_WALKABILITY)) then
            call EndSlashStrike()
            return
        endif
        call SetUnitPosition(u, x, y)
    // Circle Move
    else
        set CasterRadians[id] = rad + (CASTER_MOVE_SPEED*TIMER_MOVE_DELAY)*(1. / SS_SLASH_RADIUS)
        call SetUnitFacing(u, rad*bj_RADTODEG)
        set rad = Atan2(y-TargetPosY[id], x-TargetPosX[id]) + (CASTER_MOVE_SPEED*TIMER_MOVE_DELAY)*(1. / SS_SLASH_RADIUS)
        set x = TargetPosX[id] + SS_SLASH_RADIUS * Cos(rad)
        set y = TargetPosY[id] + SS_SLASH_RADIUS * Sin(rad)
        // Check can we move to new point
        if (IsTerrainPathable(x + CASTER_COLLISION_SIZE * Cos(rad), y + CASTER_COLLISION_SIZE * Sin(rad), PATHING_TYPE_WALKABILITY)) then
            call EndSlashStrike()
            return
        endif
        call SetUnitPosition(u, x, y)
       
        // End Circle Move
        if (CasterRadians[id] >= BackRadians[id]) then
            set CasterRadians[id] = BackRadians[id]
            set CircleMove[id] = false
            set CasterRadians[id] = BackRadians[id]
            set ConstCos[id] = Cos(BackRadians[id])
            set ConstSin[id] = Sin(BackRadians[id])
            set TargetPosX[id] = x + CasterDistance[id] * ConstCos[id]
            set TargetPosY[id] = y + CasterDistance[id] * ConstSin[id]
        endif
    endif
endfunction

//////////////////////////////////////////////////////////////////
//                 Slash Strike Main Action                     //
//////////////////////////////////////////////////////////////////

private function SlashStrikeAction takes nothing returns nothing
    //-----------------------------
    // Load all local variables
    //-----------------------------
    local unit u = GetTriggerUnit()
    local unit v = GetSpellTargetUnit()
    local player p = GetOwningPlayer(u)
    local real x1 = GetUnitX(u)
    local real x2 = GetUnitX(v)
    local real y1 = GetUnitY(u)
    local real y2 = GetUnitY(v)
    local real dist = SquareRoot(Pow2(x1-x2) + Pow2(y1-y2))
    local real rad = Atan2(y2-y1, x2-x1)
    local real x = REAL_NULL
    local real y = REAL_NULL
    local integer id = NCast
    local trigger this = null
    local integer lvl = GetUnitAbilityLevel(u, ABILITY_SLASH_STRIKE)
   
    // Not supposed to happen, however we will check to make sure
    if (lvl > Levels) then
        call DisplayTimedTextToPlayer(GetLocalPlayer(), REAL_NULL, REAL_NULL, 15., "|cffff0000Spell: Slash Strike can't be cast because level of spell is greater then defined.|r")
        call StartSound(ERROR_SOUND)
        call SetSoundVolume(ERROR_SOUND, 127)
        return
    endif
   
    set NCast = QMod(NCast+1, 128)
   
    // If we have enough distance then start quick move slash
    if (dist > SS_SLASH_RADIUS+DISTANCE_FROM_TARGET) then
        set rad = rad - PI_HALF
        set x = x1 + SS_SLASH_RADIUS * Cos(rad)
        set y = y1 + SS_SLASH_RADIUS * Sin(rad)
        set rad = rad + PI_HALF
        set CasterDistance[id] = (dist - SS_SLASH_RADIUS - DISTANCE_FROM_TARGET)
        set TargetPosX[id] = x + CasterDistance[id] * Cos(rad)
        set TargetPosY[id] = y + CasterDistance[id] * Sin(rad)
        set CircleMove[id] = false
        set QuickSlash[id] = false
        set NQuickSlashes[id] = 0
    else
    // If we dont have enough distance then start quick slash
        set rad = GetRandomReal(REAL_NULL, bj_2PI)
        set dist = GetRandomReal(SS_SLASH_RADIUS/2., SS_SLASH_RADIUS*1.5)
        set x = x2 + dist * Cos(rad)
        set y = y2 + dist * Sin(rad)
       
        set rad = GetRandomReal(REAL_NULL, bj_2PI)
        call SetRandomSeed(R2I(GetRandomReal(0., rad*10000.)))
        set dist = GetRandomReal(SS_SLASH_RADIUS/2., SS_SLASH_RADIUS*1.5)
        set TargetPosX[id] = x2 + dist * Cos(rad)
        set TargetPosY[id] = y2 + dist * Sin(rad)
        set rad = Atan2(TargetPosY[id]-y, TargetPosX[id]-x)
       
        set NQuickSlashes[id] = QuickSlashes[lvl]
        set TargetUnit[id] = v
        set QuickSlash[id] = true
    endif
   
    // Check can we move caster
    if (IsTerrainPathable(x + CASTER_COLLISION_SIZE * Cos(rad), y + CASTER_COLLISION_SIZE * Sin(rad), PATHING_TYPE_WALKABILITY)) then
        if (GetLocalPlayer() == p) then
            call SetSoundVolume(ERROR_SOUND, 110)
            call StartSound(ERROR_SOUND)
        endif
        call DisplayTimedTextToPlayer(p, REAL_NULL, REAL_NULL, 15., "|cffffcc00Invalid cast position!|r")
        return
    endif
   
    // Make sure that we can change z of caster
    call UnitAddAbility(u, CROW_FORM_RAWCODE)
    call UnitRemoveAbility(u, CROW_FORM_RAWCODE)
   
    // Add effects
    call SetUnitInvulnerable(u, true)
    call DestroyEffect(AddSpecialEffect(BLINK_CASTER_QModEL, x1, y1))
    call Sleep(MIN_SLEEP)
    call DestroyEffect(AddSpecialEffect(BLINK_TARGET_QModEL, x, y))
    call SetUnitInvulnerable(u, false)
   
   
    // Change Position & Setup Caster
    call SetUnitPosition(u, x, y)
    call SetUnitFacing(u, rad*bj_RADTODEG)
    call PauseUnit(u, true)
    call SetUnitAnimation(u, CASTER_SPELL_ANIMATION)
    call SetUnitTimeScale(u, 1.78324)
   
    call Sleep(CASTER_READY_DURATION/1.78324-0.25)
    call SetUnitTimeScale(u, .0316)
   
    // Caster is dead
    if (GetUnitState(u, UNIT_STATE_LIFE) <= REAL_NULL) then
        call PauseUnit(u, false)
        call SetUnitTimeScale(u, 1.)
        return
    endif
   
    // Store Current Value And Get Next + Start Timer + Load Trigger
    set TriggerCount = TriggerCount + 1
    set this = CreateTrigger()
    set StoredValue[QMod(GetHandleId(this) - 0xFFFFF, 128)] = id
    set ConstSin[id] = Sin(rad)
    set ConstCos[id] = Cos(rad)
    set BackRadians[id] = rad + bj_PI
    set TimerExec[id] = INT_NULL
    set PushTarget[id] = false
    set CasterRadians[id] = rad
    set Caster[id] = u
    if (ILLUSION_COUNTER != ERROR) then
        set IllusionGroup[id] = CreateGroup()
    endif
    if (USE_PHYSICS_ENGINE) then
        set BlowedUnitsGroup[id] = CreateGroup()
    endif
    if (CAN_KILL_TRESS) then
        set DestFilter[id] = Filter(function IsDestAlive)
    endif
    set DamagedUnitsGroup[id] = CreateGroup()
    set DamageFilter[id] = Filter(function DamageFilterFunc)
    set DamageRect[id] = Rect(REAL_NULL, REAL_NULL, REAL_NULL, REAL_NULL)
    set SS_SpellLevel[id] = lvl
    if (SSTimer == null) then
        set SSTimer = CreateTimer()
        call TimerStart(SSTimer, TIMER_MOVE_DELAY, TRUE, null)
    endif
    call TriggerRegisterTimerExpireEvent(this, SSTimer)
    set TAction[id] = TriggerAddAction(this, function SlashStrikePeriodicMove)
    call SetUnitPathing(u, false)
   
    // Simple null locals
    set p = null
    set u = null
    set v = null
    set this = null
endfunction

//===========================================================================
private function SlashStrike_Main takes nothing returns nothing
    // Init locals
    local trigger t = CreateTrigger()
    local sound s = null
   
    // Get All Players And Register Spell Cast Events
    // Add Condition And Action
    call TriggerRegisterAnyUnitEvent(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
    call TriggerAddCondition(t, Condition(function SlashStrikeCond))
    call TriggerAddAction(t, function SlashStrikeAction)
   
    // *** Preload Files ***
   
    // Load Sounds
    call SetSoundVolume(ERROR_SOUND, 1)
    call StartSound(ERROR_SOUND)
    if (CAN_KILL_TRESS) then
        set s = CreateSound("Sound\\Destructibles\\TreeFall1.wav", false, true, true, 10, 10, "")
        call SetSoundVolume(s, 1)
        call SetSoundPosition(s, REAL_NULL, REAL_NULL, REAL_NULL)
        call StartSound(s)
        call KillSoundWhenDone(s)
        set s = CreateSound("Sound\\Destructibles\\TreeFall2.wav", false, true, true, 10, 10, "")
        call SetSoundVolume(s, 1)
        call SetSoundPosition(s, REAL_NULL, REAL_NULL, REAL_NULL)
        call StartSound(s)
        call KillSoundWhenDone(s)
        set s = CreateSound("Sound\\Destructibles\\TreeFall3.wav", false, true, true, 10, 10, "")
        call SetSoundVolume(s, 1)
        call SetSoundPosition(s, REAL_NULL, REAL_NULL, REAL_NULL)
        call StartSound(s)
        call KillSoundWhenDone(s)
    endif
   
    // Load Files / QModels
    call Preload(BLINK_CASTER_QModEL)
    call Preload(BLINK_TARGET_QModEL)
    call Preload(DUST_EFFECT)
    call Preload(WATER_EFFECT)
    call Preload(BLOOD_EFFECT)
   
    call PreloadStart()
    // *** Finish Preload ***
   
    // Load User Spell Values
    call SlashStrike_Setup()
   
   
    set s = null
endfunction

endlibrary
 
//TESH.scrollpos=355
//TESH.alwaysfold=0
//**************************************************************************************
//                            Spell: Electric Field
//                            Author: Dark Dragon
//                            Date: 15 November 2008
//
//                    Other: Spell made for fun testing vJass
//
//
//                              Installation:
//
// - 1. Make sure you have open the JassNewGen Pack editor not normal one and make sure you have last version
// - 2. Go to Import Manager (F12) and extract BTN_CR_Alightings.tga and its DISBTN version
//      Great Lightning.mdx and thunder1.wav
// - 3. Import all of this to your map and set ther path to as you can see here (in my map)
// - 4. Go to Object Manager (F6) and copy dummy unit {Dummy (DD Universal Pack)}
//      Note: if you have copied you dont need to copy it again, only one dummy is needed.
//      Copy ability Electric Field (Dummy Effect) and Electric Field main ability.
//      When you are asked for raw codes type following for:
//      Dummy:                  'dumy'
//      Electric Field:         'elfd'
//      Electric Field (Dummy): 'efef'
// - 5. If you want different raw codes edit the below as well:
// - 6. Edit date below to your own will and enjoy the spell:
// - 7. And of course copy this trigger and DDUniversal Pack to your map.
//
//**************************************************************************************

// The electric field library
library ElectricField initializer ElectricField_Main requires DDUniversalPack

    // **************************************************************************
    // **                         SPELL SETUP                                  **
    // **                                                                      **
    // ** This variables are constants and are made to easy change spell style **
    // ** Define them as you like.                                             **
    // **************************************************************************
    globals
        // This is the raw code of Electric Field
        // Default: 'elfd'
        private constant integer ABILITY_ELECTRIC_FIELD = 'elfd'
        // This is the raw code of Electric Field (Dummy Effect)
        // Default: 'efef'
        private constant integer ABILITY_DUMMY_ELECTRIC_FIELD = 'efef'
        // This is the raw code of Dummy (DD Universal Pack) (change it in DDUniversal Pack trigger)
        // Default: 'dumy'
        private constant integer UNIT_DUMMY_CODE = DD_DUMMY_CODE
        // This is purge ability rawcode
        // Deafault: 'Apg2'
        private constant integer PURGE_CODE = 'Apg2'
        // This is thunder sounds max distance that it can
        // be heard
        // Default: 6000.
        private constant real SOUND_MAX_DISTANCE = 6000.
        // The delay of thunder when casting, will wait x seconds
        // and after that time units will be striked with lightning
        // Default: 0.5
        private constant real THUNDER_DELAY = 0.5
        // The unit velocity of z-axis during quick move
        // Default: 436.
        private constant real UNIT_DISAPPEAR_VELOCITY_QUICK = 436.
        // The unit velocity of z-axis during slow move
        // Default: 73.
        private constant real UNIT_DISAPPEAR_VELOCITY_SLOW = 73.
        // When lightning reaches ground this effect
        // will be loaded
        // Default: "Abilities\\Spells\\Human\\Thunderclap\\ThunderClapCaster.mdx"
        private constant string EF_EXPLOSION_EFFECT = "Abilities\\Spells\\Human\\Thunderclap\\ThunderClapCaster.mdx"
        // This are random thunderbolt effects around the field
        // Default: "Doodads\\Cinematic\\Lightningbolt\\Lightningbolt.mdl"
        private constant string EF_THUNDERBOLT_EFFECT = "Doodads\\Cinematic\\Lightningbolt\\Lightningbolt.mdx"
        // Effect which is loaded from the sky
        // Default: "Abilities\\Spells\\Orc\\LightningShield\\LightningShieldTarget.mdl"
        private constant string EF_LIGHTNING_EFFECT = "Abilities\\Spells\\Orc\\LightningShield\\LightningShieldTarget.mdx"
        // Effect which is loaded when unit disappears
        // Default: "Abilities\\Weapons\\Bolt\\BoltImpact.mdl"
        private constant string EF_LIGHTNING_IMPACT = "Abilities\\Weapons\\Bolt\\BoltImpact.mdx"
        // The main custom lightning QModel
        // Default: "Lightning\\Great Lightning.mdl"
        private constant string GREAT_LIGHTNING_QModEL = "Lightning\\Great Lightning.mdx"
        // Sound file of lightning
        // Default: "Custom\\Ambient\\thunder1.wav"
        private constant string SOUND_THUNDER = "Custom\\Ambient\\thunder1.wav"
        private constant real SOUND_THUNDER_VOL = 100.
        // Duration of upper lightning effect
        // Default: 0.6
        private constant real LIGHTNING_EFFECT_DURATION = 0.6
        // This is max camera noise range that players will be effected
        // Default: 2000.
        private constant real CAMERA_NOISE_RANGE = 2000.
        // Set it to true or false, if you want camera noise set it to true
        // else to false
        // Default: TRUE
        private constant boolean USE_CAMERA_NOISE = TRUE
        // This is the radius of terrain deform
        // Default: 512.
        private constant real TERRAIN_RADIUS = 512.
        // This is the depth of terrain deform
        // Default: 128.
        private constant real TERRAIN_DEPTH = 128.
        // Duration of terrain deform in seconds
        // Default: 0.75
        private constant real TERRAIN_DEFORM_DURATION = 0.75
        // This is number of how much bolts are created
        // Default: 15
        private constant integer NUMBER_OF_BOLTS = 15
        // How often are the bolts created
        // Default: 0.1
        private constant real SINGLE_BOLT_DELAY = 0.1
       
        // This variables are not supposed to be touched here
        // Go down below to edit them
        //{
            private integer Levels = 0
            private real array EF_AOE
            private real array TargetMaxDamage
            private real array SpellMaxDamage
        //}
    endglobals

    //***********************************************************************
    //
    //        This is where you setup your spell, level data
    //
    private function ElectricField_Setup takes nothing returns nothing
        // This is number of levels your spell has
        // Default: 3
        set Levels = 3
       
        // This is AOE (Area of Effect)
        // per level set
        // Default 1: 610
        // Default 2: 660
        // Default 3: 705
        set EF_AOE[1] = 610.
        set EF_AOE[2] = 660.
        set EF_AOE[3] = 705.
       
        // This is max damage per target
        // Default 1: 100
        // Default 2: 160
        // Default 3: 210
        set TargetMaxDamage[1] = 125.
        set TargetMaxDamage[2] = 260.
        set TargetMaxDamage[3] = 400.
       
        // This is the max damage spell can
        // deal to all units
        // Default 1: 1000
        // Default 2: 1650
        // Default 3: 2270
        set SpellMaxDamage[1] = 1000.
        set SpellMaxDamage[2] = 1650.
        set SpellMaxDamage[3] = 3260.
    endfunction

    //********************************************************************
    //              Do not edit below if you are not a jass
    //                         programmer
    //********************************************************************

    //----------------
    // Spell globals
    //----------------

    globals
        // Constants
        private constant real PI = 3.14159
        private constant real TPI = 2*PI
        private constant real PI_HALF = PI/2
        private constant integer INT_NULL = 0
        private constant real REAL_NULL = 0.
        private constant string ATTACH_POINT_ORIGIN = "origin"
        private constant integer ABILITY_LOCUST = 'Aloc'
        private constant real LIGHTNING_HEIGHT = 1024.
        private constant integer GENERIC_CODE = 'BTLF'
        private constant integer ABILITY_CROW_FORM = 'Amrf'
        private constant real TIMER_MOVE_DELAY = 0.01
       
       
        // Other changeable variables
        private timer EFTimer = null                 // Main Spell Timer
        private integer TGCount = INT_NULL           // Counts Triggers
        private effect array TimedEffect[8191]       // Effects stored on units
    endglobals

    // ************************************************************************
    //                          New Types
    // ************************************************************************

    private struct bolts
        public trigger t
        private triggeraction ta
        public real x
        public real y
        public integer lvl
       
        private static bolts array B_Ptr[8191]
       
        // *** Constructor ***
        static method create takes code fptr, real x, real y, integer lvl returns bolts
            local bolts this = bolts.allocate()
           
            set this.t = CreateTrigger()
            set this.ta = TriggerAddAction(this.t, fptr)
            set this.x = x
            set this.y = y
            set this.lvl = lvl
            set this.B_Ptr[ArrayId(this.t)] = (this)
           
            return (this)
        endmethod
       
        // *** Destructor ***
        method onDestroy takes nothing returns nothing
            call TriggerRemoveAction(this.t, this.ta)
            call DestroyTrigger(this.t)
            set this.ta = null
            set this.t = null
        endmethod
       
        public static method GetTriggering takes nothing returns bolts
            return bolts.B_Ptr[ArrayId(GetTriggeringTrigger())]
        endmethod
    endstruct
   
    private type punit extends unit array[1]
   
    private struct unitx
        public unit u
        public real sd
        public real dx
        public real dy
       
        private static unitx array U_Ptr[8191]
       
        // *** Constructor ***
        static method create takes unit u, real rad, real sd returns unitx
            local unitx this = unitx.allocate()
           
            set this.u = u
            set this.dx = Cos(rad)
            set this.dy = Sin(rad)
            set this.sd = sd
            set this.U_Ptr[ArrayId(this.u)] = this
           
            return (this)
        endmethod
       
        static method ResetElectrifiedHero takes nothing returns nothing
            local punit pu = GetSleepData()
            call ShowUnit(pu[0], true)
            set pu[0] = null
            call pu.destroy()
        endmethod
       
        // *** Destructor ***
        method onDestroy takes nothing returns nothing
            local punit pu
            if (not IsUnitType(this.u, UNIT_TYPE_HERO)) then
                call RemoveUnit(this.u)
            else
                call SetUnitTimeScale(this.u, 1.)
                call SetUnitVertexColor(this.u, 255, 255, 255, 255)
                call PauseUnit(this.u, false)
                call SetUnitFlyHeight(this.u, 0., 0.)
                call ShowUnit(this.u, false)
                set pu = punit.create()
                set pu[0] = this.u
                call SleepEx(3., function unitx.ResetElectrifiedHero, pu)
            endif
            set this.u = null
        endmethod
       
        public static method GetEnum takes nothing returns unitx
            return unitx.U_Ptr[ArrayId(GetEnumUnit())]
        endmethod
    endstruct

    private struct triggerx
        public trigger t
        public triggeraction ta
        public group g
        public integer i
       
        private static triggerx array T_Ptr[8191]
        public static triggerx TriggerX = 0
       
        // *** Constructor ***
        static method create takes code pf, group g returns triggerx
            local triggerx this = triggerx.allocate()
           
            set this.t = CreateTrigger()
            set this.ta = TriggerAddAction(this.t, pf)
            set this.g = g
            set this.i = 0
            set this.T_Ptr[ArrayId(this.t)] = this
           
            return (this)
        endmethod
       
        // *** Destructor ***
        method onDestroy takes nothing returns nothing
            call TriggerRemoveAction(this.t, this.ta)
            call DestroyTrigger(this.t)
            call DestroyGroup(this.g)
            set this.t = null
            set this.ta = null
            set this.g = null
        endmethod
       
        public static method GetTriggering takes nothing returns triggerx
            local triggerx this = triggerx.T_Ptr[ArrayId(GetTriggeringTrigger())]
            set this.i = this.i + 1
            return (this)
        endmethod
    endstruct

    private struct timerx
        public timer t
        public integer lvl
        public group g
        public unit u
        public player p
        public real dmg
        public unit d
        public triggerx tx
       
        private static timerx array T_Ptr[8191]
        public static timerx TimerX = 0
       
        // *** Constructor ***
        static method create takes integer lvl, group g, unit u returns timerx
            local timerx this = timerx.allocate()
           
            set this.t = CreateTimer()
            set this.lvl = lvl
            set this.g = g
            set this.u = u
            set this.p = GetOwningPlayer(u)
            set this.tx = 0
            set this.T_Ptr[ArrayId(this.t)] = (this)
           
            return (this)
        endmethod
       
        // *** Destructor ***
        method onDestroy takes nothing returns nothing
            call PauseTimer(this.t)
            call DestroyTimer(this.t)
            call RemoveUnit(this.d)
            set this.t = null
            set this.g = null
            set this.p = null
            set this.d = null
        endmethod
       
        public static method GetExpired takes nothing returns timerx
            return timerx.T_Ptr[ArrayId(GetExpiredTimer())]
        endmethod
    endstruct


    //-------------------------------------------------------------------------
    // *****            Other Spell Defined Functions                   ******
    //-------------------------------------------------------------------------


    //xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    //             Spell Filters Conditions And Other Functions
    //xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

    //***********************************************************************
    //                    Main Unit Group Filter
    private function ELFieldGroupFilter takes nothing returns boolean
        local unit f = GetFilterUnit()
        local player p = GetOwningPlayer(GetTriggerUnit())
        local boolean filter = (not IsUnitType(f, UNIT_TYPE_DEAD) and not IsUnitType(f, UNIT_TYPE_STRUCTURE) and IsUnitEnemy(f, p) and IsUnitVisible(f, p) and GetUnitTypeId(f) != UNIT_DUMMY_CODE)
        set f = null
        set p = null
        return (filter)
    endfunction

    //***********************************************************************
    //                    Add Effects Main Function
    private function EFGroupAction takes nothing returns nothing
        set TimedEffect[ArrayId(GetEnumUnit())] = AddSpecialEffectTarget(EF_LIGHTNING_EFFECT, GetEnumUnit(), ATTACH_POINT_ORIGIN)
    endfunction

    //***********************************************************************
    //                          Move Function
    private function EFMoveActionEnum takes nothing returns nothing
        local unitx ux = unitx.GetEnum()
        local real x
        local real y
        local real z
        local integer exec = triggerx.TriggerX.i
   
        // Define movement coordiantes
        if (exec <= ux.sd) then
            set x = GetUnitX(ux.u) + 2.5 * ux.dx
            set y = GetUnitY(ux.u) + 2.5 * ux.dy
            set z = GetUnitFlyHeight(ux.u) + UNIT_DISAPPEAR_VELOCITY_QUICK*TIMER_MOVE_DELAY
        else
            set x = GetUnitX(ux.u) + ux.dx
            set y = GetUnitY(ux.u) + ux.dy
            set z = GetUnitFlyHeight(ux.u) + UNIT_DISAPPEAR_VELOCITY_SLOW*TIMER_MOVE_DELAY
        endif
       
        // Apply movement coordinates
        call SetUnitX(ux.u, x)
        call SetUnitY(ux.u, y)
        call SetUnitFlyHeight(ux.u, z, REAL_NULL)
       
        // Load lightning effects on this execs
        if (exec == 125 or exec == 75 or exec == 25 or exec == 175) then
            call DestroyEffect(AddSpecialEffectTarget(EF_LIGHTNING_IMPACT, ux.u, ATTACH_POINT_ORIGIN))
        endif
       
        // Clear values if this is the last loop
        if (exec == 200) then
            call ux.destroy()
        endif
    endfunction

    private function EFMoveAction takes nothing returns nothing
        local triggerx tx = triggerx.GetTriggering()
       
        // Main Movement Loop
        set tx.TriggerX = tx
        call ForGroup(tx.g, function EFMoveActionEnum)
       
        // End spell here
        if (tx.i == 200) then
            set TGCount = TGCount - 1
            if (TGCount == INT_NULL) then
                call PauseTimer(EFTimer)
                call DestroyTimer(EFTimer)
                set EFTimer = null
            endif
            call tx.destroy()
        endif
    endfunction

    //***********************************************************************
    //                    Deal Damage Main Function
    private function EFLightningDamageEnum takes nothing returns nothing
        local timerx tx = timerx.TimerX
        local unit u = GetEnumUnit()
       
        call UnitDamageTarget(tx.d, u, tx.dmg, true, false, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_LIGHTNING, WEAPON_TYPE_WHOKNOWS)
        call DestroyEffect(AddSpecialEffect(EF_EXPLOSION_EFFECT, GetUnitX(u), GetUnitY(u)))
       
        // Unit is now dead do disappear action
        if (IsUnitType(u, UNIT_TYPE_DEAD)) then
            // Load new trigger if needed
            if (tx.tx == 0) then
                set tx.tx = triggerx.create(function EFMoveAction, tx.g)
            endif
           
            call unitx.create(u, GetRandomReal(0., TPI), GetRandomReal(25, 40))
            call SetUnitVertexColor(u, INT_NULL, INT_NULL, INT_NULL, 255)
            call SetUnitTimeScale(u, 0.2)
            call SetUnitPathing(u, false)
            call UnitAddAbility(u, ABILITY_CROW_FORM)
            call UnitRemoveAbility(u, ABILITY_CROW_FORM)
        else // Purge
            // Load dummy caster
            set bj_lastCreatedUnit = CreateUnit(tx.p, UNIT_DUMMY_CODE, GetUnitX(u), GetUnitY(u), bj_UNIT_FACING)
            // Setup this dummy
            call UnitAddAbility(bj_lastCreatedUnit, ABILITY_LOCUST)
            call UnitAddAbility(bj_lastCreatedUnit, PURGE_CODE)
            call UnitApplyTimedLife(bj_lastCreatedUnit, GENERIC_CODE, 0.75)
            // Order to purge target
            call IssueTargetOrder(bj_lastCreatedUnit, "purge", u)
            call GroupRemoveUnit(tx.g, u)
        endif
        set u = null
    endfunction

    private function EFLightningDamage takes nothing returns nothing
        // Load locals, init them
        local timerx tx = timerx.GetExpired()
       
        // Setup main dummy
        set tx.d = CreateUnit(tx.p, UNIT_DUMMY_CODE, REAL_NULL, REAL_NULL, bj_UNIT_FACING)
        call UnitAddAbility(tx.d, ABILITY_LOCUST)
       
        // Setup damage
        set tx.dmg = rmin(SpellMaxDamage[tx.lvl] / I2R(CountUnitsInGroup(tx.g)), TargetMaxDamage[tx.lvl])
       
        // Deal damage loop
        set tx.TimerX = tx
        call ForGroup(tx.g, function EFLightningDamageEnum)
       
        // Load trigger setup (if needed)
        if (tx.tx != 0) then
            if (EFTimer == null) then
                set EFTimer = CreateTimer()
                call TimerStart(EFTimer, TIMER_MOVE_DELAY, TRUE, null)
            endif
           
            call TriggerRegisterTimerExpireEvent(tx.tx.t, EFTimer)
            set TGCount = TGCount + 1
        else
            call DestroyGroup(tx.g)
        endif
       
        // Null variables and destroy objects
        call tx.destroy()
    endfunction

    //***********************************************************************
    //                 Add Dummy Effects Main Function
    private function EFBlowGroundEnum takes nothing returns nothing
        local unit u = GetEnumUnit()
        local real x = GetUnitX(u)
        local real y = GetUnitY(u)
        local real rad = GetRandomReal(0., TPI)
        local real dist = GetRandomReal(225., 375.)
        local unit d = CreateUnit(timerx.TimerX.p, UNIT_DUMMY_CODE, x + dist * Cos(rad), y + dist * Sin(rad), (rad-bj_PI)*bj_RADTODEG)
        call SetUnitFlyHeight(d, LIGHTNING_HEIGHT, REAL_NULL)
        call UnitAddAbility(d, ABILITY_DUMMY_ELECTRIC_FIELD)
        call UnitApplyTimedLife(d, GENERIC_CODE, 0.5)
        call UnitAddAbility(d, ABILITY_LOCUST)
        call IssueTargetOrder(d, "chainlightning", u)
        call DestroyEffect(TimedEffect[ArrayId(u)])
        set TimedEffect[ArrayId(u)] = null
        set d = null
        set u = null
    endfunction

    private function EFBlowGround takes nothing returns nothing
        local timerx tx = timerx.GetExpired()
       
        // Main effects loop...
        set tx.TimerX = tx
        call ForGroup(tx.g, function EFBlowGroundEnum)
       
        // Continue spell...
        call TimerStart(tx.t, 0.2, false, function EFLightningDamage)
    endfunction

    //***********************************************************************
    //   This function is trigger action which loads extra lig effects
    private function LoadThunderbolts takes nothing returns nothing
        // Load basic locals
        local bolts bl = bolts.GetTriggering()
        local integer exec = GetTriggerExecCount(bl.t)
        local real x = bl.x
        local real y = bl.y
        local real r = EF_AOE[bl.lvl]
        local real d = GetRandomReal(0., r)
        local real rad = GetRandomReal(0., TPI)
        local sound s = null
        local effect e
       
        // Gonna improve this QMod a little... (rnd_QMod)
        call SetRandomSeed(QMod(GetRandomInt(57, 37521), GetRandomInt(9, 771)))
       
        // This all's gonna blow the whole field...
       
        // Load thunderbolt
        set x = x+d*Cos(rad)
        set y = y+d*Sin(rad)
        set e = AddSpecialEffect(EF_THUNDERBOLT_EFFECT, x, y)
       
        // Is last exec
        if (exec == NUMBER_OF_BOLTS) then
            // Destroy trigger
            call DisableTrigger(bl.t)
           
            // Sleep for effect destroy
            call Sleep(1.5)
            call DestroyEffect(e)
           
            call bl.destroy()
           
            // Null
            set e = null
            return
        endif
       
        // Destroy effect timed
        call Sleep(0.75)
        call DestroyEffect(e)
       
        // Null locals
        set e = null
    endfunction

    ////////////////////////////////////////////////////////////////////////
    //                 Electric Field Main Condition                      //
    ////////////////////////////////////////////////////////////////////////

    private constant function ELFieldCondition takes nothing returns boolean
        return ( GetSpellAbilityId() == ABILITY_ELECTRIC_FIELD )
    endfunction

    ////////////////////////////////////////////////////////////////////////
    //                  Electric Field Main Action                        //
    ////////////////////////////////////////////////////////////////////////

    private function ELFieldAction takes nothing returns nothing
        // ***********************************************
        // Load locals, here we have to use location
        local unit u = GetTriggerUnit()
        local location l = GetSpellTargetLoc()
        local real x = GetLocationX(l)
        local real y = GetLocationY(l)
        local integer i = INT_NULL
        local sound s = null
        local real cx = REAL_NULL
        local real cy = REAL_NULL
        local real d = REAL_NULL
        local group g = null
        local integer lvl = GetUnitAbilityLevel(u, ABILITY_ELECTRIC_FIELD)
        local boolexpr bx = null
        local timerx t
        local bolts bl
       
        // Not supposed to happen
        if (lvl > Levels) then
            call BJDebugMsg("|cffff0000Unable to cast spell: Electric Field, current spell level is greater then defined.|r")
            return
        endif
       
        // Play Thunder Sound
        set s = CreateSound(SOUND_THUNDER, false, false, false, 10, 10, "")
       
        // Only users can hear sound
        loop
        exitwhen (i >= bj_MAX_PLAYERS)
            // We set sound volume for each player (matching)
            // distance from casted point
            if (GetLocalPlayer() == DD_p[i]) then
                set cx = GetCameraTargetPositionX()
                set cy = GetCameraTargetPositionY()
                set d = SquareRoot(hypot(cx-x, cy-y))
               
                if (d > SOUND_MAX_DISTANCE) then
                    set d = SOUND_MAX_DISTANCE
                endif
               
                call SetSoundVolume(s, R2I(SOUND_THUNDER_VOL-d*(SOUND_THUNDER_VOL/SOUND_MAX_DISTANCE)))
               
                // Camera Noise
                if (d <= CAMERA_NOISE_RANGE and USE_CAMERA_NOISE) then
                    call CameraSetSourceNoise(70.-(d*(70./CAMERA_NOISE_RANGE)), 1750.-(d*(1750./CAMERA_NOISE_RANGE)))
                endif
            endif
            set i = i + 1
        endloop
       
        // Terrain deformation crater action
        call TerrainDeformCrater(x, y, TERRAIN_RADIUS, TERRAIN_DEPTH, R2I(TERRAIN_DEFORM_DURATION*1000.), false)
       
        // Start the sound
        call StartSound(s)
        call KillSoundWhenDone(s)
        set s = null
       
        // Load main big thunder effect
        call DestroyEffect(AddSpecialEffect(GREAT_LIGHTNING_QModEL, x, y))
       
        // Load extra lightning effects
        if (NUMBER_OF_BOLTS > INT_NULL) then
            set bl = bolts.create(function LoadThunderbolts, x, y, lvl)
            call TriggerRegisterTimerEvent(bl.t, SINGLE_BOLT_DELAY, TRUE)
        endif
       
        // Sleep here if wanted
        if (THUNDER_DELAY > REAL_NULL) then
            call Sleep(THUNDER_DELAY)
        endif
       
        // Load all valid units in to damage group
        set g = CreateGroup()
        set bx = Filter(function ELFieldGroupFilter)
        call GroupEnumUnitsInRange(g, x, y, EF_AOE[lvl], bx)
        call DestroyBoolExpr(bx)
       
        // Add Effect To Enum Unit
        call ForGroup(g, function EFGroupAction)
       
        // Load Lightning Effects
        set t = timerx.create(lvl, g, u)
        call TimerStart(t.t, LIGHTNING_EFFECT_DURATION, false, function EFBlowGround)
       
        // Sleep for camera noise
        call Sleep(2.00)
       
        // Reset camera noise
        if (TGCount <= 1 and USE_CAMERA_NOISE) then
            set i = 0
            loop
            exitwhen (i >= bj_MAX_PLAYERS)
                if (GetLocalPlayer() == DD_p[i]) then
                    call CameraSetSourceNoise(REAL_NULL, REAL_NULL)
                endif
                set i = i + 1
            endloop
        endif
       
        // Null locals
        call RemoveLocation(l)
        set l = null
        set u = null
        set g = null
        set bx = null
    endfunction

    //===========================================================================
    // Main init electric field function
    private function ElectricField_Main takes nothing returns nothing
        //--------------------->
        //* Load init locals
        //<--------------------
        local trigger t = CreateTrigger()
       
        // Register any unit spell effect event
        // Add condition and action
        call TriggerRegisterAnyUnitEvent(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
        call TriggerAddCondition(t, Condition(function ELFieldCondition))
        call TriggerAddAction(t, function ELFieldAction)
       
        // Preload Files
        call Preload(GREAT_LIGHTNING_QModEL)
        call Preload(EF_EXPLOSION_EFFECT)
        call Preload(EF_LIGHTNING_EFFECT)
        call Preload(EF_LIGHTNING_IMPACT)
        call Preload(EF_THUNDERBOLT_EFFECT)
        //call Preload(SOUND_THUNDER)
        call GenericSoundDD(SOUND_THUNDER, 0., 0., 0., 1.)
       
        call PreloadStart()
        // For Player Neutral Extra make map visible
        //call FogQModifierStart(CreateFogQModifierRect(DD_p[14], FOG_OF_WAR_VISIBLE, bj_mapInitialPlayableArea, true, false))
       
        // Call for user defined stuff that will setup this spell
        call ElectricField_Setup()
       
        set t = null
    endfunction

endlibrary
 
//TESH.scrollpos=12
//TESH.alwaysfold=0
//**************************************************************************************
//                            Spell: Dark Torture
//                            Author: Dark Dragon
//                            Date: 20 November 2008
//
//                    Other: Spell made for fun testing vJass
//
//
//                              Installation:
//
// - 1. Make sure you have open the JassNewGen Pack editor not normal one and make sure you have last version
// - 2. Go to Import Manager (F12) and extract BTNDarkTouch.blp and its DISBTN version
//      sword_create.wav, sword_disappere.wav, sword_cut.wav and sword_start.wav
//      Frostmourne.mdx and (dummy.mdx -> if not from before)
// - 3. Import all of this to your map and set ther path to as you can see here (in my map)
// - 4. Go to Object Manager (F6) and copy dummy unit {Dummy (DD Universal Pack)}
//      sword unit {Sword (DD Universal Pack)}, Dark Torture Slow (Dummy) ability and
//      main ability Dark Torture. When you are pasting them to your map make sure you
//      type the following rawcodes:
//      Dummy:                  'dumy'
//      Dark Torture:           'Drkt'
//      Dark Torture Slow:      'dtsd'
//      Sword (DDUniversalPack):'drks'
// - 5. If you want different raw codes edit the below as well:
// - 6. Edit date below to your own will and enjoy the spell:
// - 7. And of course copy this trigger and DDUniversal Pack to your map.
//
//**************************************************************************************

// Dark Torture library
library DarkTorture initializer DarkTorture_Main requires DDUniversalPack

// **************************************************************************
// **                         SPELL SETUP                                  **
// **                                                                      **
// ** This variables are constants and are made to easy change spell style **
// ** Define them as you like.                                             **
// **************************************************************************
globals
    // This is the raw code of the spell 'Dark Torture'
    // Default: 'Drkt'
    private constant integer DARK_TORTURE_RAWCODE = 'Drkt'
    // This is the raw code of the sword
    // Default: 'drks'
    private constant integer SWORD_RAWCODE = 'drks'
    // This the raw code of dummy (DDUniversalPack) (change it in DDUniversal Pack trigger)
    // Default: 'dumy'
    private constant integer DUMMY_RAWCODE = DD_DUMMY_CODE
    // This is the raw code of dark torture slow (dummy) ability
    // Default: 'dtsd'
    private constant integer SLOW_RAWCODE = 'dtsd'
    // This is max sound hear range.
    // Default: 3500.
    private constant real SOUND_MAX_DISTANCE = 3500.
    // This is effect missile of each sword
    // Default: "Abilities\\Weapons\\ZigguratMissile\\ZigguratMissile.mdl"
    private constant string SWORD_EFFECT_MODEL = "Abilities\\Weapons\\ZigguratMissile\\ZigguratMissile.mdx"
    // Blood effect QModel path
    // Default: "Objects\\SpawnQModels\\Human\\HumanBlood\\BloodElfSpellThiefBlood.mdl"
    private constant string BLOOD_EFFECT = "Objects\\SpawnQModels\\Human\\HumanBlood\\BloodElfSpellThiefBlood.mdx"
    // This is the path of sword start sound. This is called for each sword when he is fired
    // Default: "Custom\\Spells\\Dark Torture\\sword_start.wav"
    private constant string SWORD_SOUND_START_PATH = "Custom\\Spells\\Dark Torture\\sword_start.wav"
    private constant real SWORD_SOUND_START_PATH_VOL = 80.
    // This is the path of start sound
    // Default: "Custom\\Spells\\Dark Torture\\sword_create.wav"
    private constant string SWORD_CREATE_SOUND_PATH = "Custom\\Spells\\Dark Torture\\sword_create.wav"
    private constant real SWORD_CREATE_SOUND_PATH_VOL = 55.
    // This is the path of start sound
    // Default: "Custom\\Spells\\Dark Torture\\sword_hit.wav"
    private constant string SWORD_HIT_PATH = "Custom\\Spells\\Dark Torture\\sword_cut.wav"
    private constant real SWORD_HIT_PATH_VOL = 70.
    // This is sound of swords disappere action
    // Default: "Custom\\Spells\\Dark Torture\\sword_disappere.wav"
    private constant string SWORD_DISAPPERE_PATH = "Custom\\Spells\\Dark Torture\\sword_disappere.wav"
    private constant real SWORD_DISAPPERE_PATH_VOL = 70.
    // This is the dust effect when moving
    // Default: "Objects\\SpawnQModels\\Undead\\ImpaleTargetDust\\ImpaleTargetDust.mdl"
    private constant string DUST_EFFECT = "Objects\\SpawnQModels\\Undead\\ImpaleTargetDust\\ImpaleTargetDust.mdx"
    // This is effect loaded on water when pushed
    // Default: "Abilities\\Spells\\Other\\CrushingWave\\CrushingWaveDamage.mdl"
    private constant string WATER_EFFECT = "Abilities\\Spells\\Other\\CrushingWave\\CrushingWaveDamage.mdx"
    // Delay of sword creation
    // If you want fast sword creation set this value to 0.01
    // Warning this value must not be zero
    // Default: 0.2
    private constant real SWORD_CREATION_DELAY = 0.15
    // Delay in seconds, how much time must pass until next sword is shooted
    // Default: 0.25
    private constant real SWORD_FIRE_DELAY = 0.2
    // This tells how much beyond or after casters swords will start loading
    // Default: 0.
    private constant real SWORD_LOAD_OFFSET = -525.
    // This is missile speed (sword speed)
    // Speed is defined in game coordinates per second
    // Default: 1000.
    private constant real SWORDS_SPEED = 1400.
    // This is defined max distance of all swords.
    // When swords pass this amount of distance they will be
    // removed even if they did not effect any target.
    // Default: 1700.
    private constant real SWORDS_MAX_DISTANCE = 1700.
    // This is swords collision size or AoE of
    // how much units are effected
    // Default: 70.
    private constant real SWORD_COLLISION = 70.
    // This is swords height (at which z sword is created)
    // Default: 80.
    private constant real SWORD_HEIGHT = 80.
    // This is distance of effects (how much distance will they pass until removed)
    // Note: changing this value to negative will turn in different direction
    // For negative value {Degress}, for positive value {Degress-180} where Degress
    // is spell cast degress
    // Default: 1000.
    private constant real EFFECTS_MAX_DISTANCE = -1000.
    // This is value of how much of speed will fall when sword hits a single target
    // Default: 400.
    private constant real ON_ADD_SPEED_DECREASE = 500.
   
    // This variables are not supposed to be touched here
    //{
        private integer Levels = 0
        private integer array MaxSwordCount
        private real array SwordsMaxDamage
        private real array SingleSwordDamage
        private real array SwordLineWidth
        private real array PushCrashDamage
        private real array MaxPushRange
    //}
endglobals

// This part of code is used to define spell constants per level
private function DarkTorture_Setup takes nothing returns nothing
    // This is spell max level
    // This spell max level is 8191, for more than that value game will crash
    // I guess, but you dont need such a high level
   
    // Default: 3
    set Levels = 3
   
    // Max sword count per level, creates n swords on cast to shoot
    // Warning for value of greather then 16 spell will crash
    // The value must not be larger then 16
   
    // Default: Level 1 = 6
    // Default: Level 2 = 7
    // Default: Level 3 = 9
    set MaxSwordCount[1] = 6
    set MaxSwordCount[2] = 7
    set MaxSwordCount[3] = 9
   
    // This is the damage of single sword at specific level
    // How much one sword deals damage
   
    // Default: Level 1 = 125.
    // Default: Level 2 = 220.
    // Default: Level 3 = 300.
    set SingleSwordDamage[1] = 125.
    set SingleSwordDamage[2] = 220.
    set SingleSwordDamage[3] = 300.
   
    // This is spells max damage at one cast
    // If this value is low and you create many swords
    // this swords will not cause any damage because this defines
    // how much damage can spell deal at one cast
    // If you want to make all swords effect enemies (all swords deal full damage)
    // then do it like that:
    // set SwordMaxDamage[level] = SingleSwordDamage[level] * MaxSwordCount[level]
    // Of course you can calculate that in your head or on calculator and just type
    // value here. So for MaxSwordsCount[1] = 6 and SingleSwordDamage[1] = 125.
    // set SwordMaxDamage[1] = 6 * 125 or set SwordMaxDamage[1] = 750 on level 3 it
    // will be 9 * 300 which is 2700.
   
    // Default: Level 1 = 625.
    // Default: Level 2 = 1320.
    // Default: Level 3 = 2100.
    set SwordsMaxDamage[1] = 625.
    set SwordsMaxDamage[2] = 1320.
    set SwordsMaxDamage[3] = 2100.
   
    // This is the value which tells on how big area will the swords
    // be shooted and created at.
    // Example for low numbers such as 10, almost all swords will be created at same
    // place and will cause damage in that small AoE. Of course for spell to
    // be better if here is put large number such as 700-800 then more swords
    // should be created as well.
    // Basically we could say that this is AoE of spell.
   
    // Default: Level 1 = 450.
    // Default: Level 2 = 450.
    // Default: Level 3 = 450.
    set SwordLineWidth[1] = 450.
    set SwordLineWidth[2] = 450.
    set SwordLineWidth[3] = 450.
   
    // This values are the one that are executed when
    // group of pushed units crash in to another unit or wall.
    // Just when crashing to wall all units will be damaged, but when some unit gots
    // crushed then only that unit will takes this small damage
   
    // Default: Level 1 = 35.
    // Default: Level 2 = 45.
    // Default: Level 3 = 55.
    set PushCrashDamage[1] = 35.
    set PushCrashDamage[2] = 45.
    set PushCrashDamage[3] = 55.
   
    // This is max push range until main target stops moving with other units
    // So after this distance calculated in (coords) all pushed units stop moving
   
    // Default: Level 1 = 300.
    // Default: Level 2 = 325.
    // Default: Level 3 = 350.
    set MaxPushRange[1] = 300.
    set MaxPushRange[2] = 325.
    set MaxPushRange[3] = 350.
endfunction

//----------------------------------------------------------
// Do not edit below if you are not a jass programmer
//----------------------------------------------------------

// Spell globals which are not supposed to be edited
// in other words should be constants
globals
    // << Some spell constants >>
   
    // Pi / 2
    private constant real PI_HALF = bj_PI/2.
    // Temp location z
    private constant location LOC_Z = Location(0., 0.)
    // Ability locust
    private constant integer LOCUST_RAWCODE = 'Aloc'
    // Ability crow form
    private constant integer CROWFORM_RAWCODE = 'Amrf'
    // Timer min delay
    private constant real TIMER_MIN_DELAY = 0.01
    // This is object null (sword)
    private constant integer NULL = 0
    // Target attach point origin
    private constant string ATTACH_POINT = "origin"
    // This is temp_group
    private constant group TempGroup = CreateGroup()
   
    // << Other spell globals >>
    private integer TempId = 0                                  // Spell id cast
    private timer DTTimer = null                                // Main spell timer
    private boolexpr GroupFilter = null                         // Filter used for picking sword targets
    private boolean array UnitIsPushed[8191]                    // Check is unit pushed by another sword
    private integer TempSword = NULL                            // This is used as temp_sword
    private integer TGCount = 0                                 // Counts current triggers
    private integer array TriggerSword[15][511]                 // Swords stored on trigger
    private sound array KillSoundVar[8191]                      // Temp sounds
endglobals
//-------------------------------------------------------------------------------------------

// This spell is different then other ones. Here we will define new object type.
// Sword type which is a new object set of other data.
// So this spell will use struct to define this new type even if it is a little slower then
// working directly with globals
// However its beautiful to code with structs and this language become more object orientated

//-------------------------------------------------------------------------------------------

// ==============================================================
// *** This is our triggerx type which has some extra usage ***
private struct triggerx
    public trigger t            // Main trigger
    private triggeraction ta    // Non-leaking trigger action
    public group array g[2]     // Group trigger pointers
    public real dmg             // Damage of the single sword
    public boolean started      // Did spell start?
    public integer lvl          // Spells level
    public triggerx tx          // Pointer to other triggerx
    public integer array sw[16] // Swords
    public integer faliure
   
    private static triggerx array TX_Ptr[8191]
   
    // Allocate (create) method for triggerx
    static method create takes code pfunc, real dmg returns triggerx
        local triggerx this = triggerx.allocate()
       
        set this.t = CreateTrigger()
        set this.ta = TriggerAddAction(this.t, pfunc)
        set this.g[0] = CreateGroup()
        set this.g[1] = CreateGroup()
        set this.dmg = dmg
        set this.started = false
        set this.TX_Ptr[ArrayId(this.t)] = (this)
       
        return (this)
    endmethod
   
    // Allocate with other option
    static method new takes code pfunc, integer lvl, triggerx tx, integer faliure returns triggerx
        local triggerx this = triggerx.allocate()
       
        set this.t = CreateTrigger()
        set this.ta = TriggerAddAction(this.t, pfunc)
        set this.lvl = lvl
        set this.tx = tx
        set this.faliure = faliure
        set this.TX_Ptr[ArrayId(this.t)] = (this)
       
        return (this)
    endmethod
   
    // *** Destructor method ***
    method onDestroy takes nothing returns nothing
        if (this.g[0] != null) then
            call DestroyGroup(this.g[0])
            call DestroyGroup(this.g[1])
        endif
        call TriggerRemoveAction(this.t, this.ta)
        call DestroyTrigger(this.t)
        set this.t = null
        set this.ta = null
        set this.g[0] = null
        set this.g[1] = null
    endmethod
   
    // Execute method
    public method Execute takes nothing returns nothing
        call TriggerExecute(this.t)
    endmethod
   
    // Register method
    public method RegisterTimedExec takes real secs returns nothing
        call TriggerRegisterTimerEvent(this.t, secs, true)
    endmethod
   
    // Our GetTriggeringTriggerx method
    public static method triggeringx takes nothing returns triggerx
        return triggerx.TX_Ptr[ArrayId(GetTriggeringTrigger())]
    endmethod
endstruct

// ==============================================================
// *** This is our timer storage helper struct type ***
private struct timerx
    public timer t      // Our main timer
    public real x       // X of cast point
    public real y       // Y of cast point
    public real rad     // Radians from cast point to target point
    public real exec    // Current execution (its real so i don't have to convert it)
    public integer lvl  // Spell's level
    public integer pid  // Player's id
    public real fz      // The floor z
    public triggerx tx  // Our triggerx
    public integer faliure

    private static timerx array TX_Ptr[8191]
   
    // Our constructor timerx()
    static method create takes real x, real y, real rad, integer lvl, integer pid, real fz, triggerx tx returns timerx
        local timerx this = timerx.allocate()
       
        set this.t = CreateTimer()
        set this.x = x
        set this.y = y
        set this.rad = rad
        set this.exec = 0.
        set this.lvl = lvl
        set this.pid = pid
        set this.fz = fz
        set this.tx = tx
        set this.faliure = 0
        set this.TX_Ptr[ArrayId(this.t)] = (this)
       
        return (this)
    endmethod
   
    // Our destructor ~timerx()
    method onDestroy takes nothing returns nothing
        call PauseTimer(this.t)
        call DestroyTimer(this.t)
        set this.t = null
    endmethod
   
    public static method expiredx takes nothing returns timerx
        return timerx.TX_Ptr[ArrayId(GetExpiredTimer())]
    endmethod
endstruct

// ==============================================================
// *** Finally our main type sword (this is a single sword) ***
private struct sword
    // Here define parts "objects" of type sword
   
   
    unit Sword                  // This is the main unit (Sword)
    unit Victim                 // Main target of the sword
    group PushGroup             // This are all effected units
    real Height                 // This is height of blade
    boolean CanMove             // Tells can sword move
    real Speed                  // Speed of sword
    integer Level               // Level of spell
    real posX                   // Position x of sword
    real posY                   // Position y of sword
    real x                      // Direction of sword x
    real y                      // Direction of sword y
    real PushRange              // The current pushed range
    integer id                  // This is player id of sword
    real Damage                 // Every sword damage
    real Distance               // Distance of sword
    triggerx pt                 // This is pointer at main loop trigger
                                // with this pointer same variables are
                                // accesible in all structs of type sword
                                // pt = pointer trigger <trigger* pt>
   
    // This are sword effects created at begining
    unit DummyEffect1
    unit DummyEffect2
    effect Effect1
    effect Effect2
    real EffectDist
    real Effect1Height
    real Effect2Height
   
    // Write sword methods
   
    // Constructor method
    static method create takes integer playerId, real x, real y, real z, real rad, real floorz, integer level, triggerx pt returns sword
        local sword this = sword.allocate()
        local real ex
        local real ey
       
        // Used to detect height of floor
        call MoveLocation(LOC_Z, x, y)
       
        // Init variables - parts of struct "object"
        set this.Sword = CreateUnit(DD_p[playerId], SWORD_RAWCODE, x, y, rad*bj_RADTODEG)
        set this.Victim = null
        set this.PushGroup = CreateGroup()
        set this.Height = z + floorz
        set this.CanMove = false
        set this.Speed = SWORDS_SPEED
        set this.Level = level
        set this.x = Cos(rad)
        set this.y = Sin(rad)
        set this.posX = x
        set this.posY = y
        set this.PushRange = MaxPushRange[level]
        set this.id = playerId
        set this.Damage = SingleSwordDamage[level]
        set this.Distance = SWORDS_MAX_DISTANCE
        set this.pt = pt
        call UnitAddAbility(this.Sword, LOCUST_RAWCODE)
        call UnitAddAbility(this.Sword, CROWFORM_RAWCODE)
        call SetUnitUserData(this.Sword, integer(this))
        call SetUnitFlyHeight(this.Sword, this.Height-GetLocationZ(LOC_Z), 0.)
       
        // Load effects
       
        // Effect One
        set ex = x + SWORD_COLLISION*0.5 * Cos(rad-PI_HALF)
        set ey = y + SWORD_COLLISION*0.5 * Sin(rad-PI_HALF)
        set this.DummyEffect1 = CreateUnit(DD_p[playerId], DUMMY_RAWCODE, ex, ey, (rad-bj_PI)*bj_RADTODEG)
        set this.Effect1 = AddSpecialEffectTarget(SWORD_EFFECT_MODEL, this.DummyEffect1, ATTACH_POINT)
        set this.Effect1Height = z + floorz
        call UnitAddAbility(this.DummyEffect1, LOCUST_RAWCODE)
        call UnitAddAbility(this.DummyEffect1, CROWFORM_RAWCODE)
        call MoveLocation(LOC_Z, ex, ey)
        call SetUnitFlyHeight(this.DummyEffect1, this.Effect1Height-GetLocationZ(LOC_Z), 0.)
        call SetUnitScale(this.DummyEffect1, .4, .4, .4)
       
       
        // Effect Two
        set ex = x + SWORD_COLLISION*0.5 * Cos(rad+PI_HALF)
        set ey = y + SWORD_COLLISION*0.5 * Sin(rad+PI_HALF)
        set this.DummyEffect2 = CreateUnit(DD_p[playerId], DUMMY_RAWCODE, ex, ey, (rad-bj_PI)*bj_RADTODEG)
        set this.Effect2 = AddSpecialEffectTarget(SWORD_EFFECT_MODEL, this.DummyEffect2, ATTACH_POINT)
        set this.Effect2Height = z + floorz
        call UnitAddAbility(this.DummyEffect2, LOCUST_RAWCODE)
        call UnitAddAbility(this.DummyEffect2, CROWFORM_RAWCODE)
        call MoveLocation(LOC_Z, ex, ey)
        call SetUnitFlyHeight(this.DummyEffect2, this.Effect2Height-GetLocationZ(LOC_Z), 0.)
        call SetUnitScale(this.DummyEffect2, .4, .4, .4)
       
        // For all effects
        set this.EffectDist = 1.
       
        return (this)
    endmethod
   
    // Picks any unit for this sword to push
    method PickUnits takes nothing returns nothing
        local unit e    // Enum unit
        set TempId = this.id
        call GroupClear(TempGroup)
        call GroupEnumUnitsInRange(TempGroup, this.posX, this.posY, SWORD_COLLISION, GroupFilter)
       
        loop
        set e = FirstOfGroup(TempGroup)
        exitwhen (e == null)
            call GroupRemoveUnit(TempGroup, e)
            call UnitDamageTarget(this.Sword, e, PushCrashDamage[this.Level], true, false, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_DEATH, WEAPON_TYPE_WHOKNOWS)
            call DestroyEffect(AddSpecialEffectTarget(BLOOD_EFFECT, e, ATTACH_POINT))
            if (not IsUnitType(e, UNIT_TYPE_DEAD)) then
                call GroupAddUnit(this.PushGroup, e)
                set UnitIsPushed[ArrayId(e)] = true
                call SetUnitTimeScale(e, .1)
                call SetUnitAnimation(e, "death")
                set this.Speed = rmax(this.Speed - ON_ADD_SPEED_DECREASE, ON_ADD_SPEED_DECREASE)
                call PauseUnit(e, true)
            endif
        endloop
    endmethod
   
    // Move sword method
    method MoveSword takes nothing returns nothing
        local real vel = TIMER_MIN_DELAY*this.Speed
        local real newX = GetUnitX(this.Sword) + vel * this.x
        local real newY = GetUnitY(this.Sword) + vel * this.y
        call MoveLocation(LOC_Z, newX, newY)
        call SetUnitX(this.Sword, newX)
        call SetUnitY(this.Sword, newY)
        call SetUnitFlyHeight(this.Sword, this.Height-GetLocationZ(LOC_Z), 0.)
        set this.posX = newX
        set this.posY = newY
        set this.Distance = this.Distance - vel
    endmethod
   
    // This method moves sword effects
    method MoveEffects takes nothing returns nothing
        local real vel
        local real rad
        local real x
        local real y
       
        if (this.EffectDist == 0.) then
            return
        endif
       
        // Set locals
        set vel = TIMER_MIN_DELAY*SWORDS_SPEED
        set rad = GetUnitFacing(this.DummyEffect1)*bj_DEGTORAD
        set x = Cos(rad)
        set y = Sin(rad)
       
        // If user changes direction of movement to negative value
        if (EFFECTS_MAX_DISTANCE > 0.) then
            set this.EffectDist = this.EffectDist + vel
        else
            set this.EffectDist = this.EffectDist - vel
            set vel = -vel
        endif
        // sqrt(x^2) = abs(x) | leave the x^2 is always positive
        if (this.EffectDist*this.EffectDist >= EFFECTS_MAX_DISTANCE*EFFECTS_MAX_DISTANCE) then
            set this.EffectDist = 0.
        endif
       
        // Effect 1
        call SetUnitX(this.DummyEffect1, GetUnitX(this.DummyEffect1)+vel*x)
        call SetUnitY(this.DummyEffect1, GetUnitY(this.DummyEffect1)+vel*y)
       
        // Effect 2
        call SetUnitX(this.DummyEffect2, GetUnitX(this.DummyEffect2)+vel*x)
        call SetUnitY(this.DummyEffect2, GetUnitY(this.DummyEffect2)+vel*y)
    endmethod
   
    // This method will destroy all sowrds effects
    method DestroyEffects takes nothing returns nothing
        if (this.Effect1 == null) then
            return
        endif
       
        call DestroyEffect(this.Effect1)
        call DestroyEffect(this.Effect2)
        call RemoveUnit(this.DummyEffect1)
        call RemoveUnit(this.DummyEffect2)
        // Must null this struct data as we know they are globals
        set this.Effect1 = null
        set this.Effect2 = null
        set this.DummyEffect1 = null
        set this.DummyEffect2 = null
        set this.Effect1Height = 0.
        set this.Effect2Height = 0.
        set this.EffectDist = 0.
    endmethod
   
    // Destructor method
    method onDestroy takes nothing returns nothing
        // onDestroy locals
        local sound onDeath
        local real cx
        local real cy
        local real d
        local integer i = 0
       
        // Now fade sword out
        call SetUnitUserData(this.Sword, float.create(100.))
        call DDStoreValue(this.Sword, float.create(this.Height))
        call GroupAddUnit(this.pt.g[1], this.Sword)
        call DestroyGroup(this.PushGroup)
        call this.DestroyEffects()
       
        // Load onDeath sound
        set onDeath = CreateSound(SWORD_DISAPPERE_PATH, false, false, false, 12700, 12700, "")
        loop
        exitwhen (i >= bj_MAX_PLAYERS)
            if (GetLocalPlayer() == DD_p[i]) then
                set cx = GetCameraTargetPositionX()
                set cy = GetCameraTargetPositionY()
                set d = SquareRoot((cx-this.posX)*(cx-this.posX) + (cy-this.posY)*(cy-this.posY))
               
                call SetSoundVolume(onDeath, R2I(SWORD_DISAPPERE_PATH_VOL-d*(SWORD_DISAPPERE_PATH_VOL/SOUND_MAX_DISTANCE)))
            endif
            set i = i + 1
        endloop
        call StartSound(onDeath)
        call KillSoundWhenDone(onDeath)
        set onDeath = null
       
        // Must null all variables as they are globals
        set this.Sword = null
        set this.Victim = null
        set this.PushGroup = null
        set this.Height = 0.
        set this.CanMove = false
        set this.Speed = 0.
        set this.Distance = 0.
        set this.Level = 0
        set this.Damage = 0.
        set this.id = 0
        set this.PushRange = 0.
        set this.x = 0.
        set this.y = 0.
        set this.posX = 0.
        set this.posY = 0.
        set this.pt = NULL
    endmethod
endstruct

//*********************************************************************************
// ---                        Other Spell Functions                             ---
//*********************************************************************************

// Killing sound timed must be called because there is a limit of 2^2 sounds of
// same type playing at same time. So we need this timed kill, dont worry its fast
// Such slow timers will not cause any lag
private function KillSound takes nothing returns nothing
    local timer t = GetExpiredTimer()
    local integer id = ArrayId(t)
    call StopSound(KillSoundVar[id], true, false)
    call PauseTimer(t)
    call DestroyTimer(t)
    set KillSoundVar[id] = null
    set t = null
endfunction

private function KillSoundTimed takes sound whichSound, real delay returns nothing
    local timer t = CreateTimer()
    set KillSoundVar[ArrayId(t)] = whichSound
    call TimerStart(t, delay, false, function KillSound)
    set t = null
endfunction

// Functions sets single sound volume for all players to specific values
private function SetSoundVolumeByDistance takes sound s, real max_volume, real x, real y returns nothing
    local integer i = 0
    local real cx
    local real cy
    local real d
   
    loop
    exitwhen (i >= bj_MAX_PLAYERS)
        if (GetLocalPlayer() == DD_p[i]) then
            // Calculate distance
            set cx = GetCameraTargetPositionX()
            set cy = GetCameraTargetPositionY()
            set d = SquareRoot((cx-x)*(cx-x) + (cy-y)*(cy-y))
   
            // For each player set sound volume depending on distance
            call SetSoundVolume(s, R2I((max_volume-d*(max_volume/SOUND_MAX_DISTANCE))*1.27))
        endif
        set i = i + 1
    endloop
endfunction

// This function will return nearest unit (victim / target)
private function GetNearestUnit takes real x, real y, real radius, integer id returns unit
    local unit u
    local unit r
    local real md
    local real d
    local real ux
    local real uy
   
    set TempId = id
    call GroupClear(TempGroup)
    call GroupEnumUnitsInRange(TempGroup, x, y, radius, GroupFilter)
    set md = -1.
    set r = null
   
    loop
    set u = FirstOfGroup(TempGroup)
    exitwhen (u == null)
        set ux = GetUnitX(u)
        set uy = GetUnitY(u)
        set d = SquareRoot((ux-x)*(ux-x) + (uy-y)*(uy-y))
       
        if (md == -1.) then
            set md = d
            set r = u
        endif
       
        if (md > d) then
            set md = d
            set r = u
        endif
        call GroupRemoveUnit(TempGroup, u)
    endloop

    return (r)
endfunction


//----------------------------------------------------------------------------------
//|*********************************************************************************|
//|---                        Spell Main Functions                               ---|
//|*********************************************************************************|
//----------------------------------------------------------------------------------

// This is main condition of the spell
private constant function DarkTorture_Condition takes nothing returns boolean
    return GetSpellAbilityId() == DARK_TORTURE_RAWCODE
endfunction

// On single sword moves all units
private function MoveEnumSwordUnits takes nothing returns nothing
    // This group locals
    local sword s = sword(TempSword)
    local unit u = GetEnumUnit()
    local real x = GetUnitX(u)
    local real y = GetUnitY(u)
   
    // For main victim we decrease max push range
    if (u == s.Victim) then
        set s.PushRange = s.PushRange - (s.Speed*TIMER_MIN_DELAY)
    endif
   
    // Move enum units (all of them)
    if (s.PushRange > 0.) then
        call SetUnitX(u, x+((s.Speed*TIMER_MIN_DELAY)*s.x))
        call SetUnitY(u, y+((s.Speed*TIMER_MIN_DELAY)*s.y))
        // Load movement effects
        if (QMod(GetTriggerExecCount(GetTriggeringTrigger()), 10) == 0)  then
            // On Ground Dust
            if (IsTerrainPathable(x, y, PATHING_TYPE_FLOATABILITY)) then
                call DestroyEffect(AddSpecialEffect(DUST_EFFECT, x, y))
            else // On Ground Water
                call DestroyEffect(AddSpecialEffect(WATER_EFFECT, x, y))
            endif
        endif
    else
        // Release all effected units when run out of range
        call SetUnitAnimation(u, "stand")
        call SetUnitTimeScale(u, 1.)
        call PauseUnit(u, false)
        set UnitIsPushed[ArrayId(u)] = false
       
        // Slow down targets
        set bj_lastCreatedUnit = CreateUnit(DD_p[s.id], DUMMY_RAWCODE, x, y, 0.)
        call UnitAddAbility(bj_lastCreatedUnit, SLOW_RAWCODE)
        call UnitAddAbility(bj_lastCreatedUnit, LOCUST_RAWCODE)
        call UnitApplyTimedLife(bj_lastCreatedUnit, 'BTLF', 0.25)
        call IssueTargetOrder(bj_lastCreatedUnit, "slow", u)
    endif
   
    if (not s.CanMove) then
        // Floor is not pathable
        // blow units away by dealing damage
        call UnitDamageTarget(s.Sword, u, PushCrashDamage[s.Level], true, false, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_DEATH, WEAPON_TYPE_WHOKNOWS)
        call DestroyEffect(AddSpecialEffectTarget(BLOOD_EFFECT, u, ATTACH_POINT))
    endif
   
    // Null locals
    set u = null
    set s = NULL
endfunction

// ForGroup action function (MAIN MOVE ALL SWORDS IN SINGLE CAST)
// Picks all swords
private function MoveEnumUnits takes nothing returns nothing
    // Load movement locals
    local sword s = sword(GetUnitUserData(GetEnumUnit()))
    local triggerx tx = triggerx.triggeringx()
    local sound snd
    local real d
   
    // Effects movement
    if (s.EffectDist != 0.) then
        call s.MoveEffects()
        if (s.EffectDist == 0.) then
            call s.DestroyEffects()
        endif
    endif
   
    // Sword move
    if (s.CanMove) then
        call s.MoveSword()
        // When sword moves we try to find target or group of targets
        if (s.Victim == null) then
            set s.Victim = GetNearestUnit(s.posX, s.posY, SWORD_COLLISION, s.id)
            if (s.Victim != null) then
                // Deal damage
                set d = rmin(SingleSwordDamage[s.Level], tx.dmg)
                if (d > 0.) then
                    // Damage target here
                    call UnitDamageTarget(s.Sword, s.Victim, d, true, false, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_DEATH, WEAPON_TYPE_WHOKNOWS)
                    // Decrease damage here
                    set tx.dmg = rmax(tx.dmg - d, 0.)
                   
                    // Load hit sound
                    set snd = CreateSound(SWORD_HIT_PATH, false, false, false, 12700, 12700, "")
                    call SetSoundVolumeByDistance(snd, SWORD_HIT_PATH_VOL, s.posX, s.posY)
                    call StartSound(snd)
                    call KillSoundWhenDone(snd)
                    set snd = null
                endif
               
                // Dont do anything if target is dead
                if (IsUnitType(s.Victim, UNIT_TYPE_DEAD)) then
                    set s.Victim = null
                    return
                endif
               
                // Set new target (add)
                set UnitIsPushed[ArrayId(s.Victim)] = true
                call GroupAddUnit(s.PushGroup, s.Victim)
                call PauseUnit(s.Victim, true)
                call DestroyEffect(AddSpecialEffectTarget(BLOOD_EFFECT, s.Victim, ATTACH_POINT))
                set s.Speed = rmax(s.Speed-ON_ADD_SPEED_DECREASE, ON_ADD_SPEED_DECREASE)
                call SetUnitTimeScale(s.Victim, 0.1)
                call SetUnitAnimation(s.Victim, "death")
            endif
        else
            // Add any unit who comes near
            call s.PickUnits()
        endif
    endif
   
    // Now pick all units on sword and move them with sword
    set TempSword = integer(s)
    if (not IsTerrainPathable(s.posX+SWORD_COLLISION*s.x, s.posY+SWORD_COLLISION*s.y, PATHING_TYPE_WALKABILITY)) then
        call ForGroup(s.PushGroup, function MoveEnumSwordUnits)
    else
        // Not pathable (stop movement)
        set s.PushRange = 0.
        set s.CanMove = false
        call ForGroup(s.PushGroup, function MoveEnumSwordUnits)
    endif
   
    // This sword is done no more range on pushing has left
    // This one tells that pushed victim with other units
    // reached its last position change
    if (s.PushRange <= 0.) then
        // When s.PushRange us zero or less this will reset units
        call ForGroup(s.PushGroup, function MoveEnumSwordUnits)
       
        // Slow down victim (add killlllllling slow)
        set bj_lastCreatedUnit = CreateUnit(DD_p[s.id], DUMMY_RAWCODE, GetUnitX(s.Victim), GetUnitY(s.Victim), 0.)
        call UnitAddAbility(bj_lastCreatedUnit, SLOW_RAWCODE)
        call UnitAddAbility(bj_lastCreatedUnit, LOCUST_RAWCODE)
        call UnitApplyTimedLife(bj_lastCreatedUnit, 'BTLF', 0.25)
        call IssueTargetOrder(bj_lastCreatedUnit, "slow", s.Victim)
       
        // Destroy
        call s.destroy()
        call GroupRemoveUnit(tx.g[0], GetEnumUnit())
        return
    endif
   
    // The sword reach its end anyway did he pick any unit
    // or not or if victim did not pass push range.
    // This will be end of spell of this sword better to say
    if (s.Distance <= 0.) then
        // When this is set to zero next for group action will unpause
        // all units inside group
        set s.PushRange = 0.
        call ForGroup(s.PushGroup, function MoveEnumSwordUnits)
        // Remove sword from this group
        call GroupRemoveUnit(tx.g[0], s.Sword)
       
        // Slow down victim (add killlllllling slow)
        set bj_lastCreatedUnit = CreateUnit(DD_p[s.id], DUMMY_RAWCODE, GetUnitX(s.Victim), GetUnitY(s.Victim), 0.)
        call UnitAddAbility(bj_lastCreatedUnit, SLOW_RAWCODE)
        call UnitAddAbility(bj_lastCreatedUnit, LOCUST_RAWCODE)
        call UnitApplyTimedLife(bj_lastCreatedUnit, 'BTLF', 0.25)
        call IssueTargetOrder(bj_lastCreatedUnit, "slow", s.Victim)
       
        call s.destroy()
    endif
endfunction

// This is fade in sword function (ForGroup action)
private function SwordFadeIn takes nothing returns nothing
    local unit u = GetEnumUnit()
    local float trans = float( GetUnitUserData(u) )
    local float height = float( DDGetValue(u) )
    local real x = GetUnitX(u)
    local real y = GetUnitY(u)
    local real rad = bj_DEGTORAD * GetUnitFacing(u)
   
    // Fade in
    set trans.val = trans.val - 0.66667
   
    // End trans here
    if (trans.val <= 0.) then
        call trans.delete()
        call height.delete()
        call DDFlushValue(u)
        call GroupRemoveUnit(triggerx.triggeringx().g[1], u)
        call RemoveUnit(u)
        set u = null
        return
    endif
   
    // Slow fade in and movement
    set x = x + Cos(rad)
    set y = y + Sin(rad)
    call SetUnitX(u, x)
    call SetUnitY(u, y)
    call MoveLocation(LOC_Z, x, y)
    call SetUnitFlyHeight(u, height.val-GetLocationZ(LOC_Z), 0.)
    call SetUnitVertexColor(u, 255, 255, 255, R2I(trans.val*2.55))
    set u = null
endfunction

//*********************************************************************
//        This is main movement function [Trigger Action]
//*********************************************************************

private function DarkTortureMovement takes nothing returns nothing
    // Load trigger locals
    local triggerx tx = triggerx.triggeringx()
   
    // Now move all units and all other stuff
    if (FirstOfGroup(tx.g[0]) != null) then
        call ForGroup(tx.g[0], function MoveEnumUnits)
    elseif (tx.started and FirstOfGroup(tx.g[1]) == null) then
        // Here spell ends (Ends 100%)
        call tx.destroy()
       
        // Clearing timer
        set TGCount = TGCount - 1
        if (TGCount == 0) then
            call PauseTimer(DTTimer)
            call DestroyTimer(DTTimer)
            set DTTimer = null
        endif
    endif
   
    // Fade sword out
    if (FirstOfGroup(tx.g[1]) != null) then
        call ForGroup(tx.g[1], function SwordFadeIn)
    endif
endfunction

// Trigger action shoot blades at random time
private function ShootBlades takes nothing returns nothing
    // Define locals
    local triggerx tx = triggerx.triggeringx()
    local integer ex = GetTriggerExecCount(tx.t)
    local integer sw_id = GetRandomInt(0, MaxSwordCount[tx.lvl]-ex-tx.faliure)
    local sound snd = null
    local sword s = sword(tx.tx.sw[sw_id])
   
    // *** this is omg ***
    if (tx.faliure == MaxSwordCount[tx.lvl]) then
        set tx.tx.started = true
        call tx.destroy()
        return
    endif
   
    debug call BJDebugMsg(I2S(s))
   
    // Sort swords for next exec (random one is replaced with last one)
    set tx.tx.sw[sw_id] = tx.tx.sw[MaxSwordCount[s.Level]-ex-tx.faliure]
   
    // Random sleep
    //call Sleep(GetRandomReal(0.1, 0.4))
    //call SetRandomSeed(QMod(GetRandomInt(1000, 100000), GetRandomInt(1, 334)))
   
    // Allow sword to move
    set s.CanMove = true
   
    // Play shoot sound
    set snd = CreateSound(SWORD_SOUND_START_PATH, false, false, false, 12700, 12700, "")
    call SetSoundVolumeByDistance(snd, SWORD_SOUND_START_PATH_VOL, s.posX, s.posY)
    call StartSound(snd)
    call KillSoundTimed(snd, 0.325)
    // Above we dont want to play full sound
    // Its because I dont have that good sounds and to find
    // free ones that are good is hard
   
    // Is last exec then end
    if (ex == MaxSwordCount[tx.lvl]-tx.faliure) then
        // Set spell has started
        set tx.tx.started = true
        // Blow triggerx
        call tx.destroy()
    //else
        // Not last exec again
        //call tx.Execute()
    endif
   
    // Now last one gets cleared
    set tx.tx.sw[MaxSwordCount[s.Level]-ex-tx.faliure] = NULL
   
    // Null locals
    set s = NULL
endfunction

// This is main function for creating swords
private function CreateSwords takes nothing returns nothing
    // Load all locals
    local timerx tmx = timerx.expiredx()
    local sword s = NULL
    local real x = tmx.x
    local real y = tmx.y
    local real radx = (tmx.rad - PI_HALF)
    local sound snd = null
    local real d = 0.
    local real cx = 0.
    local real cy = 0.
    local integer i = 0
    local real sc = I2R(MaxSwordCount[tmx.lvl])
    local triggerx tx = NULL

    // Here we end the spell
    if (tmx.exec >= MaxSwordCount[tmx.lvl]) then
        // Start moving blades by random time
        set tx = triggerx.new(function ShootBlades, tmx.lvl, tmx.tx, tmx.faliure)
        call tx.RegisterTimedExec(SWORD_FIRE_DELAY)
        call tx.Execute()
       
        // Destroy our timerx
        call tmx.destroy()
        return
    endif
   
    // Create sword
    set radx = radx + (bj_PI/(sc-1))*tmx.exec
    //set radx = radx + (bj_PI/(sc*sc))*tmx.exec
    set x = x + (SwordLineWidth[tmx.lvl]*0.5 * Cos(radx)) - (SWORD_LOAD_OFFSET*Cos(tmx.rad-PI))
    set y = y + (SwordLineWidth[tmx.lvl]*0.5 * Sin(radx)) - (SWORD_LOAD_OFFSET*Sin(tmx.rad-PI))
    // Here we call for constructor
    set s = sword.create(tmx.pid, x, y, SWORD_HEIGHT, tmx.rad, tmx.fz, tmx.lvl, tmx.tx)
   
    // Here we make sure that effects are destroyed
    if (IsTerrainPathable(x, y, PATHING_TYPE_WALKABILITY)) then
        // This as well destroys all effects
        call s.destroy()
        set tmx.faliure = (tmx.faliure + 1)
    else
        // Limit of 16 swords --- Here we store all created swords
        // data[exec][tgid] = whichSword
        set tmx.tx.sw[R2I(tmx.exec)-tmx.faliure] = integer(s)
        call GroupAddUnit(tmx.tx.g[0], s.Sword)
    endif
   
    // Load sword create sound
    set snd = CreateSound(SWORD_CREATE_SOUND_PATH, false, false, false, 12700, 12700, "")
    call SetSoundVolumeByDistance(snd, SWORD_CREATE_SOUND_PATH_VOL, x, y)
    call StartSound(snd)
   
    // Kill sound (exec starts at zero)
    if (tmx.exec + 5. < MaxSwordCount[tmx.lvl]) then
        // Sword creation delay times 2^2
        // This is called n_swords - 4 times
        call KillSoundTimed(snd, (SWORD_CREATION_DELAY*4.)-0.02)
    else
        // Last 4 loops do just normal sound kill
        call KillSoundWhenDone(snd)
    endif
    set snd = null
   
    // Exec counter
    set tmx.exec = tmx.exec + 1.
endfunction

///////////////////////////////////////////////////////////////////////
//                  *This is main action of the spell*               //
///////////////////////////////////////////////////////////////////////
private function DarkTorture_Action takes nothing returns nothing
    // Load all main locals
    local unit u = GetTriggerUnit()
    local real ux = GetUnitX(u)
    local real uy = GetUnitY(u)
    local location l = GetSpellTargetLoc()
    local real x = GetLocationX(l)
    local real y = GetLocationY(l)
    local integer lvl = GetUnitAbilityLevel(u, DARK_TORTURE_RAWCODE)
    local real floorz = 0.
    local triggerx tx = NULL
    local timerx tmx = NULL
   
    // This should never be executed
    if (lvl > Levels) then
        call BJDebugMsg("|cffff0000The spell Dark Torture canot be executed because spell level is greater then defined!|r")
        call DestroyTrigger(GetTriggeringTrigger())
        return
    endif
   
    // Get floorz
    call MoveLocation(LOC_Z, ux, uy)
    set floorz = GetLocationZ(LOC_Z)
   
    // Start move timer and load spell trigger and other objects
    if (DTTimer == null) then
        set DTTimer = CreateTimer()
        call TimerStart(DTTimer, TIMER_MIN_DELAY, true, null)
    endif
   
    // Trigger counter
    set TGCount = TGCount + 1
   
    // This is main timer executable triggerx
    // -------------------------------------------------------------------------------
    // *** Here we create new trigger, store this func as triggeraction, load two groups
    // *** store damage and boolean did spell started
    // *** Group 1 is swords group and Group 2 is fade group
    set tx = triggerx.create(function DarkTortureMovement, SwordsMaxDamage[lvl])
    call TriggerRegisterTimerExpireEvent(tx.t, DTTimer)
   
    // Here we will load swords, using timer as it is precious.
    // Dont worry timer of 0.1 seconds or more exec per second do not cause any lag
    // Even if there are 20 timer at same time.
    set tmx = timerx.create(ux, uy, Atan2(y-uy, x-ux), lvl, GetPlayerId(GetOwningPlayer(u)), floorz, tx)
    call TimerStart(tmx.t, SWORD_CREATION_DELAY, true, function CreateSwords)
   
    // Null locals
    call RemoveLocation(l)
    set l = null
    set u = null
endfunction

//===========================================================================
// Filter for picking push units
private function FuncGroupFilter takes nothing returns boolean
    local unit f = GetFilterUnit()
    local boolean b = false
    set b = (not IsUnitType(f, UNIT_TYPE_FLYING) and not IsUnitType(f, UNIT_TYPE_STRUCTURE) and not IsUnitType(f, UNIT_TYPE_DEAD) and not IsUnitType(f, UNIT_TYPE_MECHANICAL) and not (UnitIsPushed[ArrayId(f)]) and IsUnitEnemy(f, DD_p[TempId]))
    set f = null
    return (b)
endfunction

private function DarkTorture_Main takes nothing returns nothing
    // Make this trigger private
    local trigger t = CreateTrigger()
    local integer i = 0
   
    // First setup spell
    call DarkTorture_Setup()
   
    loop
    exitwhen (i >= Levels)
        if (MaxSwordCount[i] > 16) then
            // This spell will end here
            call DestroyTrigger(t)
            return
        endif
        set i = i + 1
    endloop
   
    // Register spell cast event
    // Add condition and action
    call TriggerRegisterAnyUnitEvent(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
    call TriggerAddCondition(t, Condition(function DarkTorture_Condition))
    call TriggerAddAction(t, function DarkTorture_Action)
   
    // Preload files
    call Preload(SWORD_EFFECT_MODEL)
    call Preload(BLOOD_EFFECT)
    call Preload(DUST_EFFECT)
    call Preload(WATER_EFFECT)
    //call Preload(SWORD_SOUND_START_PATH)
    //call Preload(SWORD_CREATE_SOUND_PATH)
    //call Preload(SWORD_HIT_PATH)
    //call Preload(SWORD_DISAPPERE_PATH)
    call GenericSoundDD(SWORD_SOUND_START_PATH, 0., 0., 0., 1.)
    call GenericSoundDD(SWORD_CREATE_SOUND_PATH, 0., 0., 0., 1.)
    call GenericSoundDD(SWORD_HIT_PATH, 0., 0., 0., 1.)
    call GenericSoundDD(SWORD_DISAPPERE_PATH, 0., 0., 0., 1.)
    call Preload("war3mapImported\\Frostmourne.mdx")
    call Preload("Objects\\SpawnQModels\\Human\\HumanBlood\\HeroBloodElfBlood.mdx")
   
    call PreloadStart()
    // Group filter define
    set GroupFilter = Filter(function FuncGroupFilter)
   
   
    // Null "init" locals
    set t = null
endfunction

endlibrary
 
//TESH.scrollpos=253
//TESH.alwaysfold=0
//**************************************************************************************
//                            Spell: Frost Eruption
//                            Author: Dark Dragon
//                            Date: 17 February 2009
//
//                    Other: Spell made for fun testing vJass
//
//
//                              Installation:
//
// - 1. Make sure you have open the JassNewGen Pack editor not normal one and make sure you have last version
// - 2. Go to Import Manager (F12) and extract icons: BTNCRFrostShock.blp and its DISBTN version
//      sounds: fe_start.mp3, fe_explode1.mp3 and fe_explode2.mp3
//      QModels: FrozenOrb.mdx, Frost2.mdx, FreezingRing.mdx, BlizzardEruption.mdx and (dummy.mdx -> if not from before)
// - 3. Import all of this to your map and set there path to as you can see here (in my map)
// - 4. Go to Object Manager (F6) and copy dummy unit {Dummy (DD Universal Pack)}
//      Air Freeze (Dummy) ability, Frost Eruption buff and
//      main ability Frost Eruption. When you are pasting them to your map make sure you
//      type the following rawcodes:
//      Dummy:                  'dumy'
//      Frost Eruption:         'Feru'
//      Air Freeze (Dummy):     'Afre'
//      Frost Eruption {Buff}:  'Bfer'
// - 5. If you want different raw codes edit the below as well:
// - 6. Edit data below to your own will and enjoy the spell:
// - 7. And of course copy this trigger and DDUniversal Pack to your map.
//
//**************************************************************************************

// Frost Eruption main library
library FrostEruption initializer FrostEruption_Main requires DDUniversalPack

//**************************************
//  --- Load spell constant globals ---
//**************************************
globals
    // The raw code of the spell Frost Eruption
    // Default: 'Feru'
    private constant integer FE_RAWCODE = 'Feru'
    // The raw code of dummy (change it in DDUniversal Pack trigger)
    // Default: 'dumy'
    private constant integer DUM_RAWCODE = DD_DUMMY_CODE
    // With this ability air units are slowed
    // Default: 'Afre'
    private constant integer AIR_FREEZE_RAWCODE = 'Afre'
    // This is orb QModel path
    // Default: "Spells\\FrostEruption\\FrozenOrb.mdl"
    private constant string ORB_QModEL_PATH = "Spells\\FrostEruption\\FrozenOrb.mdx"
    // Main frost eruption effect
    // Default: "Spells\\FrostEruption\\BlizzardEruption.mdl"
    private constant string ORB_ERUPTION_EFFECT = "Spells\\FrostEruption\\BlizzardEruption.mdx"
    // Frost Eruptions extra explosion effect
    // Default: "Spells\\FrostEruption\\FreezingRing.mdl"
    private constant string ORB_EXPLOSION_EFFECT = "Spells\\FrostEruption\\FreezingRing.mdx"
    // Ground units freezed QModel path
    // Default: "Abilities\\Spells\\Undead\\FreezingBreath\\FreezingBreathTargetArt.mdl"
    private constant string FREEZE_EFFECT = "Abilities\\Spells\\Undead\\FreezingBreath\\FreezingBreathTargetArt.mdx"
    // This is orb's trail effect
    // Default: "Spells\\FrostEruption\\Frost2.mdx"
    private constant string TRAIL_QModEL_PATH = "Spells\\FrostEruption\\Frost2.mdx"
    // Sound file on load (on spell cast)
    // Default: "Custom\\Spells\\Frost Eruption\\fe_start.mp3"
    private constant string SPELL_START_SOUND = "Custom\\Spells\\Frost Eruption\\fe_start.mp3"
    private constant real SPELL_START_SOUND_VOL = 75.
    // Sound file's on explosion
    // Default: "Custom\\Spells\\Frost Eruption\\fe_explode1.mp3"    
    private constant string SPELL_EXPLODE_SOUND_1 = "Custom\\Spells\\Frost Eruption\\fe_explode1.mp3"
    private constant real SPELL_EXPLODE_SOUND_VOL = 75. // Both 1 and 2 sounds volume
    // Default: "Custom\\Spells\\Frost Eruption\\fe_explode2.mp3"
    private constant string SPELL_EXPLODE_SOUND_2 = "Custom\\Spells\\Frost Eruption\\fe_explode2.mp3"
    // This is scale / size of main orb
    // Default: 1.32
    private constant real ORB_SCALE = 1.32
    // Terrain deformation depth
    // Default: 128.
    private constant real EXPLOSION_DEAPTH = 128.
    // Terrain deformatiob timeout
    // Default: 0.35
    private constant real TERRAIN_DEFORMATION_DURATION = 0.35
    // Cameras power magnitude
    // Default: 2.25
    private constant real CAMERA_MAGNITUDE = 2.25
    // Camera noise duration
    // Default: 1.85
    private constant real CAMERA_NOISE_DURATION = 1.85
    // How much time will orb need until reaching target point
    // Default: 1.5
    private constant real ORB_DURATION = 1.5
   
    // Do not edit this variables here edit then below
    private integer Level = 0
    private real array FE_Radius
    private real array FE_Damage
    private real array FE_MaxDamage
    private real array FE_Duration
endglobals

// Edit this to match your level data
private function SetupFrostEruption takes nothing returns nothing
    // Level data:
   
    // Max spell level:
    // Default: 3
    set Level = 3
   
    // Spells damage:
    // Default: 130 / 215 / 290
    set FE_Damage[1] = 130.
    set FE_Damage[2] = 215.
    set FE_Damage[3] = 290.
   
    // Spells radius:
    // Default: 500 / 515 / 540
    set FE_Radius[1] = 500.
    set FE_Radius[2] = 515.
    set FE_Radius[3] = 540.
   
    // Spells max damage:
    // Default: 700 / 1300 / 1950
    set FE_MaxDamage[1] = 700.
    set FE_MaxDamage[2] = 1300.
    set FE_MaxDamage[3] = 1950.
   
    // Spells ground units freeze duration:
    // Default: 4 / 4.5 / 5.25
    set FE_Duration[1] = 4.
    set FE_Duration[2] = 4.5
    set FE_Duration[3] = 5.25
endfunction

// ================================================================================
// ******                                                                   ******
//              Do not edit below if you don't know jass
// ******                                                                   ******
// ================================================================================

//***********************************
// <<< Uneditable spells globals >>>
//***********************************
globals
    // --- Constants ---
    private constant string ATTACH_POINT = "origin"
    private constant real TIMER_MOVE_DELAY = 0.025
    private constant real TRAIL_DISTANCE = 80.
   
    private timer Timer = null
    private integer array Triggerx[64]
    private integer ExecId = 0
    private boolean array UnitFrozen[8191]
    private effect array FreezeEffect[8191]
endglobals

//////////////////////////////////////////////////////////////////////////////
//                         Spells Main Functions                            //
//////////////////////////////////////////////////////////////////////////////

// Creates Dummy
private function CreateDummy takes player p, real x, real y returns unit
    local unit dummy = CreateUnit(p, DUM_RAWCODE, x, y, 0.)
    call UnitAddAbility(dummy, 'Aloc')
    return dummy
endfunction

// Calculates x^2
private constant function Pow2 takes real x returns real
    return (x*x)
endfunction

// Plays sound for all players
private function PlayGenericSound takes string file, real max_volume, real x, real y, real max_distance returns nothing
    local integer i = 0
    local sound s = CreateSound(file, false, false, false, 12700, 12700, "")
    local real d
    local real cx
    local real cy
   
    // Set sound volume for players
    loop
    exitwhen (i >= bj_MAX_PLAYERS)
        if (GetLocalPlayer() == i:DD_p) then
            set cx = GetCameraTargetPositionX()
            set cy = GetCameraTargetPositionY()
            set d = SquareRoot(hypot(cx-x, cy-y))
            call SetSoundVolume(s, R2I( (max_volume-(d*(max_volume/max_distance)))*1.27 ))
        endif
        set i = i + 1
    endloop
   
    // Start sound
    call StartSound(s)
    call KillSoundWhenDone(s)
    set s = null
endfunction

// Gives limits to given x number
private constant function RLimit takes real x, real min, real max returns real
    if (x < min) then
        set x = min
    elseif (x > max) then
        set x = max
    endif
    return x
endfunction

// Will create camera noise for x seconds
private function ResetNoise takes nothing returns nothing
    if (ExecId == 0) then
        call CameraSetTargetNoise(0., 0.)
        call CameraSetSourceNoise(0., 0.)
    endif
    call PauseTimer(GetExpiredTimer())
    call DestroyTimer(GetExpiredTimer())
endfunction

private function CameraSetEQNoise takes real magnitude, real timeout returns nothing
    local real richter = RLimit(magnitude, 2., 5.)
    call CameraSetTargetNoiseEx(magnitude*2., magnitude*Pow(10., richter), true)
    call CameraSetSourceNoiseEx(magnitude*2., magnitude*Pow(10., richter), true)
    call TimerStart(CreateTimer(), timeout, false, function ResetNoise)
endfunction

// Freeze ground unit
private function FreezeUnit takes unit whichUnit, boolean flag returns nothing
    if (flag) then
        debug call SetUnitMoveSpeed(whichUnit, 0.)
        call SetUnitVertexColor(whichUnit, 100, 100, 255, 255)
        call PauseUnit(whichUnit, true)
        set FreezeEffect[ArrayId(whichUnit)] = AddSpecialEffectTarget(FREEZE_EFFECT, whichUnit, ATTACH_POINT)
        set ArrayId(whichUnit):UnitFrozen = TRUE
    elseif (ArrayId(whichUnit):UnitFrozen) then
        debug call SetUnitMoveSpeed(whichUnit, GetUnitDefaultMoveSpeed(whichUnit))
        call SetUnitVertexColor(whichUnit, 255, 255, 255, 255)
        call PauseUnit(whichUnit, false)
        call DestroyEffect(FreezeEffect[ArrayId(whichUnit)])
        set FreezeEffect[ArrayId(whichUnit)] = null
        set ArrayId(whichUnit):UnitFrozen = FALSE
        if (GetPlayerController(GetOwningPlayer(whichUnit)) != MAP_CONTROL_COMPUTER) then
            call IssueImmediateOrder(whichUnit, "stop")
        endif
    endif
endfunction

//********************************************************************
//               Main Spell Damage Action Functions
//********************************************************************

//=======================================================================
// Damage data struct
private struct damagedata
    public player p
    public groupex g
    public real dmg
    public integer lvl
    public unit dmy
    public real x
    public real y
    public unit caster
   
    static method create takes player owner, integer level, unit dmy, unit caster returns damagedata
        local damagedata this = damagedata.allocate()
       
        set this.p = owner
        set this.lvl = level
        set this.dmy = dmy
        set this.caster = caster
        set this.g = CreateGroupEx()
       
        return (this)
    endmethod
   
    method onDestroy takes nothing returns nothing
        call RemoveUnit(this.dmy)
        call DestroyGroupEx(this.g)
        set this.p = null
        set this.g = 0
        set this.dmy = null
        set this.caster = null
    endmethod
endstruct

globals
    private damagedata TempDamageData = 0
endglobals
//=======================================================================

// All units unfreeze
private function UnfreezeUnitsEnum takes nothing returns nothing
    call FreezeUnit(GetEnumUnitEx(), false)
endfunction

// Timer function unfreeze units
private function UnfreezeUnits takes nothing returns nothing
    local timer t = GetExpiredTimer()
    local damagedata dd = DDGetValue(t)
   
    call ForGroupEx(dd.g, function UnfreezeUnitsEnum)
   
    call dd.destroy()
    call PauseTimer(t)
    call DestroyTimer(t)
    set t = null
endfunction

// Main damage filter
private function FE_DamageFilter takes nothing returns boolean
    return IsUnitEnemy(GetFilterUnit(), TempDamageData.p) and not IsUnitType(GetFilterUnit(), UNIT_TYPE_STRUCTURE) and not IsUnitType(GetFilterUnit(), UNIT_TYPE_MECHANICAL) and GetWidgetLife(GetFilterUnit()) > 0.405 and not IsUnitType(GetFilterUnit(), UNIT_TYPE_MAGIC_IMMUNE)
endfunction

// Main damage unit function
private function DamageEnum takes nothing returns nothing
    // Locals
    local unit u = GetEnumUnitEx()
    local unit d
    local damagedata dd = TempDamageData
   
    // Deal damage
    call UnitDamageTarget(dd.dmy, u, dd.dmg, true, false, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_COLD, WEAPON_TYPE_WHOKNOWS)
   
    // Flying units slowed
    if (IsUnitType(u, UNIT_TYPE_FLYING) == true) then
        call GroupExRemoveUnit(dd.g, u)
        set d = CreateDummy(dd.p, GetUnitX(u), GetUnitY(u))
        call UnitAddAbility(d, AIR_FREEZE_RAWCODE)
        call SetUnitAbilityLevel(d, AIR_FREEZE_RAWCODE, dd.lvl)
        call IssueTargetOrder(d, "frostnova", u)
        call UnitApplyTimedLife(d, 'BTLF', 1.)
        if (GetPlayerController(GetOwningPlayer(u)) != MAP_CONTROL_USER and not IsUnitType(u, UNIT_TYPE_PEON)) then
            call IssuePointOrder(u, "attack", GetUnitX(dd.caster), GetUnitY(dd.caster))
            debug call BJDebugMsg("exec")
        endif
        set d = null
    else
        if ( GetWidgetLife(u) > 0.405 ) then
            call FreezeUnit(u, true)
        else
            call GroupExRemoveUnit(dd.g, u)
        endif
    endif
    set u = null
endfunction

// Damages any enemy unit
private function DamageGroupRadius takes real x, real y returns nothing
    // Load locals
    local boolexpr bx = Filter(function FE_DamageFilter)
    local damagedata dd = TempDamageData
    local real n
    local timer t = CreateTimer()
   
    // Vars set
    set dd.dmg = dd.lvl:FE_Damage
   
    // Insert units
    call GroupExEnumUnitsInRange(dd.g, x, y, dd.lvl:FE_Radius, bx)
   
    // Damage setup
    set n = I2R(CountUnitsInGroupEx(dd.g))
    if (dd.dmg*n > dd.lvl:FE_MaxDamage) then
        set dd.dmg = dd.lvl:FE_MaxDamage/n
    endif
   
    // Do action for all units
    call ForGroupEx(dd.g, function DamageEnum)
   
    // Timer load and unfreeze units after...
    set TempDamageData = damagedata(0)
    call DDStoreValue(t, integer(dd))
    call TimerStart(t, dd.lvl:FE_Duration, false, function UnfreezeUnits)
   
    // Destroy objects (clear leaks and nulls)
    call DestroyBoolExpr(bx)
    set bx = null
    set t = null
endfunction

// Damage group after time
private function DmgGrpRad takes nothing returns nothing
    local timer t = GetExpiredTimer()
    set TempDamageData = DDGetValue(t)
    call DamageGroupRadius(TempDamageData.x, TempDamageData.y)
    call DDFlushValue(t)
    call PauseTimer(t)
    call DestroyTimer(t)
    set t = null
endfunction

private function DamageGroupRadiusTimed takes real x, real y, real time returns nothing
    local timer t = CreateTimer()
    set TempDamageData.x = x
    set TempDamageData.y = y
    call DDStoreValue(t, integer(TempDamageData))
    call TimerStart(t, time, false, function DmgGrpRad)
    set t = null
endfunction

//===========================================================
//===                                                    ===
//                    Struct Triggerx
//===                                                    ===
//===========================================================
globals
    private integer array StoredTriggerx[8191]
endglobals

private struct triggerx
    public trigger tg
    private triggeraction ta
    private integer val
   
    // Constructor
    static method create takes code cond, code act returns triggerx
        local triggerx this = triggerx.allocate()
       
        set this.val = 0
        set this.tg = CreateTrigger()
        if (cond != null) then
            call TriggerAddCondition(this.tg, Condition(cond))
        endif
       
        if (act != null) then
            set this.ta = TriggerAddAction(this.tg, act)
        endif
       
        set QMod(GetHandleId(this.tg), JASS_MAX_ARRAY_SIZE):StoredTriggerx = (this)
        return (this)
    endmethod
   
    // Sets new custom value
    public method SetValue takes integer val returns nothing
        set this.val = val
    endmethod
   
    // Gets custom value
    public method GetValue takes nothing returns integer
        return (this.val)
    endmethod
   
    // Destructor
    method onDestroy takes nothing returns nothing
        if (this.ta != null) then
            call TriggerRemoveAction(this.tg, this.ta)
        endif
        set QMod(GetHandleId(this.tg), JASS_MAX_ARRAY_SIZE):StoredTriggerx = 0
        call DestroyTrigger(this.tg)
        set this.ta = null
        set this.tg = null
    endmethod
endstruct

// Create new triggerx
function CreateTriggerx takes code cond, code act returns triggerx
    return triggerx.create(cond, act)
endfunction

// Register timer event
function TriggerxRegisterTimerEvent takes triggerx whichTriggerx returns event
    return TriggerRegisterTimerExpireEvent(whichTriggerx.tg, Timer)
endfunction

// Destroy triggerx
function DestroyTriggerx takes triggerx whichTriggerx returns nothing
    call whichTriggerx.destroy()
endfunction

// New Value
function SetTriggerxValue takes triggerx tx, integer newValue returns nothing
    call tx.SetValue(newValue)
endfunction

// Get Value
function GetTriggerxValue takes triggerx tx returns integer
    return tx.GetValue()
endfunction

// Triggering triggerx
private function GetTriggeringTriggerx takes nothing returns triggerx
    return QMod(GetHandleId(GetTriggeringTrigger()), JASS_MAX_ARRAY_SIZE):StoredTriggerx
endfunction

//===========================================================
//===                                                    ===
//                    Struct Parabola
//===                                                    ===
//===========================================================
private struct parabola
    private real a
    private real c
    private real md
    // b is zero
   
    // Loads new parabola
    static method create takes real max_distance, real max_height returns parabola
        local parabola this = parabola.allocate()
       
        set this.a = -max_height/Pow2(0.5*max_distance)
        set this.c = max_height
        set this.md = max_distance
       
        return (this)
    endmethod
   
    // Calculates parabolic movement
    private method Parabola takes real x returns real
        return this.a*Pow2(x) + this.c // b is zero
    endmethod
   
    // Returns parabola height at given distance
    public method Height takes real dist returns real
        return this.Parabola(RLimit(dist - (this.md/2.), -this.md/2., this.md/2.))
    endmethod
endstruct


//===========================================================
//===                                                    ===
//                      Struct Orb
//===                                                    ===
//===========================================================
private struct orb
    private unit o       // Main unit Orb
    private effect e     // Main effect orb
    private unit tr      // Trail dummy unit
    private effect te    // Trail dummy effect
    private unit caster  // Casting unit
    private real x       // Orbs x position
    private real y       // Orbs y position
    private real z       // Orbs z position
    private real vel     // Orbs velocity
    private real acc     // Orbs acceleration
    private real tx      // Target point x
    private real ty      // Target point y
    private real rad     // Target point radians
    private real dx      // Direction x
    private real dy      // Direction y
    private real fz      // Floor Z
    private real dist    // Distance
    private integer lvl  // Spell level
    private parabola p   // Our parabola movement
   
   
    // Constructor method
    static method create takes real x, real y, location tloc returns orb
        local orb this = orb.allocate()
       
        set this.tx = GetLocationX(tloc)
        set this.ty = GetLocationY(tloc)
        set this.rad = Atan2(this.ty-y, this.tx-x)
        set this.o = CreateUnit(GetOwningPlayer(GetTriggerUnit()), DUM_RAWCODE, x, y, this.rad*bj_RADTODEG)
        set this.e = AddSpecialEffectTarget(ORB_QModEL_PATH, this.o, ATTACH_POINT)
        set this.x = x
        set this.y = y
        set this.z = 0.
        set this.dx = Cos(this.rad)
        set this.dy = Sin(this.rad)
        set this.fz = DD_GetFloorZ(this.x, this.y)
        set this.lvl = GetUnitAbilityLevel(GetTriggerUnit(), GetSpellAbilityId())
        set this.tr = CreateUnit(GetOwningPlayer(GetTriggerUnit()), DUM_RAWCODE, x-TRAIL_DISTANCE*this.dx, y-TRAIL_DISTANCE*this.dy, this.rad*bj_RADTODEG)
        set this.te = AddSpecialEffectTarget(TRAIL_QModEL_PATH, this.tr, ATTACH_POINT)
        set this.caster = GetTriggerUnit()
       
        set this.dist = SquareRoot(hypot(this.tx-this.x, this.ty-this.y)) + 1. // to make sure we dont divide by zero
        set this.acc = this.dist/Pow2(ORB_DURATION/2.)
        set this.vel = this.acc*ORB_DURATION*0.5
        set this.p = parabola.create(this.dist, (4.25/6.5)*this.dist)
       
        debug call BJDebugMsg("acc="+R2S(this.acc))
        debug call BJDebugMsg("vel="+R2S(this.vel))
       
        call SetUnitScale(this.o, ORB_SCALE, ORB_SCALE, ORB_SCALE)
        call UnitAddAbility(this.o, 'Aloc')
        call UnitAddAbility(this.tr, 'Aloc')
       
        call RemoveLocation(tloc)
        return (this)
    endmethod
   
    // Moves orb at given point
    private method Move takes real x, real y, real z returns nothing
        local real fz = DD_GetFloorZ(x, y)
       
        call SetUnitX(this.o, x)
        call SetUnitY(this.o, y)
        call SetUnitFlyHeight(this.o, z-fz+this.fz, 0.)
       
        set this.x = x
        set this.y = y
       
        set x = x - TRAIL_DISTANCE * this.dx
        set y = y - TRAIL_DISTANCE * this.dy
       
        call SetUnitX(this.tr, x)
        call SetUnitY(this.tr, y)
        call SetUnitFlyHeight(this.tr, this.p.Height(this.dist+TRAIL_DISTANCE)-DD_GetFloorZ(x, y)+this.fz, 0.)
        set this.z = z-fz+this.fz
    endmethod
   
    // Calculated movement
    private method MoveEx takes real offset_dist returns nothing
        set this.dist = this.dist - offset_dist
        call this.Move(this.x+offset_dist*this.dx, this.y+offset_dist*this.dy, this.p.Height(this.dist))
    endmethod
   
    // Returns velocity converted to single distance movement
    private method Velocity2Distance takes nothing returns real
        set this.vel = this.vel - (this.acc*TIMER_MOVE_DELAY)
        return rabs(this.vel*TIMER_MOVE_DELAY)
    endmethod
   
    // Offset movement
    public method OffsetMove takes nothing returns nothing
        call this.MoveEx(this.Velocity2Distance())
    endmethod
   
    // Orb explosion
    public method Explode takes nothing returns nothing
        local unit u = CreateDummy(this.getowner, this.tx, this.ty)
        local string array file
        call SetUnitScale(u, 2.25, 2.25, 1.75)
        call UnitApplyTimedLife(u, 'BTLF', 3.)
       
        // Load explosion effects
        call DestroyEffectTimed(AddSpecialEffectTarget(ORB_ERUPTION_EFFECT, u, ATTACH_POINT), 2.5)
        call DestroyEffect(AddSpecialEffectTarget(ORB_EXPLOSION_EFFECT, u, ATTACH_POINT))
       
        // Terrain & camera blow
        call TerrainDeformCrater(this.tx, this.ty, this.lvl:FE_Radius, EXPLOSION_DEAPTH, R2I(TERRAIN_DEFORMATION_DURATION*1000.), false)
        call CameraSetEQNoise(CAMERA_MAGNITUDE, CAMERA_NOISE_DURATION)
       
        // Play explosion sound
        set file[0] = SPELL_EXPLODE_SOUND_1
        set file[1] = SPELL_EXPLODE_SOUND_2
        call PlayGenericSound(GetRandomInt(0, 1):file, SPELL_EXPLODE_SOUND_VOL, this.tx, this.ty, 3000.)
       
        // Deal damage
        set TempDamageData = damagedata.create(this.getowner, this.lvl, CreateDummy(this.getowner, this.tx, this.ty), this.caster)
        call DamageGroupRadiusTimed(this.tx, this.ty, 0.2)
       
        // Destroy this orb
        call this.destroy()
        set u = null
    endmethod
   
    //====================
    // *** Operators ***
    //====================
   
    // Checks did orb land on ground
    public method operator landed takes nothing returns boolean
        return (this.dist <= 0.) or (this.z <= 0.)
    endmethod
   
    // Returns orb owner
    public method operator getowner takes nothing returns player
        return GetOwningPlayer(this.o)
    endmethod
   
    // Destructor method
    method onDestroy takes nothing returns nothing
        call DestroyEffect(this.e)
        call UnitApplyTimedLife(this.o, 'BTLF', 1.25)
        call DestroyEffect(this.te)
        call UnitApplyTimedLife(this.tr, 'BTLF', 1.25)
        call this.p.destroy()
       
        set this.e = null
        set this.o = null
        set this.tr = null
        set this.te = null
        set this.caster = null
    endmethod
endstruct

//********************************************************************************
// ------                                                                  ------
//                            Spell's Main Code
// ------                                                                  ------
//********************************************************************************

//===========================================================================
// Spell's Main Condition
private constant function FrostEruptionCondition takes nothing returns boolean
    return (GetSpellAbilityId() == FE_RAWCODE)
endfunction

// Timer Periodic Action
private function FrostEruptionPeriodic takes nothing returns nothing
    // ::: Load Locals :::
    local triggerx tx = GetTriggeringTriggerx()
    local orb o = orb( GetTriggerxValue(tx) )
   
    // Orb movement
    call o.OffsetMove()
   
    // Reached ground?
    if (o.landed) then
        // Explode
        call o.Explode()
       
        // End single cast
        set ExecId = ExecId - 1
        if (ExecId == 0) then
            call PauseTimer(Timer)
            call DestroyTimer(Timer)
            set Timer = null
        endif
       
        // Blow triggerx
        call DestroyTriggerx(tx)
    endif
endfunction

//===========================================================================
// Spell's Main Action
private function FrostEruptionAction takes nothing returns nothing
    // *** Load locals ***
    local unit u = GetTriggerUnit()
    local integer id = ExecId
    local triggerx Triggerx
    local orb o = orb.create(GetUnitX(u), GetUnitY(u), GetSpellTargetLoc())
   
    // Never execute
    if (GetUnitAbilityLevel(u, FE_RAWCODE) > Level) then
        call BJDebugMsg("|cffff0000Spell: Frost Eruption|r - Can't cast spell. Spell level greater than defined!")
        call DestroyTrigger(GetTriggeringTrigger())
        return
    endif
   
    // Play sound
    call PlayGenericSound(SPELL_START_SOUND, SPELL_START_SOUND_VOL, GetUnitX(u), GetUnitY(u), 3000.)
   
    // New timer load if current does not exist
    if (Timer == null) then
        set Timer = CreateTimer()
        call TimerStart(Timer, TIMER_MOVE_DELAY, true, null)
    endif
   
    // Load triggerx
    set Triggerx = CreateTriggerx(null, function FrostEruptionPeriodic)
    call TriggerxRegisterTimerEvent(Triggerx)
    call SetTriggerxValue(Triggerx, integer(o))
   
    // Next exec count id
    set ExecId = id + 1
   
    // Null locals
    set u = null
endfunction

// Extra trigger action
private function UnfreezeUnitsAction takes nothing returns nothing
    local unit u = GetTriggerUnit()
    if (QMod(GetHandleId(u), JASS_MAX_ARRAY_SIZE):UnitFrozen) then
        call FreezeUnit(u, false)
    endif
    set u = null
endfunction

//====================================================================================
// Main Setup Function For FE
private function FrostEruption_Main takes nothing returns nothing
    // Load locals...
    local trigger tg = CreateTrigger()
    local trigger tgx = CreateTrigger()
    local integer i = 0
   
    // Setup user spell
    call SetupFrostEruption()
   
    // Register trigger events
    call TriggerRegisterAnyUnitEvent(tg, EVENT_PLAYER_UNIT_SPELL_EFFECT)
    call TriggerAddCondition(tg, Condition(function FrostEruptionCondition))
    call TriggerAddAction(tg, function FrostEruptionAction)
   
    call TriggerRegisterAnyUnitEvent(tgx, EVENT_PLAYER_UNIT_DEATH)
    call TriggerAddAction(tgx, function UnfreezeUnitsAction)
   
    // Preload all files
    call Preload(ORB_QModEL_PATH)
    call Preload(ORB_ERUPTION_EFFECT)
    call Preload(ORB_EXPLOSION_EFFECT)
    call Preload(FREEZE_EFFECT)
    call Preload(TRAIL_QModEL_PATH)
    //call Preload(SPELL_START_SOUND)
    //call Preload(SPELL_EXPLODE_SOUND_1)
    //call Preload(SPELL_EXPLODE_SOUND_2)
    call GenericSoundDD(SPELL_START_SOUND, 0., 0., 0., 1.)
    call GenericSoundDD(SPELL_EXPLODE_SOUND_1, 0., 0., 0., 1.)
    call GenericSoundDD(SPELL_EXPLODE_SOUND_2, 0., 0., 0., 1.)
   
    call PreloadStart()
    // Null locals
    set tg = null
    set tgx = null
endfunction

endlibrary

 
//TESH.scrollpos=1450
//TESH.alwaysfold=0
//**************************************************************************************
//                            Spell: Shadow Crossing
//                            Author: Dark Dragon
//                            Date: 19 April 2009
//
//                    Other: Spell made using vJass and coding every part of game in it
//
//
//                              Installation:
//
// - 1. Make sure you opend Jass NewGen as well that you have at least (0.9.G.1) version of jasshelper
// - 2. Go to Import Manager (F12) and extract icons: BTNNecromancy.blp and its DISBTN version
//      models: SkullBuff.mdx, DarkNova.mdx, DarkPillar.mdx, DeathMark.MDX and (dummy.mdx -> if not from before)
// - 3. Import all of this to your map and set there path to as you can see here (in my map)
// - 4. Go to Object Manager (F6) and copy dummy unit "Dummy (DD Universal Pack)" and
//      main ability Shadow Crossing. When you are pasting them to your map make sure you
//      type the following rawcodes:
//      Dummy:                  'dumy'
//      Shadow Crossing:        'scrs'
// - 5. If you want different raw codes you must edit them below as well:
// - 6. Edit data below to your own will and enjoy the spell:
// - 7. And of course copy "this" trigger and "DDUniversal Pack" to your map.
//
//**************************************************************************************


// ------    Shadow Crossing Library    ------
library ShadowCrossing initializer Init_ShadowCrossing requires DDUniversalPack

    // #############################################################################
    // * Spell Setup: Shadow Crossing
    //
    // * Edit following values to match your map and your stile just simple
    // * read comments for each part of code and then change values to your
    // * wish and so until you reach part of code which tells you do not edit
    // * below if you dont know jass
    // > Enjoy!
    // #############################################################################

    globals
        // This is the rawcode of shadow crossing ability
        // this is a must change if you did not set it to scrs while pasting ability
        // Default: 'scrs'
        private     constant    integer     SHADOW_CROSSING                 =   'scrs'
       
        // This is the path to shadow nova explosion
        // Default: "Spells\\ShadowCrossing\\DarkNova.mdl"
        private     constant    string      SHADOW_NOVA                     = "Spells\\ShadowCrossing\\DarkNova.mdx"
       
        // This is the path to shadow pillar explosion
        // Default: "Spells\\ShadowCrossing\\DarkPillar.mdl"
        private     constant    string      SHADOW_PILLAR                   = "Spells\\ShadowCrossing\\DarkPillar.mdx"
       
        // This is the path to shadow buff
        // Default: "Spells\\ShadowCrossing\\SkullBuff.mdl"
        private     constant    string      SHADOW_BUFF                     = "Spells\\ShadowCrossing\\SkullBuff.mdx"
       
        // This is the path to shadow mark
        // Default: "Spells\\ShadowCrossing\\DeathMark.MDL"
        private     constant    string      SHADOW_MARK                     = "Spells\\ShadowCrossing\\DeathMark.MDX"
       
        // This are cast effects which are created around caster
        // Default: "Abilities\\Spells\\Undead\\DarkRitual\\DarkRitualTarget.mdl"
        private     constant    string      SHADOW_RITUAL                   = "Abilities\\Spells\\Undead\\DarkRitual\\DarkRitualTarget.mdx"
       
        // This is the path to shadow missile model
        // Default: "Abilities\\Weapons\\AvengerMissile\\AvengerMissile.mdl"
        private     constant    string      SHADOW_MISSILE                  = "Abilities\\Weapons\\AvengerMissile\\AvengerMissile.mdx"
       
        // This is model path to effect which is created when missile dies
        // Default: "Abilities\\Spells\\Undead\\AnimateDead\\AnimateDeadTarget.mdl"
        private     constant    string      MISSILE_DEATH                   = "Abilities\\Spells\\Undead\\AnimateDead\\AnimateDeadTarget.mdx"
       
        // This is effect which is attached to heros when they take difference damage
        // Default: "Abilities\\Spells\\Undead\\DeathandDecay\\DeathandDecayTarget.mdl"
        private     constant    string      SHADOW_DIFFERENCE               = "Abilities\\Spells\\Undead\\DeathandDecay\\DeathandDecayTarget.mdx"
       
        // This is path to clones raise effect
        // Default: "Abilities\\Spells\\Undead\\DeathCoil\\DeathCoilSpecialArt.mdl"
        private     constant    string      CLONE_RAISE                     = "Abilities\\Spells\\Undead\\DeathCoil\\DeathCoilSpecialArt.mdx"
       
        // This is the effect which is loaded when clone avoids damage
        // Default: "Abilities\\Spells\\Items\\SpellShieldAmulet\\SpellShieldCaster.mdl"
        private     constant    string      CLONE_AVOID                     = "Abilities\\Spells\\Items\\SpellShieldAmulet\\SpellShieldCaster.mdx"
       
        // This is a sound file which is played when spell is casted
        // Default: "Buildings\\Undead\\SacrificialPit\\SacrificialPitWhat1.wav"
        private     constant    string      SHADOW_VOICE                    = "Buildings\\Undead\\SacrificialPit\\SacrificialPitWhat1.wav"
        private     constant    real        SHADOW_VOICE_VOL                = 90.
       
        // This sound is played when missiles are fired
        // Default: "Buildings\\Undead\\TempleOfTheDamned\\TempleOfTheDamnedWhat.wav"
        private     constant    string      MISSILES_FIRE                   = "Buildings\\Undead\\TempleOfTheDamned\\TempleOfTheDamnedWhat.wav"
        private     constant    real        MISSILES_FIRE_VOL               = 65.
       
        // This is explosion sound file (its played on pillar eruption)
        // Default: "Sound\\Buildings\\Death\\UndeadBuildingDeathLarge1.wav"
        private     constant    string      SHADOW_BLOW                     = "Sound\\Buildings\\Death\\UndeadBuildingDeathLarge1.wav"
        private     constant    real        SHADOW_BLOW_VOL                 = 90.
       
        // Should terrain deformation be used ?
        // Default: true
        private     constant    boolean     USE_TERRAIN_DEFORMATION         = true
       
        // Terrain deformation depth... has no effect if 'USE_TERRAIN_DEFORMATION' is false
        // Default: 32
        private     constant    real        DEFORM_DEPTH                    = 32.
       
        // Terrain deformation duration... has no effect if 'USE_TERRAIN_DEFORMATION' is false
        // Default: 2.2
        private     constant    real        DEFORM_DURATION                 = 2.2
       
        // *** Use custom AI? custom ai forces ai units not to run on cast ***
        // Default: true
        private     constant    boolean     USE_CUSTOM_AI                   = true
       
       
        // Usually shadow spells like this one do not damage enemy undead units
        // but this one by default damages enemy units, so if you dont want that
        // enemy undead units are damaged set this to 'false'
        // Default: true
        private     constant    boolean     CAN_DAMAGE_UNDEAD               = true
       
        // The number of missiles loaded
        // Default: 8
        private     constant    integer     MISSILES_COUNT                  = 8
       
        // The min height of missile (if min and max are 0)
        // missile movement will be linear
        // Default: 150
        private     constant    real        MISSILE_MIN_HEIGHT              = 150.
       
        // The max height of missile
        // Default: 225
        private     constant    real        MISSILE_MAX_HEIGHT              = 225.
       
        // Missile start height
        // Default: 140
        private     constant    real        MISSILE_START_HEIGHT            = 140.
       
        // Missiles fire rate in seconds. Must be > 0.
        // Default: 0.1
        private     constant    real        MISSILE_FIRE_RATE               = 0.1
       
        // Missiles speed in game coordinates (units movement is ranged from)
        // 270 to 320 on default units. If missiles do not move linear they will
        // travel at faster speed then you think they will
        // Default: 800 - 1000
        private     constant    real        MISSILE_MIN_SPEED               = 800.
        private     constant    real        MISSILE_MAX_SPEED               = 1000.
   
        // --------------------------------------------------------
        // --- Do not edit this level vars here edit them below ---
        // {
            private integer             Levels              = 0
            private real        array   ShadowDamage        [8191]
            private real        array   ShadowAOE           [8191]
            private integer     array   CloneMissChance     [8191]
            private real        array   CloneDamageDealPerc [8191]
            private real        array   CloneDamageTakePerc [8191]
            private real        array   CloneDuration       [8191]
            private real        array   SelfDamage          [8191]
            private real        array   StrengthPerc        [8191]
            private real        array   AgilityPerc         [8191]
            private real        array   IntelligencePerc    [8191]
            private integer     array   MovementSlow        [8191]
            private real        array   SlowDuration        [8191]
           
            private constant integer    DONT_USE_DIFFERENCE     =  0
            private constant integer    USE_DIFFERENCE_CASTER   =  1
            private constant integer    USE_DIFFERENCE_TARGET   = -1
            private          integer    UseDifference           = -2
            private          dd_color   CloneColor              =  0
        // }
    endglobals
   
    // ***************************************************************
    // **   Fell free to edit spells level data to your map needs   **
    // ***************************************************************
    private function ShadowCrossing_Setup takes nothing returns nothing
        // ---------------------------------------------------
        // --- Set this variable to your spells max level ---
        // --> Default: 3
        set Levels = 3
       
        // ---------------------------------------
        // --- This is spells damage per level ---
        // --> Default: 60 / 100 / 160
        set ShadowDamage[1] =  60.
        set ShadowDamage[2] = 100.
        set ShadowDamage[3] = 160.
       
        // ------------------------------------------------
        // --- This is spells area of effect per level ---
        // --> Default: 375 / 425 / 485
        set ShadowAOE[1] = 375.
        set ShadowAOE[2] = 425.
        set ShadowAOE[3] = 485.
       
        // ------------------------------------------
        // --- This is raised clones miss chance ---
        // --> Default: 15 / 20 / 25
        set CloneMissChance[1] = 15
        set CloneMissChance[2] = 20
        set CloneMissChance[3] = 25
       
        // --------------------------------------------------------------
        // --- This is the percentage of how much damage clones deal ---
        // --> Default: 40 / 40 / 40
        set CloneDamageDealPerc[1] = 40.
        set CloneDamageDealPerc[2] = 40.
        set CloneDamageDealPerc[3] = 40.
       
        // --------------------------------------------------------------
        // --- This is the percentage of how much damage clones take ---
        // --> Default: 170 / 170 / 170
        set CloneDamageTakePerc[1] = 170.
        set CloneDamageTakePerc[2] = 170.
        set CloneDamageTakePerc[3] = 170.
       
        // ----------------------------------------------------------
        // --- The duration of clones until they die / disappear ---
        // --> Default: 20 / 20 / 20 (in seconds)
        set CloneDuration[1] = 20.
        set CloneDuration[2] = 20.
        set CloneDuration[3] = 20.
       
        // -------------------------------------------------------
        // --- This is special (its a color of raised clones) ---
        // --- All values are integers from 0 to 255
        // --> Default: 60, 0, 100, 170 arguments(red, green, blue, alpha)
        set CloneColor = CreateColor(60, 0, 100, 170)
       
        // --------------------------------
        // --- The self damage on cast ---
        // --> Default: 200 / 250 / 325
        set SelfDamage[1] = 200.
        set SelfDamage[2] = 250.
        set SelfDamage[3] = 325.
       
        // ------------------------------------------------------------------------------------------
        // --- This is how much slowed units are who where effected by explosion but did not die ---
        // --> Default: 40 / 45 / 50
        set MovementSlow[1] = 40
        set MovementSlow[2] = 45
        set MovementSlow[3] = 50
       
        // ----------------------------------------------------
        // --- This is how long they are slowed in seconds ---
        // --> Default: 3.00 / 3.25 / 3.6
        set SlowDuration[1] = 3.00
        set SlowDuration[2] = 3.25
        set SlowDuration[3] = 3.60
       
        // -------------------------------------------------
        // --- Strength percentage damage between heros ---
        // --> Default: 2.25 / 3.00 / 4.00
        set StrengthPerc[1] = 2.25
        set StrengthPerc[2] = 3.00
        set StrengthPerc[3] = 4.00
       
        // ------------------------------------------------
        // --- Agility percentage damage between heros ---
        // --> Default: 0 / 0 / 0
        set AgilityPerc[1] = 0.
        set AgilityPerc[2] = 0.
        set AgilityPerc[3] = 0.
       
        // -----------------------------------------------------
        // --- Intelligence percentage damage between heros ---
        // --> Default: 0 / 0 / 0
        set IntelligencePerc[1] = 0.
        set IntelligencePerc[2] = 0.
        set IntelligencePerc[3] = 0.
       
        // --- Tells should difference between heros be calculated ---
        // --- DONT_USE_DIFFERENCE tells you that it will use full attributes no difference calculation ---
        // --- USE_DIFFERENCE_CASTER tells that it will substract from caster given / setuped attributes above ---
        // --- USE_DIFFERENCE_TARGET tells that it will substract from target given / setuped attributes above ---
        // *** Example:
        //      Caster -> strength: 28 | agility 17 | intelligence 32
        //      Target -> strength: 20 | agility 12 | intelligence 22
        //
        //      if DONT_USE_DIFFERENCE and spell level 1 damage will be { (28-0) * 2.25 + (17-0) * 0 + (32-0) * 0 }
        //      if USE_DIFFERENCE_CASTER and spell level 1 damage will be { (28-20) * 2.25 + (17-12) * 0 + (32-22) * 0 }
        //      if USE_DIFFERENCE_TARGET and spell level 1 damage will be { (20-28) * 2.25 + (12-17) * 0 + (22-32) * 0 }
        //      *** Note that damage cant be lesser then zero
        //
        // --> Default: USE_DIFFERENCE_CASTER
        set UseDifference = USE_DIFFERENCE_CASTER
    endfunction
   
   
    // =============================================================================================
    // *********************************************************************************************
    //                  -------------------------------------------------------
    //                      --- DO NOT EDIT BELOW IF YOU DONT KNOW JASS ---
    //                  -------------------------------------------------------
    // *********************************************************************************************
    // =============================================================================================

   
   
    // -----------------------------------------------------------------------------
    //                       ---> Other Spells globals <---
    // -----------------------------------------------------------------------------
    globals
        // **********************************************
        //              *** Constants ***
        // **********************************************
        private constant integer    NULL                    = 0         // NULL for struct types
        private constant real       TIMER_DELAY             = 0.025     // Timer precision in movement
        private constant real       SPELL_DELAY             = 0.35      // How much to wait till dealing damage...
        private constant integer    GRAPHIC_TYPE_NOVA       = 0         // Graphic type 1
        private constant integer    GRAPHIC_TYPE_PILLAR     = 1         // Graphic type 2
        private constant string     ATTACH_POINT            = "origin"  // Effects attach points
        private constant string     DIFFERENCE_ATTACH_POINT = "overhead"// Effects attach point for hero difference damage
        private constant real       PI_HALF                 = bj_PI / 2.
        private constant real       PI_4                    = PI_HALF / 2.
        private constant integer    LOC_RAWCODE             = 'Aloc'
        private constant real       SOUNDS_PITCH            = 2.
       
        private          timer      Countdown               = null      // Main movement timer
        private          integer    CastN                   = 0         // Current number of this spell casts
    endglobals
   
    // ---------------------------------------------------------
    // Module Executor: This module is used for n executions to occure
    // while at same time pointing to its base type which was created from
    // Simple performing actions over time by given code pointer 'fptr'
    // ---------------------------------------------------------
    private module executor
        // --- Our executor ---
        private timer exc
        private boolean act
        private integer cnt
       
        // *** Ptr at object ***
        private static thistype array ptrAt[8191]
       
        // *** Activates executor ***
        public method ActiveExecutor takes code fptr, boolean permanent, real timeout returns boolean
            if (this.act) then
                return false
            endif
           
            set this.exc = CreateTimer()
            call TimerStart(this.exc, timeout, permanent, fptr)
            set thistype.ptrAt[ArrayId(this.exc)] = (this)
            set this.act = true
            set this.cnt = 0
            return true
        endmethod
       
        // *** Returns executor -> in executed function / method ***
        public static method Executor takes nothing returns thistype
            return thistype.ptrAt[ArrayId(GetExpiredTimer())]
        endmethod
       
        // *** Returns current execution of this executor ***
        public method operator xcount takes nothing returns integer
            set this.cnt = this.cnt + 1
            return this.cnt
        endmethod
       
        // *** Destroys executor ***
        public method DestroyExecutor takes nothing returns nothing
            call PauseTimer(this.exc)
            call DestroyTimer(this.exc)
            set this.ptrAt[ArrayId(this.exc)] = NULL
            set this.exc = null
            set this.act = false
            set this.cnt = 0
        endmethod
    endmodule
   
    // ===========================================================================================
    //          Here we define custom actions which are needed for shadow crossing spell
    // ===========================================================================================
   
    // -----------------------------------------------------------------
    //      Here we define actions on how unit should be animated
    // -----------------------------------------------------------------
    scope AnimateDead
       
        // ----------------------------------
        //      AnimateDead Globals
        // ----------------------------------
        globals
            private     constant    string      ANIM_ON_LOAD            = "birth"
            private     constant    integer     LIFE_BUFF               = 'BTLF'
            private     constant    unitevent   ENTER_RECT              = ConvertUnitEvent(5)
        endglobals
       
        // ----------------------------------------------------------------------
        // Type Animate: This type holds all data needed for our animated unit
        // ----------------------------------------------------------------------
        private struct animate
            private unit        u
            private integer     miss
            private real        dtake
            private real        ddeal
            private real        dur
            private trigger     t
            private triggeraction ta
           
           
            // *** Ptr to this struct ***
            private static thistype array ptrAt[8191]
           
            // *** Constant damage trigger ***
            private static trigger TakeDamage = null
           
            // *** This is current number of clones ***
            private static integer NClones = 0
           
            // *** Add executor ***
            implement optional executor
           
            // ----------------------------------------------------------------------
            //             *** Actions when unit takes damage ***
            //
            //      *** Main method for clones (miss / deal and take damage) ***
            // ----------------------------------------------------------------------
            private static method Actions takes nothing returns nothing
                local thistype an
                local unit u
                local unit s
                local texttag tt
               
                // *** Here unit taked damage ***
                // *** Make sure that this is executed only when number of clones is > 0 ***
                //! runtextmacro IF("thistype.NClones == 0", "return", "")
               
                call DisableTrigger(thistype.TakeDamage)
               
                // *** We try to get type form attacked unit ***
                set u = GetTriggerUnit()
                set s = GetEventDamageSource()
                set an = thistype.ptrAt[ArrayId(u)]
               
                // *** Both are clones do nothing ***
                if (an != NULL and thistype.ptrAt[ArrayId(s)] != NULL) then
               
                    // *** Clear memory ***
                    set u = null
                    set s = null
                   
                    // *** Skip Remaining ***
                    call EnableTrigger(thistype.TakeDamage)
                    return
                endif
               
                // *** If taking damage unit is a clone then ***
                if (an != NULL) then
                   
                    // *** Clone took damage ***
                   
                    // *** Lets see can he avoid damage ***
                    if (GetRandomInt(1, 100) <= an.miss) then
                       
                        // *** Avoid damage ***
                        set tt = CreateTextTagUnitBJ("|cff777777avoid|r", u, 0., 10., 100., 100., 100., 0.)
                        call SetTextTagVelocityBJ(tt, 40., 90.)
                        call SetUnitState(u, UNIT_STATE_LIFE, GetUnitState(u, UNIT_STATE_LIFE) + GetEventDamage())
                        call DestroyEffect(AddSpecialEffectTarget(CLONE_AVOID, u, ATTACH_POINT))
                       
                        // *** Delay 2 seconds ***
                        call Sleep(2.)
                       
                        // *** Blow texttag and clear memory ***
                        call DestroyTextTag(tt)
                        set tt = null
                        set u = null
                        set s = null
                       
                        // *** Skip remaining actions ***
                        call EnableTrigger(thistype.TakeDamage)
                        return
                    endif
                   
                    // *** If damage was not avoided then do here damage setup ***
                    call UnitDamageTarget(s, u, GetEventDamage()*((an.dtake/100.) - 1.), true, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_NORMAL, WEAPON_TYPE_WHOKNOWS)
                   
                    // *** We are done setuping taking damage to animated clones ***
                    // *** Clear memory ***
                    set u = null
                    set s = null

                    // *** Skip remaining actions ***
                    call EnableTrigger(thistype.TakeDamage)
                    return
                endif
               
                // *** If we are here target was not clone ***
                set an = thistype.ptrAt[ArrayId(s)]
               
                // *** If source is a clone then ***
                if (an != NULL) then
                   
                    // *** We shall perform damage dealing here ***
                    call SetUnitState(u, UNIT_STATE_LIFE, GetUnitState(u, UNIT_STATE_LIFE) + GetEventDamage()*(an.ddeal/100.))
                   
                    // *** Clear memory ***
                    set s = null
                    set u = null
                   
                endif
               
                call EnableTrigger(thistype.TakeDamage)
            endmethod
           
            // *** This actions are executed when clone dies ***
            private static method CloneOnDeath takes nothing returns nothing
                // *** Get triggering animated clone ***
                local thistype an = thistype.ptrAt[ArrayId(GetTriggerUnit())]
               
                // *** Blow it away ***
                call an.destroy()
            endmethod
           
            // -------------------------------------------------
            //          *** Init this struct ***
            // -------------------------------------------------
            static method onInit takes nothing returns nothing
                set thistype.TakeDamage = CreateTrigger()
               
                // *** Add enter rect so when new unit is loaded its event is as well registerd ***
                // *** As well add that main action to our animate.TakeDamage trigger ***
                call TriggerRegisterAnyUnitDamaged(thistype.TakeDamage)
                call TriggerAddAction(thistype.TakeDamage, function thistype.Actions)
               
            endmethod
           
            // -------------------------------------------------------------
            // *** Stop clone death animation and give controll to user ***
            private static method CloneAllowControll takes nothing returns nothing
                // *** Get executor ***
                local thistype an = thistype.Executor()
               
                // *** Give controll now ***
                call PauseUnit(an.u, false)
                call SetUnitAnimation(an.u, "stand")
                call SetUnitAnimation(an.u, ANIM_ON_LOAD)
                call CloneColor.VertexUnit(an.u)
                call UnitApplyTimedLife(an.u, LIFE_BUFF, an.dur)
                call DestroyEffectTimed(AddSpecialEffectTarget(CLONE_RAISE, an.u, ATTACH_POINT), 2.5)
               
                // *** Blow executor ***
                call an.DestroyExecutor()
            endmethod
           
            // *** Constructor ***
            static method create takes unit origin, player owner, integer miss, real dmgTake, real dmgDeal, real dur returns thistype
                local thistype this = thistype.allocate()
               
                // *** Associate members with there values ***
                // set this.u = CreateUnit(owner, GetUnitTypeId(origin), GetUnitX(origin), GetUnitY(origin), GetUnitFacing(origin))
                set this.u = origin
                set this.miss = miss
                set this.dtake = dmgTake
                set this.ddeal = dmgDeal
                set this.dur = dur
               
                // *** Set pointer on target clone and increase current clones number ***
                set this.ptrAt[ArrayId(this.u)] = (this)
                set this.NClones = this.NClones + 1
               
                // *** Setup clone ***
                call UnitRemoveBuffs(this.u, true, true)
                call PauseUnit(this.u, true)
                call SetUnitAnimation(this.u, "death")
                call SetWidgetLife(this.u, GetUnitState(this.u, UNIT_STATE_MAX_LIFE))
                call SetUnitOwner(this.u, owner, true)
                call SetUnitExploded(this.u, true)
               
                // *** Setup clone death trigger ***
                set this.t = CreateTrigger()
                call TriggerRegisterUnitEvent(this.t, this.u, EVENT_UNIT_DEATH)
                set this.ta = TriggerAddAction(this.t, function thistype.CloneOnDeath)
               
                // *** Active executor ***
                call this.ActiveExecutor(function thistype.CloneAllowControll, false, 0.25)
               
                return (this)
            endmethod
           
            // *** Destructor ***
            method onDestroy takes nothing returns nothing
                call TriggerRemoveAction(this.t, this.ta)
                call DestroyTrigger(this.t)
                set this.NClones = this.NClones - 1
                set this.ptrAt[ArrayId(this.u)] = NULL
                set this.t = null
                set this.ta = null
                set this.u = null
            endmethod
        endstruct
       
        // --------------------------------------------------------------------------------
        // *** This is main function of AnimateDead and its accessible in this library ***
        public function AnimateUnit takes unit whichUnit, player owner, integer missChance, real dmgTake, real dmgDeal, real duration returns nothing
            call animate.create(whichUnit, owner, missChance, dmgTake, dmgDeal, duration)
        endfunction
       
    endscope
   
    // -----------------------------------------------------------------------
    //      *** Here are defined functions on how to slow target ***
    // -----------------------------------------------------------------------
    scope SlowDown
       
        // ================================================
        //          --- Slow down globals ---
        // ================================================
        globals
            // *** Since in current version of jasshelper i cant declare ***
            // *** static array in struct which extends array ***
            private     integer     array       ptrAt[8191]
        endglobals
       
        // -----------------------------------------------------------------
        //      Type Victim: Contains all data for slowed unit
        // -----------------------------------------------------------------
        private struct victim
           
            private unit            u
            private integer         slow
            private effect  array   e[2]
            private effect          skl
           
            // *** Constructor ***
            static method create takes unit u, integer slow returns victim
                // *** Allocate new victim ***
                local victim this = victim.allocate()
               
                // *** Associate our members with there proper values ***
                set this.u          = u
                set this.slow       = slow
                set this.skl        = AddSpecialEffectTarget(SHADOW_BUFF, u, ATTACH_POINT)
                set this.e[0]       = AddSpecialEffectTarget(SHADOW_MISSILE, u, "hand right")
                set this.e[1]       = AddSpecialEffectTarget(SHADOW_MISSILE, u, "hand left")
               
                // *** Now setup our unit ***
                call SetUnitMoveSpeed(this.u, GetUnitMoveSpeed(this.u) - this.slow)
               
                return (this)
            endmethod
           
            // *** Destructor ***
            method onDestroy takes nothing returns nothing
                call SetUnitMoveSpeed(this.u, GetUnitMoveSpeed(this.u) + this.slow)
                call DestroyEffect(this.skl)
                call DestroyEffect(this.e[0])
                call DestroyEffect(this.e[1])
                set this.skl = null
                set this.e[0] = null
                set this.e[1] = null
                set this.u = null
            endmethod
       
        endstruct
       
        // *** Type for victim group ***
        private type nexus extends victim array [64]
       
        // ------------------------------------------------------------------
        // Type Slow: Its a main type of slowing units and contains all data
        // ------------------------------------------------------------------      
        private struct slow extends array
            private timer t
            private nexus n
            private integer c
           
            private static integer Count = 0
           
            // *** Constructor ***
            static method create takes real duration, code fptr returns slow
                // *** Define slow local ***
                local slow this = NULL
                local integer i
               
                // *** Check do we already have slow types ***
                if (this.Count == 0) then
                    set this = slow(1)
                else
                    // *** Loop through them and if some one can be used then use it now ***
                    //! runtextmacro FOR("this", "1", "this.Count + 1")
                        if (TimerGetRemaining(this.t) == duration) then
                            return (this)
                        endif
                    //! runtextmacro ENDFOR()
                   
                    // *** We must create new one as all are already unuseable ***
                    //set this = slow( integer(this) )
                endif
               
                // *** If we are here that means we now have new id ***
                set this.t = CreateTimer()
                set this.n = nexus.create()
                set this.c = 0
                //! runtextmacro FORX("i", "0", "nexus.size", "set this.n[i] = NULL")
                call TimerStart(this.t, duration, false, fptr)
                set ptrAt[ArrayId(this.t)] = (this)
                set slow.Count = slow.Count + 1
               
                return (this)
            endmethod

            // *** Destructor ***
            method destroyx takes nothing returns nothing
                local thistype thisx = slow.Count
                local integer i
               
                // *** Clear current pointer "this" in memory ***
                call PauseTimer(this.t)
                call DestroyTimer(this.t)
                //! runtextmacro FORX("i", "0", "this.c", "call victim(this.n[i]).destroy()")
                call this.n.destroy()
                set ptrAt[ArrayId(this.t)] = NULL
               
                // *** Now replace last slow with this one ***
                set this.t = thisx.t
                set this.n = thisx.n
                set this.c = thisx.c
                set ptrAt[ArrayId(thisx.t)] = (this)
               
                // *** Once replaced clear last slow ***
                set thisx.t = null
                set thisx.n = NULL
                set thisx.c = 0
                set slow.Count = slow.Count - 1
            endmethod
           
            // *** Get slow in executed function ***
            public static method Get takes nothing returns thistype
                return ptrAt[ArrayId(GetExpiredTimer())]
            endmethod
           
            // *** Adds new unit as victim and stores it in its nexus ***
            public method AddUnit takes unit whichUnit, integer slowf returns nothing
                local victim v = victim.create(whichUnit, slowf)
                set this.n[this.c] = v
                set this.c = this.c + 1
            endmethod
        endstruct
       
        // *** This function is executed when
        private function EndSlowNexus takes nothing returns nothing
            // *** Here we get out slow ***
            local slow s = slow.Get()
           
            // *** Clear memory and reset units ***
            call s.destroyx()
        endfunction
       
        // *** This is the main function on how to slow target down ***
        public function SlowTarget takes unit whichUnit, integer slowf, real duration returns nothing
            // *** Define locals (slow is created only when needed) ***
            local slow s = slow.create(duration, function EndSlowNexus)
           
            // *** Now add that unit to slow ***
            call s.AddUnit(whichUnit, slowf)
        endfunction
       
    endscope
   
    // -----------------------------------------------------------------------
    //                       Custom Structs / Types
    // -----------------------------------------------------------------------

   
    // ===================================================================================
    // --- Type Arc: Arc is a type defined for missile movement it returns line of z height
    // --- at given distance. Arc is defined by constructor arguments which are max distance
    // --- and max height. Arc starts at zero length then at half of max distance is exactly
    // --- the max height and then starts to fall down again to zero
    // ===================================================================================
    private struct arc
        private real max_dist
        private real max_height
        private real dist
        private real x
        private real y
       
        // *** Constructor ***
        static method create takes real max_dist, real max_height returns thistype
            local thistype this = thistype.allocate()
           
            // ----------------------------------------------------
            // <<< Setuping our members to there start values >>>
            // ----------------------------------------------------
            set this.dist           = 0.
            set this.max_dist       = max_dist
            set this.max_height     = max_height
            set this.y              = max_height
            set this.x              = 1. - (this.y/(max_dist/2))
            // Formula: r = abs(conv(dist)) * x + y -> conv() is function which rounds dist from -max_dist_half to max_dist_half
           
            return (this)
        endmethod
       
        // *** Calculates absolute value of x |x| ***
        private static constant method Abs takes real x returns real
            //! runtextmacro IFX("x < 0.", "return -x")
            return x
        endmethod
       
        // *** Gives limits to real value ***
        private static constant method Limits takes real x, real min, real max returns real
            //! runtextmacro IFX("x < min", "set x = min")
            //! runtextmacro IFX("x > max", "set x = max")
            return x
        endmethod
       
        // *** Increase / Decreasse distance ***
        public method AddDist takes real range returns nothing
            set this.dist = arc.Limits(this.dist + range, 0., this.max_dist)
        endmethod
       
        // *** Converts distance to radius length value ***
        // *** Since this is an irregular arc radius is not a constant ***
        private method operator radius takes nothing returns real
            return this.y + ( arc.Abs((this.max_dist / 2.) - this.dist) * this.x )
        endmethod
       
        // ---      Main arc calculation function       ---
        // *** Math f(x) = Line Arc, this writes arc in graph ***
        public method Arc takes nothing returns real
            return SquareRoot( Pow(this.radius, 2.) - Pow((this.max_dist * 0.5) - this.dist, 2.) )
        endmethod
       
        // ---     Returns current distance of arc movement     ---
        public method operator getdist takes nothing returns real
            return this.dist
        endmethod
       
        // ---   Returns max distance of arc    ---
        public method operator getmaxdist takes nothing returns real
            return this.max_dist
        endmethod
    endstruct
   
    // ===================================================================================
    // --- Type Missile: Missile is a single one of missiles at field and its main core is
    // --- type graphic which allows it to be moved. It as well points to our arc movement
    // --- for its own arc movement. It as well is part of its own start coordinates (x, y, z)
    // --- and its own velocity as well as all 3D directions requied for arc movement
    // ===================================================================================
    private struct missile
        private graphic     m       // Missile
        private arc         a       // Arc
        private real        sx      // Start x
        private real        sy      // Start y
        private real        dx      // Direction x
        private real        dy      // Direction y
        private real        ox      // Offset x
        private real        oy      // Offset y
        private real        zx      // Direction z (x)
        private real        zy      // Direction z (y)
        private real        vel     // Velocity of missile
       
       
        // *** Constructor ***
        static method create takes real x, real y, real tx, real ty returns thistype
            local thistype this = thistype.allocate()
            local real rad
            local real w
            local real h
           
            set rad = Atan2(ty-y, tx-x)
            set this.sx = x
            set this.sy = y
            set this.dx = Cos(rad)
            set this.dy = Sin(rad)
            set this.ox = Cos(rad-PI_HALF)
            set this.oy = Sin(rad-PI_HALF)
            set this.m = AddGraphic(SHADOW_MISSILE, x, y, MISSILE_START_HEIGHT, rad*bj_RADTODEG, 1.)
            set rad = GetRandomReal(0., 6.28319)
            set this.zx = Cos(rad)
            set this.zy = Sin(rad)
            set w = SquareRoot(Pow(tx-x, 2.) + Pow(ty-y, 2.))
            set h = GetRandomReal(MISSILE_MIN_HEIGHT, MISSILE_MAX_HEIGHT)
            set this.a = arc.create(w, h)
            set this.vel = GetRandomReal(MISSILE_MIN_SPEED, MISSILE_MAX_SPEED) * SquareRoot(0.5 + ( (w*w)/(4.*h*h) ))
           
            //! novjass
           
                         /\
                       /    \      
                arc  /        \     by using that SquareRoot in velocity i am able to make movement more precious
                   /            \   to arc movement since arc is longer then distance and we want our
                  /              \  missile to move on arc (irregular arc) not on single line
                 /                 \
                /___________________\
                        dist
                       
            //! endnovjass
           
            return (this)
        endmethod
       
        // --- Done? operator ---
        // --- The distance must be >= to current distance ---
        public method operator done takes nothing returns boolean
            return this.a.getdist >= this.a.getmaxdist
        endmethod
       
        // --- When missile ends its movement ---
        public method Kill takes nothing returns nothing
            call DestroyEffect(AddSpecialEffect(MISSILE_DEATH, this.m.GetX(), this.m.GetY()))
            call this.m.Kill()
        endmethod
       
        // --- Move: Is main method for moving missile ---
        // --- Returns: Did missile reach its final position ---
        public method Move takes nothing returns boolean
            local real x = this.sx
            local real y = this.sy
            local real z = MISSILE_START_HEIGHT
            local real ac
           
            // *** Do calculations ***
            call this.a.AddDist(this.vel*TIMER_DELAY)
            set ac = this.a.Arc()
            set x = x + (this.a.getdist * this.dx) + (ac * this.ox * this.zx)
            set y = y + (this.a.getdist * this.dy) +