-----------------------------------------------------------------------------
--  File     : /mods/4DC_V0.8/units/Singularity/Singularity_script.lua
--
--  Author(s): Resin Smoker, Mithy & Bulletmagnet
--
--  Summary  : Singularity
--
--  Note     : Unit based off ideas from JZ's Microcollapsar
--
--  Copyright © 2011 4DC_V0.8  All rights reserved.
-----------------------------------------------------------------------------
local Unit = import('/lua/sim/Unit.lua').Unit
local utilities = import('/lua/utilities.lua')
local RandomFloat = import('/lua/utilities.lua').GetRandomFloat
local Custom_4D_EffectTemplate = import('/mods/4DC_V0.8/lua/4D_EffectTemplates.lua')
                                 
Singularity = Class(Unit) {

    DoNotTargetList = { 
        -- Unit restrictions
        'BLACKHOLE', 
        'COMMAND',
        'ECONOMIC',
        'EXPERIMENTAL',
        'FACTORY',
        'GATE',
        'HOLOGRAM',
        'PHASING',
        'POD', 
        'PROJECTILE', 
        'SIZE12',
        'SIZE20',        
        'SUBCOMMANDER',
        'UNTARGETABLE',                    
    },  
                   
    OnCreate = function(self,builder,layer)
        Unit.OnCreate(self,builder,layer) 
        -- Set undamageable
        self:SetCanTakeDamage(false)              
        -- Spin the singularity        
        self.Trash:Add(CreateRotator(self, 'singularity', 'y', nil, 0, 100, 100 + Random(-50, 50)))                
        -- Show target data during debug mode (select 'true' to display)       
        self.Debug = false 
        -- Globals              
        self.TargTable = {} 
        self.HelperTable = {}                                              
    end,   
    
    PassInfoToSingularity = function( self, data, launcher )
        if data and data.DamageRadius > 0 then             
            self:ForkThread(self.EventHorizon, data, launcher)        
        else 
            if self.Debug then
	            if not data then 
	                WARN('Singularity_script.lua / PassInfoToSingularity, "data" not avalible')                     
	            elseif not data.DamageRadius > 0 then
	                WARN('Singularity_script.lua / PassInfoToSingularity, "data.DamageRadius" not avalible or radius !> 0')                              
	            end
            end
            self:Destroy() 
        end 
    end,            
       
    EventHorizon = function(self, data, launcher)
        local army = self:GetArmy()
        local pos = self:GetPosition('singularity') 
        
        -- Used to verify that required data is being passed
        if self.Debug then
            if data then
                WARN('Singularity_script.lua / EventHorizon, "data" passed to function: ', repr(data))
            else
                WARN('Singularity_script.lua / EventHorizon, "data" not passed to function')
            end
            if launcher then
                WARN('Singularity_script.lua / EventHorizon, "launcher" passed to function: ', launcher:GetUnitId())
            else
                WARN('Singularity_script.lua / EventHorizon, "launcher" not passed to function')
            end
        end     
                 
        -- Add FX Animations 
        for k, v in Custom_4D_EffectTemplate.SingularityAmbientAnimation do
            CreateAttachedEmitter(self,'singularity', army, v):ScaleEmitter(data.DamageRadius * 0.05)
        end 
        self:PlayUnitSound('Impact')
        self:ShakeCamera(data.DamageRadius, 1.5, 0, 3)
        CreateDecal( pos, RandomFloat(0.0,6.28), 'Scorch_012_albedo', '', 'Albedo', (data.DamageRadius * 3), (data.DamageRadius * 3), 315, 100, army )                           
        -- Search for units in range
        local unitsInRec = GetEntitiesInRect( Rect(pos[1] - data.DamageRadius, pos[3] - data.DamageRadius, pos[1] + data.DamageRadius, pos[3] + data.DamageRadius) )                   
        -- verify that we have units in range
        if table.getsize(unitsInRec) > 0 then        
            -- Filter out unwanted units         
            local targetFilter = categories.ALLUNITS + categories.RECLAIMABLE
            for k, v in self.DoNotTargetList do
                targetFilter = targetFilter - ParseEntityCategory(v)
            end              
            local targets = EntityCategoryFilterDown(targetFilter, unitsInRec)                                                                         
            local horizon = 1
            local killcount = 0
            while self and not self:IsDead() and horizon <= data.DamageRadius do                                                                
                -- Scan for viable entities within the expanding radius                 
                for a, b in targets do              
                    local dist = VDist3(pos, b:GetPosition())
                    if dist <= horizon then
                       table.insert(self.TargTable, b)
                    end
                end                                                                                                                                  
                -- Should there be entities in range loop            
                if table.getsize(self.TargTable) > 0 then           
                    for k, v in self.TargTable do                    
				        -- Log the target list during debug
				        if self.Debug and IsUnit(v) then
				            WARN('Singularity_script.lua / EventHorizon, Target table contents: ', v:GetUnitId())
				        end                                                           
                        -- Apply helper if other helper exsists                                          
                        if v.HasHelper != true then
                            if not v:BeenDestroyed() and v:GetHealth() > 0 then
                                local helper = CreateUnit('Singularity_Helper', army, pos[1], pos[2], pos[3], 0, 0, 0, 1, 'Air' )                                                       
                                -- Sets the Singularity unit as the helpers parent 
                                helper:SetParent(self, 'Singularity') 
                                helper:SetCreator(self)
                                helper:AttachTo(self, -1)                            
                                -- Adds the new helper to the parents table 
                                if not self:IsDead() and self.HelperTable then     
                                    table.insert(self.HelperTable, helper)
                                end                             
                                -- Update the launchers kills
                                if launcher and not launcher:IsDead()then
                                    if IsUnit(v) and not v:IsDead() then
	                                    local unitKills = launcher:GetStat('KILLS', 0).Value + 1                                                          
	                                    launcher:SetStat('KILLS', unitKills)
	                                    launcher:CheckVeteranLevel()
                                    end
                                elseif self.Debug then
                                    WARN('Singularity_script.lua / EventHorizon, "launcher" not avalible to pass unit kills') 
                                end                                                     
                                -- Tell the helper which target to draw in and how long it has to do it, lifetime based upon the damage radius of the weapon
                                helper:PassTargetToHelper(v, data.DamageRadius )                            
                                -- Remove the helpers target from the table to increase speed 
                                table.removeByValue(self.TargTable, v)                             
                            end 
                        end                                                                                                                                 
                    end                                                                                                                                                                        
                end
                -- Reset the target list
                self.TargTable = {}
                -- Increase the scan range
                horizon = horizon + 1 
                -- Short delay before the next loop
                WaitTicks(1)                                         
            end 
            while self and not self:IsDead() and table.getn(self.HelperTable) > 0 do
                -- Wait for the last helper to finish
                WaitTicks(1)
            end
        end
        -- Apply area damage to anything remaining     
        DamageArea(self ,pos, data.DamageRadius, data.DamageAmount, data.DamageType, data.DamageFriendly)
        WaitSeconds(1)         
        -- Remove the Singularity          
        self:Destroy()                         
    end,      
                     
}
TypeClass = Singularity