@name 3D Holo Angular Movement
@inputs 
@outputs [Pos Loc]:vector Angle:angle Rot T:table Snap [Cur_Local Offset]:vector Ang:angle Copied:angle
@persist [Cur H O E]:entity Idx Cid:array Pause Set [Cmds Help]:table
@model 

if( dupefinished() ){ reset() }

if( first() )
{
    runOnTick(1)
    runOnChat(1)
    runOnLast(1)
    
    O = owner()
    E = entity()
    
    function number getID( N )
    {
        Idx+=N
        holoShadow( Idx, 0 )
        return Idx
    }
    function number clipIt( N:number, [V1 V2]:vector )
    {
        Cid[N,number] = Cid[N,number] + 1
        holoClipEnabled( N, Cid[N,number], 1 )
        holoClip( N, Cid[N,number], V1, V2, 0 )
    }
    #clipIt( getID(0), vec(), vec(0,0,1) )
    function vector linePlane( Ent:entity, Ply:entity )
    {
        local Normal = Ent:up()
        return Ent:toLocal( Ply:shootPos() + ( Normal:dot( Ent:pos() - Ply:shootPos() ) / Normal:dot( Ply:eye() ) ) * Ply:eye() )
    }
    function entity:setCur( V:vector )
    {
        switch( positive(Loc) )
        {
            case vec(1,0,0),
                Angle = ang(90,0,0):rotateAroundAxis(vec(0,0,1),Loc[1] < 0 ? 180 : 0)
            break
            
            case vec(0,1,0),
                Angle = ang(90,Loc[2] > 0 ? 90 : -90,0)
            break
            
            case vec(0,0,1),
                Angle = Loc[3] < 0 ? ang(180,180,0) : ang()
            break
        }
        holoAng( 1, This:toWorld(Angle) )
    }
    
    Scale = 0.4
    
    Size = 12 * Scale
    Alpha = 30
    
    local Color = hsv2rgb( 150, 1, 0.5 )
    H = holoCreate( getID(1), E:toWorld(vec(0,0,-0.1)), vec(Size*1.85) / 12, E:toWorld(ang(0,0,0)), Color )
    holoModel( getID(0), "cplane" )
    holoAlpha( getID(0), 180 )
    holoDisableShading( getID(0), 1 )
    holoParent( getID(0), E )
    
    for( I = 0, 7 )
    {
        local Color = hsv2rgb( ( 270 / 8 ) * I, 1, 1 )
        holoCreate( getID(1), H:toWorld(vec(0,0,0.02)), vec(Size) / 12, H:toWorld(ang(0,I*22.5,0)), Color )
        holoModel( getID(0), "plane" )
        holoAlpha( getID(0), I % 2 == 1 ? Alpha : 200 )
        holoMaterial( getID(0), "models/wireframe" )
        holoDisableShading( getID(0), 1 )
        holoParent( getID(0), H )
    }
    
    H = holoEntity(1)
    
#    H = holoCreate( getID(1), E:toWorld(vec(-3,0,0)), Scale*vec(32) / 12, E:toWorld(ang(0,0,0)), hsv2rgb(150,1,1) )
#    holoModel( getID(0), "cplane" )
#    holoAlpha( getID(0), 50 )
#    holoDisableShading( getID(0), 1 )
#    clipIt( getID(0), vec(), vec(-1,0,0) )
#    holoParent( getID(0), E )
    
    T = table()
    
    T["0",string] = "0"
    T["1",string] = "1"
    T["2",string] = "2"
    T["3",string] = "3"
    T["4",string] = "4"
    T["5",string] = "5"
    T["6",string] = "6"
    T["7",string] = "7"
    T["8",string] = "8"
    T["9",string] = "9"
    T[".",string] = "prd"
    T["-",string] = "min"
    
    Cmds = table( "done" = "\"done\" Removes the chip",
                    "ang" = "\"ang <num>,<num>,<num>\" sets the angle of the entity",
                    "n" = "\"n <num>\" rotates the entity based on the center by a given amount",
                    "snap" = "\"snap <num>\" sets the values the angles snap to",
                    "p" = "\"p\" pauses the chip, use \"p\" again to unpause",
                    "copy" = "\"copy\" copies the angle of the active entity",
                    "paste" = "\"paste\" sets the angle of the active entity to the copied angle",
                    "attach" = "\"attach <string>\" sets the rotation center to the attachment point of the aimed at entity",
                    "local" = "\"local <num>,<num>,<num>\" sets the rotation center to a position local to the entity",
                    "set" = "\"set\" once entered you can place the rotation center in a position by hitting use to local it",
                    "help" = "\"help <string>\" type in the name of the function to see how to use it",
                    "commands" = "\"commands\" prints off a list of all of the commands"
                    )
    Help = table( "done" = "just say \"done\" and the chip will disappear",
                    "ang" = "say \"ang 0,90,0\" and the entity will rotate to that angle",
                    "n" = "say \"n 45\" to nudge(rotate) the prop by a certain degree",
                    "snap" = "say \"snap 15\" to set the snap angles to 15 degrees",
                    "p" = "say \"p\" to pause the chip, and again to unpause",
                    "copy" = "say \"copy\" to copy the angles of the selected entity",
                    "paste" = "say \"paste\" to paste the last copied angle",
                    "attach" = "say \"attach driveshaft\" while aiming at an ACF engine to set the rotation to that point",
                    "local" = "say \"local 0,0,10\" while aiming at an entity to set the rotation center from that entity",
                    "set" = "say \"set\" to enable set mode, so you can move the rotation center by hitting USE on another spot",
                    "help" = "At this point it should be obvious",
                    "commands" = "say \"commands\" to print a list of chat commands"
                    )
    
    local Color = hsv2rgb(0,0,1)
    
    local Add = -5
    local Z = 0
    
    local Count = 8
    local Step = 360 / Count
    for(I=1,Count)
    {
        local Ang = ang(0,-Step+Step*I + 2,0)
        local Len = I % 2 == 0 ? 4.6 : 4
        
#        holoCreate( getID(1), H:toWorld(Scale*vec(0,Len,0.5):rotate(Ang)), Scale*vec(0.1,Len*2,1) / 12, H:toWorld(Ang), Color )
#        holoModel( getID(0), "plane" )
#        holoDisableShading( getID(0), 1 )
#        holoParent( getID(0), 1 )
        
        local String = toString( 180 - round(-Step + Step * I,2) )
        
        holoCreate( getID(1), H:toWorld(Scale*vec(0,Len*2+1,Z):rotate(Ang)), Scale*vec(1,0.15,1) / 12, toWorldAng( vec(), ang(180,0,0), vec(), H:toWorld(Ang+ang(0,0,90)) ), Color )
        holoModel( getID(0), "models/sprops/misc/alphanum/alphanum_"+T[String[1],string]+".mdl" )
        holoDisableShading( getID(0), 1 )
        holoBodygroup( getID(0), 0, 3 )
        holoMaterial( getID(0), "models/shiny" )
        holoParent( getID(0), 1 )
        
        if( T[String[2],string] )
        {
            Ang += ang(0,Add,0)
            holoCreate( getID(1), H:toWorld(Scale*vec(0,Len*2+1,Z):rotate(Ang)), Scale*vec(1,0.15,1) / 12, toWorldAng( vec(), ang(180,0,0), vec(), H:toWorld(Ang+ang(0,0,90)) ), Color )
            holoModel( getID(0), "models/sprops/misc/alphanum/alphanum_"+T[String[2],string]+".mdl" )
            holoDisableShading( getID(0), 1 )
            holoBodygroup( getID(0), 0, 3 )
            holoMaterial( getID(0), "models/shiny" )
            holoParent( getID(0), 1 )
        }
        
        if( T[String[3],string] )
        {
            Ang += ang(0,Add,0)
            holoCreate( getID(1), H:toWorld(Scale*vec(0,Len*2+1,Z):rotate(Ang)), Scale*vec(1,0.15,1) / 12, toWorldAng( vec(), ang(180,0,0), vec(), H:toWorld(Ang+ang(0,0,90)) ), Color )
            holoModel( getID(0), "models/sprops/misc/alphanum/alphanum_"+T[String[3],string]+".mdl" )
            holoDisableShading( getID(0), 1 )
            holoBodygroup( getID(0), 0, 3 )
            holoMaterial( getID(0), "models/shiny" )
            holoParent( getID(0), 1 )
        }
        
        if( T[String[4],string] )
        {
            Ang += ang(0,Add,0)
            holoCreate( getID(1), H:toWorld(Scale*vec(0,Len*2+1,Z):rotate(Ang)), Scale*vec(1,0.15,1) / 12, toWorldAng( vec(), ang(180,0,0), vec(), H:toWorld(Ang+ang(0,0,90)) ), Color )
            holoModel( getID(0), "models/sprops/misc/alphanum/alphanum_"+T[String[4],string]+".mdl" )
            holoDisableShading( getID(0), 1 )
            holoBodygroup( getID(0), 0, 3 )
            holoMaterial( getID(0), "models/shiny" )
            holoParent( getID(0), 1 )
        }
        
        if( T[String[5],string] )
        {
            Ang += ang(0,Add,0)
            holoCreate( getID(1), H:toWorld(Scale*vec(0,Len*2+1,Z):rotate(Ang)), Scale*vec(1,0.15,1) / 12, toWorldAng( vec(), ang(180,0,0), vec(), H:toWorld(Ang+ang(0,0,90)) ), Color )
            holoModel( getID(0), "models/sprops/misc/alphanum/alphanum_"+T[String[5],string]+".mdl" )
            holoDisableShading( getID(0), 1 )
            holoBodygroup( getID(0), 0, 3 )
            holoMaterial( getID(0), "models/shiny" )
            holoParent( getID(0), 1 )
        }
    }
    
    holoCreate( getID(1), H:toWorld(Scale * vec(0,0,0.1)), Scale*vec(1.5) / 12, H:toWorld(ang(0,0,0)), hsv2rgb(0,0.5,0.5) )
    holoModel( getID(0), "cplane" )
    holoDisableShading( getID(0), 1 )
    holoParent( getID(0), H )
    Rot = getID(0)
    
    holoCreate( getID(1), H:toWorld(Scale * vec(-4,0,0.1)), Scale*vec(1.5,0.5,8) / 12, H:toWorld(ang(0,90,-90)), hsv2rgb(0,0.5,0.5) )
    holoModel( getID(0), "prism" )
    holoDisableShading( getID(0), 1 )
    holoParent( getID(0), Rot )
    
    holoAng( Rot, H:toWorld(ang(0,90,0)) )
    
    Snap = 22.5
    
    if( !O["spawned",number] )
    {
        printTable( Cmds )
        O["spawned",number] = 1
    }
}

