@name 2015_october/hc_lib
@persist [HoloTable ClipTable HoloCore]:table [HoloCount ClipCount HoloPlus ClipPlus SpawnComplete HoloTime] 
@persist Entity:entity Factor MatTog Shading HC_Mode:string

@persist [W A S D R Alt Shift Space] CameraAim:vector Driver:entity

#interval(1000)

setName("HoloLib")

HoloTime = curtime()
HC_Mode  = "load"

function hcPrint(String:string)
{
    printColor( vec(125,255,125), "HoloCore: ", vec(255,255,255), String )       
}

function holo(Num,Parent,ScaleType,Pos:vector,Ang:angle,Scale:vector,[HC_Model Mat]:string,Color:vector4)    
{
    Scale = vec(Scale:y(), Scale:x(), Scale:z())
    HoloCount++
    HoloTable[HoloCount, table] = table(
        "Index"     = Num,
        "Parent"    = Parent,
        "Position"  = Pos,
        "Angle"     = Ang,
        "Scale"     = ScaleType ? Scale / 12 : Scale,
        "Model"     = HC_Model,
        "Material"  = Mat,
        "Color"     = Color
    )
}

function clip(Num,ClipNum,[Pos Dir]:vector)   
{
    ClipCount++
    ClipTable[ClipCount, table] = table(
        "Index"     = Num,
        "ClipID"    = ClipNum,
        "Position"  = Pos,
        "Direction" = Dir
    )
}

function loadHolo(Scale, Mats, Shading, Base:entity)  
{
    interval(HoloCount > 80 ? 15 : 15)
    if (HoloPlus < HoloCount)   
    {
        if (holoCanCreate())    
        {
            HoloPlus++
            local T = HoloTable[HoloPlus, table]
            if (T)  
            {
                local N = T["Index", number]
                local P = holoEntity(T["Parent", number]) ?: Base

                holoCreate(N)
                holoParent(N, P)
                holoPos(N, P:toWorld(T["Position", vector]*Scale))
                holoAng(N, P:toWorld(T["Angle", angle]))
                holoModel(N, T["Model", string])
                holoScale(N, vec(T["Scale", vector]:y(), T["Scale", vector]:x(), T["Scale", vector]:z())*Scale)

                if (Mats) 
                {
                    holoMaterial(N, T["Material", string])
                    holoColor(N, T["Color", vector4])
                }
                
                if (Shading)
                {
                    holoDisableShading(N, 1)    
                }
            }
        }
    } 
    elseif (ClipPlus < ClipCount) 
    {
        ClipPlus++
        local T = ClipTable[ClipPlus, table]
        if (T)  
        {
            holoClipEnabled(T["Index", number], T["ClipID", number], 1)
            holoClip(T["Index", number], T["ClipID", number], T["Position", vector]*Scale, T["Direction", vector], 0)    
        }
    } 
    else  
    {
        HC_Mode = "pause"
        hcPrint( "Loaded " + HoloPlus + " holograms and made " + ClipPlus + " clips in " + round(curtime() - HoloTime - 1, 2) + " seconds." )
    }
}


#-Holocore Function Library
function table:hcInit(Interval, Tick, Filter:array)
{
    interval(Interval)
    runOnTick(Tick), runOnLast(1)
    rangerFilter(Filter), rangerFilter(Entity), rangerPersist(1)
    #rangerHitEntities(0), rangerPersist(1)
    
    This["Owner", entity] = owner() 
}

function table:hcDeInit()
{
    if (This["Seat", entity])
    {
        This["Seat", entity]:ejectPod()
        This["Seat", entity]:deparent()
        This["Seat", entity]:setAlpha(255)
    }
    holoDeleteAll()
}

#-Set pod parent, pos, and angle
function table:hcSetPod(Parent:entity, Position:vector, Angle:angle, Alpha)
{
    This["SeatParent", entity] = Parent
    This["SeatPos", vector]    = Position
    This["SeatAng", angle]     = Angle
    This["SeatAlpha", number]  = Alpha
}

#-Set camera parameters
function table:hcSetCam(Origin:vector, Distance)
{
    This["CamPos", vector]    = Origin
    This["CamDist", vector]   = vec(-Distance,0,0)
}

