HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

What spell to revive next?

04-17-2008, 12:03 AM#1
Vexorian
So, anyone is on need of a vJass - powered, faster, safer version of one of my old spells, I have confirmed I am able to do all what's required for spell making in Linux, unless you count terraining, so I am looking forward to reviving an old spell. So, if you need one of those, please tell me, the most popular will get revived.

If nobody replies, I guess I'll do a random selection.
04-17-2008, 01:53 AM#2
Rising_Dusk
I suggest your Hydra spell, that one was pretty and I tested it a lot for those game cache bugs back in the day.
04-17-2008, 01:57 AM#3
Vexorian
And I would, but I did that a long ago, if you actually can find any gc bug in the newest version in the resources section, then I need replays.
04-17-2008, 02:07 AM#4
Rising_Dusk
I haven't tried it in a long time, so I don't know what would be expected. I just thought it would be a cool one to remake in vJass. :p
04-17-2008, 08:18 AM#5
Pyrogasm
Somebody requested a vJASS'd non-buggy version of your Rolling Boulder spell in my Spell Request Thread a while back. I don't think that user is active, but maybe he is.
04-17-2008, 09:50 AM#6
Soki
Ya, Rolling Bolder would be awesome :)
04-17-2008, 09:53 AM#7
Malf
Frozen Orb
04-17-2008, 03:01 PM#8
emjlr3
your ice nova spell you made a thread about a few days ago, or your flame armor spell
04-17-2008, 05:32 PM#9
Rising_Dusk
Quote:
Originally Posted by Malf
Frozen Orb
I wanted to code one of those, don't let him redo it!! :O
04-26-2008, 11:06 PM#10
marven15
Either Rolling Boulder and Frozen Orb would be great. :P
05-02-2008, 02:05 AM#11
burningice95
It's not a spell, but.....


Spell factory!!!
05-02-2008, 04:33 AM#12
Vexorian
Quote:
Originally Posted by burningice95
It's not a spell, but.....


Spell factory!!!
godamn, I guess I'll have to do that .
05-04-2008, 05:24 AM#13
drizza
Hello some skills I would like to see you bring back is the following,

Warshadow
Multishot
Final Slam
Final Uppercut
shield of divinity
charge
chain burning
Magma rage

I have a map with all these skills on it so you wouldnt have to redo it but he problem is it has been so long since I edited this map with these skills is that one of your skills i put on my map is causing an error and I cant remember what it is. I am not that smart at programming so the only thing I can do is just redownload the rpg and reput these spells in it but I want to redownload them from this website. If you want I can email this map to you just let me know.
05-04-2008, 12:49 PM#14
Vexorian
Quote:
one of your skills i put on my map is causing an error and I cant remember what it is.
What kind of error?

--
I was updating warshadow the other day, noticed iti s heck hard to make it without some sort of attachment system, I postponed the work on it to do hero contest stuff.
05-05-2008, 12:54 PM#15
drizza
Well I know it is something I did to the map with the spells I cant remember because it is soo long but simply the map wont start. Here is what is in the custom script is I know I have something wrong in here.

Code:
//##Start##
//====================================================================================================================================================================
constant function Caster_UnitId takes nothing returns integer
    return 'e000' //// Caster Unit type rawcode  (changes betwen maps, always use it inside '')
endfunction

constant function Caster_DefaultAttackType takes nothing returns attacktype
    return ATTACK_TYPE_CHAOS // Default attack type used by the old functions and when you use 0 as DamageOptions
endfunction

constant function Caster_DefaultDamageType takes nothing returns damagetype
    return DAMAGE_TYPE_UNIVERSAL // Default damage type used by the old functions and when you use 0 as DamageOptions
endfunction

constant function DamageTreeDetectorId takes nothing returns integer
    return 'Aeat' /// The eat tree ability, don't need to change this rawcode unless you modiffied that ability in your map, in that case copy it, reset the copied one and use its rawcode here.
endfunction

constant function ChangeableFlyingHeightAllowerId takes nothing returns integer
    return 'Amrf' /// Medivh's Crow form ability, don't need to change this rawcode unless you modiffied that ability in your map, in that case copy it, reset the copied one and use its rawcode here.
endfunction

constant function WaterDetectorId takes nothing returns integer
    return 'Asb2' // The Royal Guard's submerge ability, don't need to change this rawcode unless you modiffied that ability in your map, in that case copy it, reset the copied one and use its rawcode here.
endfunction

//=================================================================================================
function CS_H2I takes handle h returns integer
    return h
    return 0
endfunction

//=================================================================================================
function CSCache takes nothing returns gamecache
    if udg_cscache==null then
        set udg_castervars[500]=0
        call FlushGameCache(InitGameCache("CasterSystem.vx"))
        set udg_cscache=InitGameCache("CasterSystem.vx")
    endif
 return udg_cscache
endfunction

function CS_Rawcode2Real takes integer i returns real
 return i
 return 0.
endfunction

function CS_LoadRawcodeFromReal takes integer n returns integer
 return udg_castervars[n]
 return 0
endfunction

//==================================================================================================
function AttachInt takes handle h, string label, integer x returns nothing
 local string k=I2S(CS_H2I(h))
    if x==0 then
        call FlushStoredInteger(CSCache(),k,label)
    else
        call StoreInteger(CSCache(),k,label,x)
    endif
endfunction

function AttachReal takes handle h, string label, real x returns nothing
 local string k=I2S(CS_H2I(h))
    if x==0 then
        call FlushStoredReal(CSCache(),k,label)
    else
        call StoreReal(CSCache(),k,label,x)
    endif
endfunction

function AttachBoolean takes handle h, string label, boolean x returns nothing
 local string k=I2S(CS_H2I(h))
    if not x then
        call FlushStoredBoolean(CSCache(),k,label)
    else
        call StoreBoolean(CSCache(),k,label,x)
    endif
endfunction

function AttachString takes handle h, string label, string x returns nothing
 local string k=I2S(CS_H2I(h))
    if x=="" then
        call FlushStoredString(CSCache(),k,label)
    else
        call StoreString(CSCache(),k,label,x)
    endif
endfunction

function AttachObject takes handle h, string label, handle x returns nothing
    call AttachInt( h, label, CS_H2I(x) )
endfunction

//==================================================================================================
function GetAttachedInt takes handle h, string label returns integer
 local real r=udg_castervars[500]
 local integer i
 local integer L
 local string c
 local string num

    if (r>0) then
        if SubString(label,0,1)=="#" then
            set udg_castervars[500]=r-1
            set i=0
            set num=""
            loop
                set i=i+1
                set c=SubString(label,i,i+1)
                exitwhen (c==";") or (c=="")
                set num=num+c
            endloop
            if c==";" then
                return GetStoredInteger(CSCache(),I2S(CS_H2I(h))+";"+SubString(label,i+1,StringLength(label)+1),num)
            endif
        endif
    endif
 return GetStoredInteger(CSCache(), I2S(CS_H2I(h)), label)
endfunction

function GetAttachedReal takes handle h, string label returns real
    return GetStoredReal(CSCache(),I2S(CS_H2I(h)),label)
endfunction

function GetAttachedString takes handle h, string label returns string
    return GetStoredString(CSCache(),I2S(CS_H2I(h)),label)
endfunction

function GetAttachedBoolean takes handle h, string label returns boolean
    return GetStoredBoolean(CSCache(),I2S(CS_H2I(h)),label)
endfunction

function GetAttachedObject takes handle h, string label returns handle
    return GetAttachedInt(h,label)
    return null
endfunction

function GetAttachedUnit takes handle h, string label returns unit
    return GetAttachedInt(h,label)
    return null
endfunction

function GetAttachedItem takes handle h, string label returns item
    return GetAttachedInt(h,label)
    return null
endfunction

function GetAttachedEffect takes handle h, string label returns effect
    return GetAttachedInt(h,label)
    return null
endfunction

function GetAttachedDestructable takes handle h, string label returns destructable
    return GetAttachedInt(h,label)
    return null
endfunction

function GetAttachedTrigger takes handle h, string label returns trigger
    return GetAttachedInt(h,label)
    return null
endfunction

function GetAttachedTimer takes handle h, string label returns timer
    return GetAttachedInt(h,label)
    return null
endfunction

function GetAttachedGroup takes handle h, string label returns group
    return GetAttachedInt(h,label)
    return null
endfunction

function GetAttachedTriggerAction takes handle h, string label returns triggeraction
    return GetAttachedInt(h,label)
    return null
endfunction

function GetAttachedLightning takes handle h, string label returns lightning
    return GetAttachedInt(h,label)
    return null
endfunction

function GetAttachedImage takes handle h, string label returns image
    return GetAttachedInt(h,label)
    return null
endfunction

function GetAttachedUbersplat takes handle h, string label returns ubersplat
    return GetAttachedInt(h,label)
    return null
endfunction


//============================================================================================================
// Attached Sets:
//
function FromSetElement takes string setn, integer index returns string
 set udg_castervars[500]=udg_castervars[500]+1
    return "#"+I2S(index)+";"+setn
endfunction

//============================================================================================================
function AttachedSetAddInt takes handle h, string setn, integer int returns nothing
 local gamecache g=CSCache()
 local string k=I2S(CS_H2I(h))
 local integer n
 local integer x=GetStoredInteger(g,k,"#setnumberof;"+setn)
 local integer y
    if x==0 then
        set y=GetStoredInteger(g,k,"#totalsets")+1
        call StoreInteger(g,k,"#totalsets",y)
        call StoreInteger(g,k,"#setnumberof;"+setn,y)
        call StoreString(g,k,"#setName;"+I2S(y),setn)
    endif
    set k=k+";"+setn
    if not HaveStoredInteger(g,k,"Pos"+I2S(int)) then
        set n=GetStoredInteger(g,k,"n")+1
        call StoreInteger(g,k,"n",n)
        call StoreInteger(g,k,I2S(n),int)
        call StoreInteger(g,k,"Pos"+I2S(int),n)
    endif
 set g=null
endfunction

function AttachedSetAddObject takes handle h, string setn, handle val returns nothing
    call AttachedSetAddInt(h,setn,CS_H2I(val))
endfunction

//============================================================================================================
function AttachedSetHasInt takes handle h, string setn, integer int returns boolean
    return HaveStoredInteger(CSCache(),I2S(CS_H2I(h))+";"+setn,"Pos"+I2S(int))
endfunction

//============================================================================================================
function AttachedSetHasObject takes handle h, string setn, handle val returns boolean
    return AttachedSetHasInt(h,setn,CS_H2I(val))
endfunction


//============================================================================================================
function GetAttachedSetSize takes handle h, string setn returns integer
    return GetStoredInteger(CSCache(),I2S(CS_H2I(h))+";"+setn,"n")
endfunction

//============================================================================================================
function AttachedSetRemInt takes handle h, string setn, integer int returns nothing
 local gamecache g=CSCache()
 local string k=I2S(CS_H2I(h))+";"+setn
 local integer n
 local integer x
 local integer y
    if HaveStoredInteger(g,k,"Pos"+I2S(int)) then
        set x=GetStoredInteger(g,k,"Pos"+I2S(int))
        set n=GetStoredInteger(g,k,"n")
        if x!=n then
            set y=GetStoredInteger(g,k,I2S(n))
            call StoreInteger(g,k,I2S(x),y)
            call StoreInteger(g,k,"Pos"+I2S(y),x)
        endif        
        call FlushStoredInteger(g,k,"Pos"+I2S(int))
        call FlushStoredInteger(g,k,I2S(n))
        call StoreInteger(g,k,"n",n-1)
    endif
 set g=null
endfunction

function AttachedSetRemObject takes handle h, string setn, handle val returns nothing
    call AttachedSetRemInt(h,setn,CS_H2I(val))
endfunction

//============================================================================================================
function ClearAttachedSet takes handle h, string setn returns nothing
    call FlushStoredMission(CSCache(),I2S(CS_H2I(h))+";"+setn)
endfunction

//==================================================================================================
function CleanAttachedVars takes handle h returns nothing
 local gamecache g=CSCache()
 local string k=I2S(CS_H2I(h))
 local integer n=GetStoredInteger(g,k,"#totalsets")
 local integer i=1
    loop
        exitwhen i>n
        call FlushStoredMission(g,k+";"+GetStoredString(g,k,"#setName;"+I2S(i)))
        set i=i+1
    endloop
    call FlushStoredMission(g, k )
 set g=null
endfunction

//====================================================================================================================================================================
// Left For compatibility
//
function SpellEffectModelPath takes integer abilityid, effecttype t returns string
    return GetAbilityEffectById(abilityid,t, 0)
endfunction

//====================================================================================================================================================================
function AddCasterFacing takes real fac returns unit
 local unit m=CreateUnit( Player(15), Caster_UnitId(), 0 ,0 ,fac)
    call UnitAddAbility(m, 'Aloc')
    call UnitAddAbility(m, ChangeableFlyingHeightAllowerId())
    call UnitRemoveAbility(m, ChangeableFlyingHeightAllowerId())
 set udg_currentcaster=m
 set m=null
 return udg_currentcaster
endfunction

function AddCaster takes nothing returns unit
    return AddCasterFacing(0)
endfunction

//====================================================================================================================================================================
function CreateCasters takes integer n returns nothing
 local integer a=0
 local unit c
    set udg_castervars[100]=-1
    set udg_castervars[101]=-1
    set udg_castervars[102]=-1
    set udg_castervars[103]=-1
    set udg_castervars[104]=-1
    loop
        exitwhen a>=n
        set c=AddCaster()
        call GroupAddUnit( udg_casters, c)
        set a=a+1
    endloop
 set c=null
 call RemoveLocation(udg_sourcehack)
 set udg_sourcehack=null
endfunction

//====================================================================================================================================================================
function GetACaster takes nothing returns unit
    set udg_currentcaster=FirstOfGroup( udg_casters)
    if udg_currentcaster == null then
        set udg_currentcaster=AddCaster()
    endif
    call GroupRemoveUnit( udg_casters,udg_currentcaster)
    call SetUnitState( udg_currentcaster, UNIT_STATE_MANA, 1000)
 return udg_currentcaster
endfunction

