1. Are you planning to upload your awesome spell or system to Hive? Please review the rules here.
    Dismiss Notice
  2. Find your way through the deepest dungeon in the 18th Mini Mapping Contest Poll.
    Dismiss Notice
  3. A brave new world lies beyond the seven seas. Join the 34th Modeling Contest today!
    Dismiss Notice
  4. Check out the Staff job openings thread.
    Dismiss Notice
Dismiss Notice
Hive 3 Remoosed BETA - NOW LIVE. Go check it out at BETA Hive Workshop! Post your feedback in this new forum BETA Feedback.
Dismiss Notice
60,000 passwords have been reset on July 8, 2019. If you cannot login, read this.

Trigger Viewer

PS_UP_v.0.1.7.w3x
Variables
Requirements
By Myself
Loc
CustomEffect
StructUtils
-- Not mine --
ARGB
GroupUtils
Table
CustomMissile
Missile
-- Events --
MissileUnitHit
MissileGroundHit
MissileDestHit
MissileCollideHit
MissileDecay
-- Movement --
MissileMovement
-- Target --
MissileUnitTarget
MissileLocTarget
-- Utils --
MissileBounds
MissileSpellHelper
Spells
ParalyzingWave
RainOfFire
Kartenspezifischen eigenen Skript-Code unten eingeben. Dieser Text wird in das Karten-Skript nach der Deklaration der Variablen und vor jeglichem Auslöser-Code eingefügt.

		
Name Type Is Array Initial Value
//TESH.scrollpos=-1
//TESH.alwaysfold=0
//<o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o>
//:     Loc
//:         by Anachron
//:    
//:     Simple library to give me more control about locations.
//:     Feel free to use it without credits.
//<o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o>
library Loc
   
    globals
        private constant location zLoc      = Location(0, 0)
                constant real     TWO_PI    = 2 * bj_PI
    endglobals
   
    //! textmacro CMPos_addOperator takes name, type, object
    method operator $name$= takes $type$ val returns nothing
        set .$object$ = val
    endmethod
   
    method operator $name$ takes nothing returns $type$
        return .$object$
    endmethod
    //! endtextmacro
   
    function GetLocZ takes real x, real y returns real
        call MoveLocation(zLoc, x, y)
        return GetLocationZ(zLoc)
    endfunction
   
    function makeRealAngle takes real a returns real
        loop
            exitwhen a < TWO_PI and a >= 0.
           
            if a < 0 then
                set a = a + TWO_PI
            elseif a > TWO_PI then
                set a = a - TWO_PI
            endif
        endloop
       
        return a
    endfunction
   
    struct Loc
        private real F = 0.
        private real X = 0.
        private real Y = 0.
        private real Z = 0.
       
        //! runtextmacro CMPos_addOperator("f", "real", "F")
        //! runtextmacro CMPos_addOperator("x", "real", "X")
        //! runtextmacro CMPos_addOperator("y", "real", "Y")
        //! runtextmacro CMPos_addOperator("z", "real", "Z")
       
        public static method create takes real x, real y, real z, real f returns thistype
            local thistype this = thistype.allocate()
           
            set .F = f
            set .X = x
            set .Y = y
            set .Z = z
           
            return this
        endmethod
       
        public static method fromUnit takes unit theUnit returns thistype
            local real x = GetUnitX(theUnit)
            local real y = GetUnitY(theUnit)
            local real z = GetLocZ(x, y) + GetUnitFlyHeight(theUnit)
            local real f = GetUnitFacing(theUnit) * bj_DEGTORAD
            return Loc.create(x, y, z, f)
        endmethod
       
        public static method fromDest takes destructable theDest returns thistype
            local real x = GetDestructableX(theDest)
            local real y = GetDestructableY(theDest)
            local real z = GetLocZ(x, y) + GetDestructableOccluderHeight(theDest)
            local real f = 0.
            return Loc.create(x, y, z, f)
        endmethod
       
        public static method fromItem takes item theItem returns thistype
            local real x = GetItemX(theItem)
            local real y = GetItemY(theItem)
            local real z = GetLocZ(x, y)
            local real f = 0.
            return Loc.create(x, y, z, f)
        endmethod
       
        public static method fromXY takes real x, real y returns thistype
            local real z = GetLocZ(x, y)
            local real f = 0.
            return Loc.create(x, y, z, f)
        endmethod
       
        public method angleTo takes thistype that returns real
            return makeRealAngle(Atan2(that.y - .y, that.x - .x))
        endmethod
       
        public method distanceTo takes thistype that returns real
            //: Thanks to The_Reborn_Devil
            return SquareRoot((that.x - .x)*(that.x - .x) + (that.y - .y)*(that.y - .y))
        endmethod
       
        public method distanceToZ takes thistype that returns real
            //: Thanks to The_Reborn_Devil
            return SquareRoot((that.x - .x)*(that.x - .x) + (that.y - .y)*(that.y - .y) + (that.z - .z)*(that.z - .z))
        endmethod
       
        public method move takes real d returns nothing
            set .x = .x + d * Cos(.f)
            set .y = .y + d * Sin(.f)
        endmethod
       
        public method moveFaced takes real d, real f returns nothing
            set .x = .x + d * Cos(f)
            set .y = .y + d * Sin(f)
        endmethod
       
        public method applyNew takes real x, real y, real z, real f returns nothing
            set .f = f
            set .x = x
            set .y = y
            set .z = z
        endmethod
       
        public method applyLoc takes thistype that returns nothing
            set .f = that.f
            set .x = that.x
            set .y = that.y
            set .z = that.z
        endmethod
       
        public method clone takes nothing returns thistype
            local thistype that = thistype.allocate()
           
            set that.f = .f
            set that.x = .x
            set that.y = .y
            set that.z = .z
           
            return that
        endmethod
    endstruct
   
    function AngleBetweenUnits takes unit first, unit sec returns real
        local Loc lFirst = Loc.create(GetUnitX(first), GetUnitY(first), 0., 0.)
        local Loc lSec = Loc.create(GetUnitX(sec), GetUnitY(sec), 0., 0.)
        local real angle = 0.
       
        if first == null or sec == null then
            set angle = -1.
        else
            set angle = lFirst.angleTo(lSec)
        endif
       
        call lFirst.destroy()
        call lSec.destroy()
        return angle
    endfunction
   
    function AngleBetweenLocs takes real x1, real y1, real x2, real y2 returns real
        return makeRealAngle(Atan2(y2 - y1, x2 - x1))
    endfunction
   
    function DistBetweenPoints takes real startX, real startY, real endX, real endY returns real
        return SquareRoot((endX - startX)*(endX - startX) + (endY - startY)*(endY - startY))
    endfunction
   
    function DistBetweenUnits takes unit first, unit sec returns real
        local Loc lFirst = Loc.create(GetUnitX(first), GetUnitY(first), 0., GetUnitFacing(first))
        local Loc lSec = Loc.create(GetUnitX(sec), GetUnitY(sec), 0., GetUnitFacing(sec))
        local real dist = 0.
       
        if first == null or sec == null then
            set dist = -1.
        else
            set dist = lFirst.distanceTo(lSec)
        endif
       
        call lFirst.destroy()
        call lSec.destroy()
        return dist
    endfunction
   
    function DistBetweenUnitsZ takes unit first, unit sec returns real
        local real zFirst = GetLocZ(GetUnitX(first), GetUnitY(first)) + GetUnitFlyHeight(first)
        local real zSec = GetLocZ(GetUnitX(sec), GetUnitY(sec)) + GetUnitFlyHeight(sec)
        local Loc lFirst = Loc.create(GetUnitX(first), GetUnitY(first), zFirst, GetUnitFacing(first))
        local Loc lSec = Loc.create(GetUnitX(sec), GetUnitY(sec), zSec, GetUnitFacing(sec))
        local real dist = 0.
       
        if first == null or sec == null then
            set dist = -1.
        else
            set dist = lFirst.distanceToZ(lSec)
        endif
       
        call lFirst.destroy()
        call lSec.destroy()
        return dist
    endfunction
endlibrary
 
