Guest User

Untitled

a guest
Nov 2nd, 2016
145
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 69.13 KB | None | 0 0
  1. local screenX, screenY = guiGetScreenSize()
  2.  
  3. local scaleFactor = screenX / 1280
  4.  
  5. local tuningMarkers = {}
  6. local tuningMarkersCount = 0
  7.  
  8. local markerImageMaxVisibleDistance = 20
  9.  
  10. local availableTextures = {
  11.     ["logo"] = dxCreateTexture("files/images/logo.png", "argb", true, "clamp"),
  12.     ["hoveredrow"] = dxCreateTexture("files/images/hoveredrow.png", "argb", true, "clamp"),
  13.     ["menunav"] = dxCreateTexture("files/images/menunav.png", "argb", true, "clamp"),
  14.     ["mouse"] = dxCreateTexture("files/images/navbar/mouse.png", "argb", true, "clamp"),
  15. }
  16.  
  17. local availableIcons = {
  18.     ["wrench"] = "",
  19.     ["long-arrow-up"] = "",
  20.     ["long-arrow-down"] = "",
  21.     ["info-circle"] = "",
  22.     ["check"] = "",
  23.     ["exclamation-triangle"] = "",
  24. }
  25.  
  26. local mouseTable = {
  27.     ["speed"] = {0, 0},
  28.     ["last"] = {0, 0},
  29.     ["move"] = {0, 0}
  30. }
  31.  
  32. local panelState = false
  33. local enteredVehicle = false
  34. local availableFonts = nil
  35.  
  36. local panelWidth, rowHeight = 350 * scaleFactor, 35 * scaleFactor
  37. local panelX, panelY = 32, 32
  38. local logoHeight = panelWidth / 2
  39.  
  40. local hoveredCategory, selectedCategory, selectedSubCategory = 1, 0, 0
  41. local maxRowsPerPage, currentPage = 7, 1
  42.  
  43. local compatibleOpticalUpgrades = {}
  44. local equippedTuning = 1
  45.  
  46. local navbarButtonHeight = 30 * scaleFactor
  47. local navigationBar = {
  48.     {"", {"Enter"}, false},
  49.     {"", {"long-arrow-up", "long-arrow-down"}, true},
  50.     {"", {"Backspace"}, false},
  51.     {getLocalizedText("navbar.camera"), {"mouse"}, "image", 30}
  52. }
  53.  
  54. local noticeData = {
  55.     ["text"] = false,
  56.     ["type"] = "info",
  57.     ["tick"] = 0,
  58.     ["state"] = "",
  59.     ["height"] = 0,
  60.     ["timer"] = nil
  61. }
  62.  
  63. local cameraSettings = {}
  64.  
  65. local promptDialog = {
  66.     ["state"] = false,
  67.     ["itemName"] = "",
  68.     ["itemPrice"] = 0
  69. }
  70.  
  71. local availableOffroadAbilities = {
  72.     ["dirt"] = {0x100000, 2},
  73.     ["sand"] = {0x200000, 3}
  74. }
  75.  
  76. local availableWheelSizes = {
  77.     ["front"] = {
  78.         ["verynarrow"] = {0x100, 1},
  79.         ["narrow"] = {0x200, 2},
  80.         ["wide"] = {0x400, 4},
  81.         ["verywide"] = {0x800, 5}
  82.     },
  83.     ["rear"] = {
  84.         ["verynarrow"] = {0x1000, 1},
  85.         ["narrow"] = {0x2000, 2},
  86.         ["wide"] = {0x4000, 4},
  87.         ["verywide"] = {0x8000, 5}
  88.     }
  89. }
  90.  
  91. local savedVehicleColors = {["all"] = false, ["headlight"] = false}
  92. local moneyChangeTable = {["tick"] = 0, ["amount"] = 0}
  93.  
  94. local vehicleNumberplate = ""
  95.  
  96. addEvent("tuning->ShowMenu", true)
  97. addEvent("tuning->HideMenu", true)
  98.  
  99. addEventHandler("onClientResourceStart", resourceRoot, function()
  100.     for _, value in ipairs(getElementsByType("marker", root, true)) do
  101.         if getElementData(value, "tuningMarkerSettings") then
  102.             tuningMarkers[value] = true
  103.             tuningMarkersCount = tuningMarkersCount + 1
  104.         end
  105.     end
  106.    
  107.     for i = 1, 4 do
  108.         table.insert(tuningMenu[getMainCategoryIDByName(getLocalizedText("menu.color"))]["subMenu"], {
  109.             ["categoryName"] = getLocalizedText("menu.color") .. " " .. i,
  110.             ["tuningPrice"] = 10000,
  111.             ["tuningData"] = "color" .. i
  112.         })
  113.     end
  114. end)
  115.  
  116. addEventHandler("onClientResourceStop", resourceRoot, function()
  117.     if panelState and enteredVehicle then
  118.         resetOpticalUpgrade()
  119.         setVehicleColorsToDefault()
  120.         triggerEvent("tuning->HideMenu", localPlayer)
  121.     end
  122. end)
  123.  
  124. addEventHandler("onClientElementStreamIn", root, function()
  125.     if getElementType(source) == "marker" then
  126.         if getElementData(source, "tuningMarkerSettings") then
  127.             tuningMarkers[source] = true
  128.             tuningMarkersCount = tuningMarkersCount + 1
  129.         end
  130.     end
  131. end)
  132.  
  133. addEventHandler("onClientElementStreamOut", root, function()
  134.     if getElementType(source) == "marker" then
  135.         if getElementData(source, "tuningMarkerSettings") then
  136.             tuningMarkers[source] = nil
  137.             tuningMarkersCount = tuningMarkersCount - 1
  138.         end
  139.     end
  140. end)
  141.  
  142. addEventHandler("onClientRender", root, function()
  143.     --** Tuning marker image
  144.     if tuningMarkersCount ~= 0 then
  145.         local cameraX, cameraY, cameraZ = getCameraMatrix()
  146.  
  147.         for marker, id in pairs(tuningMarkers) do
  148.             if marker and isElement(marker) then
  149.                 if getElementAlpha(marker) ~= 0 and getElementDimension(marker) == getElementDimension(localPlayer) then
  150.                     local markerX, markerY, markerZ = getElementPosition(marker)
  151.                     local markerDistance = getDistanceBetweenPoints3D(cameraX, cameraY, cameraZ, markerX, markerY, markerZ)
  152.                    
  153.                     if markerDistance <= markerImageMaxVisibleDistance then
  154.                         if isLineOfSightClear(cameraX, cameraY, cameraZ, markerX, markerY, markerZ, false, false, false, true, false, false, false) then
  155.                             local screenX, screenY = getScreenFromWorldPosition(markerX, markerY, markerZ + 1, 1)
  156.                            
  157.                             if screenX and screenY then
  158.                                 local imageScale = 1 - (markerDistance / markerImageMaxVisibleDistance) * 0.5
  159.                                 local alphaScale = 255 - (markerDistance / markerImageMaxVisibleDistance) * 1.0
  160.                                
  161.                                 local imageWidth, imageHeight = 256 * imageScale, 128 * imageScale
  162.                                 local imageX, imageY = screenX - (imageWidth / 2), screenY - (imageHeight / 2)
  163.                                
  164.                                 dxDrawImage(imageX, imageY, imageWidth, imageHeight, availableTextures["logo"], 0, 0, 0, tocolor(255, 255, 255, 255 * alphaScale))
  165.                             end
  166.                         end
  167.                     end
  168.                 end
  169.             else
  170.                 tuningMarkers[marker] = nil
  171.             end
  172.         end
  173.     end
  174.    
  175.     -- ** Tuning menu
  176.     if panelState and enteredVehicle then
  177.         --> Logo
  178.  
  179.        
  180.         --> Current Money
  181.         drawTextWithBorder("$" .. formatNumber(getPlayerMoney(localPlayer), ","), 2, panelX, panelY, panelX + screenX - (panelX * 2), panelY + screenY - (panelY * 2), tocolor(0, 0, 0, 255), tocolor(189, 227, 188, 255), 1.2, 1.3, "pricedown", "right", "top", false, false, false, true)
  182.        
  183.         if moneyChangeTable["tick"] >= getTickCount() then
  184.             drawTextWithBorder("-$" .. formatNumber(moneyChangeTable["amount"], ","), 2, panelX, panelY + dxGetFontHeight(1.0, "pricedown"), panelX + screenX - (panelX * 2), panelY + screenY - (panelY * 2), tocolor(0, 0, 0, 255), tocolor(200, 80, 80, 255), 1.2, 1.3, "pricedown", "right", "top", false, false, false, true)
  185.         end
  186.        
  187.         --> Notification
  188.         if noticeData["text"] then
  189.             if noticeData["state"] == "showNotice" then
  190.                 local animationProgress = (getTickCount() - noticeData["tick"]) / 300
  191.                 local animationState = interpolateBetween(0, 0, 0, logoHeight * scaleFactor, 0, 0, animationProgress, "Linear")
  192.                
  193.                 noticeData["height"] = animationState
  194.                
  195.                 if animationProgress > 1 then
  196.                     noticeData["state"] = "fixNoticeJumping"
  197.                    
  198.                     noticeData["timer"] = setTimer(function()
  199.                         noticeData["tick"] = getTickCount()
  200.                         noticeData["state"] = "hideNotice"
  201.                     end, string.len(noticeData["text"]) * 50, 1)
  202.                 end
  203.             elseif noticeData["state"] == "hideNotice" then
  204.                 local animationProgress = (getTickCount() - noticeData["tick"]) / 300
  205.                 local animationState = interpolateBetween(logoHeight * scaleFactor, 0, 0, 0, 0, 0, animationProgress, "Linear")
  206.                
  207.                 noticeData["height"] = animationState
  208.                
  209.                 if animationProgress > 1 then
  210.                     noticeData["text"] = false
  211.                 end
  212.             elseif noticeData["state"] == "fixNoticeJumping" then
  213.                 noticeData["height"] = (logoHeight * scaleFactor)
  214.             end
  215.            
  216.             dxDrawRectangle(panelX, panelY, panelWidth, noticeData["height"], tocolor(0, 0, 0, 200))
  217.            
  218.             if noticeData["height"] == (logoHeight * scaleFactor) then
  219.                 local noticeIcon, iconColor = "", {255, 255, 255}
  220.                
  221.                 if noticeData["type"] == "info" then
  222.                     noticeIcon, iconColor = availableIcons["info-circle"], {85, 178, 243}
  223.                 elseif noticeData["type"] == "warning" then
  224.                     noticeIcon, iconColor = availableIcons["exclamation-triangle"], {220, 190, 120}
  225.                 elseif noticeData["type"] == "error" then
  226.                     noticeIcon, iconColor = availableIcons["exclamation-triangle"], {200, 80, 80}
  227.                 elseif noticeData["type"] == "success" then
  228.                     noticeIcon, iconColor = availableIcons["check"], {130, 220, 115}
  229.                 end
  230.                
  231.                 dxDrawText(noticeIcon, panelX + 5, panelY + 5, panelX + 5 + panelWidth - 10, panelY + 5 + noticeData["height"] - 10, tocolor(iconColor[1], iconColor[2], iconColor[3], 255), 1.0, availableFonts["icons"], "left", "top")
  232.                 dxDrawText(noticeData["text"], panelX + 10, panelY, panelX + 10 + panelWidth - 20, panelY + noticeData["height"], tocolor(255, 255, 255, 255), 0.5, availableFonts["chalet"], "center", "center", false, true)
  233.             end
  234.         end
  235.        
  236.         --> Looping table
  237.         loopTable, categoryCount, categoryName = {}, 0, "N/A"
  238.        
  239.         if selectedCategory == 0 then
  240.             loopTable = tuningMenu
  241.             categoryName = getLocalizedText("menu.mainMenu")
  242.            
  243.             navigationBar[1][1] = getLocalizedText("navbar.select")
  244.             navigationBar[3][1] = getLocalizedText("navbar.exit")
  245.         elseif selectedCategory ~= 0 and selectedSubCategory == 0 then
  246.             loopTable = tuningMenu[selectedCategory]["subMenu"]
  247.             categoryName = tuningMenu[selectedCategory]["categoryName"]
  248.            
  249.             if selectedCategory == getMainCategoryIDByName(getLocalizedText("menu.color")) then -- Color
  250.                 navigationBar[1][1] = getLocalizedText("navbar.buy")
  251.             else
  252.                 navigationBar[1][1] = getLocalizedText("navbar.select")
  253.             end
  254.            
  255.             navigationBar[3][1] = getLocalizedText("navbar.back")
  256.         elseif selectedCategory ~= 0 and selectedSubCategory ~= 0 then
  257.             if selectedCategory == getMainCategoryIDByName(getLocalizedText("menu.optical")) then -- Optical
  258.                 if isGTAUpgradeSlot(tuningMenu[selectedCategory]["subMenu"][selectedSubCategory]["upgradeSlot"]) then
  259.                     loopTable = tuningMenu[selectedCategory]["availableUpgrades"]
  260.                     categoryName = tuningMenu[selectedCategory]["categoryName"]
  261.                 else
  262.                     loopTable = tuningMenu[selectedCategory]["subMenu"][selectedSubCategory]["subMenu"]
  263.                     categoryName = tuningMenu[selectedCategory]["subMenu"][selectedSubCategory]["categoryName"]
  264.                 end
  265.             else
  266.                 loopTable = tuningMenu[selectedCategory]["subMenu"][selectedSubCategory]["subMenu"]
  267.                 categoryName = tuningMenu[selectedCategory]["subMenu"][selectedSubCategory]["categoryName"]
  268.             end
  269.            
  270.             navigationBar[1][1] = getLocalizedText("navbar.buy")
  271.             navigationBar[3][1] = getLocalizedText("navbar.back")
  272.         end
  273.        
  274.         --> Current category
  275.         local panelY = panelY + (logoHeight * scaleFactor)
  276.        
  277.         dxDrawRectangle(panelX, panelY, panelWidth, rowHeight, tocolor(0, 0, 0, 255))
  278.         dxDrawText(utf8.upper(categoryName), panelX + 10, panelY, panelX + 10 + panelWidth - 20, panelY + rowHeight, tocolor(255, 255, 255, 255), 0.5, availableFonts["chalet"], "left", "center", false, false, false, true)
  279.         dxDrawText(hoveredCategory .. " / " .. #loopTable, panelX + 10, panelY, panelX + 10 + panelWidth - 20, panelY + rowHeight, tocolor(255, 255, 255, 255), 0.5, availableFonts["chalet"], "right", "center", false, false, false, true)
  280.    
  281.         --> Menu rows
  282.         local panelY = panelY + rowHeight
  283.        
  284.         for id, row in ipairs(loopTable) do
  285.             if id >= currentPage and id <= currentPage + maxRowsPerPage then
  286.                 local rowX, rowY, rowWidth, rowHeight = panelX, panelY + (categoryCount * rowHeight), panelWidth, rowHeight
  287.                
  288.                 if selectedCategory == 0 or selectedSubCategory == 0 then
  289.                     equippedUpgrade = -1
  290.                 elseif selectedCategory == getMainCategoryIDByName(getLocalizedText("menu.optical")) then
  291.                     if isGTAUpgradeSlot(tuningMenu[selectedCategory]["subMenu"][selectedSubCategory]["upgradeSlot"]) then
  292.                         if row["upgradeID"] == equippedTuning then
  293.                             equippedUpgrade = id
  294.                         end
  295.                     else
  296.                         if id == equippedTuning then
  297.                             equippedUpgrade = id
  298.                         end
  299.                     end
  300.                 else
  301.                     if id == equippedTuning then
  302.                         equippedUpgrade = id
  303.                     end
  304.                 end
  305.                
  306.                 if hoveredCategory ~= id then
  307.                     if categoryCount %2 == 0 then
  308.                         dxDrawRectangle(rowX, rowY, rowWidth, rowHeight, tocolor(0, 0, 0, 150))
  309.                     else
  310.                         dxDrawRectangle(rowX, rowY, rowWidth, rowHeight, tocolor(0, 0, 0, 200))
  311.                     end
  312.                    
  313.                     dxDrawText(row["categoryName"], rowX + 15, rowY, rowX + 15 + rowWidth - 30, rowY + rowHeight, tocolor(255, 255, 255, 255), 0.5, availableFonts["chalet"], "left", "center", false, false, false, true)
  314.                
  315.                     if equippedUpgrade ~= id then
  316.                         if row["tuningPrice"] then
  317.                             if row["tuningPrice"] == 0 then
  318.                                 dxDrawText(getLocalizedText("tuningPrice.free"), rowX + 15, rowY, rowX + 15 + rowWidth - 30, rowY + rowHeight, tocolor(198, 83, 82, 255), 0.5, availableFonts["chalet"], "right", "center", false, false, false, true)
  319.                             else
  320.                                 dxDrawText("$ " .. formatNumber(row["tuningPrice"], ","), rowX + 15, rowY, rowX + 15 + rowWidth - 30, rowY + rowHeight, tocolor(255, 255, 255, 200), 0.5, availableFonts["chalet"], "right", "center", false, false, false, true)
  321.                             end
  322.                         end
  323.                     else
  324.                         dxDrawText(getLocalizedText("tuning.active"), rowX + 15, rowY, rowX + 15 + rowWidth - 30 - dxGetTextWidth(availableIcons["wrench"], 1.0, availableFonts["icons"]) - 10, rowY + rowHeight, tocolor(150, 255, 150, 255), 0.5, availableFonts["chalet"], "right", "center", false, false, false, true)
  325.                         dxDrawText(availableIcons["wrench"], rowX + 15, rowY, rowX + 15 + rowWidth - 30, rowY + rowHeight, tocolor(150, 255, 150, 255), 1.0, availableFonts["icons"], "right", "center", false, false, false, true)
  326.                     end
  327.                 else
  328.                     dxDrawImage(rowX, rowY, rowWidth, rowHeight, availableTextures["hoveredrow"])
  329.                    
  330.                     dxDrawText(row["categoryName"], rowX + 15, rowY, rowX + 15 + rowWidth - 30, rowY + rowHeight, tocolor(0, 0, 0, 255), 0.5, availableFonts["chalet"], "left", "center", false, false, false, true)
  331.                
  332.                     if equippedUpgrade ~= id then
  333.                         if row["tuningPrice"] then
  334.                             if row["tuningPrice"] == 0 then
  335.                                 dxDrawText(getLocalizedText("tuningPrice.free"), rowX + 15, rowY, rowX + 15 + rowWidth - 30, rowY + rowHeight, tocolor(0, 0, 0, 255), 0.5, availableFonts["chalet"], "right", "center", false, false, false, true)
  336.                             else
  337.                                 dxDrawText("$ " .. formatNumber(row["tuningPrice"], ","), rowX + 15, rowY, rowX + 15 + rowWidth - 30, rowY + rowHeight, tocolor(0, 0, 0, 200), 0.5, availableFonts["chalet"], "right", "center", false, false, false, true)
  338.                             end
  339.                         end
  340.                     else
  341.                         dxDrawText(getLocalizedText("tuning.active"), rowX + 15, rowY, rowX + 15 + rowWidth - 30 - dxGetTextWidth(availableIcons["wrench"], 1.0, availableFonts["icons"]) - 10, rowY + rowHeight, tocolor(0, 0, 0, 255), 0.5, availableFonts["chalet"], "right", "center", false, false, false, true)
  342.                         dxDrawText(availableIcons["wrench"], rowX + 15, rowY, rowX + 15 + rowWidth - 30, rowY + rowHeight, tocolor(0, 0, 0, 255), 1.0, availableFonts["icons"], "right", "center", false, false, false, true)
  343.                     end
  344.                 end
  345.                
  346.                 categoryCount = categoryCount + 1
  347.             end
  348.         end
  349.        
  350.         dxDrawImage(panelX, panelY + (categoryCount * rowHeight), panelWidth, rowHeight, availableTextures["menunav"])
  351.        
  352.         --> Scrollbar
  353.         if categoryCount >= (maxRowsPerPage + 1) and categoryCount ~= #loopTable then
  354.             local rowVisible = math.max(0.05, math.min(1.0, (maxRowsPerPage + 1) / #loopTable))
  355.             local scrollbarHeight = ((maxRowsPerPage + 1) * rowHeight) * rowVisible
  356.             local scrollbarPosition = math.min((currentPage - 1) / #loopTable, 1.0 - rowVisible) * ((maxRowsPerPage + 1) * rowHeight)
  357.            
  358.             dxDrawRectangle(panelX + panelWidth - 2, panelY + scrollbarPosition, 2, scrollbarHeight, tocolor(255, 255, 255, 255))
  359.         end
  360.        
  361.         --> Navigation Bar
  362.         local navbarWidth = getNavbarWidth()
  363.         local barOffsetX = 0
  364.        
  365.         drawRoundedRectangle(screenX - navbarWidth - 32 - 10, screenY - 32 - rowHeight, navbarWidth, rowHeight, 1, tocolor(0, 0, 0, 200))
  366.        
  367.         for _, row in ipairs(navigationBar) do
  368.             local textLength = dxGetTextWidth(row[1], 0.5, availableFonts["chalet"]) + 20
  369.             local navX, navY, navHeight = screenX - navbarWidth - 32 + barOffsetX, screenY - 32 - rowHeight, rowHeight
  370.             local navWidth = 0
  371.            
  372.             for id, icon in ipairs(row[2]) do
  373.                 local buttonWidth = 0
  374.                
  375.                 if type(row[3]) == "string" and row[3] == "image" then
  376.                     buttonWidth = row[4]
  377.                 elseif type(row[3]) == "boolean" and row[3] then
  378.                     buttonWidth = dxGetTextWidth(availableIcons[icon], 1.0, availableFonts["icons"]) + 20
  379.                 elseif type(row[3]) == "boolean" and not row[3] then
  380.                     buttonWidth = dxGetTextWidth(icon, 0.5, availableFonts["chalet"]) + 10
  381.                 end
  382.                
  383.                 local iconX = navX + textLength - 10 + ((id - 1) * buttonWidth) + ((id - 1) * 5)
  384.                
  385.                 if type(row[3]) == "boolean" then
  386.                     drawRoundedRectangle(iconX, navY + ((rowHeight / 2) - (navbarButtonHeight / 2)), buttonWidth, navbarButtonHeight, 1, tocolor(255, 255, 255, 255))
  387.                 end
  388.                
  389.                 if type(row[3]) == "string" and row[3] == "image" then
  390.                     dxDrawImage(iconX, navY + ((rowHeight / 2) - (navbarButtonHeight / 2)), buttonWidth, navbarButtonHeight, availableTextures[icon])
  391.                 elseif type(row[3]) == "boolean" and row[3] then
  392.                     dxDrawText(availableIcons[icon], iconX, navY + ((rowHeight / 2) - (navbarButtonHeight / 2)), iconX + buttonWidth, navY + ((rowHeight / 2) - (navbarButtonHeight / 2)) + navbarButtonHeight, tocolor(0, 0, 0, 255), 1.0, availableFonts["icons"], "center", "center")
  393.                 elseif type(row[3]) == "boolean" and not row[3] then
  394.                     dxDrawText(icon, iconX, navY + ((rowHeight / 2) - (navbarButtonHeight / 2)), iconX + buttonWidth, navY + ((rowHeight / 2) - (navbarButtonHeight / 2)) + navbarButtonHeight, tocolor(0, 0, 0, 255), 0.5, availableFonts["chalet"], "center", "center")
  395.                 end
  396.                
  397.                 navWidth = navWidth + buttonWidth + 10
  398.             end
  399.            
  400.             dxDrawText(row[1], navX, navY, navX + navWidth, navY + navHeight, tocolor(255, 255, 255, 255), 0.5, availableFonts["chalet"], "left", "center")
  401.            
  402.             barOffsetX = barOffsetX + (navWidth + textLength)
  403.         end
  404.        
  405.         --> Prompt dialog
  406.         if promptDialog["state"] then
  407.             local promptWidth = dxGetTextWidth(getLocalizedText("prompt.text"), 0.5, availableFonts["chalet"]) + 20
  408.             local promptWidth, promptHeight = promptWidth, 120 * scaleFactor
  409.             local promptX, promptY = (screenX / 2) - (promptWidth / 2), (screenY / 2) - (promptHeight / 2)
  410.            
  411.             drawRoundedRectangle(promptX, promptY, promptWidth, promptHeight, 1, tocolor(0, 0, 0, 200))
  412.             dxDrawText(getLocalizedText("prompt.text"), promptX + 10, promptY + 5, promptX + 10 + promptWidth - 20, promptY + 5 + promptHeight - 10, tocolor(255, 255, 255, 255), 0.5, availableFonts["chalet"], "left", "top")
  413.        
  414.             dxDrawText("#cccccc" .. getLocalizedText("prompt.info.1") ..": #ffffff" .. promptDialog["itemName"], promptX + 15, promptY + 30, promptX + 15 + promptWidth - 30, promptY + 30 + promptHeight - 60, tocolor(255, 255, 255, 255), 0.45, availableFonts["chalet"], "left", "top", false, false, false, true)
  415.             dxDrawText("#cccccc" .. getLocalizedText("prompt.info.2") .. ": #ffffff$ " .. formatNumber(promptDialog["itemPrice"], ","), promptX + 15, promptY + 30 + dxGetFontHeight(0.45, availableFonts["chalet"]), promptX + 15 + promptWidth - 30, promptY + 30 + dxGetFontHeight(0.45, availableFonts["chalet"]) + promptHeight - 60, tocolor(255, 255, 255, 255), 0.45, availableFonts["chalet"], "left", "top", false, false, false, true)
  416.        
  417.             local buttonX, buttonY, buttonWidth, buttonHeight = promptX + 10, promptY + promptHeight - 10 - navbarButtonHeight, (promptWidth / 2) - 20, navbarButtonHeight
  418.        
  419.             drawRoundedRectangle(buttonX, buttonY, buttonWidth, buttonHeight, 1, tocolor(110, 207, 112, 255))
  420.             dxDrawText(getLocalizedText("prompt.button.1"), buttonX, buttonY, buttonX + buttonWidth, buttonY + buttonHeight, tocolor(0, 0, 0, 255), 0.5, availableFonts["chalet"], "center", "center")
  421.            
  422.             drawRoundedRectangle((buttonX + buttonWidth + 20), buttonY, buttonWidth, buttonHeight, 1, tocolor(200, 80, 80, 255))
  423.             dxDrawText(getLocalizedText("prompt.button.2"), (buttonX + buttonWidth + 20), buttonY, (buttonX + buttonWidth + 20) + buttonWidth, buttonY + buttonHeight, tocolor(0, 0, 0, 255), 0.5, availableFonts["chalet"], "center", "center")
  424.         end
  425.        
  426.         --> License Plate inputbox
  427.         if selectedCategory == getMainCategoryIDByName(getLocalizedText("menu.extras")) then
  428.             if selectedSubCategory == 8 and hoveredCategory == 2 then
  429.                 local boxX, boxY, boxWidth, boxHeight = panelX + 2, panelY + (categoryCount * rowHeight) + rowHeight, panelWidth - 4, rowHeight
  430.                
  431.                 drawBorderedRectangle(boxX, boxY, boxWidth, boxHeight, 2, tocolor(0, 0, 0, 255), tocolor(30, 30, 30, 255))
  432.                 dxDrawText(vehicleNumberplate, boxX, boxY, boxX + boxWidth, boxY + boxHeight, tocolor(255, 255, 255, 255), 0.5, availableFonts["chalet"], "center", "center")
  433.             end
  434.         end
  435.     end
  436. end)
  437.  
  438. addEventHandler("onClientPreRender", root, function(timeSlice)
  439.     --> Calculate mouse move speed
  440.     if isCursorShowing() then
  441.         local cursorX, cursorY = getCursorPosition()
  442.        
  443.         mouseTable["speed"][1] = math.sqrt(math.pow((mouseTable["last"][1] - cursorX) / timeSlice, 2))
  444.         mouseTable["speed"][2] = math.sqrt(math.pow((mouseTable["last"][2] - cursorY) / timeSlice, 2))
  445.        
  446.         mouseTable["last"][1] = cursorX
  447.         mouseTable["last"][2] = cursorY
  448.     end
  449.    
  450.     --> Camera
  451.     if panelState and enteredVehicle then
  452.         local _, _, _, _, _, _, roll, fov = getCameraMatrix()
  453.         local cameraZoomProgress = (getTickCount() - cameraSettings["zoomTick"]) / 500
  454.         local cameraZoomAnimation = interpolateBetween(fov, 0, 0, cameraSettings["zoom"], 0, 0, cameraZoomProgress, "Linear")
  455.        
  456.         if cameraSettings["moveState"] == "moveToElement" then
  457.             local currentCameraX, currentCameraY, currentCameraZ, currentCameraRotX, currentCameraRotY, currentCameraRotZ = getCameraMatrix()
  458.             local cameraProgress = (getTickCount() - cameraSettings["moveTick"]) / 1000
  459.             local cameraX, cameraY, cameraZ, componentX, componentY, componentZ = _getCameraPosition("component")
  460.             local newCameraX, newCameraY, newCameraZ = interpolateBetween(currentCameraX, currentCameraY, currentCameraZ, cameraX, cameraY, cameraZ, cameraProgress, "Linear")
  461.             local newCameraRotX, newCameraRotY, newCameraRotZ = interpolateBetween(currentCameraRotX, currentCameraRotY, currentCameraRotZ, componentX, componentY, componentZ, cameraProgress, "Linear")
  462.             local newCameraZoom = interpolateBetween(fov, 0, 0, 60, 0, 0, cameraProgress, "Linear")
  463.            
  464.             setCameraMatrix(newCameraX, newCameraY, newCameraZ, newCameraRotX, newCameraRotY, newCameraRotZ, roll, newCameraZoom)
  465.            
  466.             if cameraProgress > 0.5 then
  467.                 cameraSettings["moveState"] = "freeMode"
  468.                 cameraSettings["zoom"] = 60
  469.             end
  470.         elseif cameraSettings["moveState"] == "backToVehicle" then
  471.             local currentCameraX, currentCameraY, currentCameraZ, currentCameraRotX, currentCameraRotY, currentCameraRotZ = getCameraMatrix()
  472.             local cameraProgress = (getTickCount() - cameraSettings["moveTick"]) / 1000
  473.             local cameraX, cameraY, cameraZ, vehicleX, vehicleY, vehicleZ = _getCameraPosition("vehicle")
  474.             local newCameraX, newCameraY, newCameraZ = interpolateBetween(currentCameraX, currentCameraY, currentCameraZ, cameraX, cameraY, cameraZ, cameraProgress, "Linear")
  475.             local newCameraRotX, newCameraRotY, newCameraRotZ = interpolateBetween(currentCameraRotX, currentCameraRotY, currentCameraRotZ, vehicleX, vehicleY, vehicleZ, cameraProgress, "Linear")
  476.             local newCameraZoom = interpolateBetween(fov, 0, 0, 60, 0, 0, cameraProgress, "Linear")
  477.            
  478.             setCameraMatrix(newCameraX, newCameraY, newCameraZ, newCameraRotX, newCameraRotY, newCameraRotZ, roll, newCameraZoom)
  479.            
  480.             if cameraProgress > 0.5 then
  481.                 cameraSettings["moveState"] = "freeMode"
  482.                 cameraSettings["zoom"] = 60
  483.             end
  484.         elseif cameraSettings["moveState"] == "freeMode" then
  485.             local cameraX, cameraY, cameraZ, elementX, elementY, elementZ = _getCameraPosition("both")
  486.            
  487.             setCameraMatrix(cameraX, cameraY, cameraZ, elementX, elementY, elementZ, roll, cameraZoomAnimation)
  488.            
  489.             if getKeyState("mouse1") and not pickingColor and not pickingLuminance and isCursorShowing() and not isMTAWindowActive() and not promptDialog["state"] then
  490.                 cameraSettings["freeModeActive"] = true
  491.             else
  492.                 cameraSettings["freeModeActive"] = false
  493.             end
  494.         end
  495.     end
  496. end)
  497.  
  498. addEventHandler("onClientCursorMove", root, function(cursorX, cursorY, absoluteX, absoluteY)
  499.     if panelState and enteredVehicle then
  500.         if cameraSettings["freeModeActive"] then
  501.             lastCursorX = mouseTable["move"][1]
  502.             lastCursorY = mouseTable["move"][2]
  503.            
  504.             mouseTable["move"][1] = cursorX
  505.             mouseTable["move"][2] = cursorY
  506.            
  507.             if cursorX > lastCursorX then
  508.                 cameraSettings["currentX"] = cameraSettings["currentX"] - (mouseTable["speed"][1] * 100)
  509.             elseif cursorX < lastCursorX then
  510.                 cameraSettings["currentX"] = cameraSettings["currentX"] + (mouseTable["speed"][1] * 100)
  511.             end
  512.            
  513.             if cursorY > lastCursorY then
  514.                 cameraSettings["currentZ"] = cameraSettings["currentZ"] + (mouseTable["speed"][2] * 50)
  515.             elseif cursorY < lastCursorY then
  516.                 cameraSettings["currentZ"] = cameraSettings["currentZ"] - (mouseTable["speed"][2] * 50)
  517.             end
  518.            
  519.             cameraSettings["currentY"] = cameraSettings["currentX"]
  520.             cameraSettings["currentZ"] = math.max(cameraSettings["minimumZ"], math.min(cameraSettings["maximumZ"], cameraSettings["currentZ"]))
  521.         end
  522.     end
  523. end)
  524.  
  525. addEventHandler("onClientCharacter", root, function(character)
  526.     if selectedCategory == getMainCategoryIDByName(getLocalizedText("menu.extras")) then
  527.         if selectedSubCategory == 8 and hoveredCategory == 2 then
  528.             if #vehicleNumberplate < 8 then
  529.                 local supportedCharacters = {
  530.                     ["q"] = true, ["w"] = true, ["x"] = true, ["4"] = true,
  531.                     ["e"] = true, ["r"] = true, ["c"] = true, ["5"] = true,
  532.                     ["t"] = true, ["z"] = true, ["v"] = true, ["6"] = true,
  533.                     ["u"] = true, ["i"] = true, ["b"] = true, ["7"] = true,
  534.                     ["o"] = true, ["p"] = true, ["n"] = true, ["8"] = true,
  535.                     ["a"] = true, ["s"] = true, ["m"] = true, ["9"] = true,
  536.                     ["d"] = true, ["f"] = true, ["0"] = true, ["-"] = true,
  537.                     ["g"] = true, ["h"] = true, ["1"] = true, [" "] = true,
  538.                     ["j"] = true, ["k"] = true, ["2"] = true,
  539.                     ["l"] = true, ["y"] = true, ["3"] = true,
  540.                 }
  541.                
  542.                 if supportedCharacters[character] then
  543.                     vehicleNumberplate = vehicleNumberplate .. utf8.upper(character)
  544.                     setVehiclePlateText(enteredVehicle, vehicleNumberplate)
  545.                 end
  546.             end
  547.         end
  548.     end
  549. end)
  550.  
  551. addEventHandler("onClientKey", root, function(key, pressed)
  552.     if panelState and enteredVehicle then
  553.         if pressed then
  554.             if key == "arrow_d" and not promptDialog["state"] then
  555.                 if hoveredCategory > #loopTable or hoveredCategory == #loopTable then
  556.                     hoveredCategory = #loopTable
  557.                 else
  558.                     if hoveredCategory > maxRowsPerPage then
  559.                         currentPage = currentPage + 1
  560.                     end
  561.                
  562.                     hoveredCategory = hoveredCategory + 1
  563.                    
  564.                     if selectedCategory == getMainCategoryIDByName(getLocalizedText("menu.optical")) then
  565.                         if selectedSubCategory ~= 0 then
  566.                             if isGTAUpgradeSlot(tuningMenu[selectedCategory]["subMenu"][selectedSubCategory]["upgradeSlot"]) then
  567.                                 showNextOpticalUpgrade()
  568.                             else
  569.                                 if selectedSubCategory == 12 then -- Neon
  570.                                     addNeon(enteredVehicle, loopTable[hoveredCategory]["tuningData"])
  571.                                 end
  572.                             end
  573.                         end
  574.                     elseif selectedCategory == getMainCategoryIDByName(getLocalizedText("menu.extras")) then
  575.                         if selectedSubCategory == 1 then
  576.                             triggerServerEvent("tuning->WheelWidth", localPlayer, enteredVehicle, "front", loopTable[hoveredCategory]["tuningData"])
  577.                         elseif selectedSubCategory == 2 then
  578.                             triggerServerEvent("tuning->WheelWidth", localPlayer, enteredVehicle, "rear", loopTable[hoveredCategory]["tuningData"])
  579.                         end
  580.                     elseif selectedCategory == getMainCategoryIDByName(getLocalizedText("menu.color")) then
  581.                         setVehicleColorsToDefault()
  582.                         setPaletteType(loopTable[hoveredCategory]["tuningData"])
  583.                         updatePaletteColor(enteredVehicle, loopTable[hoveredCategory]["tuningData"])
  584.                     end
  585.                    
  586.                     playSoundEffect("menunavigate.mp3")
  587.                 end
  588.             elseif key == "arrow_u" and not promptDialog["state"] then
  589.                 if hoveredCategory < 1 or hoveredCategory == 1 then
  590.                     hoveredCategory = 1
  591.                    
  592.                     if selectedCategory == getMainCategoryIDByName(getLocalizedText("menu.optical")) then
  593.                         if selectedSubCategory ~= 0 then
  594.                             if isGTAUpgradeSlot(tuningMenu[selectedCategory]["subMenu"][selectedSubCategory]["upgradeSlot"]) then
  595.                                 showDefaultOpticalUpgrade()
  596.                             end
  597.                         end
  598.                     end
  599.                 else
  600.                     if currentPage - 1 >= 1 then
  601.                         currentPage = currentPage - 1
  602.                     end
  603.                    
  604.                     hoveredCategory = hoveredCategory - 1
  605.                    
  606.                     if selectedCategory == getMainCategoryIDByName(getLocalizedText("menu.optical")) then
  607.                         if selectedSubCategory ~= 0 then
  608.                             if isGTAUpgradeSlot(tuningMenu[selectedCategory]["subMenu"][selectedSubCategory]["upgradeSlot"]) then
  609.                                 if hoveredCategory == 1 then -- Default upgrade
  610.                                     removeVehicleUpgrade(enteredVehicle, compatibleOpticalUpgrades[hoveredCategory])
  611.                                 else
  612.                                     showNextOpticalUpgrade()
  613.                                 end
  614.                             else
  615.                                 if selectedSubCategory == 12 then -- Neon
  616.                                     if hoveredCategory == 1 then
  617.                                         removeNeon(enteredVehicle, true)
  618.                                     else
  619.                                         addNeon(enteredVehicle, loopTable[hoveredCategory]["tuningData"])
  620.                                     end
  621.                                 end
  622.                             end
  623.                         end
  624.                     elseif selectedCategory == getMainCategoryIDByName(getLocalizedText("menu.extras")) then
  625.                         if selectedSubCategory == 1 then
  626.                             triggerServerEvent("tuning->WheelWidth", localPlayer, enteredVehicle, "front", loopTable[hoveredCategory]["tuningData"])
  627.                         elseif selectedSubCategory == 2 then
  628.                             triggerServerEvent("tuning->WheelWidth", localPlayer, enteredVehicle, "rear", loopTable[hoveredCategory]["tuningData"])
  629.                         elseif selectedSubCategory == 8 then
  630.                             if equippedTuning ~= vehicleNumberplate then
  631.                                 setVehiclePlateText(enteredVehicle, equippedTuning)
  632.                                 vehicleNumberplate = equippedTuning
  633.                             end
  634.                         end
  635.                     elseif selectedCategory == getMainCategoryIDByName(getLocalizedText("menu.color")) then
  636.                         setVehicleColorsToDefault()
  637.                         setPaletteType(loopTable[hoveredCategory]["tuningData"])
  638.                         updatePaletteColor(enteredVehicle, loopTable[hoveredCategory]["tuningData"])
  639.                     end
  640.                    
  641.                     playSoundEffect("menunavigate.mp3")
  642.                 end
  643.             elseif key == "backspace" then
  644.                 if promptDialog["state"] then
  645.                     promptDialog["state"] = false
  646.                 else
  647.                     if selectedCategory == getMainCategoryIDByName(getLocalizedText("menu.extras")) and selectedSubCategory == 8 then
  648.                         if hoveredCategory == 2 then
  649.                             if #vehicleNumberplate - 1 >= 0 then
  650.                                 vehicleNumberplate = string.sub(vehicleNumberplate, 1, #vehicleNumberplate - 1)
  651.                                 setVehiclePlateText(enteredVehicle, vehicleNumberplate)
  652.                             else
  653.                                 setVehiclePlateText(enteredVehicle, "")
  654.                                 vehicleNumberplate = ""
  655.                             end
  656.                            
  657.                             return
  658.                         else
  659.                             if equippedTuning ~= vehicleNumberplate then
  660.                                 setVehiclePlateText(enteredVehicle, equippedTuning)
  661.                                 vehicleNumberplate = equippedTuning
  662.                             end
  663.                         end
  664.                     end
  665.                    
  666.                     if selectedCategory == 0 and selectedSubCategory == 0 then
  667.                         triggerEvent("tuning->HideMenu", localPlayer)
  668.                     elseif selectedCategory ~= 0 and selectedSubCategory == 0 then
  669.                         if selectedCategory == getMainCategoryIDByName(getLocalizedText("menu.color")) then -- Color
  670.                             destroyColorPicker()
  671.                             setVehicleColorsToDefault()
  672.                         end
  673.                        
  674.                         selectedCategory, hoveredCategory, currentPage = 0, 1, 1
  675.                     elseif selectedCategory ~= 0 and selectedSubCategory ~= 0 then
  676.                         moveCameraToDefaultPosition()
  677.                        
  678.                         if selectedCategory == getMainCategoryIDByName(getLocalizedText("menu.optical")) then -- Optical
  679.                             if selectedSubCategory ~= 0 then
  680.                                 if isGTAUpgradeSlot(tuningMenu[selectedCategory]["subMenu"][selectedSubCategory]["upgradeSlot"]) then
  681.                                     resetOpticalUpgrade() -- reset to equipped upgrade
  682.                                     tuningMenu[selectedCategory]["availableUpgrades"] = {}
  683.                                     equippedTuning = 1
  684.                                 else
  685.                                     if selectedSubCategory == 11 then -- Lamp color
  686.                                         destroyColorPicker()
  687.                                         setVehicleColorsToDefault()
  688.                                         setVehicleOverrideLights(enteredVehicle, 1)
  689.                                     elseif selectedSubCategory == 12 then -- Neon
  690.                                         restoreOldNeon(enteredVehicle)
  691.                                     end
  692.                                 end
  693.                             end
  694.                         elseif selectedCategory == getMainCategoryIDByName(getLocalizedText("menu.extras")) then -- Extras
  695.                             if selectedSubCategory == 1 then
  696.                                 local defaultWheelSize = (equippedTuning == 1 and "verynarrow") or (equippedTuning == 2 and "narrow") or (equippedTuning == 3 and "default") or (equippedTuning == 4 and "wide") or (equippedTuning == 5 and "verywide")
  697.                                
  698.                                 triggerServerEvent("tuning->WheelWidth", localPlayer, enteredVehicle, "front", defaultWheelSize)
  699.                             elseif selectedSubCategory == 2 then
  700.                                 local defaultWheelSize = (equippedTuning == 1 and "verynarrow") or (equippedTuning == 2 and "narrow") or (equippedTuning == 3 and "default") or (equippedTuning == 4 and "wide") or (equippedTuning == 5 and "verywide")
  701.                                
  702.                                 triggerServerEvent("tuning->WheelWidth", localPlayer, enteredVehicle, "rear", defaultWheelSize)
  703.                             elseif selectedSubCategory == 6 then
  704.                                 setVehicleDoorOpenRatio(enteredVehicle, 2, 0, 500)
  705.                                 setVehicleDoorOpenRatio(enteredVehicle, 3, 0, 500)
  706.                                
  707.                                 setVehicleDoorToLSD(enteredVehicle, ((equippedTuning == 1 and false) or (equippedTuning == 2 and true)))
  708.                             end
  709.                         end
  710.                        
  711.                         selectedSubCategory, hoveredCategory, currentPage = 0, 1, 1
  712.                     end
  713.                    
  714.                     playSoundEffect("menuback.wav")
  715.                    
  716.                     if enteredVehicle then
  717.                         for component in pairs(getVehicleComponents(enteredVehicle)) do
  718.                             setVehicleComponentVisible(enteredVehicle, component, true)
  719.                         end
  720.                     end
  721.                 end
  722.             elseif key == "enter" then
  723.                 if not promptDialog["state"] then
  724.                     if selectedCategory == 0 then
  725.                         selectedCategory, currentPage, hoveredCategory = hoveredCategory, 1, 1
  726.                        
  727.                         if selectedCategory == getMainCategoryIDByName(getLocalizedText("menu.color")) then
  728.                             savedVehicleColors["all"] = {getVehicleColor(enteredVehicle, true)}
  729.                             savedVehicleColors["headlight"] = {getVehicleHeadLightColor(enteredVehicle)}
  730.                            
  731.                             createColorPicker(enteredVehicle, panelX + 2, (panelY + (logoHeight * scaleFactor) + rowHeight + (categoryCount * rowHeight) + rowHeight) + 2, panelWidth - 4, (panelWidth / 2) * scaleFactor, "color1")
  732.                         end
  733.                        
  734.                         playSoundEffect("menuenter.mp3")
  735.                     elseif selectedCategory ~= 0 and selectedSubCategory == 0 then
  736.                         if selectedCategory == getMainCategoryIDByName(getLocalizedText("menu.performance")) then
  737.                             local componentCompatible = false
  738.                        
  739.                             if isComponentCompatible(enteredVehicle, {"Automobile", "Monster Truck", "Quad", "Bike"}) then
  740.                                 local tuningDataName = loopTable[hoveredCategory]["upgradeData"]
  741.                                 local equippedTuningID = getElementData(enteredVehicle, "tuning." .. tuningDataName) or 1
  742.                                
  743.                                 if tuningDataName ~= "nitro" then
  744.                                     equippedTuning = equippedTuningID
  745.                                     componentCompatible = true
  746.                                 else
  747.                                     if isComponentCompatible(enteredVehicle, {"Automobile", "Monster Truck"}) then
  748.                                         equippedTuning = -1
  749.                                         componentCompatible = true
  750.                                     end
  751.                                 end
  752.                             end
  753.                            
  754.                             if componentCompatible then
  755.                                 setCameraAndComponentVisible()
  756.                                 selectedSubCategory, hoveredCategory, currentPage = hoveredCategory, 1, 1
  757.                             end
  758.                         elseif selectedCategory == getMainCategoryIDByName(getLocalizedText("menu.optical")) then
  759.                             if isGTAUpgradeSlot(loopTable[hoveredCategory]["upgradeSlot"]) then
  760.                                 local upgradeSlot = loopTable[hoveredCategory]["upgradeSlot"]
  761.                                 local compatibleUpgrades = getVehicleCompatibleUpgrades(enteredVehicle, upgradeSlot)
  762.                            
  763.                                 if compatibleUpgrades[1] == nil then
  764.                                     giveNotification("error", getLocalizedText("notification.error.notCompatible", loopTable[hoveredCategory]["categoryName"]))
  765.                                 else
  766.                                     setCameraAndComponentVisible()
  767.                                    
  768.                                     compatibleOpticalUpgrades = compatibleUpgrades
  769.                                     equippedTuning = getVehicleUpgradeOnSlot(enteredVehicle, upgradeSlot)
  770.                                    
  771.                                     table.insert(tuningMenu[selectedCategory]["availableUpgrades"], {
  772.                                         ["categoryName"] = getLocalizedText("tuningPack.0"),
  773.                                         ["tuningPrice"] = 0,
  774.                                         ["upgradeID"] = 0
  775.                                     })
  776.                                    
  777.                                     for id, upgrade in pairs(compatibleOpticalUpgrades) do
  778.                                         table.insert(tuningMenu[selectedCategory]["availableUpgrades"], {
  779.                                             ["categoryName"] = tuningMenu[selectedCategory]["subMenu"][hoveredCategory]["categoryName"] .. " " .. id,
  780.                                             ["tuningPrice"] = tuningMenu[selectedCategory]["subMenu"][hoveredCategory]["tuningPrice"],
  781.                                             ["upgradeID"] = upgrade
  782.                                         })
  783.                                     end
  784.                                    
  785.                                     selectedSubCategory, hoveredCategory, currentPage = hoveredCategory, 1, 1
  786.                                     showDefaultOpticalUpgrade()
  787.                                 end
  788.                             else -- Customs optical elements (Neon, Air-Ride etc..)
  789.                                 local componentCompatible = false
  790.                                
  791.                                 if hoveredCategory == 10 then -- Air-Ride
  792.                                     if isComponentCompatible(enteredVehicle, "Automobile") then
  793.                                         equippedTuning = (getElementData(enteredVehicle, "tuning.airRide") and 2) or 1
  794.                                         componentCompatible = true
  795.                                     end
  796.                                 elseif hoveredCategory == 11 then -- Lamp color
  797.                                     if isComponentCompatible(enteredVehicle, {"Automobile", "Monster Truck", "Quad", "Bike"}) then
  798.                                         equippedTuning = -1
  799.                                        
  800.                                         setVehicleOverrideLights(enteredVehicle, 2)
  801.                                        
  802.                                         savedVehicleColors["all"] = {getVehicleColor(enteredVehicle, true)}
  803.                                         savedVehicleColors["headlight"] = {getVehicleHeadLightColor(enteredVehicle)}
  804.                                        
  805.                                         createColorPicker(enteredVehicle, panelX + 2, (panelY + (logoHeight * scaleFactor) + (rowHeight * 2) + rowHeight) + 2, panelWidth - 4, (panelWidth / 2) * scaleFactor, "headlight")
  806.                                        
  807.                                         componentCompatible = true
  808.                                     end
  809.                                 elseif hoveredCategory == 12 then -- Neon
  810.                                     if isComponentCompatible(enteredVehicle, "Automobile") then
  811.                                         local currentNeon = getElementData(enteredVehicle, "tuning.neon") or false
  812.                                        
  813.                                         if currentNeon == "white" then currentNeon = 2
  814.                                         elseif currentNeon == "blue" then currentNeon = 3
  815.                                         elseif currentNeon == "green" then currentNeon = 4
  816.                                         elseif currentNeon == "red" then currentNeon = 5
  817.                                         elseif currentNeon == "yellow" then currentNeon = 6
  818.                                         elseif currentNeon == "pink" then currentNeon = 7
  819.                                         elseif currentNeon == "orange" then currentNeon = 8
  820.                                         elseif currentNeon == "lightblue" then currentNeon = 9
  821.                                         elseif currentNeon == "rasta" then currentNeon = 10
  822.                                         elseif currentNeon == "ice" then currentNeon = 11
  823.                                         else currentNeon = 1
  824.                                         end
  825.                                        
  826.                                         equippedTuning = currentNeon
  827.                                         removeNeon(enteredVehicle, true)
  828.                                        
  829.                                         componentCompatible = true
  830.                                     end
  831.                                 end
  832.                                
  833.                                 if componentCompatible then
  834.                                     setCameraAndComponentVisible()
  835.                                     selectedSubCategory, hoveredCategory, currentPage = hoveredCategory, 1, 1
  836.                                 end
  837.                             end
  838.                         elseif selectedCategory == getMainCategoryIDByName(getLocalizedText("menu.extras")) then
  839.                             local componentCompatible = false
  840.                            
  841.                             if hoveredCategory == 1 then
  842.                                 if isComponentCompatible(enteredVehicle, "Automobile") then
  843.                                     equippedTuning = getVehicleWheelSize(enteredVehicle, "front")
  844.                                     triggerServerEvent("tuning->WheelWidth", localPlayer, enteredVehicle, "front", loopTable[hoveredCategory]["subMenu"][1]["tuningData"])
  845.                                    
  846.                                     componentCompatible = true
  847.                                 end
  848.                             elseif hoveredCategory == 2 then
  849.                                 if isComponentCompatible(enteredVehicle, "Automobile") then
  850.                                     equippedTuning = getVehicleWheelSize(enteredVehicle, "rear")
  851.                                     triggerServerEvent("tuning->WheelWidth", localPlayer, enteredVehicle, "rear", loopTable[hoveredCategory]["subMenu"][1]["tuningData"])
  852.                                    
  853.                                     componentCompatible = true
  854.                                 end
  855.                             elseif hoveredCategory == 3 then
  856.                                 if isComponentCompatible(enteredVehicle, {"Automobile", "Monster Truck", "Quad", "Bike"}) then
  857.                                     equippedTuning = getVehicleOffroadAbility(enteredVehicle)
  858.                                     componentCompatible = true
  859.                                 end
  860.                             elseif hoveredCategory == 4 then
  861.                                 if isComponentCompatible(enteredVehicle, {"Automobile", "Monster Truck", "Quad"}) then
  862.                                     local driveType = getVehicleHandling(enteredVehicle)["driveType"]
  863.                                    
  864.                                     equippedTuning = (driveType == "fwd" and 1) or (driveType == "awd" and 2) or (driveType == "rwd" and 3)
  865.                                     componentCompatible = true
  866.                                 end
  867.                             elseif hoveredCategory == 5 then
  868.                                 if isComponentCompatible(enteredVehicle, {"Automobile", "Monster Truck", "Quad", "Bike"}) then
  869.                                     equippedTuning = (getElementData(enteredVehicle, "tuning.bulletProofTires") and 2) or 1
  870.                                     componentCompatible = true
  871.                                 end
  872.                             elseif hoveredCategory == 6 then
  873.                                 if isComponentCompatible(enteredVehicle, {"Automobile", "Monster Truck"}) then
  874.                                     equippedTuning = (getElementData(enteredVehicle, "tuning.lsdDoor") and 2) or 1
  875.                                    
  876.                                     setVehicleDoorOpenRatio(enteredVehicle, 2, 1, 500)
  877.                                     setVehicleDoorOpenRatio(enteredVehicle, 3, 1, 500)
  878.                                    
  879.                                     setVehicleDoorToLSD(enteredVehicle, true)
  880.                                    
  881.                                     componentCompatible = true
  882.                                 end
  883.                             elseif hoveredCategory == 7 then
  884.                                 if isComponentCompatible(enteredVehicle, {"Automobile", "Monster Truck", "Quad", "Bike", "BMX"}) then
  885.                                     local steeringLock = getVehicleHandling(enteredVehicle)["steeringLock"]
  886.                                    
  887.                                     equippedTuning = (steeringLock == 30 and 2) or (steeringLock == 40 and 3) or (steeringLock == 50 and 4) or (steeringLock == 60 and 5) or 1
  888.                                     componentCompatible = true
  889.                                 end
  890.                             elseif hoveredCategory == 8 then
  891.                                 if isComponentCompatible(enteredVehicle, {"Automobile", "Monster Truck", "Quad", "Bike"}) then
  892.                                     equippedTuning = getVehiclePlateText(enteredVehicle)
  893.                                     vehicleNumberplate = equippedTuning
  894.                                     componentCompatible = true
  895.                                 end
  896.                             end
  897.                            
  898.                             if componentCompatible then
  899.                                 setCameraAndComponentVisible()
  900.                                 selectedSubCategory, hoveredCategory, currentPage = hoveredCategory, 1, 1
  901.                             end
  902.                         elseif selectedCategory == getMainCategoryIDByName(getLocalizedText("menu.color")) then
  903.                             promptDialog = {
  904.                                 ["state"] = true,
  905.                                 ["itemName"] = categoryName .. " (" .. loopTable[hoveredCategory]["categoryName"] .. ")",
  906.                                 ["itemPrice"] = loopTable[hoveredCategory]["tuningPrice"]
  907.                             }
  908.                         end
  909.                        
  910.                         playSoundEffect("menuenter.mp3")
  911.                     elseif selectedCategory ~= 0 and selectedSubCategory ~= 0 then
  912.                         promptDialog = {
  913.                             ["state"] = true,
  914.                             ["itemName"] = categoryName .. " (" .. loopTable[hoveredCategory]["categoryName"] .. ")",
  915.                             ["itemPrice"] = loopTable[hoveredCategory]["tuningPrice"]
  916.                         }
  917.                     end
  918.                 else -- Buying item after accepted prompt
  919.                     if selectedCategory == getMainCategoryIDByName(getLocalizedText("menu.performance")) then
  920.                         if hoveredCategory == equippedTuning then
  921.                             giveNotification("error", getLocalizedText("notification.error.itemIsPurchased", loopTable[hoveredCategory]["categoryName"]))
  922.                             promptDialog["state"] = false
  923.                         else
  924.                             if hasPlayerMoney(loopTable[hoveredCategory]["tuningPrice"]) then
  925.                                 local tuningName = tuningMenu[selectedCategory]["subMenu"][selectedSubCategory]["upgradeData"]
  926.                
  927.                                 setElementData(enteredVehicle, "tuning." .. tuningName, hoveredCategory, true)
  928.                                
  929.                                 if tuningName ~= "nitro" then
  930.                                     triggerServerEvent("tuning->PerformanceUpgrade", localPlayer, enteredVehicle, loopTable[hoveredCategory]["tuningData"])
  931.                                     equippedTuning = hoveredCategory
  932.                                 else
  933.                                     if loopTable[hoveredCategory]["tuningData"] == 0 then
  934.                                         triggerServerEvent("tuning->OpticalUpgrade", localPlayer, enteredVehicle, "remove", 1010)
  935.                                     else
  936.                                         triggerServerEvent("tuning->OpticalUpgrade", localPlayer, enteredVehicle, "add", 1010)
  937.                                     end
  938.                                    
  939.                                     setElementData(enteredVehicle, "tuning.nitroLevel", loopTable[hoveredCategory]["tuningData"])
  940.                                     refreshVehicleNitroLevel(enteredVehicle, loopTable[hoveredCategory]["tuningData"])
  941.                                 end
  942.                                
  943.                                 moneyChange(loopTable[hoveredCategory]["tuningPrice"])
  944.                                 promptDialog["state"] = false
  945.                             else
  946.                                 giveNotification("error", getLocalizedText("notification.error.notEnoughMoney"))
  947.                                 promptDialog["state"] = false
  948.                             end
  949.                         end
  950.                     elseif selectedCategory == getMainCategoryIDByName(getLocalizedText("menu.optical")) then
  951.                         if isGTAUpgradeSlot(tuningMenu[selectedCategory]["subMenu"][selectedSubCategory]["upgradeSlot"]) then
  952.                             if equippedTuning == loopTable[hoveredCategory]["upgradeID"] then
  953.                                 giveNotification("error", getLocalizedText("notification.error.itemIsPurchased", loopTable[hoveredCategory]["categoryName"]))
  954.                                 promptDialog["state"] = false
  955.                             else
  956.                                 if hasPlayerMoney(loopTable[hoveredCategory]["tuningPrice"]) then
  957.                                     if getElementData(enteredVehicle, "tuning.airRide") and selectedSubCategory == 9 then
  958.                                         giveNotification("warning", getLocalizedText("notification.warning.airRideInstalled"))
  959.                                     else
  960.                                         if loopTable[hoveredCategory]["upgradeID"] == 0 then
  961.                                             triggerServerEvent("tuning->OpticalUpgrade", localPlayer, enteredVehicle, "remove", equippedTuning)
  962.                                             equippedTuning = 0
  963.                                         else
  964.                                             triggerServerEvent("tuning->OpticalUpgrade", localPlayer, enteredVehicle, "add", loopTable[hoveredCategory]["upgradeID"])
  965.                                             equippedTuning = loopTable[hoveredCategory]["upgradeID"]
  966.                                         end
  967.                                        
  968.                                         moneyChange(loopTable[hoveredCategory]["tuningPrice"])
  969.                                     end
  970.                                    
  971.                                     promptDialog["state"] = false
  972.                                 else
  973.                                     giveNotification("error", getLocalizedText("notification.error.notEnoughMoney"))
  974.                                     promptDialog["state"] = false
  975.                                 end
  976.                             end
  977.                         else
  978.                             if selectedSubCategory == 10 then -- Air-Ride
  979.                                 if hoveredCategory == equippedTuning then
  980.                                     giveNotification("error", getLocalizedText("notification.error.itemIsPurchased", loopTable[hoveredCategory]["categoryName"]))
  981.                                     promptDialog["state"] = false
  982.                                 else
  983.                                     if hasPlayerMoney(loopTable[hoveredCategory]["tuningPrice"]) then
  984.                                         setElementData(enteredVehicle, "tuning.airRide", loopTable[hoveredCategory]["tuningData"], true)
  985.                                        
  986.                                         if hoveredCategory == 1 then
  987.                                             removeAirRide(enteredVehicle)
  988.                                         end
  989.                                        
  990.                                         equippedTuning = hoveredCategory
  991.                                         moneyChange(loopTable[hoveredCategory]["tuningPrice"])
  992.                                         promptDialog["state"] = false
  993.                                     else
  994.                                         giveNotification("error", getLocalizedText("notification.error.notEnoughMoney"))
  995.                                         promptDialog["state"] = false
  996.                                     end
  997.                                 end
  998.                             elseif selectedSubCategory == 11 then -- Lamp color
  999.                                 if hasPlayerMoney(loopTable[hoveredCategory]["tuningPrice"]) then
  1000.                                     savedVehicleColors["all"] = {getVehicleColor(enteredVehicle, true)}
  1001.                                     savedVehicleColors["headlight"] = {getVehicleHeadLightColor(enteredVehicle)}
  1002.                                    
  1003.                                     triggerServerEvent("tuning->Color", localPlayer, enteredVehicle, savedVehicleColors["all"], savedVehicleColors["headlight"])
  1004.                                    
  1005.                                     equippedTuning = -1
  1006.                                     moneyChange(loopTable[hoveredCategory]["tuningPrice"])
  1007.                                     promptDialog["state"] = false
  1008.                                 else
  1009.                                     giveNotification("error", getLocalizedText("notification.error.notEnoughMoney"))
  1010.                                     promptDialog["state"] = false
  1011.                                 end
  1012.                             elseif selectedSubCategory == 12 then -- Neon
  1013.                                 if hasPlayerMoney(loopTable[hoveredCategory]["tuningPrice"]) then
  1014.                                     saveNeon(enteredVehicle, loopTable[hoveredCategory]["tuningData"], true)
  1015.                                    
  1016.                                     equippedTuning = hoveredCategory
  1017.                                     moneyChange(loopTable[hoveredCategory]["tuningPrice"])
  1018.                                     promptDialog["state"] = false
  1019.                                 else
  1020.                                     giveNotification("error", getLocalizedText("notification.error.notEnoughMoney"))
  1021.                                     promptDialog["state"] = false
  1022.                                 end
  1023.                             end
  1024.                         end
  1025.                     elseif selectedCategory == getMainCategoryIDByName(getLocalizedText("menu.extras")) then
  1026.                         if selectedSubCategory == 1 or selectedSubCategory == 2 then
  1027.                             local vehicleSide = (selectedSubCategory == 1 and "front") or (selectedSubCategory == 2 and "rear")
  1028.                            
  1029.                             if hoveredCategory == equippedTuning then
  1030.                                 giveNotification("error", getLocalizedText("notification.error.itemIsPurchased", loopTable[hoveredCategory]["categoryName"]))
  1031.                                 promptDialog["state"] = false
  1032.                             else
  1033.                                 if hasPlayerMoney(loopTable[hoveredCategory]["tuningPrice"]) then
  1034.                                     triggerServerEvent("tuning->WheelWidth", localPlayer, enteredVehicle, vehicleSide, loopTable[hoveredCategory]["tuningData"])
  1035.                                    
  1036.                                     equippedTuning = hoveredCategory
  1037.                                     moneyChange(loopTable[hoveredCategory]["tuningPrice"])
  1038.                                     promptDialog["state"] = false
  1039.                                 else
  1040.                                     giveNotification("error", getLocalizedText("notification.error.notEnoughMoney"))
  1041.                                     promptDialog["state"] = false
  1042.                                 end
  1043.                             end
  1044.                         elseif selectedSubCategory == 3 then
  1045.                             if hoveredCategory == equippedTuning then
  1046.                                 giveNotification("error", getLocalizedText("notification.error.itemIsPurchased", loopTable[hoveredCategory]["categoryName"]))
  1047.                                 promptDialog["state"] = false
  1048.                             else
  1049.                                 if hasPlayerMoney(loopTable[hoveredCategory]["tuningPrice"]) then
  1050.                                     triggerServerEvent("tuning->OffroadAbility", localPlayer, enteredVehicle, loopTable[hoveredCategory]["tuningData"])
  1051.                                    
  1052.                                     equippedTuning = hoveredCategory
  1053.                                     moneyChange(loopTable[hoveredCategory]["tuningPrice"])
  1054.                                     promptDialog["state"] = false
  1055.                                 else
  1056.                                     giveNotification("error", getLocalizedText("notification.error.notEnoughMoney"))
  1057.                                     promptDialog["state"] = false
  1058.                                 end
  1059.                             end
  1060.                         elseif selectedSubCategory == 4 or selectedSubCategory == 7 then
  1061.                             if hoveredCategory == equippedTuning then
  1062.                                 giveNotification("error", getLocalizedText("notification.error.itemIsPurchased", loopTable[hoveredCategory]["categoryName"]))
  1063.                                 promptDialog["state"] = false
  1064.                             else
  1065.                                 if hasPlayerMoney(loopTable[hoveredCategory]["tuningPrice"]) then
  1066.                                     triggerServerEvent("tuning->HandlingUpdate", localPlayer, enteredVehicle, tuningMenu[selectedCategory]["subMenu"][selectedSubCategory]["propertyName"], loopTable[hoveredCategory]["tuningData"])
  1067.                                    
  1068.                                     equippedTuning = hoveredCategory
  1069.                                     moneyChange(loopTable[hoveredCategory]["tuningPrice"])
  1070.                                     promptDialog["state"] = false
  1071.                                 else
  1072.                                     giveNotification("error", getLocalizedText("notification.error.notEnoughMoney"))
  1073.                                     promptDialog["state"] = false
  1074.                                 end
  1075.                             end
  1076.                         elseif selectedSubCategory == 5 then
  1077.                             if hoveredCategory == equippedTuning then
  1078.                                 giveNotification("error", getLocalizedText("notification.error.itemIsPurchased", loopTable[hoveredCategory]["categoryName"]))
  1079.                                 promptDialog["state"] = false
  1080.                             else
  1081.                                 if hasPlayerMoney(loopTable[hoveredCategory]["tuningPrice"]) then
  1082.                                     setElementData(enteredVehicle, "tuning.bulletProofTires", loopTable[hoveredCategory]["tuningData"], true)
  1083.                                    
  1084.                                     equippedTuning = hoveredCategory
  1085.                                     moneyChange(loopTable[hoveredCategory]["tuningPrice"])
  1086.                                     promptDialog["state"] = false
  1087.                                 else
  1088.                                     giveNotification("error", getLocalizedText("notification.error.notEnoughMoney"))
  1089.                                     promptDialog["state"] = false
  1090.                                 end
  1091.                             end
  1092.                         elseif selectedSubCategory == 6 then
  1093.                             if hoveredCategory == equippedTuning then
  1094.                                 giveNotification("error", getLocalizedText("notification.error.itemIsPurchased", loopTable[hoveredCategory]["categoryName"]))
  1095.                                 promptDialog["state"] = false
  1096.                             else
  1097.                                 if hasPlayerMoney(loopTable[hoveredCategory]["tuningPrice"]) then
  1098.                                     setVehicleDoorToLSD(enteredVehicle, loopTable[hoveredCategory]["tuningData"])
  1099.                                    
  1100.                                     equippedTuning = hoveredCategory
  1101.                                     moneyChange(loopTable[hoveredCategory]["tuningPrice"])
  1102.                                     promptDialog["state"] = false
  1103.                                 else
  1104.                                     giveNotification("error", getLocalizedText("notification.error.notEnoughMoney"))
  1105.                                     promptDialog["state"] = false
  1106.                                 end
  1107.                             end
  1108.                         elseif selectedSubCategory == 8 then
  1109.                             if hasPlayerMoney(loopTable[hoveredCategory]["tuningPrice"]) then
  1110.                                 if loopTable[hoveredCategory]["tuningData"] == "random" then
  1111.                                     vehicleNumberplate = generateString(8)
  1112.                                 elseif loopTable[hoveredCategory]["tuningData"] == "custom" then
  1113.                                     vehicleNumberplate = vehicleNumberplate
  1114.                                 end
  1115.                                
  1116.                                 triggerServerEvent("tuning->LicensePlate", localPlayer, enteredVehicle, vehicleNumberplate)
  1117.                                
  1118.                                 equippedTuning = vehicleNumberplate
  1119.                                 moneyChange(loopTable[hoveredCategory]["tuningPrice"])
  1120.                                 promptDialog["state"] = false
  1121.                             else
  1122.                                 giveNotification("error", getLocalizedText("notification.error.notEnoughMoney"))
  1123.                                 promptDialog["state"] = false
  1124.                             end
  1125.                         end
  1126.                     elseif selectedCategory == getMainCategoryIDByName(getLocalizedText("menu.color")) then
  1127.                         if hasPlayerMoney(loopTable[hoveredCategory]["tuningPrice"]) then
  1128.                             savedVehicleColors["all"] = {getVehicleColor(enteredVehicle, true)}
  1129.                             savedVehicleColors["headlight"] = {getVehicleHeadLightColor(enteredVehicle)}
  1130.                            
  1131.                             triggerServerEvent("tuning->Color", localPlayer, enteredVehicle, savedVehicleColors["all"], savedVehicleColors["headlight"])
  1132.                            
  1133.                             equippedTuning = hoveredCategory
  1134.                             moneyChange(loopTable[hoveredCategory]["tuningPrice"])
  1135.                             promptDialog["state"] = false
  1136.                         else
  1137.                             giveNotification("error", getLocalizedText("notification.error.notEnoughMoney"))
  1138.                             promptDialog["state"] = false
  1139.                         end
  1140.                     end
  1141.                 end
  1142.             end
  1143.            
  1144.             if key == "mouse_wheel_up" and not promptDialog["state"] then
  1145.                 if isCursorShowing() and not isMTAWindowActive() then
  1146.                     cameraSettings["zoom"] = math.max(cameraSettings["zoom"] - 5, 30)
  1147.                     cameraSettings["zoomTick"] = getTickCount()
  1148.                 end
  1149.             elseif key == "mouse_wheel_down" and not promptDialog["state"] then
  1150.                 if isCursorShowing() and not isMTAWindowActive() then
  1151.                     cameraSettings["zoom"] = math.min(cameraSettings["zoom"] + 5, 60)
  1152.                     cameraSettings["zoomTick"] = getTickCount()
  1153.                 end
  1154.             end
  1155.         end
  1156.     end
  1157. end)
  1158.  
  1159. addEventHandler("tuning->ShowMenu", root, function(vehicle)
  1160.     if source and vehicle then
  1161.         if not panelState then
  1162.             enteredVehicle = vehicle
  1163.            
  1164.             createFonts()
  1165.            
  1166.             hoveredCategory, selectedCategory, selectedSubCategory = 1, 0, 0
  1167.             maxRowsPerPage, currentPage = 7, 1
  1168.            
  1169.             navigationBar[1][1] = getLocalizedText("navbar.select")
  1170.             navigationBar[2][1] = getLocalizedText("navbar.navigate")
  1171.             navigationBar[3][1] = getLocalizedText("navbar.back")
  1172.            
  1173.             if noticeData["timer"] then
  1174.                 if isTimer(noticeData["timer"]) then
  1175.                     killTimer(noticeData["timer"])
  1176.                 end
  1177.             end
  1178.            
  1179.             noticeData = {
  1180.                 ["text"] = false,
  1181.                 ["type"] = "info",
  1182.                 ["tick"] = 0,
  1183.                 ["state"] = "",
  1184.                 ["height"] = 0,
  1185.                 ["timer"] = nil
  1186.             }
  1187.            
  1188.             local _, _, vehicleRotation = getElementRotation(enteredVehicle)
  1189.             local cameraRotation = vehicleRotation + 60
  1190.            
  1191.             cameraSettings = {
  1192.                 ["distance"] = 9,
  1193.                 ["movingSpeed"] = 2,
  1194.                 ["currentX"] = math.rad(cameraRotation),
  1195.                 ["defaultX"] = math.rad(cameraRotation),
  1196.                 ["currentY"] = math.rad(cameraRotation),
  1197.                 ["currentZ"] = math.rad(15),
  1198.                 ["maximumZ"] = math.rad(35),
  1199.                 ["minimumZ"] = math.rad(0),
  1200.                 ["freeModeActive"] = false,
  1201.                 ["zoomTick"] = 0,
  1202.                 ["zoom"] = 60
  1203.             }
  1204.            
  1205.             cameraSettings["moveState"] = "freeMode"
  1206.            
  1207.             promptDialog = {
  1208.                 ["state"] = false,
  1209.                 ["itemName"] = "",
  1210.                 ["itemPrice"] = 0
  1211.             }
  1212.            
  1213.             panelState = true
  1214.             toggleAllControls(false)
  1215.             setPlayerHudComponentVisible("all", false)
  1216.             showChat(false)
  1217.             showCursor(true)
  1218.         end
  1219.     end
  1220. end)
  1221.  
  1222. addEventHandler("tuning->HideMenu", root, function()
  1223.     if enteredVehicle and panelState then
  1224.         panelState = false
  1225.         toggleAllControls(true)
  1226.         setPlayerHudComponentVisible("all", false)
  1227.         showChat(true)
  1228.         enteredVehicle = nil
  1229.         destroyFonts()
  1230.         setCameraTarget(localPlayer)
  1231.         showCursor(false)
  1232.        
  1233.         triggerServerEvent("tuning->ResetMarker", root, localPlayer)
  1234.     end
  1235. end)
  1236.  
  1237. addEventHandler("onClientVehicleDamage", root, function(_, _, _, _, _, _, tyre) -- Bulletproof tires
  1238.     if getElementData(source, "tuning.bulletProofTires") then
  1239.         if tyre == 0 or tyre == 1 or tyre == 2 or tyre == 3 then
  1240.             cancelEvent()
  1241.         end
  1242.     end
  1243. end)
  1244.  
  1245. function moneyChange(amount)
  1246.     takePlayerMoney(loopTable[hoveredCategory]["tuningPrice"])
  1247.     giveNotification("success", getLocalizedText("notification.success.purchased"))
  1248.     playSoundEffect("moneychange.wav")
  1249.    
  1250.     if amount > 0 then
  1251.         moneyChangeTable = {
  1252.             ["tick"] = getTickCount() + 5000,
  1253.             ["amount"] = amount
  1254.         }
  1255.     end
  1256. end
  1257.  
  1258. function createFonts()
  1259.     availableFonts = {
  1260.         chalet = dxCreateFont("files/fonts/chalet.ttf", 22 * scaleFactor, false, "antialiased"),
  1261.         icons = dxCreateFont("files/fonts/icons.ttf", 11 * scaleFactor, false, "antialiased")
  1262.     }
  1263. end
  1264.  
  1265. function destroyFonts()
  1266.     if availableFonts then
  1267.         for fontName, fontElement in pairs(availableFonts) do
  1268.             destroyElement(fontElement)
  1269.             availableFonts[fontName] = nil
  1270.         end
  1271.        
  1272.         availableFonts = nil
  1273.     end
  1274. end
  1275.  
  1276. function drawTextWithBorder(text, offset, x, y, w, h, borderColor, color, scale, font, alignX, alignY, clip, wordBreak, postGUI, colorCoded, subPixelPositioning, fRotation, fRotationCenterX, fRotationCenterY)
  1277.     for offsetX = -offset, offset do
  1278.         for offsetY = -offset, offset do
  1279.             dxDrawText(text:gsub("#%x%x%x%x%x%x", ""), x + offsetX, y + offsetY, w + offsetX, h + offsetY, borderColor, scale, font, alignX, alignY, clip, wordBreak, postGUI, colorCoded, subPixelPositioning, fRotation, fRotationCenterX, fRotationCenterY)
  1280.         end
  1281.     end
  1282.    
  1283.     dxDrawText(text, x, y, w, h, color, scale, font, alignX, alignY, clip, wordBreak, postGUI, colorCoded, subPixelPositioning, fRotation, fRotationCenterX, fRotationCenterY)
  1284. end
  1285.  
  1286. function giveNotification(type, text)
  1287.     type = type or "info"
  1288.    
  1289.     if noticeData["timer"] then
  1290.         if isTimer(noticeData["timer"]) then
  1291.             killTimer(noticeData["timer"])
  1292.         end
  1293.     end
  1294.    
  1295.     noticeData = {
  1296.         ["text"] = text,
  1297.         ["type"] = type,
  1298.         ["tick"] = getTickCount(),
  1299.         ["state"] = "showNotice",
  1300.         ["height"] = 0,
  1301.         ["timer"] = nil
  1302.     }
  1303.    
  1304.     playSoundEffect("notification.mp3")
  1305. end
  1306.  
  1307. function getNavbarWidth()
  1308.     local barOffsetX = 0
  1309.        
  1310.     for _, row in ipairs(navigationBar) do
  1311.         local textLength = dxGetTextWidth(row[1], 0.5, availableFonts["chalet"]) + 20
  1312.         local navWidth = 0
  1313.        
  1314.         for id, icon in ipairs(row[2]) do
  1315.             local buttonWidth = 0
  1316.            
  1317.             if type(row[3]) == "string" and row[3] == "image" then
  1318.                 buttonWidth = row[4]
  1319.             elseif type(row[3]) == "boolean" and row[3] then
  1320.                 buttonWidth = dxGetTextWidth(availableIcons[icon], 1.0, availableFonts["icons"]) + 20
  1321.             elseif type(row[3]) == "boolean" and not row[3] then
  1322.                 buttonWidth = dxGetTextWidth(icon, 0.5, availableFonts["chalet"]) + 10
  1323.             end
  1324.            
  1325.             navWidth = navWidth + buttonWidth + 10
  1326.         end
  1327.        
  1328.         barOffsetX = barOffsetX + (navWidth + textLength)
  1329.     end
  1330.    
  1331.     return barOffsetX
  1332. end
  1333.  
  1334. function hasPlayerMoney(money)
  1335.     if getPlayerMoney(localPlayer) >= money then
  1336.         return true
  1337.     end
  1338.    
  1339.     return false
  1340. end
  1341.  
  1342. function drawRoundedRectangle(x, y, w, h, rounding, borderColor, bgColor, postGUI)
  1343.     borderColor = borderColor or tocolor(0, 0, 0, 200)
  1344.     bgColor = bgColor or borderColor
  1345.     rounding = rounding or 2
  1346.    
  1347.     dxDrawRectangle(x, y, w, h, bgColor, postGUI)
  1348.     dxDrawRectangle(x + rounding, y - 1, w - (rounding * 2), 1, borderColor, postGUI)
  1349.     dxDrawRectangle(x + rounding, y + h, w - (rounding * 2), 1, borderColor, postGUI)
  1350.     dxDrawRectangle(x - 1, y + rounding, 1, h - (rounding * 2), borderColor, postGUI)
  1351.     dxDrawRectangle(x + w, y + rounding, 1, h - (rounding * 2), borderColor, postGUI)
  1352. end
  1353.  
  1354. function showDefaultOpticalUpgrade()
  1355.     if panelState then
  1356.         if enteredVehicle then
  1357.             if equippedTuning ~= 0 then
  1358.                 removeVehicleUpgrade(enteredVehicle, equippedTuning)
  1359.             elseif equippedTuning == 0 then
  1360.                 removeVehicleUpgrade(enteredVehicle, compatibleOpticalUpgrades[hoveredCategory])
  1361.             end
  1362.         end
  1363.     end
  1364. end
  1365.  
  1366. function showNextOpticalUpgrade()
  1367.     if panelState then
  1368.         if enteredVehicle then
  1369.             addVehicleUpgrade(enteredVehicle, compatibleOpticalUpgrades[hoveredCategory - 1])
  1370.         end
  1371.     end
  1372. end
  1373.  
  1374. function resetOpticalUpgrade()
  1375.     if panelState then
  1376.         if enteredVehicle then
  1377.             if equippedTuning ~= 0 then
  1378.                 addVehicleUpgrade(enteredVehicle, equippedTuning)
  1379.             else
  1380.                 if hoveredCategory - 1 == 0 then
  1381.                     removeVehicleUpgrade(enteredVehicle, compatibleOpticalUpgrades[hoveredCategory])
  1382.                 else
  1383.                     removeVehicleUpgrade(enteredVehicle, compatibleOpticalUpgrades[hoveredCategory - 1])
  1384.                 end
  1385.             end
  1386.         end
  1387.     end
  1388. end
  1389.  
  1390. function formatNumber(amount, spacer)
  1391.     if not spacer then
  1392.         spacer = ","
  1393.     end
  1394.    
  1395.     amount = math.floor(amount)
  1396.    
  1397.     local left, num, right = string.match(tostring(amount), "^([^%d]*%d)(%d*)(.-)$")
  1398.     return left .. (num:reverse():gsub("(%d%d%d)", "%1" .. spacer):reverse()) .. right
  1399. end
  1400.  
  1401. function playSoundEffect(soundFile)
  1402.     if soundFile then
  1403.         local soundEffect = playSound("files/sounds/" .. soundFile, false)
  1404.        
  1405.         setSoundVolume(soundEffect, 0.5)
  1406.     end
  1407. end
  1408.  
  1409. function getPositionFromElementOffset(element, offsetX, offsetY, offsetZ)
  1410.     local elementMatrix = getElementMatrix(element)
  1411.     local elementX = offsetX * elementMatrix[1][1] + offsetY * elementMatrix[2][1] + offsetZ * elementMatrix[3][1] + elementMatrix[4][1]
  1412.     local elementY = offsetX * elementMatrix[1][2] + offsetY * elementMatrix[2][2] + offsetZ * elementMatrix[3][2] + elementMatrix[4][2]
  1413.     local elementZ = offsetX * elementMatrix[1][3] + offsetY * elementMatrix[2][3] + offsetZ * elementMatrix[3][3] + elementMatrix[4][3]
  1414.    
  1415.     return elementX, elementY, elementZ
  1416. end
  1417.  
  1418. function getVehicleOffroadAbility(vehicle)
  1419.     if vehicle then
  1420.         local flags = getVehicleHandling(vehicle)["handlingFlags"]
  1421.        
  1422.         for name, flag in pairs(availableOffroadAbilities) do
  1423.             if isFlagSet(flags, flag[1]) then
  1424.                 return flag[2]
  1425.             end
  1426.         end
  1427.        
  1428.         return 1
  1429.     end
  1430. end
  1431.  
  1432. function getVehicleWheelSize(vehicle, side)
  1433.     if vehicle and side then
  1434.         local flags = getVehicleHandling(vehicle)["handlingFlags"]
  1435.        
  1436.         for name, flag in pairs(availableWheelSizes[side]) do
  1437.             if isFlagSet(flags, flag[1]) then
  1438.                 return flag[2]
  1439.             end
  1440.         end
  1441.        
  1442.         return 3
  1443.     end
  1444. end
  1445.  
  1446. function isGTAUpgradeSlot(slot)
  1447.     if slot then
  1448.         for i = 0, 16 do
  1449.             if slot == i then
  1450.                 return true
  1451.             end
  1452.         end
  1453.     end
  1454.    
  1455.     return false
  1456. end
  1457.  
  1458. function isFlagSet(val, flag)
  1459.     return (bitAnd(val, flag) == flag)
  1460. end
  1461.  
  1462. function moveCameraToComponent(component, offsetX, offsetZ, zoom)
  1463.     if component then
  1464.         local _, _, vehicleRotation = getElementRotation(enteredVehicle)
  1465.        
  1466.         offsetX = offsetX or cameraSettings["defaultX"]
  1467.         offsetZ = offsetZ or 15
  1468.         zoom = zoom or 9
  1469.        
  1470.         local cameraRotation = vehicleRotation + offsetX
  1471.        
  1472.         cameraSettings["moveState"] = "moveToElement"
  1473.         cameraSettings["moveTick"] = getTickCount()
  1474.         cameraSettings["viewingElement"] = component
  1475.         cameraSettings["currentX"] = math.rad(cameraRotation)
  1476.         cameraSettings["currentY"] = math.rad(cameraRotation)
  1477.         cameraSettings["currentZ"] = math.rad(offsetZ)
  1478.         cameraSettings["distance"] = zoom
  1479.     end
  1480. end
  1481.  
  1482. function moveCameraToDefaultPosition()
  1483.     cameraSettings["moveState"] = "backToVehicle"
  1484.     cameraSettings["moveTick"] = getTickCount()
  1485.     cameraSettings["viewingElement"] = enteredVehicle
  1486.    
  1487.     cameraSettings["currentX"] = cameraSettings["defaultX"]
  1488.     cameraSettings["currentY"] = cameraSettings["defaultX"]
  1489.     cameraSettings["currentZ"] = math.rad(15)
  1490.     cameraSettings["distance"] = 9
  1491. end
  1492.  
  1493. function _getCameraPosition(element)
  1494.     if element == "component" then
  1495.         local componentX, componentY, componentZ = getVehicleComponentPosition(enteredVehicle, cameraSettings["viewingElement"])
  1496.         local elementX, elementY, elementZ = getPositionFromElementOffset(enteredVehicle, componentX, componentY, componentZ)
  1497.         local elementZ = elementZ + 0.2
  1498.        
  1499.         local cameraX = elementX + math.cos(cameraSettings["currentX"]) * cameraSettings["distance"]
  1500.         local cameraY = elementY + math.sin(cameraSettings["currentY"]) * cameraSettings["distance"]
  1501.         local cameraZ = elementZ + math.sin(cameraSettings["currentZ"]) * cameraSettings["distance"]
  1502.        
  1503.         return cameraX, cameraY, cameraZ, elementX, elementY, elementZ
  1504.     elseif element == "vehicle" then
  1505.         local elementX, elementY, elementZ = getElementPosition(enteredVehicle)
  1506.         local elementZ = elementZ + 0.2
  1507.        
  1508.         local cameraX = elementX + math.cos(cameraSettings["currentX"]) * cameraSettings["distance"]
  1509.         local cameraY = elementY + math.sin(cameraSettings["currentY"]) * cameraSettings["distance"]
  1510.         local cameraZ = elementZ + math.sin(cameraSettings["currentZ"]) * cameraSettings["distance"]
  1511.        
  1512.         return cameraX, cameraY, cameraZ, elementX, elementY, elementZ
  1513.     elseif element == "both" then
  1514.         if type(cameraSettings["viewingElement"]) == "string" then
  1515.             local componentX, componentY, componentZ = getVehicleComponentPosition(enteredVehicle, cameraSettings["viewingElement"])
  1516.            
  1517.             elementX, elementY, elementZ = getPositionFromElementOffset(enteredVehicle, componentX, componentY, componentZ)
  1518.         else
  1519.             elementX, elementY, elementZ = getElementPosition(enteredVehicle)
  1520.         end
  1521.        
  1522.         local elementZ = elementZ + 0.2
  1523.        
  1524.         local cameraX = elementX + math.cos(cameraSettings["currentX"]) * cameraSettings["distance"]
  1525.         local cameraY = elementY + math.sin(cameraSettings["currentY"]) * cameraSettings["distance"]
  1526.         local cameraZ = elementZ + math.sin(cameraSettings["currentZ"]) * cameraSettings["distance"]
  1527.        
  1528.         return cameraX, cameraY, cameraZ, elementX, elementY, elementZ
  1529.     end
  1530. end
  1531.  
  1532. function isValidComponent(vehicle, componentName)
  1533.     if vehicle and componentName then
  1534.         for component in pairs(getVehicleComponents(vehicle)) do
  1535.             if componentName == component then
  1536.                 return true
  1537.             end
  1538.         end
  1539.     end
  1540.    
  1541.     return false
  1542. end
  1543.  
  1544. function setVehicleColorsToDefault()
  1545.     local vehicleColor = savedVehicleColors["all"]
  1546.     local vehicleLightColor = savedVehicleColors["headlight"]
  1547.    
  1548.     setVehicleColor(enteredVehicle, vehicleColor[1], vehicleColor[2], vehicleColor[3], vehicleColor[4], vehicleColor[5], vehicleColor[6], vehicleColor[7], vehicleColor[8], vehicleColor[9])
  1549.     setVehicleHeadLightColor(enteredVehicle, vehicleLightColor[1], vehicleLightColor[2], vehicleLightColor[3])
  1550. end
  1551.  
  1552. function setCameraAndComponentVisible()
  1553.     if getVehicleType(enteredVehicle) == "Automobile" then
  1554.         if loopTable[hoveredCategory]["cameraSettings"] then
  1555.             local cameraSetting = loopTable[hoveredCategory]["cameraSettings"]
  1556.        
  1557.             if isValidComponent(enteredVehicle, cameraSetting[1]) then
  1558.                 moveCameraToComponent(cameraSetting[1], cameraSetting[2], cameraSetting[3], cameraSetting[4])
  1559.             end
  1560.            
  1561.             if cameraSetting[5] then
  1562.                 setVehicleComponentVisible(enteredVehicle, cameraSetting[1], false)
  1563.             end
  1564.         end
  1565.     end
  1566. end
  1567.  
  1568. function generateString(len)
  1569.     if tonumber(len) then
  1570.         local allowed = {{48, 57}, {97, 122}}
  1571.        
  1572.         math.randomseed(getTickCount())
  1573.  
  1574.         local str = ""
  1575.        
  1576.         for i = 1, len do
  1577.             local charlist = allowed[math.random(1, 2)]
  1578.            
  1579.             if i == 4 then
  1580.                 str = str .. " "
  1581.             else
  1582.                 str = str .. string.char(math.random(charlist[1], charlist[2]))
  1583.             end
  1584.         end
  1585.  
  1586.         return utf8.upper(str)
  1587.     end
  1588.  
  1589.     return false
  1590. end
  1591.  
  1592. function isComponentCompatible(vehicle, vehicleType)
  1593.     if vehicle and vehicleType then
  1594.         if type(vehicleType) == "string" then
  1595.             if getVehicleType(vehicle) == vehicleType then
  1596.                 return true
  1597.             else
  1598.                 giveNotification("error", getLocalizedText("notification.error.notCompatible", loopTable[hoveredCategory]["categoryName"]))
  1599.             end
  1600.         elseif type(vehicleType) == "table" then
  1601.             local typeFounded = false
  1602.            
  1603.             for _, modelType in pairs(vehicleType) do
  1604.                 if modelType == getVehicleType(vehicle) then
  1605.                     typeFounded = true
  1606.                 end
  1607.             end
  1608.            
  1609.             if typeFounded then
  1610.                 return true
  1611.             else
  1612.                 giveNotification("error", getLocalizedText("notification.error.notCompatible", loopTable[hoveredCategory]["categoryName"]))
  1613.             end
  1614.         end
  1615.     end
  1616.    
  1617.     return false
  1618. end
  1619.  
  1620. function drawBorder(x, y, w, h, size, color, postGUI)
  1621.     size = size or 2
  1622.    
  1623.     dxDrawRectangle(x - size, y, size, h, color or tocolor(0, 0, 0, 200), postGUI)
  1624.     dxDrawRectangle(x + w, y, size, h, color or tocolor(0, 0, 0, 200), postGUI)
  1625.     dxDrawRectangle(x - size, y - size, w + (size * 2), size, color or tocolor(0, 0, 0, 200), postGUI)
  1626.     dxDrawRectangle(x - size, y + h, w + (size * 2), size, color or tocolor(0, 0, 0, 200), postGUI)
  1627. end
  1628.  
  1629. function drawBorderedRectangle(x, y, w, h, borderSize, borderColor, bgColor, postGUI)
  1630.     borderSize = borderSize or 2
  1631.     borderColor = borderColor or tocolor(0, 0, 0, 200)
  1632.     bgColor = bgColor or borderColor
  1633.    
  1634.     dxDrawRectangle(x, y, w, h, bgColor, postGUI)
  1635.     drawBorder(x, y, w, h, borderSize, borderColor, postGUI)
  1636. end
  1637.  
  1638. addCommandHandler("markerpos", function()
  1639.     if getPedOccupiedVehicle(localPlayer) then
  1640.         local x, y, z = getElementPosition(getPedOccupiedVehicle(localPlayer))
  1641.         local _, _, rotation = getElementRotation(getPedOccupiedVehicle(localPlayer))
  1642.        
  1643.         setClipboard(x .. ", " .. y .. ", " .. z .. ", " .. rotation)
  1644.     else
  1645.         local x, y, z = getElementPosition(localPlayer)
  1646.         local rotation = getPedRotation(localPlayer)
  1647.        
  1648.         setClipboard(x .. ", " .. y .. ", " .. z .. ", " .. rotation)
  1649.     end
  1650.    
  1651.     outputDebugString("[TUNING]: Marker position set to Clipboard. Use [CTRL + V] to paste it.", 0, 2, 168, 255)
  1652. end)
Advertisement
Add Comment
Please, Sign In to add comment