lc_fuel update
This commit is contained in:
		
							parent
							
								
									e9335eaf78
								
							
						
					
					
						commit
						cae0aa5e6a
					
				
					 28 changed files with 6064 additions and 5968 deletions
				
			
		
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							| 
						 | 
				
			
			@ -1,153 +1,153 @@
 | 
			
		|||
-- Do not load anything here if electric is disabled
 | 
			
		||||
if not Config.Electric.enabled then
 | 
			
		||||
    return
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
local electricChargers = {}
 | 
			
		||||
 | 
			
		||||
-----------------------------------------------------------------------------------------------------------------------------------------
 | 
			
		||||
-- Threads
 | 
			
		||||
-----------------------------------------------------------------------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
-- Create sphere zones for each station, hooking up onEnter/onExit
 | 
			
		||||
function createElectricZones()
 | 
			
		||||
    assert(Utils.Zones, "You are using an outdated version of lc_utils. Please update your 'lc_utils' script to the latest version: https://github.com/LeonardoSoares98/lc_utils/releases/latest/download/lc_utils.zip")
 | 
			
		||||
 | 
			
		||||
    local stations = groupChargersByStation()
 | 
			
		||||
 | 
			
		||||
    for _, station in pairs(stations) do
 | 
			
		||||
        Utils.Zones.createZone({
 | 
			
		||||
            coords = station.center,
 | 
			
		||||
            radius = 50.0,
 | 
			
		||||
            onEnter = function()
 | 
			
		||||
                for _, charger in pairs(station.chargers) do
 | 
			
		||||
                    loadElectricCharger(charger)
 | 
			
		||||
                end
 | 
			
		||||
            end,
 | 
			
		||||
            onExit = function()
 | 
			
		||||
                for _, charger in pairs(station.chargers) do
 | 
			
		||||
                    unloadElectricCharger(charger)
 | 
			
		||||
                end
 | 
			
		||||
            end
 | 
			
		||||
        })
 | 
			
		||||
    end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
-- Thread to detect near electric chargers
 | 
			
		||||
function createElectricMarkersThread()
 | 
			
		||||
    CreateThread(function()
 | 
			
		||||
        while true do
 | 
			
		||||
            local ped = PlayerPedId()
 | 
			
		||||
            local playerCoords = GetEntityCoords(ped)
 | 
			
		||||
            local pump, pumpModel = GetClosestPump(playerCoords, true)
 | 
			
		||||
 | 
			
		||||
            while pump and pump > 0 and #(playerCoords - GetEntityCoords(pump)) < 2.0 do
 | 
			
		||||
                playerCoords = GetEntityCoords(ped)
 | 
			
		||||
                if not mainUiOpen and not DoesEntityExist(fuelNozzle) then
 | 
			
		||||
                    Utils.Markers.showHelpNotification(cachedTranslations.open_recharge, true)
 | 
			
		||||
                    if IsControlJustPressed(0,38) then
 | 
			
		||||
                        clientOpenUI(pump, pumpModel, true)
 | 
			
		||||
                    end
 | 
			
		||||
                end
 | 
			
		||||
                Wait(2)
 | 
			
		||||
            end
 | 
			
		||||
            Wait(1000)
 | 
			
		||||
        end
 | 
			
		||||
    end)
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
function createElectricTargetsThread()
 | 
			
		||||
    local pumpModels = {}  -- This will be the final list without duplicates
 | 
			
		||||
    local seenModels = {}  -- This acts as a set to track unique values
 | 
			
		||||
 | 
			
		||||
    for _, chargerData in pairs(Config.Electric.chargersLocation) do
 | 
			
		||||
        local model = chargerData.prop
 | 
			
		||||
        if not seenModels[model] then
 | 
			
		||||
            seenModels[model] = true  -- Mark model as seen
 | 
			
		||||
            table.insert(pumpModels, model)  -- Insert only if it's not a duplicate
 | 
			
		||||
        end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    -- Pass unique models to the target creation function
 | 
			
		||||
    Utils.Target.createTargetForModel(pumpModels, openElectricUICallback, Utils.translate('target.open_recharge'), "fas fa-plug", "#00a413",nil,nil,canOpenPumpUiTargetCallback)
 | 
			
		||||
 | 
			
		||||
    Utils.Target.createTargetForModel(pumpModels,returnNozzle,Utils.translate('target.return_nozzle'),"fas fa-plug","#a42100",nil,nil,canReturnNozzleTargetCallback)
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
function openElectricUICallback()
 | 
			
		||||
    local ped = PlayerPedId()
 | 
			
		||||
    local playerCoords = GetEntityCoords(ped)
 | 
			
		||||
    local pump, pumpModel = GetClosestPump(playerCoords, true)
 | 
			
		||||
    if pump then
 | 
			
		||||
        clientOpenUI(pump, pumpModel, true)
 | 
			
		||||
    else
 | 
			
		||||
        exports['lc_utils']:notify("error", Utils.translate("pump_not_found"))
 | 
			
		||||
    end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
-----------------------------------------------------------------------------------------------------------------------------------------
 | 
			
		||||
-- Utils
 | 
			
		||||
-----------------------------------------------------------------------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
function loadElectricCharger(chargerData)
 | 
			
		||||
    if not electricChargers[chargerData.location] then
 | 
			
		||||
        RequestModel(chargerData.prop)
 | 
			
		||||
        while not HasModelLoaded(chargerData.prop) do
 | 
			
		||||
            Wait(10)
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        local heading = chargerData.location.w + 180.0
 | 
			
		||||
        local electricCharger = CreateObject(chargerData.prop, chargerData.location.x, chargerData.location.y, chargerData.location.z, false, true, true)
 | 
			
		||||
        SetEntityHeading(electricCharger, heading)
 | 
			
		||||
        FreezeEntityPosition(electricCharger, true)
 | 
			
		||||
 | 
			
		||||
        electricChargers[chargerData.location] = electricCharger
 | 
			
		||||
    end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
function unloadElectricCharger(chargerData)
 | 
			
		||||
    local charger = electricChargers[chargerData.location]
 | 
			
		||||
    if charger and DoesEntityExist(charger) then
 | 
			
		||||
        DeleteEntity(charger)
 | 
			
		||||
        electricChargers[chargerData.location] = nil
 | 
			
		||||
    end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
-- Utility to group chargers by their station
 | 
			
		||||
function groupChargersByStation()
 | 
			
		||||
    local stations = {}
 | 
			
		||||
    for _, charger in pairs(Config.Electric.chargersLocation) do
 | 
			
		||||
        local assigned = false
 | 
			
		||||
        for _, station in pairs(stations) do
 | 
			
		||||
            local dist = #(station.center - vector3(charger.location.x, charger.location.y, charger.location.z))
 | 
			
		||||
            if dist < 20.0 then
 | 
			
		||||
                table.insert(station.chargers, charger)
 | 
			
		||||
                station.center = (station.center + vector3(charger.location.x, charger.location.y, charger.location.z)) / 2
 | 
			
		||||
                assigned = true
 | 
			
		||||
                break
 | 
			
		||||
            end
 | 
			
		||||
        end
 | 
			
		||||
        if not assigned then
 | 
			
		||||
            table.insert(stations, {
 | 
			
		||||
                center = vector3(charger.location.x, charger.location.y, charger.location.z),
 | 
			
		||||
                chargers = { charger }
 | 
			
		||||
            })
 | 
			
		||||
        end
 | 
			
		||||
    end
 | 
			
		||||
    return stations
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
AddEventHandler('onResourceStop', function(resourceName)
 | 
			
		||||
    if GetCurrentResourceName() ~= resourceName then return end
 | 
			
		||||
 | 
			
		||||
    deleteAllElectricChargers()
 | 
			
		||||
end)
 | 
			
		||||
 | 
			
		||||
function deleteAllElectricChargers()
 | 
			
		||||
    for _, charger in pairs(electricChargers) do
 | 
			
		||||
        if DoesEntityExist(charger) then
 | 
			
		||||
            DeleteEntity(charger)
 | 
			
		||||
        end
 | 
			
		||||
    end
 | 
			
		||||
    electricChargers = {}
 | 
			
		||||
-- Do not load anything here if electric is disabled
 | 
			
		||||
if not Config.Electric.enabled then
 | 
			
		||||
    return
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
local electricChargers = {}
 | 
			
		||||
 | 
			
		||||
-----------------------------------------------------------------------------------------------------------------------------------------
 | 
			
		||||
-- Threads
 | 
			
		||||
-----------------------------------------------------------------------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
-- Create sphere zones for each station, hooking up onEnter/onExit
 | 
			
		||||
function createElectricZones()
 | 
			
		||||
    assert(Utils.Zones, "You are using an outdated version of lc_utils. Please update your 'lc_utils' script to the latest version: https://github.com/LeonardoSoares98/lc_utils/releases/latest/download/lc_utils.zip")
 | 
			
		||||
 | 
			
		||||
    local stations = groupChargersByStation()
 | 
			
		||||
 | 
			
		||||
    for _, station in pairs(stations) do
 | 
			
		||||
        Utils.Zones.createZone({
 | 
			
		||||
            coords = station.center,
 | 
			
		||||
            radius = 50.0,
 | 
			
		||||
            onEnter = function()
 | 
			
		||||
                for _, charger in pairs(station.chargers) do
 | 
			
		||||
                    loadElectricCharger(charger)
 | 
			
		||||
                end
 | 
			
		||||
            end,
 | 
			
		||||
            onExit = function()
 | 
			
		||||
                for _, charger in pairs(station.chargers) do
 | 
			
		||||
                    unloadElectricCharger(charger)
 | 
			
		||||
                end
 | 
			
		||||
            end
 | 
			
		||||
        })
 | 
			
		||||
    end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
-- Thread to detect near electric chargers
 | 
			
		||||
function createElectricMarkersThread()
 | 
			
		||||
    CreateThread(function()
 | 
			
		||||
        while true do
 | 
			
		||||
            local ped = PlayerPedId()
 | 
			
		||||
            local playerCoords = GetEntityCoords(ped)
 | 
			
		||||
            local pump, pumpModel = GetClosestPump(playerCoords, true)
 | 
			
		||||
 | 
			
		||||
            while pump and pump > 0 and #(playerCoords - GetEntityCoords(pump)) < 2.0 do
 | 
			
		||||
                playerCoords = GetEntityCoords(ped)
 | 
			
		||||
                if not mainUiOpen and not DoesEntityExist(fuelNozzle) then
 | 
			
		||||
                    Utils.Markers.showHelpNotification(cachedTranslations.open_recharge, true)
 | 
			
		||||
                    if IsControlJustPressed(0,38) then
 | 
			
		||||
                        clientOpenUI(pump, pumpModel, true)
 | 
			
		||||
                    end
 | 
			
		||||
                end
 | 
			
		||||
                Wait(2)
 | 
			
		||||
            end
 | 
			
		||||
            Wait(1000)
 | 
			
		||||
        end
 | 
			
		||||
    end)
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
function createElectricTargetsThread()
 | 
			
		||||
    local pumpModels = {}  -- This will be the final list without duplicates
 | 
			
		||||
    local seenModels = {}  -- This acts as a set to track unique values
 | 
			
		||||
 | 
			
		||||
    for _, chargerData in pairs(Config.Electric.chargersLocation) do
 | 
			
		||||
        local model = chargerData.prop
 | 
			
		||||
        if not seenModels[model] then
 | 
			
		||||
            seenModels[model] = true  -- Mark model as seen
 | 
			
		||||
            table.insert(pumpModels, model)  -- Insert only if it's not a duplicate
 | 
			
		||||
        end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    -- Pass unique models to the target creation function
 | 
			
		||||
    Utils.Target.createTargetForModel(pumpModels, openElectricUICallback, Utils.translate('target.open_recharge'), "fas fa-plug", "#00a413",nil,nil,canOpenPumpUiTargetCallback)
 | 
			
		||||
 | 
			
		||||
    Utils.Target.createTargetForModel(pumpModels,returnNozzle,Utils.translate('target.return_nozzle'),"fas fa-plug","#a42100",nil,nil,canReturnNozzleTargetCallback)
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
function openElectricUICallback()
 | 
			
		||||
    local ped = PlayerPedId()
 | 
			
		||||
    local playerCoords = GetEntityCoords(ped)
 | 
			
		||||
    local pump, pumpModel = GetClosestPump(playerCoords, true)
 | 
			
		||||
    if pump then
 | 
			
		||||
        clientOpenUI(pump, pumpModel, true)
 | 
			
		||||
    else
 | 
			
		||||
        exports['lc_utils']:notify("error", Utils.translate("pump_not_found"))
 | 
			
		||||
    end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
