@name Personal Area Device
@inputs 
@outputs Mode Distance [V1 V2 Min Max Tele]:vector R:array Whitelist:table Status Players:array Keyword:string Queue:table Queue_Mode
@persist [O E]:entity Idx Cid:array EGPent:entity EGP:wirelink Tele_Mode:string Print Team:string Auto_Add_Queue Tag Cmds:array
@trigger 
@model 

if( dupefinished() ){ reset() }

if( first() )
{
    Team = "red"
    
    
    Auto_Add_Queue = 1
    
    printColor( vec(255,100,100), "NOTE: ", vec(100,255,100), "To use chat commands you have to aim at the screen, unless you end the command with the word \"override\".\n",vec(250,255,250),"ie: \"tele override\"\n",vec(200,255,200),"Type \"commands\", \"help\", or \"?\" to see a list of commands. To print the commands to chat just type \"print\" afterwards.\n",vec(250,255,250),"ie: \"help print\"" )
    
    setName( "Personal Area Device for " + owner():name() + "\nBy: OmicroN\nTeam: "+Team )
    #runOnTick(1)
    runOnChat(1)
    runOnLast(1)
    
    O = owner()
    E = entity():isWeldedTo() ?: entity()
    
    findIncludePlayerProps(O)
    findByClass("gmod_wire_egp")
    EGPent = findClosest(E:pos())
    EGP = EGPent:wirelink()
    
    EGP:egpClear()
    
    function number gid( N )
    {
        return EGP:egpNumObjects() + N
    }
    
    function number getID( N )
    {
        Idx += N
        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 )
        return N
    }
    #clipIt( getID(0), vec(), vec(0,0,1) )
    function updateList()
    {
        EGP:egpClear()
        Players = array()
        local I = 0
        foreach( K, Ply:entity = players() )
        {
            if( Whitelist[Ply:steamID(),number] )
            {
                I++
                EGP:egpBox( gid(1), vec2(256,I*24-12), vec2(400,24) )
                EGP:egpColor( gid(0), teamColor(Ply:team()) )
                
                EGP:egpText( gid(1), Ply:name(), vec2() )
                EGP:egpColor( gid(0), -teamColor(Ply:team()) )
                EGP:egpAlign( gid(0), 1, 1 )
                EGP:egpParent( gid(0), gid(-1) )
                #Players:pushEntity(Ply)
            }
        }
    }
    function sendPlayer( N, Ply:entity )
    {
        Ply:tele( Tele + vec(0,0,N-1)*72 )
        Ply:soundPlay("tele"+Ply:steamID(),0,"@*weapons/physcannon/superphys_small_zap"+randint(1,4)+".wav",0.5)
    }
    function setAllow( S:string )
    {
        print(_HUD_PRINTCENTER,"Searching...")
        foreach( K, Ply:entity = players() )
        {
            if( Ply:name():lower():find(S) )
            {
                if( Whitelist[Ply:steamID(),number] )
                {
                    hint( "Player is already on the whitelist", 2 )
                }
                else
                {
                    hint( Ply:name() + " added to the whitelist", 2 )
                    Whitelist[Ply:steamID(),number] = 1
                    Ply[Team,number] = 1
                }
            }
        }
    }
#    function printCommands()
#    {
#        Cmds = "add queue,add <name>,allow <name>,screen,include,exclude,queue <keyword>,clear,set,system <on/off>,remove <name>,tele,bring team,color team,tag":explode(",")
#        #print( _HUD_PRINTCENTER, Cmds:concat("\n") )
#    }
    
    Cmds = array("add queue","add <name>","allow <name>","screen","include","exclude","queue <keyword>","clear","set","system <on/off>","remove <name>","tele","bring team","color team","tag")
    
    holoCreate( getID(1), E:toWorld(vec(0,0,0)), vec(12,12,12) / 12, ang(0,0,0), vec(255) )
    holoModel( getID(0), "models/sprops/cuboids/height96/size_1/cube_96x96x96.mdl" )
    holoMaterial( getID(0), "Models/wireframe" )
    
    holoCreate( getID(1), E:toWorld(vec(0,0,0)), -vec(12,12,12) / 12, ang(0,0,0), vec(255) )
    holoModel( getID(0), "models/sprops/cuboids/height96/size_1/cube_96x96x96.mdl" )
    holoMaterial( getID(0), "Models/wireframe" )
    holoParent( getID(0), 1 )
    
    Whitelist[O:steamID(),number] = 1
    
    foreach( K, Ply:entity = players() )
    {
        if( Ply[Team,number] )
        {
            Whitelist[Ply:steamID(),number] = 1
        }
    }
    
    Tele_Mode = "include"
    
    Min = E["min",vector] ?: Min
    Max = E["max",vector] ?: Max
    V1 = E["v1",vector] ?: V1
    V2 = E["v2",vector] ?: V2
    Status = E["status",number] ?: -1
    Tele = E["tele",vector] ?: Tele
    Tele_Mode = E["tele_mode",string] ?: Tele_Mode
    
    Mode = Min & Max ? 0 : 1
    
    if( V1 & V2 )
    {
        holoPos( 1, mix( V1, V2, 0.5 ) )
        
        local Dir = positive( V2 - V1 )
        holoScale( 1, Dir / 96 )
        holoScale( 2, -Dir / 96 )
    }
    
    timer("update",5000)
    timer("check",500)
}