//====================================================================================================================================================================
function Caster_SetZAngle takes unit caster, real ang returns nothing
 local real a=(GetUnitFacing(caster)*bj_DEGTORAD)
 local real x
    set ang=ModuloReal(ang,360)
    set a=ModuloReal(a,360)
    if ( ang == 90 ) then
        set ang = 89
    endif
    if ( ang == 270 ) then
        set ang = 271
    endif
    if (ang>90) and (ang<270) then
        set x=-1
    else
        set x=1
    endif
    set ang=ang*bj_DEGTORAD
    call SetUnitLookAt(caster,"Bone_Chest",caster, 10000.0*Cos(a)*Cos(ang), 10000.0*Sin(a)*Cos(ang), x*(10000.0*Tan(ang)+90.0) )
endfunction


//====================================================================================================================================================================
function RecicleCaster takes unit caster returns nothing
    if not IsUnitDeadBJ(caster) then
        call ResetUnitLookAt(caster)
        call SetUnitOwner( caster, Player(15), true)
        call SetUnitVertexColor( caster, 255,255,255,255)
        call SetUnitScale( caster, 1,1,1)
        call SetUnitTimeScale( caster, 1)
        call SetUnitMoveSpeed( caster, 522)
        call SetUnitFlyHeight( caster, 0,0)
        call UnitAddAbility(caster, 'Aloc')
        call SetUnitTurnSpeed( caster, 0.6)
        call GroupAddUnit( udg_casters, caster)
    endif
endfunction

function CasterWaitForEndCast takes nothing returns nothing
 local unit caster=udg_currentcaster
 local integer abilid=udg_currentabi
 local real delay=udg_castervars[0]
 local boolean activeability=(udg_castervars[1]>0)
    loop
        exitwhen GetUnitCurrentOrder(caster) == 0
        call TriggerSleepAction(0)
    endloop
    if activeability then
        call PolledWait(delay)
        call UnitRemoveAbility( caster, abilid)
    else
        call UnitRemoveAbility( caster, abilid)
        call PolledWait(delay)
    endif
    call RecicleCaster( caster)
 set caster=null
endfunction

function RecicleCasterAfterCastEx takes unit caster, real delaytime, integer abilid, boolean activeability returns nothing
    set udg_castervars[0]=delaytime
    set udg_castervars[1]=IntegerTertiaryOp(activeability,1,0)
    set udg_currentabi=abilid
    set udg_currentcaster=caster
    call ExecuteFunc("CasterWaitForEndCast" )
endfunction

function RecicleCasterAfterCast takes unit caster, integer abilid returns nothing
    call RecicleCasterAfterCastEx(caster,udg_delayhack,abilid,false)
endfunction

//====================================================================================================================================================================
function PreloadAbility takes integer abilid returns integer
 local unit u=FirstOfGroup(udg_casters)
    if u==null then
        set u=GetACaster()
        call UnitAddAbility(u, abilid)
        call UnitRemoveAbility(u, abilid)
        call RecicleCaster( u)
    else
        call UnitAddAbility(u, abilid)
        call UnitRemoveAbility(u, abilid)
    endif
 set u=null
 return abilid
endfunction

//====================================================================================================================================================================
function CasterCastAbilityEx takes player owner, real x, real y, real z, integer abilid, integer level, string order, widget target, real delay returns unit
 local unit caster=GetACaster()
 local boolean done=false
    call SetUnitOwner( caster, owner, false)
    call UnitAddAbility( caster, abilid)
    call SetUnitAbilityLevel(caster,abilid,level)
    call SetUnitPosition( caster, x,y)
    call SetUnitFlyHeight(caster,z,0)
    if S2I(order) != 0 then
        set done=IssueTargetOrderById( caster, S2I(order), target )
    else
        set done=IssueTargetOrder( caster, order, target )
    endif
    if (delay<=0) or not(done) then
        call UnitRemoveAbility( caster, abilid)
        call RecicleCaster( caster)
    else
        call RecicleCasterAfterCastEx(caster, delay, abilid, true)
    endif
 set udg_currentcaster=caster
 set caster=null
 return udg_currentcaster
endfunction

//====================================================================================================================================================================
function CasterCastAbilityExLoc takes player owner, location loc, real z, integer abilid, integer level, string order, widget target, real delay returns unit
    return CasterCastAbilityEx(owner,GetLocationX(loc),GetLocationY(loc),z,abilid,level,order,target,delay)
endfunction

//====================================================================================================================================================================
function CasterCastAbilityLevel takes player owner, integer abilid, integer level, string order, widget target, boolean instant returns unit
 local real x
 local real y
 local real d
    if udg_sourcehack!=null then
        set x=GetLocationX(udg_sourcehack)
        set y=GetLocationY(udg_sourcehack)
    else
        set x=GetWidgetX(target)
        set y=GetWidgetY(target)
    endif
    if not(instant)  then
        set d=udg_delayhack+0.01
    else
        set d=0
    endif
 return CasterCastAbilityEx(owner,x,y,0,abilid,level,order,target,d)
endfunction

//====================================================================================================================================================================
function CasterCastAbility takes player owner, integer abilid, string order, widget target, boolean instant returns unit
    return CasterCastAbilityLevel( owner, abilid, 1, order, target, instant )
endfunction

//====================================================================================================================================================================
function CasterCastAbilityPointEx takes player owner, real x1, real y1, real z1, integer abilid, integer level, string order, real x2, real y2, real delay returns unit
 local unit caster=GetACaster()
    call SetUnitOwner( caster, owner, false)
    call UnitAddAbility( caster, abilid)
    call SetUnitAbilityLevel(caster,abilid,level)
    call SetUnitPosition( caster, x1, y1)
    call SetUnitFlyHeight(caster,z1,0)
    if S2I(order) != 0 then
        if not IssuePointOrderById( caster, S2I(order), x2,y2 ) then
            call IssueImmediateOrderById( caster, S2I(order) )
        endif
    else
        if not IssuePointOrder( caster, order, x2,y2 ) then
            call IssueImmediateOrder( caster, order )
        endif
    endif
    if (delay<=0) then
        call UnitRemoveAbility( caster, abilid)
        call RecicleCaster( caster)
    else
        call RecicleCasterAfterCastEx(caster, delay, abilid, true)
    endif
 set udg_currentcaster=caster
 set caster=null
 return udg_currentcaster
endfunction

//====================================================================================================================================================================
function CasterCastAbilityPointExLoc takes player owner, location loc1, real z1, integer abilid, integer level, string order, location loc2, real delay returns unit
    return CasterCastAbilityPointEx(owner,GetLocationX(loc1),GetLocationY(loc1),z1,abilid,level,order,GetLocationX(loc2),GetLocationY(loc2),delay)
endfunction

//====================================================================================================================================================================
function CasterCastAbilityLevelPoint takes player owner, integer abilid, integer level, string order, real x, real y, boolean instant returns unit
 local real sx
 local real sy
 local real d
    if udg_sourcehack!=null then
        set sx=GetLocationX(udg_sourcehack)
        set sy=GetLocationY(udg_sourcehack)
    else
        set sx=x
        set sy=y
    endif
    if instant then
        set d=0
    else
        set d=udg_delayhack+0.01
    endif
 return CasterCastAbilityPointEx(owner,sx,sy,0,abilid,level,order,x,y,d)
endfunction

function CasterCastAbilityPoint takes player owner, integer abilid, string order, real x, real y, boolean instant returns unit
    return CasterCastAbilityLevelPoint(owner,abilid,1,order,x,y,instant)
endfunction

function CasterCastAbilityPointLoc takes player owner, integer abilid, string order, location loc, boolean instant returns unit
    return CasterCastAbilityLevelPoint( owner, abilid, 1,order, GetLocationX(loc), GetLocationY(loc), instant )
endfunction

function CasterCastAbilityLevelPointLoc takes player owner, integer abilid, integer level, string order, location loc, boolean instant returns unit
    return CasterCastAbilityLevelPoint( owner, abilid, level,order, GetLocationX(loc), GetLocationY(loc), instant )
endfunction

//====================================================================================================================================================================
function CasterUseAbilityStatic_Child takes nothing returns nothing
 local unit caster=udg_currentcaster
 local effect fx=bj_lastCreatedEffect
 local integer abilid=udg_currentabi
    call PolledWait( udg_castervars[1])
    call DestroyEffect(fx)
    call UnitRemoveAbility(caster,abilid)
    call TriggerSleepAction(2)
    call RecicleCaster(caster)
 set fx=null
 set caster=null
endfunction

function CasterUseAbilityLevelStatic takes player owner, string modelpath, integer abilityid, integer level, real duration, real x, real y returns unit
    set udg_currentcaster=GetACaster()
    call SetUnitPosition( udg_currentcaster, x, y)
    set bj_lastCreatedEffect = AddSpecialEffectTarget( modelpath, udg_currentcaster,"origin" )
    set udg_castervars[1]=duration
    call SetUnitOwner( udg_currentcaster, owner, true)
    call UnitAddAbility( udg_currentcaster, abilityid)
    call SetUnitAbilityLevel( udg_currentcaster, abilityid, level)
    set udg_currentabi=abilityid
    call ExecuteFunc("CasterUseAbilityStatic_Child")
 return udg_currentcaster
endfunction

function CasterUseAbilityStatic takes player owner, string modelpath, integer abilityid, real duration, real x, real y returns unit
    return CasterUseAbilityLevelStatic(owner,modelpath,abilityid,1,duration,x,y)
endfunction

function CasterUseAbilityStaticLoc takes player owner, string modelpath, integer abilityid, real duration, location loc returns unit
    return CasterUseAbilityLevelStatic(owner,modelpath,abilityid,1,duration, GetLocationX(loc), GetLocationY(loc))
endfunction

function CasterUseAbilityLevelStaticLoc takes player owner, string modelpath, integer abilityid, integer level,real duration, location loc returns unit
    return CasterUseAbilityLevelStatic(owner,modelpath,abilityid,level,duration, GetLocationX(loc), GetLocationY(loc))
endfunction

//====================================================================================================================================================================
function CasterCastAbilityLevelGroup takes player owner, integer abilid, integer level,string order, group targetgroup, boolean instant returns nothing
 local group affected
 local unit tempunit
 local unit caster=null
    if bj_wantDestroyGroup then
        set bj_wantDestroyGroup=false
        set affected=targetgroup
    else
        set affected=CreateGroup()
        call GroupAddGroup( targetgroup, affected)
    endif
    loop
       set tempunit=FirstOfGroup(affected)
       exitwhen tempunit == null
       if instant then
           if caster==null then
               set caster=GetACaster()
               call SetUnitOwner( caster, owner, false)
               call UnitAddAbility( caster, abilid)
               call SetUnitAbilityLevel( caster, abilid,level)
           endif
           if udg_sourcehack != null then
               call SetUnitPositionLoc( caster, udg_sourcehack)
           else
               call SetUnitPosition( caster, GetUnitX(tempunit), GetUnitY(tempunit))
           endif

           if S2I(order) != 0 then
               call IssueTargetOrderById( caster, S2I(order), tempunit )
           else
               call IssueTargetOrder( caster, order, tempunit )
           endif
       else
           call CasterCastAbilityLevel( owner, abilid,level, order, tempunit, false)
       endif
       call GroupRemoveUnit(affected, tempunit)    
    endloop
    if caster != null then
        call UnitRemoveAbility( caster, abilid)
        call RecicleCaster(caster)
    endif
 call DestroyGroup(affected)
 set affected=null
 set tempunit=null
 set caster=null
endfunction

function CasterCastAbilityGroup takes player owner, integer abilid, string order, group targetgroup, boolean instant returns nothing
    call CasterCastAbilityLevelGroup(owner,abilid,1,order,targetgroup,instant)
endfunction

//====================================================================================================================================================================
function CasterAOE_IsFilterEnemy takes nothing returns boolean
    return IsUnitEnemy( GetFilterUnit(), bj_groupEnumOwningPlayer ) and not(IsUnitDeadBJ(GetFilterUnit()))
endfunction

function CasterAOE_IsFilterAlly takes nothing returns boolean
    return IsUnitAlly( GetFilterUnit(), bj_groupEnumOwningPlayer ) and not(IsUnitDeadBJ(GetFilterUnit()))
endfunction

//====================================================================================================================================================================
function CasterCastAbilityLevelAOE takes player owner, integer abilid, integer level, string order, real x, real y, real radius, boolean goodeffect, boolean instant returns nothing
 local boolexpr b
 local group aoe=CreateGroup()
    set bj_groupEnumOwningPlayer=owner
    if goodeffect then
        set b=Condition(function CasterAOE_IsFilterAlly)
    else
        set b=Condition(function CasterAOE_IsFilterEnemy)
    endif
    call GroupEnumUnitsInRange(aoe, x,y, radius, b)
    set bj_wantDestroyGroup=true
    call CasterCastAbilityLevelGroup( owner, abilid, level, order, aoe, instant)
 call DestroyBoolExpr(b)
 set b=null
 set aoe=null
endfunction

function CasterCastAbilityAOE takes player owner, integer abilid, string order, real x, real y, real radius, boolean goodeffect, boolean instant returns nothing
    call CasterCastAbilityLevelAOE(owner,abilid,1,order,x,y,radius,goodeffect,instant)
endfunction

function CasterCastAbilityAOELoc takes player owner, integer abilid, string order, location center, real radius, boolean goodeffect, boolean instant returns nothing
    call CasterCastAbilityLevelAOE(owner, abilid,1, order, GetLocationX(center),  GetLocationY(center), radius, goodeffect, instant)
endfunction

function CasterCastAbilityLevelAOELoc takes player owner, integer abilid, integer level, string order, location center, real radius, boolean goodeffect, boolean instant returns nothing
    call CasterCastAbilityLevelAOE(owner, abilid,level, order, GetLocationX(center),  GetLocationY(center), radius, goodeffect, instant)
endfunction

//====================================================================================================================================================================
function ResetSourceHack takes nothing returns nothing
    call RemoveLocation(udg_sourcehack)
    set udg_sourcehack=null
    call DestroyTimer(GetExpiredTimer() )
endfunction

function CasterSetCastSource takes real x, real y returns nothing
    set udg_sourcehack=Location(x,y)
    call TimerStart(CreateTimer(),0,false,function ResetSourceHack)
endfunction