function table:hcRunCore()
{
    #-Find and link pod
    if (!This["Seat", entity])
    {
        local Temp = This["Owner", entity]:aimEntity()
        if (Temp)
        {
            if (Temp:owner() == This["Owner", entity])
            {
                if (Temp:type() == "prop_vehicle_prisoner_pod" & Temp:parent() == noentity())
                {
                    Temp:setMass(1), Temp:propFreeze(1), Temp:setAlpha(This["SeatAlpha", number])
                    Temp:setPos(This["SeatParent", entity]:toWorld(This["SeatPos", vector]))
                    Temp:setAng(This["SeatParent", entity]:toWorld(This["SeatAng", angle]))
                    This["Seat", entity]     = Temp
                    This["SeatTime", number] = 1
                    
                    #ifdef noCollideAll(number)
                        Entity:noCollideAll(1)
                    #endif
                
                    #rangerFilter(Temp), rangerPersist(1)
                }
            }
        }    
    }
    elseif (This["SeatTime", number] > 0)
    {
        This["SeatTime", number] = This["SeatTime", number] - 0.5
        if (This["SeatTime", number] <= 0)
        {
            This["Seat", entity]:parentTo(This["SeatParent", entity])
            hcPrint("Seat attached!")
        }
    }
    else
    {
        #-Find and create wirelink Camera
        if (!This["Camera", wirelink])
        {
            if (findCanQuery())
            {
                findIncludePlayerProps(This["Owner", entity])
                findByClass("gmod_wire_cameracontroller")
 
                local Temp = noentity()
                foreach (K, V:entity = findToArray()) {
                    local XWL = V:wirelink()
                    if (!XWL["Parent", entity])   {
                        Temp = V
                        break
                    }
                }

                if (Temp)
                {
                    This["CamParent", entity] = holoCreate(1000, This["Seat", entity]:toWorld(This["CamPos", vector]), vec(), ang())
                                                holoParent(1000, This["Seat", entity])

                    This["Camera", wirelink] = Temp:wirelink()
                    This["Camera", wirelink]["Parent", entity]   = This["CamParent", entity]
                    This["Camera", wirelink]["Position", vector] = This["CamDist", vector]
                    This["Camera", wirelink]["Angle", angle]     = ang()

                    hcPrint("Camera created!")
                }
            }
            
        }

        #-Get Inputs
        Driver = This["Seat", entity]:driver()
        if (Driver)
        {
            W = Driver:keyPressed("W")
            A = Driver:keyPressed("A")
            S = Driver:keyPressed("S")
            D = Driver:keyPressed("D")
            
            R = Driver:keyPressed("R")
            Alt = Driver:keyPressed("LALT")
            Shift = Driver:keyPressed("LSHIFT")
            Space = Driver:keyPressed("SPACE")
            
            Mouse1 = Driver:keyAttack1()
            Mouse2 = Driver:keyAttack2()
            
            if (Driver:keyPressed("RALT")) { This["Seat", entity]:ejectPod() }
            
            if (This["Camera", wirelink])
            {
                CameraAim = rangerOffset(32768, This["CamParent", entity]:pos(), This["Seat", entity]:toLocalAxis(Driver:eye())):position()                
                local Ranger = round(rangerOffset(This["CamParent", entity]:pos(), This["CamParent", entity]:toWorld(This["CamDist", vector])):distance(), 1)
                if (changed(Ranger))
                {
                    This["Camera", wirelink]["Position", vector] = vec(-Ranger + 50, 0, 0)    
                }

                holoAng(1000, (CameraAim - This["CamParent", entity]:pos()):toAngle())
                #holoPos(1000, This["Seat", entity]:toWorld(This["CamPos", vector]))
            }
        }
        else
        {
            CameraAim = Entity:toWorld(vec(5000,0,0))
        }
        
        if (changed(Driver))
        {
            if (Driver)
            {
                hcPrint(Driver:name() + " entered your vehicle.")
                This["Camera", wirelink]["Activated", number] = 1
            }
            else
            {
                This["Camera", wirelink]["Activated", number] = 0
                W = A = S = D = R = Alt = Shift = Space = Mouse1 = Mouse2 = 0
            }    
        }    
    } 
}
