Files
KingMcDonalds 765aa151a3 fixing vehicles
2026-03-13 23:31:07 -07:00

398 lines
16 KiB
Lua

vRP = nil
ESX = nil
if ConfigHose.Notifications.Enabled and ConfigHose.Notifications.Framework.vRP then
local Tunnel = module("vrp", "lib/Tunnel")
local Proxy = module("vrp", "lib/Proxy")
vRP = Proxy.getInterface("vRP")
end
if ConfigHose.Notifications.Enabled and ConfigHose.Notifications.Framework.ESX then
ESX = exports["es_extended"]:getSharedObject()
end
if ConfigHose.EnablePositioningCommand then
TriggerEvent('chat:addSuggestion', '/'.."findhosepositioning", "Find rope spawn point with rotation", {
{ name="type", help="hose or hand" }
})
RegisterCommand("findhosepositioning", function(source, args)
local ropeLabel = (args[1] or "hose"):lower()
local ped = PlayerPedId()
local ropeType = 4
if RopeManager.RopeTypes and RopeManager.RopeTypes[ropeLabel] then
ropeType = RopeManager.RopeTypes[ropeLabel]
end
local targetVehicle = GetVehiclePedIsIn(ped, false)
if targetVehicle == 0 then targetVehicle = GetClosestVehicle(GetEntityCoords(ped)) end
if targetVehicle == 0 then return Notify("No vehicle found!") end
RopeLoadTextures()
local vehPos = GetEntityCoords(targetVehicle)
local previewRope = AddRope(vehPos.x, vehPos.y, vehPos.z, 0.0, 0.0, 0.0, 20.0, ropeType, 20.0, 0.5, 1.0, false, false, false, 5.0, false, 0)
local offSet = {x = 0.0, y = 0.0, z = 0.0}
local rotation = {x = 0.0, y = 0.0, z = 0.0}
local depth = 0.2
local mode = "MOVE"
local editing = true
Notify("~b~POSITIONING MODE~w~\n[TAB] Toggle Move/Rotate\n[Arrows] Adjust\n[INSERT/DELETE] Depth\n[ENTER] Save")
SetEntityAlpha(targetVehicle, 150, false)
while editing do
Wait(0)
local speed = IsControlPressed(0, 21) and 0.05 or 0.005
if IsControlJustPressed(0, 192) then
mode = (mode == "MOVE") and "ROTATE" or "MOVE"
Notify("Mode: ~y~" .. mode)
end
if IsControlPressed(0, 121) then depth = depth + 0.005 end
if IsControlPressed(0, 178) then depth = depth - 0.005 end
local up = IsControlPressed(0, ConfigHose.PositioningControls.up)
local down = IsControlPressed(0, ConfigHose.PositioningControls.down)
local forward = IsControlPressed(0, ConfigHose.PositioningControls.forwards)
local backward = IsControlPressed(0, ConfigHose.PositioningControls.backwards)
local left = IsControlPressed(0, ConfigHose.PositioningControls.left)
local right = IsControlPressed(0, ConfigHose.PositioningControls.right)
if mode == "MOVE" then
if up then offSet.z = offSet.z + speed end
if down then offSet.z = offSet.z - speed end
if forward then offSet.y = offSet.y + speed end
if backward then offSet.y = offSet.y - speed end
if left then offSet.x = offSet.x - speed end
if right then offSet.x = offSet.x + speed end
else
local rSpeed = speed * 50.0
if up then rotation.x = rotation.x + rSpeed end
if down then rotation.x = rotation.x - rSpeed end
if left then rotation.z = rotation.z + rSpeed end
if right then rotation.z = rotation.z - rSpeed end
end
local forwardVec = RotationToDirection(rotation)
local localPortPos = vector3(offSet.x, offSet.y, offSet.z)
local localBendPosA = localPortPos - (forwardVec * depth)
local localBendPosB = localPortPos - (forwardVec * (depth * 0.5))
local worldPointC = GetOffsetFromEntityInWorldCoords(targetVehicle, localPortPos.x, localPortPos.y, localPortPos.z)
local worldPointA = GetOffsetFromEntityInWorldCoords(targetVehicle, localBendPosA.x, localBendPosA.y, localBendPosA.z)
local worldPointB = GetOffsetFromEntityInWorldCoords(targetVehicle, localBendPosB.x, localBendPosB.y, localBendPosB.z)
local handPos = GetWorldPositionOfEntityBone(ped, GetPedBoneIndex(ped, 6286))
local vertexCount = GetRopeVertexCount(previewRope)
PinRopeVertex(previewRope, 0, handPos.x, handPos.y, handPos.z)
PinRopeVertex(previewRope, vertexCount - 1, worldPointA.x, worldPointA.y, worldPointA.z)
PinRopeVertex(previewRope, vertexCount - 2, worldPointB.x, worldPointB.y, worldPointB.z)
PinRopeVertex(previewRope, vertexCount - 3, worldPointC.x, worldPointC.y, worldPointC.z)
if IsControlJustPressed(0, ConfigHose.PositioningControls.enter) then editing = false end
end
ResetEntityAlpha(targetVehicle)
print(string.format("^2--- %s RESULT ---^7", ropeLabel:upper()))
if ropeLabel == "hose" then
print(string.format('{ x = %.3f, y = %.3f, z = %.3f, rx = %.3f, ry = %.3f, rz = %.3f, depth = %.3f, type = "%s", portId = "attack1" },', offSet.x, offSet.y, offSet.z, rotation.x, rotation.y, rotation.z, depth, ropeLabel))
else
print(string.format('{ x = %.3f, y = %.3f, z = %.3f, rx = %.3f, ry = %.3f, rz = %.3f, depth = %.3f, type = "%s" },', offSet.x, offSet.y, offSet.z, rotation.x, rotation.y, rotation.z, depth, ropeLabel))
end
DeleteRope(previewRope)
Notify("Data printed to F8 console.")
end, false)
end
function Notify(text)
if not ConfigHose.Notifications.Enabled then
return
end
if ConfigHose.Notifications.Framework.ESX then
if ESX ~= nil then
ESX.ShowNotification(text)
end
elseif ConfigHose.Notifications.Framework.QBCore then
TriggerEvent('QBCore:Notify', text, 'primary')
elseif ConfigHose.Notifications.Framework.QBX then
exports.qbx_core:Notify(text, 'primary')
elseif ConfigHose.Notifications.Framework.vRP then
vRP.notify(source, {text})
elseif ConfigHose.Notifications.Framework.okok then
exports['okokNotify']:Alert("Smart Hose", text, 2000, 'info', true)
else
showBaseNotification(text)
end
end
function showBaseNotification(message)
-- Base game notifications
SetNotificationTextEntry("STRING")
AddTextComponentString(message)
DrawNotification(0,1)
end
-- @GeneralFunctions
function DisplayHelpText(text)
SetTextComponentFormat("STRING")
AddTextComponentString(text)
DisplayHelpTextFromStringLabel(0, 0, ConfigHose.Notifications.HelpTextSound, -1)
end
function drawInstructionalText(msg, coords)
AddTextEntry('instructionalText', msg)
SetFloatingHelpTextWorldPosition(1, coords)
SetFloatingHelpTextStyle(1, 1, 2, -1, 3, 0)
BeginTextCommandDisplayHelp('instructionalText')
AddTextComponentSubstringPlayerName(msg)
EndTextCommandDisplayHelp(2, false, false, -1)
end
function IsFireHoseEnabled()
return (HoseManager.hasFireHose and not HoseManager.nozzleDropped)
end
exports("IsFireHoseEnabled", IsFireHoseEnabled)
function IsFireHoseShooting()
return HoseManager.pressed
end
exports("IsFireHoseShooting", IsFireHoseShooting)
function IsFireHoseShootingWater()
return ParticleManager.isWaterDecal
end
exports("IsFireHoseShootingWater", IsFireHoseShootingWater)
function IsVehicleUsingWater(vehicleNetID)
local settings = HoseManager.vehicleSettings[vehicleNetID]
if not settings then return true end
return settings.decalType
end
exports("IsVehicleUsingWater", IsVehicleUsingWater)
function GetCurrentDecalCoords()
return ParticleManager.CurrentDecalCoords
end
exports("GetCurrentDecalCoords", GetCurrentDecalCoords)
function GetCurrentHosePressure()
return ParticleManager.particleScale
end
exports("GetCurrentHosePressure", GetCurrentHosePressure)
if ConfigHose.InteractType.TruckInteraction.Custom then
local function _toNetId(ent)
if ent and DoesEntityExist(ent) then return ToNetId(ent) end
return nil
end
local function _neighborsFor(netId)
local list = {}
if not netId then return list end
local RM = RopeManager or {}
local cv = RM.connectedVehicles and RM.connectedVehicles[netId]
if type(cv) == 'number' then list[#list+1] = cv
elseif type(cv) == 'table' then for nid,_ in pairs(cv) do list[#list+1] = tonumber(nid) or nid end end
local ic = RM.incomingConnections and RM.incomingConnections[netId]
if type(ic) == 'number' then list[#list+1] = ic
elseif type(ic) == 'table' then for nid,_ in pairs(ic) do list[#list+1] = tonumber(nid) or nid end end
return list
end
local function _buildCtx(vehicle)
local ped = PlayerPedId()
local pos = GetEntityCoords(ped)
local model = GetEntityModel(vehicle)
local vs = (ConfigHose.Rope.VehicleSettings[model] or {})
local useBone = vs.useBone or false
local bones = vs.bones or {}
local offsets = vs.offsets or { { x = 0.0, y = 0.0, z = 0.0 } }
local pts = getAttachmentPoints(vehicle, useBone, bones, offsets)
if type(pts) ~= 'table' or #pts == 0 then pts = { GetEntityCoords(vehicle) } end
local closest = pts[1]
local minDist = #(pos - closest)
for i = 2, #pts do
local p = pts[i]
local d = #(pos - p)
if d < minDist then closest, minDist = p, d end
end
local meId = GetPlayerServerId(PlayerId())
local vehNet = _toNetId(vehicle)
local neigh = _neighborsFor(vehNet)
return {
ped = ped,
playerServerId = meId,
vehicle = vehicle,
vehNet = vehNet,
vehModel = model,
promptCoords = closest,
vehicleDistance = minDist,
neighbors = neigh,
nozzle = HoseManager.nozzle,
nozzleDropped = HoseManager.nozzleDropped,
currentVehicle = HoseManager.currentVehicle,
handLineActive = HoseManager.handLine[meId] and true or false,
currentVehicleRelay = HoseManager.currentVehicleRelay,
supplyEnabled = IsSupplyLineEnabled(),
}
end
-- Actions you can call from your custom interactions
HoseCustomActions = {
GrabHose = function(ctx)
HoseManager.currentVehicle = ctx.vehicle
InitializeFireHose()
AttachRopeToProp()
end,
StoreHose = function(ctx)
if HoseManager.nozzle and HoseManager.currentVehicle == ctx.vehicle and not HoseManager.nozzleDropped then
UnequipFireHose()
else
Notify(ConfigHose.Translations.cannotStoreHoseWhileOnGround)
end
end,
GrabRelay = function(ctx)
HoseManager.currentVehicleRelay = ctx.vehicle
InitializeHandLine()
AttachRopeToHand()
end,
StoreRelay = function(_ctx)
DeinitializeHandLine()
end,
ConnectRelayHere = function(ctx)
DeinitializeHandLine()
ConnectRelayToVehicle(ctx.vehicle)
end,
QuickDisconnectNearest = function(ctx)
if not ctx.vehNet or #ctx.neighbors == 0 then return end
local best, bestD, myPos = nil, 1e9, GetEntityCoords(PlayerPedId())
for _, n in ipairs(ctx.neighbors) do
local ent = NetEnt(n)
if ent and DoesEntityExist(ent) then
local d = #(myPos - GetEntityCoords(ent))
if d < bestD then best, bestD = n, d end
elseif not best then
best = n
end
end
if best then
local sId, tId = canonicalPair(ctx.vehNet, best)
DisconnectRelayLine(sId, tId, ctx.vehNet)
end
end,
OpenPanel = function(_ctx)
OpenControlPanel()
end
}
-- ctx = _buildCtx(vehicle) (state for the vehicle/player)
-- A = HoseCustomActions (ready actions)
-- Draw helpers available: drawInstructionalText() / DisplayHelpText() from this file.
-- Example below mirrors the original E/G/Z flow aka ConfigHose.TruckInteraction.InteractType.Drawtext.
if not CustomInteractThink then
-- CustomInteractThink = function(ctx, A)
-- local lines = {}
-- if ctx.nozzle then
-- if ctx.currentVehicle == ctx.vehicle and not ctx.nozzleDropped then
-- lines[#lines+1] = ConfigHose.Translations.storeHoseMessage
-- if IsControlJustReleased(0, ConfigHose.Keys.Interact) then A.StoreHose(ctx) end
-- else
-- lines[#lines+1] = ConfigHose.Translations.cannotStoreHoseWhileOnGround
-- end
-- elseif ctx.handLineActive then
-- if ctx.supplyEnabled then
-- if ctx.currentVehicleRelay == ctx.vehicle then
-- if #ctx.neighbors > 0 then lines[#lines+1] = ConfigHose.Translations.disconnectLine end
-- lines[#lines+1] = ConfigHose.Translations.storeSupplyLine
-- if IsControlJustReleased(0, ConfigHose.Keys.GrabLine) then
-- if #ctx.neighbors > 0 then A.QuickDisconnectNearest(ctx) else A.StoreRelay(ctx) end
-- end
-- else
-- if #ctx.neighbors > 0 then
-- lines[#lines+1] = ConfigHose.Translations.disconnectLine
-- if IsControlJustReleased(0, ConfigHose.Keys.GrabLine) then A.QuickDisconnectNearest(ctx) end
-- else
-- lines[#lines+1] = ConfigHose.Translations.connectRelayLineMessage
-- if IsControlJustReleased(0, ConfigHose.Keys.GrabLine) then A.ConnectRelayHere(ctx) end
-- end
-- end
-- end
-- else
-- if ctx.supplyEnabled then
-- if #ctx.neighbors > 0 then
-- lines[#lines+1] = ConfigHose.Translations.grabHoseMessage
-- lines[#lines+1] = ConfigHose.Translations.disconnectLine
-- else
-- lines[#lines+1] = ConfigHose.Translations.grabHoseMessage
-- lines[#lines+1] = ConfigHose.Translations.SupplyLine
-- end
-- else
-- lines[#lines+1] = ConfigHose.Translations.grabHoseMessage
-- end
-- if IsControlJustReleased(0, ConfigHose.Keys.Interact) then A.GrabHose(ctx) end
-- if ctx.supplyEnabled and IsControlJustReleased(0, ConfigHose.Keys.GrabLine) then A.GrabRelay(ctx) end
-- end
-- -- SHS Panel
-- if not ctx.nozzle and ctx.supplyEnabled then
-- local showPanelHint = (ctx.handLineActive and ctx.currentVehicleRelay == ctx.vehicle) or (not ctx.nozzle and not ctx.handLineActive)
-- if showPanelHint then
-- lines[#lines+1] = ConfigHose.Translations.interactDisplay
-- if IsControlJustReleased(0, ConfigHose.Keys.OpenDisplayPrompt) then A.OpenPanel(ctx) end
-- end
-- end
-- if #lines > 0 then drawInstructionalText(table.concat(lines, "\n"), ctx.promptCoords) end
-- end
CustomInteractThink = function(ctx, A)
-- Write logic here
-- ctx = live state for the closest fire vehicle
-- A = actions you can call
end
end
CreateThread(function()
while true do
Wait(1)
local ped = PlayerPedId()
if IsPedInAnyVehicle(ped, false) then
Wait(500)
else
local pos = GetEntityCoords(ped)
local vehicle = GetClosestVehicle(pos)
if vehicle and DoesEntityExist(vehicle) and IsVehicleDriveable(vehicle, false) and HasWaterTank(vehicle) then
local ctx = _buildCtx(vehicle)
if ctx.vehicleDistance < 3.0 then
local ok, err = pcall(CustomInteractThink, ctx, HoseCustomActions)
if not ok then print("^1[CustomInteract] error:^0", err) end
else
Wait(250)
end
else
Wait(750)
end
end
end
end)
end