отрефактори и почини(он не работает вообще) 


script_name('mouseFlight')
script_author('(^^)')
script_description('i like war thunder.')

local maf 		= require 'maf'
local socket 	= require "socket"

local lastUpdateTime = socket.gettime()


--- Main
function main()
	if not isSampLoaded() or not isCleoLoaded() or not isSampfuncsLoaded() then return end
	while not isSampAvailable() do wait(100) end
	sampRegisterChatCommand("maf", initialize)
	while true do wait(0)
		update()
	end
end

-- script variables
local aircraft 				= nil
local mouseAim 				= nil
local cameraRig 			= nil
local cam 					= nil

local useFixed 				= true      -- Follow aircraft using fixed update loop
local camSmoothSpeed 		= 5         -- How quickly the camera tracks the mouse aim point
local mouseSensitivity 		= 3         -- Mouse sensitivity for the mouse flight target
local aimDistance 			= 500		-- How far the boresight and mouse flight are from the aircraft
local showDebugInfo 		= false		-- How far the boresight and mouse flight are from the aircraft

local horisontal_inversion	= false
local vertical_inversion	= false

local frozenDirection 		= maf.vector(0, 1, 0)
local isMouseAimFrozen 		= false

local cameraDistance		= 5
local cameraOffset			= maf.vector(0, 0, 2)

function getBoresightPos()
	return getPlanePosition() + (getPlaneRotation() * maf.vector(0, aimDistance, 0))
end

function getMouseAimPos()
	if isMouseAimFrozen then
        return getPlanePosition() + (frozenDirection * aimDistance)
    else
        return getPlanePosition() + (mouseAim * aimDistance)
    end
end

function update()
	deltaTime = socket.gettime() - lastUpdateTime
	if isActive then
		updateCameraPos()                
		rotateRig()
		if showDebugInfo then DrawGizmos() end
	end
	lastUpdateTime = socket.gettime()
end

function rotateRig()
    if not mouseAim or not cam or not cameraRig then return end
    
    isMouseAimFrozen = isKeyDown(67)
	if isMouseAimFrozen then frozenDirection:set(mouseAim * maf.vector(0, 1, 0)) end
	
	local screenW, screenH 	= getScreenResolution()
	local mouseX, mouseY	= getPcMouseMovement()
	local halfW 			= screenW / 2
	local halfH 			= screenH / 2
	
	local mouseX = (mouseX)/halfW * mouseSensitivity * (( horisontal_inversion 	and -1) or 1)
	local mouseY = (mouseY)/halfH * mouseSensitivity * (( vertical_inversion 	and -1) or 1)

    mouseAim:rotate(maf.quat():setAngleAxis(mouseX, cameraRig * maf.vector(1, 0, 0))) -- !!! cam ->> cameraRig !!!
    mouseAim:rotate(maf.quat():setAngleAxis(mouseY, cameraRig * maf.vector(0, 0, 1))) -- !!! cam ->> cameraRig !!!

    local upVec = math.abs((mouseAim * maf.vector(0, 1, 0)).y) > 0.9 and (cameraRig * maf.vector(0, 0, 1)) or maf.vector(0, 0, 1)


	cameraRig:setRotation(damp(cameraRig,
						  lookRotation((mouseAim * maf.vector(0, 1, 0)), upVec),
						  camSmoothSpeed,
						  deltaTime))
end

function updateCameraPos()
	local cameraPos = (cameraRig * maf.vector(0, cameraDistance*-1, 0)) -- cam position vec3 w/o offset
	local cameraVec = -cameraPos										-- inverted to look from cam to plane 
	cameraPos = cameraPos + cameraOffset
	cam = maf.quat():fromDirection(cameraVec)
	
	local camX, camY, camZ = cameraPos:unpack()
	local rotX, rotY, rotZ = quaternionToEuler(cameraRig:unpack())
	attachCameraToVehicle(storeCarCharIsInNoSave(playerPed), camX, camY, camZ, rotX, rotY, rotZ, 0, 1)
end

local function damp(a, b, lambda, dt)
    return a:slerp(b, 1 - math.exp(-lambda * dt))