-----------------------------------------------------------------------------------------------------------------------------------------
 | 
			
		||||
-- Utils
 | 
			
		||||
-----------------------------------------------------------------------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
function loadElectricCharger(chargerData)
 | 
			
		||||
    if not electricChargers[chargerData.location] then
 | 
			
		||||
        RequestModel(chargerData.prop)
 | 
			
		||||
        while not HasModelLoaded(chargerData.prop) do
 | 
			
		||||
            Wait(10)
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        local heading = chargerData.location.w + 180.0
 | 
			
		||||
        local electricCharger = CreateObject(chargerData.prop, chargerData.location.x, chargerData.location.y, chargerData.location.z, false, true, true)
 | 
			
		||||
        SetEntityHeading(electricCharger, heading)
 | 
			
		||||
        FreezeEntityPosition(electricCharger, true)
 | 
			
		||||
 | 
			
		||||
        electricChargers[chargerData.location] = electricCharger
 | 
			
		||||
    end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
function unloadElectricCharger(chargerData)
 | 
			
		||||
    local charger = electricChargers[chargerData.location]
 | 
			
		||||
    if charger and DoesEntityExist(charger) then
 | 
			
		||||
        DeleteEntity(charger)
 | 
			
		||||
        electricChargers[chargerData.location] = nil
 | 
			
		||||
    end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
-- Utility to group chargers by their station
 | 
			
		||||
function groupChargersByStation()
 | 
			
		||||
    local stations = {}
 | 
			
		||||
    for _, charger in pairs(Config.Electric.chargersLocation) do
 | 
			
		||||
        local assigned = false
 | 
			
		||||
        for _, station in pairs(stations) do
 | 
			
		||||
            local dist = #(station.center - vector3(charger.location.x, charger.location.y, charger.location.z))
 | 
			
		||||
            if dist < 20.0 then
 | 
			
		||||
                table.insert(station.chargers, charger)
 | 
			
		||||
                station.center = (station.center + vector3(charger.location.x, charger.location.y, charger.location.z)) / 2
 | 
			
		||||
                assigned = true
 | 
			
		||||
                break
 | 
			
		||||
            end
 | 
			
		||||
        end
 | 
			
		||||
        if not assigned then
 | 
			
		||||
            table.insert(stations, {
 | 
			
		||||
                center = vector3(charger.location.x, charger.location.y, charger.location.z),
 | 
			
		||||
                chargers = { charger }
 | 
			
		||||
            })
 | 
			
		||||
        end
 | 
			
		||||
    end
 | 
			
		||||
    return stations
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
AddEventHandler('onResourceStop', function(resourceName)
 | 
			
		||||
    if GetCurrentResourceName() ~= resourceName then return end
 | 
			
		||||
 | 
			
		||||
    deleteAllElectricChargers()
 | 
			
		||||
end)
 | 
			
		||||
 | 
			
		||||
function deleteAllElectricChargers()
 | 
			
		||||
    for _, charger in pairs(electricChargers) do
 | 
			
		||||
        if DoesEntityExist(charger) then
 | 
			
		||||
            DeleteEntity(charger)
 | 
			
		||||
        end
 | 
			
		||||
    end
 | 
			
		||||
    electricChargers = {}
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			@ -1,77 +1,77 @@
 | 
			
		|||
 | 
			
		||||
 | 
			
		||||
-----------------------------------------------------------------------------------------------------------------------------------------
 | 
			
		||||
-- Fuel consumption chart
 | 
			
		||||