//TESH.scrollpos=-1
//TESH.alwaysfold=0
//<o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o>
//:     CustomEffect
//:         by Anachron
//:
//:     This system is thought to replace xefx.
//:
//:     What it is:
//:         This system uses a dummy unit to create an effect that is scale- and
//:         colorizeble and gives the posability to modify it in any way you want.
//:
//:     Credits:
//:         Vexorian for xe(fx) [which I don't use]
//:         Vexorian for ARGB (optional) [http://www.wc3c.net/showthread.php?t=101858]
//:
//:     Thanks to:
//:         Slaydon, catch_ya, Flame_Phoenix, Element_Of_Water and Berbanog
//:         for their input to the system. Without them this wouldn't be that
//:         customizeable and would've less functionality.
//:
//<o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o>
library CustomEffect requires Loc, optional ARGB

    globals
                constant integer EFFECT_UNIT_TYPE = 'cefx'
        private constant integer EFFECT_HEIGHT_ENABLER = 'Arav'
        private constant integer EFFECT_DISSELECT = 'Aloc'
        private constant integer MAX_INSTANCES = 8190
    endglobals
   
    struct CustomEffect[MAX_INSTANCES]
        private unit    effUnit     = null
        private effect  effHandle   = null
        private string  effSFX      = null
       
        private Loc     pos         = 0
        private real    zAng        = 0.
       
        /* ------- Scale ------- */
        private real    scal       = 1.
       
        /* ------- Color ------- */
        private integer    colr       = 255
        private integer    colrA      = 255
        private integer    colrR      = 255
        private integer    colrG      = 255
        private integer    colrB      = 255
       
        public static method create takes nothing returns thistype
            local thistype this = thistype.allocate()
           
            set .pos                = Loc.create(0., 0., 0., 0.)
           
            return this
        endmethod
       
        public method use takes real x, real y, real z, real f returns nothing
            call .pos.applyNew      (x, y, z, f)
            call RemoveUnit         (.effUnit)
            set .effUnit            = CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE), EFFECT_UNIT_TYPE, x, y, bj_RADTODEG * f)
            call UnitAddAbility     (.effUnit, EFFECT_HEIGHT_ENABLER)
            call SetUnitFlyHeight   (.effUnit, z - GetLocZ(x, y), 0.)
            call UnitRemoveAbility  (.effUnit, EFFECT_HEIGHT_ENABLER)
            call UnitAddAbility     (.effUnit, EFFECT_DISSELECT)
           
            // apply the settings to the new unit
            set .sfx                = .sfx
            set .scale              = .scale
            set .colorA             = .colorA
            set .colorR             = .colorR
            set .colorG             = .colorG
            set .colorB             = .colorB
        endmethod
       
        public static method copy takes thistype this, thistype that returns nothing
            set that.sfx        = .sfx
            set that.scale      = .scale
            set that.colorA     = .colorA
            set that.colorR     = .colorR
            set that.colorG     = .colorG
            set that.colorB     = .colorB
        endmethod
       
        //# ======= -----------------------------------
        /* Position */
        //# ======= -----------------------------------
        method operator f takes nothing returns real
            return .pos.f
        endmethod
       
        method operator f= takes real f returns nothing
            call SetUnitFacing(.effUnit, f * bj_RADTODEG)
            set .pos.f = f
        endmethod
       
        method operator x takes nothing returns real
            return .pos.x
        endmethod
       
        method operator x= takes real x returns nothing
            call SetUnitX(.effUnit, x)
            set .pos.x = x
        endmethod
       
        method operator y takes nothing returns real
            return .pos.y
        endmethod
       
        method operator y= takes real y returns nothing
            call SetUnitY(.effUnit, y)
            set .pos.y = y
        endmethod
       
        method operator z takes nothing returns real
            return .pos.z
        endmethod
       
        method operator z= takes real z returns nothing
            call SetUnitFlyHeight(.effUnit, z - GetLocZ(.pos.x, .pos.y), 0.)
            set .pos.z = z
        endmethod
       
        method operator zAngle takes nothing returns real
            return .zAng
        endmethod

        //: Thanks to The_Reborn_Devil
        method operator zAngle= takes real value returns nothing
            local integer i = R2I(value * bj_RADTODEG + 90.5)
           
            if i >= 180 then
               set i = 179
            elseif i < 0 then
               set i = 0
            endif
               
            call SetUnitAnimationByIndex(.effUnit, i)
            set .zAng = value
        endmethod
       
        method operator loc takes nothing returns Loc
            return .pos
        endmethod
       
        method operator loc= takes Loc l returns nothing
            call .pos.applyLoc(l)
            call SetUnitFacing(.effUnit, .pos.f * bj_RADTODEG)
            call SetUnitX(.effUnit, .pos.x)
            call SetUnitY(.effUnit, .pos.y)
            call SetUnitFlyHeight(.effUnit, .pos.z - GetLocZ(pos.x, .pos.y), 0.)
        endmethod
       
        public method applyFOnce takes real f returns nothing
            call SetUnitFacing(.effUnit, f * bj_RADTODEG)
        endmethod
       
        public method applyXOnce takes real x returns nothing
            call SetUnitX(.effUnit, x)
        endmethod
       
        public method applyYOnce takes real y returns nothing
            call SetUnitY(.effUnit, y)
        endmethod
       
        public method applyZOnce takes real z returns nothing
            call SetUnitFlyHeight(.effUnit, z - GetLocZ(pos.x, .pos.y), 0.)
        endmethod
       
        public method applyLocOnce takes Loc l returns nothing
            call SetUnitFacing(.effUnit, l.f * bj_RADTODEG)
            call SetUnitX(.effUnit, l.x)
            call SetUnitY(.effUnit, l.y)
            call SetUnitFlyHeight(.effUnit, l.z - GetLocZ(l.x, l.y), 0.)
        endmethod
       
        //# ======= -----------------------------------
        /* Scale */
        //# ======= -----------------------------------
       
        method operator scale takes nothing returns real
            return .scal
        endmethod
       
        method operator scale= takes real s returns nothing
            set .scal = s
            call SetUnitScale(.effUnit, .scal, .scal, .scal)
        endmethod
       
        //# ======= -----------------------------------
        /* Color */
        //# ======= -----------------------------------
        private method applyColor takes nothing returns nothing
            call SetUnitVertexColor(.effUnit, .colorR, .colorG, .colorB, .colorA)
        endmethod
       
        method operator colorA takes nothing returns integer
            return .colrA
        endmethod
       
        method operator colorA= takes integer c returns nothing
            set .colrA = c
            call .applyColor()
        endmethod
       
        method operator colorR takes nothing returns integer
            return .colrA
        endmethod
       
        method operator colorR= takes integer c returns nothing
            set .colrR = c
            call .applyColor()
        endmethod
       
        method operator colorG takes nothing returns integer
            return .colrG
        endmethod
       
        method operator colorG= takes integer c returns nothing
            set .colrG = c
            call .applyColor()
        endmethod
       
        method operator colorB takes nothing returns integer
            return .colrB
        endmethod
       
        method operator colorB= takes integer c returns nothing
            set .colrB = c
            call .applyColor()
        endmethod
       
        method operator color takes nothing returns integer
            return .colr
        endmethod
       
        method operator color= takes integer c returns nothing
            set .colrA = c
            set .colrR = c
            set .colrG = c
            set .colrB = c
            call .applyColor()
        endmethod
       
        public method colorARGB takes integer a, integer r, integer g, integer b returns nothing
            set .colrA = a
            set .colrR = r
            set .colrG = g
            set .colrB = b
            call .applyColor()
        endmethod
       
        static if LIBRARY_ARGB then
            public method ARGB takes ARGB color returns nothing
                set .colrA = color.alpha
                set .colrR = color.red
                set .colrG = color.green
                set .colrB = color.blue
                call .applyColor()
            endmethod
        endif
       
        //# ======= -----------------------------------
        /* Misc */
        //# ======= -----------------------------------
        method operator owner takes nothing returns player
            return GetOwningPlayer(.effUnit)
        endmethod
       
        method operator owner= takes player p returns nothing
            call SetUnitOwner(.effUnit, p, false)
        endmethod
       
        method operator sfx takes nothing returns string
            return .effSFX
        endmethod
       
        method operator sfx= takes string sfx returns nothing
            call DestroyEffect(.effHandle)
            set .effHandle = AddSpecialEffectTarget(sfx, .effUnit, "origin")
            set .effSFX = sfx
        endmethod
       
        public method toUnit takes nothing returns unit
            return .effUnit
        endmethod
       
        //# ======= -----------------------------------
        /* Effects */
        //# ======= -----------------------------------
        public method createHere takes string sfx returns thistype
            local thistype that = thistype.create()
            local real x = GetUnitX(.effUnit)
            local real y = GetUnitY(.effUnit)
            local real z = GetLocZ(x, y) + GetUnitFlyHeight(.effUnit)
            local real f = GetUnitFacing(.effUnit) * bj_DEGTORAD
           
            set that.sfx = sfx
            call that.use(x, y, z, f)
           
            return that
        endmethod
       
        private method onDestroy takes nothing returns nothing
            call DestroyEffect(.effHandle)
            if .pos != 0 then
                call .pos.destroy()
                set .pos = 0
            endif
            call RemoveUnit(.effUnit)
        endmethod
    endstruct
endlibrary
 
