[vJASS] Looking for ways to make this spell more computationally efficient

Hello Hive,

I am wondering if there is a way that I can make the attached spell more computationally efficient?

edit: I was using a local varable for the group "g" but I figured destroying it and re-creating it would be wasteful when I can re-use it

Spell:

JASS:
scope LaserSweep
    private struct Missile extends Missiles
    static integer AID = 'A008'
    static real angleincrement = 9.0
    real angle
    static real distance = 1200.
    real anglecovered
    static real anglecoveredmax = 45.
    group alreadyhit
    Lightning beam
    static group g = CreateGroup()

        method onFinish takes nothing returns boolean
    if UnitAlive(source) and anglecovered < anglecoveredmax then
        set angle = angle + angleincrement
        set anglecovered = anglecovered + angleincrement       
        call deflect(GetUnitX(source) + distance * Cos(angle * bj_DEGTORAD),GetUnitY(source) + distance * Sin(angle * bj_DEGTORAD),0)
        return false
    endif
    call DestroyGroup(alreadyhit)
    call beam.remove()
    return true
    endmethod

        method onPeriod takes nothing returns boolean
        local unit u
        call LightningUtils.enumUnits(g, beam, 100.)
        loop
        set u=FirstOfGroup(g)
        exitwhen u==null
        if not IsUnitInGroup(u,alreadyhit) and IsUnitEnemy(u, owner) and not IsUnitType(u, UNIT_TYPE_MAGIC_IMMUNE) and not BlzIsUnitInvulnerable(u) and UnitAlive(u) and not IsUnitType(u,UNIT_TYPE_STRUCTURE) then
            call GroupAddUnit(alreadyhit,u)
            call UnitDamageTarget(source, u, damage, false, true, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_MAGIC, null)
            call AddUnitBonusTimed(u,BONUS_ARMOR,-5,30.0)
        endif
        call GroupRemoveUnit(g,u)
        endloop
        set beam.targetX = .x
        set beam.targetY = .y
            return false
        endmethod

        static method onCast takes nothing returns nothing
            local unit     c = GetTriggerUnit()
            local real     x = GetUnitX(c)
            local real     y = GetUnitY(c)
        local real startingangle = GetUnitFacing(c) - (anglecoveredmax / 2)
        local real startingx = x + distance * Cos(startingangle * bj_DEGTORAD)
        local real startingy = y + distance * Sin(startingangle * bj_DEGTORAD)
            local thistype this = thistype.create(startingx, startingy, 50.0, startingx,startingy, 50.0)

            set source    = c
        set owner = GetOwningPlayer(c)
            set model     = ""
            set speed     = 1000
            set arc       = 0.
            set curve     = 0.
        set damage = 150 + (150 * GetUnitAbilityLevel(c,AID))
        set .angle = GetUnitFacing(c)
        set .anglecovered = 0.
        set .beam = Lightning.unitToPoint(c,startingx,startingy,50,50.,false,0.,"DRAM",0)
        set .alreadyhit = CreateGroup()
            call launch()
        set c=null
        endmethod

        static method onInit takes nothing returns nothing
            call RegisterSpellEffectEvent(AID, function thistype.onCast)
        endmethod
    endstruct
endscope

Lightning System:

JASS:
//TESH.scrollpos=75
//TESH.alwaysfold=0
/*
    Lightning System v1.03
    by Adiktuz
   
    Basically it allows you to easily create timed or un-timed lightning effects
   
    Features:
        ->You can create lightnings between two points, two unit, or a point and a unit.
        ->For lightnings attached to a unit, the system automatically updates the lightning
          for changes on the unit (like  unit position, height etc)
        ->Specify the height of the lightning
        ->Create timed-lightnings that get automatically destroyed when their duration is over
        ->Supports moving points too (but the lightnings are forced to be timed)
        ->Allows you to add actions that will run when a lightning has ended and during
          update (time of which is equal to T32's period)
        ->Allows you to attach any type of custom data to each instance
       
    Methods available
       
        How to use: call Lightning.methodName(parameters)
       
        unitToPoint takes unit unit1, real x, real y, real sourceZ, real targetZ, boolean timed, real duration, string leffect, integer eventkey returns thistype
        unitToUnit takes unit unit1, unit unit2, real sourceZ, real targetZ, boolean timed, real duration, string leffect, integer eventkey  returns thistype
        pointToPoint takes real sourceX, real sourceY,real targetX, real targetY, real sourceZ, real targetZ, boolean timed, real duration, string leffect, integer eventkey  returns thistype
        pointToPointEx takes real sourceX, real deltaSourceX, real sourceY, real deltaSourceY, real targetX, real deltaTargetX, real targetY, real deltaTargetY, real sourceZ, real targetZ, real duration, string leffect, integer eventkey  returns thistype
        unitToPointEx takes unit unit1, real x, real xx, real y, real yx, real sourceZ, real targetZ, real duration, string leffect, integer eventkey  returns thistype
        pointToPointExZ takes real sourceX, real deltaSourceX, real sourceY, real deltaSourceY, real targetX, real deltaTargetX, real targetY, real deltaTargetY, real sourceZ, real sourceCurZ, real targetZ, real targetCurZ, real duration, string leffect, integer eventkey  returns thistype
        unitToPointExZ takes unit unit1, real x, real xx, real y, real yx, real sourceZ, real targetZ, real targetCurZ, real duration, string leffect, integer eventkey  returns thistype
       
        Parameters:
       
        unit unit1 -> unit end of the lightning
        unit unit2 -> other unit end of the lightning for the UTU methods
        real x,y -> X,Y coordinates of the point end of the lightning for the UTP methods
        real sourceX,sourceY -> X,Y coordinates of the first point of the lightning for the PTP methods
        real sourceZ,targetZ -> height of the lightning at each ends (actual height is calculated as z + height of unit (if there's a unit end) + locationZ)
        real deltaSourceX,deltaSourceY,deltaTargetX,deltaTargetY,sourceCurZ,targetCurZ -> for the Ex and ExZ methods, the final value of each coordinate/height
             (the lightning moves from sourceX to deltaSourceX, etc through the given time)
        boolean timed -> whether the lightning has a timed life or not, defaulted to true for the Ex and ExZ methods
        real duration -> timed life of the lightning
        string leffect -> string name of the lightning effect
        integer eventkey -> a key used to determine the correct update and end functions to run if available
                            (if you're not using the update and end events, you're probably saf to just set it to 0)
       
        Note: all of the above methods return the Lightning instance so you can save it in a variable
       
        Extra/Interface/Events:
       
        registerUpdateEvent(integer eventkey, code ToDo) returns nothing
        -> allows you to register an action that will be run whenever a lightning with the
           same eventkey as the one registered is updated (every T32_PERIOD)
       
        registerEndEvent(integer eventkey, code ToDo) returns nothing
        -> allows you to register an action that will be run whenever a lightning with the
           same eventkey as the one registered ends
       
        NOTE: If you're going to use the next three functions/methods, make sure you set the
              corresponding boolean at the globals block to true
       
        registerGlobalUpdateEvent(code ToDo) returns nothing
        -> allows you to register an action that will be run whenever a lightning
           is updated (every T32_PERIOD)
       
        registerGlobalEndEvent(code ToDo) returns nothing
        -> allows you to register an action that will be run whenever a lightning ends
       
        registerGlobalCreateEvent(code ToDo) returns nothing
        -> allows you to register an action that will be run whenever a lightning is created
       
        To allow creation and usage of custom data that is attached to every instance
        turn the boolean USE_CUSTOM_DATA to true
       
        then to add a custom data to an instance:
       
        for integers:
       
        set YourLightningInstance.customData[integer key] = value
       
        for others:
       
        set YourLightningInstance.customData.type[integer key] = value
       
        ->type can be real,unit,trigger,effect, etc...
       
        ->integer key is the key that will point to the data, you can utilize StringHash if you want to use strings
          something like: customData.real[StringHash("damage")]
         
        then to load data:
       
        YourLightningInstance.customData.type[integer key]
       
        To forcefully remove a lightning:
       
        remove() returns nothing
       
        To obtain which lightning instance triggered the events:
       
        instance()
*/


    //DO NOT EDIT ANYTHING BELOW THIS LINE UNLESS YOU KNOW WHAT YOU ARE DOING
   
   
    //Note: I've set the checkvisibility field to false because the lightnings look
    //      weird when I set it to true (sometimes they "jump")
   