interval(100)

if( Status < 0 & Mode == 1 )
{
    Clk = O:keyUse()
    Move = O:keyAttack2()
    
    if( changed(Move) & Move )
    {
        Distance = O:eyeTrace():distance()
    }
    
    if( changed(Clk) )
    {
        if( Clk )
        {
            V1 = O:aimPos()
        }
        elseif( V1 )
        {
            Min = vec( min(V1[1],V2[1]),
                        min(V1[2],V2[2]),
                        min(V1[3],V2[3])
                        )
            Max = vec( max(V1[1],V2[1]),
                        max(V1[2],V2[2]),
                        max(V1[3],V2[3])
                        )
            #print( "Min: " + Min + "\nMax: " + Max )
            Status = 1
            Mode = 0
        }
    }

    if( Clk )
    {
        V2 = Move ? O:shootPos() + O:eye() * Distance : O:aimPos()
        holoPos( 1, mix( V1, V2, 0.5 ) )
        
        local Dir = positive( V2 - V1 )
        holoScale( 1, Dir / 96 )
        holoScale( 2, -Dir / 96 )
    }
}

if( Status > 0 )
{
    if( findCanQuery() )
    {
        findClearBlackList()
        findClearWhiteList()
        findByClass("player")
        #findExcludeEntity(O)
        findClipToBox(Min,Max)
        R = findToArray()
    }
    
    if( Tele:isInWorld() & ( changed(R:count()) | clk("check") ) )
    {
        local I = 0
        foreach( K, Ply:entity = R )
        {
            if( Tele_Mode == "include" )
            {
                if( Whitelist[Ply:steamID(),number] )
                {
                    I++
                    sendPlayer(I,Ply)
                }
            }
            if( Tele_Mode == "exclude" )
            {
                if( !Whitelist[Ply:steamID(),number] )
                {
                    I++
                    sendPlayer(I,Ply)
                }
            }
        }
        timer("check",500)
    }
}