//TESH.scrollpos=-1
//TESH.alwaysfold=0
library StructUtils

    //! textmacro DynamicCallStructModule takes Action
    module Dynamic$Action$Struct
        public     static          trigger       $Action$Trigger = null
               
        public static method add$Action$ takes code theFunc returns triggeraction
            return TriggerAddAction(thistype.$Action$Trigger, theFunc)
        endmethod
       
        public static method remove$Action$ takes triggeraction theFunc returns nothing
            call TriggerRemoveAction(thistype.$Action$Trigger, theFunc)
        endmethod
       
        public static method invoke$Action$ takes nothing returns nothing
            call TriggerExecute(thistype.$Action$Trigger)
        endmethod
       
        private static method onInit takes nothing returns nothing
            set thistype.$Action$Trigger = CreateTrigger()
        endmethod
    endmodule
    //! endtextmacro
   
    //! runtextmacro DynamicCallStructModule("Register")
    //! runtextmacro DynamicCallStructModule("Periodic")
    //! runtextmacro DynamicCallStructModule("Cleanup")
   
    module SaveLoadStruct
        private     static      Table       INSTANCES   = 0
        public                  integer     id          = -1
        public      static      integer     SELF        = 0

        public method save takes nothing returns nothing
            set thistype.INSTANCES[.id] = integer(this)
        endmethod
       
        public method clear takes nothing returns nothing
            call thistype.INSTANCES.reset()
        endmethod
       
        public method remove takes nothing returns nothing
            call thistype.INSTANCES.flush(.id)
        endmethod
       
        public static method exists takes integer id returns boolean
            return thistype.INSTANCES.exists(id)
        endmethod
       
        public static method load takes integer id returns thistype
            return thistype(thistype.INSTANCES[id])
        endmethod
       
        private static method onInit takes nothing returns nothing
            set thistype.INSTANCES = Table.create()
        endmethod
    endmodule
   
    module IndexedStruct
        public      static      integer         amount          = 0
       
        implement SaveLoadStruct
       
        public method isIndexed takes nothing returns boolean
            return thistype.exists(.id)
        endmethod
       
        public static method lastKey takes nothing returns integer
            return thistype.amount -1
        endmethod
       
        public method index takes nothing returns boolean
            if .isIndexed() then
                return false
            endif
           
            set .id = thistype.amount
            call .save()
            set thistype.amount = thistype.amount +1
            return true
        endmethod
       
        public method deindex takes nothing returns boolean
            local thistype that = 0
       
            if not .isIndexed() then
                return false
            endif
           
            call .remove()
            set thistype.amount = thistype.amount -1
            if thistype.amount >= 0 then
                set that = thistype.load(thistype.amount)
                if that != 0 then
                    call that.remove()
                    set that.id = .id
                    call that.save()
                endif
            endif
            return true
        endmethod
    endmodule
   
    module PeriodicStruct
        public              boolean         isAlive         = false
        public              boolean         isActive        = false
        public  static      timer           clock           = null
       
        implement IndexedStruct
       
        public stub method onPeriod takes nothing returns boolean
            return true
        endmethod
       
        public method isRegistered takes nothing returns boolean
            return .isIndexed()
        endmethod
       
        public method register takes nothing returns boolean
            if .index() then
                if thistype.lastKey() == 0 then
                    call thistype.startClock()
                endif
                return true
            endif
            return false
        endmethod
       
        public method unregister takes nothing returns boolean
            if .deindex() then
                if thistype.lastKey() == -1 then
                    call thistype.pauseClock()
                endif
                return true
            endif
            return false
        endmethod
               
        private static method runPeriod takes nothing returns nothing
            local integer i = 0
            local thistype this = 0
           
            loop
                exitwhen i > thistype.lastKey()
                               
                set this = thistype.load(i)
                set thistype.SELF = this
               
                if .onPeriod() then
                    set i = i +1
                else
                    call .destroy()
                endif
            endloop
        endmethod
       
        public static method startClock takes nothing returns nothing
            call TimerStart(thistype.clock, thistype.period, true, function thistype.runPeriod)
        endmethod
       
        public static method pauseClock takes nothing returns nothing
            call PauseTimer(thistype.clock)
        endmethod
       
        private static method onInit takes nothing returns nothing
            set thistype.clock = CreateTimer()
        endmethod
    endmodule
endlibrary
//TESH.scrollpos=-1
//TESH.alwaysfold=0
library ARGB initializer init
//******************************************************************************
//*
//* ARGB 1.2
//* ====
//*  For your color needs.
//*  
//*  An ARGB object is a by-value struct, this means that assigning copies the
//* contents of the struct and that you don't have to use .destroy(), the
//* downside is that you cannot assign its members (can't do set c.r= 123 )
//*
//*  This library should have plenty of uses, for example, if your spell involves
//* some unit recoloring you can allow users to input the color in the config
//* section as 0xAARRGGBB and you can then use this to decode that stuff.
//*
//* You can also easily merge two colors and make fading effects using ARGB.mix
//*
//* There's ARGB.fromPlayer which gets an ARGB object containing the player's
//* color. Then you can use the previous utilities on it.
//*
//* The .str() instance method can recolor a string, and the recolorUnit method
//* will apply the ARGB on a unit
//*
//* For other uses, you can use the .red, .green, .blue and .alpha members to get
//* an ARGB object's color value (from 0 to 255).
//*
//* structs that have a recolor method that takes red,green,blue and alpha as 0.255
//* integers can implement the ARGBrecolor module to gain an ability to quickly
//* recolor using an ARGB object.
//*
//********************************************************************************

//=================================================================================
globals
    private string array i2cc
endglobals

//this double naming stuff is beginning to make me insane, if only TriggerEvaluate() wasn't so slow...
struct ARGB extends array
    static method create takes integer a, integer r, integer g, integer b returns ARGB
        return ARGB(b + g*0x100 + r*0x10000 + a*0x1000000)
    endmethod
   
    // not really part of the exported stuff, I may remove it in the future, so please don't call this textmacro
    //! textmacro ARGB_PLAYER_COLOR_2_ARGB
        if(pc==PLAYER_COLOR_RED) then
            return 0xFFFF0303
        elseif(pc==PLAYER_COLOR_BLUE) then
            return 0xFF0042FF
        elseif(pc==PLAYER_COLOR_CYAN) then
            return 0xFF1CE6B9
        elseif(pc==PLAYER_COLOR_PURPLE) then
            return 0xFF540081
        elseif(pc==PLAYER_COLOR_YELLOW) then
            return 0xFFFFFC01
        elseif(pc==PLAYER_COLOR_ORANGE) then
            return 0xFFFE8A0E
        elseif(pc==PLAYER_COLOR_GREEN) then
            return 0xFF20C000
        elseif(pc==PLAYER_COLOR_PINK) then
            return 0xFFE55BB0
        elseif(pc==PLAYER_COLOR_LIGHT_GRAY) then
            return 0xFF959697
        elseif(pc==PLAYER_COLOR_LIGHT_BLUE) then
            return 0xFF7EBFF1
        elseif(pc==PLAYER_COLOR_AQUA) then
            return 0xFF106246
        elseif(pc==PLAYER_COLOR_BROWN) then
            return 0xFF4E2A04
        endif
       
      return 0xFF111111
    //! endtextmacro
    static method fromPlayerColor takes playercolor pc returns ARGB
        //! runtextmacro ARGB_PLAYER_COLOR_2_ARGB()
    endmethod

    static method fromPlayer takes player p returns ARGB
     local playercolor pc=GetPlayerColor(p)
        //! runtextmacro ARGB_PLAYER_COLOR_2_ARGB()
    endmethod

    method operator alpha takes nothing returns integer
        if( integer(this) <0) then
            return 0x80+(-(-integer(this)+0x80000000))/0x1000000
        else
            return (integer(this))/0x1000000
        endif
    endmethod
    method operator alpha= takes integer na returns ARGB
     local integer a
     local integer r
     local integer g
     local integer b
     local integer col=integer(this)

       if (col<0) then
           set col=-(-col+0x80000000)
           set a=0x80+col/0x1000000
           set col=col-(a-0x80)*0x1000000
       else
           set a=col/0x1000000
           set col=col-a*0x1000000
       endif
       set r=col/0x10000
       set col=col-r*0x10000
       set g=col/0x100
       set b=col-g*0x100
       return ARGB(b + g*0x100 + r*0x10000 + na*0x1000000)
    endmethod




    method operator red takes nothing returns integer
     local integer c=integer(this)*0x100
        if(c<0) then
            return 0x80+(-(-c+0x80000000))/0x1000000
        else
            return c/0x1000000
        endif
    endmethod
    method operator red= takes integer nr returns ARGB
     local integer a
     local integer r
     local integer g
     local integer b
     local integer col=integer(this)

       if (col<0) then
           set col=-(-col+0x80000000)
           set a=0x80+col/0x1000000
           set col=col-(a-0x80)*0x1000000
       else
           set a=col/0x1000000
           set col=col-a*0x1000000
       endif
       set r=col/0x10000
       set col=col-r*0x10000
       set g=col/0x100
       set b=col-g*0x100
       return ARGB(b + g*0x100 + nr*0x10000 + a*0x1000000)
    endmethod

    method operator green takes nothing returns integer
     local integer c=integer(this)*0x10000
        if(c<0) then
            return 0x80+(-(-c+0x80000000))/0x1000000
        else
            return c/0x1000000
        endif
    endmethod
    method operator green= takes integer ng returns ARGB
     local integer a
     local integer r
     local integer g
     local integer b
     local integer col=integer(this)

       if (col<0) then
           set col=-(-col+0x80000000)
           set a=0x80+col/0x1000000
           set col=col-(a-0x80)*0x1000000
       else
           set a=col/0x1000000
           set col=col-a*0x1000000
       endif
       set r=col/0x10000
       set col=col-r*0x10000
       set g=col/0x100
       set b=col-g*0x100
       return ARGB(b + ng*0x100 + r*0x10000 + a*0x1000000)
    endmethod

    //=======================================================
    //
    //
    method operator blue takes nothing returns integer
     local integer c=integer(this)*0x1000000
        if(c<0) then
            return 0x80+(-(-c+0x80000000))/0x1000000
        else
            return c/0x1000000
        endif
    endmethod
    method operator blue= takes integer nb returns ARGB
     local integer a
     local integer r
     local integer g
     local integer b
     local integer col=integer(this)

       if (col<0) then
           set col=-(-col+0x80000000)
           set a=0x80+col/0x1000000
           set col=col-(a-0x80)*0x1000000
       else
           set a=col/0x1000000
           set col=col-a*0x1000000
       endif
       set r=col/0x10000
       set col=col-r*0x10000
       set g=col/0x100
       set b=col-g*0x100
       return ARGB(nb + g*0x100 + r*0x10000 + a*0x1000000)
    endmethod

    //====================================================================
    // Mixes two colors, s would be a number 0<=s<=1 that determines
    // the weight given to color c2.
    //
    //  mix(c1,c2,0)   = c1
    //  mix(c1,c2,1)   = c2
    //  mix(c1,c2,0.5) = Mixing the colors c1 and c2 in equal proportions.
    //
    static method mix takes ARGB c1, ARGB c2, real s returns ARGB
      //widest function ever
      return ARGB( R2I(c2.blue*s+c1.blue*(1-s)+0.5) + R2I(c2.green*s+c1.green*(1-s)+0.5)*0x100 + R2I(c2.red*s+c1.red*(1-s)+0.5)*0x10000 + R2I(c2.alpha*s+c1.alpha*(1-s)+0.5)*0x1000000)
    endmethod

    method str takes string s returns string
       return "|c"+i2cc[.alpha]+i2cc[.red]+i2cc[.green]+i2cc[.blue]+s+"|r"
    endmethod

    method recolorUnit takes unit u returns nothing
     local integer a
     local integer r
     local integer g
     local integer b
     local integer col=integer(this)

       if (col<0) then
           set col=-(-col+0x80000000)
           set a=0x80+col/0x1000000
           set col=col-(a-0x80)*0x1000000
       else
           set a=col/0x1000000
           set col=col-a*0x1000000
       endif
       set r=col/0x10000
       set col=col-r*0x10000
       set g=col/0x100
       set b=col-g*0x100
       call SetUnitVertexColor(u,r,g,b,a)
    endmethod