library LightningSystem requires T32, Table

    globals
        //Set this to true if you're gonna use the global update event handler
        private constant boolean USE_GLOBAL_UPDATE = false
        //Set this to true if you're gonna use the global end event handler
        private constant boolean USE_GLOBAL_END = false
        //Set this to true if you're gonna use the global create event handler
        private constant boolean USE_GLOBAL_CREATE = false
        //Set this to true if you're gonna use the custom data feature
        private constant boolean USE_CUSTOM_DATA = true
        private location loc = Location(0,0)
        public Table UpdateTable
        public Table EndTable
        private trigger globalUpdate
        private trigger globalEnd
        private trigger globalCreate
    endglobals
   
    private module init
        static method onInit takes nothing returns nothing
            set EndTable = Table.create()
            set UpdateTable = Table.create()
            static if USE_GLOBAL_UPDATE then
                set globalUpdate = CreateTrigger()
            endif
            static if USE_GLOBAL_END then
                set globalEnd = CreateTrigger()
            endif
            static if USE_GLOBAL_CREATE then
                set globalCreate = CreateTrigger()
            endif
        endmethod
    endmodule
   
    struct Lightning extends array
        lightning light
        real sourceX
        real targetX
        real sourceY
        real targetY
        real sourceZ
        real targetZ
        real sourceZOffset
        real targetZOffset
        real deltaSourceX
        real deltaTargetX
        real deltaSourceY
        real deltaTargetY
        real sourceCurZ
        real targetCurZ
        real deltaSourceZ
        real deltaTargetZ
        unit u1
        unit u2
        integer xtype
        boolean timed
        boolean moving
        real duration
        integer eventkey
        Table customData
        static thistype instance
        private static integer instanceCount = 0
        private static thistype recycle = 0
        private thistype recycleNext
       
        static method registerEndEvent takes integer eventkey, code toDo returns nothing
            if not EndTable.handle.has(eventkey) then
                set EndTable.trigger[eventkey] = CreateTrigger()
            endif
            call TriggerAddCondition(EndTable.trigger[eventkey],Filter(toDo))
        endmethod
       
        static method registerUpdateEvent takes integer eventkey, code toDo returns nothing
            if not UpdateTable.handle.has(eventkey) then
                set UpdateTable.trigger[eventkey] = CreateTrigger()
            endif
            call TriggerAddCondition(UpdateTable.trigger[eventkey],Filter(toDo))
        endmethod
       
        static method registerGlobalEndEvent takes code toDo returns nothing
            call TriggerAddCondition(globalEnd,Filter(toDo))
        endmethod
       
        static method registerGlobalUpdateEvent takes code toDo returns nothing
            call TriggerAddCondition(globalUpdate,Filter(toDo))
        endmethod
       
        static method registerGlobalCreateEvent takes code toDo returns nothing
            call TriggerAddCondition(globalCreate,Filter(toDo))
        endmethod
       
        method remove takes nothing returns nothing
            call DestroyLightning(this.light)
            set instance = this
            if EndTable.handle.has(this.eventkey) then
                call TriggerEvaluate(EndTable.trigger[this.eventkey])
            endif
            static if USE_GLOBAL_END then
                call TriggerEvaluate(globalEnd)
            endif
            call this.stopPeriodic()
            set this.deltaSourceZ = 0.0
            set this.deltaTargetZ = 0.0
            set .recycleNext=recycle
            set recycle=this
        endmethod
       
        static method new takes nothing returns thistype
            local thistype this
            if (recycle == 0) then
                set instanceCount = instanceCount + 1
                return instanceCount
            else
                set this = recycle
                set recycle = recycle.recycleNext
            endif
            return this
        endmethod
       
        private method periodic takes nothing returns nothing
            if this.xtype == 1 then
                set this.sourceX = GetUnitX(this.u1)
                set this.sourceY = GetUnitY(this.u1)
                set this.sourceCurZ = sourceZOffset + BlzGetLocalUnitZ(this.u1) + GetUnitFlyHeight(this.u1)
                if this.moving then
                    set this.targetX = this.targetX + this.deltaTargetX
                    set this.targetY = this.targetY + this.deltaTargetY
                endif
                if this.deltaTargetZ != 0.0 then
                    set this.targetZ = this.targetZ + this.deltaTargetZ
                endif
                set this.targetCurZ = targetZ + this.deltaTargetZ
                call MoveLightningEx(this.light,false,this.sourceX,this.sourceY,this.sourceCurZ,this.targetX,this.targetY,this.targetCurZ)
            elseif this.xtype == 2 then
                set this.sourceX = GetUnitX(this.u1)
                set this.sourceY = GetUnitY(this.u1)
                set this.targetX = GetUnitX(this.u2)
                set this.targetY = GetUnitY(this.u2)
                set this.sourceCurZ = sourceZOffset + BlzGetLocalUnitZ(this.u1) + GetUnitFlyHeight(this.u1)
                set this.targetCurZ = targetZOffset + BlzGetLocalUnitZ(this.u2) + GetUnitFlyHeight(this.u2)
                call MoveLightningEx(this.light,false,this.sourceX,this.sourceY,this.sourceCurZ,this.targetX,this.targetY,this.targetCurZ)
            else
                if this.moving then
                    set this.sourceX = this.sourceX + this.deltaSourceX
                    set this.targetX = this.targetX + this.deltaTargetX
                    set this.sourceY = this.sourceY + this.deltaSourceY
                    set this.targetY = this.targetY + this.deltaTargetY
                    if this.deltaSourceZ != 0.0 then
                        set this.sourceZ = this.sourceZ + this.deltaSourceZ
                    endif
                    if this.deltaTargetZ != 0.0 then
                        set this.targetZ = this.targetZ + this.deltaTargetZ
                    endif
                    set this.sourceCurZ = sourceZ + this.deltaSourceZ
                    set this.targetCurZ = targetZ + this.deltaTargetZ
                    call MoveLightningEx(this.light,false,this.sourceX,this.sourceY,this.sourceCurZ,this.targetX,this.targetY,this.targetCurZ)
                endif
            endif
            set instance = this
            if UpdateTable.handle.has(this.eventkey) then
                call TriggerEvaluate(UpdateTable.trigger[this.eventkey])
            endif
            static if USE_GLOBAL_UPDATE then
                call TriggerEvaluate(globalUpdate)
            endif
            if this.timed then
                set this.duration = this.duration - T32_PERIOD
                if this.duration <= 0.0 then
                    call this.remove()
                endif
            endif
        endmethod
       
        implement T32x
       
        static method unitToPoint takes unit unit1, real x, real y, real sourceZ, real targetZ, boolean timed, real duration, string leffect, integer eventkey returns thistype
            local thistype this = thistype.new()
            set this.u1 = unit1
            set this.u2 = null
            set this.sourceX = GetUnitX(this.u1)
            set this.sourceY = GetUnitY(this.u1)
            set this.targetX = x
            set this.targetY = y
            set this.sourceZOffset =sourceZ
            //call MoveLocation(loc, this.sourceX,this.sourceY)
            set this.sourceZ = sourceZOffset + BlzGetLocalUnitZ(this.u1) + GetUnitFlyHeight(this.u1)
            call MoveLocation(loc, this.targetX,this.targetY)
            set this.targetZ = targetZ + GetLocationZ(loc)
            set this.timed = timed
            set this.duration = duration
            set this.eventkey = eventkey
            set this.light = AddLightningEx(leffect,false,this.sourceX,this.sourceY,this.sourceZ,this.targetX,this.targetY,this.targetZ)
            set this.xtype = 1
            set this.moving = false
            static if USE_CUSTOM_DATA then
                if this.customData < 0 then
                    set this.customData = Table.create()
                endif
            endif
            static if USE_GLOBAL_CREATE then
                call TriggerEvaluate(globalCreate)
            endif
            call this.startPeriodic()
            return this
        endmethod
       
        static method unitToUnit takes unit unit1, unit unit2, real sourceZ, real targetZ, boolean timed, real duration, string leffect, integer eventkey  returns thistype
            local thistype this = thistype.new()
            set this.u1 = unit1
            set this.u2 = unit2
            set this.sourceX = GetUnitX(this.u1)
            set this.sourceY = GetUnitY(this.u1)
            set this.targetX = GetUnitX(this.u2)
            set this.targetY = GetUnitY(this.u2)
            set this.sourceZOffset =sourceZ
            set this.targetZOffset =targetZ
            //call MoveLocation(loc, this.sourceX,this.sourceY)
            set this.sourceZ = sourceZOffset + BlzGetLocalUnitZ(this.u1) + GetUnitFlyHeight(this.u1)
            //call MoveLocation(loc, this.targetX,this.targetY)
            set this.targetZ = targetZOffset + BlzGetLocalUnitZ(this.u2) + GetUnitFlyHeight(this.u2)
            set this.timed = timed
            set this.duration = duration
            set this.eventkey = eventkey
            set this.light = AddLightningEx(leffect,false,this.sourceX,this.sourceY,this.sourceZ,this.targetX,this.targetY,this.targetZ)
            set this.xtype = 2
            set this.moving = false
            static if USE_CUSTOM_DATA then
                if this.customData < 0 then
                    set this.customData = Table.create()
                endif
            endif
            static if USE_GLOBAL_CREATE then
                call TriggerEvaluate(globalCreate)
            endif
            call this.startPeriodic()
            return this
        endmethod
       
        static method pointToPoint takes real sourceX, real sourceY,real targetX, real targetY, real sourceZ, real targetZ, boolean timed, real duration, string leffect, integer eventkey  returns thistype
            local thistype this = thistype.new()
            set this.u1 = null
            set this.u2 = null
            set this.sourceX = sourceX
            set this.sourceY = sourceY
            set this.targetX = targetX
            set this.targetY = targetY
            call MoveLocation(loc, this.sourceX,this.sourceY)
            set this.sourceZ = sourceZ + GetLocationZ(loc)
            call MoveLocation(loc, this.targetX,this.targetY)
            set this.targetZ = targetZ + GetLocationZ(loc)
            set this.timed = timed
            set this.duration = duration
            set this.eventkey = eventkey
            set this.light = AddLightningEx(leffect,false,this.sourceX,this.sourceY,this.sourceZ,this.targetX,this.targetY,this.targetZ)
            set this.xtype = 3
            set this.moving = false
            static if USE_CUSTOM_DATA then
                if this.customData < 0 then
                    set this.customData = Table.create()
                endif
            endif
            static if USE_GLOBAL_CREATE then
                call TriggerEvaluate(globalCreate)
            endif
            call this.startPeriodic()
            return this
        endmethod
       
        static method pointToPointEx takes real sourceX, real deltaSourceX, real sourceY, real deltaSourceY, real targetX, real deltaTargetX, real targetY, real deltaTargetY, real sourceZ, real targetZ, real duration, string leffect, integer eventkey  returns thistype
            local thistype this = thistype.new()
            set this.u1 = null
            set this.u2 = null
            set this.sourceX = sourceX
            set this.sourceY = sourceY
            set this.targetX = targetX
            set this.targetY = targetY
            set this.deltaSourceX = (deltaSourceX - sourceX)*(T32_PERIOD/duration)
            set this.deltaSourceY = (deltaSourceY - sourceY)*(T32_PERIOD/duration)
            set this.deltaTargetX = (deltaTargetX - targetX)*(T32_PERIOD/duration)
            set this.deltaTargetY = (deltaTargetY - targetY)*(T32_PERIOD/duration)
            call MoveLocation(loc, this.sourceX,this.sourceY)
            set this.sourceZ = sourceZ + GetLocationZ(loc)
            call MoveLocation(loc, this.targetX,this.targetY)
            set this.targetZ = targetZ + GetLocationZ(loc)
            set this.timed = true
            set this.duration = duration
            set this.eventkey = eventkey
            set this.light = AddLightningEx(leffect,false,this.sourceX,this.sourceY,this.sourceZ,this.targetX,this.targetY,this.targetZ)
            set this.xtype = 3
            set this.moving = true
            static if USE_CUSTOM_DATA then
                if this.customData < 0 then
                    set this.customData = Table.create()
                endif
            endif
            static if USE_GLOBAL_CREATE then
                call TriggerEvaluate(globalCreate)
            endif
            call this.startPeriodic()
            return this
        endmethod
       
        static method unitToPointEx takes unit unit1, real x, real xx, real y, real yx, real sourceZ, real targetZ, real duration, string leffect, integer eventkey  returns thistype
            local thistype this = thistype.new()
            set this.u1 = unit1
            set this.u2 = null
            set this.sourceX = GetUnitX(this.u1)
            set this.sourceY = GetUnitY(this.u1)
            set this.targetX = x
            set this.targetY = y
            set this.sourceZOffset =sourceZ
            set this.deltaTargetX = (xx - x)*(T32_PERIOD/duration)
            set this.deltaTargetY = (yx - y)*(T32_PERIOD/duration)
            //call MoveLocation(loc, this.sourceX,this.sourceY)
            set this.sourceZ = sourceZOffset + BlzGetLocalUnitZ(this.u1) + GetUnitFlyHeight(this.u1)
            call MoveLocation(loc, this.targetX,this.targetY)
            set this.targetZ = targetZ + GetLocationZ(loc)
            set this.timed = true
            set this.duration = duration
            set this.eventkey = eventkey
            set this.light = AddLightningEx(leffect,false,this.sourceX,this.sourceY,this.sourceZ,this.targetX,this.targetY,this.targetZ)
            set this.xtype = 1
            set this.moving = true
            static if USE_CUSTOM_DATA then
                if this.customData < 0 then
                    set this.customData = Table.create()
                endif
            endif
            static if USE_GLOBAL_CREATE then
                call TriggerEvaluate(globalCreate)
            endif
            call this.startPeriodic()
            return this
        endmethod
       
        static method pointToPointExZ takes real sourceX, real deltaSourceX, real sourceY, real deltaSourceY, real targetX, real deltaTargetX, real targetY, real deltaTargetY, real sourceZ, real sourceCurZ, real targetZ, real targetCurZ, real duration, string leffect, integer eventkey  returns thistype
            local thistype this = thistype.new()
            set this.u1 = null
            set this.u2 = null
            set this.sourceX = sourceX
            set this.sourceY = sourceY
            set this.targetX = targetX
            set this.targetY = targetY
            set this.deltaSourceZ = (sourceCurZ - sourceZ)*(T32_PERIOD/duration)
            set this.deltaTargetZ = (targetCurZ-targetZ)*(T32_PERIOD/duration)
            set this.deltaSourceX = (deltaSourceX - sourceX)*(T32_PERIOD/duration)
            set this.deltaSourceY = (deltaSourceY - sourceY)*(T32_PERIOD/duration)
            set this.deltaTargetX = (deltaTargetX - targetX)*(T32_PERIOD/duration)
            set this.deltaTargetY = (deltaTargetY - targetY)*(T32_PERIOD/duration)
            call MoveLocation(loc, this.sourceX,this.sourceY)
            set this.sourceZ = sourceZ + GetLocationZ(loc)
            call MoveLocation(loc, this.targetX,this.targetY)
            set this.targetZ = targetZ + GetLocationZ(loc)
            set this.timed = true
            set this.duration = duration
            set this.eventkey = eventkey
            set this.light = AddLightningEx(leffect,false,this.sourceX,this.sourceY,this.sourceZ,this.targetX,this.targetY,this.targetZ)
            set this.xtype = 3
            set this.moving = true
            static if USE_CUSTOM_DATA then
                if this.customData < 0 then
                    set this.customData = Table.create()
                endif
            endif
            static if USE_GLOBAL_CREATE then
                call TriggerEvaluate(globalCreate)
            endif
            call this.startPeriodic()
            return this
        endmethod
       
        static method unitToPointExZ takes unit unit1, real x, real xx, real y, real yx, real sourceZ, real targetZ, real targetCurZ, real duration, string leffect, integer eventkey  returns thistype
            local thistype this = thistype.new()
            set this.u1 = unit1
            set this.u2 = null
            set this.sourceX = GetUnitX(this.u1)
            set this.sourceY = GetUnitY(this.u1)
            set this.targetX = x
            set this.targetY = y
            set this.sourceZOffset =sourceZ
            set this.deltaTargetZ = (targetCurZ - targetZ)*(T32_PERIOD/duration)
            set this.deltaTargetX = (xx - x)*(T32_PERIOD/duration)
            set this.deltaTargetY = (yx - y)*(T32_PERIOD/duration)
            //call MoveLocation(loc, this.sourceX,this.sourceY)
            set this.sourceZ = sourceZOffset + BlzGetLocalUnitZ(this.u1) + GetUnitFlyHeight(this.u1)
            call MoveLocation(loc, this.targetX,this.targetY)
            set this.targetZ = targetZ + GetLocationZ(loc)
            set this.timed = true
            set this.duration = duration
            set this.eventkey = eventkey
            set this.light = AddLightningEx(leffect,false,this.sourceX,this.sourceY,this.sourceZ,this.targetX,this.targetY,this.targetZ)
            set this.xtype = 1
            set this.moving = true
            static if USE_CUSTOM_DATA then
                if this.customData < 0 then
                    set this.customData = Table.create()
                endif
            endif
            static if USE_GLOBAL_CREATE then
                call TriggerEvaluate(globalCreate)
            endif
            call this.startPeriodic()
            return this
        endmethod
       
        implement init
    endstruct
   
