1. Are you planning to upload your awesome spell or system to Hive? Please review the rules here.
    Dismiss Notice
  2. Updated Resource Submission Rules: All model & skin resource submissions must now include an in-game screenshot. This is to help speed up the moderation process and to show how the model and/or texture looks like from the in-game camera.
    Dismiss Notice
  3. DID YOU KNOW - That you can unlock new rank icons by posting on the forums or winning contests? Click here to customize your rank or read our User Rank Policy to see a list of ranks that you can unlock. Have you won a contest and still havn't received your rank award? Then please contact the administration.
    Dismiss Notice
  4. The poll for Hive's 12th Concept Art Contest is up! Go cast your vote for your favourite genie!
    Dismiss Notice
  5. Travel to distant realms and encounter scenes unknown to the common folk. The Greatest of Adventures is upon us with the 8th Cinematic Contest. Join in on a fun ride.
    Dismiss Notice
  6. The 18th Icon Contest is ON! Choose any ingame unit and give him/her Hero abilities. Good luck to all.
    Dismiss Notice
  7. Contestants are to create a scene set in the Stone Age. Come and see what you can come up with. We wish you the best of luck!
    Dismiss Notice
  8. Colour outside the lines! Techtree Contest #13 is a go. The contest is optionally paired.
    Dismiss Notice
  9. Greetings cerebrates, our Swarm needs new spawners that will have numerous children. Join the HIVE's 31st Modeling Contest - Spawners and Spawned! The contest is optionally paired.
    Dismiss Notice
  10. 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

D1000_ExpandingSphere1.4b.w3x
Variables
Spell
Expanding Sphere
Systems
TimerUtils
XE:
xe readme
xebasic
xepreload readme
xepreload
xefx readme
xefx
xedamage readme
xedamage
Unimportant
Ini
Heal
Time
Revive
//TESH.scrollpos=0
//TESH.alwaysfold=0
Name Type Is Array Initial Value
R_Locations location Yes
T_Integer integer No
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope ExpandingSphere

//============================================||
//----------------------------Spell made by D1000---------------------------||
//-----Please give Credits if you use it in your (Or anyone else) map----||
//-------------------------------Version 1.4b----------------------------------||
//-------------------------------------------------------------------------------||
//--Requires: JassHelper, TimerUtils and xe (basic,fx,preload,damage)-||
//------Credits to Vexorian for: JassHelper, TimerUtils and xe------------||
//============================================||

//============================================||
//------------------------------------Import------------------------------------||
//1) Copy the folders "Spell" and "Systems" to your map.----------------||
//2) Import the Dummy-model used in this map in your map -----------||
//3) Follow the import-instructions of xebasic -----------------------------||
//4) Create a dummy-spell and set "AbilityID" in this trigger to its ID ---||
//5) Give credits to Vexorian and me (D1000) -----------------------------||
//6) Have fun :-) --------------------------------------------------------------||
//============================================||

    globals
        //Things you can change
       
        /*Different*/
        private constant integer AbilityID = 'A000' //ID of the dummy Spell
        private constant real Interval = XE_ANIMATION_PERIOD //The loop-Interval
        private constant real Height = 60 //How high above the ground the spell takes place
        private constant integer MaxInstances = 8190 //Maximum number of instances of the Spelldata-Struct. Each usage of the spell needs 17 of them, so you can cast the spell with "MaxInstances = 8190" 8190/17 ~ 481 times at once.

       
        /*Lightnings*/
        private constant string LightningType = "DRAB" //Which lightning effect should be used.
        private constant real Length = 90 //The Length of each lightning
        private constant real LengthAdd = 0 //The Length increase each level
        private constant real SpinSpeed = 0.11 //Spin movement per "Interval" (in Radians)
        private constant real SpinSpeedAdd = 0 //Everytime the same...
                    //Color of the lightnings
        private constant real LightningColorR = 1 //Red
        private constant real LightningColorG = 1 //Green
        private constant real LightningColorB = 1 //Blue
        private constant real LightningColorA = 1 //Alpha
       
       
        /*The ball*/
        private constant string BallModel = "Abilities\\Spells\\Other\\Parasite\\ParasiteMissile.mdl" //The model of the lightning ball
        private constant real StartScale = 0.2 //The scale the ball has to begin of the spell
        private constant real StartScaleAdd = 0 //The scale-increase each level
        private constant real GrowScale = 0.09 //How much the dummy-unit grows each "Interval"
        private constant real GrowScaleAdd = 0 //The groth increase each level
        private constant real MaxScale = 18 //When the dummy reaches this size, it will explode
        private constant real MaxScaleAdd = 0 //Guess what
                    //Color of the ball
        private constant integer BallColorR = 255 //Red
        private constant integer BallColorG = 255 //Green
        private constant integer BallColorB = 255 //Blue
        private constant integer BallColorA = 255 //Alpha
       
       
        /*The effect at the end*/
        private constant string EndEffect = "Objects\\Spawnmodels\\Undead\\UDeathMedium\\UDeath.mdl" //The model of the explosion at the end
        private constant real EndScale = 1.6 //The scale of the effect
        private constant real EndScaleAdd = 0
        private constant real EndZ = 100 //The flying-Height of the effect
        private constant real EndZAdd = 0 //....
        private constant real EndTimeAfter = 1 //Time after the EndEffect until the DummyUnit gets destroyed.
        private constant real EndTimeAfterAdd = 0
                    //Color of the EndEffect
        private constant integer EndColorR = 255 //Red
        private constant integer EndColorG = 255 //Green
        private constant integer EndColorB = 255 //Blue
        private constant integer EndColorA = 255 //Alpha
       
       
        /*Damage*/
        private constant real Range = 240 //The range of the damage
        private constant real RangeAdd = 0
        private constant real Damage = 200 //Damage to each target
        private constant real DamageAdd = 100 // self-explanatory
        //Here you can alter the damage type and similar things (uses xedamage)
        //! textmacro ExpandingSphereDamageSettings
            set .dtype  = DAMAGE_TYPE_MAGIC
            set .atype  = ATTACK_TYPE_HERO
            //the wepon-type is per default "WEAPON_TYPE_WHOKNOWS"
            set .damageTrees = true
            set .damageNeutral = false
            //Damage enemies and not harming allies is default
            //You can find the xe-readmes in the "Systems"-Folder
           
            //You can also define other "onInit" actions in this textmacro, if you need them
        //! endtextmacro
       
        endglobals
       
        /*Advanced Settings*/
        //The following textmacros are called in different parts of the spell.
        //You can define locals in them, if you want.
        //You can access the struct members by using d.StructMember
            //! textmacro ExpandingSphereStart
                //This textmacro is called when the spell starts.
                debug call BJDebugMsg("|cffFFCC00"+GetUnitName(.caster)+"|r starts to cast 'Expanding Sphere'")
            //! endtextmacro
       
            //! textmacro ExpandingSpherePeriodic
                //This textmacro is called every "Interval" seconds, while the spell takes place
                debug call BJDebugMsg("Periodic event of 'Expanding Sphere' (casted by |cffFFCC00"+GetUnitName(.caster)+"|r)")
            //! endtextmacro
       
            //! textmacro ExpandingSphereEnd
                //This textmacro is called when the spell ends
                debug call BJDebugMsg("|cffFFCC00"+GetUnitName(.caster)+"|r finished casting 'Expanding Sphere'")
            //! endtextmacro
           
    private struct ES[MaxInstances]
        //If you want, you can declare additional struct-members here