if( !Pause )
{
    Use = O:keyUse() & !O:keyAttack1() & !O:keyReload()
    
    if( changed(Use) & Use )
    {
        Tmp = O:aimEntity()
        
        Cur_Local = Tmp:toLocal( O:aimPos() + O:aimNormal()/10 )
        
        if( O:keySprint() )
        {
            local Box = Tmp:aabbSize() / 2
            Cur_Local = round( Cur_Local / Box ) * Box
            holoPos( 1, Tmp:toWorld(Cur_Local) + O:aimNormal()/10 )
        }
        else
        {
            holoPos( 1, Tmp:toWorld( Cur_Local ) )
        }
        holoAng( Rot, H:toWorld(ang(0,90,0)) )
        
        Loc = round( Tmp:toLocalAxis(O:aimNormal()) )
        
        Cur = Set ? Cur : Tmp
        
        Set = 0
        
        Cur:setCur( Loc )
    }
    
    Swap = O:keyAttack2()
    if( changed(Swap) & Swap )
    {
        holoAng( 1, holoEntity(1):toWorld(ang(0,90,0)) )
    }
    
    Drag = O:keyAttack1()
    
    if( changed(Drag) )
    {
        if( Drag )
        {
            Offset = H:toLocal(Cur:pos())
            Ang = H:toLocal(Cur:angles())
        }
        else
        {
            Cur_Local = Cur:toLocal(H:pos())
            timer("reset",100)
        }
    }
    
    if( Drag & Cur )
    {
        local Local = linePlane( H, O )
        Pos = H:toWorld( Local )
        local Yaw = H:bearing(Pos) - 90
        if( O:keySprint() )
        {
            Yaw = round( Yaw / Snap ) * Snap
        }
        holoAng( Rot, H:toWorld(ang(0,90-Yaw,0)) )
        Cur:setPos( H:toWorld(Offset:rotate(ang(0,-Yaw,0))) )
        Cur:setAng( H:toWorld(Ang-ang(0,Yaw,0)) )
        
        if( changed(Yaw) )
        {
            print( _HUD_PRINTCENTER, "Rotation: " + Yaw )
        }
    }
    
    Reload = O:keyReload()
    
    if( changed(Reload) & Reload )
    {
        if( O:keySprint() )
        {
            Loc = round( O:aimEntity():toLocalAxis(O:aimNormal()) )
            O:aimEntity():setCur( Loc )
        }
        else
        {
            local Eye = round( ( O:eyeAngles() - ang(90,0,0) ) / 90 ) * 90
            holoAng( 1, Eye )
        }
    }
}