endlibrary

Lightning Utils:

JASS:
//TESH.scrollpos=114
//TESH.alwaysfold=0
/*
    Lightning Utilities v1.01
    by Adiktuz
   
    A set of methods that can help you make more out of the
    lightning system.
   
    I chose to separate it from the main system because these are
    extra methods only to extend the capabilities of the LS.
    This way, the user has the option of not using LU library
    as the LS will work fine without it.
   
    How to use:
   
        LightningUtils.method(parameters)
   
    Methods:
   
        enumUnits(group g, Lightning light, real radius)
       
    Parameters:
   
        group g -> group that you want to fill with the units between the Lightning's ends
        Lightning light -> the Lightning object
        real radius -> radius around the Lightning in which unit's will be picked
       
    Note: the following Gradient methods are only for timed lightnings
       
        registerGradientKey(integer eventkey)
       
        ->eventkey of the Lightning's that you want to have a color/alpha gradient
       
    Notes:
       
        ->it is important that you register first the eventkey using this method
          before using the next method which sets the gradient of each Lightning
          instance.
        ->Do this registration only once per eventkey
       
        addLightningGradient(Lightning light, real red1, real blue1, real green1, real alpha1,real red2, real blue2, real green2, real alpha2)
       
    Parameters:
   
        Lightning light -> the Lightning instance that you want to have a gradient
        real red1,blue1,green1,alpha1 -> the initial values of the colors/alpha of the Lightning
        real red2,blue2,green2,alpha2 -> the final values of the colors/alpha of the Lightning
                                      ->these reals are from 0.0 up to 1.0
       
    Notes:
       
        ->Make sure that the eventkey used by this Lightning is already registered using the
         method above (registerGradientKey)
        ->This method automatically fetches the duration of the Lightning
        ->Do not modify the Lightning's duration afterwards else it might look bad
       
        See the Example trigger for an example of how to use these methods.
*/