//=========================================================\\
/*                                        DonĀ“t touch anything below!                                              */
//=========================================================\\    
        real array x[17]
        real array y[17]
        real array z[17]
        unit caster
        lightning array l[16]
        integer level
        real scale
        real radians = 0
        real array dist[16]
       
        delegate xefx ball
       
        static delegate xedamage dmg
        static location loc = Location(0,0) //Used to get the Z value of the target point
       
        static method create takes unit caster, real x, real y returns ES
            local ES this = ES.allocate()
            set .caster = caster
           
            set .level = GetUnitAbilityLevel(caster,AbilityID)-1
            set .scale = StartScale+StartScaleAdd*.level
           
            set .x[16] = x
            set .y[16] = y
            set .ball = xefx.create(x,y,0)
                //Sets the color of the ball
            set .fxpath = BallModel
            set .red = EndColorR
            set .green = EndColorG
            set .blue = EndColorB
            set .alpha = EndColorA
               
       
            set .dist[0] = -(Length + LengthAdd*.level)/2
            set .x[0] = x + .dist[0]
            set .y[0] = y
            return this
        endmethod
       
        static method EndSpell takes nothing returns nothing
            local ES this = GetTimerData(GetExpiredTimer())
            //! runtextmacro ExpandingSphereEnd()
       
            call ReleaseTimer(GetExpiredTimer())
       
            //Destroys the ball
            call .ball.destroy()
       
            //Destroys the spell-struct
            call .destroy()
        endmethod
   
        static method Loop takes nothing returns nothing
            //Local declaration
            local timer t = GetExpiredTimer()
            local ES this = GetTimerData(t)
            local integer i = 1
            local xefx EndSFX
            //! runtextmacro ExpandingSpherePeriodic()
       
            //Lets the dummy grow^^
            set .ball.scale = .scale
            set .scale = .scale + GrowScale+GrowScaleAdd*.level
       
            if .scale >= MaxScale + MaxScaleAdd*.level then // When the max scale is reached, destroy the shapes and so on...
                call PauseTimer(t) //Only pauses the timer becauses it is still needed
           
                //The explosion
                set EndSFX = xefx.create(.x[16],.y[16],0)
                set EndSFX.fxpath = EndEffect
                set EndSFX.z = EndZ+EndZAdd*.level
                set EndSFX.scale = EndScale+EndScaleAdd*.level
                //Sets the color of the effect
                set EndSFX.red = EndColorR
                    set EndSFX.green = EndColorG
                set EndSFX.blue = EndColorB
                set EndSFX.alpha = EndColorA
           
                set i = 0
                loop //Destroys the shapes
                    call DestroyLightning(.l[i])
                    set i = i + 1
                    exitwhen i == 16
                endloop
           
                if Damage+DamageAdd*.level > 0 then //Only triggers if the damage is > 0
                    call .damageAOE(.caster,.x[16],.y[16],Range+RangeAdd*.level,Damage+DamageAdd*.level)
                endif

                call TimerStart(t,EndTimeAfter+EndTimeAfterAdd*.level,false,function ES.EndSpell)
                return //Skips the rest of the trigger
            endif
       
       
            set .x[0] = .x[16]+ .dist[0]*Sin(.radians)
            set .y[0] = .y[16]+ .dist[0]*Cos(.radians)
       
            loop // Moves the lightnings
                if i <= 7 then
                    set .x[i] = .x[16]+ .dist[i]*Sin(.radians)
                    set .y[i] = .y[16]+ .dist[i]*Cos(.radians)
                    call MoveLightningEx(.l[i-1],true,.x[i],.y[i],.z[i],.x[i-1],.y[i-1],.z[i-1])
                elseif i == 8 then
                    set .y[i] = .y[16]+ .dist[i]*Sin(.radians)
                    set .z[i] = .z[16]+ .dist[i]*Cos(.radians)
                    call MoveLightningEx(.l[i-1],true,.x[0],.y[0],.z[0],.x[i-1],.y[i-1],.z[i-1])
                else
                    set .y[i] = .y[16]+ .dist[i]*Sin(.radians)
                    set .z[i] = .z[16]+ .dist[i]*Cos(.radians)
                    call MoveLightningEx(.l[i-1],true,.x[i],.y[i],.z[i],.x[i-1],.y[i-1],.z[i-1])
                endif
           
                set i = i + 1      
                exitwhen i >= 16
            endloop
            call MoveLightningEx(.l[15],true,.x[8],.y[8],.z[8],.x[15],.y[15],.z[15])
       
            set .radians = .radians + SpinSpeed+SpinSpeedAdd*.level
        endmethod
   
        static method StartSpell takes nothing returns nothing
            // Local declaration
            local ES this = ES.create(GetTriggerUnit(),GetSpellTargetX(),GetSpellTargetY())
            local timer t = NewTimer()
            local integer i = 1
            //! runtextmacro ExpandingSphereStart()
       
            call MoveLocation(.loc,.x[16],.y[16])
            set .z[16] = GetLocationZ(.loc)
       
            call SetTimerData(t,this) //Attaches the struct to the timer
       
            set .z[0] = .z[16] + Height
       
            set .ball.z = (Length + LengthAdd*.level)/2 + SquareRoot(((Length + LengthAdd*.level)*(Length + LengthAdd*.level))/2) + Height // Sets the Height of the ball
       
            set .z[16] = .z[16]+.ball.z
            //Creates the lightnings (there are 16 of them)
            loop
                if i <= 7 then
                    set .x[i] = .x[i-1] + (Length+LengthAdd*.level)*Cos(bj_PI/4*(i-1))
                    set .y[i] = .y[16]
                    set .z[i] = .z[i-1] + (Length+LengthAdd*.level)*Sin(bj_PI/4*(i-1))
                    set .l[i-1] = AddLightningEx(LightningType,true,.x[i],.y[i],.z[i],.x[i-1],.y[i-1],.z[i-1])
                    set .dist[i] = .x[i]-.x[16]
                elseif i == 8 then
                    set .x[i] = .x[16] - (Length + LengthAdd*.level)/2
                    set .y[i] = .y[16] - (Length + LengthAdd*.level)/2 - SquareRoot(((Length + LengthAdd*.level)*(Length + LengthAdd*.level))/2)
                    set .z[i] = .z[16]
                    set .l[i-1] = AddLightningEx(LightningType,true,.x[0],.y[0],.z[0],.x[i-1],.y[i-1],.z[i-1])
                    set .dist[i] = .y[i]-.y[16]
                else
                    set .x[i] = .x[i-1] + (Length+LengthAdd*.level)*Cos(bj_PI/4*(i-1))
                    set .y[i] = .y[i-1] + (Length+LengthAdd*.level)*Sin(bj_PI/4*(i-1))
                    set .z[i] = .z[8]
                    set .l[i-1] = AddLightningEx(LightningType,true,.x[i],.y[i],.z[i],.x[i-1],.y[i-1],.z[i-1])
                    set .dist[i] = .y[i]-.y[16]
                endif
           
                call SetLightningColor(.l[i-1],LightningColorR,LightningColorG,LightningColorB,LightningColorA)
           
                set i = i + 1
                exitwhen i >= 16
            endloop
       
            set .l[15] = AddLightningEx(LightningType,true,.x[15],.y[15],.z[15],.x[8],.y[8],.z[8])
            call SetLightningColor(.l[15],LightningColorR,LightningColorG,LightningColorB,LightningColorA)
               
            call TimerStart(t,Interval,true,function ES.Loop) //Starts the loop
        endmethod
   
        static method onInit takes nothing returns nothing
            local trigger tr = CreateTrigger()
       
            call XE_PreloadAbility(AbilityID)
       
            call TriggerRegisterAnyUnitEventBJ(tr,EVENT_PLAYER_UNIT_SPELL_EFFECT )
            call TriggerAddCondition(tr,Condition(function ES.IsSpell))
            call TriggerAddAction(tr,function ES.StartSpell)
       
            set tr = null
            set .dmg = xedamage.create()
            //! runtextmacro ExpandingSphereDamageSettings()
        endmethod
   
        static method IsSpell takes nothing returns boolean
            return GetSpellAbilityId() == AbilityID
        endmethod
    endstruct
endscope
TimerUtils (Red) by Vexorian
//TESH.scrollpos=0
//TESH.alwaysfold=0
library_once TimerUtils initializer redInit
//*********************************************************************
//* TimerUtils (Red flavo for 1.23b)
//* ----------
//*
//*  To implement it , create a custom text trigger called TimerUtils
//* and paste the contents of this script there.
//*
//*  To copy from a map to another, copy the trigger holding this
//* library to your map.
//*
//* (requires vJass)   More scripts: htt://www.wc3campaigns.net
//*
//* For your timer needs:
//*  * Attaching
//*  * Recycling (with double-free protection)
//*
//* set t=NewTimer()      : Get a timer (alternative to CreateTimer)
//* ReleaseTimer(t)       : Relese a timer (alt to DestroyTimer)
//* SetTimerData(t,2)     : Attach value 2 to timer
//* GetTimerData(t)       : Get the timer's value.
//*                         You can assume a timer's value is 0
//*                         after NewTimer.
//*
//* Red flavor: Fastest, method in existence for timer attaching,
//*             only takes an array lookup, GetHandleId and subtraction.
//*             However, all the code in your map requires extra care
//*             not to forget to call ReleaseTimer. It also requires
//*             to preload a lot of timers at map init, they use
//*             memory and handle ids.
//*
//*             I recommend you run your map in debug mode the first
//* time after adding it, make sure you can see map init messages
//* if nothing appears, all is done, if an error appears, it might
//* suggest you a value with OFFSET, in that case, update that value
//* if it still does not work after updating (rare), try a bigger
//* OFFSET by 1000 for example. (Sounds hard? Then use blue or purple
//* timerutils that are friendlier though not as fast)
//*
//********************************************************************

//================================================================
    globals
        private constant integer OFFSET     = 0x100000
        private constant integer QUANTITY   = 256
        private constant integer ARRAY_SIZE = 8191 //changing this to a higher value would effectively
                                                   //cripple the performance making this thing irrelevant

    endglobals

    //==================================================================================================
    globals
        private integer array data[ARRAY_SIZE]
    endglobals

    //It is dependent on jasshelper's recent inlining optimization in order to perform correctly.
    function SetTimerData takes timer t, integer value returns nothing
        debug if(GetHandleId(t)-OFFSET<0) then
        debug     call BJDebugMsg("SetTimerData: Wrong handle id, only use SetTimerData on timers created by NewTimer")
        debug endif
        set data[GetHandleId(t)-OFFSET]=value
    endfunction

    function GetTimerData takes timer t returns integer
        debug if(GetHandleId(t)-OFFSET<0) then
        debug     call BJDebugMsg("GetTimerData: Wrong handle id, only use GetTimerData on timers created by NewTimer")
        debug endif

        return data[GetHandleId(t)-OFFSET]
    endfunction

    //==========================================================================================
    globals
        private timer array tT
        private integer tN = 0
        private constant integer HELD=0x28829022
        //use a totally random number here, the more improbable someone uses it, the better.
    endglobals

    //==========================================================================================
    function NewTimer takes nothing returns timer
        if (tN==0) then
            //If this happens then the QUANTITY rule has already been broken, try to fix the
            // issue, else fail.
            debug call BJDebugMsg("NewTimer: Warning, Exceeding TimerUtils_QUANTITY, please increase it for your map, fix your map's timer leaks or switch to blue flavor when applicable")
            set tT[0]=CreateTimer()
            if (GetHandleId(tT[0])-OFFSET<0) or (GetHandleId(tT[0])-OFFSET>=ARRAY_SIZE) then
                //all right, couldn't fix it
                call BJDebugMsg("NewTimer: Unable to allocate a timer, you should probably switch to the blue flavor or fix timer leaks.")
                return null
            endif
        else
            set tN=tN-1
        endif
        call SetTimerData(tT[tN],0)
     return tT[tN]
    endfunction

    //==========================================================================================
    function ReleaseTimer takes timer t returns nothing
        if(t==null) then
            debug call BJDebugMsg("Warning: attempt to release a null timer")
            return
        endif
        if (tN==8191) then
            debug call BJDebugMsg("Warning: Timer stack is full, destroying timer!!")

            //stack is full, the map already has much more troubles than the chance of bug
            call DestroyTimer(t)
        else
            call PauseTimer(t)
            if(GetTimerData(t)==HELD) then
                debug call BJDebugMsg("Warning: ReleaseTimer: Double free!")
                return
            endif
            call SetTimerData(t,HELD)
            set tT[tN]=t
            set tN=tN+1
        endif    
    endfunction

    private function redInit takes nothing returns nothing
     local integer i=0
     local integer bestoffset=-1

        loop
            exitwhen (i==QUANTITY)
            set tT[i] = CreateTimer()
            if(i==0) then
                set bestoffset=GetHandleId(tT[i])
            endif
            if (GetHandleId(tT[i])-OFFSET>=ARRAY_SIZE) then
                debug call BJDebugMsg("TimerUtils_redInit: Failed a initializing attempt")
                debug call BJDebugMsg("The timer limit is "+I2S(i))
                debug call BJDebugMsg("This is a rare ocurrence, if the timer limit is too low, to change OFFSET to "+I2S(bestoffset) )
                exitwhen true
            endif
            if (GetHandleId(tT[i])-OFFSET>=0)  then
                set i=i+1
            endif
        endloop

        set tN=i
    endfunction