function CasterSetCastSourceLoc takes location loc returns nothing
    call CasterSetCastSource( GetLocationX(loc), GetLocationY(loc) )
endfunction

function ResetDelayHack takes nothing returns nothing
    set udg_delayhack=0
    call DestroyTimer(GetExpiredTimer() )
endfunction

//====================================================================================================================================================================
function CasterSetRecycleDelay takes real Delay returns nothing
    set udg_delayhack=Delay
    call TimerStart(CreateTimer(),0,false,function ResetDelayHack)
endfunction

//====================================================================================================================================================================
function DamageTypes takes attacktype attT, damagetype dmgT returns integer
    set udg_castervars[100] = CS_H2I(attT)
    set udg_castervars[101] = CS_H2I(dmgT)
 return 1
endfunction

function DamageException takes unittype Exception, real ExceptionFactor returns integer
    set udg_castervars[102] = CS_H2I(Exception)
    set udg_castervars[103] = ExceptionFactor
 return 2
endfunction

function DamageOnlyTo takes unittype ThisUnitType returns integer
    set udg_castervars[104] = CS_H2I(ThisUnitType)
 return 4
endfunction

constant function DontDamageSelf takes nothing returns integer
 return 8
endfunction

constant function DamageTrees takes nothing returns integer
 return 16
endfunction

constant function DamageOnlyVisibles takes nothing returns integer
 return 32
endfunction

function DamageOnlyEnemies takes nothing returns integer
    set udg_castervars[105]=0
 return 64
endfunction

function ForceDamageAllies takes nothing returns integer
    set udg_castervars[105]=1
 return 64
endfunction

function DamageOnlyAllies takes nothing returns integer
    set udg_castervars[105]=2
 return 64
endfunction

function DamageFactorAbility1 takes integer spellid, real factor returns integer
    set udg_castervars[106]=CS_Rawcode2Real(spellid)
    set udg_castervars[107]=factor
 return 128
endfunction

function DamageFactorAbility2 takes integer spellid, real factor returns integer
    set udg_castervars[108]=CS_Rawcode2Real(spellid)
    set udg_castervars[109]=factor
 return 256
endfunction

function DamageFactorAbility3 takes integer spellid, real factor returns integer
    set udg_castervars[110]=CS_Rawcode2Real(spellid)
    set udg_castervars[111]=factor
 return 512
endfunction

function DamageIgnore takes unittype ThisUnitType returns integer
    set udg_castervars[112] = CS_H2I(ThisUnitType)
 return 1024
endfunction

function DamageAlliedFactor takes real fct returns integer
    set udg_castervars[113] = fct
 return 2048
endfunction


//===============================================================================================
function CS_IsUnitVisible takes unit u, player p returns boolean
     return IsUnitVisible(u,Player(bj_PLAYER_NEUTRAL_VICTIM)) or IsUnitVisible(u,p)
endfunction

//=================================================================================================
function GetDamageFactor takes unit u,attacktype a, damagetype d returns real
 local real hp=GetWidgetLife(u)
 local real r
 local unit caster=GetACaster()
    call UnitRemoveAbility(caster,'Aloc') //Otherwise the units would flee like crazy
    call SetUnitPosition(caster,GetUnitX(u),GetUnitY(u))
    call SetUnitOwner(caster,GetOwningPlayer(u),false)
    call UnitDamageTarget(caster,u,0.01,true,false,a,d,null)
    call RecicleCaster(caster)
    set r= (hp-GetWidgetLife(u))*100
    call SetWidgetLife(u,hp)
 return r
endfunction

//======================================================================================================
// Fix for the unit type bugs from blizzard, amphibious units aren't considered ground for some reason
// so this considers any non flying unit as ground.
//
// Also heroes are resistant too, so in case UNIT_TYPE_RESISTANT is used it will return true in case the
// unit is a hero too.
//
function CS_IsUnitType takes unit u, unittype ut returns boolean
    if (ut==UNIT_TYPE_GROUND) then
        return not(IsUnitType(u,UNIT_TYPE_FLYING))
    elseif (ut==UNIT_TYPE_RESISTANT) then
        return IsUnitType(u,ut) or IsUnitType(u,UNIT_TYPE_HERO)
    endif
 return IsUnitType(u,ut)
endfunction

function GetDamageFactorByOptions takes unit hurter, unit target, integer DamageOptions returns real
 local real r=1
 local integer d=DamageOptions
    if (GetWidgetLife(target)<1) then
        return 0.0
    endif
    if d>=2048 then
        if IsUnitAlly(target,GetOwningPlayer(hurter)) then
            set r=r*udg_castervars[113]
        endif
        set d=d-2048
    endif
    if d>=1024 then
        if CS_IsUnitType(target, ConvertUnitType(R2I(udg_castervars[112])) ) then
            return 0.0
        endif
        set d=d-1024
    endif
    if d>=512 then
        if GetUnitAbilityLevel(target,CS_LoadRawcodeFromReal(110))>0 then
            set r=r*udg_castervars[111]
        endif
        set d=d-512
    endif
    if d>=256 then
        if GetUnitAbilityLevel(target,CS_LoadRawcodeFromReal(108))>0 then
            set r=r*udg_castervars[109]
        endif
        set d=d-256
    endif
    if d>=128 then
        if GetUnitAbilityLevel(target,CS_LoadRawcodeFromReal(106))>0 then
            set r=r*udg_castervars[107]
        endif
        set d=d-128
    endif
    if d>=64 then
        if (udg_castervars[105]==0) and IsUnitAlly(target,GetOwningPlayer(hurter)) then
            return 0.0
        elseif (udg_castervars[105]==2) and IsUnitEnemy(target,GetOwningPlayer(hurter)) then
            return 0.0
        endif
        set d=d-64
    endif
    if d>=32 then
        set d=d-32
        if not CS_IsUnitVisible(target,GetOwningPlayer(hurter)) then
            return 0.0
        endif
    endif
    if d>=16 then
        set d=d-16
    endif
    if d>=8 then
        set d=d-8
        if hurter==target then
            return 0.0
        endif
    endif
    if d>=4 then
        set d=d-4
        if not CS_IsUnitType( target, ConvertUnitType(R2I(udg_castervars[104])) ) then
            return 0.0
        endif
    endif
    if d>=2 then
        set d=d-2
        if CS_IsUnitType( target, ConvertUnitType(R2I(udg_castervars[102])) ) then
            set r=r*udg_castervars[103]
        endif
    endif
    if d>=1 then
        set d=d-1
        set r=r*GetDamageFactor(target,ConvertAttackType(R2I(udg_castervars[100])),ConvertDamageType(R2I(udg_castervars[101])))
    endif
 return r
endfunction

//======================================================================================================================
// This used to be needed because in 1.17 UnitDamageTarget didn't consider the damagetype argument, this bug
// was fixed in 1.18, and we no longer need this function, left for compatibility.
//
function DamageUnitByTypes takes unit hurter, unit target, real dmg, attacktype attT, damagetype dmgT returns boolean
    return UnitDamageTarget(hurter,target,dmg,true,false,attT,dmgT,null)
endfunction

//=============================================================================================================================
function DamageUnitByOptions takes unit hurter, unit target, real dmg, integer DamageOptions returns boolean
 local real f=GetDamageFactorByOptions(hurter,target,DamageOptions)
    if (f==0) then
        return false
    endif
 return UnitDamageTarget(hurter,target,dmg*f,true,false,null,null,null)
endfunction

//=============================================================================================================================
function DamageUnit takes player hurter, real damage, unit victim returns boolean
 local unit caster=GetACaster()
    call UnitRemoveAbility(caster,'Aloc') //Otherwise the units would flee like crazy
    call SetUnitPosition(caster,GetUnitX(victim),GetUnitY(victim))
    call SetUnitOwner(caster,hurter,false)
    call DamageUnitByTypes(caster,victim,damage,Caster_DefaultAttackType(),Caster_DefaultDamageType())
    call RecicleCaster(caster)
 return GetWidgetLife(victim)<=0 // I thought UnitDamageTarget returned true when it killed the unit, but nope, it returns true when it was able to do the damage.
endfunction

//====================================================================================================================================================================
function UnitDamageUnitTimed_Child takes nothing returns nothing
 local real damage = udg_castervars[0]
 local real damageperiod= udg_castervars[2]
 local effect fx=bj_lastCreatedEffect
 local timer t=CreateTimer()
 local unit hurter=udg_currenthurter
 local real next=0
 local integer i=0
 local real c
 local unit target=udg_currentcaster
 local damagetype dmgT=ConvertDamageType(R2I(udg_castervars[4]))
 local attacktype attT=ConvertAttackType(R2I(udg_castervars[3]))

    call TimerStart(t, udg_castervars[1]-0.01, false,null)
    loop
        if TimerGetElapsed(t) >= next then
            exitwhen not UnitDamageTarget(hurter, target, damage,true,false, attT, dmgT,null)
            exitwhen IsUnitDeadBJ(target)
            set i=i+1
            set next=i*damageperiod
        endif
        exitwhen (TimerGetRemaining(t) <= 0) or IsUnitDeadBJ(target)
        call TriggerSleepAction(0)
    endloop
 call DestroyEffect(fx)
 call DestroyTimer(t)
 set t=null
 set fx=null
 set dmgT=null
 set attT=null
endfunction

function UnitDamageUnitTimed takes unit hurter, real damageps, real damageperiod, real duration, unit target, string modelpath, string attachPointName, attacktype attT, damagetype dmgT returns nothing
 local unit c=udg_currentcaster
    set bj_lastCreatedEffect=AddSpecialEffectTarget( modelpath, target,attachPointName )
    set udg_currentcaster=target
    set udg_castervars[0]=damageps
    set udg_castervars[1]=duration
    set udg_castervars[2]=damageperiod
    set udg_castervars[3]=CS_H2I(attT)
    set udg_castervars[4]=CS_H2I(dmgT)
    set udg_currenthurter=hurter
    call ExecuteFunc("UnitDamageUnitTimed_Child")
    set udg_currentcaster=c
 set c=null
endfunction

//=============================================================================================================
// Left for compatibility
//
function DamageUnitTimedEx_Child takes nothing returns nothing
 local real damage = udg_castervars[0]
 local real damageperiod= udg_castervars[2]
 local effect fx=bj_lastCreatedEffect
 local timer t=CreateTimer()
 local integer id=udg_currentabi
 local real next=0
 local integer i=0
 local real c
 local unit target=udg_currentcaster
    call TimerStart(t, udg_castervars[1]-0.01, false,null)
    loop
        if TimerGetElapsed(t) >= next then
            exitwhen DamageUnit( Player(id), damage, target)
            set i=i+1
            set next=i*damageperiod
        endif
        exitwhen (TimerGetRemaining(t) <= 0) or IsUnitDeadBJ(target)
        call TriggerSleepAction(0)
    endloop
 call DestroyEffect(fx)
 call DestroyTimer(t)
 set t=null
 set fx=null
endfunction

function DamageUnitTimedEx takes player owner, real damageps, real damageperiod, real duration, unit target, string modelpath, string attachPointName returns nothing
 local unit c=udg_currentcaster
    set bj_lastCreatedEffect=AddSpecialEffectTarget( modelpath, target,attachPointName )
    set udg_currentcaster=target
    set udg_castervars[0]=damageps
    set udg_castervars[1]=duration
    set udg_castervars[2]=damageperiod
    set udg_currentabi=GetPlayerId( owner )
    call ExecuteFunc("DamageUnitTimedEx_Child")
    set udg_currentcaster=c
 set c=null
endfunction

function DamageUnitTimed takes player owner, real damageps, real duration, unit target, string modelpath, string attachPointName returns nothing
    call DamageUnitTimedEx(owner , damageps, 1, duration, target, modelpath, attachPointName )
endfunction

function SetDamageOptions_i takes gamecache g, integer n, integer DamageOptions returns nothing
 local string key="DOPT"+I2S(n)
 local integer d=DamageOptions
    call StoreInteger(g,key,"value",d)
    if d>=2048 then
        call StoreReal(g,key,"allf",udg_castervars[113])
        set d=d-2048
    endif
    if d>=1024 then
        call StoreInteger(g,key,"ign",R2I(udg_castervars[112]))
        set d=d-1024
    endif
    if d>=512 then
        call StoreInteger(g,key,"ab3",CS_LoadRawcodeFromReal(110))
        call StoreReal(g,key,"fc3",udg_castervars[111])
        set d=d-512
    endif
    if d>=256 then
        call StoreInteger(g,key,"ab2",CS_LoadRawcodeFromReal(108))
        call StoreReal(g,key,"fc2",udg_castervars[109])
        set d=d-256
    endif
    if d>=128 then
        call StoreInteger(g,key,"ab1",CS_LoadRawcodeFromReal(106))
        call StoreReal(g,key,"fc1",udg_castervars[107])
        set d=d-128
    endif
    if d >= 64 then
        set d=d-64
        call StoreInteger(g,key,"allied",R2I(udg_castervars[105]))
    endif
    if d >= 32 then
        set d=d-32
    endif
    if d >= 16 then
        set d=d-16
    endif
    if d >= 8 then
        set d=d-8
    endif
    if d >= 4 then
        call StoreInteger(g,key,"only",R2I(udg_castervars[104]))
        set d=d-4
    endif
    if d >= 2 then
        call StoreInteger(g,key,"excp",R2I(udg_castervars[102]))
        call StoreReal(g,key,"excf",udg_castervars[103])
        set d=d-2
    endif
    if d >= 1 then
        call StoreInteger(g,key,"attT",R2I(udg_castervars[100]))
        call StoreInteger(g,key,"dmgT",R2I(udg_castervars[101]))
    endif
endfunction

function SetDamageOptions takes integer id, integer DamageOptions returns nothing
    call SetDamageOptions_i(CSCache(),id,DamageOptions)
endfunction

function CreateDamageOptions takes integer DamageOptions returns integer
 local gamecache g=CSCache()
 local integer n=GetStoredInteger(g,"misc","DOPTn")+1
    call StoreInteger(g,"misc","DOPTn",n)
    call SetDamageOptions_i(g,n,DamageOptions)
 set g=null
 return n
endfunction

function DestroyDamageOptions takes integer id returns nothing
    call FlushStoredMission(CSCache(),"DOPT"+I2S(id))