library LightningUtilities requires LightningSystem
   
    private module init
        static method onInit takes nothing returns nothing
            set thistype.redTable = Table.create()
            set thistype.blueTable = Table.create()
            set thistype.greenTable = Table.create()
            set thistype.alphaTable = Table.create()
            set thistype.redCTable = Table.create()
            set thistype.blueCTable = Table.create()
            set thistype.greenCTable = Table.create()
            set thistype.alphaCTable = Table.create()
        endmethod
    endmodule
   
    struct LightningUtils extends array
       
        private static group tmpGroup = CreateGroup()
        private static unit tmpUnit = null
        private static Table redTable
        private static Table blueTable
        private static Table greenTable
        private static Table alphaTable
        private static Table redCTable
        private static Table blueCTable
        private static Table greenCTable
        private static Table alphaCTable
       
        static method enumUnits takes group g, Lightning light, real radius returns nothing
            call LineSegment.EnumUnitsEx(g,light.sourceX, light.sourceY, light.targetX, light.targetY, radius, true, null)
        endmethod
       
        //I used Table to save the RGBA values because if I use the GeLightningColor natives, it returns
        //rounded down values, resulting to bad behavior at durations > 4.0
        static method updateGradient takes nothing returns nothing
            set redCTable.real[Lightning.instance] = redCTable.real[Lightning.instance] + redTable.real[Lightning.instance]
            set blueCTable.real[Lightning.instance] = blueCTable.real[Lightning.instance] + blueTable.real[Lightning.instance]
            set greenCTable.real[Lightning.instance] = greenCTable.real[Lightning.instance] + greenTable.real[Lightning.instance]
            set alphaCTable.real[Lightning.instance] = alphaCTable.real[Lightning.instance] + alphaTable.real[Lightning.instance]
            call SetLightningColor(Lightning.instance.light, redCTable.real[Lightning.instance],greenCTable.real[Lightning.instance],blueCTable.real[Lightning.instance],alphaCTable.real[Lightning.instance])
        endmethod
       
        static method addLightningGradient takes Lightning light, real red1, real blue1, real green1, real alpha1,real red2, real blue2, real green2, real alpha2 returns nothing
            set redCTable.real[light] = red1
            set blueCTable.real[light] = blue1
            set greenCTable.real[light] = green1
            set alphaCTable.real[light] = alpha1
            set redTable.real[light] = (((red2-red1)/light.duration)*T32_PERIOD)
            set blueTable.real[light] = (((blue2-blue1)/light.duration)*T32_PERIOD)
            set greenTable.real[light] = (((green2-green1)/light.duration)*T32_PERIOD)
            set alphaTable.real[light] = (((alpha2-alpha1)/light.duration)*T32_PERIOD)
        endmethod
       
        static method registerGradientKey takes integer eventkey returns nothing
            call Lightning.registerUpdateEvent(eventkey,function thistype.updateGradient)
        endmethod
       
        implement init
    endstruct

endlibrary

Line segment enumeration:

JASS:
library LineSegmentEnumeration /* v2.2b -- hiveworkshop.com/threads/line-segment-enumeration-v1-1.286552/

    Information
    ¯¯¯¯¯¯¯¯¯¯¯

        Allows to enumerate widgets inside a line segment with an offset.
        So basicly it will result in a rect, but which is also allowed to be rotated.
    
    
    Mechanics
    ¯¯¯¯¯¯¯¯¯
    
        (Issue:)
    
        The problem with normal jass rects is that they aren't defined by 4 points, but only by 4 values: x/y -min/max.
        The result is that a jass rect is never rotated, so it's always paralel to the x/y axis.
    
        But when we draw a line from point A to point B we might also create a non-axix-parelel rect, and then
        we can't use the normal rect natives from jass anymore to find out if a point is inside the rect.

        (Solution:)
    
        To solve this problem the system does following:
    
        jass rect: rectangular defined by 4 values (axis paralel)
        custom rect: the real rectangular that is defined by user (not axis parelel)

        1. Create a big jass rect that is big enough so we can ensure to enum all widgets that are potentialy inside our custom rect. (Enum_Group)
           This Enum_Group will contain all wanted units, but may also contain not wanted units.

        2. Construct the custom rect following a form with the same parameters as in this image, but in 2D:
           https://upload.wikimedia.org/wikipedia/commons/thumb/3/33/Ellipsoide.svg/800px-Ellipsoide.svg.png

        3. Loop through Enum_Group and define each widget's coordinates relative to the center of the custom rect as a 2D vector

        4. Get the components of the widget's position vector on the local (rotated) x-y axis of the custom rect

        5. Check if the projected lengths (absolute value of components) of the widget's position is less than <a> and <b> as described in the
           image linked above.

*/
//  --- API ---
//! novjass

    struct LineSegment

        static constant real MAX_UNIT_COLLISION
 
        static method EnumUnitsEx takes group whichgroup, real ax, real ay, real bx, real by, real offset, boolean checkCollision, boolexpr filter returns nothing
        static method EnumUnits takes group whichgroup, real ax, real ay, real bx, real by, real offset, boolexpr filter returns nothing
 
        static method EnumDestructables takes real ax, real ay, real bx, real by, real offset returns nothing
        
        //  after enumerated destructables you have access to:
    
            static integer DestructableCounter      // starts with index "0"
            static destructable array Destructable
        
        static method EnumItems takes real ax, real ay, real bx, real by, real offset returns nothing
        
        //  after enumerated items you have access to:
    
            static integer ItemCounter      // starts with index "0"
            static destructable array Item
        
//! endnovjass
// ==== End API ====

struct LineSegment extends array

    public static constant real MAX_UNIT_COLLISION = 197.00

    private static constant rect RECT = Rect(0, 0, 0, 0)

    private static constant group GROUP = CreateGroup()

    private static real ox
    private static real oy
    private static real dx
    private static real dy
    private static real da
    private static real db
    private static real ui
    private static real uj
    private static real wdx
    private static real wdy

    private static method PrepareRect takes real ax, real ay, real bx, real by, real offset, real offsetCollision returns nothing
        local real maxX
        local real maxY
        local real minX
        local real minY

        // get center coordinates of rectangle
        set ox = 0.5*(ax + bx)
        set oy = 0.5*(ay + by)

        // get rectangle major axis as vector
        set dx = 0.5*(bx - ax)
        set dy = 0.5*(by - ay)

        // get half of rectangle length (da) and height (db)
        set da = SquareRoot(dx*dx + dy*dy)
        set db = offset

        // get unit vector of the major axis
        set ui = dx/da
        set uj = dy/da

        // Prepare the bounding Jass Rect
        set offset = offset + offsetCollision

        if ax > bx then
            set maxX = ax + offset
            set minX = bx - offset
        else
            set maxX = bx + offset
            set minX = ax - offset
        endif

        if ay > by then
            set maxY = ay + offset
            set minY = by - offset
        else
            set maxY = by + offset
            set minY = ay - offset
        endif

        call SetRect(RECT, minX, minY, maxX, maxY)
    endmethod

    private static method RotateWidgetCoordinates takes widget w returns nothing
        // distance of widget from rectangle center in vector form
        set wdx = GetWidgetX(w) - ox
        set wdy = GetWidgetY(w) - oy

        set dx = wdx*ui + wdy*uj    // get the component of above vector in the rect's major axis
        set dy = wdx*(-uj) + wdy*ui // get the component of above vector in the rect's transverse axis
    endmethod

    private static method IsWidgetInRect takes widget w returns boolean
        call RotateWidgetCoordinates(w)

        // Check if the components above are less than half the length and height of the rectangle
        // (Square them to compare absolute values)
        return dx*dx <= da*da and dy*dy <= db*db
    endmethod

    private static method IsUnitInRect takes unit u, boolean checkCollision returns boolean
        if checkCollision then
            call RotateWidgetCoordinates(u)

            // Check if the perpendicular distances of the unit from both axes of the rect are less than
            // da and db
            return IsUnitInRangeXY(u, ox - dy*uj, oy + dy*ui, RAbsBJ(da)) /*
            */ and IsUnitInRangeXY(u, ox + dx*ui, oy + dx*uj, RAbsBJ(db))
        endif

        return IsWidgetInRect(u)
    endmethod

    public static method EnumUnitsEx takes group whichgroup, real ax, real ay, real bx, real by, real offset, boolean checkCollision, boolexpr filter returns nothing
        local unit u

        if checkCollision then
            call PrepareRect(ax, ay, bx, by, offset, MAX_UNIT_COLLISION)
        else
            call PrepareRect(ax, ay, bx, by, offset, 0.00)
        endif

        call GroupEnumUnitsInRect(GROUP, RECT, filter)

        // enum through all tracked units, and check if it's inside bounds
        call GroupClear(whichgroup)
        loop
            set u = FirstOfGroup(GROUP)
            exitwhen u == null

            if IsUnitInRect(u, checkCollision) then
                call GroupAddUnit(whichgroup, u)
            endif

            call GroupRemoveUnit(GROUP, u)
        endloop
    endmethod

    public static method EnumUnits takes group whichgroup, real ax, real ay, real bx, real by, real offset, boolexpr filter returns nothing
        call EnumUnitsEx(whichgroup, ax, ay, bx, by, offset, false, filter)
    endmethod

//! textmacro LSE_WIDGET takes TYPE, NAME
    public static integer $NAME$Counter = -1
    public static $TYPE$ array $NAME$
 
    private static method on$NAME$Filter takes nothing returns nothing
        local $TYPE$ t = GetFilter$NAME$()

        if IsWidgetInRect(t) then
            set $NAME$Counter = $NAME$Counter + 1
            set $NAME$[$NAME$Counter] = t
        endif

        set t = null
    endmethod
 
    public static method Enum$NAME$s takes real ax, real ay, real bx, real by, real offset returns nothing
        call PrepareRect(ax, ay, bx, by, offset, 0.00)

        set $NAME$Counter = -1
        call Enum$NAME$sInRect(RECT, Filter(function thistype.on$NAME$Filter), null)
    endmethod
//! endtextmacro

//! runtextmacro LSE_WIDGET("destructable", "Destructable")
//! runtextmacro LSE_WIDGET("item", "Item")
 
endstruct
endlibrary
 

