
function aom_playerapi.physics.do_stair_slow(player, dtime)
    if not aom_playerapi.get_setting(nil, "gameplay_stair_slowness", false) then return end
    local pi = aom_playerapi.check_player(player)
    local info = core.get_player_information(player:get_player_name())
    local checkpos = player:get_pos()
    local vel = vector.copy(pi.avg_vel)
    local latency = info.avg_rtt or 0.2
    local predict = (latency + 0.5) * vel
    checkpos = checkpos + predict
    checkpos.y = checkpos.y + 0.5
    local ray = core.raycast(checkpos, vector.offset(checkpos, 0, -2.2 + predict.y, 0), false, false)
    local stair = nil
    for pt in ray do
        local node = core.get_node(pt.under)
        if core.get_item_group(node.name, "stair") > 0 then
            stair = pt
            break
        end
    end
    if stair then
        local node = core.get_node_or_nil(stair.under)
		-- no slow if it's upside down / on its side
        if node.param2 > 4 then
            stair = nil
        else -- no slow if only one stair present
            local dir = core.facedir_to_dir(node.param2)
            dir.y = 0
            local p = stair.under + vector.normalize(dir)
			if (core.get_item_group(core.get_node(vector.offset(p, 0, 1, 0)).name, "stair") > 0)
			or (core.get_item_group(core.get_node(vector.offset(p, 0,-1, 0)).name, "stair") > 0) then else
				stair = nil
			end
        end
    end
    if stair then
        if math.abs(pi.avg_vel.y) < 0.8 * dtime then return end
        aom_statusfx.apply_status(player, "stair_slowness", 0.2, {speed = 0.6, no_stack = true})
    else
        aom_statusfx.remove_status(player, "stair_slowness")
    end
end

aom_playerapi.register_on_player_step(aom_playerapi.physics.do_stair_slow)
