@name anim/projects/examples/biped
@inputs Vehicle:entity Camera:wirelink
@outputs 
@persist [DestHeight JumpHeight MaxSpeed Acceleration BreakFactor]
@persist [CollisionRadius FallDampeningFactor] MoveDir:vector
@persist [Position]:vector [Angle]:angle [Speed Gravity MaxGravity] [Base Player]:entity
@trigger none

if (first()) {

    #--------------
    #-- Settings
    
    #include "anim/libraries/animate"
    
    DestHeight          = 75
    JumpHeight          = 50
    MaxSpeed            = 25
    MaxGravity          = 10
    Acceleration        = MaxSpeed
    BreakFactor         = 0.8
    CollisionRadius     = 32
    FallDampeningFactor = 0.7
    
    #--------------
    #-- Setup
    
    runOnLast(1)
    rangerHitEntities(1)
    rangerFilter(Vehicle)
    rangerPersist(1)
    
    holoCreate(1)
    holoModel(1, "models/sprops/misc/origin.mdl")
    
    Base = holoEntity(1)
    
    if (Vehicle["Position", vector]) {
        Position = Vehicle["Position", vector]
        holoPos(1, Position)
    }
    else {
        Position = entity():pos() + vec(0, 0, DestHeight)
        holoPos(1, Position)
    }
    
    function setup() {
        Camera["Parent", entity]   = Base
        Camera["Position", vector] = vec(8, 0, 38)
        Camera["Distance", number] = 0
        
        rangerFilter(Vehicle)
    }
    
    function number lerp(A, B, X) {
        return A + (B - A) * X
    }
    
    setup()
    
    holoCreate(10,Base:pos())
    holoParent(10,1)

    local L1 = 50
    local L2 = 20
    local L3 = 35
    
    holoCreate(70)
    holoParent(70,holoEntity(10))
    holoPos(70,holoEntity(10):toWorld(vec(0,15,0)))
    holoModel(70,"models/props_c17/oildrum001.mdl")
    holoScaleUnits(70,vec(16,16,L1))
        
    holoCreate(71)
    holoParent(71,70)
    holoPos(71,holoEntity(70):toWorld(vec(0,0,L1)))
    holoModel(71,"models/props_c17/oildrum001.mdl")
    holoScaleUnits(71,vec(14,14,L2))
    
    holoCreate(72)
    holoParent(72,71)
    holoPos(72,holoEntity(71):toWorld(vec(0,0,L2)))
    holoModel(72,"models/props_c17/oildrum001.mdl")
    holoScaleUnits(72,vec(13,13,L3))
    
    holoCreate(73)
    holoParent(73,72)
    holoPos(73,holoEntity(72):toWorld(vec(0,0,L3)))
    holoScaleUnits(73,vec(12,12,12))
    

    holoCreate(80)
    holoParent(80,holoEntity(10))
    holoPos(80,holoEntity(10):toWorld(vec(0,-15,0)))
    holoModel(80,"models/props_c17/oildrum001.mdl")
    holoScaleUnits(80,vec(16,16,L1))
        
    holoCreate(81)
    holoParent(81,80)
    holoPos(81,holoEntity(80):toWorld(vec(0,0,L1)))
    holoModel(81,"models/props_c17/oildrum001.mdl")
    holoScaleUnits(81,vec(14,14,L2))
    
    holoCreate(82)
    holoParent(82,81)
    holoPos(82,holoEntity(81):toWorld(vec(0,0,L2)))
    holoModel(82,"models/props_c17/oildrum001.mdl")
    holoScaleUnits(82,vec(13,13,L3))
    
    holoCreate(83)
    holoParent(83,82)
    holoPos(83,holoEntity(82):toWorld(vec(0,0,L3)))
    holoScaleUnits(83,vec(12,12,12))  
    
                    
    addFootController("fl",Base,vec(-10,10,0),0,3,30,45)
    addFootController("fr",Base,vec(-10,-10,0),180,3,30,45)
    
    addHitSound("fl","npc/dog/dog_footstep1.wav",0.272)
    addHitSound("fr","npc/dog/dog_footstep1.wav",0.272)


    addIKinematics("fl","Humanoid.Digitigrade",array(holoEntity(10),70,71,72,73))
    addIKinematics("fr","Humanoid.Digitigrade",array(holoEntity(10),80,81,82,83)) 
        
    #addStepSound("fl","doors/doormove1.wav",1)
    #addStepSound("fr","doors/doormove1.wav",1)
}

interval(90)


#--------------
#- Vehicle
Player = Vehicle:driver()