Attachments

  • laser sweep.w3x
    237.3 KB · Views: 8
Hello Hive,

I am wondering if there is a way that I can make the attached spell more computationally efficient?

edit: I was using a local varable for the group "g" but I figured destroying it and re-creating it would be wasteful when I can re-use it

Spell:

JASS:
scope LaserSweep
    private struct Missile extends Missiles
    static integer AID = 'A008'
    static real angleincrement = 9.0
    real angle
    static real distance = 1200.
    real anglecovered
    static real anglecoveredmax = 45.
    group alreadyhit
    Lightning beam
    static group g = CreateGroup()

        method onFinish takes nothing returns boolean
    if UnitAlive(source) and anglecovered < anglecoveredmax then
        set angle = angle + angleincrement
        set anglecovered = anglecovered + angleincrement      
        call deflect(GetUnitX(source) + distance * Cos(angle * bj_DEGTORAD),GetUnitY(source) + distance * Sin(angle * bj_DEGTORAD),0)
        return false
    endif
    call DestroyGroup(alreadyhit)
    call beam.remove()
    return true
    endmethod

        method onPeriod takes nothing returns boolean
        local unit u
        call LightningUtils.enumUnits(g, beam, 100.)
        loop
        set u=FirstOfGroup(g)
        exitwhen u==null
        if not IsUnitInGroup(u,alreadyhit) and IsUnitEnemy(u, owner) and not IsUnitType(u, UNIT_TYPE_MAGIC_IMMUNE) and not BlzIsUnitInvulnerable(u) and UnitAlive(u) and not IsUnitType(u,UNIT_TYPE_STRUCTURE) then
            call GroupAddUnit(alreadyhit,u)
            call UnitDamageTarget(source, u, damage, false, true, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_MAGIC, null)
            call AddUnitBonusTimed(u,BONUS_ARMOR,-5,30.0)
        endif
        call GroupRemoveUnit(g,u)
        endloop
        set beam.targetX = .x
        set beam.targetY = .y
            return false
        endmethod

        static method onCast takes nothing returns nothing
            local unit     c = GetTriggerUnit()
            local real     x = GetUnitX(c)
            local real     y = GetUnitY(c)
        local real startingangle = GetUnitFacing(c) - (anglecoveredmax / 2)
        local real startingx = x + distance * Cos(startingangle * bj_DEGTORAD)
        local real startingy = y + distance * Sin(startingangle * bj_DEGTORAD)
            local thistype this = thistype.create(startingx, startingy, 50.0, startingx,startingy, 50.0)

            set source    = c
        set owner = GetOwningPlayer(c)
            set model     = ""
            set speed     = 1000
            set arc       = 0.
            set curve     = 0.
        set damage = 150 + (150 * GetUnitAbilityLevel(c,AID))
        set .angle = GetUnitFacing(c)
        set .anglecovered = 0.
        set .beam = Lightning.unitToPoint(c,startingx,startingy,50,50.,false,0.,"DRAM",0)
        set .alreadyhit = CreateGroup()
            call launch()
        set c=null
        endmethod

        static method onInit takes nothing returns nothing
            call RegisterSpellEffectEvent(AID, function thistype.onCast)
        endmethod
    endstruct
endscope

Lightning System:

JASS:
//TESH.scrollpos=75
//TESH.alwaysfold=0
/*
    Lightning System v1.03
    by Adiktuz
  
    Basically it allows you to easily create timed or un-timed lightning effects
  
    Features:
        ->You can create lightnings between two points, two unit, or a point and a unit.
        ->For lightnings attached to a unit, the system automatically updates the lightning
          for changes on the unit (like  unit position, height etc)
        ->Specify the height of the lightning
        ->Create timed-lightnings that get automatically destroyed when their duration is over
        ->Supports moving points too (but the lightnings are forced to be timed)
        ->Allows you to add actions that will run when a lightning has ended and during
          update (time of which is equal to T32's period)
        ->Allows you to attach any type of custom data to each instance
      
    Methods available
      
        How to use: call Lightning.methodName(parameters)
      
        unitToPoint takes unit unit1, real x, real y, real sourceZ, real targetZ, boolean timed, real duration, string leffect, integer eventkey returns thistype
        unitToUnit takes unit unit1, unit unit2, real sourceZ, real targetZ, boolean timed, real duration, string leffect, integer eventkey  returns thistype
        pointToPoint takes real sourceX, real sourceY,real targetX, real targetY, real sourceZ, real targetZ, boolean timed, real duration, string leffect, integer eventkey  returns thistype
        pointToPointEx takes real sourceX, real deltaSourceX, real sourceY, real deltaSourceY, real targetX, real deltaTargetX, real targetY, real deltaTargetY, real sourceZ, real targetZ, real duration, string leffect, integer eventkey  returns thistype
        unitToPointEx takes unit unit1, real x, real xx, real y, real yx, real sourceZ, real targetZ, real duration, string leffect, integer eventkey  returns thistype
        pointToPointExZ takes real sourceX, real deltaSourceX, real sourceY, real deltaSourceY, real targetX, real deltaTargetX, real targetY, real deltaTargetY, real sourceZ, real sourceCurZ, real targetZ, real targetCurZ, real duration, string leffect, integer eventkey  returns thistype
        unitToPointExZ takes unit unit1, real x, real xx, real y, real yx, real sourceZ, real targetZ, real targetCurZ, real duration, string leffect, integer eventkey  returns thistype
      
        Parameters:
      
        unit unit1 -> unit end of the lightning
        unit unit2 -> other unit end of the lightning for the UTU methods
        real x,y -> X,Y coordinates of the point end of the lightning for the UTP methods
        real sourceX,sourceY -> X,Y coordinates of the first point of the lightning for the PTP methods
        real sourceZ,targetZ -> height of the lightning at each ends (actual height is calculated as z + height of unit (if there's a unit end) + locationZ)
        real deltaSourceX,deltaSourceY,deltaTargetX,deltaTargetY,sourceCurZ,targetCurZ -> for the Ex and ExZ methods, the final value of each coordinate/height
             (the lightning moves from sourceX to deltaSourceX, etc through the given time)
        boolean timed -> whether the lightning has a timed life or not, defaulted to true for the Ex and ExZ methods
        real duration -> timed life of the lightning
        string leffect -> string name of the lightning effect
        integer eventkey -> a key used to determine the correct update and end functions to run if available
                            (if you're not using the update and end events, you're probably saf to just set it to 0)
      
        Note: all of the above methods return the Lightning instance so you can save it in a variable
      
        Extra/Interface/Events:
      
        registerUpdateEvent(integer eventkey, code ToDo) returns nothing
        -> allows you to register an action that will be run whenever a lightning with the
           same eventkey as the one registered is updated (every T32_PERIOD)
      
        registerEndEvent(integer eventkey, code ToDo) returns nothing
        -> allows you to register an action that will be run whenever a lightning with the
           same eventkey as the one registered ends
      
        NOTE: If you're going to use the next three functions/methods, make sure you set the
              corresponding boolean at the globals block to true
      
        registerGlobalUpdateEvent(code ToDo) returns nothing
        -> allows you to register an action that will be run whenever a lightning
           is updated (every T32_PERIOD)
      
        registerGlobalEndEvent(code ToDo) returns nothing
        -> allows you to register an action that will be run whenever a lightning ends
      
        registerGlobalCreateEvent(code ToDo) returns nothing
        -> allows you to register an action that will be run whenever a lightning is created
      
        To allow creation and usage of custom data that is attached to every instance
        turn the boolean USE_CUSTOM_DATA to true
      
        then to add a custom data to an instance:
      
        for integers:
      
        set YourLightningInstance.customData[integer key] = value
      
        for others:
      
        set YourLightningInstance.customData.type[integer key] = value
      
        ->type can be real,unit,trigger,effect, etc...
      
        ->integer key is the key that will point to the data, you can utilize StringHash if you want to use strings
          something like: customData.real[StringHash("damage")]
        
        then to load data:
      
        YourLightningInstance.customData.type[integer key]
      
        To forcefully remove a lightning:
      
        remove() returns nothing
      
        To obtain which lightning instance triggered the events:
      
        instance()
*/


    //DO NOT EDIT ANYTHING BELOW THIS LINE UNLESS YOU KNOW WHAT YOU ARE DOING
  
  
    //Note: I've set the checkvisibility field to false because the lightnings look
    //      weird when I set it to true (sometimes they "jump")
  