endfunction

function LoadDamageOptions takes integer id returns integer
 local gamecache g=CSCache()
 local string key="DOPT"+I2S(id)
 local integer opt=GetStoredInteger(g,key,"value")
 local integer v=opt
    if v>=2048 then
        set udg_castervars[113]=GetStoredReal(g,key,"allf")
        set v=v-2028
    endif
    if v>=1024 then
        set udg_castervars[112]= GetStoredInteger(g,key,"ign")
        set v=v-1024
    endif
    if v>=512 then
        set udg_castervars[110]=CS_Rawcode2Real(GetStoredInteger(g,key,"ab3"))
        set udg_castervars[111]=GetStoredReal(g,key,"fc3")
        set v=v-512
    endif
    if v>=256 then
        set udg_castervars[108]=CS_Rawcode2Real(GetStoredInteger(g,key,"ab2"))
        set udg_castervars[109]=GetStoredReal(g,key,"fc2")
        set v=v-256
    endif
    if v>=128 then
        set udg_castervars[106]=CS_Rawcode2Real(GetStoredInteger(g,key,"ab1"))
        set udg_castervars[107]=GetStoredReal(g,key,"fc1")
        set v=v-128
    endif
    if v >= 64 then
        set v=v-64
        set udg_castervars[105]= GetStoredInteger(g,key,"allied")
    endif
    if v >= 32 then
        set v=v-32
    endif
    if v >= 16 then
        set v=v-16
    endif
    if v >= 8 then
        set v=v-8
    endif
    if v >= 4 then
        set udg_castervars[104]=GetStoredInteger(g,key,"only")
        set v=v-4
    endif
    if v >= 2 then
        set udg_castervars[102]=GetStoredInteger(g,key,"excp")
        set udg_castervars[103]=GetStoredReal(g,key,"excf")
        set v=v-2
    endif
    if v >= 1 then
        set udg_castervars[100]=GetStoredInteger(g,key,"attT")
        set udg_castervars[101]=GetStoredInteger(g,key,"dmgT")
    endif
 set g=null
 return opt
endfunction

//==================================================================================================
function IsDestructableTree_withcs takes destructable d returns boolean
 local unit c=GetACaster()
 local boolean b
 local boolean i=IsDestructableInvulnerable(d)
 local integer s=DamageTreeDetectorId()
    if i then
        call SetDestructableInvulnerable(d,false)
    endif
    call UnitAddAbility(c,s)
    call SetUnitPosition(c,GetWidgetX(d),GetWidgetY(d))
    set b=(IssueTargetOrder(c,"eattree",d))
    call UnitRemoveAbility(c,s)
    call RecicleCaster(c)
    set c=null
    if i then
        call SetDestructableInvulnerable(d,true)
    endif
 return b 
endfunction

function IsDestructableTree takes destructable d returns boolean
 local gamecache g=CSCache()
 local string k=I2S(GetDestructableTypeId(d))
 local boolean b

    if HaveStoredBoolean(g,"trees",k) then
        set b=GetStoredBoolean(g,"trees",k)
        set g=null
        return b
    else
        set b=IsDestructableTree_withcs(d)
        call StoreBoolean(g,"trees",k,b)
    endif
 set g=null
 return b
endfunction

//===============================================================================================
function DamageDestructablesInCircleEnum takes nothing returns nothing
 local destructable d=GetEnumDestructable()
 local unit u=udg_currentcaster
    if (GetWidgetLife(d)>0) and not(IsDestructableInvulnerable(d)) and (SquareRoot(Pow(GetDestructableX(d)-udg_castervars[200],2)+Pow(GetDestructableY(d)-udg_castervars[201],2)) <= udg_castervars[202]) then
        call SetWidgetLife(d,GetWidgetLife(d)-udg_castervars[203])
    endif
 set udg_currentcaster=u
 set u=null
 set d=null
endfunction

function DamageDestructablesInCircle takes real x, real y, real radius, real dmg returns nothing
 local rect r=Rect(x - radius,y - radius,x + radius,y + radius)
    set udg_castervars[200]=x
    set udg_castervars[201]=y
    set udg_castervars[202]=radius
    set udg_castervars[203]=dmg
    call EnumDestructablesInRect(r,null,function DamageDestructablesInCircleEnum)
 call RemoveRect(r)
 set r=null
endfunction

function DamageDestructablesInCircleLoc takes location loc, real radius, real dmg returns nothing
    call DamageDestructablesInCircle(GetLocationX(loc),GetLocationY(loc),radius,dmg)
endfunction

function DamageTreesInCircleEnum takes nothing returns nothing
 local destructable d=GetEnumDestructable()
    if (GetWidgetLife(d)>0) and not(IsDestructableInvulnerable(d)) and (SquareRoot(Pow(GetDestructableX(d)-udg_castervars[200],2)+Pow(GetDestructableY(d)-udg_castervars[201],2)) <= udg_castervars[202]) and (IsDestructableTree(d)) then
        call KillDestructable(d)
    endif
 set d=null
endfunction

function DamageTreesInCircle takes real x, real y, real radius returns nothing
 local rect r=Rect(x - radius,y - radius,x + radius,y + radius)
    set udg_castervars[200]=x
    set udg_castervars[201]=y
    set udg_castervars[202]=radius
    call EnumDestructablesInRect(r,null,function DamageTreesInCircleEnum)
 call RemoveRect(r)
 set r=null
endfunction

function DamageTreesInCircleLoc takes location loc, real radius returns nothing
    call DamageTreesInCircle(GetLocationX(loc),GetLocationY(loc),radius)
endfunction

function DamageUnitGroupEx takes unit hurter, real damage, group targetgroup, integer DamageOptions returns nothing
 local group affected
 local unit p
    if bj_wantDestroyGroup then
        set bj_wantDestroyGroup=false
        set affected=targetgroup
    else
        set affected=CreateGroup()
        call GroupAddGroup( targetgroup, affected)
    endif
    loop
        set p=FirstOfGroup(affected)
        exitwhen p==null
        call DamageUnitByOptions(hurter,p,damage,DamageOptions)
        call GroupRemoveUnit(affected,p)
    endloop
 call DestroyGroup(affected)
 set affected=null
 set p=null
endfunction

function DamageUnitsInAOEEx takes unit hurter, real damage, real x, real y, real radius, boolean affectallied, integer DamageOptions returns nothing
 local boolexpr b=null
 local group aoe=CreateGroup()
 local integer d=DamageOptions
    set bj_groupEnumOwningPlayer=GetOwningPlayer(hurter)
    if d>=2048 then
        set d=d-2048
    endif
    if d>=1024 then
        set d=d-1024
    endif
    if d>=512 then
        set d=d-512
    endif
    if d>=256 then
        set d=d-256
    endif
    if d>=128 then
        set d=d-128
    endif
    if d>=64 then
        if     (udg_castervars[105]==2) then
            set b=Condition(function CasterAOE_IsFilterAlly)
        elseif (udg_castervars[105]==1) then
        else
            set b=Condition(function CasterAOE_IsFilterEnemy)
        endif
        set d=d-64
    elseif not(affectallied) then
        set b=Condition(function CasterAOE_IsFilterEnemy)
    endif
    if d>=32 then
        set d=d-32
    endif
    if d>=16 then
        call DamageTreesInCircle(x,y,radius)
    endif
    call GroupEnumUnitsInRange(aoe, x,y, radius, b)
    set bj_wantDestroyGroup=true
    call DamageUnitGroupEx( hurter, damage, aoe,DamageOptions)
 call DestroyBoolExpr(b)
 set b=null
 set aoe=null
endfunction

function DamageUnitsInAOEExLoc takes unit hurter, real damage, location loc, real radius, boolean affectallied, integer DamageOptions returns nothing
    call DamageUnitsInAOEEx(hurter,damage, GetLocationX(loc), GetLocationY(loc), radius, affectallied,DamageOptions)
endfunction

function DamageUnitGroup takes player hurter, real damage, group targetgroup returns nothing
 local unit caster=GetACaster()
    call UnitRemoveAbility(caster,'Aloc') //Otherwise the units would flee like crazy
    call SetUnitOwner(caster,hurter,false)
    call DamageUnitGroupEx(caster,damage,targetgroup,0)
 call RecicleCaster(caster)
 set caster=null
endfunction

//====================================================================================================================================================================
function DamageUnitsInAOE takes player hurter, real damage, real x, real y, real radius, boolean affectallied returns nothing
 local unit caster=GetACaster()
    call UnitRemoveAbility(caster,'Aloc') //Otherwise the units would flee like crazy
    call SetUnitOwner(caster,hurter,false)
    call DamageUnitsInAOEEx(caster,damage,x,y,radius,affectallied,0)
 call RecicleCaster(caster)
 set caster=null
endfunction

function DamageUnitsInAOELoc takes player hurter, real damage, location loc, real radius, boolean affectallied returns nothing
    call DamageUnitsInAOE( hurter, damage, GetLocationX(loc), GetLocationY(loc), radius, affectallied)
endfunction

//====================================================================================================================================================================
function AddAreaDamagerForUnit_Child takes nothing returns nothing
 local real D
 local real damageps = udg_castervars[0]
 local real area = udg_castervars[2]
 local real damageperiod = udg_castervars[3]
 local real excd=udg_castervars[8]
 local boolean affectallies = (udg_castervars[4]>=1)
 local boolean onlyallies = (udg_castervars[4]==2)
 local boolean self = (udg_castervars[5]==1)
 local effect fx = bj_lastCreatedEffect
 local unit hurter=udg_currenthurter
 local unit fire = udg_currentcaster
 local player owner = GetOwningPlayer(fire)
 local timer t = CreateTimer()
 local real next = 0
 local integer a = 0
 local group inrange = CreateGroup()
 local string c
 local string art=bj_lastPlayedMusic
 local string attach=""
 local unit picked
 local boolean recicled=false
 local unittype only=null
 local unittype ign=null
 local unittype exce=null
 local attacktype attT
 local damagetype dmgT
 local boolean trees=(udg_castervars[11]==1)
 local boolean inv=(udg_castervars[12]==1)
 local integer a1=0
 local integer a2=0
 local integer a3=0
 local real f1=udg_castervars[107]
 local real f2=udg_castervars[109]
 local real f3=udg_castervars[111]
 local real allf=udg_castervars[113]
    if f1!=1 then
        set a1=CS_LoadRawcodeFromReal(106)
    endif
    if f2!=1 then
        set a2=CS_LoadRawcodeFromReal(108)
    endif
    if f3!=1 then
        set a3=CS_LoadRawcodeFromReal(110)
    endif
    if udg_castervars[112]!=-1 then
        set ign=ConvertUnitType(R2I(udg_castervars[112]))
    endif
    if udg_castervars[6]!=-1 then
        set only=ConvertUnitType(R2I(udg_castervars[6]))
    endif
    if udg_castervars[7]!=-1 then
        set exce=ConvertUnitType(R2I(udg_castervars[7]))    
    endif
    if udg_castervars[9]!=-1 then
        set attT=ConvertAttackType(R2I(udg_castervars[9]))
    else
        set attT=Caster_DefaultAttackType()
    endif
    if udg_castervars[10]!=-1 then
        set dmgT=ConvertDamageType(R2I(udg_castervars[10]))
    else
        set dmgT=Caster_DefaultDamageType()
    endif
    loop
        set c=SubString(art,a,a+1)
        exitwhen c=="!" or c==""
        set attach=attach+c
        set a=a+1
    endloop
    set art=SubString(art,a+1,10000)
    call TimerStart(t, udg_castervars[1]-0.01, false,null)
    set a=0
    loop
        if IsUnitInGroup( fire, udg_casters) then
            set recicled=true
            call GroupRemoveUnit( udg_casters,fire)
        endif
        exitwhen recicled
        if TimerGetElapsed(t) >= next then
            set a=a+1
            set next=a*damageperiod
            call GroupEnumUnitsInRange(inrange, GetUnitX(fire), GetUnitY(fire), area, null )
            if trees then
                call DamageTreesInCircle(GetUnitX(fire), GetUnitY(fire), area)
            endif
            loop
                set picked=FirstOfGroup(inrange)
                exitwhen picked==null
                if (self or picked!=hurter) and not(IsUnitDeadBJ(picked)) and ( ((affectallies or onlyallies) and IsUnitAlly(picked, owner)) or (not(onlyallies) and IsUnitEnemy(picked, owner)) ) and (only==null or CS_IsUnitType(picked,only)) and (ign==null or not(CS_IsUnitType(picked,ign))) then
                    set D=damageps
                    if (allf!=1) and IsUnitAlly(picked, owner) then
                        set D=D*allf
                    endif
                    if (exce!=null) and CS_IsUnitType(picked,exce) then
                        set D=D*excd
                    endif
                    if inv and not(CS_IsUnitVisible(picked,owner)) then
                        set D=0
                    endif
                    if (a1!=0) and (GetUnitAbilityLevel(picked,a1)>0) then
                        set D=D*f1
                    endif
                    if (a2!=0) and (GetUnitAbilityLevel(picked,a2)>0) then
                        set D=D*f2
                    endif
                    if (a3!=0) and (GetUnitAbilityLevel(picked,a3)>0) then
                        set D=D*f3
                    endif
                    if D!=0 then
                        call UnitDamageUnitTimed(hurter,D,damageperiod,damageperiod,picked,art,attach,attT,dmgT)
                    endif
                endif
                call GroupRemoveUnit(inrange,picked)
            endloop
        endif
        exitwhen TimerGetRemaining(t)<=0
        call TriggerSleepAction(0)
    endloop
 call DestroyGroup(inrange)
 call DestroyEffect(fx)
 call TriggerSleepAction(2)
 call RecicleCaster(fire)
 call DestroyTimer(t)
 set inrange=null
 set fire=null
 set t=null
 set owner=null
 set fx=null
 set picked=null
 set hurter=null
 set only=null
 set ign=null
 set exce=null
 set attT=null
 set dmgT=null
endfunction