endstruct

module ARGBrecolor
    method ARGBrecolor takes ARGB color returns nothing
     local integer a
     local integer r
     local integer g
     local integer b
     local integer col=integer(this)

       if (col<0) then
           set col=-(-col+0x80000000)
           set a=0x80+col/0x1000000
           set col=col-(a-0x80)*0x1000000
       else
           set a=col/0x1000000
           set col=col-a*0x1000000
       endif
       set r=col/0x10000
       set col=col-r*0x10000
       set g=col/0x100
       set b=col-g*0x100
       
       call this.recolor(r, g , b, a)
    endmethod

endmodule

private function init takes nothing returns nothing
 local integer i=0

    // Don't run textmacros you don't own!
    //! textmacro ARGB_CHAR takes int, chr
        set i=0
        loop
            exitwhen i==16
            set i2cc[$int$*16+i]="$chr$"+i2cc[$int$*16+i]
            set i2cc[i*16+$int$]=i2cc[i*16+$int$]+"$chr$"
            set i=i+1
        endloop
    //! endtextmacro
    //! runtextmacro ARGB_CHAR( "0","0")
    //! runtextmacro ARGB_CHAR( "1","1")
    //! runtextmacro ARGB_CHAR( "2","2")
    //! runtextmacro ARGB_CHAR( "3","3")
    //! runtextmacro ARGB_CHAR( "4","4")
    //! runtextmacro ARGB_CHAR( "5","5")
    //! runtextmacro ARGB_CHAR( "6","6")
    //! runtextmacro ARGB_CHAR( "7","7")
    //! runtextmacro ARGB_CHAR( "8","8")
    //! runtextmacro ARGB_CHAR( "9","9")
    //! runtextmacro ARGB_CHAR("10","A")
    //! runtextmacro ARGB_CHAR("11","B")
    //! runtextmacro ARGB_CHAR("12","C")
    //! runtextmacro ARGB_CHAR("13","D")
    //! runtextmacro ARGB_CHAR("14","E")
    //! runtextmacro ARGB_CHAR("15","F")
endfunction

endlibrary
//TESH.scrollpos=-1
//TESH.alwaysfold=0
library GroupUtils initializer Init requires optional xebasic
//******************************************************************************
//* BY: Rising_Dusk
//*
//* This library is a combination of several features relevant to groups. First
//* and foremost, it contains a group stack that you can access dynamic groups
//* from. It also provides means to refresh groups and clear any shadow
//* references within them. The included boolexprs are there for backwards
//* compatibility with maps that happen to use them. Since the 1.24c patch,
//* null boolexprs used in GroupEnumUnits* calls no longer leak, so there is no
//* performance gain to using the BOOLEXPR_TRUE constant.
//*
//* Instead of creating/destroying groups, we have moved on to recycling them.
//* NewGroup pulls a group from the stack and ReleaseGroup adds it back. Always
//* remember to call ReleaseGroup on a group when you are done using it. If you
//* fail to do so enough times, the stack will overflow and no longer work.
//*
//* GroupRefresh cleans a group of any shadow references which may be clogging
//* its hashtable. If you remove a unit from the game who is a member of a unit
//* group, it will 'effectively' remove the unit from the group, but leave a
//* shadow in its place. Calling GroupRefresh on a group will clean up any
//* shadow references that may exist within it. It is only worth doing this on
//* groups that you plan to have around for awhile.
//*
//* Constants that can be used from the library:
//*     [group]    ENUM_GROUP      As you might expect, this group is good for
//*                                when you need a group just for enumeration.
//*     [boolexpr] BOOLEXPR_TRUE   This is a true boolexpr, which is important
//*                                because a 'null' boolexpr in enumeration
//*                                calls results in a leak. Use this instead.
//*     [boolexpr] BOOLEXPR_FALSE  This exists mostly for completeness.
//*
//* This library also includes a simple implementation of a group enumeration
//* call that factors collision of units in a given area of effect. This is
//* particularly useful because GroupEnumUnitsInRange doesn't factor collision.
//*
//* In your map, you can just replace all instances of GroupEnumUnitsInRange
//* with GroupEnumUnitsInArea with identical arguments and your spells will
//* consider all units colliding with the area of effect. After calling this
//* function as you would normally call GroupEnumUnitsInRange, you are free to
//* do anything with the group that you would normally do.
//*
//* If you don't use xebasic in your map, you may edit the MAX_COLLISION_SIZE
//* variable below and the library will use that as the added radius to check.
//* If you use xebasic, however, the script will automatically use xe's
//* collision size variable.
//*
//* You are also able to use GroupUnitsInArea. This function returns all units
//* within the area, no matter what they are, which can be convenient for those
//* instances where you actually want that.
//*
//* Example usage:
//*     local group MyGroup = NewGroup()
//*     call GroupRefresh(MyGroup)
//*     call ReleaseGroup(MyGroup)
//*     call GroupEnumUnitsInArea(ENUM_GROUP, x, y, 350., BOOLEXPR_TRUE)
//*     call GroupUnitsInArea(ENUM_GROUP, x, y, 350.)
//*
globals
    //If you don't have xebasic in your map, this value will be used instead.
    //This value corresponds to the max collision size of a unit in your map.
    private constant real    MAX_COLLISION_SIZE = 197.
    //If you are insane and don't care about any of the protection involved in
    //this library, but want this script to be really fast, set this to true.
    private constant boolean LESS_SAFETY        = false
endglobals

globals
    //* Constants that are available to the user
    group    ENUM_GROUP     = CreateGroup()
    boolexpr BOOLEXPR_TRUE  = null
    boolexpr BOOLEXPR_FALSE = null
endglobals

globals
    //* Hashtable for debug purposes
    private hashtable     ht     = InitHashtable()
    //* Temporary references for GroupRefresh
    private boolean       Flag   = false
    private group         Refr   = null
    //* Arrays and counter for the group stack
    private group   array Groups
    private integer       Count  = 0
    //* Variables for use with the GroupUnitsInArea function
    private real          X      = 0.
    private real          Y      = 0.
    private real          R      = 0.
    private hashtable     H      = InitHashtable()
endglobals

private function HookDestroyGroup takes group g returns nothing
    if g == ENUM_GROUP then
        call BJDebugMsg(SCOPE_PREFIX+"Warning: ENUM_GROUP destroyed")
    endif
endfunction

debug hook DestroyGroup HookDestroyGroup

private function AddEx takes nothing returns nothing
    if Flag then
        call GroupClear(Refr)
        set Flag = false
    endif
    call GroupAddUnit(Refr, GetEnumUnit())
endfunction
function GroupRefresh takes group g returns nothing
    set Flag = true
    set Refr = g
    call ForGroup(Refr, function AddEx)
    if Flag then
        call GroupClear(g)
    endif
endfunction

function NewGroup takes nothing returns group
    if Count == 0 then
        set Groups[0] = CreateGroup()
    else
        set Count = Count - 1
    endif
    static if not LESS_SAFETY then
        call SaveInteger(ht, 0, GetHandleId(Groups[Count]), 1)
    endif
    return Groups[Count]