library LightningSystem requires T32, Table

    globals
        //Set this to true if you're gonna use the global update event handler
        private constant boolean USE_GLOBAL_UPDATE = false
        //Set this to true if you're gonna use the global end event handler
        private constant boolean USE_GLOBAL_END = false
        //Set this to true if you're gonna use the global create event handler
        private constant boolean USE_GLOBAL_CREATE = false
        //Set this to true if you're gonna use the custom data feature
        private constant boolean USE_CUSTOM_DATA = true
        private location loc = Location(0,0)
        public Table UpdateTable
        public Table EndTable
        private trigger globalUpdate
        private trigger globalEnd
        private trigger globalCreate
    endglobals
  
    private module init
        static method onInit takes nothing returns nothing
            set EndTable = Table.create()
            set UpdateTable = Table.create()
            static if USE_GLOBAL_UPDATE then
                set globalUpdate = CreateTrigger()
            endif
            static if USE_GLOBAL_END then
                set globalEnd = CreateTrigger()
            endif
            static if USE_GLOBAL_CREATE then
                set globalCreate = CreateTrigger()
            endif
        endmethod
    endmodule
  
    struct Lightning extends array
        lightning light
        real sourceX
        real targetX
        real sourceY
        real targetY
        real sourceZ
        real targetZ
        real sourceZOffset
        real targetZOffset
        real deltaSourceX
        real deltaTargetX
        real deltaSourceY
        real deltaTargetY
        real sourceCurZ
        real targetCurZ
        real deltaSourceZ
        real deltaTargetZ
        unit u1
        unit u2
        integer xtype
        boolean timed
        boolean moving
        real duration
        integer eventkey
        Table customData
        static thistype instance
        private static integer instanceCount = 0
        private static thistype recycle = 0
        private thistype recycleNext
      
        static method registerEndEvent takes integer eventkey, code toDo returns nothing
            if not EndTable.handle.has(eventkey) then
                set EndTable.trigger[eventkey] = CreateTrigger()
            endif
            call TriggerAddCondition(EndTable.trigger[eventkey],Filter(toDo))
        endmethod
      
        static method registerUpdateEvent takes integer eventkey, code toDo returns nothing
            if not UpdateTable.handle.has(eventkey) then
                set UpdateTable.trigger[eventkey] = CreateTrigger()
            endif
            call TriggerAddCondition(UpdateTable.trigger[eventkey],Filter(toDo))
        endmethod
      
        static method registerGlobalEndEvent takes code toDo returns nothing
            call TriggerAddCondition(globalEnd,Filter(toDo))
        endmethod
      
        static method registerGlobalUpdateEvent takes code toDo returns nothing
            call TriggerAddCondition(globalUpdate,Filter(toDo))
        endmethod
      
        static method registerGlobalCreateEvent takes code toDo returns nothing
            call TriggerAddCondition(globalCreate,Filter(toDo))
        endmethod
      
        method remove takes nothing returns nothing
            call DestroyLightning(this.light)
            set instance = this
            if EndTable.handle.has(this.eventkey) then
                call TriggerEvaluate(EndTable.trigger[this.eventkey])
            endif
            static if USE_GLOBAL_END then
                call TriggerEvaluate(globalEnd)
            endif
            call this.stopPeriodic()
            set this.deltaSourceZ = 0.0
            set this.deltaTargetZ = 0.0
            set .recycleNext=recycle
            set recycle=this
        endmethod
      
        static method new takes nothing returns thistype
            local thistype this
            if (recycle == 0) then
                set instanceCount = instanceCount + 1
                return instanceCount
            else
                set this = recycle
                set recycle = recycle.recycleNext
            endif
            return this
        endmethod
      
        private method periodic takes nothing returns nothing
            if this.xtype == 1 then
                set this.sourceX = GetUnitX(this.u1)
                set this.sourceY = GetUnitY(this.u1)
                set this.sourceCurZ = sourceZOffset + BlzGetLocalUnitZ(this.u1) + GetUnitFlyHeight(this.u1)
                if this.moving then
                    set this.targetX = this.targetX + this.deltaTargetX
                    set this.targetY = this.targetY + this.deltaTargetY
                endif
                if this.deltaTargetZ != 0.0 then
                    set this.targetZ = this.targetZ + this.deltaTargetZ
                endif
                set this.targetCurZ = targetZ + this.deltaTargetZ
                call MoveLightningEx(this.light,false,this.sourceX,this.sourceY,this.sourceCurZ,this.targetX,this.targetY,this.targetCurZ)
            elseif this.xtype == 2 then
                set this.sourceX = GetUnitX(this.u1)
                set this.sourceY = GetUnitY(this.u1)
                set this.targetX = GetUnitX(this.u2)
                set this.targetY = GetUnitY(this.u2)
                set this.sourceCurZ = sourceZOffset + BlzGetLocalUnitZ(this.u1) + GetUnitFlyHeight(this.u1)
                set this.targetCurZ = targetZOffset + BlzGetLocalUnitZ(this.u2) + GetUnitFlyHeight(this.u2)
                call MoveLightningEx(this.light,false,this.sourceX,this.sourceY,this.sourceCurZ,this.targetX,this.targetY,this.targetCurZ)
            else
                if this.moving then
                    set this.sourceX = this.sourceX + this.deltaSourceX
                    set this.targetX = this.targetX + this.deltaTargetX
                    set this.sourceY = this.sourceY + this.deltaSourceY
                    set this.targetY = this.targetY + this.deltaTargetY
                    if this.deltaSourceZ != 0.0 then
                        set this.sourceZ = this.sourceZ + this.deltaSourceZ
                    endif
                    if this.deltaTargetZ != 0.0 then
                        set this.targetZ = this.targetZ + this.deltaTargetZ
                    endif
                    set this.sourceCurZ = sourceZ + this.deltaSourceZ
                    set this.targetCurZ = targetZ + this.deltaTargetZ
                    call MoveLightningEx(this.light,false,this.sourceX,this.sourceY,this.sourceCurZ,this.targetX,this.targetY,this.targetCurZ)
                endif
            endif
            set instance = this
            if UpdateTable.handle.has(this.eventkey) then
                call TriggerEvaluate(UpdateTable.trigger[this.eventkey])
            endif
            static if USE_GLOBAL_UPDATE then
                call TriggerEvaluate(globalUpdate)
            endif
            if this.timed then
                set this.duration = this.duration - T32_PERIOD
                if this.duration <= 0.0 then
                    call this.remove()
                endif
            endif
        endmethod
      
        implement T32x
      
        static method unitToPoint takes unit unit1, real x, real y, real sourceZ, real targetZ, boolean timed, real duration, string leffect, integer eventkey returns thistype
            local thistype this = thistype.new()
            set this.u1 = unit1
            set this.u2 = null
            set this.sourceX = GetUnitX(this.u1)
            set this.sourceY = GetUnitY(this.u1)
            set this.targetX = x
            set this.targetY = y
            set this.sourceZOffset =sourceZ
            //call MoveLocation(loc, this.sourceX,this.sourceY)
            set this.sourceZ = sourceZOffset + BlzGetLocalUnitZ(this.u1) + GetUnitFlyHeight(this.u1)
            call MoveLocation(loc, this.targetX,this.targetY)
            set this.targetZ = targetZ + GetLocationZ(loc)
            set this.timed = timed
            set this.duration = duration
            set this.eventkey = eventkey
            set this.light = AddLightningEx(leffect,false,this.sourceX,this.sourceY,this.sourceZ,this.targetX,this.targetY,this.targetZ)
            set this.xtype = 1
            set this.moving = false
            static if USE_CUSTOM_DATA then
                if this.customData < 0 then
                    set this.customData = Table.create()
                endif
            endif
            static if USE_GLOBAL_CREATE then
                call TriggerEvaluate(globalCreate)
            endif
            call this.startPeriodic()
            return this
        endmethod
      
        static method unitToUnit takes unit unit1, unit unit2, real sourceZ, real targetZ, boolean timed, real duration, string leffect, integer eventkey  returns thistype
            local thistype this = thistype.new()
            set this.u1 = unit1
            set this.u2 = unit2
            set this.sourceX = GetUnitX(this.u1)
            set this.sourceY = GetUnitY(this.u1)
            set this.targetX = GetUnitX(this.u2)
            set this.targetY = GetUnitY(this.u2)
            set this.sourceZOffset =sourceZ
            set this.targetZOffset =targetZ
            //call MoveLocation(loc, this.sourceX,this.sourceY)
            set this.sourceZ = sourceZOffset + BlzGetLocalUnitZ(this.u1) + GetUnitFlyHeight(this.u1)
            //call MoveLocation(loc, this.targetX,this.targetY)
            set this.targetZ = targetZOffset + BlzGetLocalUnitZ(this.u2) + GetUnitFlyHeight(this.u2)
            set this.timed = timed
            set this.duration = duration
            set this.eventkey = eventkey
            set this.light = AddLightningEx(leffect,false,this.sourceX,this.sourceY,this.sourceZ,this.targetX,this.targetY,this.targetZ)
            set this.xtype = 2
            set this.moving = false
            static if USE_CUSTOM_DATA then
                if this.customData < 0 then
                    set this.customData = Table.create()
                endif
            endif
            static if USE_GLOBAL_CREATE then
                call TriggerEvaluate(globalCreate)
            endif
            call this.startPeriodic()
            return this
        endmethod
      
        static method pointToPoint takes real sourceX, real sourceY,real targetX, real targetY, real sourceZ, real targetZ, boolean timed, real duration, string leffect, integer eventkey  returns thistype
            local thistype this = thistype.new()
            set this.u1 = null
            set this.u2 = null
            set this.sourceX = sourceX
            set this.sourceY = sourceY
            set this.targetX = targetX
            set this.targetY = targetY
            call MoveLocation(loc, this.sourceX,this.sourceY)
            set this.sourceZ = sourceZ + GetLocationZ(loc)
            call MoveLocation(loc, this.targetX,this.targetY)
            set this.targetZ = targetZ + GetLocationZ(loc)
            set this.timed = timed
            set this.duration = duration
            set this.eventkey = eventkey
            set this.light = AddLightningEx(leffect,false,this.sourceX,this.sourceY,this.sourceZ,this.targetX,this.targetY,this.targetZ)
            set this.xtype = 3
            set this.moving = false
            static if USE_CUSTOM_DATA then
                if this.customData < 0 then
                    set this.customData = Table.create()
                endif
            endif
            static if USE_GLOBAL_CREATE then
                call TriggerEvaluate(globalCreate)
            endif
            call this.startPeriodic()
            return this
        endmethod
      
        static method pointToPointEx takes real sourceX, real deltaSourceX, real sourceY, real deltaSourceY, real targetX, real deltaTargetX, real targetY, real deltaTargetY, real sourceZ, real targetZ, real duration, string leffect, integer eventkey  returns thistype
            local thistype this = thistype.new()
            set this.u1 = null
            set this.u2 = null
            set this.sourceX = sourceX
            set this.sourceY = sourceY
            set this.targetX = targetX
            set this.targetY = targetY
            set this.deltaSourceX = (deltaSourceX - sourceX)*(T32_PERIOD/duration)
            set this.deltaSourceY = (deltaSourceY - sourceY)*(T32_PERIOD/duration)
            set this.deltaTargetX = (deltaTargetX - targetX)*(T32_PERIOD/duration)
            set this.deltaTargetY = (deltaTargetY - targetY)*(T32_PERIOD/duration)
            call MoveLocation(loc, this.sourceX,this.sourceY)
            set this.sourceZ = sourceZ + GetLocationZ(loc)
            call MoveLocation(loc, this.targetX,this.targetY)
            set this.targetZ = targetZ + GetLocationZ(loc)
            set this.timed = true
            set this.duration = duration
            set this.eventkey = eventkey
            set this.light = AddLightningEx(leffect,false,this.sourceX,this.sourceY,this.sourceZ,this.targetX,this.targetY,this.targetZ)
            set this.xtype = 3
            set this.moving = true
            static if USE_CUSTOM_DATA then
                if this.customData < 0 then
                    set this.customData = Table.create()
                endif
            endif
            static if USE_GLOBAL_CREATE then
                call TriggerEvaluate(globalCreate)
            endif
            call this.startPeriodic()
            return this
        endmethod
      
        static method unitToPointEx takes unit unit1, real x, real xx, real y, real yx, real sourceZ, real targetZ, real duration, string leffect, integer eventkey  returns thistype
            local thistype this = thistype.new()
            set this.u1 = unit1
            set this.u2 = null
            set this.sourceX = GetUnitX(this.u1)
            set this.sourceY = GetUnitY(this.u1)
            set this.targetX = x
            set this.targetY = y
            set this.sourceZOffset =sourceZ
            set this.deltaTargetX = (xx - x)*(T32_PERIOD/duration)
            set this.deltaTargetY = (yx - y)*(T32_PERIOD/duration)
            //call MoveLocation(loc, this.sourceX,this.sourceY)
            set this.sourceZ = sourceZOffset + BlzGetLocalUnitZ(this.u1) + GetUnitFlyHeight(this.u1)
            call MoveLocation(loc, this.targetX,this.targetY)
            set this.targetZ = targetZ + GetLocationZ(loc)
            set this.timed = true
            set this.duration = duration
            set this.eventkey = eventkey
            set this.light = AddLightningEx(leffect,false,this.sourceX,this.sourceY,this.sourceZ,this.targetX,this.targetY,this.targetZ)
            set this.xtype = 1
            set this.moving = true
            static if USE_CUSTOM_DATA then
                if this.customData < 0 then
                    set this.customData = Table.create()
                endif
            endif
            static if USE_GLOBAL_CREATE then
                call TriggerEvaluate(globalCreate)
            endif
            call this.startPeriodic()
            return this
        endmethod
      
        static method pointToPointExZ takes real sourceX, real deltaSourceX, real sourceY, real deltaSourceY, real targetX, real deltaTargetX, real targetY, real deltaTargetY, real sourceZ, real sourceCurZ, real targetZ, real targetCurZ, real duration, string leffect, integer eventkey  returns thistype
            local thistype this = thistype.new()
            set this.u1 = null
            set this.u2 = null
            set this.sourceX = sourceX
            set this.sourceY = sourceY
            set this.targetX = targetX
            set this.targetY = targetY
            set this.deltaSourceZ = (sourceCurZ - sourceZ)*(T32_PERIOD/duration)
            set this.deltaTargetZ = (targetCurZ-targetZ)*(T32_PERIOD/duration)
            set this.deltaSourceX = (deltaSourceX - sourceX)*(T32_PERIOD/duration)
            set this.deltaSourceY = (deltaSourceY - sourceY)*(T32_PERIOD/duration)
            set this.deltaTargetX = (deltaTargetX - targetX)*(T32_PERIOD/duration)
            set this.deltaTargetY = (deltaTargetY - targetY)*(T32_PERIOD/duration)
            call MoveLocation(loc, this.sourceX,this.sourceY)
            set this.sourceZ = sourceZ + GetLocationZ(loc)
            call MoveLocation(loc, this.targetX,this.targetY)
            set this.targetZ = targetZ + GetLocationZ(loc)
            set this.timed = true
            set this.duration = duration
            set this.eventkey = eventkey
            set this.light = AddLightningEx(leffect,false,this.sourceX,this.sourceY,this.sourceZ,this.targetX,this.targetY,this.targetZ)
            set this.xtype = 3
            set this.moving = true
            static if USE_CUSTOM_DATA then
                if this.customData < 0 then
                    set this.customData = Table.create()
                endif
            endif
            static if USE_GLOBAL_CREATE then
                call TriggerEvaluate(globalCreate)
            endif
            call this.startPeriodic()
            return this
        endmethod
      
        static method unitToPointExZ takes unit unit1, real x, real xx, real y, real yx, real sourceZ, real targetZ, real targetCurZ, real duration, string leffect, integer eventkey  returns thistype
            local thistype this = thistype.new()
            set this.u1 = unit1
            set this.u2 = null
            set this.sourceX = GetUnitX(this.u1)
            set this.sourceY = GetUnitY(this.u1)
            set this.targetX = x
            set this.targetY = y
            set this.sourceZOffset =sourceZ
            set this.deltaTargetZ = (targetCurZ - targetZ)*(T32_PERIOD/duration)
            set this.deltaTargetX = (xx - x)*(T32_PERIOD/duration)
            set this.deltaTargetY = (yx - y)*(T32_PERIOD/duration)
            //call MoveLocation(loc, this.sourceX,this.sourceY)
            set this.sourceZ = sourceZOffset + BlzGetLocalUnitZ(this.u1) + GetUnitFlyHeight(this.u1)
            call MoveLocation(loc, this.targetX,this.targetY)
            set this.targetZ = targetZ + GetLocationZ(loc)
            set this.timed = true
            set this.duration = duration
            set this.eventkey = eventkey
            set this.light = AddLightningEx(leffect,false,this.sourceX,this.sourceY,this.sourceZ,this.targetX,this.targetY,this.targetZ)
            set this.xtype = 1
            set this.moving = true
            static if USE_CUSTOM_DATA then
                if this.customData < 0 then
                    set this.customData = Table.create()
                endif
            endif
            static if USE_GLOBAL_CREATE then
                call TriggerEvaluate(globalCreate)
            endif
            call this.startPeriodic()
            return this
        endmethod
      
        implement init
    endstruct
  
