-- Глобальная переменная для масштабирования
local scale = 0.75


function vehHaveGun()
	for _, v in ipairs({425, 447, 464, 476, 520}) do
		if isCharInModel(playerPed, v) then 
			return true 
		end
	end
	return false
end

function getRhinoCannonCorner(carHandle)
	local memory = require 'memory'
	local ptr = getCarPointer(carHandle)
	local x = memory.getfloat(ptr + 0x94C, false) * 180.0 / math.pi
	local y = memory.getfloat(ptr + 0x950, false) * 180.0 / math.pi
	return x, y
end

function renderCrosshair(x, y)
    -- Центрированное компактное центральное кольцо
    local ringRadius = 8 * scale
    local ringThickness = 0.95 * scale
    dxDrawRing(x, y, ringRadius, ringThickness, 0, 1, 0x10FFFFFF, false, 1)

    -- Толщина линии для корректировки центрального выравнивания
    local lineThickness = 1 * scale
    
    -- Длина линий от центра
    local lineLength = 10 * scale
    local gapLength = 3 * scale

    -- Корректировка вертикальных линий
    renderDrawLine(x + lineThickness / 2, y - lineLength, x + lineThickness / 2, y - gapLength, lineThickness, 0xFFFFFFFF) -- Верхняя линия
    renderDrawLine(x + lineThickness / 2, y + gapLength, x + lineThickness / 2, y + lineLength, lineThickness, 0xFFFFFFFF) -- Нижняя линия

    -- Корректировка горизонтальных линий
    renderDrawLine(x - lineLength, y - lineThickness / 2, x - gapLength, y - lineThickness / 2, lineThickness, 0xFFFFFFFF) -- Левая линия
    renderDrawLine(x + gapLength, y - lineThickness / 2, x + lineLength, y - lineThickness / 2, lineThickness, 0xFFFFFFFF) -- Правая линия
end

function dxDrawRing(posX, posY, radius, width, startAngle, amount, color, absoluteAmount, anglesPerLine)
    -- Проверка входных данных на правильность типов
    if type(posX) ~= "number" or type(posY) ~= "number" or type(startAngle) ~= "number" or type(amount) ~= "number" then
        print("Error: One of the required parameters (posX, posY, startAngle, amount) is not a number.")
        return false
    end

    -- Установка значений по умолчанию для параметров
    radius = type(radius) == "number" and radius or 50
    width = type(width) == "number" and width or 5
    color = color or 0xFFFFFFFF
    absoluteAmount = type(absoluteAmount) == "boolean" and absoluteAmount or false
    anglesPerLine = type(anglesPerLine) == "number" and anglesPerLine or 1

    -- Вычисление конечного угла
    local stopAngle = absoluteAmount and (amount + startAngle) or ((amount * 360) + startAngle)

    -- Отрисовка кольца путем создания линий
    for angle = startAngle, stopAngle, anglesPerLine do
        local radAngle = math.rad(angle)
        local startX = math.cos(radAngle) * (radius - width)
        local startY = math.sin(radAngle) * (radius - width)
        local endX = math.cos(radAngle) * (radius + width)
        local endY = math.sin(radAngle) * (radius + width)

        -- Отрисовка линии с использованием скорректированных координат
        renderDrawLine(startX + posX, startY + posY, endX + posX, endY + posY, width, color)
    end

    -- Возвращаем количество линий, которое было нарисовано
    return math.floor((stopAngle - startAngle) / anglesPerLine)
end







local ffi = require 'ffi'
--HOOKS
local hook = {hooks = {}}
addEventHandler('onScriptTerminate', function(scr)
    if scr == script.this then
        for i, hook in ipairs(hook.hooks) do
            if hook.status then
                hook.stop()
            end
        end
    end
end)
ffi.cdef [[
    int VirtualProtect(void* lpAddress, unsigned long dwSize, unsigned long flNewProtect, unsigned long* lpflOldProtect);
]]
function hook.new(cast, callback, hook_addr, size)
    jit.off(callback, true) --off jit compilation
    local size = size or 5
    local new_hook = {}
    local detour_addr = tonumber(ffi.cast('intptr_t', ffi.cast('void*', ffi.cast(cast, callback))))
    local void_addr = ffi.cast('void*', hook_addr)
    local old_prot = ffi.new('unsigned long[1]')
    local org_bytes = ffi.new('uint8_t[?]', size)
    ffi.copy(org_bytes, void_addr, size)
    local hook_bytes = ffi.new('uint8_t[?]', size, 0x90)
    hook_bytes[0] = 0xE9
    ffi.cast('uint32_t*', hook_bytes + 1)[0] = detour_addr - hook_addr - 5
    new_hook.call = ffi.cast(cast, hook_addr)
    new_hook.status = false
    local function set_status(bool)
        new_hook.status = bool
        ffi.C.VirtualProtect(void_addr, size, 0x40, old_prot)
        ffi.copy(void_addr, bool and hook_bytes or org_bytes, size)
        ffi.C.VirtualProtect(void_addr, size, old_prot[0], old_prot)
    end
    new_hook.stop = function() set_status(false) end
    new_hook.start = function() set_status(true) end
    new_hook.start()
    table.insert(hook.hooks, new_hook)
    return setmetatable(new_hook, {
        __call = function(self, ...)
            self.stop()
            local res = self.call(...)
            self.start()
            return res
        end
    })
end
--HOOKS

function main()
    -- Предположительный адрес функции
    local preRenderAddr = 0x6D0E60
    -- Установим хук
    vehiclePreRenderHook = hook.new('void(__thiscall *)(void*)', preRenderHook, preRenderAddr)
end

function preRenderHook(this)

	if isCharInAnyCar(playerPed) then
		local car = storeCarCharIsInNoSave(playerPed)
		local cX, cY, cZ = getCarCoordinates(car)
		if vehHaveGun() then
			fX, fY, fZ = getOffsetFromCarInWorldCoords(car, 0, 128, 0)
			local result, tPoint = processLineOfSight(cX, cY, cZ, fX, fY, fZ, true, false, true, true, false, false, false, true)
			if result then fX, fY, fZ = tPoint.pos[1], tPoint.pos[2], tPoint.pos[3] end
			local _, gx, gy, z, _, _ = convert3DCoordsToScreenEx(fX, fY, fZ)
			if z > 1 then renderCrosshair(gx, gy) end
		elseif isCharInModel(playerPed, 432) then
			local oX, oY, oZ = getOffsetFromCarInWorldCoords(car, 0, 0, 1.1)
			if not rail then rail = createObject(1551, oX, oY, oZ) end
			if rail then
				local x, y = getRhinoCannonCorner(car)
				attachObjectToCar(rail, car, 0.0, 0.0, 1.1, y, 0.0, x)
				local x1, y1, z1 = getOffsetFromObjectInWorldCoords(rail, 0.0, 6.5, 0.0)
				local x2, y2, z2 = getOffsetFromObjectInWorldCoords(rail, 0.0, 67.0, .0)
				local result, tPoint = processLineOfSight(x1, y1, z1, x2, y2, z2, true, false, true, true, false, false, false, true)
				if result then x2, y2, z2 = tPoint.pos[1], tPoint.pos[2], tPoint.pos[3] end
				local _, gx, gy, z, _, _ = convert3DCoordsToScreenEx(x2, y2, z2)
				if z > 1 then renderCrosshair(gx, gy) end
			end
		end
	else
		if rail then deleteObject(rail); rail = nil end
	end

    vehiclePreRenderHook(this) -- Вызовем оригинальную функцию после выполнения нашего кода
end

сделай изменение размера в зависимости от дальности точки