endfunction
function ReleaseGroup takes group g returns boolean
    local integer id = GetHandleId(g)
    static if LESS_SAFETY then
        if g == null then
            debug call BJDebugMsg(SCOPE_PREFIX+"Error: Null groups cannot be released")
            return false
        elseif Count == 8191 then
            debug call BJDebugMsg(SCOPE_PREFIX+"Error: Max groups achieved, destroying group")
            call DestroyGroup(g)
            return false
        endif
    else
        if g == null then
            debug call BJDebugMsg(SCOPE_PREFIX+"Error: Null groups cannot be released")
            return false
        elseif not HaveSavedInteger(ht, 0, id) then
            debug call BJDebugMsg(SCOPE_PREFIX+"Error: Group not part of stack")
            return false
        elseif LoadInteger(ht, 0, id) == 2 then
            debug call BJDebugMsg(SCOPE_PREFIX+"Error: Groups cannot be multiply released")
            return false
        elseif Count == 8191 then
            debug call BJDebugMsg(SCOPE_PREFIX+"Error: Max groups achieved, destroying group")
            call DestroyGroup(g)
            return false
        endif
        call SaveInteger(ht, 0, id, 2)
    endif
    call GroupClear(g)
    set Groups[Count] = g
    set Count         = Count + 1
    return true
endfunction

private function Filter takes nothing returns boolean
    return IsUnitInRangeXY(GetFilterUnit(), X, Y, R)
endfunction

private function HookDestroyBoolExpr takes boolexpr b returns nothing
    local integer bid = GetHandleId(b)
    if HaveSavedHandle(H, 0, bid) then
        //Clear the saved boolexpr
        call DestroyBoolExpr(LoadBooleanExprHandle(H, 0, bid))
        call RemoveSavedHandle(H, 0, bid)
    endif
endfunction

hook DestroyBoolExpr HookDestroyBoolExpr

private constant function GetRadius takes real radius returns real
    static if LIBRARY_xebasic then
        return radius+XE_MAX_COLLISION_SIZE
    else
        return radius+MAX_COLLISION_SIZE
    endif
endfunction

function GroupEnumUnitsInArea takes group whichGroup, real x, real y, real radius, boolexpr filter returns nothing
    local real    prevX = X
    local real    prevY = Y
    local real    prevR = R
    local integer bid   = 0
   
    //Set variables to new values
    set X = x
    set Y = y
    set R = radius
    if filter == null then
        //Adjusts for null boolexprs passed to the function
        set filter = Condition(function Filter)
    else
        //Check for a saved boolexpr
        set bid = GetHandleId(filter)
        if HaveSavedHandle(H, 0, bid) then
            //Set the filter to use to the saved one
            set filter = LoadBooleanExprHandle(H, 0, bid)
        else
            //Create a new And() boolexpr for this filter
            set filter = And(Condition(function Filter), filter)
            call SaveBooleanExprHandle(H, 0, bid, filter)
        endif
    endif
    //Enumerate, if they want to use the boolexpr, this lets them
    call GroupEnumUnitsInRange(whichGroup, x, y, GetRadius(radius), filter)
    //Give back original settings so nested enumerations work
    set X = prevX
    set Y = prevY
    set R = prevR
endfunction

function GroupUnitsInArea takes group whichGroup, real x, real y, real radius returns nothing
    local real prevX = X
    local real prevY = Y
    local real prevR = R
   
    //Set variables to new values
    set X = x
    set Y = y
    set R = radius
    //Enumerate
    call GroupEnumUnitsInRange(whichGroup, x, y, GetRadius(radius), Condition(function Filter))
    //Give back original settings so nested enumerations work
    set X = prevX
    set Y = prevY
    set R = prevR
endfunction

private function True takes nothing returns boolean
    return true
endfunction
private function False takes nothing returns boolean
    return false
endfunction
private function Init takes nothing returns nothing
    set BOOLEXPR_TRUE  = Condition(function True)
    set BOOLEXPR_FALSE = Condition(function False)
endfunction
endlibrary
//TESH.scrollpos=-1
//TESH.alwaysfold=0
library Table
//***************************************************************
//* Table object 3.0
//* ------------
//*
//*   set t=Table.create() - instanceates a new table object
//*   call t.destroy()     - destroys it
//*   t[1234567]           - Get value for key 1234567
//*                          (zero if not assigned previously)
//*   set t[12341]=32      - Assigning it.
//*   call t.flush(12341)  - Flushes the stored value, so it
//*                          doesn't use any more memory
//*   t.exists(32)         - Was key 32 assigned? Notice
//*                          that flush() unassigns values.
//*   call t.reset()       - Flushes the whole contents of the
//*                          Table.
//*
//*   call t.destroy()     - Does reset() and also recycles the id.
//*
//*   If you use HandleTable instead of Table, it is the same
//* but it uses handles as keys, the same with StringTable.
//*
//*  You can use Table on structs' onInit  if the struct is
//* placed in a library that requires Table or outside a library.
//*
//*  You can also do 2D array syntax if you want to touch
//* mission keys directly, however, since this is shared space
//* you may want to prefix your mission keys accordingly:
//*
//*  set Table["thisstring"][ 7 ] = 2
//*  set Table["thisstring"][ 5 ] = Table["thisstring"][7]
//*
//***************************************************************

//=============================================================
    globals
        private constant integer MAX_INSTANCES=8100 //400000
        //Feel free to change max instances if necessary, it will only affect allocation
        //speed which shouldn't matter that much.

    //=========================================================
        private hashtable ht
    endglobals

    private struct GTable[MAX_INSTANCES]

        method reset takes nothing returns nothing
            call FlushChildHashtable(ht, integer(this) )
        endmethod

        private method onDestroy takes nothing returns nothing
            call this.reset()
        endmethod

        //=============================================================
        // initialize it all.
        //
        private static method onInit takes nothing returns nothing
            set ht = InitHashtable()
        endmethod

    endstruct

    //Hey: Don't instanciate other people's textmacros that you are not supposed to, thanks.
    //! textmacro Table__make takes name, type, key
    struct $name$ extends GTable

        method operator [] takes $type$ key returns integer
            return LoadInteger(ht, integer(this), $key$)
        endmethod

        method operator []= takes $type$ key, integer value returns nothing
            call SaveInteger(ht,  integer(this)  ,$key$, value)
        endmethod

        method flush takes $type$ key returns nothing
            call RemoveSavedInteger(ht, integer(this), $key$)
        endmethod

        method exists takes $type$ key returns boolean
            return HaveSavedInteger( ht,  integer(this), $key$)
        endmethod

        static method flush2D takes string firstkey returns nothing
            call $name$(- StringHash(firstkey)).reset()
        endmethod

        static method operator [] takes string firstkey returns $name$
            return $name$(- StringHash(firstkey) )
        endmethod

    endstruct
    //! endtextmacro

    //! runtextmacro Table__make("Table","integer","key" )
    //! runtextmacro Table__make("String","string","StringHash(key)" )

endlibrary
Changed all constants (TRUE, FALSE) to true/false
Changed interval to 0.03125
Fixed object leaks
Performance improvements on MissileMovement: Less object generation
Merged MissileLocHelpers to Missile<type>Target
Removed HomingMissile wrapper
Added second spell (Rain of Fire)
Removed Libraries from Modules
//TESH.scrollpos=-1
//TESH.alwaysfold=0
library Missile requires CustomEffect, Loc, StructUtils
 
    private interface BaseEvents
        method onRegister   takes nothing returns nothing defaults nothing
        method onDeath      takes nothing returns nothing defaults nothing
        method onLoop       takes nothing returns nothing defaults nothing
    endinterface

    private struct MissileFrame extends BaseEvents
        public      static          real                period          = 0.03125
   
        implement PeriodicStruct
        implement DynamicRegisterStruct
        implement DynamicCleanupStruct
        implement DynamicPeriodicStruct
    endstruct
 
    struct Missile extends MissileFrame
        public                      real                height          = 0.
        private     delegate        CustomEffect        eff             = 0
       
        public static method create takes nothing returns thistype
            local thistype this = thistype.allocate()
           
            set .eff = CustomEffect.create()
           
            return this
        endmethod
       
        public stub method onPeriod takes nothing returns boolean
            call .onLoop()
            call thistype.invokePeriodic()
            return .isAlive
        endmethod
       
        public method use takes real x, real y, real z, real f returns nothing
            call .eff.use(x, y, z, f)
           
            set .isAlive = true
            set .isActive = true
            if .register() then
                call thistype.invokeRegister()
                call .onRegister()
            endif
        endmethod
       
        private method onDestroy takes nothing returns nothing
            call .unregister()
            if .eff != 0 then
                call .eff.destroy()
                set .eff = 0
            endif
            call .onDeath()
            call thistype.invokeCleanup()
        endmethod
    endstruct