endlibrary

Lightning Utils:

JASS:
//TESH.scrollpos=114
//TESH.alwaysfold=0
/*
    Lightning Utilities v1.01
    by Adiktuz
  
    A set of methods that can help you make more out of the
    lightning system.
  
    I chose to separate it from the main system because these are
    extra methods only to extend the capabilities of the LS.
    This way, the user has the option of not using LU library
    as the LS will work fine without it.
  
    How to use:
  
        LightningUtils.method(parameters)
  
    Methods:
  
        enumUnits(group g, Lightning light, real radius)
      
    Parameters:
  
        group g -> group that you want to fill with the units between the Lightning's ends
        Lightning light -> the Lightning object
        real radius -> radius around the Lightning in which unit's will be picked
      
    Note: the following Gradient methods are only for timed lightnings
      
        registerGradientKey(integer eventkey)
      
        ->eventkey of the Lightning's that you want to have a color/alpha gradient
      
    Notes:
      
        ->it is important that you register first the eventkey using this method
          before using the next method which sets the gradient of each Lightning
          instance.
        ->Do this registration only once per eventkey
      
        addLightningGradient(Lightning light, real red1, real blue1, real green1, real alpha1,real red2, real blue2, real green2, real alpha2)
      
    Parameters:
  
        Lightning light -> the Lightning instance that you want to have a gradient
        real red1,blue1,green1,alpha1 -> the initial values of the colors/alpha of the Lightning
        real red2,blue2,green2,alpha2 -> the final values of the colors/alpha of the Lightning
                                      ->these reals are from 0.0 up to 1.0
      
    Notes:
      
        ->Make sure that the eventkey used by this Lightning is already registered using the
         method above (registerGradientKey)
        ->This method automatically fetches the duration of the Lightning
        ->Do not modify the Lightning's duration afterwards else it might look bad
      
        See the Example trigger for an example of how to use these methods.
*/