if (!Vehicle:parent()) {
    Vehicle:propFreeze(1)
    
    local Pos = holoEntity(10):toWorld(vec(0, 0, 0))
    local Ang = holoEntity(10):toWorld(ang(0, -90, 0))

    Vehicle:setPos(Pos)
    Vehicle:setAng(Ang)
    
    if ((Vehicle:pos() - Pos):length() < 0.1 & vec(Vehicle:angles() - Ang):length() < 0.1) {
        Vehicle:parentTo(holoEntity(10))
        
        setup()
    }
}
if (last()) { 
    Vehicle["Position", vector] = Position
    Vehicle:deparent()
}


if (Player) {

    #--------------
    #- Camera

    Camera["Activated", number] = 1
    if (Player:keyReload()) { Vehicle:ejectPod() }
    
    #--------------
    #- Directions
    
    local Trace = rangerOffsetHull(DestHeight*2, Position, vec(0, 0, -1), vec(24))
    
    local AimDir  = Vehicle:toLocalAxis(Player:eye()):setZ(0):normalized()
    local SideDir = AimDir:cross(vec(0, 0, 1))
    local Forward = Player:keyForward() - Player:keyBack()
    local Strafe  = Player:keyRight() - Player:keyLeft()
    
    if (Forward | Strafe) { Speed = min(Speed + Acceleration, MaxSpeed + Player:keySprint()*10) } else { Speed *= BreakFactor }

    local MoveDir = (AimDir*Forward + SideDir*Strafe):normalized()
    
    #--------------
    #- Gravity

    if (Trace:distance() <= DestHeight + 2) {
        Gravity *= FallDampeningFactor
        
        local Diff = Trace:distance() - DestHeight
        Position += Diff*vec(0, 0, -1)
    }
    elseif (Trace:distance() <= DestHeight + 20) {
        if (MoveDir:length() > 0) {
            local SlopeDot = MoveDir:dot(Trace:hitNormal())
            
            if (SlopeDot > 0.1) {
                local Diff = Trace:distance() - DestHeight
                Position += Diff*vec(0, 0, -1)
            }
            
        }
    }
    else { 
        Gravity = min(Gravity - 3, Gravity)
    }
    
    #--------------
    #- Movement
    
    Position += MoveDir*Speed + vec(0, 0, Gravity)
    
    if (MoveDir:length() > 0) {
        Angle = slerp(quat(MoveDir:toAngle()), quat(Angle), 0.5):toAngle()

        local Trace = rangerOffsetHull(CollisionRadius, Position, MoveDir, vec(CollisionRadius))
        
        local Dist = Trace:distance()
        if (Dist <= CollisionRadius) {
            local Normal = Trace:hitNormal()
            local Diff = -(Dist - CollisionRadius)
            local Approach = MoveDir * Speed
            
            local Reflection = -2 * (Approach:dot(Normal)) * Normal - Approach
            
            Position += Reflection:normalized() * Diff
        }
        
        #Anim += Speed*pi()/3
    } else {
        #Anim *= BreakFactor
    }
    
    #FootControllers["fl", table]["stepMaxL", number] = Speed
    #FootControllers["fr", table]["stepMaxL", number] = Speed
    #FootControllers["rl", table]["stepMaxL", number] = Speed
    #FootControllers["rr", table]["stepMaxL", number] = Speed
    
    holoPos(1, Position)#mix(Position, Base:pos(), 0.5))
    holoAng(1, Angle)

    #holoPos(9, rangerOffset(DestHeight*2, Base:pos(), WorldDownVec):position() + vec(0, 0, BreathS + DestHeight + abs(cos(GaitFrameTime/2))*GaitTable["fl", table]["stepCurH", number]))
    
    local Cos = cos(FrameTime)*FootControllers["fl", table]["stepH", number]/3
    local RD = rangerOffset(DestHeight*5,Base:toWorld(vec(0,-Cos/2,0)),WorldDownVec):position() + vec(0,0,DestHeight+abs(Cos))
    holoPos(10, RD) #Base:toWorld(vec(15, 0, abs(cos(FrameTime/2)*FootControllers["fl", table]["stepH", number]))))
    holoAng(10, Base:toWorld(ang(0, 0, Cos/5-Base:toLocalAxis(MoveDir*Speed):y()/3)))
   # holoAng(10, Base:toWorld(ang(5+sin(-FrameTime)*FootControllers["fl", table]["stepH", number], 0, -Base:toLocalAxis(MoveDir*Speed):y())))
    
    #updateFootControllers( Speed, 1)
    updateFootControllers( Speed*1.35*MoveDir:length(), 1)

}
else {
    Camera["Activated", number] = 0
}