function AddAreaDamagerForUnit takes unit hurter, string modelpath, string targetart, string targetattach, real x, real y, real damage , real damageperiod, real duration, real area, boolean affectallies, integer DamageOptions returns unit
 local string s=bj_lastPlayedMusic
 local integer v=DamageOptions
    set bj_lastPlayedMusic=targetattach+"!"+targetart
    set udg_currentcaster=GetACaster()
    call SetUnitPosition( udg_currentcaster, x, y)
    set bj_lastCreatedEffect = AddSpecialEffectTarget( modelpath, udg_currentcaster,"origin" )
    set udg_castervars[0]=damage
    set udg_castervars[1]=duration
    set udg_castervars[2]=area
    set udg_castervars[3]=damageperiod
    if v>=2048 then
        set v=v-2048
    else
        set udg_castervars[113]=1
    endif
    if v >= 1024 then
        set v=v-1024
    else
        set udg_castervars[112]=-1
    endif
    if v >= 512 then
        set v=v-512
    else
        set udg_castervars[111]=0
    endif
    if v >= 256 then
        set v=v-256
    else
        set udg_castervars[109]=0
    endif
    if v >= 128 then
        set v=v-128
    else
        set udg_castervars[107]=0
    endif
    if v >= 64 then
        set v=v-64
        set udg_castervars[4]=udg_castervars[105]
    else
        set udg_castervars[4]=IntegerTertiaryOp(affectallies,1,0)
    endif
    if v >= 32 then
        set udg_castervars[12]=1
        set v=v-32
    else
        set udg_castervars[12]=0
    endif
    if v >= 16 then
        set udg_castervars[11]=1
        set v=v-16
    else
        set udg_castervars[11]=0
    endif
    if v >= 8 then
        set udg_castervars[5]=0
        set v=v-8
    else
        set udg_castervars[5]=1
    endif
    if v >= 4 then
        set udg_castervars[6]=udg_castervars[104]
        set v=v-4
    else
        set udg_castervars[6]=-1
    endif
    if v >= 2 then
        set udg_castervars[7]=udg_castervars[102]
        set udg_castervars[8]=damage*udg_castervars[103]
        set v=v-2
    else
        set udg_castervars[7]=-1
        set udg_castervars[8]=-1
    endif
    if v >= 1 then
        set udg_castervars[9]=udg_castervars[100]
        set udg_castervars[10]=udg_castervars[101]
    else
        set udg_castervars[9]=-1
        set udg_castervars[10]=-1
    endif
    set udg_currenthurter=hurter
    call SetUnitOwner( udg_currentcaster, GetOwningPlayer(hurter), true)
    call ExecuteFunc("AddAreaDamagerForUnit_Child")
    set bj_lastPlayedMusic=s
 return udg_currentcaster
endfunction

function AddAreaDamagerForUnitLoc takes unit hurter, string modelpath, string targetart, string targetattach, location loc, real damage , real damageperiod, real duration, real area, boolean affectallies, integer DamageOptions returns unit
 return AddAreaDamagerForUnit(hurter,modelpath,targetart,targetattach,GetLocationX(loc),GetLocationY(loc), damage , damageperiod, duration, area,affectallies, DamageOptions)
endfunction

function AddDamagingEffectEx takes player owner, string modelpath, string targetart, string targetattach, real x, real y, real damage , real damageperiod, real duration, real area, boolean affectallies returns unit
 local string s=bj_lastPlayedMusic
    set bj_lastPlayedMusic=targetattach+"!"+targetart
    set udg_currentcaster=GetACaster()
    call SetUnitPosition( udg_currentcaster, x, y)
    set bj_lastCreatedEffect = AddSpecialEffectTarget( modelpath, udg_currentcaster,"origin" )
    set udg_castervars[0]=damage
    set udg_castervars[1]=duration
    set udg_castervars[2]=area
    set udg_castervars[3]=damageperiod
    set udg_castervars[4]=IntegerTertiaryOp(affectallies,1,0)
    set udg_castervars[5]=1
    set udg_castervars[6]=-1
    set udg_castervars[7]=-1
    set udg_castervars[8]=-1
    set udg_castervars[9]=-1
    set udg_castervars[10]=-1
    set udg_castervars[107]=0
    set udg_castervars[109]=0
    set udg_castervars[111]=0
    set udg_castervars[112]=-1
    set udg_castervars[113]=1
    set udg_currenthurter=udg_currentcaster
    call SetUnitOwner( udg_currentcaster, owner, true)
    call ExecuteFunc("AddAreaDamagerForUnit_Child")
    set bj_lastPlayedMusic=s
 return udg_currentcaster
endfunction

function AddDamagingEffectExLoc takes player owner, string modelpath, string targetart, string targetattach, location loc, real damage , real damageperiod, real duration, real area, boolean affectallies returns unit
    return AddDamagingEffectEx( owner, modelpath, targetart, targetattach, GetLocationX(loc), GetLocationY(loc), damage , damageperiod, duration, area, affectallies )
endfunction

function AddDamagingEffect takes player owner, string modelpath, real x, real y, real damageps , real duration, real area, boolean affectallies returns unit
    return AddDamagingEffectEx( owner, modelpath, "", "", x, y, damageps , 1, duration, area, affectallies )
endfunction

function AddDamagingEffectLoc takes player owner, string modelpath, location loc, real damageps , real duration, real area, boolean affectallies returns unit
    return AddDamagingEffectEx( owner, modelpath, "", "", GetLocationX(loc), GetLocationY(loc), damageps ,1, duration, area, affectallies)
endfunction

//============================================================================================================
constant function CS_Cycle takes nothing returns real
    return 0.04
endfunction

function UnitMoveToAsProjectileAnySpeed_Timer takes nothing returns nothing
 local timer t=GetExpiredTimer()
 local boolean tounit = GetAttachedBoolean(t,"unit")
 local unit tg
 local real x2
 local real y2
 local real z2
 local unit m=GetAttachedUnit(t,"m")
 local real x1=GetUnitX(m)
 local real y1=GetUnitY(m)
 local real z1=GetUnitFlyHeight(m)
 local real g
 local real d
 local real v
 local real time
 local integer n
    if tounit then
        set tg=GetAttachedUnit(t,"tg")
        if (GetWidgetLife(tg)<1) then
            set tounit=false
            call AttachBoolean(t,"unit",false)
        else
            set x2=GetUnitX(tg)
            set y2=GetUnitY(tg)
            set z2=GetUnitFlyHeight(tg)+GetAttachedReal(t,"z2o")
            set n=GetAttachedInt(t,"N")
            if (n>=25) then
                //I have the tilt writing on gamecache is slower than reading, in that case I prevent writting
                // these 3 reals, but use a counter so each second they are backuped.
                // They are needed because if the unit dies or is removed, they would otherwise go to the
                // center of the map, and that is not something nice.
                call AttachReal(t,"z2",z2)
                call AttachReal(t,"x2",x2) // Backup stuff just in case
                call AttachReal(t,"y2",y2)
                set n=0
            endif
            call AttachInt(t,"N",n)
        endif
        set tg=null
    endif
    if not(tounit) then
        set z2=GetAttachedReal(t,"z2")
        set x2=GetAttachedReal(t,"x2")
        set y2=GetAttachedReal(t,"y2")
    endif

    set g=Atan2(y2-y1,x2-x1)
    call SetUnitFacing(m,g*bj_RADTODEG)
    set v=GetAttachedReal(t,"speed") //xy speed
    set d= CS_Cycle() * v
    call SetUnitPosition(m , x1+d*Cos(g), y1+d*Sin(g) )
    set g=GetAttachedReal(t,"acel")
    set time= SquareRoot( Pow(x1-x2,2) + Pow(y1-y2,2) ) / v
    set v=(z2-z1+0.5*g*time*time)/time //z speed
    call SetUnitFlyHeight(m,z1+v*CS_Cycle(),0)
    set d=SquareRoot( Pow(GetUnitX(m)-x2,2) + Pow(GetUnitY(m)-y2,2) )
    if (d<=20) then
        call AttachBoolean(t,"done",true)
    else
        call TimerStart(t,CS_Cycle(),false,function UnitMoveToAsProjectileAnySpeed_Timer)
    endif
 set m=null
 set t=null
endfunction

function UnitMoveToAsProjectileAnySpeed takes unit m, real speed, real arc, real x2, real y2, unit target, real z2 returns nothing
//
//   The internal projectile system used by all the projectile functions
//
 local timer t=CreateTimer()
    if (target!=null) then
        call AttachBoolean(t,"unit",true)
        call AttachObject(t,"tg",target)
        call AttachReal(t,"x2",GetUnitX(target))
        call AttachReal(t,"y2",GetUnitY(target))
        call AttachReal(t,"z2o",z2)
    else
        call AttachReal(t,"x2",x2)
        call AttachReal(t,"y2",y2)
    endif
    call AttachReal(t,"z2",z2)
    call AttachReal(t,"speed",speed)
    call AttachReal(t,"acel",arc*8000)
    call AttachObject(t,"m",m)
    call TimerStart(t,CS_Cycle(),false,function UnitMoveToAsProjectileAnySpeed_Timer)
    loop
        exitwhen GetAttachedBoolean(t,"done")
        call TriggerSleepAction(0)
    endloop
    call CleanAttachedVars(t)
    call DestroyTimer(t)
 set t=null 
endfunction

//========================================================================================================================
function UnitMoveToAsProjectileGen takes unit m, real arc, real x2, real y2, unit target, real z2 returns nothing
//
//   The internal projectile system used by all the projectile functions
//
 local real x1=GetUnitX(m)
 local real y1=GetUnitY(m)
 local real acel=arc*1600
 local real speed=GetUnitMoveSpeed(m) 
 local real z1=GetUnitFlyHeight(m)
 local real d
 local real d1
 local real d2
 local real t
 local real vel
 local real dif=0
 local boolean tounit= (target!=null)
 local boolean b=false
 local boolean mode=false
    if tounit then
        set x2=GetUnitX(target)
        set y2=GetUnitY(target)
        set z2=GetUnitFlyHeight(target)+z2
    endif
    set mode=(z2>z1)
    set d=SquareRoot(Pow(x2-x1,2)+Pow(y2-y1,2))
    set d1=1000000
    set d2=0
    set t=d/speed
    if t==0 then
        set t=0.001
    endif
    set vel=(z2-z1+0.5*acel*t*t)/t
    call SetUnitFacing( m, Atan2BJ(y2 - y1, x2 - x2) )
    call IssuePointOrder( m, "move", x2,y2)
    set t=0
    loop
        set d2=d1
        if tounit then
            if IsUnitDeadBJ(target) then
                set tounit=false
            else
                set x2=GetUnitX(target)
                set y2=GetUnitY(target)
            endif
        endif
        set d1=SquareRoot(Pow(x2-GetUnitX(m),2)+Pow(y2-GetUnitY(m),2))
        exitwhen b or d1==0
        set b=(d1<=speed*(t-dif))
        exitwhen (mode and b) or (GetUnitCurrentOrder(m) != OrderId("move"))
        if tounit then
            call IssuePointOrder( m, "move", x2,y2)
        endif
        set dif=t
        if dif==0.001 then
           set t=0.1
        else
            set t= (d-d1)/speed
        endif
        set t= 2*t-dif
        call SetUnitFlyHeight( m, z1+(vel*t-0.5*acel*t*t), RAbsBJ( vel-acel*(t+dif)/2) )
        set t=(t+dif)/2
        call TriggerSleepAction(0)
    endloop
    if tounit then
        set x2=GetUnitX(target)
        set y2=GetUnitY(target)
    endif
    call SetUnitFlyHeight( m,z2,0)
    call SetUnitPosition(m,x2,y2)
endfunction

function UnitMoveToAsProjectile takes unit m, real arc, real x2, real y2, real z2 returns nothing
    call UnitMoveToAsProjectileGen(m, arc,x2,y2,null,z2)
endfunction

//============================================================================================================
function ProjectileLaunchEx takes player owner, string modelpath, real scale, integer red, integer green, integer blue, integer alpha, real speed, real arc,real x1, real y1, real z1, real x2, real y2, real z2 returns nothing
 local unit m=AddCasterFacing( Atan2BJ(y2 - y1, x2 - x1) )
 local effect fx=null
    call SetUnitPosition( m, x1,y1)
    call SetUnitScale( m, scale, scale, scale)
    call SetUnitVertexColor(m, red, green, blue, alpha)

    call SetUnitFlyHeight( m, z1, 0)
    set fx= AddSpecialEffectTarget( modelpath, m,"origin" )
    call SetUnitOwner( m, owner, true)

    if (speed<=522) then
        call SetUnitMoveSpeed(m, speed)
        call UnitMoveToAsProjectile(m, arc, x2, y2, z2)
    else
        call UnitMoveToAsProjectileAnySpeed(m,speed,arc,x2,y2,null,z2)
    endif
    call DestroyEffect(fx)
    call ExplodeUnitBJ(m)
 set owner=null
 set fx=null
 set m=null
endfunction

function ProjectileLaunchExLoc takes player owner, string modelpath, real scale, integer red, integer green, integer blue, integer alpha, real speed, real arc, location loc1, real z1, location loc2, real z2 returns nothing
    call ProjectileLaunchEx( owner, modelpath, scale, red, green, blue, alpha, speed, arc,GetLocationX(loc1), GetLocationY(loc1), z1, GetLocationX(loc2), GetLocationY(loc2), z2)
endfunction

//============================================================================================================
function ProjectileLaunch takes string modelpath, real speed, real arc,real x1, real y1, real z1, real x2, real y2, real z2 returns nothing
    call ProjectileLaunchEx( Player(15), modelpath, 1, 255, 255, 255, 255, speed, arc,x1,y1,z1,x2,y2,z2)
endfunction

function ProjectileLaunchLoc takes string modelpath, real speed, real arc, location loc1, real z1, location loc2, real z2 returns nothing
    call ProjectileLaunchExLoc( Player(15), modelpath, 1,255,255,255,255,speed,arc,loc1,z1,loc2,z2)
endfunction

