@name 3d holo Chassis Assistant
@inputs
@outputs [LLocal PLocal]:vector P:entity Snap X Y Count Freeze
@persist [H E O]:entity Idx Time Info:table [Path]:string Ang:angle Offset Bx:vector

if( first() )
{
    runOnTick(1)
    runOnChat(1)
    #runOnLast(1)
    
    setName("OmicroN's Chassis Assistant")
    
    E = entity():isWeldedTo() ?: entity()
    O = owner()
    
    Info["cylinders",string] = "models/sprops/cylinders/(folder)/(1)x(2).mdl"
    Info["cylinders_length",array] = array( 3, 6, 12, 18, 24, 30, 36, 42, 48, 54, 60, 66, 72, 78, 84, 90, 96, 108, 120, 132, 144, 192, 240, 288, 336, 384, 432, 480 )
    Info["cylinders_group",array] = array( "cylinder_1_5", "cylinder_3", "cylinder_6", "cylinder_9", "cylinder_12" )
    Info["cylinders_folder",array] = array( "size_1", "size_2", "size_3", "size_4", "size_5" )
    Info["cylinders_count",vector] = vec( 5, 5, Info["cylinders_length",array]:count() )
    
    Type = "cylinders"
    Path = Info[Type,string]
    
    function number getID( N )
    {
        Idx += N
        return Idx
    }
    function string getFolder( N )
    {
        return Info["cylinders_folder",array][N,string]
    }
    function string getGroup( N )
    {
        return Info["cylinders_group",array][N,string]
    }
    function number getLength( N )
    {
        return Info["cylinders_length",array][N,number]
    }
    function string getModel( N1, N2, N3 )
    {
        local Length = getLength(N3)
        return Path:replace( "(folder)", getFolder(N1) ):replace( "(1)", getGroup(N2) ):replace( "(2)", Length + "" )
    }
    function setPosAng( A:angle )
    {
        Pos = P:toWorld(LLocal/2)-A:up()*PLocal[3]/2
        holoPos(1,Pos)
        holoAng(1,A)
    }
    function string setModel( N1, N2, N3 )
    {
        local Model = getModel( N1, N2, N3 )
        holoModel( 1, Model )
        Bx = H:boxSize() - 0.5
        PLocal = vec( 0, 0, -Bx[3] )
        setPosAng( Ang )
        return Model
    }
    function string entity:sphereModel()
    {
        return "models/sprops/geometry/sphere_"+This:model():explode("x")[1,string]:explode("_")[3,string]+".mdl"
    }
    
    Bx = E:boxSize()-0.5
    
    LLocal = vec( 0, 0, Bx[3] - Bx[3] * Offset )
    PLocal = vec( 0, 0, -Bx[3] )
    H = holoCreate( getID(1), E:toWorld( PLocal ), vec( 12, 12, 12 ) / 12, E:toWorld( ang( 0, 0, 0 ) ), vec( 255, 255, 255 ) )
    holoAlpha( getID(0), 150 )
    holoModel( getID(0), E:model() )
    holoParent( getID(0) , E )
    
    P = E
    
    Snap = 45/2
    X = Y = 1
    Offset = 1
}

if( !Freeze )
{
    Ang = O:eyeAngles()+ang(90,0,0)
    Ang = round( Ang / Snap ) * Snap
}

    if( changed(Ang) )
    {
        setPosAng( Ang )
        print(_HUD_PRINTCENTER,"Snapping: " + Snap)
    }
    
    Use = O:keyUse()
    Set = O:keySprint()
    Change = O:keyAttack1() - O:keyAttack2()
    New = !Set & Use & Change>0
    Sphere = O:keyReload()
    
    if( changed(New) & New )
    {
        if( curtime()-Time > 1/4 )
        {
            if( Sphere )
            {
                S = propSpawn( P:sphereModel(), P:toWorld(LLocal/2), P:angles(), 1 )
            }
            
            P = propSpawn( H:model(), H:pos(), H:toWorld(ang(180,0,0)), 1 )
            Bx = H:boxSize()-0.5
            LLocal = vec( 0, 0, Bx[3] - ( Bx[3] * Offset ) * 2 )
            holoPos(1,P:toWorld(LLocal))
            Time = curtime()
        }
    }
    
    if( Set & changed(Change) & Change )
    {
        local Count = Info["cylinders_count",vector]
        
        X = clamp( X + Change * !Use, 1, Count[2] )
        Y = clamp( Y + Change * Use, 1, Count[3] )
        
        setModel( X, X, Y )
        print( _HUD_PRINTCENTER, getModel( X, X, Y ) )
    }

if( chatClk(O) )
{
    Lsx = O:lastSaid():lower():explode(" ")
    Cmd = Lsx[1,string]
    if( Cmd == "snap" )
    {
        local Num = Lsx[2,string]:toNumber()
        Snap = clamp( Num, 1, 270 )
        print(_HUD_PRINTCENTER,"Snap @ " + Snap)
        hideChat(1)
    }
    if( Cmd == "done" )
    {
        selfDestruct()
        hideChat(1)
    }
    if( Cmd == "set" )
    {
        P = O:aimEntity()
        Bx = P:boxSize()-0.5
        LLocal = vec( 0, 0, Bx[3]-( Bx[3] * Offset ) * 2 )
        PLocal = vec( 0, 0, -Bx[3] )
        holoModel(1,P:model())
        setPosAng( Ang )
        hideChat(1)
    }
    if( Cmd == "p" )
    {
        Freeze = !Freeze
        hint( Freeze ? "Chip Frozen" : "Chip Unfrozen", 4 )
        hideChat(1)
    }
    if( Cmd:right(1) == "%" )
    {
        local Str = Cmd:replace("%","")
        Offset = Str == "0" ? 0 : 1 / ( 100 / Str:toNumber() )
        LLocal = vec( 0, 0, Bx[3]-( Bx[3] * Offset ) * 2 )
        setPosAng( Ang )
        hint( Offset + "", 2 )
        hideChat(1)
    }
    if( Cmd == "n" )
    {
        local Nudge = ang( Lsx[2,string]:toNumber(), Lsx[3,string]:toNumber(), Lsx[4,string]:toNumber() )
        Ang+=Nudge
        printColor( vec()+255, "Nudging by " + Nudge )
        hideChat(1)
    }
    if( Cmd == "pointat" )
    {
        local Dir = ( O:aimPos() - P:toWorld(LLocal/2) )
        Ang = Dir:toAngle()+ang(90,0,0)
        hideChat(1)
    }
}
