script_name("CamHack")
script_author("sanek a.k.a Maks_Fender, edited by ANIKI")
require "lib.moonloader"
local mad = require "MoonAdditions"

-- GLOBAL VARIABLES AND CONSTANTS
local camHack_posX, camHack_posY, camHack_posZ = 0, 0, 0 -- Camera’s positional coordinates
local camHack_angZ, camHack_angY = 0, 0 -- Camera’s orientation angles (Z for horizontal rotation, Y for vertical)
local camHack_speed = 1.0 -- Speed at which the camera moves
local camHack_flyModeActive = 0 -- Fly mode status: 0 = inactive, 1 = active
local camHack_collisionEnabled = true -- Toggle for collision checking

-- Collision settings
local camHack_checkSolidObjects = true
local camHack_checkVehicles = false
local camHack_checkPeds = false
local camHack_checkObjects = true
local camHack_checkParticles = false
local camHack_seeThroughObjects = false
local camHack_ignoreSomeObjects = false
local camHack_allowShootThrough = false

-- Function to check camera collision and adjust position if necessary
local function isCameraColliding(destX, destY, destZ)
    if not camHack_collisionEnabled then
        return false, nil, destX, destY, destZ
    end

    local result, colPoint = processLineOfSight(
        camHack_posX, camHack_posY, camHack_posZ,
        destX, destY, destZ,
        camHack_checkSolidObjects, camHack_checkVehicles, camHack_checkPeds,
        camHack_checkObjects, camHack_checkParticles, camHack_seeThroughObjects,
        camHack_ignoreSomeObjects, camHack_allowShootThrough
    )
    if result then
        -- If collision is detected, reset position to the current camera position
        return true, colPoint, camHack_posX, camHack_posY, camHack_posZ
    end
    return false, colPoint, destX, destY, destZ
end