//============================================================================================================
function DamagingProjectileLaunchAOE_Child takes nothing returns nothing
 local unit m=udg_currentcaster
 local effect fx=bj_lastCreatedEffect
 local real x2=udg_castervars[0]
 local real y2=udg_castervars[1]
 local real aoeradius=udg_castervars[3]
 local real damage=udg_castervars[4]
 local boolean affectallied=bj_isUnitGroupInRectResult
 local integer V=CreateDamageOptions(R2I(udg_castervars[5]))
 local unit hurter=udg_currenthurter
 local real speed=udg_castervars[6]
    if (speed<=522) then
        call SetUnitMoveSpeed(m, speed)
        call UnitMoveToAsProjectile(m, bj_meleeNearestMineDist, udg_castervars[0], udg_castervars[1], udg_castervars[2])
    else
        call UnitMoveToAsProjectileAnySpeed(m,speed,bj_meleeNearestMineDist, udg_castervars[0], udg_castervars[1],null, udg_castervars[2])
    endif
    call DestroyEffect(fx)
    call DamageUnitsInAOEEx(hurter,damage,x2,y2,aoeradius,affectallied,LoadDamageOptions(V))
    call DestroyDamageOptions(V)
    call ExplodeUnitBJ(m)
 set m=null
 set fx=null
endfunction

function DamagingProjectileLaunchAOE takes unit hurter, string modelpath, real speed, real arc, real x1, real y1, real z1, real x2, real y2, real z2, real aoeradius, real damage, boolean affectallied, integer DamageOptions returns unit
 local unit m=AddCasterFacing( Atan2BJ(y2 - y1, x2 - x1) )
    call SetUnitPosition(m, x1,y1)
    call SetUnitFlyHeight( m, z1, 0)
    set udg_currentcaster=m
    set bj_lastCreatedEffect=AddSpecialEffectTarget( modelpath, m,"origin" )
    call SetUnitOwner( m, GetOwningPlayer(hurter), true)
    set bj_meleeNearestMineDist = arc
    set udg_castervars[0] = x2
    set udg_castervars[1] = y2
    set udg_castervars[2] = z2
    set udg_castervars[3] =aoeradius
    set udg_castervars[4] =damage
    set udg_castervars[5] =DamageOptions
    set udg_castervars[6] =speed
    set udg_currenthurter=hurter
    call ExecuteFunc("DamagingProjectileLaunchAOE_Child")
 set m=null
 return udg_currentcaster
endfunction

function DamagingProjectileLaunchAOELoc takes unit hurter, string modelpath, real speed, real arc, location loc1, real z1, location loc2, real z2, real aoeradius, real damage, boolean affectallied, integer DamageOptions returns unit
    return DamagingProjectileLaunchAOE(hurter,modelpath,speed,arc,GetLocationX(loc1),GetLocationY(loc1),z1,GetLocationX(loc2),GetLocationY(loc2),z2, aoeradius, damage, affectallied, DamageOptions )
endfunction

function ProjectileLaunchDamage takes player owner, string modelpath, real speed, real arc, real x1, real y1, real z1, real x2, real y2, real z2, real aoeradius, real damage, boolean affectallied returns unit
 local unit m=AddCasterFacing( Atan2BJ(y2 - y1, x2 - x1) )
    call SetUnitPosition(m, x1,y1)
    call SetUnitFlyHeight( m, z1, 0)
    set udg_currentcaster=m
    set bj_lastCreatedEffect=AddSpecialEffectTarget( modelpath, m,"origin" )
    call SetUnitOwner( m, owner, true)
    set bj_meleeNearestMineDist = arc
    set udg_castervars[0] = x2
    set udg_castervars[1] = y2
    set udg_castervars[2] = z2
    set udg_castervars[3] =aoeradius
    set udg_castervars[4] =damage
    set udg_castervars[5] =0
    set udg_castervars[6]= speed

    set bj_isUnitGroupInRectResult=affectallied
    set udg_currenthurter=m
    call ExecuteFunc("DamagingProjectileLaunchAOE_Child")
 set m=null
 return udg_currentcaster
endfunction

function ProjectileLaunchDamageLoc takes player owner, string modelpath, real speed, real arc, location loc1, real z1, location loc2, real z2, real aoeradius, real damage, boolean affectallied returns unit
    return ProjectileLaunchDamage( owner, modelpath, speed, arc, GetLocationX(loc1), GetLocationY(loc1), z1, GetLocationX(loc2), GetLocationY(loc2), z2, aoeradius, damage, affectallied) 
endfunction

//============================================================================================================
function ProjectileLaunchKill_Child takes nothing returns nothing
 local unit m=udg_currentcaster
 local effect fx=bj_lastCreatedEffect
 local real x2=udg_castervars[0]
 local real y2=udg_castervars[1]
 local real speed=udg_castervars[3]

    if (speed<=522) then
        call SetUnitMoveSpeed( m, speed)
        call UnitMoveToAsProjectile(m, bj_meleeNearestMineDist, udg_castervars[0], udg_castervars[1], udg_castervars[2])
    else
        call UnitMoveToAsProjectileAnySpeed(m,speed, bj_meleeNearestMineDist, udg_castervars[0], udg_castervars[1], null, udg_castervars[2])
    endif

    call ExplodeUnitBJ(m)
    call DestroyEffect( fx)
 set m=null
 set fx=null
endfunction

function ProjectileLaunchKill takes player owner, string modelpath, real speed, real arc, real x1, real y1, real z1, real x2, real y2, real z2 returns unit
 local unit m=AddCasterFacing( Atan2BJ(y2 - y1, x2 - x1) )
    call SetUnitPosition(m, x1,y1)

    call SetUnitFlyHeight( m, z1, 0)
    set udg_currentcaster=m
    set bj_lastCreatedEffect=AddSpecialEffectTarget( modelpath, m,"origin" )
    call SetUnitOwner( m, owner, true)
    set bj_meleeNearestMineDist = arc
    set udg_castervars[0] = x2
    set udg_castervars[1] = y2
    set udg_castervars[2] = z2
    set udg_castervars[3] = speed
    call ExecuteFunc("ProjectileLaunchKill_Child")
 set m=null
 return udg_currentcaster
endfunction

function ProjectileLaunchKillLoc takes player owner, string modelpath, real speed, real arc, location loc1, real z1, location loc2, real z2 returns unit
    return ProjectileLaunchKill( owner, modelpath, speed, arc, GetLocationX(loc1), GetLocationY(loc1), z1, GetLocationX(loc2), GetLocationY(loc2), z2)
endfunction

//====================================================================================================================================================================
function UnitMoveToUnitAsProjectile takes unit m, real arc, unit target, real zoffset returns nothing
    call UnitMoveToAsProjectileGen(m, arc,0,0,target,zoffset)
endfunction

//====================================================================================================================================================================
function ProjectileLaunchToUnitEx takes player owner, string modelpath, real scale, integer red, integer green, integer blue, integer alpha, real speed, real arc, real x1, real y1, real z1, unit target, real zoffset returns nothing
 local unit m=AddCasterFacing( Atan2BJ(GetUnitY(target) - y1, GetUnitX(target) - x1) )
 local effect fx=null
    call SetUnitPosition( m, x1,y1)
    call SetUnitFlyHeight( m, z1, 0)
    call SetUnitScale( m, scale, scale, scale)
    call SetUnitVertexColor(m, red, green, blue, alpha)
    set fx=AddSpecialEffectTarget( modelpath, m,"origin" )
    call SetUnitOwner( m , owner, true)

    if (speed<=522) then
        call SetUnitMoveSpeed( m, speed)
        call UnitMoveToUnitAsProjectile(m,arc,target, zoffset)
    else
        call UnitMoveToAsProjectileAnySpeed(m,speed, arc,0,0,target,zoffset)
    endif
    call DestroyEffect(fx)
    call ExplodeUnitBJ(m)
 set m=null
 set fx=null
endfunction

function ProjectileLaunchToUnitExLoc takes player owner, string modelpath, real scale, integer red, integer green, integer blue, integer alpha, real speed, real arc, location loc1, real z1, unit target, real zoffset returns nothing
    call ProjectileLaunchToUnitEx( owner, modelpath, scale, red, green, blue, alpha, speed, arc, GetLocationX(loc1),GetLocationY(loc1), z1, target, zoffset)
endfunction

function ProjectileLaunchToUnit takes string modelpath, real speed, real arc,real x1, real y1, real z1, unit target, real zoffset returns nothing
    call ProjectileLaunchToUnitEx( Player(15), modelpath, 1, 255,255,255,255,speed,arc,x1,y1,z1,target,zoffset)
endfunction

function ProjectileLaunchToUnitLoc takes string modelpath, real speed, real arc, location loc1, real z1, unit target, real zoffset returns nothing
    call ProjectileLaunchToUnitExLoc( Player(15), modelpath, 1, 255,255,255,255, speed, arc, loc1, z1, target,zoffset)
endfunction

//====================================================================================================================================================================
function DamagingProjectileLaunchTarget_Child takes nothing returns nothing
 local unit m=udg_currentcaster
 local unit target=bj_meleeNearestMine
 local effect fx=bj_lastCreatedEffect
 local real damage=udg_castervars[4]
 local damagetype dmgT=ConvertDamageType(R2I(udg_castervars[6]))
 local attacktype attT=ConvertAttackType(R2I(udg_castervars[5]))
 local unit hurter=udg_currenthurter
 local real speed=udg_castervars[7]
    if (speed<=522) then
        call SetUnitMoveSpeed( m, speed)
        call UnitMoveToUnitAsProjectile(m, bj_meleeNearestMineDist, target, udg_castervars[2])
    else
        call UnitMoveToAsProjectileAnySpeed(m,speed, bj_meleeNearestMineDist,0,0,target,udg_castervars[2])
    endif
    call DestroyEffect( fx)
    call DamageUnitByTypes(hurter,target,damage,attT,dmgT)
    call ExplodeUnitBJ(m)
 set m=null
 set hurter=null
 set target=null
 set fx=null
 set dmgT=null
 set attT=null
endfunction

function DamagingProjectileLaunchTarget takes unit hurter, string modelpath, real speed, real arc, real x1, real y1, real z1, unit target, real zoffset, real damage, attacktype attT, damagetype dmgT returns unit
 local unit m=AddCasterFacing( Atan2BJ(GetUnitY(target) - y1, GetUnitX(target) - x1) )
    call SetUnitPosition(m, x1,y1)
    set udg_castervars[7]=speed
    call SetUnitFlyHeight( m, z1, 0)
    set udg_currentcaster=m
    set bj_lastCreatedEffect=AddSpecialEffectTarget( modelpath, m,"origin" )
    call SetUnitOwner( m, GetOwningPlayer(hurter), true)
    set bj_meleeNearestMineDist = arc
    set udg_castervars[2]= zoffset
    set bj_meleeNearestMine=target
    set udg_castervars[4]=damage
    set udg_castervars[5]=CS_H2I(attT)
    set udg_castervars[6]=CS_H2I(dmgT)
    set udg_currenthurter=hurter
    call ExecuteFunc("DamagingProjectileLaunchTarget_Child")
 set m=null
 return udg_currentcaster
endfunction

function DamagingProjectileLaunchTargetLoc takes unit hurter, string modelpath, real speed, real arc, location loc, real z1, unit target, real zoffset, real damage, attacktype attT, damagetype dmgT returns unit
    return DamagingProjectileLaunchTarget(hurter,modelpath,speed,arc,GetLocationX(loc),GetLocationY(loc), z1, target, zoffset, damage, attT, dmgT)
endfunction

function ProjectileLaunchToUnitDamage takes player owner, string modelpath, real speed, real arc, real x1, real y1, real z1, unit target, real zoffset, real damage returns unit
 local unit m=AddCasterFacing( Atan2BJ(GetUnitY(target) - y1, GetUnitX(target) - x1) )
    call SetUnitPosition(m, x1,y1)
    set udg_castervars[7]=speed
    call SetUnitFlyHeight( m, z1, 0)
    set udg_currentcaster=m
    set bj_lastCreatedEffect=AddSpecialEffectTarget( modelpath, m,"origin" )
    call SetUnitOwner( m, owner, true)
    set bj_meleeNearestMineDist = arc
    set udg_castervars[2]= zoffset
    set bj_meleeNearestMine=target
    set udg_castervars[4]=damage
    set udg_castervars[5]=CS_H2I(Caster_DefaultAttackType())
    set udg_castervars[6]=CS_H2I(Caster_DefaultDamageType())
    set udg_currenthurter=m
    call ExecuteFunc("DamagingProjectileLaunchTarget_Child")
 set m=null
 return udg_currentcaster
endfunction

function ProjectileLaunchToUnitDamageLoc takes player owner, string modelpath, real speed, real arc, location loc1, real z1, unit target, real zoffset, real damage returns unit
    return ProjectileLaunchToUnitDamage( owner, modelpath, speed, arc,GetLocationX(loc1),GetLocationY(loc1),z1,target,zoffset,damage)
endfunction

//==================================================================================================
function IsPointWater takes real x, real y returns boolean
    return IsTerrainPathable(x,y,PATHING_TYPE_WALKABILITY) and not(IsTerrainPathable(x,y,PATHING_TYPE_AMPHIBIOUSPATHING))
endfunction

function IsPointWaterLoc takes location loc returns boolean
    return IsPointWater(GetLocationX(loc),GetLocationY(loc))
endfunction

//==================================================================================================
function IsUnitSpellImmune takes unit u returns boolean
    return IsUnitType(u,UNIT_TYPE_MAGIC_IMMUNE)
endfunction

function IsUnitImmuneToPhisical takes unit u returns boolean
    return (GetDamageFactor(u,ATTACK_TYPE_CHAOS,DAMAGE_TYPE_DEMOLITION)==0)
endfunction

function IsUnitInvulnerable takes unit u returns boolean
    return (GetDamageFactor(u,ATTACK_TYPE_CHAOS,DAMAGE_TYPE_UNIVERSAL)==0)
endfunction
//##End##

//##Start##
//==================================================================================================
function H2I takes handle h returns integer
    return h
    return 0
endfunction

//==================================================================================================
function LocalVars takes nothing returns gamecache
    return InitGameCache("jasslocalvars.w3v")
endfunction

//==================================================================================================
function SetHandleInt takes handle subject, string name, integer value returns nothing
    if value==0 then
        call FlushStoredInteger(LocalVars(),I2S(H2I(subject)),name)
    else
        call StoreInteger(LocalVars(), I2S(H2I(subject)), name, value)
    endif
endfunction

//==================================================================================================
function SetHandleReal takes handle subject, string name, real value returns nothing
    if value==0 then
        call FlushStoredReal(LocalVars(), I2S(H2I(subject)), name)
    else
        call StoreReal(LocalVars(), I2S(H2I(subject)), name, value)
    endif
