--lightspeed dash
local function P_RingNearby(player)
    local closest
    closest = NULL

    for mo in mobjs.iterate() do
        if mo.health <= 0 then
            continue
        end

        if not (mo.type == MT_RING or mo.type == MT_COIN) then
            continue
        end

        if P_AproxDistance(P_AproxDistance(player.mo.x - mo.x, player.mo.y - mo.y), player.mo.z - mo.z) > 192 * FRACUNIT then
            continue
        end

        if not P_CheckSight(player.mo, mo) then
            continue
        end

        if closest and P_AproxDistance(P_AproxDistance(player.mo.x - mo.x, player.mo.y - mo.y), player.mo.z - mo.z) > P_AproxDistance(P_AproxDistance(player.mo.x - closest.x, player.mo.y - closest.y), player.mo.z - closest.z) then
            continue
        end

        closest = mo
    end

    if closest then
        return true
    end

    return false
end

local function P_LightDash(source, enemy)
    if not source.tracer then
        return
    end

    local dest = source.tracer

    if not dest then
        return
    end

    source.angle = R_PointToAngle2(source.x, source.y, enemy.x, enemy.y)

    local dist = P_AproxDistance(P_AproxDistance(dest.x - source.x, dest.y - source.y), dest.z - source.z)
    if dist < 1 then
        dist = 1
    end

    source.momx = FixedMul(FixedDiv(dest.x - source.x, dist), 60 * FRACUNIT)
    source.momy = FixedMul(FixedDiv(dest.y - source.y, dist), 60 * FRACUNIT)
    source.momz = FixedMul(FixedDiv(dest.z - source.z, dist), 60 * FRACUNIT)
end

local function P_LookForRings(player)
    local found
    player.mo.target = NULL
    player.mo.tracer = NULL

    for mo in mobjs.iterate() do
        if mo.health <= 0 then
            continue
        end

        if not (mo.type == MT_RING or mo.type == MT_COIN) then
            continue
        end

        if P_AproxDistance(P_AproxDistance(player.mo.x - mo.x, player.mo.y - mo.y), player.mo.z - mo.z) > 192 * FRACUNIT then
            continue
        end

        if not P_CheckSight(player.mo, mo) then
            continue
        end

        if player.mo.target and P_AproxDistance(P_AproxDistance(player.mo.x - mo.x, player.mo.y - mo.y), player.mo.z - mo.z) > P_AproxDistance(P_AproxDistance(player.mo.x - player.mo.target.x, player.mo.y - player.mo.target.y), player.mo.z - player.mo.target.z) then
            continue
        end

        found = true
        player.mo.target = mo
        player.mo.tracer = mo
    end

    if found then
        P_ResetPlayer(player)
        player.mo.state = S_PLAY_FALL
        P_ResetScore(player)
        P_LightDash(player.mo, player.mo.tracer)
        return
    end
    player.mo.momx = FixedDiv(player.mo.momx, 2 * FRACUNIT)
    player.mo.momy = FixedDiv(player.mo.momy, 2 * FRACUNIT)
    player.mo.momz = FixedDiv(player.mo.momz, 2 * FRACUNIT)
    player.lightdash = false
end

addHook("PlayerThink", function(player)
    if (player.mo and player.mo.valid and player.mo.skin == "neostreak") then
        if P_RingNearby(player) then
            player.lightdashallowed = true

            if player.cmd.buttons & BT_TOSSFLAG ~= 0 then
                if not player.attackdown then
                    if player.lightdash then
                        player.lightdash = false
                    else
                        player.lightdash = TICRATE
                    end
                    player.attackdown = true
                end
            elseif not (player.cmd.buttons & BT_TOSSFLAG ~= 0) then
                player.attackdown = false
            end
        else
            player.lightdashallowed = false
        end

        if player.lightdash then
            P_LookForRings(player)
            player.powers[pw_flashing] = 2
        end
    end
end)