library LightningUtilities requires LightningSystem
  
    private module init
        static method onInit takes nothing returns nothing
            set thistype.redTable = Table.create()
            set thistype.blueTable = Table.create()
            set thistype.greenTable = Table.create()
            set thistype.alphaTable = Table.create()
            set thistype.redCTable = Table.create()
            set thistype.blueCTable = Table.create()
            set thistype.greenCTable = Table.create()
            set thistype.alphaCTable = Table.create()
        endmethod
    endmodule
  
    struct LightningUtils extends array
      
        private static group tmpGroup = CreateGroup()
        private static unit tmpUnit = null
        private static Table redTable
        private static Table blueTable
        private static Table greenTable
        private static Table alphaTable
        private static Table redCTable
        private static Table blueCTable
        private static Table greenCTable
        private static Table alphaCTable
      
        static method enumUnits takes group g, Lightning light, real radius returns nothing
            call LineSegment.EnumUnitsEx(g,light.sourceX, light.sourceY, light.targetX, light.targetY, radius, true, null)
        endmethod
      
        //I used Table to save the RGBA values because if I use the GeLightningColor natives, it returns
        //rounded down values, resulting to bad behavior at durations > 4.0
        static method updateGradient takes nothing returns nothing
            set redCTable.real[Lightning.instance] = redCTable.real[Lightning.instance] + redTable.real[Lightning.instance]
            set blueCTable.real[Lightning.instance] = blueCTable.real[Lightning.instance] + blueTable.real[Lightning.instance]
            set greenCTable.real[Lightning.instance] = greenCTable.real[Lightning.instance] + greenTable.real[Lightning.instance]
            set alphaCTable.real[Lightning.instance] = alphaCTable.real[Lightning.instance] + alphaTable.real[Lightning.instance]
            call SetLightningColor(Lightning.instance.light, redCTable.real[Lightning.instance],greenCTable.real[Lightning.instance],blueCTable.real[Lightning.instance],alphaCTable.real[Lightning.instance])
        endmethod
      
        static method addLightningGradient takes Lightning light, real red1, real blue1, real green1, real alpha1,real red2, real blue2, real green2, real alpha2 returns nothing
            set redCTable.real[light] = red1
            set blueCTable.real[light] = blue1
            set greenCTable.real[light] = green1
            set alphaCTable.real[light] = alpha1
            set redTable.real[light] = (((red2-red1)/light.duration)*T32_PERIOD)
            set blueTable.real[light] = (((blue2-blue1)/light.duration)*T32_PERIOD)
            set greenTable.real[light] = (((green2-green1)/light.duration)*T32_PERIOD)
            set alphaTable.real[light] = (((alpha2-alpha1)/light.duration)*T32_PERIOD)
        endmethod
      
        static method registerGradientKey takes integer eventkey returns nothing
            call Lightning.registerUpdateEvent(eventkey,function thistype.updateGradient)
        endmethod
      
        implement init
    endstruct

endlibrary

Line segment enumeration:

JASS:
library LineSegmentEnumeration /* v2.2b -- hiveworkshop.com/threads/line-segment-enumeration-v1-1.286552/

    Information
    ¯¯¯¯¯¯¯¯¯¯¯

        Allows to enumerate widgets inside a line segment with an offset.
        So basicly it will result in a rect, but which is also allowed to be rotated.
   
   
    Mechanics
    ¯¯¯¯¯¯¯¯¯
   
        (Issue:)
   
        The problem with normal jass rects is that they aren't defined by 4 points, but only by 4 values: x/y -min/max.
        The result is that a jass rect is never rotated, so it's always paralel to the x/y axis.
   
        But when we draw a line from point A to point B we might also create a non-axix-parelel rect, and then
        we can't use the normal rect natives from jass anymore to find out if a point is inside the rect.

        (Solution:)
   
        To solve this problem the system does following:
   
        jass rect: rectangular defined by 4 values (axis paralel)
        custom rect: the real rectangular that is defined by user (not axis parelel)

        1. Create a big jass rect that is big enough so we can ensure to enum all widgets that are potentialy inside our custom rect. (Enum_Group)
           This Enum_Group will contain all wanted units, but may also contain not wanted units.

        2. Construct the custom rect following a form with the same parameters as in this image, but in 2D:
           https://upload.wikimedia.org/wikipedia/commons/thumb/3/33/Ellipsoide.svg/800px-Ellipsoide.svg.png

        3. Loop through Enum_Group and define each widget's coordinates relative to the center of the custom rect as a 2D vector

        4. Get the components of the widget's position vector on the local (rotated) x-y axis of the custom rect

        5. Check if the projected lengths (absolute value of components) of the widget's position is less than <a> and <b> as described in the
           image linked above.

*/
//  --- API ---
//! novjass

    struct LineSegment

        static constant real MAX_UNIT_COLLISION
 
        static method EnumUnitsEx takes group whichgroup, real ax, real ay, real bx, real by, real offset, boolean checkCollision, boolexpr filter returns nothing
        static method EnumUnits takes group whichgroup, real ax, real ay, real bx, real by, real offset, boolexpr filter returns nothing
 
        static method EnumDestructables takes real ax, real ay, real bx, real by, real offset returns nothing
       
        //  after enumerated destructables you have access to:
   
            static integer DestructableCounter      // starts with index "0"
            static destructable array Destructable
       
        static method EnumItems takes real ax, real ay, real bx, real by, real offset returns nothing
       
        //  after enumerated items you have access to:
   
            static integer ItemCounter      // starts with index "0"
            static destructable array Item
       
//! endnovjass
// ==== End API ====

struct LineSegment extends array

    public static constant real MAX_UNIT_COLLISION = 197.00

    private static constant rect RECT = Rect(0, 0, 0, 0)

    private static constant group GROUP = CreateGroup()

    private static real ox
    private static real oy
    private static real dx
    private static real dy
    private static real da
    private static real db
    private static real ui
    private static real uj
    private static real wdx
    private static real wdy

    private static method PrepareRect takes real ax, real ay, real bx, real by, real offset, real offsetCollision returns nothing
        local real maxX
        local real maxY
        local real minX
        local real minY

        // get center coordinates of rectangle
        set ox = 0.5*(ax + bx)
        set oy = 0.5*(ay + by)

        // get rectangle major axis as vector
        set dx = 0.5*(bx - ax)
        set dy = 0.5*(by - ay)

        // get half of rectangle length (da) and height (db)
        set da = SquareRoot(dx*dx + dy*dy)
        set db = offset

        // get unit vector of the major axis
        set ui = dx/da
        set uj = dy/da

        // Prepare the bounding Jass Rect
        set offset = offset + offsetCollision

        if ax > bx then
            set maxX = ax + offset
            set minX = bx - offset
        else
            set maxX = bx + offset
            set minX = ax - offset
        endif

        if ay > by then
            set maxY = ay + offset
            set minY = by - offset
        else
            set maxY = by + offset
            set minY = ay - offset
        endif

        call SetRect(RECT, minX, minY, maxX, maxY)
    endmethod

    private static method RotateWidgetCoordinates takes widget w returns nothing
        // distance of widget from rectangle center in vector form
        set wdx = GetWidgetX(w) - ox
        set wdy = GetWidgetY(w) - oy

        set dx = wdx*ui + wdy*uj    // get the component of above vector in the rect's major axis
        set dy = wdx*(-uj) + wdy*ui // get the component of above vector in the rect's transverse axis
    endmethod

    private static method IsWidgetInRect takes widget w returns boolean
        call RotateWidgetCoordinates(w)

        // Check if the components above are less than half the length and height of the rectangle
        // (Square them to compare absolute values)
        return dx*dx <= da*da and dy*dy <= db*db
    endmethod

    private static method IsUnitInRect takes unit u, boolean checkCollision returns boolean
        if checkCollision then
            call RotateWidgetCoordinates(u)

            // Check if the perpendicular distances of the unit from both axes of the rect are less than
            // da and db
            return IsUnitInRangeXY(u, ox - dy*uj, oy + dy*ui, RAbsBJ(da)) /*
            */ and IsUnitInRangeXY(u, ox + dx*ui, oy + dx*uj, RAbsBJ(db))
        endif

        return IsWidgetInRect(u)
    endmethod

    public static method EnumUnitsEx takes group whichgroup, real ax, real ay, real bx, real by, real offset, boolean checkCollision, boolexpr filter returns nothing
        local unit u

        if checkCollision then
            call PrepareRect(ax, ay, bx, by, offset, MAX_UNIT_COLLISION)
        else
            call PrepareRect(ax, ay, bx, by, offset, 0.00)
        endif

        call GroupEnumUnitsInRect(GROUP, RECT, filter)

        // enum through all tracked units, and check if it's inside bounds
        call GroupClear(whichgroup)
        loop
            set u = FirstOfGroup(GROUP)
            exitwhen u == null

            if IsUnitInRect(u, checkCollision) then
                call GroupAddUnit(whichgroup, u)
            endif

            call GroupRemoveUnit(GROUP, u)
        endloop
    endmethod

    public static method EnumUnits takes group whichgroup, real ax, real ay, real bx, real by, real offset, boolexpr filter returns nothing
        call EnumUnitsEx(whichgroup, ax, ay, bx, by, offset, false, filter)
    endmethod

//! textmacro LSE_WIDGET takes TYPE, NAME
    public static integer $NAME$Counter = -1
    public static $TYPE$ array $NAME$
 
    private static method on$NAME$Filter takes nothing returns nothing
        local $TYPE$ t = GetFilter$NAME$()

        if IsWidgetInRect(t) then
            set $NAME$Counter = $NAME$Counter + 1
            set $NAME$[$NAME$Counter] = t
        endif

        set t = null
    endmethod
 
    public static method Enum$NAME$s takes real ax, real ay, real bx, real by, real offset returns nothing
        call PrepareRect(ax, ay, bx, by, offset, 0.00)

        set $NAME$Counter = -1
        call Enum$NAME$sInRect(RECT, Filter(function thistype.on$NAME$Filter), null)
    endmethod
//! endtextmacro

//! runtextmacro LSE_WIDGET("destructable", "Destructable")
//! runtextmacro LSE_WIDGET("item", "Item")
 
endstruct
endlibrary
Another questionL do I need to set beam=null to fee memory?
 
Top