2026-04-14 17:41:39 +02:00

849 lines
33 KiB
Lua

local currentMechanicId = nil
local isMenuOpen = false
local isPromptShowing = false
local currentVehicle = nil
local originalVehicleProps = {}
local vehiclePlate = ""
local isPurchaseFinalized = false
local isDoingBurnout = false
local canTyresBeBurst = true
local isFreecamActive = false
local isHornLoopActive = false
local appliedMods = {
repair = {},
performance = {},
cosmetics = {},
stance = {},
respray = {},
wheels = {},
neonLights = {},
headlights = {},
tyreSmoke = {},
bulletproofTyres = {},
extras = {}
}
local function toggleVehicleFreeze(vehicle, shouldFreeze)
if not vehicle then return end
SetVehicleEngineOn(vehicle, not shouldFreeze, true, true)
FreezeEntityPosition(vehicle, shouldFreeze)
SetEntityCollision(vehicle, not shouldFreeze, not shouldFreeze)
end
local function stopBurnoutPreview()
if not currentVehicle then return end
ClearPedTasks(cache.ped)
SetVehicleTyresCanBurst(currentVehicle, canTyresBeBurst)
SetVehicleCurrentRpm(currentVehicle, 0)
FreezeEntityPosition(currentVehicle, true)
SetEntityCollision(currentVehicle, false, false)
SetVehicleEngineOn(currentVehicle, false, true, true)
isDoingBurnout = false
end
local function revertToOriginalMods()
if not currentVehicle then return end
if isPurchaseFinalized then return end
setVehicleProperties(currentVehicle, originalVehicleProps, true)
end
local function getModSlotName(vehicle, modType)
if type(modType) == "string" then return false end
local label = GetLabelText(GetModSlotName(vehicle, modType))
if label ~= "NULL" then
return label
end
local rawName = GetModSlotName(vehicle, modType)
if rawName and rawName ~= "" then
return rawName
end
return false
end
local function getModName(vehicle, modType, modSlotName, modIndex)
if modType == "LIVERY" then
local label = GetLabelText(GetLiveryName(vehicle, modIndex))
if label ~= "NULL" then
return label
end
end
if type(modType) == "string" then return "ERROR" end
local label = GetLabelText(GetModTextLabel(vehicle, modType, modIndex))
if label ~= "NULL" then
return label
end
local rawLabel = GetModTextLabel(vehicle, modType, modIndex)
if rawLabel and rawLabel ~= "" then
return rawLabel
end
return (modSlotName or "") .. " " .. (modIndex + 1)
end
local function isModInCameraGroup(modGroup, vehicle, modId)
for _, mod in ipairs(modGroup) do
if modId == mod then
return true
elseif type(mod) == "string" and type(modId) == "number" then
local slotName = GetModSlotName(vehicle, modId)
if slotName == mod then
return true
end
end
end
return false
end
local function getAvailableMods(vehicle, originalProps, mechanicId)
local mechanicConfig = Config.MechanicLocations[mechanicId]
local allowedMods = mechanicConfig.mods
if not allowedMods then return false end
if Config.ModsPricesAsPercentageOfVehicleValue then
local vehicleValue = Framework.Client.GetVehicleValue(GetEntityArchetypeName(vehicle))
for modCategory in pairs(allowedMods) do
local categoryData = allowedMods[modCategory]
categoryData.price = round(vehicleValue * (categoryData.percentVehVal or 0.01), 0)
end
end
local vehicleModel = GetEntityModel(vehicle)
SetVehicleModKit(vehicle, 0)
local performanceMods = {}
for _, modInfo in pairs(Config.Mods.Performance) do
local modCount = GetNumVehicleMods(vehicle, modInfo.modType)
if modCount > 0 or modInfo.toggle then
local slotName = getModSlotName(vehicle, modInfo.modType) or modInfo.name
local modsList = { { modIndex = -1, name = "Stock" } }
if modInfo.overrideOptions and type(modInfo.overrideOptions) == "table" then
for _, overrideOption in pairs(modInfo.overrideOptions) do
modsList[#modsList + 1] = {
modIndex = overrideOption.modIndex,
name = overrideOption.name,
price = overrideOption.price or round(allowedMods.performance.price * (1 + overrideOption.modIndex * (allowedMods.performance.priceMult or 0)), 0)
}
end
else
for i = 0, modCount - 1 do
modsList[#modsList + 1] = {
modIndex = i,
name = getModName(vehicle, modInfo.modType, slotName, i),
price = round(allowedMods.performance.price * (i > 0 and (1 + i * (allowedMods.performance.priceMult or 0)) or 1), 0)
}
end
end
performanceMods[#performanceMods + 1] = {
modType = modInfo.modType,
name = slotName,
mods = modsList,
toggle = modInfo.toggle,
price = allowedMods.performance.price
}
end
end
local cosmeticMods = {}
for _, modInfo in pairs(Config.Mods.Cosmetics) do
local slotName = modInfo.name
local ignorePriceMult = modInfo.ignorePriceMult
local options = {}
if modInfo.modType == "PLATE_INDEX" then
if IsThisModelACar(vehicleModel) or IsThisModelAQuadbike(vehicleModel) or IsThisModelABike(vehicleModel) then
for i = 1, #Config.Mods.PlateIndexes do
if i < 6 or GetGameBuildNumber() >= 3095 then
options[#options + 1] = Config.Mods.PlateIndexes[i]
local price = ignorePriceMult and allowedMods.cosmetics.price or round(allowedMods.cosmetics.price * (i > 0 and (1 + i * (allowedMods.cosmetics.priceMult or 0)) or 1), 0)
options[i].price = price
end
end
end
elseif modInfo.modType == "WINDOW_TINT" then
if not IsThisModelABicycle(vehicleModel) then
for i = 1, #Config.Mods.WindowTints do
options[#options + 1] = Config.Mods.WindowTints[i]
local price = ignorePriceMult and allowedMods.cosmetics.price or round(allowedMods.cosmetics.price * (i > 0 and (1 + i * (allowedMods.cosmetics.priceMult or 0)) or 1), 0)
options[i].price = price
end
end
else
local modCount = 0
if modInfo.modType == "LIVERY" then
modCount = GetVehicleLiveryCount(vehicle)
elseif modInfo.modType == "LIVERY_ROOF" then
modCount = GetVehicleRoofLiveryCount(vehicle)
else
modCount = GetNumVehicleMods(vehicle, modInfo.modType)
end
if modCount > 0 or modInfo.toggle then
slotName = getModSlotName(vehicle, modInfo.modType) or slotName or modInfo.name
if modInfo.modType == 14 then
for i = 1, #Config.Mods.Horns do
options[#options + 1] = Config.Mods.Horns[i]
local price = ignorePriceMult and allowedMods.cosmetics.price or round(allowedMods.cosmetics.price * (i > 0 and (1 + i * (allowedMods.cosmetics.priceMult or 0)) or 1), 0)
options[i].price = price
end
else
options = { { modIndex = -1, name = "Stock" } }
for i = 0, modCount - 1 do
local name = Config.UseCustomNamesInTuningMenu and modInfo.name or getModName(vehicle, modInfo.modType, slotName, i)
local price = ignorePriceMult and allowedMods.cosmetics.price or round(allowedMods.cosmetics.price * (i > 0 and (1 + i * (allowedMods.cosmetics.priceMult or 0)) or 1), 0)
options[#options + 1] = {
modIndex = i,
name = name,
price = price
}
end
end
end
end
if #options > 0 then
local displayName = Config.UseCustomNamesInTuningMenu and modInfo.name or slotName
cosmeticMods[#cosmeticMods + 1] = {
modType = modInfo.modType,
name = displayName,
mods = options,
toggle = modInfo.toggle,
price = allowedMods.cosmetics.price
}
end
end
local wheelMods = {}
if IsThisModelACar(vehicleModel) or IsThisModelAQuadbike(vehicleModel) or IsThisModelABike(vehicleModel) then
for _, wheelType in ipairs(Config.Mods.WheelTypes) do
local isCorrectVehicleType = (IsThisModelACar(vehicleModel) or IsThisModelAQuadbike(vehicleModel)) or (IsThisModelABike(vehicleModel) and wheelType.modIndex == 6)
if isCorrectVehicleType then
SetVehicleWheelType(vehicle, wheelType.modIndex)
local modCount = GetNumVehicleMods(vehicle, 23)
if modCount > 0 then
local options = { { modIndex = -1, name = "Stock" } }
for i = 0, modCount - 1 do
options[#options + 1] = {
modIndex = i,
name = getModName(vehicle, 23, wheelType.name, i),
price = round(allowedMods.wheels.price * (i > 0 and (1 + i * (allowedMods.wheels.priceMult or 0)) or 1), 0)
}
end
wheelMods[#wheelMods + 1] = {
modType = wheelType.modIndex,
name = wheelType.name,
mods = options
}
end
end
end
end
SetVehicleWheelType(vehicle, originalProps.wheels)
if originalProps.modFrontWheels then
SetVehicleMod(vehicle, 23, originalProps.modFrontWheels, originalProps.modCustomTiresF)
end
if originalProps.modBackWheels then
SetVehicleMod(vehicle, 24, originalProps.modBackWheels, originalProps.modCustomTiresR)
end
local modCategories = {}
if allowedMods.repair and allowedMods.repair.enabled then modCategories.repair = allowedMods.repair end
if allowedMods.performance and allowedMods.performance.enabled and #performanceMods > 0 then modCategories.performance = performanceMods end
if allowedMods.cosmetics and allowedMods.cosmetics.enabled and #cosmeticMods > 0 then modCategories.cosmetics = cosmeticMods end
if IsThisModelACar(vehicleModel) and allowedMods.stance and allowedMods.stance.enabled then modCategories.stance = allowedMods.stance end
if allowedMods.respray and allowedMods.respray.enabled and #Config.Mods.Colours > 0 then
modCategories.respray = { price = allowedMods.respray.price, colours = Config.Mods.Colours }
end
if allowedMods.wheels and allowedMods.wheels.enabled and #wheelMods > 0 then modCategories.wheels = wheelMods end
if allowedMods.neonLights then
if (IsThisModelACar(vehicleModel) or IsThisModelAQuadbike(vehicleModel)) and allowedMods.neonLights.enabled then
modCategories.neonLights = allowedMods.neonLights
else
modCategories.neonLights = { enabled = false, price = 0 }
end
end
if allowedMods.headlights then
if not IsThisModelABicycle(vehicleModel) and allowedMods.headlights.enabled then
modCategories.headlights = allowedMods.headlights
else
modCategories.headlights = { enabled = false, price = 0 }
end
end
if (IsThisModelACar(vehicleModel) or IsThisModelABike(vehicleModel) or IsThisModelAQuadbike(vehicleModel)) and allowedMods.tyreSmoke and allowedMods.tyreSmoke.enabled then
modCategories.tyreSmoke = allowedMods.tyreSmoke
end
if (IsThisModelACar(vehicleModel) or IsThisModelABike(vehicleModel) or IsThisModelAQuadbike(vehicleModel)) and allowedMods.bulletproofTyres and allowedMods.bulletproofTyres.enabled then
modCategories.bulletproofTyres = allowedMods.bulletproofTyres
end
if allowedMods.extras and allowedMods.extras.enabled and next(originalProps.extras) ~= nil then
modCategories.extras = true
end
return modCategories
end
function closeModsMenu()
if currentVehicle then
toggleVehicleFreeze(currentVehicle, false)
revertToOriginalMods()
Entity(currentVehicle).state:set("unpaidModifications", false, true)
end
SetNuiFocusKeepInput(false)
Framework.Client.ToggleHud(true)
LocalPlayer.state:set("isBusy", false, true)
appliedMods = {
repair = {},
performance = {},
cosmetics = {},
stance = {},
respray = {},
wheels = {},
neonLights = {},
headlights = {},
tyreSmoke = {},
bulletproofTyres = {},
extras = {}
}
isMenuOpen = false
currentVehicle = nil
originalVehicleProps = nil
isPurchaseFinalized = false
end
function openModsMenu(mechId, mechLabel)
local mechanicConfig = Config.MechanicLocations[mechId]
if not mechanicConfig then return false end
currentMechanicId = mechId
if not cache.vehicle then return false end
currentVehicle = cache.vehicle
if GetPedInVehicleSeat(currentVehicle, -1) ~= cache.ped then
Framework.Client.Notify(Locale.notInDriversSeat, "error")
currentVehicle = nil
return false
end
local health = {
GetVehicleBodyHealth(currentVehicle),
GetVehicleEngineHealth(currentVehicle)
}
local props = getVehicleProperties(currentVehicle, true)
if not props then error("Could not get the vehicle's props") end
originalVehicleProps = props
local plate = Framework.Client.GetPlate(currentVehicle)
if not plate then error("Could not get the vehicle's plate") end
vehiclePlate = plate
canTyresBeBurst = not props.bulletProofTyres
props.windowTint = math.max(props.windowTint, 0)
local mods = getAvailableMods(currentVehicle, props, mechId)
if not mods then return false end
for i = 0, 5 do
if GetPedInVehicleSeat(currentVehicle, i) ~= 0 then
Framework.Client.Notify(Locale.passengersMustLeaveVehicleFirst, "error")
return false
end
end
toggleVehicleFreeze(currentVehicle, true)
SetVehicleModKit(currentVehicle, 0)
setupVehicleCamera(currentVehicle)
if Config.ChangePlateDuringPreview then
lib.callback.await("jg-mechanic:server:open-mods-menu", false, VehToNet(currentVehicle))
end
local isMechanicEmployee = lib.callback.await("jg-mechanic:server:is-mechanic-employee", false, mechId)
local mechanicBalance = isMechanicEmployee and lib.callback.await("jg-mechanic:server:get-mechanic-balance", false, mechId) or false
local mechanicsOnDuty = lib.callback.await("jg-mechanic:server:count-currently-on-duty", false, mechId)
local mechanicType = mechanicConfig.type ~= "self-service" and not (Config.MechanicEmployeesCanSelfServiceMods and isMechanicEmployee) and "owned" or "self-service"
LocalPlayer.state:set("isBusy", true, true)
Framework.Client.ToggleHud(false)
SetNuiFocus(true, true)
SendNUIMessage({
type = "show-vehicle-tuning",
logo = mechanicConfig.logo,
mechanicId = mechId,
name = mechLabel or (mechLabel == "" and mechId or mechLabel),
mechanicType = mechanicType,
mechanicsOnDuty = mechanicsOnDuty,
isMechanicEmployee = isMechanicEmployee,
mechBalance = isMechanicEmployee and mechanicType == "self-service" and mechanicBalance or false,
bankBalance = Framework.Client.GetBalance("bank"),
cashBalance = Framework.Client.GetBalance("cash"),
changeCamBtn = parseControlBinding(0),
vehicleDamaged = health,
props = props,
mods = mods,
config = Config,
locale = Locale
})
return true
end
RegisterNetEvent("jg-mechanic:client:open-customisation-menu", openModsMenu)
onEnterModsZone = function(mechId, mechLabel)
if not cache.vehicle then return false end
CreateThread(function()
currentMechanicId = mechId
while currentMechanicId do
Wait(0)
if not isMenuOpen and not isPromptShowing then
Framework.Client.ShowTextUI(Config.CustomiseVehiclePrompt)
isPromptShowing = true
end
if IsControlJustPressed(0, Config.CustomiseVehicleKey) and not isMenuOpen then
if openModsMenu(currentMechanicId, mechLabel) then
isMenuOpen = true
isPromptShowing = false
Framework.Client.HideTextUI()
end
end
end
end)
end
onExitModsZone = function()
currentMechanicId = nil
closeModsMenu()
SetTimeout(1, function()
Framework.Client.HideTextUI()
isPromptShowing = false
end)
end
RegisterNUICallback("purchase-mods", function(data, cb)
if not (currentMechanicId and currentVehicle and originalVehicleProps and currentVehicle) then
return cb({ error = true })
end
local cart = data.cart
local paymentMethod = data.paymentMethod
if not cart or type(cart) ~= "table" then
return cb({ error = true })
end
local mechanicConfig = Config.MechanicLocations[currentMechanicId]
if not mechanicConfig then
return cb({ error = false })
end
local currentProps = getVehicleProperties(currentVehicle, true)
currentProps.plate = vehiclePlate
if not currentProps then
return cb({ error = false })
end
local vehicleValue = Framework.Client.GetVehicleValue(GetEntityArchetypeName(currentVehicle))
local amountPaid = lib.callback.await("jg-mechanic:server:purchase-mods", false, currentMechanicId, vehicleValue, cart, paymentMethod)
if amountPaid == false then
return cb({ error = true })
end
amountPaid = tonumber(amountPaid) or 0
local isMechanicEmployee = lib.callback.await("jg-mechanic:server:is-mechanic-employee", false, currentMechanicId)
if mechanicConfig.type == "self-service" or (Config.MechanicEmployeesCanSelfServiceMods and isMechanicEmployee) then
toggleVehicleFreeze(currentVehicle, false)
local combinedMods = {}
for _, category in pairs(appliedMods) do
combinedMods = tableConcat(combinedMods, category)
end
setStatebagsFromProps(currentVehicle, combinedMods, vehiclePlate)
lib.callback.await("jg-mechanic:server:save-veh-statebag-data-to-db", false, vehiclePlate)
isPurchaseFinalized = true
lib.callback.await("jg-mechanic:server:self-service-mods-applied", false, currentMechanicId, VehToNet(currentVehicle), vehiclePlate, cart, amountPaid, paymentMethod)
if Config.UpdatePropsOnChange then
lib.callback.await("jg-mechanic:server:save-vehicle-props", false, vehiclePlate, currentProps)
end
if originalVehicleProps and currentProps then
originalVehicleProps.wheels = currentProps.wheels
originalVehicleProps.modFrontWheels = currentProps.modFrontWheels
originalVehicleProps.modBackWheels = currentProps.modBackWheels
end
else
local orderPlaced = lib.callback.await("jg-mechanic:server:place-order", false, currentMechanicId, vehiclePlate, cart, amountPaid, appliedMods, paymentMethod)
if not orderPlaced then
return cb({ error = true })
end
end
cb(true)
end)
RegisterNUICallback("exit-mods", function(data, cb)
closeModsMenu()
cb(true)
end)
RegisterNUICallback("switch-camera", function(data, cb)
if not currentVehicle then return cb(false) end
local modId = data and data.modId
CreateThread(function()
SetVehicleDoorsShut(currentVehicle, true)
if IsVehicleDoorDamaged(currentVehicle, 4) then
SetVehicleFixed(currentVehicle)
end
stopBurnoutPreview()
if isModInCameraGroup({ "TOP_HL_CV", "TOP_HLT", "TOP_SUNST", "HEADLIGHTS", "TOP_SPLIT" }, currentVehicle, modId) then
transitionCamera("frontCamera")
elseif isModInCameraGroup({ "TOP_TRUNK", "TOP_BOOT", "TOP_TGATE", "TOP_RPNL", "TOP_WINP", "TOP_WBAR", "TOP_COVER", "TOP_LOUV" }, currentVehicle, modId) then
transitionCamera("backCamera")
elseif isModInCameraGroup({ "TOP_CAGE" }, currentVehicle, modId) then
transitionCamera("interior")
elseif isModInCameraGroup({ "TOP_ROOFSC", "TOP_ROOFFIN" }, currentVehicle, modId) then
transitionCamera("roof")
elseif isModInCameraGroup({ "TOP_VALHD", "TOP_ENGHD" }, currentVehicle, modId) then
transitionCamera("backCamera")
SetVehicleDoorOpen(currentVehicle, 4, false, true)
elseif isModInCameraGroup({ "TOP_SIDE_PAN", "TOP_MIR" }, currentVehicle, modId) then
transitionCamera("sideCamera")
elseif isModInCameraGroup({ "TOP_CATCH" }, currentVehicle, modId) then
transitionCamera("engineBay")
elseif isModInCameraGroup({ "TOP_ENGINE", "TOP_BRACE", "TOP_ENGD" }, currentVehicle, modId) then
transitionCamera("engineBay")
if GetEntityArchetypeName(currentVehicle) == "z190" then
SetVehicleDoorBroken(currentVehicle, 4, true)
end
SetVehicleDoorOpen(currentVehicle, 4, false, true)
elseif isModInCameraGroup({ 1, 6, 26, 42, 43 }, currentVehicle, modId) then
transitionCamera("frontCamera")
elseif isModInCameraGroup({ 37 }, currentVehicle, modId) then
transitionCamera("backCamera")
SetVehicleDoorOpen(currentVehicle, 5, false, true)
elseif isModInCameraGroup({ 5, 27, 32, "COLOR_INTERIOR" }, currentVehicle, modId) then
transitionCamera("interior")
elseif isModInCameraGroup({ 4 }, currentVehicle, modId) then
transitionCamera("exhaust")
elseif isModInCameraGroup({ 0, 2, 4, 25, "PLATE_INDEX" }, currentVehicle, modId) then
transitionCamera("backCamera")
elseif isModInCameraGroup({ 3, 8, 23, 24, "WHEELS" }, currentVehicle, modId) then
transitionCamera("sideCamera")
elseif isModInCameraGroup({ 7 }, currentVehicle, modId) then
transitionCamera("engineBay")
elseif isModInCameraGroup({ 39, 40, 41 }, currentVehicle, modId) then
transitionCamera("engineBay")
if GetEntityArchetypeName(currentVehicle) == "banshee2" then
SetVehicleDoorBroken(currentVehicle, 4, true)
end
SetVehicleDoorOpen(currentVehicle, 4, false, true)
elseif isModInCameraGroup({ 31 }, currentVehicle, modId) then
transitionCamera("doorSpeaker")
elseif isModInCameraGroup({ 28, 29, 30, 33, 34, "COLOR_DASHBOARD" }, currentVehicle, modId) then
transitionCamera("pov")
else
transitionCamera("default")
end
cb(true)
end)
end)
RegisterNUICallback("toggle-freecam", function(data, cb)
if data.enable then
isFreecamActive = true
toggleCamTemporarily(false)
else
toggleCamTemporarily(true)
isFreecamActive = false
end
cb(true)
end)
RegisterNUICallback("move-freecam", function(data, cb)
if not isFreecamActive then return cb(false) end
SetNuiFocus(true, false)
SetNuiFocusKeepInput(true)
CreateThread(function()
while isFreecamActive do
DisableAllControlActions(0)
EnableControlAction(0, 0, false)
EnableControlAction(0, 1, true)
EnableControlAction(0, 2, true)
EnableControlAction(0, 59, true)
Wait(0)
end
end)
cb(true)
end)
RegisterNUICallback("stop-moving-freecam", function(data, cb)
SetNuiFocus(true, true)
SetNuiFocusKeepInput(false)
cb(true)
end)
RegisterNUICallback("repair-vehicle", function(data, cb)
if not (currentVehicle and currentVehicle) then
return cb(false)
end
local vehicleValue = Framework.Client.GetVehicleValue(GetEntityArchetypeName(currentVehicle))
local success = lib.callback.await("jg-mechanic:server:self-service-repair-vehicle", false, currentMechanicId, vehicleValue, data and data.paymentMethod)
if success then
Framework.Client.RepairVehicle(currentVehicle)
if originalVehicleProps then
originalVehicleProps.dirtLevel = 0.0
originalVehicleProps.engineHealth = 1000.0
originalVehicleProps.bodyHealth = 1000.0
originalVehicleProps.tankHealth = 1000.0
originalVehicleProps.windowStatus = nil
originalVehicleProps.doorStatus = nil
originalVehicleProps.tireHealth = nil
originalVehicleProps.tireBurstState = nil
originalVehicleProps.tireBurstCompletely = nil
originalVehicleProps.windowsBroken = nil
originalVehicleProps.doorsBroken = nil
originalVehicleProps.tyreBurst = nil
end
end
cb(true)
end)
RegisterNUICallback("preview-performance-mod", function(data, cb)
if not currentVehicle then return cb(false) end
Entity(currentVehicle).state:set("unpaidModifications", true, true)
local propKey = data.propKey
local modType = data.modType
local modIndex = data.modIndex
local toggleMod = data.toggleMod
SetVehicleModKit(currentVehicle, 0)
if toggleMod then
ToggleVehicleMod(currentVehicle, modType, modIndex)
appliedMods.performance[propKey] = modIndex
elseif type(modType) == "number" then
SetVehicleMod(currentVehicle, modType, modIndex, false)
appliedMods.performance[propKey] = modIndex
end
cb(true)
end)
RegisterNUICallback("preview-cosmetic-mod", function(data, cb)
if not currentVehicle then return cb(false) end
Entity(currentVehicle).state:set("unpaidModifications", true, true)
local propKey = data.propKey
local modType = data.modType
local modIndex = data.modIndex
local toggleMod = data.toggleMod
SetVehicleModKit(currentVehicle, 0)
if modType == "LIVERY" then
SetVehicleLivery(currentVehicle, modIndex)
elseif modType == "LIVERY_ROOF" then
SetVehicleRoofLivery(currentVehicle, modIndex)
elseif modType == "PLATE_INDEX" then
SetVehicleNumberPlateTextIndex(currentVehicle, modIndex)
elseif modType == "WINDOW_TINT" then
SetVehicleWindowTint(currentVehicle, modIndex)
elseif modType == 14 then
SetVehicleMod(currentVehicle, 14, modIndex, false)
Citizen.CreateThreadNow(function()
if isHornLoopActive then
isHornLoopActive = false
Wait(10)
end
isHornLoopActive = true
local duration = Config.Mods.Horns[modIndex + 2].musical and 750 or 100
while duration > 1 do
if not isHornLoopActive then break end
SetControlNormal(0, 86, 1.0)
Wait(1)
duration = duration - 1
end
end)
elseif toggleMod then
ToggleVehicleMod(currentVehicle, modType, modIndex)
elseif type(modType) == "number" then
SetVehicleMod(currentVehicle, modType, modIndex, false)
end
appliedMods.cosmetics[propKey] = modIndex
cb(true)
end)
RegisterNUICallback("preview-wheels", function(data, cb)
if not currentVehicle then return cb(false) end
Entity(currentVehicle).state:set("unpaidModifications", true, true)
SetVehicleModKit(currentVehicle, 0)
SetVehicleWheelType(currentVehicle, data.modType)
appliedMods.wheels.wheels = data.modType
SetVehicleMod(currentVehicle, 23, data.modIndex, false)
appliedMods.wheels.modFrontWheels = data.modIndex
if IsThisModelABike(GetEntityModel(currentVehicle)) then
SetVehicleMod(currentVehicle, 24, data.modIndex, false)
appliedMods.wheels.modBackWheels = data.modIndex
end
appliedMods.wheels.wheelWidth = GetVehicleWheelWidth(currentVehicle)
appliedMods.wheels.wheelSize = GetVehicleWheelSize(currentVehicle)
cb(true)
end)
RegisterNUICallback("preview-pri-sec-colours", function(data, cb)
if not currentVehicle then return cb(false) end
Entity(currentVehicle).state:set("unpaidModifications", true, true)
SetVehicleModKit(currentVehicle, 0)
Entity(currentVehicle).state:set("primarySecondarySync", data.primarySecondarySync)
appliedMods.respray.primarySecondarySync = data.primarySecondarySync
if data.paintTypeKey == "paintType1" then
if data.enableRgb then
SetVehicleModColor_1(currentVehicle, data.paint, 0, 0)
SetVehicleCustomPrimaryColour(currentVehicle, data.rgbColour[1], data.rgbColour[2], data.rgbColour[3])
appliedMods.respray.color1 = data.rgbColour
else
local _, sec = GetVehicleColours(currentVehicle)
SetVehicleColours(currentVehicle, data.colourId, sec)
ClearVehicleCustomPrimaryColour(currentVehicle)
appliedMods.respray.color1 = data.colourId
end
appliedMods.respray.paintType1 = data.paint
end
if data.paintTypeKey == "paintType2" or data.primarySecondarySync then
if data.enableRgb then
SetVehicleModColor_2(currentVehicle, data.paint, 0)
SetVehicleCustomSecondaryColour(currentVehicle, data.rgbColour[1], data.rgbColour[2], data.rgbColour[3])
appliedMods.respray.color2 = data.rgbColour
else
local pri, _ = GetVehicleColours(currentVehicle)
SetVehicleColours(currentVehicle, pri, data.colourId)
ClearVehicleCustomSecondaryColour(currentVehicle)
appliedMods.respray.color2 = data.colourId
end
appliedMods.respray.paintType2 = data.paint
end
cb(true)
end)
RegisterNUICallback("preview-other-colours", function(data, cb)
if not currentVehicle then return cb(false) end
Entity(currentVehicle).state:set("unpaidModifications", true, true)
SetVehicleModKit(currentVehicle, 0)
if data.colourIdKey == "dashboardColor" then
SetVehicleDashboardColor(currentVehicle, data.colourId)
elseif data.colourIdKey == "interiorColor" then
SetVehicleInteriorColor(currentVehicle, data.colourId)
else
local pearl, wheel = GetVehicleExtraColours(currentVehicle)
if data.colourIdKey == "pearlescentColor" then
SetVehicleExtraColours(currentVehicle, data.colourId, wheel)
local disablePearl = data.disablePearl or false
Entity(currentVehicle).state:set("disablePearl", disablePearl)
appliedMods.respray.disablePearl = disablePearl
end
if data.colourIdKey == "wheelColor" then
SetVehicleExtraColours(currentVehicle, pearl, data.colourId)
end
end
appliedMods.respray[data.colourIdKey] = data.colourId
cb(true)
end)
RegisterNUICallback("preview-xenons", function(data, cb)
if not currentVehicle then return cb(false) end
Entity(currentVehicle).state:set("unpaidModifications", true, true)
SetVehicleModKit(currentVehicle, 0)
ToggleVehicleMod(currentVehicle, 22, data.enableXenons)
SetVehicleLights(currentVehicle, 2)
SetVehicleXenonLightsColor(currentVehicle, data.xenonColor)
appliedMods.headlights.modXenon = true
appliedMods.headlights.xenonColor = data.xenonColor
cb(true)
end)
RegisterNUICallback("preview-neons", function(data, cb)
if not currentVehicle then return cb(false) end
Entity(currentVehicle).state:set("unpaidModifications", true, true)
SetVehicleModKit(currentVehicle, 0)
for i = 0, 3 do
SetVehicleNeonLightEnabled(currentVehicle, i, data.enableNeons[i + 1])
end
SetVehicleNeonLightsColour(currentVehicle, data.neonColor[1], data.neonColor[2], data.neonColor[3])
appliedMods.neonLights.neonEnabled = data.enableNeons
appliedMods.neonLights.neonColor = data.neonColor
cb(true)
end)
RegisterNUICallback("preview-tyre-smoke", function(data, cb)
if not currentVehicle then return cb(false) end
Entity(currentVehicle).state:set("unpaidModifications", true, true)
if isDoingBurnout and not data.enableTyreSmoke then
stopBurnoutPreview()
end
if not isDoingBurnout and data.enableTyreSmoke then
CreateThread(function()
isDoingBurnout = true
if canTyresBeBurst then
SetVehicleTyresCanBurst(currentVehicle, false)
end
SetVehicleEngineOn(currentVehicle, true, true, true)
SetEntityCollision(currentVehicle, true, true)
FreezeEntityPosition(currentVehicle, false)
TaskVehicleTempAction(cache.ped, currentVehicle, 30, 999999)
end)
end
SetVehicleModKit(currentVehicle, 0)
ToggleVehicleMod(currentVehicle, 20, data.enableTyreSmoke)
SetVehicleTyreSmokeColor(currentVehicle, data.tyreSmokeColor[1], data.tyreSmokeColor[2], data.tyreSmokeColor[3])
appliedMods.tyreSmoke.modSmokeEnabled = data.enableTyreSmoke
appliedMods.tyreSmoke.tyreSmokeColor = data.tyreSmokeColor
cb(true)
end)
RegisterNUICallback("preview-bulletproof-tyres", function(data, cb)
if not currentVehicle then return cb(false) end
Entity(currentVehicle).state:set("unpaidModifications", true, true)
local canBurst = not data.enableBulletproofTyres
SetVehicleTyresCanBurst(currentVehicle, canBurst)
canTyresBeBurst = canBurst
appliedMods.bulletproofTyres.bulletProofTyres = data.enableBulletproofTyres
cb(true)
end)
RegisterNUICallback("preview-extras", function(data, cb)
if not currentVehicle then return cb(false) end
Entity(currentVehicle).state:set("unpaidModifications", true, true)
for extraId, enabled in pairs(data.extras) do
SetVehicleExtra(currentVehicle, tonumber(extraId), not enabled)
end
appliedMods.extras.extras = data.extras
cb(true)
end)
RegisterNUICallback("preview-stance", function(data, cb)
if not currentVehicle then return cb(false) end
Entity(currentVehicle).state:set("unpaidModifications", true, true)
previewVehicleStance(currentVehicle, data.enableStance, data.defaultStance, data.stance)
PreviewingNewStance = true
cb(true)
end)
RegisterNUICallback("save-previewed-stance", function(data, cb)
if not currentVehicle then return cb(false) end
Entity(currentVehicle).state:set("unpaidModifications", true, true)
setStanceState(currentVehicle, data.enableStance, data.wheelsAdjIndv, data.defaultStance, data.stance)
PreviewingNewStance = false
appliedMods.stance.enableStance = data.enableStance
appliedMods.stance.wheelsAdjIndv = data.wheelsAdjIndv
appliedMods.stance.defaultStance = data.defaultStance
appliedMods.stance.stance = data.stance
cb(true)
end)
AddEventHandler("onResourceStop", function(resourceName)
if GetCurrentResourceName() == resourceName then
if currentVehicle then
revertToOriginalMods()
Entity(currentVehicle).state:set("unpaidModifications", false, true)
toggleVehicleFreeze(currentVehicle, false)
end
end
end)