endfunction

//==================================================================================================
function SetHandleHandle takes handle subject, string name, handle value returns nothing
    call SetHandleInt( subject, name, H2I(value) )
endfunction

//==================================================================================================
function GetHandleHandle takes handle subject, string name returns handle
    return GetStoredInteger(LocalVars(), I2S(H2I(subject)), name)
    return null
endfunction

//==================================================================================================
function GetHandleInt takes handle subject, string name returns integer
    return GetStoredInteger(LocalVars(), I2S(H2I(subject)), name)
endfunction

//==================================================================================================
function GetHandleReal takes handle subject, string name returns real
    return GetStoredReal(LocalVars(), I2S(H2I(subject)), name)
endfunction

//==================================================================================================
function FlushHandleLocals takes handle subject returns nothing
    call FlushStoredMission(LocalVars(), I2S(H2I(subject)) )
endfunction
//##End##

//##Start##
//***************************************************************************************************
//*
//*  SimError: Simulates an Error message for a player, requires:
//*
//*     If you don't have this function in your map yet, then copy the SimError function 
//*  (starting with the //##Start## and ending with the //#End## TO YOUR MAP's CUSTOM
//*  SCRIPT SECTION, (it is at the top of the trigger list in the trigger editor)
//*
//*  (If you have other stuff in the custom script section like the caster system just insert
//* this function below the contents of your custom script section)
//*
//*  (If you already have this function in your map don't copy this one)
//*
//***************************************************************************************************

//===================================================================================================
function SimError takes player ForPlayer, string msg returns nothing
 local sound error=CreateSoundFromLabel( "InterfaceError",false,false,false,10,10)
    if (GetLocalPlayer() == ForPlayer) then
        if (msg!="") and (msg!=null) then
            call ClearTextMessages()
            call DisplayTimedTextToPlayer( ForPlayer, 0.52, -1.00, 2.00, "|cffffcc00"+msg+"|r" )
        endif
        call StartSound( error )
    endif
 call KillSoundWhenDone( error)
 set error=null
endfunction
//##end##

//##Start##
//**************************************************************************************************
//*
//*  UnitGuardUnitAI Function (Controls all the Diablo 2 summons system)
//*
//*     To implement this function, you must select the contents of this trigger starting
//*   with the //##Start## and finishing with the  //##End##, and copy that TO YOUR MAP's
//*   CUSTOM SCRIPT SECTION, (it is at the top of the trigger list in the trigger editor)
//*
//*     DON'T JUST COPY THE TRIGGER; copy this to the custom script section
//*
//*     (If you already have this functions in your map don't copy this one)
//*
//**************************************************************************************************

//=================================================================================================
//
// http://www.wc3jass.com : The place with tons of JASS scripts
//
//=================================================================================================

//==================================================================================================
//  Unit Guard AI Configuration: (Added this section so you can easily customize the ai without
//  ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯  Messing with the functions, just replace the numbers)
//
constant function UnitGuardUnitAI_maxdelay takes nothing returns real
    return 2.5 //* The max delay betwen orders issued to the summon
endfunction

constant function UnitGuardUnitAI_mindelay takes nothing returns real
    return 1.00 //* The min delay betwen orders issued to the summon
endfunction

constant function UnitGuardUnitAI_maxdistance takes nothing returns real
    return 1000.0 //* If the distance betwen the summon and the master is greater than this value,
                  //  The summon will move to the position of the master instead of attack move
endfunction

constant function UnitGuardUnitAI_cometomaxdist takes nothing returns real
    return 500.0 //* Max distance for issued orders to approach the master
endfunction

constant function UnitGuardUnitAI_cometomindist takes nothing returns real
    return 100.0 //* Min distance for issued orders to approach the master
endfunction

//==================================================================================================
function GuardUnit_GetSummonMaster takes unit u returns unit
    return GetAttachedObject(u, "master")
endfunction

function GuardUnitOrder takes unit summon, unit master returns nothing
 local integer o=GetUnitCurrentOrder(summon)
 local real tx=GetUnitX(master)
 local real ty=GetUnitY(master)
 local real angle
 local real dist

    set dist=SquareRoot(Pow(tx-GetUnitX(summon),2) + Pow(ty-GetUnitY(summon),2))
    if (dist > UnitGuardUnitAI_maxdistance() )  and (o == 0 or o == OrderId("attack") or o == OrderId("move") or o == OrderId("stop") or o==851971) then
        call IssuePointOrder(summon, "move", tx,ty) 
    elseif dist >= UnitGuardUnitAI_cometomindist() and (o == 0 or o == 851971) then
        set angle = GetRandomReal( GetUnitFacing(master)-80, GetUnitFacing(master)+80) * IntegerTertiaryOp( ModuloInteger( GetUnitPointValue(summon), 2) == 0,1,-1)
        set dist = GetRandomReal(UnitGuardUnitAI_cometomindist(), UnitGuardUnitAI_cometomaxdist() )
        set tx=tx+dist*CosBJ(angle)
        set ty=ty+dist*SinBJ(angle)
        if not IssuePointOrder(summon, "attack", tx, ty ) then
            call IssuePointOrder(summon, "move", tx, ty )
        endif
    endif
 set summon=null
 set master=null
endfunction

function UnitGuardUnitAI_Smart_Order_timer takes nothing returns nothing
 local timer t=GetExpiredTimer()
 local unit s=GetAttachedUnit(t,"summon")
    if (GetUnitCurrentOrder(s)!=851971) then
        call CleanAttachedVars(t)
        call DestroyTimer(t)
    else
        call GuardUnitOrder( s, GetAttachedUnit(s,"master"))
        call TimerStart(t,0.1,false,function UnitGuardUnitAI_Smart_Order_timer)
    endif
 set t=null
endfunction


function UnitGuardUnitAI_Smart_Order_Actions takes nothing returns nothing
 local timer t

    if (GetIssuedOrderId() == 851971) then
        set t=CreateTimer()
        call AttachObject(t,"summon",GetTriggerUnit())
        call TimerStart(t,0,false,function UnitGuardUnitAI_Smart_Order_timer)
        set t=null
    endif

endfunction

function UnitGuardUnitAI_loop takes nothing returns nothing
// Executed in another thread
 local unit summon=bj_ghoul[0]  
 local unit master=GetAttachedUnit(summon,"master")
 local trigger smart=CreateTrigger()
 local integer n=0
 local triggeraction ac=TriggerAddAction( smart, function UnitGuardUnitAI_Smart_Order_Actions)

    call TriggerRegisterUnitEvent( smart, summon, EVENT_UNIT_ISSUED_TARGET_ORDER )
    call TriggerRegisterUnitEvent( smart, summon, EVENT_UNIT_ISSUED_POINT_ORDER )
    loop
        exitwhen (GetWidgetLife(summon)<=0)
        call GuardUnitOrder( summon, master)
        call PolledWait( GetRandomReal( UnitGuardUnitAI_mindelay(), UnitGuardUnitAI_maxdelay() ))
    endloop

    call CleanAttachedVars(summon)
    call TriggerRemoveAction(smart,ac)
    call DestroyTrigger(smart)

 set ac=null
 set summon=null
 set master=null
 set smart=null
endfunction

function UnitGuardUnitAI takes unit summon, unit master returns nothing
 local unit a=bj_ghoul[0]

    call AttachObject( summon, "master", master)
    set bj_ghoul[0]=summon
    call ExecuteFunc("UnitGuardUnitAI_loop")
    set bj_ghoul[0]=a

 set a=null
endfunction
//##End##

//##Start##
//*************************************************************************************************
//*
//*  Special Events ( http://vexorian.wc3campaigns.com/templates/ )
//*
//* Requires:
//*          - udg_spellevents gamecache variable
//*
//*    To be able to use Special Events in your map, make sure you have the udg_spellevents
//*  gamecache variable, Either use the "Variable Copying Trigger" or create it with your
//*  WE's variable editor.
//*
//*    After that, you have to copy this to your map's custom script section!
//* (The Custom Script Section Is at the top of the list of the triggers and has the Map's name.)
//*
//*    Select the text from the //##Start## to the //##End## and copy it to the custom script
//* section that is at the top of the trigger list and has your map's name.
//*
//*    After copying them and saving in your map, you need to call SetupSpecialEvents() at map
//*  Initialization in order to allow the system to work. (check next trigger)
//*
//*    If you already have them in your map, Delete the ones in your map, then copy these ones,
//*  this is a new version that fixes some memory leaks that were blizzard's fault, also the
//*  Special Events functions have a new option.
//*
//*   In theory, you may just copy the trigger, making sure it is above any other trigger, then
//* Instantly save, this is easier, but may not work well.
//*
//*************************************************************************************************

//==================================================================================================
//
// For more JASS scripts, visit : http://www.wc3JASS.com
//
//==================================================================================================

//==================================================================================================
function Eventscache takes nothing returns gamecache
    if (udg_spellevents==null) then
        call FlushGameCache(InitGameCache("spellevents.vx"))
        set udg_spellevents=InitGameCache("spellevents.vx")

        call ExecuteFunc("SpecialEvents_Init")
    endif
 return udg_spellevents
endfunction

function GetPassiveAbilityUser takes nothing returns unit
    return GetStoredInteger(Eventscache(),"passives","unit")
    return null
endfunction

function GetPassiveAbilityId takes nothing returns integer
    return GetStoredInteger(Eventscache(),"passives","current")
endfunction

function events_H2I takes handle h returns integer
    return h
    return 0
endfunction

function PassiveAbilitiesPrepare takes nothing returns nothing
 local gamecache g=Eventscache()
 local integer n=GetStoredInteger(g,"passives","n")
 local integer i=1
 local integer array p
 local string array s
 local unit u
 local group a=CreateGroup()
    loop
        exitwhen (i>n)
        set p[i]=GetStoredInteger(g,"passives",I2S(i))
        set s[i]=GetStoredString(g,"spelllearnfuncs", I2S(p[i]))
        set i=i+1
    endloop
    call GroupEnumUnitsInRect(a,bj_mapInitialPlayableArea,null)
    loop
        set u=FirstOfGroup(a)
        exitwhen (u==null)
        set i=1
        call StoreInteger(g,"passives","unit",events_H2I(u))
        loop
            exitwhen (i>n)
            if (GetUnitAbilityLevel(u,p[i])>0) then
                call StoreInteger(g,"passives","current",p[i])
                call ExecuteFunc(s[i])
            endif
            set i=i+1
        endloop
        call GroupRemoveUnit(a,u)
    endloop  
 set a=null
endfunction

//==================================================================================================
function PassiveAbilityBrowse takes gamecache g, unit u, string k returns nothing
 local integer n=GetStoredInteger(g,"passives","n")
 local integer un=0
 local integer i=1
 local integer s
    call StoreInteger(g,"passives","unit",events_H2I(u))
    loop
        exitwhen (i>n)
        set s=GetStoredInteger(g,"passives",I2S(i))
        if (GetUnitAbilityLevel(u,s)>0) then
            set un=un+1
            call StoreInteger(g,"passiveREG"+I2S(un),k,s)
            call StoreInteger(g,"passives","current",s)
            call ExecuteFunc(GetStoredString(g,"spelllearnfuncs",I2S(s)))
        endif
        set i=i+1
    endloop
    if (un==0) then
        call StoreBoolean(g,"pasignore",k,true)
    else
        call StoreInteger(g,"passiveREGN",k,un)
    endif
endfunction

function DoPassiveAbilities takes gamecache g, unit u, string k returns nothing
 local integer n=GetStoredInteger(g,"passiveREGN",k)
 local integer i=1
 local integer s
    call StoreInteger(g,"passives","unit",events_H2I(u))
    loop
        exitwhen (i>n)
        set s=GetStoredInteger(g,"passiveREG"+I2S(i),k)
        if (GetUnitAbilityLevel(u,s)>0) then
            call StoreInteger(g,"passives","current",s)
            call ExecuteFunc(GetStoredString(g,"spelllearnfuncs",I2S(s)))
        endif
        set i=i+1
    endloop
endfunction

function PassiveAbilitiesOnCreated takes gamecache g, unit u, string k returns nothing
    if HaveStoredInteger(g,"passiveREGN",k) then
        call DoPassiveAbilities(g,u,k)
    else
        call PassiveAbilityBrowse(g,u,k)
    endif      
endfunction

//==================================================================================================
function Trig_SpecialEvents_Actions takes nothing returns nothing
 local unit u=GetTriggerUnit()
 local eventid e=GetTriggerEventId()
 local gamecache sp=Eventscache()
 local integer s
 local string k

    if (e==EVENT_PLAYER_UNIT_SPELL_EFFECT) then
        set k=I2S(GetSpellAbilityId())
        if HaveStoredString( sp, "spellfuncs",k) then
            call ExecuteFunc( GetStoredString( sp, "spellfuncs",k))
        endif

    elseif (e==EVENT_PLAYER_UNIT_SPELL_CAST) then
        set k=I2S(GetSpellAbilityId())
        if HaveStoredString( sp, "castfuncs", k) then
            call ExecuteFunc( GetStoredString( sp, "castfuncs",k))
        endif

    elseif (e==EVENT_PLAYER_HERO_SKILL) then
        set s=GetLearnedSkill()
        set k=I2S(s)
        if HaveStoredString( sp, "spelllearnfuncs",k) then
            call StoreInteger(sp,"passives","unit",events_H2I(u))
            call StoreInteger(sp,"passives","current",s)
            call ExecuteFunc( GetStoredString( sp, "spelllearnfuncs",k))
        endif

    elseif (e==EVENT_PLAYER_UNIT_SUMMON) then
        set k=I2S(GetUnitTypeId( GetSummonedUnit() ))
        if HaveStoredString( sp, "unitfuncs",k) then
            call ExecuteFunc( GetStoredString( sp, "unitfuncs", k))
        endif

    elseif (e==EVENT_PLAYER_UNIT_USE_ITEM) then
        set k=I2S( GetItemTypeId( GetManipulatedItem() ))
        if HaveStoredString( sp, "itemfuncs", k) then
            call ExecuteFunc(GetStoredString(sp,"itemfuncs",k))
        endif

    elseif (e==EVENT_PLAYER_UNIT_PICKUP_ITEM) then
        set k=I2S( GetItemTypeId( GetManipulatedItem() ))
        if HaveStoredString( sp, "itemgetfuncs", k) then
            call ExecuteFunc(GetStoredString( sp, "itemgetfuncs",k))
        endif

    else
        set k=I2S(GetUnitTypeId(u))
        if not(HaveStoredBoolean(sp,"pasignore",k)) then
            call PassiveAbilitiesOnCreated(sp,u,k)
        endif
    endif
 set u=null
 set e=null
 set sp=null
