@name A-Chair2
@inputs Chair:entity
@persist [Owner Entity Driver]:entity
@persist [RED GREEN BLUE YELLOW CYAN WHITE GREY BLACK]:vector

interval(100)
runOnChat(1)

if(first()) {
    #include "e2shared/graph_gm_construct"
    
    Owner=owner()
    Entity=entity()
    
    RED=vec(255,0,0)
    GREEN=vec(0,255,0)
    BLUE=vec(0,0,255)
    YELLOW=vec(255,255,0)
    CYAN=vec(0,255,255)
    WHITE=vec(255)
    GREY=vec(128)
    BLACK=vec(0)
    
    function table table:path2(Start:string,End:string) {
        local Open=table((Start)=1)
        local Parents=table((Start)="__END")
        
        local OpenCt=1
        local NodeGraph=This:clone()
        
        local StartPos=NodeGraph[Start,table]["Pos",vector]
        local EndPos=NodeGraph[End,table]["Pos",vector]
        
        local IterationCt=0
        local MaxIterations=500
        
        local Deny_Blocked_Routes=1 # Skip routes blocked by entities instead of penalizing them
        local Blocked_Route_Penalty=100000 # Blocked route heuristic penalty
        local BaseOffset=vec(0,0,20) # Offset for rangers, e.g. to prevent clipping below props
        
        NodeGraph[Start,table]["State",number]=1
        
        while(1) {
            # Edge case: Took too many tries
            IterationCt++
            if(IterationCt>MaxIterations) {
                return table(
                    "error"="Exceeded hard limit of "+MaxIterations+" iterations.",
                    "success"=0,
                    "path"=array()
                )
            }
            # Edge Cases
            if(OpenCt<=0) {
                return table(
                    "error"="Ran out of open nodes.  No path found.",
                    "success"=0,
                    "path"=array()
                )
            }
            
            # Select and delete best node
            local BestH=9e99
            local BestNode=""
            foreach(NodeName,State:number=Open) {
                if(State!=1) {continue}
                local NodeData=NodeGraph[NodeName,table]
                if(NodeData["H",number]<BestH) {
                    BestH=NodeData["H",number]
                    BestNode=NodeName
                }
            }
            
            NodeGraph[BestNode,table]["State",number]=2
            Open:removeNumber(BestNode)
            OpenCt--
            
            # Edge case: End reached
            if(BestNode==End) {
                local Output=array()
                local Parent=Parents[End,string]
                while(1) {
                    Output:unshiftString(Parent)
                    if(Parent!="__END") {
                        Parent=Parents[Parent,string]
                    } else {
                        break
                    }
                }
                
                Output:shiftString()
                Output:pushString(End)
                
                return table(
                    "error"="No error.",
                    "success"=1,
                    "path"=Output
                )
            }
            
            # Add neighbors to open set and continue
            local BaseH=NodeGraph[BestNode,table]["H",number]
            local LastPos=NodeGraph[BestNode,table]["Pos",vector]
            
            foreach(I,V:string=NodeGraph[BestNode,table]["N",array]) {
                if(NodeGraph[V,table]["State",number]!=0) {continue}
                local ThisPos=NodeGraph[V,table]["Pos",vector]
                local DistDiff=(ThisPos:distance(LastPos))
                local Ranger=rangerOffset(ThisPos+BaseOffset,LastPos+BaseOffset)
                local Hit=Ranger:hit()
                
                local Heuristic=
                    BaseH
                    +DistDiff
                    +ThisPos:distance(EndPos)
                    +(Hit ? Blocked_Route_Penalty : 0)
                
                NodeGraph[V,table]["H",number]=Heuristic
                NodeGraph[V,table]["State",number]=1
                
                if(!Deny_Blocked_Routes || !Hit) {
                    Parents[V,string]=BestNode
                    Open[V,number]=1
                } elseif (Deny_Blocked_Routes) {
                    NodeGraph[V,table]["State",number]=2
                }
                OpenCt++
            }
        }
    }
}

if(changed(Chair) & Chair) {
    # Entity:setAlpha(0)
    lightCreate(1,Chair:pos())
    lightColor(1,vec(64))
    lightParent(1,Chair)
}

if(clk()) {
    Driver=Chair:driver()
    if(changed(Driver) & Driver) {
        Chair:printColorDriver(YELLOW,"[A-Chair2] ",WHITE,"Welcome to A-Chair 2, the A* pathfinding chair.")
        Chair:printColorDriver(YELLOW,"[A-Chair2] ",WHITE,"Say ",GREEN,"goto <player>",WHITE," to go to a player.")
    }
}

if(chatClk(Driver) & Driver:lastSaid():sub(1,4)=="goto") {
    local PlayerName=Driver:lastSaid():sub(6)
    local Player=findPlayerByName(PlayerName)
    
    
}