endlibrary
//TESH.scrollpos=-1
//TESH.alwaysfold=0
module MissileUnitHit
    public                  boolean         hitsUnits       = true
    public                  real            unitHitRange    = 0.
    private                 group           unitHitGroup    = null
    private     static      boolean         unitHitSurvive  = true
    private     static      group           tempHitGroup    = null
   
    public static method checkUnitHit takes nothing returns nothing
        local thistype this = thistype.SELF
       
        if not .hitsUnits then
            return
        endif
       
        if .unitHitGroup == null then
            set .unitHitGroup = NewGroup()
        endif
       
        call GroupEnumUnitsInRange(thistype.tempHitGroup, .x, .y, .unitHitRange, function thistype.delegateUnitHitCheck)
    endmethod
   
    private static method delegateUnitHitCheck takes nothing returns boolean
        local thistype this = thistype.SELF
        local unit theUnit = GetFilterUnit()
        local boolean hasHit = .unitHitCond(theUnit)
       
        if hasHit and .isAlive and .isActive then
            call GroupAddUnit(.unitHitGroup, theUnit)
            if not .onUnitHit(theUnit) then
                set .isAlive = false
                set .isActive = false
            endif
        endif
       
        set theUnit = null
        return false
    endmethod
   
    public method isUnitHit takes unit theUnit returns boolean
        return IsUnitInGroup(theUnit, .unitHitGroup)
    endmethod
   
    stub method unitHitCond takes unit theUnit returns boolean
        local   boolean     triggerHit  = true
       
        set triggerHit = triggerHit and IsPlayerEnemy(.owner, GetOwningPlayer(theUnit))
        set triggerHit = triggerHit and GetUnitState(theUnit, UNIT_STATE_LIFE) > 0.405
        set triggerHit = triggerHit and not .isUnitHit(theUnit)
       
        return triggerHit
    endmethod
   
    stub method onUnitHit takes unit theUnit returns boolean
        //: return whether missile should stay alive or not
        return thistype.unitHitSurvive
    endmethod
   
    private static method clearUnitHit takes nothing returns nothing
        local thistype this = thistype.SELF
        if .unitHitGroup != null then
            call ReleaseGroup(.unitHitGroup)
            set .unitHitGroup = null
        endif
    endmethod
   
    private static method onInit takes nothing returns nothing
        call thistype.addPeriodic(function thistype.checkUnitHit)
        call thistype.addCleanup(function thistype.clearUnitHit)
        set thistype.tempHitGroup = NewGroup()
    endmethod
endmodule
//TESH.scrollpos=-1
//TESH.alwaysfold=0
module MissileGroundHit
    public                  boolean         hitsGround          = true
    public                  boolean         hideInGround        = true
    public                  boolean         inGround            = false
    private     static      boolean         groundHitSurvive    = true
   
    public static method checkGroundHit takes nothing returns nothing
        local   thistype    this            = thistype.SELF
        local   unit        effectUnit      = null
        local   boolean     checkGround     = false
        local   boolean     survive         = true
   
        if not .hitsGround or not .isAlive or not .isActive then
            return
        endif
       
        set effectUnit = .toUnit()
        set checkGround = .groundHitCond(.x, .y, .z, .height)
        if not checkGround then
            if .inGround and .hideInGround then
                call ShowUnit(effectUnit, true)
            endif
            set .inGround = false
        else
            if not .inGround and .hideInGround then
                call ShowUnit(effectUnit, false)
            endif
            set .inGround = true
           
            set survive = .onGroundHit()
            if not survive then
                set .isAlive = false
                set .isActive = false
            endif
        endif
    endmethod
   
    public method isGroundHit takes real x, real y returns boolean
        return .groundHitCond(x, y, .z, .height)
    endmethod
   
    stub method groundHitCond takes real x, real y, real z, real h returns boolean
        return GetLocZ(x, y) >= z
    endmethod
   
    stub method onGroundHit takes nothing returns boolean
        //: return whether missile should stay alive or not
        return thistype.groundHitSurvive
    endmethod
   
    private static method onInit takes nothing returns nothing
        call thistype.addPeriodic(function thistype.checkGroundHit)
    endmethod
endmodule
//TESH.scrollpos=-1
//TESH.alwaysfold=0
module MissileDestHit
    public                  boolean         hitsDests       = true
    public                  real            destHitRange    = 0.
    public                  Table           destHitGroup    = 0
    private                 rect            destCheckRect   = null
    private     static      boolean         destHitSurvive  = true
           
    public static method checkDestHit takes nothing returns nothing
        local thistype this = thistype.SELF
        local real minX = .x - .destHitRange / 2
        local real minY = .y - .destHitRange / 2
        local real maxX = .x + .destHitRange / 2
        local real maxY = .y + .destHitRange / 2
   
        if not .hitsDests then
            return
        endif
       
        if .destHitGroup == 0 then
            set .destHitGroup = Table.create()
        endif
       
        if .destCheckRect == null then
            set .destCheckRect = Rect(minX, minY, maxX, maxY)
        else
            call SetRect(.destCheckRect, minX, minY, maxX, maxY)
        endif
       
        call EnumDestructablesInRect(.destCheckRect, function thistype.delegateDestHitCheck, null)
    endmethod
   
    private static method delegateDestHitCheck takes nothing returns boolean
        local thistype this = thistype.SELF
        local destructable theDest = GetFilterDestructable()
        local boolean shouldHit = false
        local boolean survive = true
                   
        if DistBetweenPoints(.x, .y, GetDestructableX(theDest), GetDestructableY(theDest)) <= .destHitRange then
            set shouldHit = .destHitCond(theDest)
        endif
       
        if shouldHit and .isAlive and .isActive then
            set .destHitGroup[GetHandleId(theDest)] = 1
            set survive = .onDestHit(theDest)
            if not survive then
                set .isAlive = false
                set .isActive = false
            endif
        endif
       
        set theDest = null
        return false
    endmethod
   
    public method isDestHit takes destructable theDest returns boolean
        return .destHitGroup[GetHandleId(theDest)] == 1
    endmethod
   
    stub method destHitCond takes destructable theDest returns boolean
        local   boolean     triggerHit  = true
       
        set triggerHit = triggerHit and not .isDestHit(theDest)
       
        return triggerHit
    endmethod
   
    stub method onDestHit takes destructable theDest returns boolean
        //: return whether missile should stay alive or not
        return thistype.destHitSurvive
    endmethod
   
    private static method clearDestHit takes nothing returns nothing
        local thistype this = thistype.SELF
        if .destHitGroup != 0 then
            call .destHitGroup.reset()
            call .destHitGroup.destroy()
            set .destHitGroup = 0
        endif
    endmethod
   
    private static method onInit takes nothing returns nothing
        call thistype.addPeriodic(function thistype.checkDestHit)
        call thistype.addCleanup(function thistype.clearDestHit)
    endmethod
endmodule
//TESH.scrollpos=-1
//TESH.alwaysfold=0
//: Warning: Not implemented yet!
module MissileCollideHit
    public                  boolean         hitsMissiles        = true
    public                  real            missileHitRange     = 0.
    public                  Table           missileHitGroup     = 0
    private     static      boolean         missileHitSurvive   = false
   
    public method checkMissileHit takes nothing returns nothing
    endmethod
   
    public method isMissileHit takes CustomMissile theMissile returns boolean
        return .missileHitGroup[theMissile] == 1
    endmethod
   
    stub method missileHitCond takes CustomMissile theMissile returns boolean
        local   boolean     triggerHit  = true
       
        set triggerHit = triggerHit and theMissile.isAlive and theMissile.isActive
        set triggerHit = triggerHit and not .isMissileHit(theMissile)
       
        return triggerHit
    endmethod
   
    stub method onMissileHit takes CustomMissile theMissile returns boolean
        //: return whether missile should stay alive or not
        return thistype.missileHitSurvive
    endmethod
   
    private static method clearMissileHit takes nothing returns nothing
        if .missileHitGroup != 0 then
            call .missileHitGroup.reset()
            call .missileHitGroup.destroy()
            set .missileHitGroup = 0
        endif
    endmethod
   
    private static method onInit takes nothing returns nothing
        call thistype.addPeriodic(function thistype.checkMissileHit)
        call thistype.addCleanup(function thistype.clearMissileHit)
    endmethod
endmodule
//TESH.scrollpos=-1
//TESH.alwaysfold=0
module MissileDecay
    public      real        decay       = 0.
   
    public static method checkDecay takes nothing returns nothing
        local thistype this = thistype.SELF
       
        if .decay <= 0. then
            set .isAlive = false
            set .isActive = false
        else
            set .decay = .decay - thistype.period
        endif
    endmethod
   
    private static method onInit takes nothing returns nothing
        call thistype.addPeriodic(function thistype.checkDecay)
    endmethod
endmodule
//TESH.scrollpos=-1
//TESH.alwaysfold=0
library MissileMovement requires Loc
    function GetHeightChange takes Loc firstLoc, Loc secLoc, real speed, real period returns real
        return (speed / firstLoc.distanceTo(secLoc) * (secLoc.z - firstLoc.z)) * period
    endfunction
   
    function GetZAngle takes real x1, real y1, real z1, real x2, real y2, real z2 returns real
        return Atan2(z2 - z1, SquareRoot((x2-x1) * (x2-x1) + (y2-y1) * (y2-y1)))
    endfunction
   
    function GetXYArcDistance takes real h, real d, real x returns real
        return (4 * h / d) * (d - x) * (x / d)
    endfunction
   
    //: y0 = starting height
    //: y1 = end height
    //: h = max height
    //: d = max distance
    //: x = current distance
    function GetZArcHeight takes real y0, real y1, real h, real d, real x returns real
        //: Thanks to The_Reborn_Devil, he's a mathbeast
        return ((2*(y0+y1)-4*h)/(d*d))*x*x + ((y1-y0-((2*(y0+y1)-4*h)/(d*d))*d*d)/d)*x + y0
    endfunction
   
    function GetZArcMaxHeight takes real startZ, real targZ, real maxDist, real arc returns real
        return ((startZ + targZ) / 2) + (maxDist * arc)
    endfunction