endlibrary
By Vexorian
//TESH.scrollpos=0
//TESH.alwaysfold=0
xe
--
  Q. Why xe?
  A. As the caster system grew bigger vJass also appeared, there are also a lot
   of things in the caster system that could have been done better but cannot
   be fixed without dropping the caster system's function interface.
   
  Q. No, really, WHY IS IT NAMED XE?
  A. I have no idea.
 
  Q. What'
s wrong with the caster system?
  A. Instead of answering that I will list what's right with xe:
  *  It is modular. You can make a whole spell with just xebasic which is just
  like a "constant package" that comes with the dummy model and unit. All the
  other parts are disposable or replaceable.
 
     Still, I made them and will probably keep making new modules as I advance,
  right now xe can only do some basic functions, still cannot 100% replace
  the caster system in functionality, certain parts like the parabolic
  projectiles most notably, don'
t have a xe module yet, maybe later...
 
     xebasic is so minimal I personally hope people could use it on their spells
  and systems as a way to make it common to use these constants as constants of
  that kind are often required to make things work.
 
  * It is quite OOP, this is more related to the modules themselves, I wanted it
  to exploit OOP for two reasons: 1) It prevents the 'ultra long function calls'
  disease that has plagued the caster system since the beginning of time. 2) I
  personally think it is easier this way instead of memorizing function names
  and their argument lists.
 
xebasic
-------
  xebasic is the nucleous of all xe, in order to use a xe module you would most
 likely need xebasic. It is also meant to be the only part of xe that most users
 would really need to tweak for their map.
 
  This section is supposed to be a rapid guide on copying xebasic. The rest of
 the xe modules should be rather easy to implement (just copy the 'trigger' that
 contains it to the map).
 
 1) Make a backup of your map.
 2) Get vJass support. The most usual way would be using the newgen pack. There
 are plenty of other ways. I for example do my vJass coding on Linux using just
 jasshelper.exe, WINE and some editor tricks using a tool called Warcity.
 
     Getting vJass to work is a wide area, if just installing and using the
 "Jass newgen pack" doesn't work to you, please request/search help somehow. As
 of now there really is no vJass support in OS/X, so you would need virtualization
 and things of that style.
 
 -- Note: You can have two maps open in the editor, and it is the only way to
 make copy and paste work.
 
 3) Copy the model, in this map'
s import manager you may find dummy.mdx, select
 it and export it to some temp folder, then go to your map and import it, use
 war3mapimported\dummy.mdx for path.
 
 Please save the map immediatelly after importing the model to prevent it from
 getting unimported due to a rare WE bug.
 
 4) Copy the dummy unit: In the object editor under neutral passive, you may
 find the dummy unit, select it, go to 'edit' then click copy. Now switch to
 your map's object editor and use 'paste'.
 
 5) Write down the rawcode: While you are in the object editor select your map'
s
 recently pasted dummy unit, then go to the 'view' menu and click the option to
 show values as raw data. Now take a look to the selected unit type. It will now
 come with a code like "ewsp:e001", the last four characters of the code are
 what matter, write them down.
 
 6) Copy this map's xebasic trigger to your map.
 
 7) Update your map'
s xebasic: change the value assigned to XE_DUMMY_UNITID to
 'XXXX' where XXXX is the four character code you wrote down in step 5.
 
 8) Save your map and pray, if it compiles correctly then it is done. Make sure
 to test (after implementing) whatever needed you to install xebasic. If it
 doesn't work correctly then it is likely you made a mistake when copying the
 unit or the model or updating the rawcode.

 9) Update the other values if you think it is necessary.

Using xebasic
-------------
  Well, once you state your trigger/spell/system requires xebasic, just use
 its constants, on a map that has implemented xebasic XE_DUMMY_UNITID will be
 your key to creating dummy units, just remember to add it '
Aloc' ...
 
Contact
-------
 I got a forum that'
s supposed to hold questions related to my systems at:
    http://wc3campaigns.net/vexorian
   
 I'd really appreciate that you used that forum for your questions, for starters
 it is a lot more likely I would actually find the questions in that case.
 
 Changelog
 ---------
 
 0.5:
 - xecollider.terminate now prevents events from firing.
 - fixed a unit handle index kidnap in inRangeEnum (xecollider).
 - fixed a small documentation bug about xecollider.terminate
 - xecast'
s anti-AI protection now pauses the unit instead of removing the
   ability (since that seemed to have bad side effects)
 - xecast is now able to deal with units not visible to the player by setting
   a constant to true.
 - Due to technical split, xecast.castOnTarget now only takes unit and not
   widget, old castOnTarget that takes widget has been renamed castOnWidgetTarget.
 - xecollider now will not miss the detection of certain units that get inside
  the range too fast anymore, however now creates a group per collider (damn) I
  hope to find a better solution.
 - Added a notice in xepreload's documentation about order events firing during
   the preload.
 - Added gem of double green fire

 0.4:
 - More documentation fixes.
 - xecast no longer has double frees when using create/Basic/A  and the
   AOE/group methods.
 - damageDestructablesInAOE now actually works and does not leak a xedamage
   reference.
 - damageTarget now returns true if it was succesful and false if it wasn'
t.
 - xefx's recycle bin now extends array.
 - added rune of illusions sample.
 
 0.3:
 - More documentation fixes.
 - xefx requires xebasic in the library declaration (as it was supposed to)
 - xefx now creates the effects at the correct place (used to consider pathing
 during creation for some reason).
 - xebasic sample uses 197.0 for max collision size since that'
s the default in
 warcraft 3 (The default + 1)
 - xebasic now includes an explanation for max collision size and its effects.
 - added useSpecialEffect to xedamage
 - included BoundSentinel
 - added xecollider
 - xedamage's required unittype field is not ignored anymore.
 - Added the fireNovaStrike example.
 
 0.2:
 - Fixed a bug with xecast.castInPoint basically ignoring the arguments.
 - Fixed a bug with xecast.createBasic ignoring the order id.
 - Fixed documentation bugs.
 - Added xedamage.
 - Added sheep staff sample.

 0.1 : Initial release

 
 
 


//TESH.scrollpos=21
//TESH.alwaysfold=0
library xebasic
//**************************************************************************
//
// xebasic 0.4
// =======
// XE_DUMMY_UNITID : Rawcode of the dummy unit in your map. It should
//                   use the dummy.mdx model, so remember to import it as
//                   well, just use copy&paste to copy the dummy from the
//                   xe map to yours, then change the rawcode.
//
// XE_HEIGHT_ENABLER: Medivh's raven form ability, you may need to change
//                    this rawcode to another spell that morphs into a flier
//                    in case you modified medivh's spell in your map.
//
// XE_TREE_RECOGNITION: The ancients' Eat tree ability, same as with medivh
//                      raven form, you might have to change it.
//
// XE_ANIMATION_PERIOD: The global period of animation used by whatever
//                      timer that depends on it, if you put a low value
//                      the movement will look good but it may hurt your
//                      performance, if instead you use a high value it
//                      will not lag but will be fast.
//
// XE_MAX_COLLISION_SIZE: The maximum unit collision size in your map, if
//                        you got a unit bigger than 197.0 it would be
//                        a good idea to update this constant, since some
//                        enums will not find it. Likewise, if none of
//                        your units can go bellow X and X is much smaller
//                        than 197.0, it would be a good idea to update
//                        as well, since it will improve the performance
//                        those enums.
//
// Notice you probably don't have to update this library, unless I specify
// there are new constants which would be unlikely.
//
//**************************************************************************

//===========================================================================
globals
   constant integer XE_DUMMY_UNITID       = 'e000'
   constant integer XE_HEIGHT_ENABLER     = 'Amrf'
   constant integer XE_TREE_RECOGNITION   = 'Aeat'
   constant real    XE_ANIMATION_PERIOD   =  0.025
   constant real    XE_MAX_COLLISION_SIZE =  197.0
endglobals

endlibrary




 
xepreload
---------

  xepreload attacks the ability preloading issue. It is a good idea to preload
 abilities you are going to add to units during the game to avoid the typical
 "first-cast freeze". xepreload exploits jasshelper's inline and a timer to
 minimize the time spent preloading each ability.

Install
-------
 Copy the xepreload trigger to your map.
 
