Твоя задача уменьшить количество строк в коде, не меняя его логику, сделай профессионально рефакторинг кода, улучши код
```lua
local vector3d = require('vector3d')
local ffi = require('ffi')
local sampev = require('samp.events')
require('Tasking')
require('addon')
local tp = false
local tp_dist = 175
local waiting = 1400
local percent = 0
local processedPickups = {}
local settings = {
    modes = {
        buying_hotel = false;
    },
    money = 10000;
    hours = 2;
    check_payment = 1;
}

local hotel = {
    spawn_pos = {
        x = 0,
        y = 0,
        z = 0
    };
    updating_rent = false;
    lowhp = false;
    hungry = false;
    best_hotels = {
        line_number = 0,
        name = '',
        dist = 0
    };
}

math.randomseed(os.time())
local race_checkpoint = {
    x = 0,
    y = 0,
    z = 0
}

local selected_hotel = {}
function onSendRPC(id, bs)
    if id == 52 then
        newTask(function()
            wait(250)
            sendInput('/stats')
        end)

        if getBotMoney() <= tonumber(settings.money) then
            SCMF('Не, у тебя маловато деньжат')
            exit()
        end
    end
end

local tasks = {}
local outSpawn = false
local inHotel = false
function sampev.onSetSpawnInfo(team, skin, _unused, position, rotation, weapons, ammo)
    hotel.spawn_pos = position
end

function sampev.onSetRaceCheckpoint(type, position, nextPosition, size)
    if not settings.modes.buying_hotel and getBotInterior() == 0 and position and not inHotel then
        race_checkpoint.x, race_checkpoint.y, race_checkpoint.z = position.x, position.y, position.z
        SCMF(string.format('Координаты отеля установлены: %s %s %s', race_checkpoint.x, race_checkpoint.y, race_checkpoint.z))
        newTask(function()
            wait(1000)
            teleportToCoords(race_checkpoint.x, race_checkpoint.y, race_checkpoint.z, true)
        end)
    end
end

function onLoad()
    tasks.findLarec = Tasking.new(findLarec)
    tasks.autoPaymentTask = Tasking.new(autoPaymentTask)
    tasks.autoEat = Tasking.new(autoEat)
    tasks.getHealth = Tasking.new(getHealth)
    tasks.checkInHotel = Tasking.new(checkInHotel)
end

function onDisconnect()
    for id in pairs(processedPickups) do
        processedPickups[id] = nil
    end
end

function onUnload()
    for name, task in pairs(tasks) do
        Tasking.remove(task)
        tasks[name] = nil
    end
end

function onUpdate()
    Tasking.tick()
end

function onCoordStop()
    for id in pairs(processedPickups) do
        processedPickups[id] = nil
    end
end

local inOrg = false
function sampev.onShowDialog(dialogId, style, title, button1, button2, text)
    local botInterior = getBotInterior()
    if title:find('Основная статистика') then
        for line in text:gmatch('[^\r\n]+') do
            if line:find('{FFFFFF}Должность: {B83434}.+') then
                sendDialogResponse(dialogId, 0, 0, '')
                inOrg = true
                newTask(function()
                    wait(250)
                    sendInput('/setspawn')
                end)
            elseif line:find('{FFFFFF}Организация: {B83434}%[Не имеется%]') then
                sendDialogResponse(dialogId, 0, 0, '')
                inOrg = false
            elseif line:find('{FFFFFF}Отель:.+') then
                settings.modes.buying_hotel = true
            end
        end
        return false
    end

    if title:find('Выберите место спавна') then
        for line in text:gmatch('[^\r\n]+') do
            if line:find('Текущее место спавна: {.-}Отель') then
                SCMF('Мы ещё в отеле, всё норм')
                settings.modes.buying_hotel = true
                inHotel = true
                break
            elseif line:find('Текущее место спавна: {.-}Вокзал') and inOrg then
                SCMF('Меняем сетспавн на более близкий к организации...')
                newTask(function()
                    wait(250)
                    sendDialogResponse(dialogId, 1, 3, '')
                    wait(250)
                    reconnect()
                end)
            end
        end

        if not inHotel then
            settings.modes.buying_hotel = false
            if outSpawn then
                SCMF('Пора искать новый дом')
                if botInterior == 0 then
                    newTask(function()
                        sendDialogResponse(dialogId, 0, 0, '')
                        wait(500)
                        sendInput('/gps')
                    end)
                else
                    SCMF('Находимся внутри, GPS не будет введен до выхода на улицу')
                end
            end
        end
        return false
    end

    if title:find('{.-}Лифт отеля') and hotel.updating_rent or hotel.get_debt then
        local line_number = 0
        for line in text:gmatch('[^\r\n]+') do
            line_number = line_number + 1
            if line:find('Холл') then sendDialogResponse(dialogId, 1, line_number - 1, '') end
        end
        return false
    end

    if title:find('Лечение в номере') and hotel.lowhp then
        sendDialogResponse(dialogId, 1, 0, '')
        return false
    end

    if (title:find('Меню ресторана отеля') or title:find('Меню мини%-бара')) and hotel.hungry then
        sendDialogResponse(dialogId, 1, 4, '')
        return false
    end

    if settings.modes.buying_hotel == false and hotel.updating_rent == false then
        if title:find('GPS Навигатор') then
            local line_number = 0
            for line in text:gmatch('[^\r\n]+') do
                line_number = line_number + 1
                if line:find('{ff6666}%- {FFFFFF}Отели') then sendDialogResponse(dialogId, 1, line_number - 1, '') end
            end
            return false
        end

        if title:find('Отель') then
            local line_number = 0
            for line in text:gmatch('[^\r\n]+') do
                line_number = line_number + 1
                if line:find('{FF6666}%d+.{ffffff} "(.*)"	{ffffff}(%d+) номеров	{cccccc}(%d+) м{ffffff}	{FF6666}%d+ звезд%(ы%)') then
                    local name, rooms, dist = line:match('{FF6666}%d+.{ffffff} "(.*)"	{ffffff}(%d+) номеров	{cccccc}(%d+) м{ffffff}	{FF6666}%d+ звезд%(ы%)')
                    if tonumber(rooms) >= 5 and tonumber(dist) <= 1000 then
                        table.insert(hotel.best_hotels, {
                            line_number = line_number,
                            name = name,
                            dist = dist
                        })
                    end
                end
            end

            if #hotel.best_hotels > 0 then
                math.randomseed(os.time())
                local random_index = math.random(1, #hotel.best_hotels)
                selected_hotel = hotel.best_hotels[random_index]
                SCMF(string.format('Случайный подходящий отель: %s. Расстояние %s м. Номер строки: %d', selected_hotel.name, selected_hotel.dist, selected_hotel.line_number))
                newTask(function()
                    wait(250)
                    sendDialogResponse(dialogId, 1, selected_hotel.line_number - 2, '')
                end)
            else
                SCMF('Подходящих отелей не найдено.')
            end
            return false
        end

        if title:find('Ресепшен отеля') then
            newTask(function()
                wait(250)
                sendDialogResponse(dialogId, 1, 0, '')
            end)
            return false
        end

        if title:find('Список номеров') then
            local line_number = 0
            local rooms = {}
            for line in text:gmatch('[^\r\n]+') do
                line_number = line_number + 1
                print(line)
                if line:find('{.-}Комната №(%d+){ffffff}%s+{cccccc}Отсутствует') then
                    table.insert(rooms, {
                        line_number = line_number,
                        room_number = line:match('Комната №(%d+)')
                    })
                end
            end

            if #rooms > 0 then
                local random_index = math.random(1, #rooms)
                local selected_room = rooms[random_index]
                SCMF(string.format('Случайный подходящий номер: %s. Номер строки: %d', selected_room.room_number, selected_room.line_number))
                newTask(function()
                    wait(250)
                    sendDialogResponse(dialogId, 1, selected_room.line_number - 2, '')
                end)
            else
                SCMF('Подходящих номеров не найдено, процесс самоликвидации запущен')
                exit()
            end
            return false
        end

        if title:find('Информация о номере') then
            newTask(function()
                wait(250)
                sendDialogResponse(dialogId, 1, 0, tostring(settings.hours))
            end)
            return false
        end

        if text:find('{FF6666}%-{ffffff} Вы действительно хотите взять номер в аренду?') then
            sendDialogResponse(dialogId, 1, 0, '')
            return false
        end

        if title:find('Выбор типа номера') then
            newTask(function()
                wait(250)
                sendDialogResponse(dialogId, 1, 2, '')
            end)
            return false
        end
    end

    if hotel.updating_rent == true then
        if title:find('Ресепшен отеля') then
            newTask(function()
                wait(250)
                sendDialogResponse(dialogId, 1, 1, '')
            end)
            return false
        end

        if title:find('Управление бронированием') then
            newTask(function()
                wait(250)
                sendDialogResponse(dialogId, 1, 5, '')
            end)
            return false
        end

        if text:find('{FF6666}%-{ffffff} Вы действительно хотите начать процесс продления номера?') then
            newTask(function()
                wait(250)
                sendDialogResponse(dialogId, 1, 0, tostring(settings.hours))
            end)
            return false
        end

        if text:find('{FF6666}%-{ffffff} Вы действительно хотите продлить аренду номера?') then
            newTask(function()
                wait(250)
                sendDialogResponse(dialogId, 1, 0, '')
                hotel.updating_rent = false
                SCMF('Продлили аренду на: ' .. settings.hours .. ' часов.Перезаходим...')
                reconnect()
            end)
            return false
        end
    end
end

function getDistanceBetweenCoords3d(point1, point2)
    return math.sqrt((point2.x - point1.x) ^ 2 + (point2.y - point1.y) ^ 2 + (point2.z - point1.z) ^ 2)
end

function sendKey(id)
    key = id
    updateSync()
end

function sampev.onSendPlayerSync(data)
    if key then
        data.keysData = key
        key = nil
    end

    if tp then return false end
end

local wasInside = true
function sampev.onSetInterior(interior)
    if interior == 0 and wasInside and settings.modes.buying_hotel == false then
        SCMF('Бот на улице, ищем отель...')
        newTask(function()
            wait(500)
            sendInput('/gps')
        end)

        wasInside = false
    elseif interior ~= 0 then
        wasInside = true
    end

    for k, v in ipairs({170, 171, 172, 173, 174, 175}) do
        if interior == v then
            outSpawn = true
            SCMF('Находимся в инте, надо бы выйти')
        end
    end

    if interior == 0 then outSpawn = false end
end

function sampev.onServerMessage(color, text)
    local messages = {
        ['>> {FF6347} Местом спавна автоматически назначен Отель%. Изменить место спавна {FFFFFF}>>{FF6347} /setspawn!'] = {
            mode = true,
            message = 'Отель куплен, перезаходим, увидимся в номере',
            reconnect = true
        },
        ['>> {FF6347} Местом спавна автоматически назначен Вокзал%. Изменить место спавна {FFFFFF}>>{FF6347} /setspawn!'] = {
            mode = false,
            message = 'Тебя выселили, пора заселяться опять!',
            reconnect = true
        }
    }

    for pattern, data in pairs(messages) do
        if text:find(pattern) then
            SCMF(data.message)
            settings.modes.buying_hotel = data.mode
            if data.reconnect then reconnect() end
        end
    end

    if text:find('^' .. getBotNick() .. '%[(%d+)%] скушал .+$') or text:find('^%[Ошибка%] {.-}Вы не голодны!$') then
        hotel.hungry = false
        coordStart(hotel.spawn_pos.x, hotel.spawn_pos.y, hotel.spawn_pos.z, 35, 2, false)
        SCMF('Покушали еду, возвращаеся обратно')
    end
end

function sampev.onDisplayGameText(style, time, text)
    if text:find('Full health') then
        coordStart(hotel.spawn_pos.x, hotel.spawn_pos.y, hotel.spawn_pos.z, 35, 2, false)
        hotel.lowhp = false
    end

    if text:find('You are hungry!') or text:find('You are very hungry!') then
        hotel.hungry = true
        SCMF('Пора покушать!')
    end
end

function getHealth()
    while true do
        Tasking.wait(0)
        local position = vector3d(getBotPosition())
        if getBotHealth() <= 10 and hotel.lowhp and settings.modes.buying_hotel then
            for id, pickup in pairs(getAllPickups()) do
                if not processedPickups[id] then
                    local distance = getDistanceBetweenCoords3d(position, pickup.position)
                    if pickup.model == 1240 and distance < 2 then
                        SCMF(string.format('Вы находитесь рядом с сердечком на расстоянии %.2f', distance))
                        sendPickedUpPickup(id)
                        sendKey(1024)
                        processedPickups[id] = true
                    elseif distance <= 30 then
                        SCMF(string.format('Курд на сердечко, расстояние %.2f', distance))
                        coordStart(pickup.position.x, pickup.position.y, pickup.position.z, 35, 2, false)
                        processedPickups[id] = 'teleported'
                    end
                end
            end
        end
    end
end

function findLarec()
    while true do
        Tasking.wait(0)
        local position = vector3d(getBotPosition())
        if hotel.lowhp == true and settings.modes.buying_hotel == true then
            for id, pickup in pairs(getAllPickups()) do
                if not processedPickups[id] then
                    local distance = getDistanceBetweenCoords3d(position, pickup.position)
                    if pickup.model == 19054 and distance < 2 then
                        SCMF(string.format('Вы находитесь рядом с подарком с ларцами на расстоянии %.2f', distance))
                        sendPickedUpPickup(id)
                        sendKey(1024)
                        processedPickups[id] = true
                    elseif distance >= 3 and distance <= 30 then
                        SCMF(string.format('Курд на подарок с ларцами, расстояние %.2f', distance))
                        coordStart(pickup.position.x, pickup.position.y, pickup.position.z, 35, 2, false)
                        processedPickups[id] = 'teleported'
                    end
                end
            end
        end
    end
end

function autoPaymentTask()
    local timer = os.time()
    local function processPickup(id, pickup, position)
        local distance = getDistanceBetweenCoords3d(position, pickup.position)
        if distance <= 2 then
            SCMF(string.format('Вы находитесь рядом с объектом ID %d на расстоянии %.2f', pickup.model, distance))
            sendPickedUpPickup(id)
            sendKey(1024)
            processedPickups[id] = true
        elseif distance >= 2 and distance <= 35 then
            local actions = {
                [19523] = 'Курд на выход',
                [19197] = 'Курд на лифт',
                [1239] = 'Курд на ресепшн'
            }

            local action = actions[pickup.model]
            if action then
                SCMF(string.format('%s, расстояние %.2f', action, distance))
                coordStart(pickup.position.x, pickup.position.y, pickup.position.z, 35, 2, false)
                processedPickups[id] = 'teleported'
            end
        end
    end

    while true do
        Tasking.wait(0)
        local position = vector3d(getBotPosition())
        if os.time() - timer > (60 * 60) * tonumber(settings.check_payment) then
            SCMF('Пора продлевать аренду...')
            hotel.updating_rent = true
            timer = os.time()
        end

        if hotel.updating_rent then
            for id, pickup in pairs(getAllPickups()) do
                if not processedPickups[id] then
                    local validModels = {19523, 19197, 1239}
                    if table_contain(validModels, pickup.model) then
                        for _, label in pairs(getAllLabels()) do
                            local labelConditions = {
                                [19523] = label.text:find('Выход из номера.+'),
                                [19197] = label.text:find('Лифт {.-}%(Этаж: Номера%)')
                            }
                            if settings.modes.buying_hotel and (labelConditions[pickup.model] or pickup.model == 1239) then
                                processPickup(id, pickup, position)
                                break
                            end
                        end
                    end
                elseif processedPickups[id] == 'teleported' then
                    local distance = getDistanceBetweenCoords3d(position, pickup.position)
                    if distance < 2 then
                        sendPickedUpPickup(id)
                        sendKey(1024)
                        processedPickups[id] = true
                    end
                end
            end
        end
    end
end

function table_contain(tbl, element)
    for _, value in pairs(tbl) do
        if value == element then
            return true
        end
    end
    return false
end

function checkInHotel()
    while true do
        Tasking.wait(0)
        local position = vector3d(getBotPosition())
        for id, pickup in pairs(getAllPickups()) do
            if settings.modes.buying_hotel == false and hotel.updating_rent == false then
                if not processedPickups[id] then
                    local distance = getDistanceBetweenCoords3d(position, pickup.position)
                    if pickup.model == 19132 and outSpawn == true then
                        for label_id, label in pairs(getAllLabels()) do
                            if label.text:find('Выход на улицу.+') and distance < 2 then
                                sendPickedUpPickup(id)
                                sendKey(1024)
                                processedPickups[id] = true
                            elseif distance >= 5 and distance <= 25 then
                                SCMF(string.format('Курд на выход, расстояние %.2f', distance))
                                coordStart(pickup.position.x, pickup.position.y, pickup.position.z, 35, 2, false)
                                processedPickups[id] = 'teleported'
                            end
                        end
                    elseif pickup.model == 19132 then
                        for label_id, label in pairs(getAllLabels()) do
                            if selected_hotel.name and label.text:find('Отель {.-}"" .. selected_hotel.name .. "') and distance <= 2 then
                                sendPickedUpPickup(id)
                                sendKey(1024)
                                processedPickups[id] = true
                            end
                        end
                    elseif pickup.model == 1239 then
                        for label_id, label in pairs(getAllLabels()) do
                            if label.text:find('Ресепшен для гостей') and distance < 2 then
                                SCMF(string.format('Вы находитесь рядом с объектом ID 1239 на расстоянии %.2f', distance))
                                sendPickedUpPickup(id)
                                sendKey(1024)
                                processedPickups[id] = true
                            elseif distance >= 3 and distance <= 25 then
                                SCMF(string.format('Курд на ресепшн, расстояние %.2f', distance))
                                coordStart(pickup.position.x, pickup.position.y, pickup.position.z, 35, 2, false)
                                processedPickups[id] = 'teleported'
                            end
                        end
                    end
                elseif processedPickups[id] == 'teleported' then
                    local distance = getDistanceBetweenCoords3d(position, pickup.position)
                    if distance < 2 then
                        sendPickedUpPickup(id)
                        sendKey(1024)
                        processedPickups[id] = true
                    end
                end
            end
        end
    end
end

function autoEat()
    while true do
        Tasking.wait(0)
        local position = vector3d(getBotPosition())
        for id, pickup in pairs(getAllPickups()) do
            local distance = getDistanceBetweenCoords3d(position, pickup.position)
            if hotel.hungry == true and not processedPickups[id] then
                if pickup.model == 19824 or pickup.model == 1517 and distance < 2 then
                    SCMF(string.format('Вы находитесь рядом с рестораном на расстоянии %.2f', distance))
                    sendPickedUpPickup(id)
                    sendKey(1024)
                    processedPickups[id] = true
                elseif distance >= 5 and distance <= 25 then
                    SCMF(string.format('Курд на ресторан, расстояние %.2f', distance))
                    coordStart(pickup.position.x, pickup.position.y, pickup.position.z, 35, 2, false)
                    processedPickups[id] = 'teleported'
                end
            end
        end
    end
end

function getHeadingFromVector2d(x, y)
    local angle = math.deg(math.atan2(y, x))
    if angle < 0 then angle = angle + 360 end
    angle = angle - 90
    if angle < 0 then angle = angle + 360 end
    return angle
end

function getDistanceBetweenCoords2d(x1, y1, x2, y2)
    return math.sqrt(((x2 - x1) ^ 2) + ((y2 - y1) ^ 2))
end

function sampev.onSendVehicleSync(data)
    if tp then return false end
end

function math.calculate(MinInt, MaxInt, MinFloat, MaxFloat, CurrentFloat)
    local res = CurrentFloat - MinFloat
    local res2 = MaxFloat - MinFloat
    local res3 = res / res2
    local res4 = res3 * (MaxInt - MinInt)
    return res4 + MinInt
end

function teleportToCoords(targetX, targetY, targetZ, bool)
    newTask(function()
        if tp then
            SCMF('Ошибка. Уже телепортируемся.')
            return
        end

        local bx, by, bz = targetX, targetY, targetZ
        if bx == 0 and by == 0 and bz == 0 then
            SCMF('Ошибка. Координаты не установлены.')
            return
        end

        if bool then
            tp = true
            local x, y, z = getBotPosition()
            local nx, ny, nz = x, y, z
            local dist = getDistanceBetweenCoords2d(x, y, bx, by)
            local angle = -math.rad(getHeadingFromVector2d(bx - x, by - y))
            print(tostring(angle))
            local data = samp_create_sync_data('player')
            if dist > tp_dist then
                for ds = dist - tp_dist, 0, -tp_dist do
                    data.moveSpeed = {0, 0, -0.7}
                    for i = nz, -135, -25 do
                        data.position = {nx, ny, i}
                        data.send()
                        wait(200)
                    end

                    data.moveSpeed = {0, 0, 0}
                    nx, ny, nz = nx + math.sin(angle) * tp_dist, ny + math.cos(angle) * tp_dist, -60
                    data.position = {nx, ny, nz}
                    data.send()
                    percent = math.calculate(0, 100, dist, 0, ds)
                    SCMF('Teleporting: [' .. ('%0.1f'):format(percent) .. ']')
                    wait(waiting)
                end
            end

            data.moveSpeed = {0, 0, -0.7}
            for i = nz, -135, -25 do
                data.position = {nx, ny, i}
                data.send()
                wait(50)
            end

            data.position = {bx, by, bz}
            data.send()
            setBotPosition(bx, by, bz)
            SCMF('Успех. Телепортировались на указанные координаты.')
            tp = false
        end
    end)
end

function samp_create_sync_data(sync_type)
    local raknet = require'samp.raknet'
    require'samp.synchronization'
    local sync_traits = {
        player = {'PlayerSyncData', raknet.PACKET.PLAYER_SYNC},
        vehicle = {'VehicleSyncData', raknet.PACKET.VEHICLE_SYNC},
        passenger = {'PassengerSyncData', raknet.PACKET.PASSENGER_SYNC},
        aim = {'AimSyncData', raknet.PACKET.AIM_SYNC},
        trailer = {'TrailerSyncData', raknet.PACKET.TRAILER_SYNC},
        unoccupied = {'UnoccupiedSyncData', raknet.PACKET.UNOCCUPIED_SYNC},
        bullet = {'BulletSyncData', raknet.PACKET.BULLET_SYNC},
        spectator = {'SpectatorSyncData', raknet.PACKET.SPECTATOR_SYNC}
    }

    local sync_info = sync_traits[sync_type]
    local data_type = 'struct ' .. sync_info[1]
    local data = ffi.new(data_type, {})
    local raw_data_ptr = tonumber(ffi.cast('uintptr_t', ffi.new(data_type .. '*', data)))
    local func_send = function()
        local bs = bitStream.new()
        bs:writeUInt8(sync_info[2])
        bs:writeBuffer(raw_data_ptr, ffi.sizeof(data))
        bs:sendPacketEx(HIGH_PRIORITY, UNRELIABLE_SEQUENCED, 1)
        bs:reset()
    end

    local mt = {
        __index = function(t, index) return data[index] end,
        __newindex = function(t, index, value) data[index] = value end
    }
    return setmetatable({
        send = func_send
    }, mt)
end

function SCMF(...)
    return print(string.format('[Auto-Hotel]: %s', string.format(...)))
end
```