endlibrary
   
module MissileMovement
    public  real        moveSpeed       = 1000.
    public  real        turnSpeed       = -1.
   
    public  real        offsetX         = 0.
    public  real        offsetY         = 0.
    public  real        offsetZ         = 0.
    public  real        offsetF         = 0.
    public  real        offsetXYAngle   = 0.
    public  real        offsetZAngle    = 0.
   
    public  real        xySpeed         = 0.
    public  real        zSpeed          = 0.
   
    public  real        xyArc           = 0.
    public  real        zArc            = 0.
   
    public  boolean     moveXY          = true
    public  boolean     moveZ           = true
   
    public  boolean     changeXYAngle   = true
    public  boolean     changeZAngle    = true
   
    public  boolean     waitForXYAngle  = false
    public  boolean     waitForZAngle   = false
   
    public  Loc         startLoc        = 0
   
    public  static      Loc             CUR_LOC         = 0
    public  static      Loc             NEXT_LOC        = 0
    public  static      real            RAD_PER_PERIOD  = 0.
   
    public method execMove takes Loc targLoc returns nothing
        local real curXYAngle = makeRealAngle(.f)
        local real newXYAngle = curXYAngle
        local real turnAround = thistype.RAD_PER_PERIOD / .turnSpeed
        local real targXYAngle = 0
        local real curDistance = 0
        local real maxDistance = 0
        local real maxHeight = 0.
        local boolean doWaitForXYAngle = false
        local boolean doWaitForZ = false
       
        call thistype.CUR_LOC.applyLoc(.loc)
        call thistype.NEXT_LOC.applyLoc(.loc)
       
        set targXYAngle = makeRealAngle(thistype.CUR_LOC.angleTo(targLoc))
        set curDistance = thistype.CUR_LOC.distanceTo(.startLoc)
        set maxDistance = .startLoc.distanceTo(targLoc)
       
        if .changeXYAngle then
            if .turnSpeed == -1. then
                set newXYAngle = targXYAngle
            elseif curXYAngle < targXYAngle then
                set newXYAngle = curXYAngle + turnAround
                if newXYAngle > targXYAngle then
                    set newXYAngle = targXYAngle
                endif
                if .waitForXYAngle then
                    set doWaitForXYAngle = newXYAngle < targXYAngle
                endif
            elseif curXYAngle > targXYAngle then
                set newXYAngle = curXYAngle - turnAround
                if newXYAngle < targXYAngle then
                    set newXYAngle = targXYAngle
                endif
                if .waitForXYAngle then
                    set doWaitForXYAngle = newXYAngle > targXYAngle
                endif
            endif
        endif
       
        set thistype.NEXT_LOC.f = newXYAngle
        set .f = newXYAngle
       
        if .moveXY and not doWaitForXYAngle and R2I(curDistance) != R2I(maxDistance) then
            call thistype.NEXT_LOC.move(.moveSpeed * thistype.period)
            set .x = thistype.NEXT_LOC.x
            set .y = thistype.NEXT_LOC.y
            if .xyArc != 0. then
                call thistype.NEXT_LOC.moveFaced(GetXYArcDistance(maxDistance * .xyArc, maxDistance, curDistance), targXYAngle + 1.571) // 90deg to rad
                call .applyXOnce(thistype.NEXT_LOC.x)
                call .applyYOnce(thistype.NEXT_LOC.y)
                call .applyFOnce(makeRealAngle(thistype.NEXT_LOC.angleTo(targLoc)))
            endif
        endif
       
        if .moveZ then
            if .zArc == 0. then
                set thistype.NEXT_LOC.z = thistype.NEXT_LOC.z + GetHeightChange(thistype.NEXT_LOC, targLoc, .moveSpeed, thistype.period)
            else
                set maxHeight = GetZArcMaxHeight(.startLoc.z, targLoc.z, maxDistance, .zArc)
                set thistype.NEXT_LOC.z = GetZArcHeight(.startLoc.z, targLoc.z, maxHeight, maxDistance, curDistance)
            endif
            set .z = thistype.NEXT_LOC.z
        endif
       
        if .changeZAngle and not doWaitForZ then
            set .zAngle = GetZAngle(thistype.CUR_LOC.x, thistype.CUR_LOC.y, thistype.CUR_LOC.z, thistype.NEXT_LOC.x, thistype.NEXT_LOC.y, thistype.NEXT_LOC.z)
        endif
    endmethod
   
    private static method onInit takes nothing returns nothing
        set thistype.CUR_LOC = Loc.create(0., 0., 0., 0.)
        set thistype.NEXT_LOC = Loc.create(0., 0., 0., 0.)
        set thistype.RAD_PER_PERIOD = bj_PI * 2 * thistype.period
    endmethod
endmodule
//TESH.scrollpos=-1
//TESH.alwaysfold=0
module MissileUnitTarget
    public      boolean     hasUnitTarget           = false
    public      real        unitTargetHitRange      = 0.
    public      boolean     checkUnitTargetHeight   = false
    public      unit        unitTarget              = null
   
    private     static      Loc   LOC_TARGET        = 0
   
    implement optional MissileMovement
   
    public method fire takes Loc theStart, unit theTarget returns nothing
        set .startLoc = theStart.clone()
        set .unitTarget = theTarget
        call .use(.startLoc.x, .startLoc.y, .startLoc.z, .startLoc.f)
    endmethod
   
    private static method move takes nothing returns nothing
        local thistype this = thistype.SELF
        local real targX = GetUnitX(.unitTarget) + .offsetX
        local real targY = GetUnitY(.unitTarget) + .offsetY
        local real targZ = GetLocZ(targX, targY) + GetUnitFlyHeight(.unitTarget) + .offsetZ
        local real targF = (GetUnitFacing(.unitTarget) * bj_DEGTORAD) + .offsetF
        local boolean hitsTarget = false
       
        call thistype.LOC_TARGET.applyNew(targX, targY, targZ, targF)
        call .execMove(thistype.LOC_TARGET)
       
        if .checkUnitTargetHeight then
            set hitsTarget = DistBetweenUnitsZ(.toUnit(), .unitTarget) <= .unitTargetHitRange
        else
            set hitsTarget = DistBetweenUnits(.toUnit(), .unitTarget) <= .unitTargetHitRange
        endif
       
        if hitsTarget then
            if not .onUnitTargetHit() then
                set .isAlive = false
                set .isActive = false
            endif
        endif
    endmethod
   
    stub method onUnitTargetHit takes nothing returns boolean
        return false
    endmethod
   
    private static method cleanupLocTarget takes nothing returns nothing
        local thistype this = thistype.SELF
        set .unitTarget = null
        if .startLoc != 0 then
            call .startLoc.destroy()
            set .startLoc = 0
        endif
    endmethod
   
    public static method onInit takes nothing returns nothing
        set thistype.LOC_TARGET = Loc.create(0., 0., 0., 0.)
        call thistype.addPeriodic(function thistype.move)
        call thistype.addCleanup(function thistype.cleanupLocTarget)
    endmethod
endmodule
//TESH.scrollpos=-1
//TESH.alwaysfold=0
module MissileLocTarget
    public      boolean     hasLocTarget           = false
    public      real        locTargetHitRange      = 0.
    public      boolean     checkLocTargetHeight   = false
    public      Loc         locTarget              = 0
   
    implement optional MissileMovement
   
    public method fire takes Loc theStart, Loc theTarget returns nothing
        set .startLoc = theStart.clone()
        set .locTarget = theTarget.clone()
        call .use(.startLoc.x, .startLoc.y, .startLoc.z, .startLoc.f)
    endmethod
   
    private static method move takes nothing returns nothing
        local thistype this = thistype.SELF
        local boolean hitsTarget = false
       
        call .execMove(.locTarget)
       
        if .checkLocTargetHeight then
            set hitsTarget = .locTarget.distanceToZ(.loc) <= .locTargetHitRange
        else
            set hitsTarget = .locTarget.distanceTo(.loc) <= .locTargetHitRange
        endif
       
        if hitsTarget then
            if not .onLocTargetHit() then
                set .isAlive = false
                set .isActive = false
            endif
        endif
    endmethod
   
    stub method onLocTargetHit takes nothing returns boolean
        return false
    endmethod
   
    private static method cleanupLocTarget takes nothing returns nothing
        local thistype this = thistype.SELF
        if .startLoc != 0 then
            call .startLoc.destroy()
            set .startLoc = 0
        endif
        if .locTarget != 0 then
            call .locTarget.destroy()
            set .locTarget = 0
        endif
    endmethod
   
    public static method onInit takes nothing returns nothing
        call thistype.addPeriodic(function thistype.move)
        call thistype.addCleanup(function thistype.cleanupLocTarget)
    endmethod
endmodule
//TESH.scrollpos=-1
//TESH.alwaysfold=0
module MissileBounds
    private     static          real                MIN_X           = GetRectMinX(bj_mapInitialPlayableArea)
    private     static          real                MIN_Y           = GetRectMinY(bj_mapInitialPlayableArea)
    private     static          real                MAX_X           = GetRectMaxX(bj_mapInitialPlayableArea)
    private     static          real                MAX_Y           = GetRectMaxY(bj_mapInitialPlayableArea)