if( chatClk(O) )
{
    local Lsx = O:lastSaid():lower():explode(" ")
    local Secondary = Lsx[2,string]
    
    if( Cmds:exists( Lsx[1,string] ) )
    {
        printColor( vec(255,100,0), Lsx:concat(" ") )
    }
    
    switch( Lsx[1,string] )
    {
        default,
        break
        
        case "done",
            hideChat(1)
            selfDestruct()
        break
        
        case "ang",
            if( Cur )
            {
                if( Secondary == "?" )
                {
                    local A = Cur:angles()
                    print( "ang("+A[1]+","+A[2]+","+A[3]+")" )
                }
                else
                {
                    Cur_Local = Cur:toLocal(H:pos())
                    local StrAng = Lsx[2,string]:explode(",")
                    Cur:setAng( ang( StrAng[1,string]:toNumber(), StrAng[2,string]:toNumber(), StrAng[3,string]:toNumber() ) )
                    timer("reset",100)
                }
            }
            else
            {
                print( _HUD_PRINTCENTER, "No entity selected" )
            }
            hideChat(1)
        break

        case "n",
            if( Cur )
            {
                Offset = H:toLocal(Cur:pos())
                Ang = H:toLocal(Cur:angles())
                
                local N = Lsx[2,string]:toNumber()
                Cur:setPos( H:toWorld(Offset:rotate(ang(0,-N,0))) )
                Cur:setAng( H:toWorld(Ang-ang(0,N,0)) )
                
                timer("reset",100)
            }
            hideChat(1)
        break
        
        case "snap",
            Snap = Lsx[2,string]:toNumber()
            hideChat(1)
        break
        
        case "p",
            Pause = !Pause
            print( _HUD_PRINTCENTER, Pause ? "Paused" : "Unpaused" )
            hideChat(1)
        break
        
        case "copy",
            Copied = Cur:angles()
            print( _HUD_PRINTCENTER, "Angle Copied: " + round(Copied) )
            hideChat(1)
        break
        
        case "paste",
            Cur:setAng( Copied )
            hideChat(1)
        break
        
        case "attach",
            Tmp = O:aimEntity() ?: Cur
            local Attachment = Lsx[2,string]
            local Position = Tmp:attachmentPos(Attachment) ?: Cur:pos()
            Cur_Local = Cur:toLocal(Position)
            holoPos( 1, Cur:toWorld(Cur_Local) )
            hideChat(1)
        break
        
        case "local",
            Tmp = O:aimEntity()
            local Exp = Lsx[2,string]:explode(",")
            local Position = Cur:toLocal( Tmp:toWorld(vec( Exp[1,string]:toNumber(), Exp[2,string]:toNumber(), Exp[3,string]:toNumber() ) ) )
            holoPos( 1, Cur:toWorld(Position) )
            hideChat(1)
        break
        
        case "set",
            Set = 1
            print( _HUD_PRINTCENTER, "Press Use to set the new rotation center..." )
            hideChat(1)
        break
        
        case "help",
            if( Lsx[2,string] )
            {
                printColor( vec(0,255,255), Help[ Lsx[2,string], string ] )
            }
            else
            {
                printColor( vec(255), "No command given, type \"commands\" to see what commands are available" )
            }
            hideChat(1)
        break
        
        case "commands",
            printColor( vec(255), Cmds:keys():concat(" , ") )
            hideChat(1)
        break
    }
}

if( clk("reset") )
{
    holoPos( 1, Cur:toWorld( Cur_Local ) )
    holoAng( 1, Cur:toWorld(Angle) )
    holoAng( Rot, H:toWorld(ang(0,90,0)) )
}

if( last() )
{
    holoDeleteAll()
}