if( chatClk(O) )
{
    local Lsx = O:lastSaid():lower():explode(" ")
    
    if( !O:lastSaid():lower():find("override") & O:aimEntity() != EGPent ){ exit() }
    
    switch( Lsx[1,string] )
    {
        default, break
        
        case "tele",
            Tele = O:pos()+vec(0,0,6)
            hideChat(1)
        break
        
        case "allow",
            local Name = Lsx[2,string]
            setAllow(Name)
            hideChat(1)
        break
        
        case "remove",
            local Name = Lsx[2,string]
            foreach( K, Ply:entity = players() )
            {
                if( Ply:name():lower():find(Name) )
                {
                    Whitelist:remove(Ply:steamID())
                    Ply[Team,number] = 0
                }
            }
            hideChat(1)
        break
        
        case "system",
            local Cmd = Lsx[2,string]
            Status = Cmd == "on" ? 1 : Cmd == "off" ? 0 : Status
            hideChat(1)
        break
        
        case "set",
            V1 = V2 = Min = Max = vec()
            Mode = 1
            Status = -1
            hideChat(1)
        break
        
        case "clear",
            Whitelist:clear()
            foreach( K, Ply:entity = players() )
            {
                Ply[Team,number] = 0
            }
            hideChat(1)
        break
        
        case "queue",
            Queue:clear()
            Keyword = Lsx[2,string]
            Queue_Mode = 1
            hideChat(1)
        break
        
        case "add",
            if( Lsx[2,string] == "queue" )
            {
                Queue_Mode = 0
                foreach( K, Ply:entity = players() )
                {
                    if( !Whitelist[Ply:steamID(),number] & Queue[Ply:steamID(),number] )
                    {
                        Whitelist[Ply:steamID(),number] = 1
                        Ply[Team,number] = 1
                    }
                }
                Queue:clear()
            }
            else
            {
                local Name = Lsx[2,string]
                setAllow(Name)
            }
            hideChat(1)
        break
        
        case "include",
            Tele_Mode = "include"
            hideChat(1)
        break
        
        case "exclude",
            Tele_Mode = "exclude"
            hideChat(1)
        break
        
        case "screen",
            hideChat(1)
            reset()
        break
        
        case "commands",
        case "help",
        case "?",
            if( Lsx[2,string] == "print" )
            {
                print( Cmds:concat("\n") )
            }
            else
            {
                Print = Cmds:count()
                timer("commands",150)
            }
            hideChat(1)
        break
        
        case "color",
            if( Lsx[2,string] == "team" )
            {
                local Ex = Lsx[3,string]:explode(",")
                local Color = vec( Ex[1,string]:toNumber(), Ex[2,string]:toNumber(), Ex[3,string]:toNumber() )
                
                foreach( K, Ply:entity = players() )
                {
                    if( Whitelist[Ply:steamID(),number] )
                    {
                        Ply:setColor( Color )
                    }
                }
            }
            hideChat(1)
        break
        
        case "material",
            if( Lsx[2,string] == "team" )
            {
                local Mat = Lsx[3,string]
                
                foreach( K, Ply:entity = players() )
                {
                    if( Whitelist[Ply:steamID(),number] )
                    {
                        Ply:setMaterial( Mat )
                    }
                }
            }
            hideChat(1)
        break
        
        case "bring",
            if( Lsx[2,string] == "team" )
            {
                local I = 0
                foreach( K, Ply:entity = players() )
                {
                    if( Whitelist[Ply:steamID(),number] & Ply != O )
                    {
                        I++
                        Ply:tele( O:pos() + vec(Whitelist:count()*15,0,0):rotate(ang(0,(360/Whitelist:count())*I,0)) )
                    }
                }
            }
            hideChat(1)
        break
        
        case "tag",
            Idx = 2
            foreach( K, Ply:entity = players() )
            {
                if( Whitelist[Ply:steamID(),number] )
                {
                    local Ang = Ply:attachmentAng( "eyes" )
                    holoCreate( getID(1), Ply:attachmentPos("eyes") + Ang:up() * 20, vec(1,0.1,1), Ang, vec(255,0,0) )
                    holoModel( getID(0), "models/sprops/misc/alphanum/alphanum_star_4.mdl" )
                    holoMaterial( getID(0), "models/debug/debugwhite" )
                    holoDisableShading( getID(0), 1 )
                    holoParent( getID(0), Ply )
                }
            }
            timer("undo",10000)
            Tag = 1
            hideChat(1)
        break
    }
}

if( Queue_Mode & chatClk() )
{
    local Ls = lastSpoke()
    local Lsx = Ls:lastSaid():lower():explode(" ")
    switch( Lsx[1,string] )
    {
        default,break
        
        case Keyword,
            if( Auto_Add_Queue )
            {
                if( !Whitelist[Ls:steamID(),number] )
                {
                    Whitelist[Ls:steamID(),number] = 1
                    Ls[Team,number] = 1
                }
                updateList()
            }
            else
            {
                if( !Queue[Ls:steamID(),number] )
                {
                    Queue[Ls:steamID(),number] = 1
                }
            }
        break
        
        case "checkpoint",
            if( Auto_Add_Queue )
            {
                if( Whitelist[Ls:steamID(),number] )
                {
                    Whitelist[Ls:steamID(),number] = 0
                    Ls[Team,number] = 0
                }
                updateList()
            }
            else
            {
                Queue:remove(Ls:steamID())
            }
        break
    }
}

if( changed(Whitelist:count()) | clk("update") )
{
    updateList()
    
    timer("update",5000)
}

if( changed(Status) )
{
    holoColor( 1, Status < 0 ? vec(255) : Status ? vec(0,255,0) : vec(255,0,0) )
    holoColor( 2, Status < 0 ? vec(255) : Status ? vec(0,255,0) : vec(255,0,0) )
}

#if( Print )
#{
#    printCommands()
#}

if( clk("commands") & Print )
{
    hint( Cmds[Print,string], 10 )
    timer("commands",500)
    Print--
}

if( Tag & Idx > 2 )
{
    for(I=3,Idx)
    {
        holoAng( I, holoEntity(I):angles() + ang(0,25,0) )
    }
}

if( clk("undo") & Idx > 2 )
{
    for(I=3,Idx)
    {
        holoDelete( I )
    }
    Tag = 0
}

if( last() )
{
    holoDeleteAll()
    E["min",vector] = Min
    E["max",vector] = Max
    E["v1",vector] = V1
    E["v2",vector] = V2
    E["status",number] = Status
    E["tele",vector] = Tele
    E["tele_mode",string] = Tele_Mode
}