endmodule
//TESH.scrollpos=-1
//TESH.alwaysfold=0
module MissileCastHelper
    public  static  trigger     CAST_TRIG       = null

    private static method castCond takes nothing returns boolean
        return GetSpellAbilityId() == thistype.ABILITY_ID
    endmethod
   
    private static method onInit takes nothing returns nothing
        local integer i = 0
       
        set thistype.CAST_TRIG = CreateTrigger()
       
        call TriggerAddCondition(thistype.CAST_TRIG, Condition(function thistype.castCond))
        call TriggerAddAction(thistype.CAST_TRIG, function thistype.onCast)
       
        loop
            exitwhen i >= bj_MAX_PLAYER_SLOTS
           
            call TriggerRegisterPlayerUnitEvent(thistype.CAST_TRIG, Player(i), EVENT_PLAYER_UNIT_SPELL_CAST, null)
            set i = i +1
        endloop
    endmethod
endmodule

module MissileCastEndHelper
    public  static  trigger     ENDCAST_TRIG       = null

    private static method castEndCond takes nothing returns boolean
        return GetSpellAbilityId() == thistype.ABILITY_ID
    endmethod
   
    private static method onInit takes nothing returns nothing
        local integer i = 0
       
        set thistype.ENDCAST_TRIG = CreateTrigger()
       
        call TriggerAddCondition(thistype.ENDCAST_TRIG, Condition(function thistype.castEndCond))
        call TriggerAddAction(thistype.ENDCAST_TRIG, function thistype.onCastEnd)
       
        loop
            exitwhen i >= bj_MAX_PLAYER_SLOTS
           
            call TriggerRegisterPlayerUnitEvent(thistype.ENDCAST_TRIG, Player(i), EVENT_PLAYER_UNIT_SPELL_ENDCAST, null)
            set i = i +1
        endloop
    endmethod
endmodule

module MissileBuffHelper
    //public    static  integer     BUFF_ID         = 0
    //public    static  string      BUFF_ORDER      = ""
    public  unit    dummy       = null
   
    public method createDummy takes integer theLevel returns nothing
        set .dummy = CreateUnit(GetOwningPlayer(.toUnit()), EFFECT_UNIT_TYPE, .x, .y, 0.)
        call UnitAddAbility(.dummy, 'Aloc')
        call UnitAddAbility(.dummy, thistype.BUFF_ID)
        call SetUnitAbilityLevel(.dummy, thistype.BUFF_ID, theLevel)
    endmethod
   
    public method castDummy takes unit theUnit returns nothing
        call SetUnitX(.dummy, GetUnitX(theUnit))
        call SetUnitY(.dummy, GetUnitY(theUnit))
        call IssueTargetOrder(.dummy, thistype.BUFF_ORDER, theUnit)
    endmethod
   
    private static method clearDummy takes nothing returns nothing
        local thistype this = thistype.SELF
        call RemoveUnit(.dummy)
    endmethod
   
    private static method onInit takes nothing returns nothing
        call thistype.addCleanup(function thistype.clearDummy)
    endmethod
endmodule
//TESH.scrollpos=-1
//TESH.alwaysfold=0
scope ParalyzingWave

    private struct dm extends Missile
        implement MissileLocTarget
        implement MissileUnitHit
        implement MissileGroundHit
    endstruct

    private struct msl extends dm
        private static integer      BUFF_ID     = 'pssl'
        private static string       BUFF_ORDER  = "slow"
   
        public real dmg = 0.
        public unit caster = null
       
        implement MissileBuffHelper
       
        method onRegister takes nothing returns nothing
            set .owner              = GetOwningPlayer(.caster)
           
            set .sfx                = "Abilities\\Weapons\\WingedSerpentMissile\\WingedSerpentMissile.mdl"
            set .scale              = 2.
           
            set .moveSpeed          = 700.
            set .turnSpeed          = .15
            set .unitHitRange       = 125.
            set .height             = 50.
            set .locTargetHitRange  = 50.
        endmethod
       
        method onUnitHit takes unit theUnit returns boolean
            call UnitDamageTarget(.caster, theUnit, .dmg, false, false, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_UNKNOWN, WEAPON_TYPE_WHOKNOWS)
            call .castDummy(theUnit)
            return true
        endmethod
    endstruct
   
    private struct spell
        private static integer      ABILITY_ID  = 'plsh'
       
        implement MissileCastHelper
       
        private static method onCast takes nothing returns nothing
            local   msl         m           = msl.create()
            local   unit        u           = GetTriggerUnit()
            local   Loc         target      = Loc.fromXY(GetSpellTargetX(), GetSpellTargetY())
            local   Loc         source      = Loc.fromUnit(u)
            local   integer     lvl         = GetUnitAbilityLevel(u, thistype.ABILITY_ID)
            local   real        face        = source.angleTo(target)
           
            set m.caster = u
            set m.dmg = 50 + lvl * 50
           
            set source.z = GetLocZ(source.x, source.y) + 50.
            set m.moveZ = false // dont set unit z coordinate after initial setting
           
            call target.applyLoc(source)
            call target.moveFaced(1200., face)
            set target.z = GetLocZ(target.x, target.y) + 50.
           
            set source.f = face
            call m.fire(source, target)
            call m.createDummy(lvl)
           
            call source.destroy()
            call target.destroy()
        endmethod
    endstruct

endscope
 
//TESH.scrollpos=-1
//TESH.alwaysfold=0
scope RainOfFire //requires Missile, Table, StructUtils, Loc, MissileSpellHelper
   
    private struct dm extends Missile
        implement MissileUnitHit
    endstruct

    private struct msl extends dm    
        public real dmg = 0.
        public unit caster = null
       
        public method onUnitHit takes unit theUnit returns boolean
            call UnitDamageTarget(.caster, theUnit, .dmg, false, false, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_UNKNOWN, WEAPON_TYPE_WHOKNOWS)
            return true
        endmethod
       
        public method onPeriod takes nothing returns boolean
            if GetLocZ(.x, .y) >= .z then
                call DestroyEffect(AddSpecialEffect("Abilities\\Weapons\\LavaSpawnMissile\\LavaSpawnBirthMissile.mdl", .x, .y))
                set .hitsUnits = true
                call .checkUnitHit()
                return false
            endif
           
            set .z = .z - 1200 * thistype.period
            return true
        endmethod
       
        method onRegister takes nothing returns nothing
            set .owner              = GetOwningPlayer(.caster)
           
            set .sfx                = "Abilities\\Weapons\\RedDragonBreath\\RedDragonMissile.mdl"
            set .hitsUnits          = false
            set .unitHitRange       = 125.
           
            set .height             = 50.
        endmethod
    endstruct
   
    private struct dummySpell
        private static real         period      = 1.
       
        implement PeriodicStruct
    endstruct
   
    private struct spell extends dummySpell
        private static integer      ABILITY_ID  = 'roar'
        private static Table        MAP         = 0
        private static thistype     WAVESIZE    = 5
       
        private        unit         caster      = null
        private        integer      level       = 0
        private        Loc          target      = 0
       
        implement MissileCastHelper
        implement MissileCastEndHelper
       
        public method onPeriod takes nothing returns boolean
            local msl m = 0
            local integer i = 0
            local Loc l = Loc.create(0., 0., 0., 0.)
           
            loop
                exitwhen i >= WAVESIZE
                set m = msl.create()
                set m.dmg = 20 + .level * 10
                set m.caster = .caster
                call l.applyLoc(.target)
               
                call l.moveFaced(125., 360. / WAVESIZE * i * bj_DEGTORAD)
               
                call m.use(l.x, l.y, l.z + 2000., l.f)
                set i = i +1
            endloop
           
            set m = msl.create()
            set m.dmg = 20 + .level * 10
            set m.caster = .caster
            call m.use(.target.x, .target.y, .target.z + 2000., .target.f)
           
            call l.destroy()
            return true
        endmethod
       
        private static method onCast takes nothing returns nothing
            local unit u = GetTriggerUnit()
            local integer id = GetHandleId(u)
            local thistype this = thistype.create()
           
            set thistype.MAP[id] = this
            call this.register()
           
            set .target = Loc.fromXY(GetSpellTargetX(), GetSpellTargetY())
            set .level = GetUnitAbilityLevel(u, thistype.ABILITY_ID)
            set .caster = u
           
            set u = null
            //call BJDebugMsg("RainOfFire: onCast")
        endmethod
       
        private static method onCastEnd takes nothing returns nothing
            local unit u = GetTriggerUnit()
            local integer id = GetHandleId(u)
            local thistype this = 0
           
            //call BJDebugMsg("RainOfFire: onCastEnd")
           
            if thistype.MAP.exists(id) then
                //call BJDebugMsg("RainOfFire: onCastEnd --> found instance")
                set this = thistype.MAP[id]
                call thistype.MAP.flush(id)
                call .destroy()
            endif
           
            set u = null
        endmethod
       
        private method onDestroy takes nothing returns nothing
            if .target != 0 then
                call .target.destroy()
                set .target = 0
            endif
            call .unregister()
        endmethod
       
        private static method onInit takes nothing returns nothing
            set thistype.MAP = Table.create()
        endmethod
    endstruct

endscope