local isActive = true

local memory = require ‘memory’
require “socket”

local Arial_8px = renderCreateFont(‘Arial’, 6.5, 0)
local Arial_20px = renderCreateFont(‘Arial’, 16.25, 0)
local Arial_10px = renderCreateFont(‘Arial’, 8.125)

– Константы
local SPEED_END = 160 – максимальная скорость, отображаемая на спидометре
local SPEED_WIDTH = 160 – ширина полосы скорости

local POS_X = 1200 – позиция спидометра по X
local POS_Y = 730 – позиция спидометра по Y

local MAIN_TICK_WIDTH = 20 –
local SECONDARY_TICK_WIDTH = 10 –

local BORDER_WIDTH = 1.1 –

local SPEEDOMETER_WIDTH = 200 –
local SPEEDOMETER_HEIGHT = 70 –

local SPEED_BAR_HEIGHT = 25 –
local SPEED_BAR_OFFSET_X = 20 –
local SPEED_BAR_OFFSET_Y = 10
–
local SPEED_TEXT_OFFSET_Y = 48 –

local CURRENT_SPEED_OFFSET_Y = 10 + SPEED_BAR_HEIGHT / 2 –

local LABEL_OFFSET_Y = 62 –
local MAIN_TICK_START_X = 20 –
local MAIN_TICK_END_X = 180 –
local MAIN_TICK_START_Y = 35 –
local MAIN_TICK_END_Y = 40 –
local SECONDARY_TICK_START_X = 30 –
local SECONDARY_TICK_END_X = 180 –
local SECONDARY_TICK_START_Y = 35 –
local SECONDARY_TICK_END_Y = 38 –



function main()
repeat wait(0) until isSampAvailable()

sampRegisterChatCommand(“z”, function(arg)
isActive = not isActive
end)

while true do wait(0)

if isCharInAnyCar(playerPed) then

local car = storeCarCharIsInNoSave(playerPed)
local speedUnits = math.floor(getCarSpeed(car) * 2)
local speedStart = speedUnits > SPEED_END and SPEED_END * math.floor(speedUnits / SPEED_END) or 0

– Отрисовка фона спидометра
renderDrawBox(POS_X, POS_Y, SPEEDOMETER_WIDTH, SPEEDOMETER_HEIGHT, 0xd9FFFFFF)

– Отрисовка полосы скорости
renderDrawBox(POS_X + SPEED_BAR_OFFSET_X, POS_Y + SPEED_BAR_OFFSET_Y, math.min((SPEED_WIDTH / SPEED_END) * (speedUnits - speedStart), SPEED_WIDTH), SPEED_BAR_HEIGHT, 0x800000ff)

– Отрисовка основных делений
for x = MAIN_TICK_START_X, MAIN_TICK_END_X, MAIN_TICK_WIDTH do
renderDrawLine(POS_X + x, POS_Y + MAIN_TICK_START_Y, POS_X + x, POS_Y + MAIN_TICK_END_Y, 1, 0xff000000)
end

– Отрисовка промежуточных делений
for x = SECONDARY_TICK_START_X, SECONDARY_TICK_END_X, MAIN_TICK_WIDTH do
renderDrawLine(POS_X + x, POS_Y + SECONDARY_TICK_START_Y, POS_X + x, POS_Y + SECONDARY_TICK_END_Y, 1, 0xff000000)
end

– Отрисовка чисел скорости
for speed = 0, SPEED_END, MAIN_TICK_WIDTH do
local length = renderGetFontDrawTextLength(Arial_8px, tostring(speed))
local height = renderGetFontDrawHeight(Arial_8px)
renderFontDrawText(Arial_8px, tostring(speed), POS_X + speed + SPEED_BAR_OFFSET_X - (length / 2), POS_Y + SPEED_TEXT_OFFSET_Y - (height / 2), 0xff000000)
end

– Отрисовка текущей скорости
local length2 = renderGetFontDrawTextLength(Arial_20px, tostring(speedUnits))
local height2 = renderGetFontDrawHeight(Arial_20px)
renderFontDrawText(Arial_20px, tostring(speedUnits), POS_X + SPEEDOMETER_WIDTH / 2 - (length2 / 2), POS_Y + CURRENT_SPEED_OFFSET_Y - (height2 / 2), 0xff000000)

– Отрисовка надписи “Speed(MPH)”
local length3 = renderGetFontDrawTextLength(Arial_10px, ‘Speed(MPH)’)
local height3 = renderGetFontDrawHeight(Arial_10px)
renderFontDrawText(Arial_10px, ‘Speed(MPH)’, POS_X + SPEEDOMETER_WIDTH / 2 - (length3 / 2), POS_Y + LABEL_OFFSET_Y - (height3 / 2), 0xff000000)



– Отрисовка границ спидометра
renderDrawLine(POS_X + SPEED_BAR_OFFSET_X, POS_Y + SPEED_BAR_OFFSET_Y, POS_X + SPEED_BAR_OFFSET_X + SPEED_WIDTH, POS_Y + SPEED_BAR_OFFSET_Y, BORDER_WIDTH, 0xff000000)
renderDrawLine(POS_X + SPEED_BAR_OFFSET_X, POS_Y + SPEED_BAR_OFFSET_Y + SPEED_BAR_HEIGHT, POS_X + SPEED_BAR_OFFSET_X + SPEED_WIDTH, POS_Y + SPEED_BAR_OFFSET_Y + SPEED_BAR_HEIGHT, BORDER_WIDTH, 0xff000000)
renderDrawLine(POS_X + SPEED_BAR_OFFSET_X, POS_Y + SPEED_BAR_OFFSET_Y, POS_X + SPEED_BAR_OFFSET_X, POS_Y + SPEED_BAR_OFFSET_Y + SPEED_BAR_HEIGHT, BORDER_WIDTH, 0xff000000)
renderDrawLine(POS_X + SPEED_BAR_OFFSET_X + SPEED_WIDTH, POS_Y + SPEED_BAR_OFFSET_Y, POS_X + SPEED_BAR_OFFSET_X + SPEED_WIDTH, POS_Y + SPEED_BAR_OFFSET_Y + SPEED_BAR_HEIGHT, BORDER_WIDTH, 0xff000000)
end
end
end

function getHandlingFromCarHandle(carHandle, offset)
CCar = getCarPointer(carHandle) – указатель на структуру автомобиля
CHandling = readMemory(CCar + 0x384, 4, false) – указатель на структуру хендлинга автомобиля
res = memory.getfloat(CHandling + offset, false)
return (res/0.02)*2
end

function getVehicleRPM(vehicle)
local vehicleRPM = 0
if (vehicle) then
if (isCarEngineOn(vehicle) == true) then
if getCarCurrentGear(vehicle) > 0 then
vehicleRPM = math.floor(((getCarSpeed(vehicle) / getCarCurrentGear(vehicle)) * 160) + 0.5)
else
vehicleRPM = math.floor((getCarSpeed(vehicle) * 160) + 0.5)
end
if (vehicleRPM < 650) then
vehicleRPM = math.random(650, 750) – Когда машина стоит, обороты будут колебаться от 650 до 750, их можно менять
elseif (vehicleRPM >= 9000) then
vehicleRPM = math.random(9000, 9900) – Максимальное количество оборотов
end
else
vehicleRPM = 0
end

return tonumber(vehicleRPM)
else
return 0
end
end

function roundToTenths(num)
return math.floor(num * 10 + 0.5) / 10
end

окончательно убери из этого кода ‘магические числа’, измени использование переменных - а т.е. сделай названия более понятными, сгруппируй по таблицам