require("level")
require("render")

function lerp(a, b, x)
    return a + ((b - a) * x)
end

function qlerp(a, b, x)
    return lerp(a, b, x * x)
end

function game_tick()
    if ctx.udata == nil then
        ctx.udata = {
            level = load_level("levels/00.lvl")
        }
        ctx.udata.player = {
            position = ctx.udata.level.classes.player_spawn.position,
            position_lerp = ctx.udata.level.classes.player_spawn.position,
            direction = { x = 1, y = 0, z = 0 },
            direction_lerp = { x = 1, y = 0, z = 0 },
        }
    end

    input_action { control = "A", name = "turn_left" }
    input_action { control = "D", name = "turn_right" }
    input_action { control = "W", name = "walk_forward" }
    input_action { control = "S", name = "walk_backward" }

    if input_action_just_released { name = "turn_left" } then
        ctx.udata.player.direction = { x = ctx.udata.player.direction.z,
                                       y = ctx.udata.player.direction.y,
                                       z =-ctx.udata.player.direction.x }
    end

    if input_action_just_released { name = "turn_right" } then
        ctx.udata.player.direction = { x =-ctx.udata.player.direction.z,
                                       y = ctx.udata.player.direction.y,
                                       z = ctx.udata.player.direction.x }
    end

    local move = { x = 0, y = 0 }
    if input_action_just_released { name = "walk_forward" } then
        move = { x = move.x + ctx.udata.player.direction.x, y = move.y + ctx.udata.player.direction.z }
    end
    if input_action_just_released { name = "walk_backward" } then
        move = { x = move.x - ctx.udata.player.direction.x, y = move.y - ctx.udata.player.direction.z }
    end

    if ctx.udata.level.grid[ctx.udata.player.position.y + move.y][ctx.udata.player.position.x + move.x].solid ~= nil then
        move = { x = 0, y = 0 }
    end

    ctx.udata.player.position = { x = ctx.udata.player.position.x + move.x, y = ctx.udata.player.position.y + move.y }

    ctx.udata.player.position_lerp.x = qlerp(ctx.udata.player.position_lerp.x, ctx.udata.player.position.x, ctx.frame_duration * 30)
    ctx.udata.player.position_lerp.y = qlerp(ctx.udata.player.position_lerp.y, ctx.udata.player.position.y, ctx.frame_duration * 30)
    ctx.udata.player.direction_lerp.x = qlerp(ctx.udata.player.direction_lerp.x, ctx.udata.player.direction.x, ctx.frame_duration * 40)
    ctx.udata.player.direction_lerp.z = qlerp(ctx.udata.player.direction_lerp.z, ctx.udata.player.direction.z, ctx.frame_duration * 40)

    draw_camera {
        position = {
            x = ctx.udata.player.position_lerp.x + 0.5 - ctx.udata.player.direction.x / 2,
            y = 0.5,
            z = ctx.udata.player.position_lerp.y + 0.5 - ctx.udata.player.direction.z / 2,
        },
        direction = ctx.udata.player.direction_lerp,
    }

    render_dungeon(ctx.udata.level)
end