Files
ND_Core/ND_Fuel/source/client.lua

617 lines
24 KiB
Lua
Raw Normal View History

local FUEL_DECOR = "_ANDY_FUEL_DECORE_"
local nozzleDropped = false
local holdingNozzle = false
local nozzleInVehicle = false
local nozzle
local rope
local vehicleFueling
local usedPump
local pumpCoords
local wastingFuel = false
local usingCan = false
-- Nozzle Z position based on vehicle class.
local nozzleBasedOnClass = {
0.65, -- Compacts
0.65, -- Sedans
0.85, -- SUVs
0.6, -- Coupes
0.55, -- Muscle
0.6, -- Sports Classics
0.6, -- Sports
0.55, -- Super
0.12, -- Motorcycles
0.8, -- Off-road
0.7, -- Industrial
0.6, -- Utility
0.7, -- Vans
0.0, -- Cycles
0.0, -- Boats
0.0, -- Helicopters
0.0, -- Planes
0.6, -- Service
0.65, -- Emergency
0.65, -- Military
0.75, -- Commercial
0.0 -- Trains
}
-- ND Core object.
if not config.standalone then
NDCore = exports["ND_Core"]:GetCoreObject()
end
-- Setting the electric vehicle config keys to hashes.
for _, vehHash in pairs(config.electricVehicles) do
config.electricVehicles[vehHash] = vehHash
end
-- Get the fuel of a vehicle, which is set to an entity.
function GetFuel(vehicle)
if not DecorExistOn(vehicle, FUEL_DECOR) then
return GetVehicleFuelLevel(vehicle)
end
return DecorGetFloat(vehicle, FUEL_DECOR)
end
-- Setting the fuel to the vehicle entity using decor.
function SetFuel(vehicle, fuel)
if type(fuel) == "number" and fuel >= 0 and fuel <= 100 then
SetVehicleFuelLevel(vehicle, fuel)
DecorSetFloat(vehicle, FUEL_DECOR, GetVehicleFuelLevel(vehicle))
end
end
-- returns pump position if a player is near it.
function nearPump(coords)
local entity = nil
for hash in pairs(config.pumpModels) do
entity = GetClosestObjectOfType(coords.x, coords.y, coords.z, 0.8, hash, true, true, true)
if entity ~= 0 then break end
end
if config.pumpModels[GetEntityModel(entity)] then
return GetEntityCoords(entity), entity
end
end
-- Draws 3D text on coords.
function DrawText3D(x, y, z, text)
local onScreen, _x, _y = World3dToScreen2d(x, y, z)
local pX, pY, pZ = table.unpack(GetGameplayCamCoords())
SetTextScale(0.4, 0.4)
SetTextFont(4)
SetTextProportional(1)
SetTextEntry("STRING")
SetTextCentre(true)
SetTextColour(255, 255, 255, 255)
SetTextOutline()
AddTextComponentString(text)
DrawText(_x, _y)
end
-- used to load the filling manually animation.
function LoadAnimDict(dict)
if not HasAnimDictLoaded(dict) then
RequestAnimDict(dict)
while not HasAnimDictLoaded(dict) do
Wait(1)
end
end
end
-- Used to play the effect of pouring fuel from the nozzle.
function PlayEffect(pdict, pname)
CreateThread(function()
local position = GetOffsetFromEntityInWorldCoords(nozzle, 0.0, 0.28, 0.17)
UseParticleFxAssetNextCall(pdict)
local pfx = StartParticleFxLoopedAtCoord(pname, position.x, position.y, position.z, 0.0, 0.0, GetEntityHeading(nozzle), 1.0, false, false, false, false)
Wait(100)
StopParticleFxLooped(pfx, 0)
end)
end
-- Getting the vehicle infront if the player.
function vehicleInFront()
local entity = nil
local offset = GetOffsetFromEntityInWorldCoords(ped, 0.0, 2.0, 0.0)
local rayHandle = CastRayPointToPoint(pedCoords.x, pedCoords.y, pedCoords.z - 1.3, offset.x, offset.y, offset.z, 10, ped, 0)
local A, B, C, D, entity = GetRaycastResult(rayHandle)
if IsEntityAVehicle(entity) then
return entity
end
end
-- Create nozzle, rope and attach them to the player.
function grabNozzleFromPump()
LoadAnimDict("anim@am_hold_up@male")
TaskPlayAnim(ped, "anim@am_hold_up@male", "shoplift_high", 2.0, 8.0, -1, 50, 0, 0, 0, 0)
Wait(300)
nozzle = CreateObject(`prop_cs_fuel_nozle`, 0, 0, 0, true, true, true)
AttachEntityToEntity(nozzle, ped, GetPedBoneIndex(ped, 0x49D9), 0.11, 0.02, 0.02, -80.0, -90.0, 15.0, true, true, false, true, 1, true)
RopeLoadTextures()
while not RopeAreTexturesLoaded() do
Wait(0)
end
RopeLoadTextures()
while not pump do
Wait(0)
end
rope = AddRope(pump.x, pump.y, pump.z, 0.0, 0.0, 0.0, 3.0, 1, 1000.0, 0.0, 1.0, false, false, false, 1.0, true)
while not rope do
Wait(0)
end
ActivatePhysics(rope)
Wait(50)
local nozzlePos = GetEntityCoords(nozzle)
nozzlePos = GetOffsetFromEntityInWorldCoords(nozzle, 0.0, -0.033, -0.195)
AttachEntitiesToRope(rope, pumpHandle, nozzle, pump.x, pump.y, pump.z + 1.45, nozzlePos.x, nozzlePos.y, nozzlePos.z, 5.0, false, false, nil, nil)
nozzleDropped = false
holdingNozzle = true
nozzleInVehicle = false
vehicleFueling = false
usedPump = pumpHandle
SendNUIMessage({
type = "status",
status = true
})
SendNUIMessage({
type = "update",
fuelCost = "0.00",
fuelTank = "0.00"
})
end
-- attach the nozzle to the player.
function grabExistingNozzle()
AttachEntityToEntity(nozzle, ped, GetPedBoneIndex(ped, 0x49D9), 0.11, 0.02, 0.02, -80.0, -90.0, 15.0, true, true, false, true, 1, true)
nozzleDropped = false
holdingNozzle = true
nozzleInVehicle = false
vehicleFueling = false
end
-- attach nozzle to vehicle.
function putNozzleInVehicle(vehicle, ptankBone, isBike, dontClear, newTankPosition)
if isBike then
AttachEntityToEntity(nozzle, vehicle, ptankBone, 0.0 + newTankPosition.x, -0.2 + newTankPosition.y, 0.2 + newTankPosition.z, -80.0, 0.0, 0.0, true, true, false, false, 1, true)
else
AttachEntityToEntity(nozzle, vehicle, ptankBone, -0.18 + newTankPosition.x, 0.0 + newTankPosition.y, 0.75 + newTankPosition.z, -125.0, -90.0, -90.0, true, true, false, false, 1, true)
end
if not dontClear and IsEntityPlayingAnim(ped, "timetable@gardener@filling_can", "gar_ig_5_filling_can", 3) then
ClearPedTasks(ped)
end
nozzleDropped = false
holdingNozzle = false
nozzleInVehicle = true
wastingFuel = false
vehicleFueling = vehicle
end
-- detach nozzle from everything and hide ui.
function dropNozzle()
DetachEntity(nozzle, true, true)
nozzleDropped = true
holdingNozzle = false
nozzleInVehicle = false
vehicleFueling = false
SendNUIMessage({
type = "status",
status = false
})
end
-- delete nozzle and rope, and hide ui.
function returnNozzleToPump()
DeleteEntity(nozzle)
RopeUnloadTextures()
DeleteRope(rope)
nozzleDropped = false
holdingNozzle = false
nozzleInVehicle = false
vehicleFueling = false
SendNUIMessage({
type = "status",
status = false
})
end
-- Get important information.
CreateThread(function()
while true do
ped = PlayerPedId()
pedCoords = GetEntityCoords(ped)
pump, pumpHandle = nearPump(pedCoords)
veh = GetVehiclePedIsIn(ped, true)
Wait(500)
end
end)
-- Refuel the vehicle.
CreateThread(function()
while true do
Wait(2000)
if vehicleFueling then
local classMultiplier = config.vehicleClasses[GetVehicleClass(vehicleFueling)]
if usingCan then
while usingCan do
local fuel = GetFuel(vehicleFueling)
if fuel < 97 then
SetFuel(vehicleFueling, fuel + (2.5 / classMultiplier))
else
fuel = 100.0
SetFuel(vehicleFueling, fuel)
vehicleFueling = false
end
Wait(500)
end
else
local cost = 0
while vehicleFueling do
local fuel = GetFuel(vehicleFueling)
if not DoesEntityExist(vehicleFueling) then
dropNozzle()
break
end
fuel = GetFuel(vehicleFueling)
cost = cost + ((2.0 / classMultiplier) * config.fuelCostMultiplier) - math.random(0, 100) / 100
if not config.standalone then
if NDCore.Functions.GetSelectedCharacter().bank < cost then
SendNUIMessage({
type = "warn"
})
vehicleFueling = false
break
end
end
if fuel < 97 then
SetFuel(vehicleFueling, fuel + ((2.0 / classMultiplier) - math.random(0, 100) / 100))
else
fuel = 100.0
SetFuel(vehicleFueling, fuel)
vehicleFueling = false
end
SendNUIMessage({
type = "update",
fuelCost = string.format("%.2f", cost),
fuelTank = string.format("%.2f", fuel)
})
Wait(600)
end
if not config.standalone and cost ~= 0 then
TriggerServerEvent("ND_Fuel:pay", cost)
cost = 0
end
end
end
end
end)
-- pumping fuel on the groud.
CreateThread(function()
while true do
Wait(500)
if wastingFuel then
local cost = 0
while wastingFuel do
cost = cost + (2.0 * config.fuelCostMultiplier) - math.random(0, 100) / 100
SendNUIMessage({
type = "update",
fuelCost = string.format("%.2f", cost),
fuelTank = "0.0"
})
if not config.standalone then
if NDCore.Functions.GetSelectedCharacter().bank < cost then
SendNUIMessage({
type = "warn"
})
end
end
Wait(800)
end
if not config.standalone and cost ~= 0 then
TriggerServerEvent("ND_Fuel:pay", cost)
end
end
end
end)
-- Grabbing and returning the nozzle from the pump.
CreateThread(function()
local wait = 500
while true do
Wait(wait)
if pump then
wait = 0
if not holdingNozzle and not nozzleInVehicle and not nozzleDropped then
local jerryCanText = ""
local ammo = GetAmmoInPedWeapon(ped, 883325847)
local weapon = HasPedGotWeapon(ped, 883325847)
local price = config.jerryCanPrice
if not weapon then
jerryCanText = " \n$" .. price .. " buy Jerry Can [G]"
elseif weapon and GetSelectedPedWeapon(ped) == 883325847 and ammo < 4500 then
price = math.floor(config.jerryCanrefillCost - (config.jerryCanrefillCost / (4500 / ammo)))
jerryCanText = " \n$" .. price .. " refill Jerry Can [G]"
end
DrawText3D(pump.x, pump.y, pump.z + 1.2, "Grab Nozzle [E]" .. jerryCanText)
if IsControlJustPressed(0, 51) then
grabNozzleFromPump()
Wait(1000)
ClearPedTasks(ped)
end
if IsControlJustPressed(0, 47) then
if not config.standalone then
if NDCore.Functions.GetSelectedCharacter().bank > price then
TriggerServerEvent("ND_Fuel:jerryCan", price)
if HasPedGotWeapon(ped, 883325847) then
SetPedAmmo(ped, 883325847, 4500)
else
GiveWeaponToPed(ped, 883325847, 4500, false, true)
end
end
else
if HasPedGotWeapon(ped, 883325847) then
SetPedAmmo(ped, 883325847, 4500)
else
GiveWeaponToPed(ped, 883325847, 4500, false, true)
end
end
end
elseif holdingNozzle and pumpHandle == usedPump then
DrawText3D(pump.x, pump.y, pump.z + 1.2, "Return Nozzle [E]")
if IsControlJustPressed(0, 51) then
LoadAnimDict("anim@am_hold_up@male")
TaskPlayAnim(ped, "anim@am_hold_up@male", "shoplift_high", 2.0, 8.0, -1, 50, 0, 0, 0, 0)
Wait(300)
returnNozzleToPump()
Wait(1000)
ClearPedTasks(ped)
end
end
else
wait = 500
end
end
end)
-- Attaching and taking the nozzle form the vehicle, and dropping the nozzle form the player or vehicle.
CreateThread(function()
local wait = 500
while true do
Wait(wait)
if holdingNozzle or nozzleInVehicle or nozzleDropped then
wait = 0
-- drop the nozzle and remove it if it's far away from the pump.
if pump then
pumpCoords = GetEntityCoords(usedPump)
end
if nozzle and pumpCoords then
nozzleLocation = GetEntityCoords(nozzle)
if #(pumpCoords - pedCoords) < 3.0 then
SendNUIMessage({
type = "status",
status = true
})
else
SendNUIMessage({
type = "status",
status = false
})
end
if #(nozzleLocation - pumpCoords) > 6.0 then
dropNozzle()
elseif #(pumpCoords - pedCoords) > 100.0 then
returnNozzleToPump()
end
if nozzleDropped and #(nozzleLocation - pedCoords) < 1.5 then
DrawText3D(nozzleLocation.x, nozzleLocation.y, nozzleLocation.z, "Grab Nozzle [E]")
if IsControlJustPressed(0, 51) then
LoadAnimDict("anim@mp_snowball")
TaskPlayAnim(ped, "anim@mp_snowball", "pickup_snowball", 2.0, 8.0, -1, 50, 0, 0, 0, 0)
Wait(700)
grabExistingNozzle()
ClearPedTasks(ped)
end
end
end
local veh = vehicleInFront(ped, pedCoords)
-- Animations for manually fueling and effect for sparying fuel.
if holdingNozzle and nozzle then
DisableControlAction(0, 25, true)
DisableControlAction(0, 24, true)
if IsDisabledControlPressed(0, 24) then
if veh and tankPosition and #(pedCoords - tankPosition) < 1.2 then
if not IsEntityPlayingAnim(ped, "timetable@gardener@filling_can", "gar_ig_5_filling_can", 3) then
LoadAnimDict("timetable@gardener@filling_can")
TaskPlayAnim(ped, "timetable@gardener@filling_can", "gar_ig_5_filling_can", 2.0, 8.0, -1, 50, 0, 0, 0, 0)
end
wastingFuel = false
vehicleFueling = veh
else
if IsEntityPlayingAnim(ped, "timetable@gardener@filling_can", "gar_ig_5_filling_can", 3) then
vehicleFueling = false
ClearPedTasks(ped)
end
if nozzleLocation then
wastingFuel = true
PlayEffect("core", "veh_trailer_petrol_spray")
end
end
else
if IsEntityPlayingAnim(ped, "timetable@gardener@filling_can", "gar_ig_5_filling_can", 3) then
vehicleFueling = false
ClearPedTasks(ped)
end
wastingFuel = false
end
end
-- attaching and taking the nozzle from the vehicle.
if veh then
local vehClass = GetVehicleClass(veh)
local zPos = nozzleBasedOnClass[vehClass + 1]
local isBike = false
local nozzleModifiedPosition = {
x = 0.0,
y = 0.0,
z = 0.0
}
local textModifiedPosition = {
x = 0.0,
y = 0.0,
z = 0.0
}
if vehClass == 8 and vehClass ~= 13 and not config.electricVehicles[GetHashKey(veh)] then
tankBone = GetEntityBoneIndexByName(veh, "petrolcap")
if tankBone == -1 then
tankBone = GetEntityBoneIndexByName(veh, "petroltank")
end
if tankBone == -1 then
tankBone = GetEntityBoneIndexByName(veh, "engine")
end
isBike = true
elseif vehClass ~= 13 and not config.electricVehicles[GetHashKey(veh)] then
tankBone = GetEntityBoneIndexByName(veh, "petrolcap")
if tankBone == -1 then
tankBone = GetEntityBoneIndexByName(veh, "petroltank_l")
end
if tankBone == -1 then
tankBone = GetEntityBoneIndexByName(veh, "hub_lr")
end
if tankBone == -1 then
tankBone = GetEntityBoneIndexByName(veh, "handle_dside_r")
nozzleModifiedPosition.x = 0.1
nozzleModifiedPosition.y = -0.5
nozzleModifiedPosition.z = -0.6
textModifiedPosition.x = 0.55
textModifiedPosition.y = 0.1
textModifiedPosition.z = -0.2
end
end
tankPosition = GetWorldPositionOfEntityBone(veh, tankBone)
if tankPosition and #(pedCoords - tankPosition) < 1.2 then
if not nozzleInVehicle and holdingNozzle then
DrawText3D(tankPosition.x + textModifiedPosition.x, tankPosition.y + textModifiedPosition.y, tankPosition.z + zPos + textModifiedPosition.z, "Attach Nozzle [E]")
if IsControlJustPressed(0, 51) then
LoadAnimDict("timetable@gardener@filling_can")
TaskPlayAnim(ped, "timetable@gardener@filling_can", "gar_ig_5_filling_can", 2.0, 8.0, -1, 50, 0, 0, 0, 0)
Wait(300)
putNozzleInVehicle(veh, tankBone, isBike, true, nozzleModifiedPosition)
Wait(300)
ClearPedTasks(ped)
end
elseif nozzleInVehicle then
DrawText3D(tankPosition.x + textModifiedPosition.x, tankPosition.y + textModifiedPosition.y, tankPosition.z + zPos + textModifiedPosition.z, "Grab Nozzle [E]")
if IsControlJustPressed(0, 51) then
LoadAnimDict("timetable@gardener@filling_can")
TaskPlayAnim(ped, "timetable@gardener@filling_can", "gar_ig_5_filling_can", 2.0, 8.0, -1, 50, 0, 0, 0, 0)
Wait(300)
grabExistingNozzle()
Wait(300)
ClearPedTasks(ped)
end
end
end
end
else
wait = 500
end
end
end)
-- refueling using jerry can.
CreateThread(function()
local wait = 500
while true do
Wait(wait)
if GetSelectedPedWeapon(ped) == 883325847 and not holdingNozzle and not nozzleInVehicle then
wait = 0
local veh = vehicleInFront(ped, pedCoords)
if veh then
local vehClass = GetVehicleClass(veh)
local zPos = nozzleBasedOnClass[vehClass + 1]
local can = GetAmmoInPedWeapon(ped, 883325847)
if vehClass == 8 and vehClass ~= 13 and not config.electricVehicles[GetHashKey(veh)] then
tankBone = GetEntityBoneIndexByName(veh, "petroltank")
if tankBone == -1 then
tankBone = GetEntityBoneIndexByName(veh, "engine")
end
elseif vehClass ~= 13 and not config.electricVehicles[GetHashKey(veh)] then
tankBone = GetEntityBoneIndexByName(veh, "petroltank_l")
if tankBone == -1 then
tankBone = GetEntityBoneIndexByName(veh, "hub_lr")
end
end
tankPosition = GetWorldPositionOfEntityBone(veh, tankBone)
if tankPosition and #(pedCoords - tankPosition) < 1.2 then
local fuel = GetFuel(veh)
DrawText3D(tankPosition.x, tankPosition.y, tankPosition.z + zPos, math.floor(fuel) .. "% refuel [E]")
local ammo = GetAmmoInPedWeapon(ped, 883325847)
if IsControlPressed(0, 51) and ammo > 0 then
if not IsEntityPlayingAnim(ped, "timetable@gardener@filling_can", "gar_ig_5_filling_can", 3) then
LoadAnimDict("timetable@gardener@filling_can")
TaskPlayAnim(ped, "timetable@gardener@filling_can", "gar_ig_5_filling_can", 2.0, 8.0, -1, 50, 0, 0, 0, 0)
elseif can and DoesEntityExist(veh) then
SetPedAmmo(ped, 883325847, ammo - 3)
vehicleFueling = veh
usingCan = true
end
else
vehicleFueling = false
usingCan = false
if IsEntityPlayingAnim(ped, "timetable@gardener@filling_can", "gar_ig_5_filling_can", 3) then
ClearPedTasks(ped)
end
end
end
end
else
wait = 500
end
end
end)
-- Create blips for each gas station location.
CreateThread(function()
for _, coords in pairs(config.blipLocations) do
local blip = AddBlipForCoord(coords)
SetBlipSprite(blip, 361)
SetBlipScale(blip, 0.9)
SetBlipColour(blip, 4)
SetBlipDisplay(blip, 4)
SetBlipAsShortRange(blip, true)
BeginTextCommandSetBlipName("STRING")
AddTextComponentString("Gas Station")
EndTextCommandSetBlipName(blip)
end
end)
-- vehicle fuel consumption.
CreateThread(function()
while true do
Wait(3500)
local pedVeh = GetVehiclePedIsIn(ped)
if pedVeh ~= 0 then
local vehClass = GetVehicleClass(pedVeh)
local fuel = GetFuel(pedVeh)
if fuel < 5.0 and GetIsVehicleEngineRunning(pedVeh) then
DisableControlAction(0, 71)
SetVehicleEngineOn(pedVeh, false, true, true)
end
SetFuel(pedVeh, fuel - ((GetVehicleCurrentRpm(pedVeh) * config.vehicleClasses[vehClass]) / 1.7))
end
end
end)
-- spawn pumps on the map.
CreateThread(function()
for _, pumps in pairs(config.addPumps) do
CreateObject(GetHashKey(pumps.hash), pumps.x, pumps.y, pumps.z - 1.0, true, true, true)
end
end)