@name Hanoi
@persist [O,E,Up]:entity Count [P1,P2,P3,Pos]:array Moves Start FW Q

runOnTick(10)

if(first()) {
    O = findPlayerByName("XD")
    E = entity()
    
    Count = 6
    Pos = array(40,0,-40)
    Start = 1
    
    if(Count > 10) {
        print("Clamped to 10 (anything past this point is impractical)")
        clamp(Count,1,10)
    }
        
    for(I=101,103) {
        holoCreate(I,E:pos()+vec(0,Pos[I-100,number],18),vec(0.1,0.1,3),ang(),vec()+30,"hqcylinder")
        holoCreate(I+3,E:pos()+vec(0,Pos[I-100,number],0),vec(3,3,0.1)), holoAlpha(I+3,1)
    }
    
    for(I=1,Count) {
        Size = (I != 1 & I != Count ? 3 / Count * I : ( I == 1 ? 0.5 : 3 ) )
        holoCreate(I,E:pos()+vec(0,Pos[1,number],-(1-(Count*3)+(I-1)*3)),vec(Size,Size,0.25),ang(),hsv2rgb(vec(random(1,360),1,1)),"hqcylinder")
        P1:pushEntity(holoEntity(I))
    }

    function number checkLPI(H) {
        local Holo = holoEntity(H)
        local Vec = (O:shootPos()+(Holo:up():dot(Holo:pos()-O:shootPos()))/(Holo:up():dot((O:shootPos()+O:eye())-O:shootPos()))*((O:shootPos()+O:eye())-O:shootPos()))
        return inrange(Vec,Holo:pos()-(holoScaleUnits(holoIndex(Holo))/2)-vec(0,0,5),Holo:pos()+(holoScaleUnits(holoIndex(Holo))/2)+vec(0,0,5))
    }
}

if(!FW) {
    if(Up:isValid()) {
        for(I=104,106) {
            if(checkLPI(I)) {
                holoPos(holoIndex(Up),holoEntity(I):pos()+vec(0,0,50))
            }
        }
        
        if(changed(O:keyUse()) & O:keyUse()) {
            for(I=1,3) {
                if(checkLPI(I+103)) {
                    Ar = (I == 1 ? P1 : (I == 2 ? P2 : P3))
                    if(holoScale(holoIndex(Up)):x() < holoScale(holoIndex(Ar[1,entity])):x() | Ar:count() == 0) {
                        holoPos(holoIndex(Up),E:pos()+vec(0,Pos[I,number],Ar:count()*3))
                        Ar:insertEntity(1,Up)
                        Up = noentity()
                        
                        if(Ar:count() == Count & I != Start) {
                            if(O == owner()) {
                                printColor(vec()+255,"Congratulations, you won!  It took you ",vec(0,255,100),Moves,vec()+255," moves.")
                            } else {
                                concmd("say Congratulations, you won!  It took you "+toString(Moves)+" moves") 
                            }
                            for(I=1,8) {
                                holoCreate(I)
                                holoPos(I,E:pos()+vec(sin(360/8*I)*50,cos(360/8*I)*50,0))
                                holoColor(I,hsv2rgb(vec(360/8*I,1,1)))
                                holoEntity(I):setTrails(20,20,20,"trails/laser",hsv2rgb(vec(360/8*I,1,1)),255)
                            }
                            E:soundPlay(1,0,"/vo/announcer_victory.wav")
                            
                            FW = I
                            timer("delay",5000)
                        } else {
                            Moves++
                        }
                    }
                }
            }
        }    
    } else {
        if(changed(O:keyUse()) & O:keyUse()) {
            for(I=1,3) {
                if(checkLPI(I+103)) {
                    Ar = (I == 1 ? P1 : (I == 2 ? P2 : P3))
                    if(Ar:count()) {
                        Up = Ar:shiftEntity()
                        holoPos(holoIndex(Up),holoEntity(I+103):pos()+vec(0,0,50))
                    }
                }
            }
        }
    }
} else {
    Q+=2
    for(I=1,8) {
        holoPos(I,E:pos()+vec(sin(360/8*I+Q)*50,cos(360/8*I+Q)*50,Q))
    }
    
    if(clk("delay")) {             
        Moves = 0
        Start = FW
        FW = 0
        holoDeleteAll()
    }
}