-- Main loop, runs continuously while the script is active
function main()
    while true do
        wait(0)

        -- Check if Fly Mode is inactive
        if camHack_flyModeActive == 0 then
            -- Check for the key combination to activate Fly Mode (C + 1)
            if isKeyDown(VK_C) and isKeyDown(VK_1) then
                -- Enter Fly Mode: Disable radar and HUD, set initial camera position and angle
                displayRadar(false)
                displayHud(false)
                camHack_posX, camHack_posY, camHack_posZ = getCharCoordinates(playerPed)
                camHack_angZ = -getCharHeading(playerPed) -- Invert to match the player heading
                camHack_angY = 0.0
                setFixedCameraPosition(camHack_posX, camHack_posY, camHack_posZ, 0.0, 0.0, 0.0) -- Set initial camera position
                lockPlayerControl(true) -- Prevent player control while in Fly Mode
                camHack_flyModeActive = 1 -- Fly Mode is now active
            end
        else
            -- Handle Fly Mode if active
            if not sampIsChatInputActive() and not isSampfuncsConsoleActive() then
                -- Update camera orientation based on mouse movement
                local offMouX, offMouY = getPcMouseMovement()
                camHack_angZ = (camHack_angZ + offMouX / 4.0) % 360 -- Horizontal angle
                camHack_angY = math.max(math.min(camHack_angY + offMouY / 4.0, 89.0), -89.0) -- Vertical angle within bounds

                -- Calculate the movement vector based on the camera’s orientation
                local radZ, radY = math.rad(camHack_angZ), math.rad(camHack_angY)
                local sinZ, cosZ, sinY, cosY = math.sin(radZ), math.cos(radZ), math.sin(radY), math.cos(radY)
                local movX, movY, movZ = cosY * sinZ, cosY * cosZ, sinY

                local newX, newY, newZ = camHack_posX, camHack_posY, camHack_posZ

                -- Calculate direction vectors for movement
                local forwardX, forwardY, forwardZ = movX, movY, movZ
                local rightX, rightY = math.cos(radZ + math.pi / 2), math.sin(radZ + math.pi / 2)

                -- Determine movement direction based on key inputs
                local moveForward, moveSideways, moveUpDown = 0, 0, 0
                if isKeyDown(VK_W) then
                    moveForward = camHack_speed
                elseif isKeyDown(VK_S) then
                    moveForward = -camHack_speed
                end
                if isKeyDown(VK_A) then
                    moveSideways = -camHack_speed
                elseif isKeyDown(VK_D) then
                    moveSideways = camHack_speed
                end
                if isKeyDown(VK_SPACE) then
                    moveUpDown = camHack_speed
                elseif isKeyDown(VK_SHIFT) then
                    moveUpDown = -camHack_speed
                end

                -- Compute the resultant vector
                newX = camHack_posX + (forwardX * moveForward + rightX * moveSideways)
                newY = camHack_posY + (forwardY * moveForward + rightY * moveSideways)
                newZ = camHack_posZ + (forwardZ * moveForward) + moveUpDown

                -- Check for collisions and adjust camera position
                local collision, colPoint, adjX, adjY, adjZ = isCameraColliding(newX, newY, newZ)
                camHack_posX, camHack_posY, camHack_posZ = adjX, adjY, adjZ

                -- Update camera position and point it in the direction of movement
                setFixedCameraPosition(camHack_posX, camHack_posY, camHack_posZ, 0.0, 0.0, 0.0)
                pointCameraAtPoint(camHack_posX + movX, camHack_posY + movY, camHack_posZ + movZ, 2)

                -- Adjust camera speed (Plus/Minus keys)
                if isKeyDown(187) then -- Increase speed with the ‘Plus’ key
                    camHack_speed = camHack_speed + 0.01
                elseif isKeyDown(189) then -- Decrease speed with the ‘Minus’ key
                    camHack_speed = math.max(camHack_speed - 0.01, 0.01) -- Prevent speed from becoming negative or zero
                end

                -- Debug info
                local collisionText = collision and string.format(
                    "~ghhh~Collision Detected~n~" ..
                    "~w~Entity: ~ph~%d~n~" ..
                    "~w~Type: ~ph~%d~ph~ ~w~Surface: ~ph~%d~n~" ..
                    "~w~Position: ~ph~(%.2f, %.2f, %.2f)~n~" ..
                    "~w~Normal: ~ph~(%.2f, %.2f, %.2f)",
                    colPoint.entity, colPoint.entityType, colPoint.surfaceType[1],
                    colPoint.pos[1], colPoint.pos[2], colPoint.pos[3],
                    colPoint.normal[1], colPoint.normal[2], colPoint.normal[3]
                ) or "~rhhh~No Collision"

                -- Formatting CamHack Debug Info
                local text = string.format(
                    "~bhhh~CamHack Debug Info~n~" ..
                    "~w~Position:~n~" ..
                    " ~ph~(%.2f, %.2f, %.2f)~n~" ..
                    "~w~Direction:~n~" .. 
                    " ~ph~(%.2f, %.2f, %.2f)~n~" ..
                    "~w~Angle:~n~" ..
                    " ~ph~Z: %.2f| ~ph~Y: %.2f|~n~" ..
                    "~w~Speed:~n~" ..
                    " ~ph~%.2f units/sec~n~" ..
                    "~w~Collision Status:~n~" ..
                    " %s",
                    camHack_posX, camHack_posY, camHack_posZ,
                    camHack_posX + movX, camHack_posY + movY, camHack_posZ + movZ,
                    camHack_angZ, camHack_angY,
                    camHack_speed,
                    collisionText
                )

                mad.draw_text(text, 45, 240, mad.font_style.BEFORE_TEXT, 0.40, 1.0, mad.font_align.LEFT, 9999, true, false, 255, 255, 255, 255, 1, 2, 0, 0, 0, 150)

                -- Check for Fly Mode deactivation (C + 2)
                if isKeyDown(VK_C) and isKeyDown(VK_2) then
                    -- Exit Fly Mode: Restore normal player control and camera behavior
                    lockPlayerControl(false)
                    restoreCameraJumpcut()
                    setCameraBehindPlayer()
                    camHack_flyModeActive = 0 -- Fly Mode is now inactive
                end
            end
        end
    end
end

-- Intercept player chat bubble events
local sampev = require "lib.samp.events"
-- Modify the chat bubble display duration while in Fly Mode
function sampev.onPlayerChatBubble(id, col, dist, dur, msg)
    if camHack_flyModeActive == 1 then return {id, col, 1488, dur, msg} end -- Extend bubble duration in Fly Mode
end

если тут есть повторяющиеся блоки кода - вынеси их в отдельные функции. но только если это сделает код проще и читабельнее и если функция будет использоваться больше 1 раза.