end


local function DrawGizmos()
    if showDebugInfo then
        -- Store old color
        local oldColorR, oldColorG, oldColorB, oldColorA = getDrawColor()

        -- Draw Boresight Position
        setDrawColor(255, 255, 255, 255)
        local boresightPos = GetBoresightPos()
        drawCircle(boresightPos.x, boresightPos.y, 10)

        -- Draw Mouse Aim Position
        setDrawColor(255, 0, 0, 255)
        local mouseAimPos = GetMouseAimPos()
        drawCircle(mouseAimPos.x, mouseAimPos.y, 10)

        -- Draw Axes for Mouse Aim Transform
        local aimPos = mouseAim:position()
        setDrawColor(0, 0, 255, 255)
        drawLine(aimPos, aimPos + mouseAim:forward() * 50)
        setDrawColor(0, 255, 0, 255)
        drawLine(aimPos, aimPos + mouseAim:up() * 50)
        setDrawColor(255, 0, 0, 255)
        drawLine(aimPos, aimPos + mouseAim:right() * 50)

        -- Restore old color
        setDrawColor(oldColorR, oldColorG, oldColorB, oldColorA)
    end
end




-- Initialization function
function initialize()
	if not isActive then 
		if isCharInAnyPlane(playerPed) then
			local planeHandle	= storeCarCharIsInNoSave(playerPed) 
			local x, y, z, w 	= getVehicleQuaternion(planeHandle)
			local planeQuat 	= maf.quat(x, y, z, w)
			mouseAim 			= planeQuat 
			cameraRig 			= planeQuat
			lastUpdateTime		= socket.gettime()
			
			isActive = true
		else 
			sampAddChatMessage("в самолет сядь", -1)
		end
	else 
		isActive = false
	end
end


function lookRotation(forward, upwards)

    forward = forward:normalize()
    local right = upwards:cross(forward):normalize()
    local correctedUpwards = forward:cross(right)

    local rotationMatrix = {
        {right.x, correctedUpwards.x, forward.x},
        {right.y, correctedUpwards.y, forward.y},
        {right.z, correctedUpwards.z, forward.z}
    }

    local qw = math.sqrt(1 + rotationMatrix[1][1] + rotationMatrix[2][2] + rotationMatrix[3][3]) / 2
    local w4 = (4 * qw)
    local qx = (rotationMatrix[3][2] - rotationMatrix[2][3]) / w4 
    local qy = (rotationMatrix[1][3] - rotationMatrix[3][1]) / w4 
    local qz = (rotationMatrix[2][1] - rotationMatrix[1][2]) / w4 

    return maf.quat(qx, qy, qz, qw)
end

function quaternionToEuler(qx, qy, qz, qw)
    -- Roll (x-axis rotation)
    local sinr_cosp = 2 * (qw * qx + qy * qz)
    local cosr_cosp = 1 - 2 * (qx * qx + qy * qy)
    local roll = math.atan2(sinr_cosp, cosr_cosp)

    -- Pitch (y-axis rotation)
    local sinp = 2 * (qw * qy - qz * qx)
    local pitch
    if math.abs(sinp) >= 1 then
        pitch = math.pi / 2 * (sinp / math.abs(sinp)) -- use 90 degrees if out of range
    else
        pitch = math.asin(sinp)
    end

    -- Yaw (z-axis rotation)
    local siny_cosp = 2 * (qw * qz + qx * qy)
    local cosy_cosp = 1 - 2 * (qy * qy + qz * qz)
    local yaw = math.atan2(siny_cosp, cosy_cosp)

    return roll, pitch, yaw
end

function getPlanePosition() 
	local planeHandle	= storeCarCharIsInNoSave(playerPed) 
	local x, y, z 		= getCarCoordinates(planeHandle)
	
	return maf.vector(x, y, z)
end

function getPlaneRotation()
	local planeHandle	= storeCarCharIsInNoSave(playerPed) 
	local x, y, z, w 	= getVehicleQuaternion(planeHandle)
	local planeQuat 	= maf.quat(x, y, z, w)
	
	return planeQuat
end

---