Usage
-----
_____________________________________________________________________________
    function XE_PreloadAbility takes integer abilid returns nothing
----
    Preloads the ability, pass it an ability id (rawcode). Notice that this
 function may only work during map init. In order to use it in a library'
s
 initializer, make sure the library requires xepreload.
       

* Please notice that the ability removal might trigger certain order events, try
ignoring xe dummy units in those events if necessary.


 
//TESH.scrollpos=9
//TESH.alwaysfold=0
library xepreload initializer init requires xebasic
//************************************************************************
// xepreload 0.4
// ---------
// Ah, the joy of preloading abilities, it is such a necessary evil...
// Notice you are not supposed to use this system in places outside map init
//
// This one does the preloading and tries to minimize the hit on loading time
// for example, it only needs one single native call per ability preloaded.
//
//************************************************************************

//===========================================================================================================
    globals
        private unit dum=null
    endglobals

    //inline friendly
    function XE_PreloadAbility takes integer abilid returns nothing
        call UnitAddAbility(dum, abilid)
    endfunction

    private function kill takes nothing returns nothing
        call RemoveUnit(dum)
        set dum=null
        call DestroyTimer(GetExpiredTimer()) //I do hope this doesn't trigger the apocallypse.  I didn't think
                                             // it was a great idea to make this require a whole timer recycling
                                             // system, so, just destroy. Anyone got a better idea on how to make
                                             // this execute after all the other calls at init?
    endfunction

    private function init takes nothing returns nothing
        set dum=CreateUnit(Player(15),XE_DUMMY_UNITID, 0,0,0)
        call TimerStart(CreateTimer(),0.0,false,function kill)
    endfunction




endlibrary



 
//TESH.scrollpos=0
//TESH.alwaysfold=0
xefx
----
  This module just allows you to have movable special effects, they are actually
 dummy units, you can do plenty of things like changing their position, their
 height, their rotation (in the xy and in the z axis as well), color, and things
 like that. It is all about assigning attributes, the only two important methods
 xefx objects have are create and destroy. There are other accessory methods.
 
implementation
--------------
  Just copy the xecast trigger to your map.
 
xefx object
-------------

__________________________________________________________________________________________________
  static method create    takes real x, real y, real facing returns xefx
--
  This is the create method, it will make a new xefx for you to use, there are
 initial values you must specify, like the x,y coordinate and the facing angle.
 facing is in radians.

  Eg. set myfx = xefx.create()
__________________________________________________________________________________________________
  method destroy   takes nothing returns nothing
--
  This just destroys your xefx object. (call myfx.destroy() )

* List of attributes *

________________________________________________________________________________
    string fxpath
----
    Determines the model of the special effect, yes, you may  change it after
 assigning it if necessary to change the model path.
   
    Example: set myfx.path = "abilities\thisisamadeup\modelpath.mdl"

________________________________________________________________________________
    real x
    real y
    real z
----
    Determine the position of your special effect, you can keep moving the
  effect in a periodic loop, etc.
   
    Example: set myfx.x=myfx.x + 65.0
             set myfx.y=GetUnitY(u)
             set myfx.z=JumpParabola(t)
           
________________________________________________________________________________
    real xyangle
----
    The angle in the xy plane, also called 'facing' angle. (Note: uses radians)
   
    Example: set myfx.xyangle = AngleBetweenPoints(target, source)*bj_DEGTORAD
   
________________________________________________________________________________
    real zangle
----
    The angle in the z-axis (inclination?), (Note: uses radians)
   
    Example: set myfx.zangle = bj_PI/2 //Now the model will look towards the sky

   
________________________________________________________________________________
    integer r
    integer g
    integer b
    integer a
----
    Well, the model's vertex coloring in RGB , a is the opacity value (use
 values from 0 to 255 here)
   
    Example: set myfx.r=255
             set myfx.g=0
             set myfx.b=255
             set myfx.a=128
             
______________________________________________________________________________________
    method recolor takes integer r, integer g , integer b, integer a returns nothing
----
    This one assigns all the color values in one pass.

________________________________________________________________________________
    real scale (write-only)
----
    Allows you to resize the xefx object, the default scale is 1.
   
    Example:   set myfx.scale=2.0 //double size (in fact 8x)
               set myfx.scale=0.5 //half size   (in fact 1/8x)
________________________________________________________________________________
    player owner
----
    For some reason you might want to change ownership of the effect, for
  example, if you use abilityid (see bellow) and the ability does damage.
 
    Example: set myfx.owner = GetOwningPlayer(GetTriggerUnit() )
________________________________________________________________________________
    integer abilityid
----
    Well, you may use a xefx object to grab a passive ability, perhaps you need
    it for ye candy reasons or you want to use it as a damage dealer.

        Example: set myfx.abilityid = '
Hphf'
________________________________________________________________________________
    playercolor teamcolor
----
    The team color to use for the model.
   
        Example: set somevar.teamcolor=PLAYER_COLOR_RED
                 set somevar.teamcolor=GetPlayerColor(GetOwningPlayer(u))
   
________________________________________________________________________________
    method flash           takes string modelpath returns nothing
----
    It shows the dead animation of the model specified by modelpath. This is
    in case you need this sort of eye candy.
   
________________________________________________________________________________
    method ARGBrecolor     takes ARGB color returns nothing
----
    If you got the ARGB library in your map, xefx then acquires the ARGBrecolor
   method, that you can use to use an ARGB object to recolor the fx'
s model,
   in a way similar to how recolor() works.
   
   
   


 
//TESH.scrollpos=0
//TESH.alwaysfold=0
library xefx initializer init requires xebasic
//**************************************************
// xefx 0.6
// --------
//  Recommended: ARGB (adds ARGBrecolor method)
//  For your movable fx needs
//
//**************************************************

//==================================================
 globals
    private constant integer MAX_INSTANCES = 8190 //change accordingly.
    private constant real    RECYCLE_DELAY = 4.0

    //recycling, in order to show the effect correctly, must wait some time before
    //removing the unit.
    private timer    recycler
    private timer    NOW

 endglobals

   private struct recyclebin extends array
       unit u
       real schedule
       static recyclebin end=0
       static recyclebin begin=0

       static method Recycle takes nothing returns nothing
            call RemoveUnit(.begin.u) //this unit is private, systems shouldn't mess with it.
            set .begin.u=null
            set .begin=recyclebin(integer(.begin)+1)
            if(.begin==.end) then
                set .begin=0
                set .end=0
            else
                call TimerStart(recycler, .begin.schedule-TimerGetElapsed(NOW), false, function recyclebin.Recycle)
            endif

       endmethod
   endstruct

   private function init takes nothing returns nothing
       set recycler=CreateTimer()
       set NOW=CreateTimer()
       call TimerStart(NOW,43200,true,null)
   endfunction

   struct xefx[MAX_INSTANCES]
       public integer tag=0
       private unit   dummy
       private effect fx=null
       private real   zang=0.0
       private integer r=255
       private integer g=255
       private integer b=255
       private integer a=255

       private integer abil=0

       static method create takes real x, real y, real facing returns xefx
        local xefx this=xefx.allocate()
           set this.dummy= CreateUnit(Player(15), XE_DUMMY_UNITID, x,y, facing*bj_RADTODEG)
           call UnitAddAbility(this.dummy,XE_HEIGHT_ENABLER)
           call UnitAddAbility(this.dummy,'Aloc')
           call UnitRemoveAbility(this.dummy,XE_HEIGHT_ENABLER)
           call SetUnitX(this.dummy,x)
           call SetUnitY(this.dummy,y)
        return this
       endmethod

       method operator owner takes nothing returns player
           return GetOwningPlayer(this.dummy)
       endmethod

       method operator owner= takes player p returns nothing
           call SetUnitOwner(this.dummy,p,false)
       endmethod

       method operator teamcolor= takes playercolor c returns nothing
           call SetUnitColor(this.dummy,c)
       endmethod

       method operator scale= takes real value returns nothing
           call SetUnitScale(this.dummy,value,value,value)
       endmethod

       //! textmacro XEFX_colorstuff takes colorname, colorvar
       method operator $colorname$ takes nothing returns integer
           return this.$colorvar$
       endmethod
       method operator $colorname$= takes integer value returns nothing
           set this.$colorvar$=value
           call SetUnitVertexColor(this.dummy,this.r,this.g,this.b,this.a)
       endmethod
       //! endtextmacro
       //! runtextmacro XEFX_colorstuff("red","r")
       //! runtextmacro XEFX_colorstuff("green","g")
       //! runtextmacro XEFX_colorstuff("blue","b")
       //! runtextmacro XEFX_colorstuff("alpha","a")

       method recolor takes integer r, integer g , integer b, integer a returns nothing
           set this.r=r
           set this.g=g
           set this.b=b
           set this.a=a
           call SetUnitVertexColor(this.dummy,this.r,this.g,this.b,this.a)
       endmethod

       implement optional ARGBrecolor

       method operator abilityid takes nothing returns integer
           return this.abil
       endmethod

       method operator abilityid= takes integer a returns nothing
           if(this.abil!=0) then
               call UnitRemoveAbility(this.dummy,this.abil)
           endif

           if(a!=0) then
               call UnitAddAbility(this.dummy,a)
           endif
           set this.abil=a
       endmethod

       method flash takes string fx returns nothing
           call DestroyEffect(AddSpecialEffectTarget(fx,this.dummy,"origin"))
       endmethod

       method operator xyangle takes nothing returns real
           return GetUnitFacing(this.dummy)*bj_DEGTORAD
       endmethod
       method operator xyangle= takes real value returns nothing
           call SetUnitFacing(this.dummy,value*bj_RADTODEG)
       endmethod

       method operator zangle takes nothing returns real
           return this.zang
       endmethod

       method operator zangle= takes real value returns nothing
        local integer i=R2I(value*bj_RADTODEG+90.5)
           set this.zang=value
           if(i>=180) then
               set i=179
           elseif(i<0) then
               set i=0
           endif
               
           call SetUnitAnimationByIndex(this.dummy, i  )
       endmethod


       method operator x takes nothing returns real
           return GetUnitX(this.dummy)
       endmethod
       method operator y takes nothing returns real
           return GetUnitY(this.dummy)
       endmethod
       method operator z takes nothing returns real
           return GetUnitFlyHeight(this.dummy)
       endmethod

       method operator z= takes real value returns nothing
           call SetUnitFlyHeight(this.dummy,value,0)
       endmethod

       method operator x= takes real value returns nothing
           call SetUnitX(this.dummy,value)
       endmethod

       method operator y= takes real value returns nothing
           call SetUnitY(this.dummy,value)
       endmethod

       method operator fxpath= takes string newpath returns nothing
           if (this.fx!=null) then
               call DestroyEffect(this.fx)
           endif
           if (newpath=="") then
               set this.fx=null
           else
               set this.fx=AddSpecialEffectTarget(newpath,this.dummy,"origin")
           endif

       endmethod
 
       private method onDestroy takes nothing returns nothing
           if(this.abil!=0) then
               call UnitRemoveAbility(this.dummy,this.abil)
           endif
           if(this.fx!=null) then
               call DestroyEffect(this.fx)
               set this.fx=null
           endif

           if (recyclebin.end==MAX_INSTANCES) then
               call TimerStart(recycler,0,false,function recyclebin.Recycle)
               call ExplodeUnitBJ(this.dummy)
           else
               set recyclebin.end.u=this.dummy
               set recyclebin.end.schedule=TimerGetElapsed(NOW)+RECYCLE_DELAY
               set recyclebin.end= recyclebin( integer(recyclebin.end)+1)
               if( recyclebin.end==1) then
                   call TimerStart(recycler, RECYCLE_DELAY, false, function recyclebin.Recycle)
               endif
               call SetUnitOwner(this.dummy,Player(15),false)
           endif
           set this.dummy=null
       endmethod

   endstruct
   


