@name metatesting
@inputs 
@outputs 
@persist Gaits:table FootData:table WalkCycle WalkDelta Sprinting
@trigger none
@model models/maxofs2d/cube_tool.mdl

if (first()) {
    
    function setGait(ID, Start, Length) {
        local Tbl = table()
        Start -= floor(Start)
        Length -= floor(Length)
        
        Tbl["start", number] = Start
        Tbl["end", number] = Start + Length
        
        Gaits[ID, table] = Tbl
    }
    
    function number gaitGetFract(Idx, X) {
        local Gait = Gaits[Idx, table]
        
        local Start = Gait["start", number]
        local End = Gait["end", number]
        local GFract = 0
        local GMove = 0
        
        if (X >= Start && X <= End) {
            return (X - Start) / (End - Start)
        }
        
        if (Start < 0) {
            if (X >= abs(Start) && X <= 1) {
                return (X - Start) / (End - Start)
            }
        }
        elseif (End > 1) {
            if (X + 1 >= Start && X + 1 <= End) {                    
                return (X + 1 - Start) / (End - Start)
            }
        }
        
        return 0
    }
    
    function void resetLeg(Str) {
        FootData[Str + ".Dest", vector] = FootData[Str + ".Pos", vector]
        FootData[Str + ".Prev", vector] = FootData[Str + ".Pos", vector]
        
        FootData[Str + ".IsMoving", number] = 0
        FootData[Str + ".ShouldMove", number] = 0
    }
    
    function number lerp(A, B, X) {
        return A + (B - A) * X
    }
    
    function vector lerp(A:vector, B:vector, X) {
        return A + (B - A) * X
    }
    
    function angle lerp(A:angle, B:angle, X) {
        return A + (B - A) * X
    }
    
    function number smoothstep(A, B, X) {
        local X = max(0, min(1, (X - A) / (B - A)))
        return X * X * (3 - 2 * X)
    }
    
    
    for (I = 1, 4) { holoCreate(I) }
}

    interval( 60 )


    if (Sprinting) {
        local GaitSizeFront = clamp(0.35, 0, 0.9)
        local GaitSizeRear = clamp(0.5, 0, 0.9)
        
        setGait(1, 0.95, 0.5) # Right Front
        setGait(2, 0.85, 0.5) # Left Front
        
        setGait(3, 0.0, 0.65) # Right Rear
        setGait(4, 0.3, 0.65) # Left Rear
    
        WalkDelta = 0.2
    }
    else {
        local GaitSizeFront = clamp(0.5, 0, 0.8)
        local GaitSizeRear = clamp(0.4, 0, 0.8)
        
        setGait(1, 0.0, 0.5) # Right Front
        setGait(2, 0.5, 0.5) # Left Front
        
        setGait(3, 0.75, 0.5) # Right Rear
        setGait(4, 0.25, 0.5) # Left Rear
    
        WalkDelta = lerp(WalkDelta, 0.11, 0.1)
    }
    
    WalkCycle += WalkDelta
    
    Base = entity()
    BaseVel = Base:vel()
    BaseForward = Base:forward()
    
    Down = vec(0,0,-1)
    
    Offset = vec(50,0,0)
    
    for (I = 1, 4) {
        local VelOffset = BaseVel / 5
        local LegOffset = BaseForward * 0
        if (Sprinting) { VelOffset = BaseVel / 9 }
        
        
        local LRG = rangerOffset(200, Base:toWorld(Offset:rotate(0, 90*I + 45, 0)) + LegOffset + VelOffset, Down)
        
        local GFract = gaitGetFract(I, WalkCycle)
        local GMove = GFract != 0
        
        local ZDot = abs((LRG:pos() - FootData[I + ".Pos", vector]):normalized():dot(vec(0, 0, 1)))
        if (ZDot > 0.9) {
            FootData[I + ".Pos", vector ] = LRG:pos()
        }
        
        if (GMove) {
            FootData[I + ".Dest", vector ] = LRG:pos()
            
            if (!FootData[I + ".IsMoving", number]) {
                FootData[I + ".Prev", vector] = FootData[I + ".Pos", vector]
                
                if (FootData[I + ".Pos", vector ]:distance(LRG:pos()) >= 8) {
                    local Dot = 0
                    if (LRG:hit()) {
                        Dot = 1 - vec( 0, 0, 1 ):dot(LRG:hitNormal())
                    }
                    
                    if (LRG:distance() <= 200 + Dot * 100 * clamp((Base:vel():setZ( 0 ):length() / 100), 0, 200 / 2)) {
                        FootData[I + ".ShouldMove", number ] = 1
                        
                        #playFootSound(I, Sprinting)
                    }
                }
            }
            
            if (FootData[I + ".ShouldMove", number]) {
                
                local Prev = FootData[I + ".Prev", vector]
                local Dest = LRG:pos()
                
                local Mid = mix(Dest, Prev, 0.4) + vec(0, 0, clamp((Prev:distance(Dest) / 3), 0, 200 / 1.5))
                
                local Pos = bezier(Prev, Mid, Dest, GFract)
                FootData[I + ".Pos", vector] = Pos
            }
        } else {
            FootData[I + ".ShouldMove", number] = 0
            if (FootData[I + ".IsMoving", number]) {
                FootData[I + ".Pos", vector] = FootData[I + ".Dest", vector]
            }
        }
            
        FootData[I + ".IsMoving", number] = GMove && FootData[I + ".ShouldMove", number]
        
        holoPos(I, FootData[I + ".Pos", vector])
    }


    if (WalkCycle > 1) {
        WalkCycle = 0
    }
#local LRG = rangerOffset(FLLength * 1.3, holoEntity(Shoulder3):pos() + LegOffset + VelOffset, vec(0, 0, -1))

                
                