endfunction




//==================================================================================================
// Call This Function at map initialization if you want the whole thing to work.
//
function SetupSpecialEvents takes nothing returns nothing
    call Eventscache() //Left For compat
endfunction

function SpecialEvents_Init takes nothing returns nothing
 local trigger trig=CreateTrigger()
 local integer i = 0
    loop
        call TriggerRegisterPlayerUnitEvent(trig, Player(i),EVENT_PLAYER_UNIT_SPELL_EFFECT, null)
        call TriggerRegisterPlayerUnitEvent(trig, Player(i),EVENT_PLAYER_UNIT_SUMMON, null)
        call TriggerRegisterPlayerUnitEvent(trig, Player(i),EVENT_PLAYER_UNIT_USE_ITEM, null)
        call TriggerRegisterPlayerUnitEvent(trig, Player(i),EVENT_PLAYER_UNIT_PICKUP_ITEM, null)
        call TriggerRegisterPlayerUnitEvent(trig, Player(i),EVENT_PLAYER_HERO_SKILL, null)
        call TriggerRegisterPlayerUnitEvent(trig, Player(i),EVENT_PLAYER_UNIT_SPELL_CAST, null)
        set i=i+1
        exitwhen i==bj_MAX_PLAYER_SLOTS
    endloop
    call TriggerRegisterEnterRectSimple(trig,bj_mapInitialPlayableArea)
    call TriggerAddAction(trig,function Trig_SpecialEvents_Actions)
    call TimerStart(CreateTimer(),0,false,function PassiveAbilitiesPrepare)
 set trig=null
endfunction






//==================================================================================================
// Registers the function to be executed when the effect of an ability is started:
//
function RegisterAbilityEvent takes integer abilid, string funcname returns nothing
    call StoreString( Eventscache(), "spellfuncs", I2S(abilid), funcname)
endfunction

//==================================================================================================
// Registers the function to be executed when an ability is about to be casted
//
function RegisterAbilityPreCastEvent takes integer abilid, string funcname returns nothing
    call StoreString( Eventscache(), "castfuncs", I2S(abilid), funcname)
endfunction

//==================================================================================================
// Registers the function to be executed when an ability is learned:
//   
function RegisterAbilityLearnEvent takes integer abilid, string funcname returns nothing
    call StoreString( Eventscache(), "spelllearnfuncs", I2S(abilid), funcname)
endfunction

//==================================================================================================
// Registers the function to be executed when an ability is learned:
//   
function RegisterPassiveAbility takes integer abilid, string funcname returns nothing
 local gamecache g=Eventscache()
 local integer n=GetStoredInteger(g,"passives","n")+1
    call StoreString( Eventscache(), "spelllearnfuncs", I2S(abilid), funcname)
    call StoreInteger(g,"passives","n",n)
    call StoreInteger(g,"passives",I2S(n),abilid)   
 set g=null
endfunction

//##Start##
//*************************************************************************************************
//*
//*  Special Events ( http://vexorian.wc3campaigns.com/templates/ )
//*
//* Requires:
//*          - udg_spellevents gamecache variable
//*
//*    To be able to use Special Events in your map, make sure you have the udg_spellevents
//*  gamecache variable, Either use the "Variable Copying Trigger" or create it with your
//*  WE's variable editor.
//*
//*    After that, you have to copy this to your map's custom script section!
//* (The Custom Script Section Is at the top of the list of the triggers and has the Map's name.)
//*
//*    Select the text from the //##Start## to the //##End## and copy it to the custom script
//* section that is at the top of the trigger list and has your map's name.
//*
//*    After copying them and saving in your map, you need to call SetupSpecialEvents() at map
//*  Initialization in order to allow the system to work. (check next trigger)
//*
//*    If you already have them in your map, Delete the ones in your map, then copy these ones,
//*  this is a new version that fixes some memory leaks that were blizzard's fault, also the
//*  Special Events functions have a new option.
//*
//*   In theory, you may just copy the trigger, making sure it is above any other trigger, then
//* Instantly save, this is easier, but may not work well.
//*
//*************************************************************************************************

//==================================================================================================
//
// For more JASS scripts, visit : http://www.wc3JASS.com
//
//==================================================================================================

//==================================================================================================
function Eventscache takes nothing returns gamecache
    if (udg_spellevents==null) then
        call FlushGameCache(InitGameCache("spellevents.vx"))
        set udg_spellevents=InitGameCache("spellevents.vx")

        call ExecuteFunc("SpecialEvents_Init")
    endif
 return udg_spellevents
endfunction

function GetPassiveAbilityUser takes nothing returns unit
    return GetStoredInteger(Eventscache(),"passives","unit")
    return null
endfunction

function GetPassiveAbilityId takes nothing returns integer
    return GetStoredInteger(Eventscache(),"passives","current")
endfunction

function events_H2I takes handle h returns integer
    return h
    return 0
endfunction

function PassiveAbilitiesPrepare takes nothing returns nothing
 local gamecache g=Eventscache()
 local integer n=GetStoredInteger(g,"passives","n")
 local integer i=1
 local integer array p
 local string array s
 local unit u
 local group a=CreateGroup()
    loop
        exitwhen (i>n)
        set p[i]=GetStoredInteger(g,"passives",I2S(i))
        set s[i]=GetStoredString(g,"spelllearnfuncs", I2S(p[i]))
        set i=i+1
    endloop
    call GroupEnumUnitsInRect(a,bj_mapInitialPlayableArea,null)
    loop
        set u=FirstOfGroup(a)
        exitwhen (u==null)
        set i=1
        call StoreInteger(g,"passives","unit",events_H2I(u))
        loop
            exitwhen (i>n)
            if (GetUnitAbilityLevel(u,p[i])>0) then
                call StoreInteger(g,"passives","current",p[i])
                call ExecuteFunc(s[i])
            endif
            set i=i+1
        endloop
        call GroupRemoveUnit(a,u)
    endloop  
 set a=null
endfunction

//==================================================================================================
function PassiveAbilityBrowse takes gamecache g, unit u, string k returns nothing
 local integer n=GetStoredInteger(g,"passives","n")
 local integer un=0
 local integer i=1
 local integer s
    call StoreInteger(g,"passives","unit",events_H2I(u))
    loop
        exitwhen (i>n)
        set s=GetStoredInteger(g,"passives",I2S(i))
        if (GetUnitAbilityLevel(u,s)>0) then
            set un=un+1
            call StoreInteger(g,"passiveREG"+I2S(un),k,s)
            call StoreInteger(g,"passives","current",s)
            call ExecuteFunc(GetStoredString(g,"spelllearnfuncs",I2S(s)))
        endif
        set i=i+1
    endloop
    if (un==0) then
        call StoreBoolean(g,"pasignore",k,true)
    else
        call StoreInteger(g,"passiveREGN",k,un)
    endif
endfunction

function DoPassiveAbilities takes gamecache g, unit u, string k returns nothing
 local integer n=GetStoredInteger(g,"passiveREGN",k)
 local integer i=1
 local integer s
    call StoreInteger(g,"passives","unit",events_H2I(u))
    loop
        exitwhen (i>n)
        set s=GetStoredInteger(g,"passiveREG"+I2S(i),k)
        if (GetUnitAbilityLevel(u,s)>0) then
            call StoreInteger(g,"passives","current",s)
            call ExecuteFunc(GetStoredString(g,"spelllearnfuncs",I2S(s)))
        endif
        set i=i+1
    endloop
endfunction

function PassiveAbilitiesOnCreated takes gamecache g, unit u, string k returns nothing
    if HaveStoredInteger(g,"passiveREGN",k) then
        call DoPassiveAbilities(g,u,k)
    else
        call PassiveAbilityBrowse(g,u,k)
    endif      
endfunction

//==================================================================================================
function Trig_SpecialEvents_Actions takes nothing returns nothing
 local unit u=GetTriggerUnit()
 local eventid e=GetTriggerEventId()
 local gamecache sp=Eventscache()
 local integer s
 local string k

    if (e==EVENT_PLAYER_UNIT_SPELL_EFFECT) then
        set k=I2S(GetSpellAbilityId())
        if HaveStoredString( sp, "spellfuncs",k) then
            call ExecuteFunc( GetStoredString( sp, "spellfuncs",k))
        endif

    elseif (e==EVENT_PLAYER_UNIT_SPELL_CAST) then
        set k=I2S(GetSpellAbilityId())
        if HaveStoredString( sp, "castfuncs", k) then
            call ExecuteFunc( GetStoredString( sp, "castfuncs",k))
        endif

    elseif (e==EVENT_PLAYER_HERO_SKILL) then
        set s=GetLearnedSkill()
        set k=I2S(s)
        if HaveStoredString( sp, "spelllearnfuncs",k) then
            call StoreInteger(sp,"passives","unit",events_H2I(u))
            call StoreInteger(sp,"passives","current",s)
            call ExecuteFunc( GetStoredString( sp, "spelllearnfuncs",k))
        endif

    elseif (e==EVENT_PLAYER_UNIT_SUMMON) then
        set k=I2S(GetUnitTypeId( GetSummonedUnit() ))
        if HaveStoredString( sp, "unitfuncs",k) then
            call ExecuteFunc( GetStoredString( sp, "unitfuncs", k))
        endif

    elseif (e==EVENT_PLAYER_UNIT_USE_ITEM) then
        set k=I2S( GetItemTypeId( GetManipulatedItem() ))
        if HaveStoredString( sp, "itemfuncs", k) then
            call ExecuteFunc(GetStoredString(sp,"itemfuncs",k))
        endif

    elseif (e==EVENT_PLAYER_UNIT_PICKUP_ITEM) then
        set k=I2S( GetItemTypeId( GetManipulatedItem() ))
        if HaveStoredString( sp, "itemgetfuncs", k) then
            call ExecuteFunc(GetStoredString( sp, "itemgetfuncs",k))
        endif

    else
        set k=I2S(GetUnitTypeId(u))
        if not(HaveStoredBoolean(sp,"pasignore",k)) then
            call PassiveAbilitiesOnCreated(sp,u,k)
        endif
    endif
 set u=null
 set e=null
 set sp=null
endfunction




//==================================================================================================
// Call This Function at map initialization if you want the whole thing to work.
//
function SetupSpecialEvents takes nothing returns nothing
    call Eventscache() //Left For compat
endfunction

function SpecialEvents_Init takes nothing returns nothing
 local trigger trig=CreateTrigger()
 local integer i = 0
    loop
        call TriggerRegisterPlayerUnitEvent(trig, Player(i),EVENT_PLAYER_UNIT_SPELL_EFFECT, null)
        call TriggerRegisterPlayerUnitEvent(trig, Player(i),EVENT_PLAYER_UNIT_SUMMON, null)
        call TriggerRegisterPlayerUnitEvent(trig, Player(i),EVENT_PLAYER_UNIT_USE_ITEM, null)
        call TriggerRegisterPlayerUnitEvent(trig, Player(i),EVENT_PLAYER_UNIT_PICKUP_ITEM, null)
        call TriggerRegisterPlayerUnitEvent(trig, Player(i),EVENT_PLAYER_HERO_SKILL, null)
        call TriggerRegisterPlayerUnitEvent(trig, Player(i),EVENT_PLAYER_UNIT_SPELL_CAST, null)
        set i=i+1
        exitwhen i==bj_MAX_PLAYER_SLOTS
    endloop
    call TriggerRegisterEnterRectSimple(trig,bj_mapInitialPlayableArea)
    call TriggerAddAction(trig,function Trig_SpecialEvents_Actions)
    call TimerStart(CreateTimer(),0,false,function PassiveAbilitiesPrepare)
 set trig=null
endfunction






//==================================================================================================
// Registers the function to be executed when the effect of an ability is started:
//
function RegisterAbilityEvent takes integer abilid, string funcname returns nothing
    call StoreString( Eventscache(), "spellfuncs", I2S(abilid), funcname)
endfunction

//==================================================================================================
// Registers the function to be executed when an ability is about to be casted
//
function RegisterAbilityPreCastEvent takes integer abilid, string funcname returns nothing
    call StoreString( Eventscache(), "castfuncs", I2S(abilid), funcname)
endfunction

//==================================================================================================
// Registers the function to be executed when an ability is learned:
//   
function RegisterAbilityLearnEvent takes integer abilid, string funcname returns nothing
    call StoreString( Eventscache(), "spelllearnfuncs", I2S(abilid), funcname)
endfunction

//==================================================================================================
// Registers the function to be executed when an ability is learned:
//   
function RegisterPassiveAbility takes integer abilid, string funcname returns nothing
 local gamecache g=Eventscache()
 local integer n=GetStoredInteger(g,"passives","n")+1
    call StoreString( Eventscache(), "spelllearnfuncs", I2S(abilid), funcname)
    call StoreInteger(g,"passives","n",n)
    call StoreInteger(g,"passives",I2S(n),abilid)   
 set g=null
endfunction



//==================================================================================================
// Registers the function to be executed when an unit type is summoned:
//   
function RegisterItemUseEvent takes integer itemid, string funcname returns nothing
    call StoreString( Eventscache(), "itemfuncs", I2S(itemid), funcname)
endfunction

//==================================================================================================
// Registers the function to be executed when an unit type enters to the map:
//   
function RegisterUnitSummonEvent takes integer unitid, string funcname returns nothing
    call StoreString( Eventscache(), "unitfuncs", I2S(unitid), funcname)
endfunction

//==================================================================================================
// Registers the function to be executed when an item type is acquired:
//   
function RegisterItemGetEvent takes integer itemid, string funcname returns nothing
    call StoreString( Eventscache(), "itemgetfuncs", I2S(itemid), funcname)
endfunction
//##End##