endlibrary





 
xedamage
------
 When blizzard released UnitDamageTarget and UnitDamagePoint there were some
issue, both had a lot of parameters that were undocumented, but more importantly
DamagePoint was not a good enough solution, UnitDamagePoint causes issues with
apple players and it also misses ways to specify what sort of unit to target.
What many people missed was a way to specify these things in a similar way
to targets allowed in the object editor.

 Determining and configuring valid targets and things like damage factors is
always a hassle, xedamage can automatize that process in a nice way.

 xedamage is the successor of damageoptions it is also a little less messy.
bitflags are not used anymore, instead xedamage uses struct members to specify
most of it. So, when using xedamage, you may end up feeling like feeling a
table of fields. An example is worth a thousand of words:

 local xedamage d=xedamage.create()

   set d.damageAllies=true                       // also harm allies
   set d.exception = UNIT_TYPE_FLYING            // don't harm fliers
   call d.factor ( UNIT_TYPE_STRUCTURE, 0.5)     // half damage to buildings
   set d.dtype = DAMAGE_TYPE_UNIVERSAL           // Do universal damage.
   
   //Execute AOE damage using those options:
   call d.damageAOE(GetTriggerUnit(), point_x, point_y, 250.0, 450)
 
 But there is more, xedamage also has a couple of members like isInUse() that
would add some event responses for the damaged unit event. That will allow you
to recognize when xedamage was in use to inflict the damage, the damagetype and
attacktype used, and even a custom tag that you could specify as a xedamage
field, this would allow you to have a bridge between xedamage and certain damage
detection systems that rely on such things.

 
implementation
--------------
  Just copy the xedamage trigger to your map.
 
xedamage object
----------------
   xedamage fields include a bunch of boolean fields that you can set to
 true/false, they hopefully got  self-explaining names, I just list them and
 their default values, remember I got a whole forum in wc3c, if you got doubts
 don't forget to ask questions there:
 
  boolean damageSelf    = false

  boolean damageAllies  = false
  boolean damageEnemies = true
  boolean damageNeutral = true

  boolean visibleOnly   = false
 
  boolean deadOnly      = false
  boolean alsoDead      = false

  boolean damageTrees   = false

  Something to notice is that damageTrees is probably only considered by AOE
 damage and perhaps by some spells using xedamage to specify targets.
 _______________________
  boolean ranged = true
 -----------------------
  This is a special boolean field, it doesn'
t really determine valid targets
 like the ones above, it merely determines if the damage should be considered
 ranged, this merely determines how the AI reacts to the damage, a lot of people
 don't care that much and just use true, that's the default.

 ___________________________________________________
  damagetype dtype  = DAMAGE_TYPE_UNIVERSAL
  attacktype atype  = ATTACK_TYPE_NORMAL
  weapontype wtype  = WEAPON_TYPE_WHOKNOWS
 ---------------------------------------------------
 
  These fields determine the types to use in the damage native, the damage type
 usually determines if the damage would be magical, universal (ultimate) or
 physical, attacktype determines armor stuff, and weapon type determines sound.
 
  There's some work on knowing what each combination does, for example:
  http://www.wc3campaigns.net/showthread.php?t=100752
 
  Some basic knowledge: For spells it is fine to use ATTACK_TYPE_NORMAL, and
 that is default in xedamage, wtype usually doesn'
t need to be updated . dtype
 is the important one, _UNIVERSAL makes the damage behave as a ultimate, there
 is also _UNKNOWN which seems to ignore a lot of things, _FIRE, _LIGHTNING and
 similar damagetypes are all magical, while DAMAGE_TYPE_NORMAL is physical.
 Ultimate damage can harm both ethereal and spell immune units, magical damage
 harms ethereal (with bonus) but cannot harm spell immune, physical damage can't
 hurt ethereal units.
 
 ___________________________
  integer tag = 0
 ---------------------------
  This little field allows you to have a custom damage response CurrentDamageTag
 (see bellow for event responses) basically, you can use whatever you want here
 it all depends on what the thing that uses the event responses will do about it.

 ____________________________
  unittype exception
  unittype required
 ----------------------------
  Learn a little about unittype, it is what blizzard calls unit classifications,
 basically a unit can be a building, a flier, etc. exception specifies a
 unittype that is required for a unit to receive damage. required, does the
 opposite, for example:
 
   set d.exception = UNIT_TYPE_FLYING
   set d.required  = UNIT_TYPE_SUMMONED
   
 This xedamage instance can only hit ground summoned units.

 * factor stuff:
  Factor options in xedamage, specify some rules, if those rules are matched,
 the damage will be multiplied by the specified factor, you can use negative
 factor, half factor, etc. Notice that when using negative factors, these
 things stack, so if you make a xedamage instance that does negative damage to
 undead and negative damage to allies, it might do possitive damage to undead
 allies.
 
  If the total damage factor is 0.0 it is the same as adding an exception.
 
  _____________________________
     real allyfactor = 1.0
  -----------------------------
    If the xedamage can affect allies (damageAllies is true), then the damage
  will be multiplied by allyfactor, for example, you can make a spell that does
  half damage to allies. Or one that heals allies while hurting enemies.
 
  _____________________________________________________________
     method factor takes unittype ut, real fc returns nothing
  -------------------------------------------------------------
    This method allows you to add a specific factor for a unit type, by default
  a xedamage instance allows up to three of these rules, you can increase this
  cap by increasing MAX_SUB_OPTIONS in the top of the library.
 
    For example:
    call d.factor(UNIT_TYPE_STRUCTURE, 0.5)
    call d.factor(UNIT_TYPE_SUMMONED, 2.0)
   
    This instance of xedamage would do half damage to structures and double
  damage to summoned units. Notice these things stack, so if for some reason
  there was a "summoned building" in your map, it would do 100% damage.
 
  _________________________________________________________________________
     method abilityFactor takes integer abilityId, real fc returns nothing
  -------------------------------------------------------------------------
     Let'
s say you want a passive ability that makes you receive half damage
   from fire spells, a way to do this is to make a whole damage detection system
   and use xedamage's event responses to find out fire was used in the spell.
   Then block the damage somehow... another way is to just change the spell so
   when a unit has such passive ability, the damage is multiplied by 0.5 .
   
     The 3 rules cap also works with abilityFactor and can as well be increased
   by changing MAX_SUB_OPTIONS.
   
      call d.abilityFactor( '
A000', 0.5)

  ____________________________________________________________________________
     method useSpecialEffect takes string path, string attach returns nothing
  ----------------------------------------------------------------------------
     This will make a special effect show up whenever succesful damage is done
    using the xedamage object.
   
      call d.useSpecialEffect("Abilities\\Weapons\\RedDragonBreath\\RedDragonMissile.mdl","origin")
 

xedamage methods
----------------
  There would be little point in using all those fields without the methods that
 make use of them.

 ____________________________________________________________________________________
   method damageTarget takes unit source, unit target, real damage returns boolean
 ------------------------------------------------------------------------------------
   A single unit targetting method, it will consider all the rules we just
 reviewed when doing the damage, if the damage would get a factor of 0.0 it will
 not perform any damage.
 
 local unit u = GetTriggerUnit()
 local unit t = GetSpellTargetUnit()
 local xedamage d= xedamage.create()
 
     set d.dtype = DAMAGE_TYPE_FIRE
     set d.damageAllies = true
     set d.allyfactor = -1.0
     call d.damageTarget(u,t, 100)
     call d.destroy()
     
 This would be a simple spell that does 100.0 fire damage on enemy units or
 heals for 100 hitpoints to allies.
 
 This method returns true if non zero damage was done, and false otherwise.
 
 ____________________________________________________________________________________________
   method damageTargetForceValue takes unit source, unit target, real damage returns nothing
 ---------------------------------------------------------------------------------------------
   This is an analogue for damageTarget, but it will IGNORE every specified
 field, and try to do the specified damage, no matter the circumstances, however
 it will use the xedamage instances'
dtype, atype and tag for the xedamage event
 responses (see bellow).
 
   This could be useful when you already know the factor
    (you have previously used getTargetFactor)

 __________________________________________________________________________    
  method allowedTarget takes unit source, unit target returns boolean
 --------------------------------------------------------------------------
   Returns true if xedamage would do a damage different than 0.0 in this case.
 It is useful if you intend to use xedamage to configure a spell's allowed
 targets.
 
   if ( d.allowedTarget(u,t) ) then
       //...
       
 ____________________________________________________________________________
   method getTargetFactor takes unit source, unit target returns real
 ----------------------------------------------------------------------------
   For applications similar to allowedTarget, this returns the whole damage
 factor, so you can decide what to do based on it.
 
    set fc = d.getTargetFactor(u, t)
 
 ________________________________________________________________________________________
  method damageGroup takes unit source, group targetGroup, real damage returns integer
 ----------------------------------------------------------------------------------------
   This method does what damageTarget does, but it executes it on a whole unit
 group, probably faster than calling damageTarget on every unit in the group.
 
   Notice this method will empty the provided group.

 _________________________________________________________________________________________________
  method damageAOE    takes unit source, real x, real y, real radius, real damage returns integer
  method damageAOELoc takes unit source, location loc, real radius, real damage returns integer  
 -------------------------------------------------------------------------------------------------
   It will perform damage on units and destructables (if damageTrees is true)
 that are inside the circle, notice collision sizes are considered. The returned
 value is the number of targets that were affected by the function, the loc
 version allows you to use a location instead of the more sane x,y coordinates.
 
 ______________________________________________________________________________________________________________
  method damageDestructablesAOE    takes unit source, real x, real y, real radius, real damage returns integer
  method damageDestructablesAOELoc takes unit source, location loc, real radius, real damage returns integer
 -----------------------------------------------------------------------------------------------------------
  This one damages all the destructables in a circle, regardless of damageTrees
 being true or not.
 
xedamage static method
-----------------------
 ________________________________________________________________________________________________
  static method getDamageTypeFactor takes unit u, attacktype a, damagetype d returns real
 ------------------------------------------------------------------------------------------------
  This method is used by one of the factor methods up there, thought it would be
 useful to make it available as a public method, it just returns the factor that
 a specific attacktype/damagetype couple would do on a certain unit u:
 
  set fc = xedamage.getDamageTypeFactor( GetTriggerUnit(), ATTACK_TYPE_NORMAL, DAMAGE_TYPE_FIRE)
 
  Would return 1.0 if the unit is a normal unit, 1.66 if it is ethereal and 0 if it is spell immune.
 


xedamage event responses
------------------------
 ______________________________________________________________________
  static method isInUse takes nothing returns boolean
 ----------------------------------------------------------------------
  This method will return true if xedamage was in use during a damaged event,
 this would help you determine if the damage was inflicted by a xedamage call.
 
 _______________________________________________________________________
  readonly static damagetype CurrentDamageType=null
  readonly static attacktype CurrentAttackType=null
  readonly static integer    CurrentDamageTag =0
 -----------------------------------------------------------------------
   When isInUse() returns true, you can use these event responses to determine
 how was the damage inflicted, you can get the damage type, the attack type and
 the tag (specified by the field tag in the xedamage object) of the call.


   if (xedamage.isInUse() ) then
       if(xedamage.CurrentDamageType == DAMAGE_TYPE_FIRE ) then
           call BJDebugMsg(R2S(GetEventDamage())+" fire damage was inflicted to "+GetUnitName(GetTriggerUnit() ) )
       endif
       call BJDebugMsg("tag used: "+I2S(xedamage.CurrentDamageTag) )
   endif


--
  The FireNovaStrike sample attempts to be a quick example on
 how to use xedamage.
   


//TESH.scrollpos=0
//TESH.alwaysfold=0
library xedamage initializer init requires xebasic
//************************************************************************
// xedamage 0.6
// --------
//  For all your damage and targetting needs.
//
//************************************************************************

//===========================================================================================================
    globals
        private constant integer   MAX_SUB_OPTIONS = 3

        //=======================================================
        private constant real      EPSILON = 0.000000001
        private unit     dmger
        private constant integer   MAX_SPACE = 8190 // MAX_SPACE/MAX_SUB_OPTIONS is the instance limit for xedamage, usually big enough...
    endglobals

    private keyword structInit

    struct xedamage[MAX_SPACE]

        //----
        // fields and methods for a xedamage object, they aid determining valid targets and special
        // damage factor conditions.
        //
        // Notice the default values.
        //
        boolean damageSelf    = false  // the damage and factor methods  usually have a source unit parameter
                                       // xedamage would consider this unit as immune unless you set damageSelf to true

        boolean damageAllies  = false  // Alliance dependent target options.
        boolean damageEnemies = true   // *
        boolean damageNeutral = true   // *
        boolean ranged        = true   // Is the attack ranged? This has some effect on the AI of the affected units
                                       // true by default, you may not really need to modify this.

        boolean visibleOnly   = false  // Should only units that are visible for source unit's owner be affected?
        boolean deadOnly      = false  // Should only corpses be affected by "the damage"? (useful when using xedamage as a target selector)
        boolean alsoDead      = false  // Should even corpses and alive units be considered?

        boolean damageTrees   = false  //Also damage destructables? Notice this is used only in certain methods.
                                       //AOE for example targets a circle, so it can affect the destructables
                                       //in that circle, a custom spell using xedamage for targetting configuration
                                       //could also have an if-then-else implemented so it can verify if it is true
                                       //then affect trees manually.

        //
        // Damage type stuff:
        //    .dtype : the "damagetype" , determines if the spell is physical, magical or ultimate.
        //    .atype : the "attacktype" , deals with armor.
        //    .wtype : the "weapontype" , determines the sound effect to be played when damage is done.
        //
        //  Please use common.j/blizzard.j/ some guide to know what damage/attack/weapon types can be used
        //
        damagetype dtype  = DAMAGE_TYPE_UNIVERSAL
        attacktype atype  = ATTACK_TYPE_NORMAL
        weapontype wtype  = WEAPON_TYPE_WHOKNOWS

        //
        // Damage type 'tag' people might use xedamage.isInUse() to detect xedamage usage, there are other static
        //  variables like xedamage.CurrentDamageType and xedamage.CurrentDamageTag. The tag allows you to specify
        //  a custom id for the damage type ** Notice the tag would aid you for some spell stuff, for example,
        //  you can use it in a way similar to Rising_Dusk's damage system.
        //
        integer    tag    = 0

        //
        // if true, forceDamage will make xedamage ignore dtype and atype and try as hard as possible to deal 100%
        // damage.
        boolean    forceDamage = false


        //
        // Ally factor! Certain spells probably have double purposes and heal allies while harming enemies. This
        // field allows you to do such thing.
        //
        real     allyfactor = 1.0

        //
        // field: .exception = SOME_UNIT_TYPE
        // This field adds an exception unittype (classification), if the unit belongs to this unittype it will
        // be ignored.
        //
        method operator exception= takes unittype ut returns nothing
            set this.use_ex=true
            set this.ex_ut=ut
        endmethod

        //
        // field: .required = SOME_UNIT_TYPE
        // This field adds a required unittype (classification), if the unit does not belong to this unittype
        //  it will be ignored.
        //
        method operator required= takes unittype ut returns nothing
            set this.use_req=true
            set this.req_ut=ut
        endmethod
        private boolean  use_ex    =  false
        private unittype ex_ut = null

        private boolean  use_req   = false
        private unittype req_ut  = null


        private unittype array fct[MAX_SUB_OPTIONS]
        private real     array fc[MAX_SUB_OPTIONS]
        private integer  fcn=0

        //
        // method .factor(SOME_UNIT_TYPE, factor)
        //  You might call factor() if you wish to specify a special damage factor for a certain classification,
        // for example call d.factor(UNIT_TYPE_STRUCTURE, 0.5) makes xedamage do half damage to structures.
        //
        method factor takes unittype ut, real fc returns nothing
            if(this.fcn==MAX_SUB_OPTIONS) then
                debug call BJDebugMsg("In one instance of xedamage, you are doing too much calls to factor(), please increase MAX_SUB_OPTIONS to allow more, or cut the number of factor() calls")
                return
            endif
            set this.fct[this.fcn] = ut
            set this.fc[this.fcn] = fc
            set this.fcn = this.fcn+1
        endmethod

        private integer  array abifct[MAX_SUB_OPTIONS]
        private real     array abifc[MAX_SUB_OPTIONS]
        private integer  abifcn=0

        //
        // method .abilityFactor('abil', factor)
        //  You might call abilityFactor() if you wish to specify a special damage factor for units that have a
        // certain ability/buff.
        // for example call d.abilityFactor('A000', 1.5 ) makes units that have the A000 ability take 50% more
        // damage than usual.
        //
       
        method abilityFactor takes integer abilityId, real fc returns nothing
            if(this.abifcn==MAX_SUB_OPTIONS) then
                debug call BJDebugMsg("In one instance of xedamage, you are doing too much calls to abilityFactor(), please increase MAX_SUB_OPTIONS to allow more, or cut the number of abilityFactor() calls")
                return
            endif
            set this.abifct[this.abifcn] = abilityId
            set this.abifc[this.abifcn] = fc
            set this.abifcn = this.abifcn+1
        endmethod

        private boolean  usefx  = false
        private string   fxpath
        private string   fxattach

        //
        // method .useSpecialEffect("effect\\path.mdl", "origin")
        // Makes it add (and destroy) an effect when damage is performed.
        //
        method useSpecialEffect takes string path, string attach returns nothing
            set this.usefx = true
            set this.fxpath=path
            set this.fxattach=attach
        endmethod


        //********************************************************************
        //* Now, the usage stuff:
        //*

        //================================================================================
        // static method xedamage.isInUse()  will return true during a unit damaged
        // event in case this damage was caused by xedamage, in this case, you can
        // read variables like CurrentDamageType, CurrentAttackType and CurrentDamageTag
        // to be able to recognize what sort of damage was done.
        //
        readonly static damagetype CurrentDamageType=null
        readonly static attacktype CurrentAttackType=null
        readonly static integer    CurrentDamageTag =0

        private static integer    inUse = 0
        static method isInUse takes nothing returns boolean
            return (.inUse>0) //inline friendly.
        endmethod

        //========================================================================================================
        // This function calculates the damage factor caused by a certain attack and damage
        // type, it is static : xedamage.getDamageTypeFactor(someunit, ATTAcK_TYPE_NORMAL, DAMAGE_TYPE_FIRE, 100)
        //
        static method getDamageTypeFactor takes unit u, attacktype a, damagetype d returns real
         local real hp=GetWidgetLife(u)
         local real mana=GetUnitState(u,UNIT_STATE_MANA)
         local real r

            //Since a unit is in that point, we don't need checks.
            call SetUnitX(dmger,GetUnitX(u))
            call SetUnitY(dmger,GetUnitY(u))

            call SetUnitOwner(dmger,GetOwningPlayer(u),false)
            set r=hp
            if (hp<1) then
                call SetWidgetLife(u,1)
                set r=1
            endif
            call UnitDamageTarget(dmger,u,0.01,false,false,a,d,null)
            call SetUnitOwner(dmger,Player(15),false)
            if (mana>GetUnitState(u,UNIT_STATE_MANA)) then
                //Unit had mana shield, return 1 and restore mana too.
                call SetUnitState(u,UNIT_STATE_MANA,mana)
                set r=1
            else
                set r= (r-GetWidgetLife(u))*100
            endif
            call SetWidgetLife(u,hp)

         return r
        endmethod


        private method getTargetFactorCore takes unit source, unit target, boolean usetypes returns real
         local player p=GetOwningPlayer(source)
         local boolean allied=IsUnitAlly(target,p)
         local boolean enemy =IsUnitEnemy(target,p)
         local boolean neutral=allied
         local real   f
         local real   negf=1.0
         local integer i

            if(this.damageAllies != this.damageNeutral) then
                set neutral= allied and not (GetPlayerAlliance(GetOwningPlayer(target),p, ALLIANCE_HELP_REQUEST ))
                //I thought accuracy was not as important as speed , I think that REQUEST is false is enough to consider
                // it neutral.
                //set neutral= allied and not (GetPlayerAlliance(GetOwningPlayer(target),p, ALLIANCE_HELP_RESPONSE ))
                //set neutral= allied and not (GetPlayerAlliance(GetOwningPlayer(target),p, ALLIANCE_SHARED_XP ))
                //set neutral= allied and not (GetPlayerAlliance(GetOwningPlayer(target),p, ALLIANCE_SHARED_SPELLS ))
                set allied= allied and not(neutral)
            endif

            if (not this.damageAllies) and allied then
                return 0.0
            elseif (not this.damageEnemies) and enemy then
                return 0.0
            elseif( (not this.damageSelf) and (source==target) ) then
                return 0.0
            elseif (not this.damageNeutral) and neutral  then
                return 0.0
            elseif( this.use_ex and IsUnitType(target, this.ex_ut) ) then
                return 0.0
            elseif( this.visibleOnly and not IsUnitVisible(target,p) ) then
                return 0.0
            elseif ( this.deadOnly and not IsUnitType(target,UNIT_TYPE_DEAD) ) then
                return 0.0
            elseif ( not(this.alsoDead) and IsUnitType(target,UNIT_TYPE_DEAD) ) then
                return 0.0              
            endif

            set f=1.0
            if ( IsUnitAlly(target,p) ) then
                set f=f*this.allyfactor
                if(f<=-EPSILON) then
                    set f=-f
                    set negf=-1.0
                endif
            endif
            if (this.use_req and not IsUnitType(target,this.req_ut)) then
                return 0.0
            endif

            set i=.fcn-1
            loop
                exitwhen (i<0)
                if( IsUnitType(target, this.fct[i] ) ) then
                    set f=f*this.fc[i]
                    if(f<=-EPSILON) then
                        set f=-f
                        set negf=-1.0
                    endif
                endif
                set i=i-1
            endloop
            set i=.abifcn-1
            loop
                exitwhen (i<0)
                if( GetUnitAbilityLevel(target,this.abifct[i] )>0 ) then
                    set f=f*this.abifc[i]
                    if(f<=-EPSILON) then
                        set f=-f
                        set negf=-1.0
                    endif
                endif
                set i=i-1
            endloop
            set f=f*negf

            if ( f<=EPSILON) and (f>=-EPSILON) then
                return 0.0
            endif
            if( this.forceDamage or not usetypes ) then
                return f
            endif
            set f=f*xedamage.getDamageTypeFactor(target,this.atype,this.dtype)

            if ( f<=EPSILON) and (f>=-EPSILON) then
                return 0.0
            endif

            return f
        endmethod

        //====================================================================
        // With this you might decide if a unit is a valid target for a spell.
        //
        method getTargetFactor takes unit source, unit target returns real
            return this.getTargetFactorCore(source,target,true)
        endmethod

        //======================================================================
        // a little better, I guess
        //
        method allowedTarget takes unit source, unit target returns boolean
            return (this.getTargetFactorCore(source,target,false)!=0.0)
        endmethod


        //=======================================================================
        // performs damage to the target unit, for unit 'source'.
        //
        method damageTarget takes unit source, unit target, real damage returns boolean
         local damagetype dt=.CurrentDamageType
         local attacktype at=.CurrentAttackType
         local integer    tg=.CurrentDamageTag
         local real       f = this.getTargetFactorCore(source,target,false)
         local real       pl

            if(f!=0.0) then
                set .CurrentDamageType = .dtype
                set .CurrentAttackType = .atype
                set .CurrentDamageTag  = .tag

                if(.usefx) then
                    call DestroyEffect(  AddSpecialEffectTarget(this.fxpath, target, this.fxattach) )
                endif
               
                set .inUse = .inUse +1
                set pl=GetWidgetLife(target)
                call UnitDamageTarget(source,target,  f*damage, true, .ranged, .atype, .dtype, .wtype )
                set .inUse = .inUse -1
                set .CurrentDamageTag = tg
                set .CurrentDamageType = dt
                set .CurrentAttackType = at
                return (pl!=GetWidgetLife(target))
            endif
            return false
        endmethod

        //=======================================================================================
        // The same as damageTarget, but it forces a specific damage value, good if you already
        // know the target.
        //
        method damageTargetForceValue takes unit source, unit target, real damage returns nothing
         local damagetype dt=.CurrentDamageType
         local attacktype at=.CurrentAttackType
         local integer    tg=.CurrentDamageTag

                set .CurrentDamageType = .dtype
                set .CurrentAttackType = .atype
                set .CurrentDamageTag  = .tag

                if(.usefx) then
                    call DestroyEffect(  AddSpecialEffectTarget(this.fxpath, target, this.fxattach) )
                endif
               
                set .inUse = .inUse +1
                call UnitDamageTarget(source,target,  damage, true, .ranged, null, null, .wtype )
                set .inUse = .inUse -1
                set .CurrentDamageTag  = tg
                set .CurrentDamageType = dt
                set .CurrentAttackType = at
        endmethod

        //=====================================================================================
        // Notice: this will not Destroy the group, but it will certainly empty the group.
        //
        method damageGroup takes unit source, group targetGroup, real damage returns integer
         local damagetype dt=.CurrentDamageType
         local attacktype at=.CurrentAttackType
         local integer    tg=.CurrentDamageTag
         local unit       target
         local real       f
         local integer    count=0

            set .CurrentDamageType = .dtype
            set .CurrentAttackType = .atype
            set .CurrentDamageTag  = .tag
            set .inUse = .inUse +1
            loop
                set target=FirstOfGroup(targetGroup)
                exitwhen (target==null)
                call GroupRemoveUnit(targetGroup,target)
                set f= this.getTargetFactorCore(source,target,false)
                if (f!=0.0) then
                    set count=count+1

                    if(.usefx) then
                        call DestroyEffect(  AddSpecialEffectTarget(this.fxpath, target, this.fxattach) )
                    endif                

                    call UnitDamageTarget(source,target, f*damage, true, .ranged, .atype, .dtype, .wtype )
                endif
            endloop


            set .inUse = .inUse -1
            set .CurrentDamageTag=tg
            set .CurrentDamageType = dt
            set .CurrentAttackType = at
         return count
        endmethod

        private static xedamage instance
        private integer countAOE
        private unit    sourceAOE
        private real    AOEx
        private real    AOEy
        private real    AOEradius
        private real    AOEdamage
        private static boolexpr filterAOE
        private static boolexpr filterDestAOE
        private static group    enumgroup
        private static rect     AOERect

        private static method damageAOE_Enum takes nothing returns boolean
         local unit target=GetFilterUnit()
         local xedamage this=.instance //adopting a instance.
         local real     f

             if( not IsUnitInRangeXY(target,.AOEx, .AOEy, .AOEradius) ) then
                 set target=null
                 return false
             endif
             set f=.getTargetFactorCore(.sourceAOE, target, false)
             if(f!=0.0) then
                 set .countAOE=.countAOE+1
                 call UnitDamageTarget(.sourceAOE,target, f*this.AOEdamage, true, .ranged, .atype, .dtype, .wtype )
                 if(.usefx) then
                     call DestroyEffect(  AddSpecialEffectTarget(this.fxpath, target, this.fxattach) )
                 endif                                  
             endif

          set .instance= this //better restore, nesting IS possible!
          set target=null
          return false
        endmethod

        private static method damageAOE_DestructablesEnum takes nothing returns boolean
         local destructable target=GetFilterDestructable()
         local xedamage this=.instance //adopting a instance.
         local real     dx=.AOEx-GetDestructableX(target)
         local real     dy=.AOEy-GetDestructableY(target)

             if( dx*dx + dy*dy >= .AOEradius+EPSILON )  then
                 set target=null
                 return false
             endif
             set .countAOE=.countAOE+1
             if(.usefx) then
                 call DestroyEffect(  AddSpecialEffectTarget(this.fxpath, target, this.fxattach) )
             endif            
             call UnitDamageTarget(.sourceAOE,target, this.AOEdamage, true, .ranged, .atype, .dtype, .wtype )

          set .instance= this //better restore, nesting IS possible!
          set target=null
          return false
        endmethod
        //==========================================================================================
        // will affect trees if damageTrees is true!
        //
        method damageAOE takes unit source, real x, real y, real radius, real damage returns integer
         local damagetype dt=.CurrentDamageType
         local attacktype at=.CurrentAttackType
         local integer    tg=.CurrentDamageTag

            set .CurrentDamageType = .dtype
            set .CurrentAttackType = .atype
            set .CurrentDamageTag  = .tag
            set .inUse = .inUse +1
            set .instance=this
            set .countAOE=0
            set .sourceAOE=source
            set .AOEx=x
            set .AOEradius=radius
            set .AOEy=y
            set .AOEdamage=damage
            call GroupEnumUnitsInRange(.enumgroup,x,y,radius+XE_MAX_COLLISION_SIZE, .filterAOE)
            if(.damageTrees) then
                call SetRect(.AOERect, x-radius, y-radius, x+radius, y+radius)
                set .AOEradius=.AOEradius*.AOEradius
                call EnumDestructablesInRect(.AOERect, .filterDestAOE, null)
            endif
            set .inUse = .inUse -1
            set .CurrentDamageTag  = tg
            set .CurrentDamageType = dt
            set .CurrentAttackType = at
         return .countAOE
        endmethod

        method damageAOELoc takes unit source, location loc, real radius, real damage returns integer
            return .damageAOE(source, GetLocationX(loc), GetLocationY(loc), radius, damage)
        endmethod

        //==========================================================================================
        // only affects trees, ignores damageTrees
        //
        method damageDestructablesAOE takes unit source, real x, real y, real radius, real damage returns integer
            set .instance=this
            set .countAOE=0
            set .sourceAOE=source
            set .AOEx=x
            set .AOEradius=radius*radius
            set .AOEy=y
            set .AOEdamage=damage
            //if(.damageTrees) then
                call SetRect(.AOERect, x-radius, y-radius, x+radius, y+radius)
                call EnumDestructablesInRect(.AOERect, .filterDestAOE, null)
            //endif
         return .countAOE
        endmethod
        method damageDestructablesAOELoc takes unit source, location loc, real radius, real damage returns integer
            return .damageDestructablesAOE(source,GetLocationX(loc), GetLocationY(loc), radius, damage)
        endmethod

        //'friend' with the library init
        static method structInit takes nothing returns nothing
            set .AOERect= Rect(0,0,0,0)
            set .filterAOE= Condition(function xedamage.damageAOE_Enum)
            set .filterDestAOE = Condition( function xedamage.damageAOE_DestructablesEnum)
            set .enumgroup = CreateGroup()
        endmethod
    endstruct

    private function init takes nothing returns nothing
        set dmger=CreateUnit(Player(15), XE_DUMMY_UNITID , 0.,0.,0.)
        call UnitAddAbility(dmger,'Aloc')
        call xedamage.structInit()
    endfunction




endlibrary




 
//TESH.scrollpos=18
//TESH.alwaysfold=0
function Trig_Ini_Func004001002 takes nothing returns boolean
    return ( IsUnitType(GetFilterUnit(), UNIT_TYPE_HERO) == false )
endfunction

function Trig_Ini_Func004A takes nothing returns nothing
    call SetUnitUserData( GetEnumUnit(), udg_T_Integer )
    set udg_R_Locations[udg_T_Integer] = GetUnitLoc(GetEnumUnit())
    set udg_T_Integer = ( udg_T_Integer + 1 )
endfunction

function Trig_Ini_Actions takes nothing returns nothing
    local real TX = 0
    local real TY = 0
    local integer i = 0
    local integer r = 0
    loop
        exitwhen i > 299
        set i = i + 1
        set TX = GetRandomReal(-5376,5344)
        set TY = GetRandomReal(-5632,5088)
        set r = GetRandomInt(0, 3)
        if r == 0 then
            call SetTerrainType(TX,TY,'Adrd',-1,GetRandomInt(1, 5),0)
        elseif r == 1 then
            call SetTerrainType(TX,TY,'Adrg',-1,GetRandomInt(1, 5),0)
        elseif r == 2 then
            call SetTerrainType(TX,TY,'Alvd',-1,GetRandomInt(1, 5),0)
        elseif r == 3 then
            call SetTerrainType(TX,TY,'Adrt',-1,GetRandomInt(1, 5),0)
        endif
    endloop
    call ForGroup( GetUnitsInRectMatching(GetWorldBounds(), Condition(function Trig_Ini_Func004001002)), function Trig_Ini_Func004A )
    call BJDebugMsg("TRIGSTR_250")
    call BJDebugMsg("
                Spell made by: D1000
   
Thanks to Vexorian for JassHelper, TimeUtils and XE"
)
    call Cheat("iseedeadpeople")
    call Cheat("thereisnospoon")
endfunction

//===========================================================================
function InitTrig_Ini takes nothing returns nothing
    set gg_trg_Ini = CreateTrigger()
    call TriggerAddAction( gg_trg_Ini, function Trig_Ini_Actions )
endfunction

 
//TESH.scrollpos=0
//TESH.alwaysfold=0
function Heal takes nothing returns nothing
    call SetUnitState(GetEnumUnit(), UNIT_STATE_LIFE, GetUnitState(GetEnumUnit(), UNIT_STATE_MAX_LIFE))
    call SetUnitState(GetEnumUnit(), UNIT_STATE_MANA, GetUnitState(GetEnumUnit(), UNIT_STATE_MAX_MANA))
    call UnitResetCooldown(GetEnumUnit())
endfunction

function Trig_Heal_Actions takes nothing returns nothing
local group g = CreateGroup()
    call SyncSelections()
call GroupEnumUnitsSelected(g,Player(0),null)
    call ForGroup(g, function Heal )
    call DestroyGroup (g)
    endfunction

//===========================================================================
function InitTrig_Heal takes nothing returns nothing
    set gg_trg_Heal = CreateTrigger()
    call TriggerRegisterPlayerEventEndCinematic( gg_trg_Heal, Player(0) )
    call TriggerAddAction( gg_trg_Heal, function Trig_Heal_Actions )
endfunction

 
//TESH.scrollpos=0
//TESH.alwaysfold=0
function Trig_Time_Actions takes nothing returns nothing
    call SetFloatGameState(GAME_STATE_TIME_OF_DAY, S2R(GetEventPlayerChatString()))
endfunction

//===========================================================================
function InitTrig_Time takes nothing returns nothing
    set gg_trg_Time = CreateTrigger()
    call TriggerRegisterPlayerChatEvent(gg_trg_Time,Player(0),"", false)
    call TriggerAddAction(gg_trg_Time,function Trig_Time_Actions)
endfunction

 
//TESH.scrollpos=0
//TESH.alwaysfold=0
function startunits takes nothing returns boolean
    if GetUnitTypeId(GetDyingUnit()) == 'earc' then
        return true
    endif
    return GetUnitTypeId(GetDyingUnit()) == 'edry'
endfunction


function Trig_Revive_Actions takes nothing returns nothing
local unit u = GetDyingUnit()
local unit uu = null
if GetOwningPlayer(u) == Player(0) then
  if IsUnitType(u, UNIT_TYPE_HERO) then
                call TriggerSleepAction( 3.00 )
                call ReviveHero( u, GetStartLocationX(GetPlayerStartLocation(GetOwningPlayer(u))),GetStartLocationX(GetPlayerStartLocation(GetOwningPlayer(u))), false )
    elseif startunits() then
                set uu = CreateUnitAtLoc(Player(0),GetUnitTypeId(u), udg_R_Locations[GetUnitUserData(u)], GetUnitFacing(GetEnumUnit()) )
                call SetUnitUserData( uu, GetUnitUserData(u) )
  endif
elseif IsUnitType(u, UNIT_TYPE_HERO) == true then
            call TriggerSleepAction( 10.00 )
            call ReviveHeroLoc( u, GetUnitLoc(u), false )
else
            call TriggerSleepAction( 10.00 )
            set uu = CreateUnitAtLoc(GetOwningPlayer(u), GetUnitTypeId(u),udg_R_Locations[GetUnitUserData(u)], GetUnitFacing(GetEnumUnit()) )
            call SetUnitUserData( uu, GetUnitUserData(u) )
endif
set u = null
set uu = null
endfunction

//===========================================================================
function InitTrig_Revive takes nothing returns nothing
    set gg_trg_Revive = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ(gg_trg_Revive,EVENT_PLAYER_UNIT_DEATH)
    call TriggerAddAction(gg_trg_Revive,function Trig_Revive_Actions)
endfunction