-----------------------------------------------------------------------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
if Config.FuelConsumptionChart.enabled then
 | 
			
		||||
    RegisterCommand(Config.FuelConsumptionChart.command,function(source)
 | 
			
		||||
        toggleFuelConsumptionChart()
 | 
			
		||||
    end, false)
 | 
			
		||||
 | 
			
		||||
    RegisterCommand("fuel_focus", function()
 | 
			
		||||
        if isFuelConsumptionChartOpen then
 | 
			
		||||
            SetNuiFocus(true,true)
 | 
			
		||||
        end
 | 
			
		||||
    end, false)
 | 
			
		||||
 | 
			
		||||
    RegisterKeyMapping(
 | 
			
		||||
        "fuel_focus",             -- command triggered by key
 | 
			
		||||
        "Focus Fuel Chart UI",    -- description in keybindings
 | 
			
		||||
        "keyboard",
 | 
			
		||||
        Config.FuelConsumptionChart.focusShortcut
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    function toggleFuelConsumptionChart()
 | 
			
		||||
        loadNuiVariables()
 | 
			
		||||
        if isFuelConsumptionChartOpen then
 | 
			
		||||
            closeFuelConsumptionChartUI()
 | 
			
		||||
        else
 | 
			
		||||
            local ped = PlayerPedId()
 | 
			
		||||
            if not IsPedInAnyVehicle(ped, false) then
 | 
			
		||||
                exports['lc_utils']:notify("error",Utils.translate("vehicle_not_found"))
 | 
			
		||||
                return
 | 
			
		||||
            end
 | 
			
		||||
            local vehicle = GetVehiclePedIsIn(ped, false)
 | 
			
		||||
            if GetPedInVehicleSeat(vehicle, -1) ~= ped or IsVehicleBlacklisted(vehicle) then
 | 
			
		||||
                exports['lc_utils']:notify("error",Utils.translate("vehicle_not_found"))
 | 
			
		||||
                return
 | 
			
		||||
            end
 | 
			
		||||
 | 
			
		||||
            SendNUIMessage({
 | 
			
		||||
                showFuelConsumptionChart = true,
 | 
			
		||||
                isRecording = isRecording,
 | 
			
		||||
                position = Config.FuelConsumptionChart.position,
 | 
			
		||||
                focusShortcut = Config.FuelConsumptionChart.focusShortcut,
 | 
			
		||||
            })
 | 
			
		||||
            isFuelConsumptionChartOpen = true
 | 
			
		||||
        end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    function updateFuelConsumptionChart(fuelConsumptionData)
 | 
			
		||||
        SendNUIMessage({
 | 
			
		||||
            updateFuelConsumptionChart = true,
 | 
			
		||||
            fuelConsumptionData = fuelConsumptionData,
 | 
			
		||||
        })
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    function closeFuelConsumptionChartUI()
 | 
			
		||||
        SendNUIMessage({
 | 
			
		||||
            hideFuelConsumptionChart = true,
 | 
			
		||||
        })
 | 
			
		||||
        isFuelConsumptionChartOpen = false
 | 
			
		||||
        SetNuiFocus(false,false)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    function storeDataForChart(vehicle, newFuelLevel, currentConsumption)
 | 
			
		||||
        if not isRecording then 
 | 
			
		||||
            updateFuelConsumptionChart({ fuel = nil, speed = nil, consumption = nil })
 | 
			
		||||
            return
 | 
			
		||||
         end
 | 
			
		||||
 | 
			
		||||
        local speed = GetEntitySpeed(vehicle) * 3.6
 | 
			
		||||
        if isFuelConsumptionChartOpen then
 | 
			
		||||
            updateFuelConsumptionChart({ fuel = newFuelLevel, speed = speed, consumption = currentConsumption })
 | 
			
		||||
        end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
-----------------------------------------------------------------------------------------------------------------------------------------
 | 
			
		||||
-- Fuel consumption chart
 | 
			
		||||
-----------------------------------------------------------------------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
if Config.FuelConsumptionChart.enabled then
 | 
			
		||||
    RegisterCommand(Config.FuelConsumptionChart.command,function(source)
 | 
			
		||||
        toggleFuelConsumptionChart()
 | 
			
		||||
    end, false)
 | 
			
		||||
 | 
			
		||||
    RegisterCommand("fuel_focus", function()
 | 
			
		||||
        if isFuelConsumptionChartOpen then
 | 
			
		||||
            SetNuiFocus(true,true)
 | 
			
		||||
        end
 | 
			
		||||
    end, false)
 | 
			
		||||
 | 
			
		||||
    RegisterKeyMapping(
 | 
			
		||||
        "fuel_focus",             -- command triggered by key
 | 
			
		||||
        "Focus Fuel Chart UI",    -- description in keybindings
 | 
			
		||||
        "keyboard",
 | 
			
		||||
        Config.FuelConsumptionChart.focusShortcut
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    function toggleFuelConsumptionChart()
 | 
			
		||||
        loadNuiVariables()
 | 
			
		||||
        if isFuelConsumptionChartOpen then
 | 
			
		||||
            closeFuelConsumptionChartUI()
 | 
			
		||||
        else
 | 
			
		||||
            local ped = PlayerPedId()
 | 
			
		||||
            if not IsPedInAnyVehicle(ped, false) then
 | 
			
		||||
                exports['lc_utils']:notify("error",Utils.translate("vehicle_not_found"))
 | 
			
		||||
                return
 | 
			
		||||
            end
 | 
			
		||||
            local vehicle = GetVehiclePedIsIn(ped, false)
 | 
			
		||||
            if GetPedInVehicleSeat(vehicle, -1) ~= ped or IsVehicleBlacklisted(vehicle) then
 | 
			
		||||
                exports['lc_utils']:notify("error",Utils.translate("vehicle_not_found"))
 | 
			
		||||
                return
 | 
			
		||||
            end
 | 
			
		||||
 | 
			
		||||
            SendNUIMessage({
 | 
			
		||||
                showFuelConsumptionChart = true,
 | 
			
		||||
                isRecording = isRecording,
 | 
			
		||||
                position = Config.FuelConsumptionChart.position,
 | 
			
		||||
                focusShortcut = Config.FuelConsumptionChart.focusShortcut,
 | 
			
		||||
            })
 | 
			
		||||
            isFuelConsumptionChartOpen = true
 | 
			
		||||
        end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    function updateFuelConsumptionChart(fuelConsumptionData)
 | 
			
		||||
        SendNUIMessage({
 | 
			
		||||
            updateFuelConsumptionChart = true,
 | 
			
		||||
            fuelConsumptionData = fuelConsumptionData,
 | 
			
		||||
        })
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    function closeFuelConsumptionChartUI()
 | 
			
		||||
        SendNUIMessage({
 | 
			
		||||
            hideFuelConsumptionChart = true,
 | 
			
		||||
        })
 | 
			
		||||
        isFuelConsumptionChartOpen = false
 | 
			
		||||
        SetNuiFocus(false,false)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    function storeDataForChart(vehicle, newFuelLevel, currentConsumption)
 | 
			
		||||
        if not isRecording then 
 | 
			
		||||
            updateFuelConsumptionChart({ fuel = nil, speed = nil, consumption = nil })
 | 
			
		||||
            return
 | 
			
		||||
         end
 | 
			
		||||
 | 
			
		||||
        local speed = GetEntitySpeed(vehicle) * 3.6
 | 
			
		||||
        if isFuelConsumptionChartOpen then
 | 
			
		||||
            updateFuelConsumptionChart({ fuel = newFuelLevel, speed = speed, consumption = currentConsumption })
 | 
			
		||||
        end
 | 
			
		||||
    end
 | 
			
		||||
end
 | 
			
		||||
							
								
								
									
										10
									
								
								resources/[carscripts]/lc_fuel/client/client_fuel_type.lua
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								resources/[carscripts]/lc_fuel/client/client_fuel_type.lua
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,10 @@
 | 
			
		|||
RegisterCommand(Config.FuelTypeCommand, function()
 | 
			
		||||
    local vehicle =  GetVehiclePedIsIn(PlayerPedId(), false)
 | 
			
		||||
    if not DoesEntityExist(vehicle) then
 | 
			
		||||
        exports['lc_utils']:notify("error", Utils.translate("vehicle_not_found"))
 | 
			
		||||
        return
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    local fuelType = getVehicleFuelTypeFromServer(vehicle)
 | 
			
		||||
    exports['lc_utils']:notify("info", Utils.translate("fuel_types.type_title"):format(Utils.translate("fuel_types."..fuelType)))
 | 
			
		||||
end, false)
 | 
			
		||||
| 
						 | 
				
			
			@ -1,140 +1,140 @@
 | 
			
		|||
local customGasPumps = {}
 | 
			
		||||
-----------------------------------------------------------------------------------------------------------------------------------------
 | 
			
		||||
-- Threads
 | 
			
		||||
-----------------------------------------------------------------------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
-- Thread to detect near fuel pumps
 | 
			
		||||
function createGasMarkersThread()
 | 
			
		||||
    CreateThread(function()
 | 
			
		||||
        while true do
 | 
			
		||||
            local ped = PlayerPedId()
 | 
			
		||||
            local playerCoords = GetEntityCoords(ped)
 | 
			
		||||
            local pump, pumpModel = GetClosestPump(playerCoords, false)
 | 
			
		||||
 | 
			
		||||
            while pump and pump > 0 and #(playerCoords - GetEntityCoords(pump)) < 2.0 do
 | 
			
		||||
                playerCoords = GetEntityCoords(ped)
 | 
			
		||||
                if not mainUiOpen and not DoesEntityExist(fuelNozzle) then
 | 
			
		||||
                    Utils.Markers.showHelpNotification(cachedTranslations.open_refuel, true)
 | 
			
		||||
                    if IsControlJustPressed(0,38) then
 | 
			
		||||
                        clientOpenUI(pump, pumpModel, false)
 | 
			
		||||
                    end
 | 
			
		||||
                end
 | 
			
		||||
                Wait(2)
 | 
			
		||||
            end
 | 
			
		||||
            Wait(1000)
 | 
			
		||||
        end
 | 
			
		||||
    end)
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
function createGasTargetsThread()
 | 
			
		||||
    local pumpModels = {}
 | 
			
		||||
    for _, v in pairs(Config.GasPumpProps) do
 | 
			
		||||
        table.insert(pumpModels, v.prop)
 | 
			
		||||
    end
 | 
			
		||||
    Utils.Target.createTargetForModel(pumpModels,openFuelUICallback,Utils.translate('target.open_refuel'),"fas fa-gas-pump","#a42100",nil,nil,canOpenPumpUiTargetCallback)
 | 
			
		||||
 | 
			
		||||
    Utils.Target.createTargetForModel(pumpModels,returnNozzle,Utils.translate('target.return_nozzle'),"fas fa-gas-pump","#a42100",nil,nil,canReturnNozzleTargetCallback)
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
function openFuelUICallback()
 | 
			
		||||
    local ped = PlayerPedId()
 | 
			
		||||
    local playerCoords = GetEntityCoords(ped)
 | 
			
		||||
    local pump, pumpModel = GetClosestPump(playerCoords, false)
 | 
			
		||||
    if pump then
 | 
			
		||||
        clientOpenUI(pump, pumpModel, false)
 | 
			
		||||
    else
 | 
			
		||||
        exports['lc_utils']:notify("error", Utils.translate("pump_not_found"))
 | 
			
		||||
    end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
function createCustomPumpModelsThread()
 | 
			
		||||
    for _, pumpConfig in pairs(Config.CustomGasPumpLocations) do
 | 
			
		||||
        RequestModel(pumpConfig.prop)
 | 
			
		||||
 | 
			
		||||
        while not HasModelLoaded(pumpConfig.prop) do
 | 
			
		||||
            Wait(50)
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        local heading = pumpConfig.location.w + 180.0
 | 
			
		||||
        local gasPump = CreateObject(pumpConfig.prop, pumpConfig.location.x, pumpConfig.location.y, pumpConfig.location.z, false, true, true)
 | 
			
		||||
        SetEntityHeading(gasPump, heading)
 | 
			
		||||
        FreezeEntityPosition(gasPump, true)
 | 
			
		||||
        table.insert(customGasPumps, gasPump)
 | 
			
		||||
    end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
AddEventHandler('onResourceStop', function(resourceName)
 | 
			
		||||
    if GetCurrentResourceName() ~= resourceName then return end
 | 
			
		||||
 | 
			
		||||
    deleteAllCustomGasPumps()
 | 
			
		||||
end)
 | 
			
		||||
 | 
			
		||||
function deleteAllCustomGasPumps()
 | 
			
		||||
    for k, v in ipairs(customGasPumps) do
 | 
			
		||||
        DeleteEntity(v)
 | 
			
		||||
    end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
-----------------------------------------------------------------------------------------------------------------------------------------
 | 
			
		||||
-- Jerry Cans
 | 
			
		||||
-----------------------------------------------------------------------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
-- Thread to handle the fuel consumption
 | 
			
		||||
function createJerryCanThread()
 | 
			
		||||
    CreateThread(function()
 | 
			
		||||
        while true do
 | 
			
		||||
            Wait(1000)
 | 
			
		||||
            local ped = PlayerPedId()
 | 
			
		||||
            if not IsPedInAnyVehicle(ped, false) and GetSelectedPedWeapon(ped) == JERRY_CAN_HASH then
 | 
			
		||||
                refuelLoop(true)
 | 
			
		||||
            end
 | 
			
		||||
        end
 | 
			
		||||
    end)
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
-- Code to save jerry can ammo in any inventory
 | 
			
		||||
local currentWeaponData
 | 
			
		||||
function updateWeaponAmmo(ammo)
 | 
			
		||||
    ammo = math.floor(ammo) -- This is needed or some inventories will break
 | 
			
		||||
 | 
			
		||||
    if currentWeaponData and currentWeaponData.info and currentWeaponData.info.ammo then
 | 
			
		||||
        currentWeaponData.info.ammo = ammo
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    TriggerServerEvent('ox_inventory:updateWeapon', "ammo", ammo)
 | 
			
		||||
    TriggerServerEvent("weapons:server:UpdateWeaponAmmo", currentWeaponData, ammo)
 | 
			
		||||
    TriggerServerEvent("qb-weapons:server:UpdateWeaponAmmo", currentWeaponData, ammo)
 | 
			
		||||
 | 
			
		||||
    if Config.Debug then print("updateWeaponAmmo:ammo",ammo) end
 | 
			
		||||
    if Config.Debug then Utils.Debug.printTable("updateWeaponAmmo:currentWeaponData",currentWeaponData) end
 | 
			
		||||
 | 
			
		||||
    local ped = PlayerPedId()
 | 
			
		||||
    SetPedAmmo(ped, JERRY_CAN_HASH, ammo)
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
AddEventHandler('weapons:client:SetCurrentWeapon', function(data, bool)
 | 
			
		||||
    if bool ~= false then
 | 
			
		||||
        currentWeaponData = data
 | 
			
		||||
    else
 | 
			
		||||
        currentWeaponData = {}
 | 
			
		||||
    end
 | 
			
		||||
end)
 | 
			
		||||
 | 
			
		||||
AddEventHandler('qb-weapons:client:SetCurrentWeapon', function(data, bool)
 | 
			
		||||
    if bool ~= false then
 | 
			
		||||
        currentWeaponData = data
 | 
			
		||||
    else
 | 
			
		||||
        currentWeaponData = {}
 | 
			
		||||
    end
 | 
			
		||||
end)
 | 
			
		||||
 | 
			
		||||
-- Get jerry can ammo by metadata
 | 
			
		||||
function getJerryCanAmmo()
 | 
			
		||||
    if currentWeaponData and currentWeaponData.info and currentWeaponData.info.ammo then
 | 
			
		||||
        if Config.Debug then print("getJerryCanAmmo:currentWeaponData.info.ammo", currentWeaponData.info.ammo) end
 | 
			
		||||
        return currentWeaponData.info.ammo
 | 
			
		||||
    end
 | 
			
		||||
    local ped = PlayerPedId()
 | 
			
		||||
    if Config.Debug then print("getJerryCanAmmo:GetAmmoInPedWeapon", GetAmmoInPedWeapon(ped, JERRY_CAN_HASH)) end
 | 
			
		||||
    return GetAmmoInPedWeapon(ped, JERRY_CAN_HASH)
 | 
			
		||||
local customGasPumps = {}
 | 
			
		||||
-----------------------------------------------------------------------------------------------------------------------------------------
 | 
			
		||||
-- Threads
 | 
			
		||||
-----------------------------------------------------------------------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
-- Thread to detect near fuel pumps
 | 
			
		||||
function createGasMarkersThread()
 | 
			
		||||
    CreateThread(function()
 | 
			
		||||
        while true do
 | 
			
		||||
            local ped = PlayerPedId()
 | 
			
		||||
            local playerCoords = GetEntityCoords(ped)
 | 
			
		||||
            local pump, pumpModel = GetClosestPump(playerCoords, false)
 | 
			
		||||
 | 
			
		||||
            while pump and pump > 0 and #(playerCoords - GetEntityCoords(pump)) < 2.0 do
 | 
			
		||||
                playerCoords = GetEntityCoords(ped)
 | 
			
		||||
                if not mainUiOpen and not DoesEntityExist(fuelNozzle) then
 | 
			
		||||
                    Utils.Markers.showHelpNotification(cachedTranslations.open_refuel, true)
 | 
			
		||||
                    if IsControlJustPressed(0,38) then
 | 
			
		||||
                        clientOpenUI(pump, pumpModel, false)
 | 
			
		||||
                    end
 | 
			
		||||
                end
 | 
			
		||||
                Wait(2)
 | 
			
		||||
            end
 | 
			
		||||
            Wait(1000)
 | 
			
		||||
        end
 | 
			
		||||
    end)
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
function createGasTargetsThread()
 | 
			
		||||
    local pumpModels = {}
 | 
			
		||||
    for _, v in pairs(Config.GasPumpProps) do
 | 
			
		||||
        table.insert(pumpModels, v.prop)
 | 
			
		||||
    end
 | 
			
		||||
    Utils.Target.createTargetForModel(pumpModels,openFuelUICallback,Utils.translate('target.open_refuel'),"fas fa-gas-pump","#a42100",nil,nil,canOpenPumpUiTargetCallback)
 | 
			
		||||
 | 
			
		||||
    Utils.Target.createTargetForModel(pumpModels,returnNozzle,Utils.translate('target.return_nozzle'),"fas fa-gas-pump","#a42100",nil,nil,canReturnNozzleTargetCallback)
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
function openFuelUICallback()
 | 
			
		||||
    local ped = PlayerPedId()
 | 
			
		||||
    local playerCoords = GetEntityCoords(ped)
 | 
			
		||||
    local pump, pumpModel = GetClosestPump(playerCoords, false)
 | 
			
		||||
    if pump then
 | 
			
		||||
        clientOpenUI(pump, pumpModel, false)
 | 
			
		||||
    else
 | 
			
		||||
        exports['lc_utils']:notify("error", Utils.translate("pump_not_found"))
 | 
			
		||||
    end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
function createCustomPumpModelsThread()
 | 
			
		||||
    for _, pumpConfig in pairs(Config.CustomGasPumpLocations) do
 | 
			
		||||
        RequestModel(pumpConfig.prop)
 | 
			
		||||
 | 
			
		||||
        while not HasModelLoaded(pumpConfig.prop) do
 | 
			
		||||
            Wait(50)
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        local heading = pumpConfig.location.w + 180.0
 | 
			
		||||
        local gasPump = CreateObject(pumpConfig.prop, pumpConfig.location.x, pumpConfig.location.y, pumpConfig.location.z, false, true, true)
 | 
			
		||||
        SetEntityHeading(gasPump, heading)
 | 
			
		||||
        FreezeEntityPosition(gasPump, true)
 | 
			
		||||
        table.insert(customGasPumps, gasPump)
 | 
			
		||||
    end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
AddEventHandler('onResourceStop', function(resourceName)
 | 
			
		||||
    if GetCurrentResourceName() ~= resourceName then return end
 | 
			
		||||
 | 
			
		||||
    deleteAllCustomGasPumps()
 | 
			
		||||
end)
 | 
			
		||||
 | 
			
		||||
function deleteAllCustomGasPumps()
 | 
			
		||||
    for k, v in ipairs(customGasPumps) do
 | 
			
		||||
        DeleteEntity(v)
 | 
			
		||||
    end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
-----------------------------------------------------------------------------------------------------------------------------------------
 | 
			
		||||
-- Jerry Cans
 | 
			
		||||
-----------------------------------------------------------------------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
-- Thread to handle the fuel consumption
 | 
			
		||||
function createJerryCanThread()
 | 
			
		||||
    CreateThread(function()
 | 
			
		||||
        while true do
 | 
			
		||||
            Wait(1000)
 | 
			
		||||
            local ped = PlayerPedId()
 | 
			
		||||
            if not IsPedInAnyVehicle(ped, false) and GetSelectedPedWeapon(ped) == JERRY_CAN_HASH then
 | 
			
		||||
                refuelLoop(true)
 | 
			
		||||
            end
 | 
			
		||||
        end
 | 
			
		||||
    end)
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
-- Code to save jerry can ammo in any inventory
 | 
			
		||||
local currentWeaponData
 | 
			
		||||
function updateWeaponAmmo(ammo)
 | 
			
		||||
    ammo = math.floor(ammo) -- This is needed or some inventories will break
 | 
			
		||||
 | 
			
		||||
    if currentWeaponData and currentWeaponData.info and currentWeaponData.info.ammo then
 | 
			
		||||
        currentWeaponData.info.ammo = ammo
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    TriggerServerEvent('ox_inventory:updateWeapon', "ammo", ammo)
 | 
			
		||||
    TriggerServerEvent("weapons:server:UpdateWeaponAmmo", currentWeaponData, ammo)
 | 
			
		||||
    TriggerServerEvent("qb-weapons:server:UpdateWeaponAmmo", currentWeaponData, ammo)
 | 
			
		||||
 | 
			
		||||
    if Config.Debug then print("updateWeaponAmmo:ammo",ammo) end
 | 
			
		||||
    if Config.Debug then Utils.Debug.printTable("updateWeaponAmmo:currentWeaponData",currentWeaponData) end
 | 
			
		||||
 | 
			
		||||
    local ped = PlayerPedId()
 | 
			
		||||
    SetPedAmmo(ped, JERRY_CAN_HASH, ammo)
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
AddEventHandler('weapons:client:SetCurrentWeapon', function(data, bool)
 | 
			
		||||
    if bool ~= false then
 | 
			
		||||
        currentWeaponData = data
 | 
			
		||||
    else
 | 
			
		||||
        currentWeaponData = {}
 | 
			
		||||
    end
 | 
			
		||||
end)
 | 
			
		||||
 | 
			
		||||
AddEventHandler('qb-weapons:client:SetCurrentWeapon', function(data, bool)
 | 
			
		||||
    if bool ~= false then
 | 
			
		||||
        currentWeaponData = data
 | 
			
		||||
    else
 | 
			
		||||
        currentWeaponData = {}
 | 
			
		||||
    end
 | 
			
		||||
end)
 | 
			
		||||
 | 
			
		||||
-- Get jerry can ammo by metadata
 | 
			
		||||
function getJerryCanAmmo()
 | 
			
		||||
    if currentWeaponData and currentWeaponData.info and currentWeaponData.info.ammo then
 | 
			
		||||
        if Config.Debug then print("getJerryCanAmmo:currentWeaponData.info.ammo", currentWeaponData.info.ammo) end
 | 
			
		||||
        return currentWeaponData.info.ammo
 | 
			
		||||
    end
 | 
			
		||||
    local ped = PlayerPedId()
 | 
			
		||||
    if Config.Debug then print("getJerryCanAmmo:GetAmmoInPedWeapon", GetAmmoInPedWeapon(ped, JERRY_CAN_HASH)) end
 | 
			
		||||
    return GetAmmoInPedWeapon(ped, JERRY_CAN_HASH)
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			@ -1,477 +1,497 @@
 | 
			
		|||
local refuelingThread = nil
 | 
			
		||||
local isRefuelling = false
 | 
			
		||||
local inCooldown = false
 | 
			
		||||
local vehicleAttachedToNozzle = nil
 | 
			
		||||
local remainingFuelToRefuel = 0
 | 
			
		||||
local currentFuelTypePurchased = nil
 | 
			
		||||
local distanceToCap, distanceToPump = math.maxinteger, math.maxinteger
 | 
			
		||||
local litersDeductedEachTick = 0.5
 | 
			
		||||
 | 
			
		||||
-----------------------------------------------------------------------------------------------------------------------------------------
 | 
			
		||||
-- Refuelling
 | 
			
		||||
-----------------------------------------------------------------------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
RegisterNetEvent('lc_fuel:getPumpNozzle')
 | 
			
		||||
AddEventHandler('lc_fuel:getPumpNozzle', function(fuelAmountPurchased, fuelTypePurchased)
 | 
			
		||||
    closeUI()
 | 
			
		||||
    if DoesEntityExist(fuelNozzle) then return end
 | 
			
		||||
    if not currentPump then return end
 | 
			
		||||
    local ped = PlayerPedId()
 | 
			
		||||
    local pumpCoords = GetEntityCoords(currentPump)
 | 
			
		||||
 | 
			
		||||
    -- Animate the ped to grab the nozzle
 | 
			
		||||
    Utils.Animations.loadAnimDict("anim@am_hold_up@male")
 | 
			
		||||
    TaskPlayAnim(ped, "anim@am_hold_up@male", "shoplift_high", 2.0, 8.0, -1, 50, 0, false, false, false)
 | 
			
		||||
    Wait(300)
 | 
			
		||||
    StopAnimTask(ped, "anim@am_hold_up@male", "shoplift_high", 1.0)
 | 
			
		||||
 | 
			
		||||
    -- Spawn the nozzle
 | 
			
		||||
    fuelNozzle = createFuelNozzleObject(fuelTypePurchased)
 | 
			
		||||
 | 
			
		||||
    -- Attach the nozzle
 | 
			
		||||
    attachNozzleToPed()
 | 
			
		||||
    if Config.EnablePumpRope then
 | 
			
		||||
        fuelRope = CreateRopeToPump(pumpCoords)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    -- Get the max distance the player can go with the nozzle
 | 
			
		||||
    local ropeLength = getNearestPumpRopeLength(fuelTypePurchased, pumpCoords)
 | 
			
		||||
 | 
			
		||||
    -- Thread to handle fuel nozzle
 | 
			
		||||
    CreateThread(function()
 | 
			
		||||
        while DoesEntityExist(fuelNozzle) do
 | 
			
		||||
            local waitTime = 500
 | 
			
		||||
            local nozzleCoords = GetEntityCoords(fuelNozzle) -- Conside the nozzle position, not the ped
 | 
			
		||||
            distanceToPump = #(pumpCoords - nozzleCoords)
 | 
			
		||||
            -- If player reach the distance limit delete the nozzle
 | 
			
		||||
            if distanceToPump > ropeLength then
 | 
			
		||||
                exports['lc_utils']:notify("error", Utils.translate("too_far_away"))
 | 
			
		||||
                deleteRopeAndNozzleProp()
 | 
			
		||||
            end
 | 
			
		||||
            -- If player is near the distance limit, show a notification to him
 | 
			
		||||
            if distanceToPump > (ropeLength * 0.7) then
 | 
			
		||||
                Utils.Markers.showHelpNotification(Utils.translate("too_far_away"), true)
 | 
			
		||||
            end
 | 
			
		||||
            -- Check if ped entered a vehicle
 | 
			
		||||
            if IsPedSittingInAnyVehicle(ped) then
 | 
			
		||||
                -- Gives him 2 seconds to leave before clearing the nozzle
 | 
			
		||||
                SetTimeout(2000,function()
 | 
			
		||||
                    if IsPedSittingInAnyVehicle(ped) and DoesEntityExist(fuelNozzle) then
 | 
			
		||||
                        exports['lc_utils']:notify("error", Utils.translate("too_far_away"))
 | 
			
		||||
                        deleteRopeAndNozzleProp()
 | 
			
		||||
                    end
 | 
			
		||||
                end)
 | 
			
		||||
            end
 | 
			
		||||
            if Utils.Config.custom_scripts_compatibility.target == "disabled" and distanceToPump < 1.5 then
 | 
			
		||||
                waitTime = 2
 | 
			
		||||
                Utils.Markers.showHelpNotification(cachedTranslations.return_nozzle, true)
 | 
			
		||||
                if IsControlJustPressed(0,38) then
 | 
			
		||||
                    -- See which one the player is nearer. The fuel cap or fuel pump
 | 
			
		||||
                    if distanceToPump < distanceToCap then
 | 
			
		||||
                        -- Avoid player press E to return nozzle and press E to refuel in same tick, so it gives preference to refuel
 | 
			
		||||
                        Wait(100)
 | 
			
		||||
                        returnNozzle()
 | 
			
		||||
                    end
 | 
			
		||||
                end
 | 
			
		||||
            end
 | 
			
		||||
            Wait(waitTime)
 | 
			
		||||
        end
 | 
			
		||||
        -- Not near the pump anymore
 | 
			
		||||
        distanceToPump = math.maxinteger
 | 
			
		||||
    end)
 | 
			
		||||
 | 
			
		||||
    -- Thread to refuel the vehicle
 | 
			
		||||
    CreateThread(function()
 | 
			
		||||
        -- Set the fuel purchased in a global variable
 | 
			
		||||
        remainingFuelToRefuel = fuelAmountPurchased
 | 
			
		||||
        -- Set the fuel type in a global variable
 | 
			
		||||
        currentFuelTypePurchased = fuelTypePurchased
 | 
			
		||||
        -- Trigger the function to allow refuel on markers
 | 
			
		||||
        if Utils.Config.custom_scripts_compatibility.target == "disabled" then
 | 
			
		||||
            refuelLoop(false)
 | 
			
		||||
        end
 | 
			
		||||
        -- Not near the fuel cap anymore
 | 
			
		||||
        distanceToCap = math.maxinteger
 | 
			
		||||
    end)
 | 
			
		||||
end)
 | 
			
		||||
 | 
			
		||||
function returnNozzle()
 | 
			
		||||
    local ped = PlayerPedId()
 | 
			
		||||
 | 
			
		||||
    if not isRefuelling then
 | 
			
		||||
        Utils.Animations.loadAnimDict("anim@am_hold_up@male")
 | 
			
		||||
        TaskPlayAnim(ped, "anim@am_hold_up@male", "shoplift_high", 2.0, 8.0, -1, 50, 0, false, false, false)
 | 
			
		||||
        Wait(300)
 | 
			
		||||
        StopAnimTask(ped, "anim@am_hold_up@male", "shoplift_high", 1.0)
 | 
			
		||||
        deleteRopeAndNozzleProp()
 | 
			
		||||
 | 
			
		||||
        if Config.ReturnNozzleRefund then
 | 
			
		||||
            local isElectric = Utils.Table.contains({"electricnormal", "electricfast"}, currentFuelTypePurchased)
 | 
			
		||||
            TriggerServerEvent('lc_fuel:returnNozzle', remainingFuelToRefuel, isElectric)
 | 
			
		||||
        end
 | 
			
		||||
    end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
function executeRefuelAction(isFromJerryCan, closestVehicle, closestCapPos, closestVehicleHash, customVehicleParameters)
 | 
			
		||||
    if Config.Debug then print("executeRefuelAction:p", isFromJerryCan, closestVehicle, closestCapPos, closestVehicleHash, customVehicleParameters) end
 | 
			
		||||
    local ped = PlayerPedId()
 | 
			
		||||
    local refuelTick = Config.RefuelTick
 | 
			
		||||
    local isElectric = false
 | 
			
		||||
    local fuelTypePurchased = currentFuelTypePurchased
 | 
			
		||||
 | 
			
		||||
    -- Change the fuel tick if its electric charging
 | 
			
		||||
    if fuelTypePurchased == "electricfast" then
 | 
			
		||||
        isElectric = true
 | 
			
		||||
        refuelTick = Config.Electric.chargeTypes.fast.time * 1000 / 2 -- Divide by 2 because each tick adds 0.5kWh.
 | 
			
		||||
    end
 | 
			
		||||
    if fuelTypePurchased == "electricnormal" then
 | 
			
		||||
        isElectric = true
 | 
			
		||||
        refuelTick = Config.Electric.chargeTypes.normal.time * 1000 / 2
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    local animationDuration = 1000 -- 1 sec
 | 
			
		||||
    if isFromJerryCan then
 | 
			
		||||
        animationDuration = -1 -- (infinite) Do not allow the player walk during refuel from jerry can
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    -- Do not allow user mix electric and petrol fuel/vehicles
 | 
			
		||||
    if (isElectric and Config.Electric.vehiclesListHash[closestVehicleHash]) or (not isElectric and not Config.Electric.vehiclesListHash[closestVehicleHash]) then
 | 
			
		||||
        if not isRefuelling and not vehicleAttachedToNozzle then
 | 
			
		||||
            if remainingFuelToRefuel > 0 then
 | 
			
		||||
                -- Reset the vehicle fuel to 0 when refueling with a different fuel type
 | 
			
		||||
                if not isFromJerryCan and not isElectric then
 | 
			
		||||
                    local fuelType = getVehicleFuelTypeFromServer(closestVehicle)
 | 
			
		||||
                    if fuelTypePurchased ~= fuelType then
 | 
			
		||||
                        changeVehicleFuelType(closestVehicle, fuelTypePurchased)
 | 
			
		||||
                    end
 | 
			
		||||
                end
 | 
			
		||||
                isRefuelling = true
 | 
			
		||||
 | 
			
		||||
                -- Animate the ped
 | 
			
		||||
                TaskTurnPedToFaceCoord(ped, closestCapPos.x, closestCapPos.y, closestCapPos.z, animationDuration)
 | 
			
		||||
                Utils.Animations.loadAnimDict("weapons@misc@jerrycan@")
 | 
			
		||||
                TaskPlayAnim(ped, "weapons@misc@jerrycan@", "fire", 2.0, 8.0, animationDuration, 50, 0, false, false, false)
 | 
			
		||||
 | 
			
		||||
                -- Plug the nozzle in the car
 | 
			
		||||
                attachNozzleToVehicle(closestVehicle, customVehicleParameters)
 | 
			
		||||
 | 
			
		||||
                -- Refuel the vehicle
 | 
			
		||||
                refuelingThread = CreateThread(function()
 | 
			
		||||
                    local vehicleToRefuel = closestVehicle
 | 
			
		||||
                    local startingFuel = GetFuel(vehicleToRefuel) -- Get vehicle fuel level
 | 
			
		||||
                    local vehicleTankSize = getVehicleTankSize(vehicleToRefuel)
 | 
			
		||||
 | 
			
		||||
                    local currentFuel = startingFuel
 | 
			
		||||
                    -- Loop keep happening while the player has not canceled, while the fuelNozzle exists and while the ped still has jerry can in hands
 | 
			
		||||
                    while isRefuelling and (DoesEntityExist(fuelNozzle) or (isFromJerryCan and GetSelectedPedWeapon(ped) == JERRY_CAN_HASH)) do
 | 
			
		||||
                        currentFuel = GetFuel(vehicleToRefuel)
 | 
			
		||||
                        local percentageOfFuelToAdd = calculateFuelToAddPercentage(vehicleTankSize) -- Add 0.5L each tick, but the % is proportional to the vehicle tank
 | 
			
		||||
                        if currentFuel + percentageOfFuelToAdd > 100 then
 | 
			
		||||
                            -- Increase the vehicle fuel level
 | 
			
		||||
                            percentageOfFuelToAdd = 100 - currentFuel
 | 
			
		||||
                        end
 | 
			
		||||
                        if remainingFuelToRefuel < litersDeductedEachTick then
 | 
			
		||||
                            -- Break when the user has used all the fuel he paid for
 | 
			
		||||
                            break
 | 
			
		||||
                        end
 | 
			
		||||
                        if percentageOfFuelToAdd <= 0.01 then
 | 
			
		||||
                            -- Break when the vehicle tank is full
 | 
			
		||||
                            exports['lc_utils']:notify("info", Utils.translate("vehicle_tank_full"))
 | 
			
		||||
                            break
 | 
			
		||||
                        end
 | 
			
		||||
                        -- Decrease the purchased fuel amount and increase the vehicle fuel level
 | 
			
		||||
                        remainingFuelToRefuel = remainingFuelToRefuel - litersDeductedEachTick
 | 
			
		||||
                        currentFuel = currentFuel + percentageOfFuelToAdd
 | 
			
		||||
                        SetFuel(vehicleToRefuel, currentFuel)
 | 
			
		||||
                        SendNUIMessage({
 | 
			
		||||
                            showRefuelDisplay = true,
 | 
			
		||||
                            remainingFuelAmount = remainingFuelToRefuel,
 | 
			
		||||
                            currentVehicleTankSize = vehicleTankSize,
 | 
			
		||||
                            currentDisplayFuelAmount = getVehicleDisplayFuelAmount(currentFuel, vehicleTankSize),
 | 
			
		||||
                            isElectric = isElectric,
 | 
			
		||||
                            fuelTypePurchased = fuelTypePurchased
 | 
			
		||||
                        })
 | 
			
		||||
                        if Config.Debug then print("executeRefuelAction:remainingFuelToRefuel", remainingFuelToRefuel) end
 | 
			
		||||
                        Wait(refuelTick)
 | 
			
		||||
                    end
 | 
			
		||||
                    if isFromJerryCan then
 | 
			
		||||
                        -- Update the jerry can ammo
 | 
			
		||||
                        SetPedAmmo(ped, JERRY_CAN_HASH, remainingFuelToRefuel)
 | 
			
		||||
                        updateWeaponAmmo(remainingFuelToRefuel)
 | 
			
		||||
                        vehicleAttachedToNozzle = nil
 | 
			
		||||
                    end
 | 
			
		||||
                    if isElectric then
 | 
			
		||||
                        exports['lc_utils']:notify("success", Utils.translate("vehicle_recharged"):format(Utils.Math.round(getVehicleDisplayFuelAmount(currentFuel, vehicleTankSize) - getVehicleDisplayFuelAmount(startingFuel, vehicleTankSize), 1)))
 | 
			
		||||
                    else
 | 
			
		||||
                        exports['lc_utils']:notify("success", Utils.translate("vehicle_refueled"):format(Utils.Math.round(getVehicleDisplayFuelAmount(currentFuel, vehicleTankSize) - getVehicleDisplayFuelAmount(startingFuel, vehicleTankSize), 1)))
 | 
			
		||||
                    end
 | 
			
		||||
 | 
			
		||||
                    -- Stop refuelling
 | 
			
		||||
                    stopRefuelAnimation()
 | 
			
		||||
                    SendNUIMessage({ hideRefuelDisplay = true })
 | 
			
		||||
                    isRefuelling = false
 | 
			
		||||
                end)
 | 
			
		||||
            else
 | 
			
		||||
                exports['lc_utils']:notify("error", Utils.translate("not_enough_refuel"))
 | 
			
		||||
            end
 | 
			
		||||
        else
 | 
			
		||||
            -- Terminate refuelling
 | 
			
		||||
            stopRefuelAction()
 | 
			
		||||
            -- Cooldown to prevent the user to spam E and glitch things
 | 
			
		||||
            inCooldown = true
 | 
			
		||||
            SetTimeout(refuelTick + 1,function()
 | 
			
		||||
                inCooldown = false
 | 
			
		||||
            end)
 | 
			
		||||
        end
 | 
			
		||||
    else
 | 
			
		||||
        exports['lc_utils']:notify("error", Utils.translate("incompatible_fuel"))
 | 
			
		||||
    end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
function calculateFuelToAddPercentage(totalVolumeLiters)
 | 
			
		||||
    local percentage = (litersDeductedEachTick / totalVolumeLiters) * 100
 | 
			
		||||
    return percentage
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
-----------------------------------------------------------------------------------------------------------------------------------------
 | 
			
		||||
-- Markers
 | 
			
		||||
-----------------------------------------------------------------------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
function refuelLoop(isFromJerryCan)
 | 
			
		||||
    -- Load variables to open te UI
 | 
			
		||||
    loadNuiVariables()
 | 
			
		||||
 | 
			
		||||
    local ped = PlayerPedId()
 | 
			
		||||
    local closestCapPos
 | 
			
		||||
    local closestVehicle
 | 
			
		||||
    local customVehicleParameters
 | 
			
		||||
    local closestVehicleHash
 | 
			
		||||
 | 
			
		||||
    if isFromJerryCan then
 | 
			
		||||
        remainingFuelToRefuel = getJerryCanAmmo()
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    isRefuelling = false
 | 
			
		||||
    while DoesEntityExist(fuelNozzle) or (isFromJerryCan and GetSelectedPedWeapon(ped) == JERRY_CAN_HASH) do
 | 
			
		||||
        local waitTime = 200
 | 
			
		||||
        if closestCapPos then
 | 
			
		||||
            distanceToCap = #(GetEntityCoords(ped) - vector3(closestCapPos.x,closestCapPos.y,closestCapPos.z + customVehicleParameters.nozzleOffset.up + 0.0))
 | 
			
		||||
            if distanceToCap < customVehicleParameters.distance + 0.0 and (not vehicleAttachedToNozzle or (vehicleAttachedToNozzle and DoesEntityExist(vehicleAttachedToNozzle) and vehicleAttachedToNozzle == closestVehicle)) then
 | 
			
		||||
                waitTime = 1
 | 
			
		||||
                Utils.Markers.drawText3D(closestCapPos.x,closestCapPos.y,closestCapPos.z + customVehicleParameters.nozzleOffset.up + 0.0, cachedTranslations.interact_with_vehicle)
 | 
			
		||||
                if IsControlJustPressed(0, 38) and not inCooldown then
 | 
			
		||||
                    -- See which one the player is nearer. The fuel cap or fuel pump
 | 
			
		||||
                    if distanceToPump >= distanceToCap then
 | 
			
		||||
                        executeRefuelAction(isFromJerryCan, closestVehicle, closestCapPos, closestVehicleHash, customVehicleParameters)
 | 
			
		||||
                    end
 | 
			
		||||
                end
 | 
			
		||||
            else
 | 
			
		||||
                -- Player is not near the cap, set it to null to find it again later
 | 
			
		||||
                closestCapPos = nil
 | 
			
		||||
            end
 | 
			
		||||
        else
 | 
			
		||||
            -- Find the nearest vehicle and cap pos
 | 
			
		||||
            closestVehicle, closestCapPos, closestVehicleHash, customVehicleParameters = getClosestVehicleVariables()
 | 
			
		||||
        end
 | 
			
		||||
        Wait(waitTime)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    terminateRefuelThread()
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
-----------------------------------------------------------------------------------------------------------------------------------------
 | 
			
		||||
-- Target
 | 
			
		||||
-----------------------------------------------------------------------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
function createTargetForVehicleIteraction()
 | 
			
		||||
    local attachParams = {
 | 
			
		||||
        labelText = Utils.translate("target.start_refuel"),
 | 
			
		||||
        icon = "fas fa-gas-pump",
 | 
			
		||||
        iconColor = "#2986cc",
 | 
			
		||||
        zone_id = "start_refuel",
 | 
			
		||||
        distance = 2.0
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Utils.Target.createTargetForBone(vehicleCapBoneList(),attachParams,executeRefuelActionFromTarget,nil,canAttachNozzleTargetCallback)
 | 
			
		||||
 | 
			
		||||
    local detachParams = {
 | 
			
		||||
        labelText = Utils.translate("target.stop_refuel"),
 | 
			
		||||
        icon = "fas fa-gas-pump",
 | 
			
		||||
        iconColor = "#2986cc",
 | 
			
		||||
        zone_id = "stop_refuel",
 | 
			
		||||
        distance = 2.0
 | 
			
		||||
    }
 | 
			
		||||
    Utils.Target.createTargetForBone(vehicleCapBoneList(),detachParams,stopRefuelAction,nil,canDetachNozzleTargetCallback)
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
function executeRefuelActionFromTarget()
 | 
			
		||||
    -- Load variables to open te UI
 | 
			
		||||
    loadNuiVariables()
 | 
			
		||||
 | 
			
		||||
    local ped = PlayerPedId()
 | 
			
		||||
 | 
			
		||||
    -- Calculate if player is holding a jerry can
 | 
			
		||||
    local isFromJerryCan = false
 | 
			
		||||
    if not IsPedInAnyVehicle(ped, false) and GetSelectedPedWeapon(ped) == JERRY_CAN_HASH then
 | 
			
		||||
        isFromJerryCan = true
 | 
			
		||||
        remainingFuelToRefuel = getJerryCanAmmo()
 | 
			
		||||
        if Config.Debug then print("executeRefuelActionFromTarget:remainingFuelToRefuel",remainingFuelToRefuel) end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    local closestVehicle, closestCapPos, closestVehicleHash, customVehicleParameters = getClosestVehicleVariables()
 | 
			
		||||
    executeRefuelAction(isFromJerryCan, closestVehicle, closestCapPos, closestVehicleHash, customVehicleParameters)
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
function canAttachNozzleTargetCallback(entity, distance)
 | 
			
		||||
    local ped = PlayerPedId()
 | 
			
		||||
    if (DoesEntityExist(fuelNozzle) or GetSelectedPedWeapon(ped) == JERRY_CAN_HASH)
 | 
			
		||||
        and not isRefuelling
 | 
			
		||||
        and not vehicleAttachedToNozzle then
 | 
			
		||||
        return true
 | 
			
		||||
    end
 | 
			
		||||
    return false
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
function canDetachNozzleTargetCallback(entity, distance)
 | 
			
		||||
    local ped = PlayerPedId()
 | 
			
		||||
    if (DoesEntityExist(fuelNozzle) or GetSelectedPedWeapon(ped) == JERRY_CAN_HASH)
 | 
			
		||||
        and vehicleAttachedToNozzle then
 | 
			
		||||
        return true
 | 
			
		||||
    end
 | 
			
		||||
    return false
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
function canOpenPumpUiTargetCallback()
 | 
			
		||||
    return not DoesEntityExist(fuelNozzle)
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
function canReturnNozzleTargetCallback()
 | 
			
		||||
    return DoesEntityExist(fuelNozzle)
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
-----------------------------------------------------------------------------------------------------------------------------------------
 | 
			
		||||
-- Utils
 | 
			
		||||
-----------------------------------------------------------------------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
function getClosestVehicleVariables()
 | 
			
		||||
    -- Get the closest vehicle and its cap pos
 | 
			
		||||
    local closestVehicle = GetClosestVehicle()
 | 
			
		||||
    local closestCapPos = GetVehicleCapPos(closestVehicle)
 | 
			
		||||
    local closestVehicleHash = GetEntityModel(closestVehicle)
 | 
			
		||||
    local customVehicleParameters = (Config.CustomVehicleParametersHash[closestVehicleHash] or Config.CustomVehicleParametersHash.default or { distance = 1.2, nozzleOffset = { forward = 0.0, right = -0.15, up = 0.5 }, nozzleRotation = { x = 0, y = 0, z = 0} })
 | 
			
		||||
    if not closestCapPos then
 | 
			
		||||
        print("Cap not found for vehicle")
 | 
			
		||||
    end
 | 
			
		||||
    return closestVehicle, closestCapPos, closestVehicleHash, customVehicleParameters
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
function terminateRefuelThread()
 | 
			
		||||
    -- Stop the refueling process
 | 
			
		||||
    if refuelingThread and IsThreadActive(refuelingThread) then
 | 
			
		||||
        TerminateThread(refuelingThread)
 | 
			
		||||
        refuelingThread = nil
 | 
			
		||||
    end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
function stopRefuelAnimation()
 | 
			
		||||
    local ped = PlayerPedId()
 | 
			
		||||
    ClearPedTasks(ped)
 | 
			
		||||
    RemoveAnimDict("weapons@misc@jerrycan@")
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
function stopRefuelAction()
 | 
			
		||||
    -- Stop refuelling
 | 
			
		||||
    stopRefuelAnimation()
 | 
			
		||||
    SendNUIMessage({ hideRefuelDisplay = true })
 | 
			
		||||
    attachNozzleToPed()
 | 
			
		||||
    isRefuelling = false
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
function attachNozzleToVehicle(closestVehicle, customVehicleParameters)
 | 
			
		||||
    DetachEntity(fuelNozzle, true, true)
 | 
			
		||||
 | 
			
		||||
    -- Find the appropriate bone for the fuel cap
 | 
			
		||||
    local tankBones = vehicleCapBoneList()
 | 
			
		||||
    local boneIndex = -1
 | 
			
		||||
 | 
			
		||||
    for _, boneName in ipairs(tankBones) do
 | 
			
		||||
        boneIndex = GetEntityBoneIndexByName(closestVehicle, boneName)
 | 
			
		||||
        if boneIndex ~= -1 then
 | 
			
		||||
            break
 | 
			
		||||
        end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    if boneIndex ~= -1 then
 | 
			
		||||
        local vehicleRotation = GetEntityRotation(closestVehicle)
 | 
			
		||||
        local forwardVector, rightVector, upVector, _ = GetEntityMatrix(closestVehicle)
 | 
			
		||||
 | 
			
		||||
        -- Adjust the offsets
 | 
			
		||||
        local forwardOffset = forwardVector * customVehicleParameters.nozzleOffset.forward
 | 
			
		||||
        local rightoffset = rightVector * customVehicleParameters.nozzleOffset.right
 | 
			
		||||
        local upOffset = upVector * customVehicleParameters.nozzleOffset.up
 | 
			
		||||
        local finalOffset = forwardOffset + rightoffset + upOffset
 | 
			
		||||
 | 
			
		||||
        -- Adjust the rotation
 | 
			
		||||
        local nozzleRotation = customVehicleParameters.nozzleRotation or { x = 0, y = 0, z = 0 }
 | 
			
		||||
        local finalRotationX = vehicleRotation.x + nozzleRotation.x
 | 
			
		||||
        local finalRotationY = vehicleRotation.y + nozzleRotation.y
 | 
			
		||||
        local finalRotationZ = vehicleRotation.z + nozzleRotation.z
 | 
			
		||||
 | 
			
		||||
        -- Attach the nozzle to the vehicle's fuel cap bone with the calculated rotation
 | 
			
		||||
        AttachEntityToEntity(fuelNozzle, closestVehicle, boneIndex, finalOffset.x, finalOffset.y, finalOffset.z, finalRotationX - 45, finalRotationY, finalRotationZ - 90, false, false, false, false, 2, false)
 | 
			
		||||
    else
 | 
			
		||||
        print("No valid fuel cap bone found on the vehicle.")
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    -- Set the global variable to indicate the vehicle attached to nozzle
 | 
			
		||||
    vehicleAttachedToNozzle = closestVehicle
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
function attachNozzleToPed()
 | 
			
		||||
    DetachEntity(fuelNozzle, true, true)
 | 
			
		||||
 | 
			
		||||
    local ped = PlayerPedId()
 | 
			
		||||
    local pedBone = GetPedBoneIndex(ped, 18905)
 | 
			
		||||
    AttachEntityToEntity(fuelNozzle, ped, pedBone, 0.13, 0.04, 0.01, -42.0, -115.0, -63.42, false, true, false, true, 0, true)
 | 
			
		||||
 | 
			
		||||
    vehicleAttachedToNozzle = nil
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
function getNearestPumpRopeLength(fuelTypePurchased, pumpCoords)
 | 
			
		||||
    local distanceToFindPump = 10
 | 
			
		||||
    local ropeLength = Config.DefaultRopeLength
 | 
			
		||||
    if fuelTypePurchased == "electricfast" or fuelTypePurchased == "electricnormal" then
 | 
			
		||||
        for _, pumpConfig in pairs(Config.Electric.chargersLocation) do
 | 
			
		||||
            local distance = #(vector3(pumpConfig.location.x, pumpConfig.location.y, pumpConfig.location.z) - pumpCoords)
 | 
			
		||||
            if distance < distanceToFindPump then
 | 
			
		||||
                ropeLength = pumpConfig.ropeLength
 | 
			
		||||
                break
 | 
			
		||||
            end
 | 
			
		||||
        end
 | 
			
		||||
    else
 | 
			
		||||
        for _, pumpConfig in pairs(Config.CustomGasPumpLocations) do
 | 
			
		||||
            local distance = #(vector3(pumpConfig.location.x, pumpConfig.location.y, pumpConfig.location.z) - pumpCoords)
 | 
			
		||||
            if distance < distanceToFindPump then
 | 
			
		||||
                ropeLength = pumpConfig.ropeLength
 | 
			
		||||
                break
 | 
			
		||||
            end
 | 
			
		||||
        end
 | 
			
		||||
    end
 | 
			
		||||
    return ropeLength
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
function createFuelNozzleObject(fuelTypePurchased)
 | 
			
		||||
    local nozzle_prop_label = Config.NozzleProps.gas
 | 
			
		||||
    -- Change the nozzle prop to electric
 | 
			
		||||
    if fuelTypePurchased == "electricfast" or fuelTypePurchased == "electricnormal" then
 | 
			
		||||
        nozzle_prop_label = Config.NozzleProps.electric
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    RequestModel(nozzle_prop_label)
 | 
			
		||||
    while not HasModelLoaded(nozzle_prop_label) do
 | 
			
		||||
        Wait(50)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    return CreateObject(joaat(nozzle_prop_label), 1.0, 1.0, 1.0, true, true, false)
 | 
			
		||||
local refuelingThread = nil
 | 
			
		||||
local isRefuelling = false
 | 
			
		||||
local inCooldown = false
 | 
			
		||||
local vehicleAttachedToNozzle = nil
 | 
			
		||||
local remainingFuelToRefuel = 0
 | 
			
		||||
local currentFuelTypePurchased = nil
 | 
			
		||||
local distanceToCap, distanceToPump = math.maxinteger, math.maxinteger
 | 
			
		||||
local litersDeductedEachTick = 0.5
 | 
			
		||||
 | 
			
		||||
-----------------------------------------------------------------------------------------------------------------------------------------
 | 
			
		||||
-- Refuelling
 | 
			
		||||
-----------------------------------------------------------------------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
RegisterNetEvent('lc_fuel:getPumpNozzle')
 | 
			
		||||
AddEventHandler('lc_fuel:getPumpNozzle', function(fuelAmountPurchased, fuelTypePurchased)
 | 
			
		||||
    closeUI()
 | 
			
		||||
    if DoesEntityExist(fuelNozzle) then return end
 | 
			
		||||
    if not currentPump then return end
 | 
			
		||||
    local ped = PlayerPedId()
 | 
			
		||||
    local pumpCoords = GetEntityCoords(currentPump)
 | 
			
		||||
 | 
			
		||||
    -- Animate the ped to grab the nozzle
 | 
			
		||||
    Utils.Animations.loadAnimDict("anim@am_hold_up@male")
 | 
			
		||||
    TaskPlayAnim(ped, "anim@am_hold_up@male", "shoplift_high", 2.0, 8.0, -1, 50, 0, false, false, false)
 | 
			
		||||
    Wait(300)
 | 
			
		||||
    StopAnimTask(ped, "anim@am_hold_up@male", "shoplift_high", 1.0)
 | 
			
		||||
 | 
			
		||||
    -- Spawn the nozzle
 | 
			
		||||
    fuelNozzle = createFuelNozzleObject(fuelTypePurchased)
 | 
			
		||||
 | 
			
		||||
    -- Attach the nozzle
 | 
			
		||||
    attachNozzleToPed()
 | 
			
		||||
    if Config.EnablePumpRope then
 | 
			
		||||
        fuelRope = CreateRopeToPump(pumpCoords)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    -- Get the max distance the player can go with the nozzle
 | 
			
		||||
    local ropeLength = getNearestPumpRopeLength(fuelTypePurchased, pumpCoords)
 | 
			
		||||
 | 
			
		||||
    -- Thread to handle fuel nozzle
 | 
			
		||||
    CreateThread(function()
 | 
			
		||||
        while DoesEntityExist(fuelNozzle) do
 | 
			
		||||
            local waitTime = 500
 | 
			
		||||
            local nozzleCoords = GetEntityCoords(fuelNozzle) -- Conside the nozzle position, not the ped
 | 
			
		||||
            distanceToPump = #(pumpCoords - nozzleCoords)
 | 
			
		||||
            -- If player reach the distance limit delete the nozzle
 | 
			
		||||
            if distanceToPump > ropeLength then
 | 
			
		||||
                exports['lc_utils']:notify("error", Utils.translate("too_far_away"))
 | 
			
		||||
                deleteRopeAndNozzleProp()
 | 
			
		||||
            end
 | 
			
		||||
            -- If player is near the distance limit, show a notification to him
 | 
			
		||||
            if distanceToPump > (ropeLength * 0.7) then
 | 
			
		||||
                Utils.Markers.showHelpNotification(Utils.translate("too_far_away"), true)
 | 
			
		||||
            end
 | 
			
		||||
            -- Check if ped entered a vehicle
 | 
			
		||||
            if IsPedSittingInAnyVehicle(ped) then
 | 
			
		||||
                -- Gives him 2 seconds to leave before clearing the nozzle
 | 
			
		||||
                SetTimeout(2000,function()
 | 
			
		||||
                    if IsPedSittingInAnyVehicle(ped) and DoesEntityExist(fuelNozzle) then
 | 
			
		||||
                        exports['lc_utils']:notify("error", Utils.translate("too_far_away"))
 | 
			
		||||
                        deleteRopeAndNozzleProp()
 | 
			
		||||
                    end
 | 
			
		||||
                end)
 | 
			
		||||
            end
 | 
			
		||||
            if Utils.Config.custom_scripts_compatibility.target == "disabled" and distanceToPump < 1.5 then
 | 
			
		||||
                waitTime = 2
 | 
			
		||||
                Utils.Markers.showHelpNotification(cachedTranslations.return_nozzle, true)
 | 
			
		||||
                if IsControlJustPressed(0,38) then
 | 
			
		||||
                    -- See which one the player is nearer. The fuel cap or fuel pump
 | 
			
		||||
                    if distanceToPump < distanceToCap then
 | 
			
		||||
                        -- Avoid player press E to return nozzle and press E to refuel in same tick, so it gives preference to refuel
 | 
			
		||||
                        Wait(100)
 | 
			
		||||
                        returnNozzle()
 | 
			
		||||
                    end
 | 
			
		||||
                end
 | 
			
		||||
            end
 | 
			
		||||
            Wait(waitTime)
 | 
			
		||||
        end
 | 
			
		||||
        -- Not near the pump anymore
 | 
			
		||||
        distanceToPump = math.maxinteger
 | 
			
		||||
    end)
 | 
			
		||||
 | 
			
		||||
    -- Thread to refuel the vehicle
 | 
			
		||||
    CreateThread(function()
 | 
			
		||||
        -- Set the fuel purchased in a global variable
 | 
			
		||||
        remainingFuelToRefuel = fuelAmountPurchased
 | 
			
		||||
        -- Set the fuel type in a global variable
 | 
			
		||||
        currentFuelTypePurchased = fuelTypePurchased
 | 
			
		||||
        -- Trigger the function to allow refuel on markers
 | 
			
		||||
        if Utils.Config.custom_scripts_compatibility.target == "disabled" then
 | 
			
		||||
            refuelLoop(false)
 | 
			
		||||
        end
 | 
			
		||||
        -- Not near the fuel cap anymore
 | 
			
		||||
        distanceToCap = math.maxinteger
 | 
			
		||||
    end)
 | 
			
		||||
end)
 | 
			
		||||
 | 
			
		||||
function returnNozzle()
 | 
			
		||||
    local ped = PlayerPedId()
 | 
			
		||||
 | 
			
		||||
    if not isRefuelling then
 | 
			
		||||
        Utils.Animations.loadAnimDict("anim@am_hold_up@male")
 | 
			
		||||
        TaskPlayAnim(ped, "anim@am_hold_up@male", "shoplift_high", 2.0, 8.0, -1, 50, 0, false, false, false)
 | 
			
		||||
        Wait(300)
 | 
			
		||||
        StopAnimTask(ped, "anim@am_hold_up@male", "shoplift_high", 1.0)
 | 
			
		||||
        deleteRopeAndNozzleProp()
 | 
			
		||||
 | 
			
		||||
        if Config.ReturnNozzleRefund then
 | 
			
		||||
            local isElectric = Utils.Table.contains({"electricnormal", "electricfast"}, currentFuelTypePurchased)
 | 
			
		||||
            TriggerServerEvent('lc_fuel:returnNozzle', remainingFuelToRefuel, isElectric)
 | 
			
		||||
        end
 | 
			
		||||
    end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
function executeRefuelAction(isFromJerryCan, closestVehicle, closestCapPos, closestVehicleHash, customVehicleParameters)
 | 
			
		||||
    if Config.Debug then print("executeRefuelAction:p", isFromJerryCan, closestVehicle, closestCapPos, closestVehicleHash, customVehicleParameters) end
 | 
			
		||||
    local ped = PlayerPedId()
 | 
			
		||||
    local refuelTick = Config.RefuelTick
 | 
			
		||||
    local isElectric = false
 | 
			
		||||
    local fuelTypePurchased = currentFuelTypePurchased
 | 
			
		||||
 | 
			
		||||
    -- Change the fuel tick if its electric charging
 | 
			
		||||
    if fuelTypePurchased == "electricfast" then
 | 
			
		||||
        isElectric = true
 | 
			
		||||
        refuelTick = Config.Electric.chargeTypes.fast.time * 1000 / 2 -- Divide by 2 because each tick adds 0.5kWh.
 | 
			
		||||
    end
 | 
			
		||||
    if fuelTypePurchased == "electricnormal" then
 | 
			
		||||
        isElectric = true
 | 
			
		||||
        refuelTick = Config.Electric.chargeTypes.normal.time * 1000 / 2
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    local animationDuration = 1000 -- 1 sec
 | 
			
		||||
    if isFromJerryCan then
 | 
			
		||||
        animationDuration = -1 -- (infinite) Do not allow the player walk during refuel from jerry can
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    -- Do not allow user mix electric and petrol fuel/vehicles
 | 
			
		||||
    if (isElectric and Config.Electric.vehiclesListHash[closestVehicleHash]) or (not isElectric and not Config.Electric.vehiclesListHash[closestVehicleHash]) then
 | 
			
		||||
        if not isRefuelling and not vehicleAttachedToNozzle then
 | 
			
		||||
            if remainingFuelToRefuel > 0 then
 | 
			
		||||
                -- Reset the vehicle fuel to 0 when refueling with a different fuel type
 | 
			
		||||
                if not isFromJerryCan and not isElectric then
 | 
			
		||||
                    local fuelType = getVehicleFuelTypeFromServer(closestVehicle)
 | 
			
		||||
                    if fuelTypePurchased ~= fuelType then
 | 
			
		||||
                        changeVehicleFuelType(closestVehicle, fuelTypePurchased)
 | 
			
		||||
                    end
 | 
			
		||||
                end
 | 
			
		||||
                isRefuelling = true
 | 
			
		||||
 | 
			
		||||
                -- Animate the ped
 | 
			
		||||
                TaskTurnPedToFaceCoord(ped, closestCapPos.x, closestCapPos.y, closestCapPos.z, animationDuration)
 | 
			
		||||
                Utils.Animations.loadAnimDict("weapons@misc@jerrycan@")
 | 
			
		||||
                TaskPlayAnim(ped, "weapons@misc@jerrycan@", "fire", 2.0, 8.0, animationDuration, 50, 0, false, false, false)
 | 
			
		||||
 | 
			
		||||
                -- Plug the nozzle in the car
 | 
			
		||||
                attachNozzleToVehicle(closestVehicle, customVehicleParameters)
 | 
			
		||||
 | 
			
		||||
                -- Refuel the vehicle
 | 
			
		||||
                refuelingThread = CreateThread(function()
 | 
			
		||||
                    local vehicleToRefuel = closestVehicle
 | 
			
		||||
                    local startingFuel = GetFuel(vehicleToRefuel) -- Get vehicle fuel level
 | 
			
		||||
                    local vehicleTankSize = getVehicleTankSize(vehicleToRefuel)
 | 
			
		||||
 | 
			
		||||
                    local currentFuel = startingFuel
 | 
			
		||||
                    -- Loop keep happening while the player has not canceled, while the fuelNozzle exists and while the ped still has jerry can in hands
 | 
			
		||||
                    while isRefuelling and (DoesEntityExist(fuelNozzle) or (isFromJerryCan and GetSelectedPedWeapon(ped) == JERRY_CAN_HASH)) do
 | 
			
		||||
                        currentFuel = GetFuel(vehicleToRefuel)
 | 
			
		||||
                        local percentageOfFuelToAdd = calculateFuelToAddPercentage(vehicleTankSize) -- Add 0.5L each tick, but the % is proportional to the vehicle tank
 | 
			
		||||
                        if currentFuel + percentageOfFuelToAdd > 100 then
 | 
			
		||||
                            -- Increase the vehicle fuel level
 | 
			
		||||
                            percentageOfFuelToAdd = 100 - currentFuel
 | 
			
		||||
                        end
 | 
			
		||||
                        if remainingFuelToRefuel < litersDeductedEachTick then
 | 
			
		||||
                            -- Break when the user has used all the fuel he paid for
 | 
			
		||||
                            break
 | 
			
		||||
                        end
 | 
			
		||||
                        if percentageOfFuelToAdd <= 0.01 then
 | 
			
		||||
                            -- Break when the vehicle tank is full
 | 
			
		||||
                            exports['lc_utils']:notify("info", Utils.translate("vehicle_tank_full"))
 | 
			
		||||
                            break
 | 
			
		||||
                        end
 | 
			
		||||
                        -- Decrease the purchased fuel amount and increase the vehicle fuel level
 | 
			
		||||
                        remainingFuelToRefuel = remainingFuelToRefuel - litersDeductedEachTick
 | 
			
		||||
                        currentFuel = currentFuel + percentageOfFuelToAdd
 | 
			
		||||
                        SetFuel(vehicleToRefuel, currentFuel)
 | 
			
		||||
                        SendNUIMessage({
 | 
			
		||||
                            showRefuelDisplay = true,
 | 
			
		||||
                            remainingFuelAmount = remainingFuelToRefuel,
 | 
			
		||||
                            currentVehicleTankSize = vehicleTankSize,
 | 
			
		||||
                            currentDisplayFuelAmount = getVehicleDisplayFuelAmount(currentFuel, vehicleTankSize),
 | 
			
		||||
                            isElectric = isElectric,
 | 
			
		||||
                            fuelTypePurchased = fuelTypePurchased
 | 
			
		||||
                        })
 | 
			
		||||
                        if Config.Debug then print("executeRefuelAction:remainingFuelToRefuel", remainingFuelToRefuel) end
 | 
			
		||||
                        Wait(refuelTick)
 | 
			
		||||
                    end
 | 
			
		||||
                    if isFromJerryCan then
 | 
			
		||||
                        -- Update the jerry can ammo
 | 
			
		||||
                        SetPedAmmo(ped, JERRY_CAN_HASH, remainingFuelToRefuel)
 | 
			
		||||
                        updateWeaponAmmo(remainingFuelToRefuel)
 | 
			
		||||
                        vehicleAttachedToNozzle = nil
 | 
			
		||||
                    end
 | 
			
		||||
                    if isElectric then
 | 
			
		||||
                        exports['lc_utils']:notify("success", Utils.translate("vehicle_recharged"):format(Utils.Math.round(getVehicleDisplayFuelAmount(currentFuel, vehicleTankSize) - getVehicleDisplayFuelAmount(startingFuel, vehicleTankSize), 1)))
 | 
			
		||||
                    else
 | 
			
		||||
                        exports['lc_utils']:notify("success", Utils.translate("vehicle_refueled"):format(Utils.Math.round(getVehicleDisplayFuelAmount(currentFuel, vehicleTankSize) - getVehicleDisplayFuelAmount(startingFuel, vehicleTankSize), 1)))
 | 
			
		||||
                    end
 | 
			
		||||
 | 
			
		||||
                    -- Stop refuelling
 | 
			
		||||
                    stopRefuelAnimation()
 | 
			
		||||
                    SendNUIMessage({ hideRefuelDisplay = true })
 | 
			
		||||
                    isRefuelling = false
 | 
			
		||||
                end)
 | 
			
		||||
            else
 | 
			
		||||
                exports['lc_utils']:notify("error", Utils.translate("not_enough_refuel"))
 | 
			
		||||
            end
 | 
			
		||||
        else
 | 
			
		||||
            -- Terminate refuelling
 | 
			
		||||
            stopRefuelAction()
 | 
			
		||||
            -- Cooldown to prevent the user to spam E and glitch things
 | 
			
		||||
            inCooldown = true
 | 
			
		||||
            SetTimeout(refuelTick + 1,function()
 | 
			
		||||
                inCooldown = false
 | 
			
		||||
            end)
 | 
			
		||||
        end
 | 
			
		||||
    else
 | 
			
		||||
        exports['lc_utils']:notify("error", Utils.translate("incompatible_fuel"))
 | 
			
		||||
    end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
function calculateFuelToAddPercentage(totalVolumeLiters)
 | 
			
		||||
    local percentage = (litersDeductedEachTick / totalVolumeLiters) * 100
 | 
			
		||||
    return percentage
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
-----------------------------------------------------------------------------------------------------------------------------------------
 | 
			
		||||
-- Markers
 | 
			
		||||
-----------------------------------------------------------------------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
function refuelLoop(isFromJerryCan)
 | 
			
		||||
    -- Load variables to open te UI
 | 
			
		||||
    loadNuiVariables()
 | 
			
		||||
 | 
			
		||||
    local ped = PlayerPedId()
 | 
			
		||||
    local closestCapPos
 | 
			
		||||
    local closestVehicle
 | 
			
		||||
    local customVehicleParameters
 | 
			
		||||
    local closestVehicleHash
 | 
			
		||||
 | 
			
		||||
    if isFromJerryCan then
 | 
			
		||||
        remainingFuelToRefuel = getJerryCanAmmo()
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    isRefuelling = false
 | 
			
		||||
    while DoesEntityExist(fuelNozzle) or (isFromJerryCan and GetSelectedPedWeapon(ped) == JERRY_CAN_HASH) do
 | 
			
		||||
        local waitTime = 200
 | 
			
		||||
        if closestCapPos then
 | 
			
		||||
            distanceToCap = #(GetEntityCoords(ped) - vector3(closestCapPos.x,closestCapPos.y,closestCapPos.z))
 | 
			
		||||
            if distanceToCap < customVehicleParameters.distance + 0.0 and (not vehicleAttachedToNozzle or (vehicleAttachedToNozzle and DoesEntityExist(vehicleAttachedToNozzle) and vehicleAttachedToNozzle == closestVehicle)) then
 | 
			
		||||
                waitTime = 1
 | 
			
		||||
                Utils.Markers.drawText3D(closestCapPos.x,closestCapPos.y,closestCapPos.z, cachedTranslations.interact_with_vehicle)
 | 
			
		||||
                if IsControlJustPressed(0, 38) and not inCooldown then
 | 
			
		||||
                    -- See which one the player is nearer. The fuel cap or fuel pump
 | 
			
		||||
                    if distanceToPump >= distanceToCap then
 | 
			
		||||
                        executeRefuelAction(isFromJerryCan, closestVehicle, closestCapPos, closestVehicleHash, customVehicleParameters)
 | 
			
		||||
                    end
 | 
			
		||||
                end
 | 
			
		||||
            else
 | 
			
		||||
                -- Player is not near the cap, set it to null to find it again later
 | 
			
		||||
                closestCapPos = nil
 | 
			
		||||
            end
 | 
			
		||||
        else
 | 
			
		||||
            -- Find the nearest vehicle and cap pos
 | 
			
		||||
            closestVehicle, closestCapPos, closestVehicleHash, customVehicleParameters = getClosestVehicleVariables()
 | 
			
		||||
        end
 | 
			
		||||
        Wait(waitTime)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    terminateRefuelThread()
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
-----------------------------------------------------------------------------------------------------------------------------------------
 | 
			
		||||
-- Target
 | 
			
		||||
-----------------------------------------------------------------------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
function createTargetForVehicleIteraction()
 | 
			
		||||
    local attachParams = {
 | 
			
		||||
        labelText = Utils.translate("target.start_refuel"),
 | 
			
		||||
        icon = "fas fa-gas-pump",
 | 
			
		||||
        iconColor = "#2986cc",
 | 
			
		||||
        zone_id = "start_refuel",
 | 
			
		||||
        distance = 2.0
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Utils.Target.createTargetForBone(vehicleCapBoneList(),attachParams,executeRefuelActionFromTarget,nil,canAttachNozzleTargetCallback)
 | 
			
		||||
 | 
			
		||||
    local detachParams = {
 | 
			
		||||
        labelText = Utils.translate("target.stop_refuel"),
 | 
			
		||||
        icon = "fas fa-gas-pump",
 | 
			
		||||
        iconColor = "#2986cc",
 | 
			
		||||
        zone_id = "stop_refuel",
 | 
			
		||||
        distance = 2.0
 | 
			
		||||
    }
 | 
			
		||||
    Utils.Target.createTargetForBone(vehicleCapBoneList(),detachParams,stopRefuelAction,nil,canDetachNozzleTargetCallback)
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
function executeRefuelActionFromTarget()
 | 
			
		||||
    -- Load variables to open te UI
 | 
			
		||||
    loadNuiVariables()
 | 
			
		||||
 | 
			
		||||
    local ped = PlayerPedId()
 | 
			
		||||
 | 
			
		||||
    -- Calculate if player is holding a jerry can
 | 
			
		||||
    local isFromJerryCan = false
 | 
			
		||||
    if not IsPedInAnyVehicle(ped, false) and GetSelectedPedWeapon(ped) == JERRY_CAN_HASH then
 | 
			
		||||
        isFromJerryCan = true
 | 
			
		||||
        remainingFuelToRefuel = getJerryCanAmmo()
 | 
			
		||||
        if Config.Debug then print("executeRefuelActionFromTarget:remainingFuelToRefuel",remainingFuelToRefuel) end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    local closestVehicle, closestCapPos, closestVehicleHash, customVehicleParameters = getClosestVehicleVariables()
 | 
			
		||||
    executeRefuelAction(isFromJerryCan, closestVehicle, closestCapPos, closestVehicleHash, customVehicleParameters)
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
function canAttachNozzleTargetCallback(entity, distance)
 | 
			
		||||
    local ped = PlayerPedId()
 | 
			
		||||
    if (DoesEntityExist(fuelNozzle) or GetSelectedPedWeapon(ped) == JERRY_CAN_HASH)
 | 
			
		||||
        and not isRefuelling
 | 
			
		||||
        and not vehicleAttachedToNozzle then
 | 
			
		||||
        return true
 | 
			
		||||
    end
 | 
			
		||||
    return false
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
function canDetachNozzleTargetCallback(entity, distance)
 | 
			
		||||
    local ped = PlayerPedId()
 | 
			
		||||
    if (DoesEntityExist(fuelNozzle) or GetSelectedPedWeapon(ped) == JERRY_CAN_HASH)
 | 
			
		||||
        and vehicleAttachedToNozzle then
 | 
			
		||||
        return true
 | 
			
		||||
    end
 | 
			
		||||
    return false
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
function canOpenPumpUiTargetCallback()
 | 
			
		||||
    return not DoesEntityExist(fuelNozzle)
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
function canReturnNozzleTargetCallback()
 | 
			
		||||
    return DoesEntityExist(fuelNozzle)
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
-----------------------------------------------------------------------------------------------------------------------------------------
 | 
			
		||||
-- Utils
 | 
			
		||||
-----------------------------------------------------------------------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
function getClosestVehicleVariables()
 | 
			
		||||
    -- Get the closest vehicle and its cap pos
 | 
			
		||||
    local closestVehicle = GetClosestVehicle()
 | 
			
		||||
    local closestCapPos = GetVehicleCapPos(closestVehicle)
 | 
			
		||||
    local closestVehicleHash = GetEntityModel(closestVehicle)
 | 
			
		||||
    local customVehicleParameters = (Config.CustomVehicleParametersHash[closestVehicleHash] or Config.CustomVehicleParametersHash.default or { distance = 1.2, nozzleOffset = { forward = 0.0, right = -0.15, up = 0.5 }, nozzleRotation = { x = 0, y = 0, z = 0} })
 | 
			
		||||
    if not closestCapPos then
 | 
			
		||||
        print("Cap not found for vehicle")
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    local finalWorldPos = getWorldPosFromOffset(closestVehicle, customVehicleParameters.nozzleOffset)
 | 
			
		||||
 | 
			
		||||
    return closestVehicle, finalWorldPos, closestVehicleHash, customVehicleParameters
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
function getWorldPosFromOffset(vehicle, offset)
 | 
			
		||||
    local closestCapPos = GetVehicleCapPos(vehicle)
 | 
			
		||||
    local forwardVector, rightVector, upVector, _ = GetEntityMatrix(vehicle)
 | 
			
		||||
 | 
			
		||||
    -- Adjust the offsets
 | 
			
		||||
    local forwardOffset = forwardVector * offset.forward
 | 
			
		||||
    local rightoffset = rightVector * offset.right
 | 
			
		||||
    local upOffset = upVector * offset.up
 | 
			
		||||
 | 
			
		||||
    -- Final world position of the nozzle point
 | 
			
		||||
    return vector3(
 | 
			
		||||
        closestCapPos.x + forwardOffset.x + rightoffset.x + upOffset.x,
 | 
			
		||||
        closestCapPos.y + forwardOffset.y + rightoffset.y + upOffset.y,
 | 
			
		||||
        closestCapPos.z + forwardOffset.z + rightoffset.z + upOffset.z
 | 
			
		||||
    )
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
function terminateRefuelThread()
 | 
			
		||||
    -- Stop the refueling process
 | 
			
		||||
    if refuelingThread and IsThreadActive(refuelingThread) then
 | 
			
		||||
        TerminateThread(refuelingThread)
 | 
			
		||||
        refuelingThread = nil
 | 
			
		||||
    end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
function stopRefuelAnimation()
 | 
			
		||||
    local ped = PlayerPedId()
 | 
			
		||||
    ClearPedTasks(ped)
 | 
			
		||||
    RemoveAnimDict("weapons@misc@jerrycan@")
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
function stopRefuelAction()
 | 
			
		||||
    -- Stop refuelling
 | 
			
		||||
    stopRefuelAnimation()
 | 
			
		||||
    SendNUIMessage({ hideRefuelDisplay = true })
 | 
			
		||||
    attachNozzleToPed()
 | 
			
		||||
    isRefuelling = false
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
function attachNozzleToVehicle(closestVehicle, customVehicleParameters)
 | 
			
		||||
    DetachEntity(fuelNozzle, true, true)
 | 
			
		||||
 | 
			
		||||
    -- Find the appropriate bone for the fuel cap
 | 
			
		||||
    local tankBones = vehicleCapBoneList()
 | 
			
		||||
    local boneIndex = -1
 | 
			
		||||
 | 
			
		||||
    for _, boneName in ipairs(tankBones) do
 | 
			
		||||
        boneIndex = GetEntityBoneIndexByName(closestVehicle, boneName)
 | 
			
		||||
        if boneIndex ~= -1 then
 | 
			
		||||
            break
 | 
			
		||||
        end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    if boneIndex ~= -1 then
 | 
			
		||||
        local vehicleRotation = GetEntityRotation(closestVehicle)
 | 
			
		||||
        local forwardVector, rightVector, upVector, _ = GetEntityMatrix(closestVehicle)
 | 
			
		||||
 | 
			
		||||
        -- Adjust the offsets
 | 
			
		||||
        local forwardOffset = forwardVector * customVehicleParameters.nozzleOffset.forward
 | 
			
		||||
        local rightoffset = rightVector * customVehicleParameters.nozzleOffset.right
 | 
			
		||||
        local upOffset = upVector * customVehicleParameters.nozzleOffset.up
 | 
			
		||||
        local finalOffset = forwardOffset + rightoffset + upOffset
 | 
			
		||||
 | 
			
		||||
        -- Adjust the rotation
 | 
			
		||||
        local nozzleRotation = customVehicleParameters.nozzleRotation or { x = 0, y = 0, z = 0 }
 | 
			
		||||
        local finalRotationX = vehicleRotation.x + nozzleRotation.x
 | 
			
		||||
        local finalRotationY = vehicleRotation.y + nozzleRotation.y
 | 
			
		||||
        local finalRotationZ = vehicleRotation.z + nozzleRotation.z
 | 
			
		||||
 | 
			
		||||
        -- Attach the nozzle to the vehicle's fuel cap bone with the calculated rotation
 | 
			
		||||
        AttachEntityToEntity(fuelNozzle, closestVehicle, boneIndex, finalOffset.x, finalOffset.y, finalOffset.z, finalRotationX - 45, finalRotationY, finalRotationZ - 90, false, false, false, false, 2, false)
 | 
			
		||||
    else
 | 
			
		||||
        print("No valid fuel cap bone found on the vehicle.")
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    -- Set the global variable to indicate the vehicle attached to nozzle
 | 
			
		||||
    vehicleAttachedToNozzle = closestVehicle
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
function attachNozzleToPed()
 | 
			
		||||
    DetachEntity(fuelNozzle, true, true)
 | 
			
		||||
 | 
			
		||||
    local ped = PlayerPedId()
 | 
			
		||||
    local pedBone = GetPedBoneIndex(ped, 18905)
 | 
			
		||||
    AttachEntityToEntity(fuelNozzle, ped, pedBone, 0.13, 0.04, 0.01, -42.0, -115.0, -63.42, false, true, false, true, 0, true)
 | 
			
		||||
 | 
			
		||||
    vehicleAttachedToNozzle = nil
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
function getNearestPumpRopeLength(fuelTypePurchased, pumpCoords)
 | 
			
		||||
    local distanceToFindPump = 10
 | 
			
		||||
    local ropeLength = Config.DefaultRopeLength
 | 
			
		||||
    if fuelTypePurchased == "electricfast" or fuelTypePurchased == "electricnormal" then
 | 
			
		||||
        for _, pumpConfig in pairs(Config.Electric.chargersLocation) do
 | 
			
		||||
            local distance = #(vector3(pumpConfig.location.x, pumpConfig.location.y, pumpConfig.location.z) - pumpCoords)
 | 
			
		||||
            if distance < distanceToFindPump then
 | 
			
		||||
                ropeLength = pumpConfig.ropeLength
 | 
			
		||||
                break
 | 
			
		||||
            end
 | 
			
		||||
        end
 | 
			
		||||
    else
 | 
			
		||||
        for _, pumpConfig in pairs(Config.CustomGasPumpLocations) do
 | 
			
		||||
            local distance = #(vector3(pumpConfig.location.x, pumpConfig.location.y, pumpConfig.location.z) - pumpCoords)
 | 
			
		||||
            if distance < distanceToFindPump then
 | 
			
		||||
                ropeLength = pumpConfig.ropeLength
 | 
			
		||||
                break
 | 
			
		||||
            end
 | 
			
		||||
        end
 | 
			
		||||
    end
 | 
			
		||||
    return ropeLength
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
function createFuelNozzleObject(fuelTypePurchased)
 | 
			
		||||
    local nozzle_prop_label = Config.NozzleProps.gas
 | 
			
		||||
    -- Change the nozzle prop to electric
 | 
			
		||||
    if fuelTypePurchased == "electricfast" or fuelTypePurchased == "electricnormal" then
 | 
			
		||||
        nozzle_prop_label = Config.NozzleProps.electric
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    RequestModel(nozzle_prop_label)
 | 
			
		||||
    while not HasModelLoaded(nozzle_prop_label) do
 | 
			
		||||
        Wait(50)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    return CreateObject(joaat(nozzle_prop_label), 1.0, 1.0, 1.0, true, true, false)
 | 
			
		||||
end
 | 
			
		||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue