forked from Simnation/Main
487 lines
15 KiB
Lua
487 lines
15 KiB
Lua
local createdRope = nil
|
|
local ropeLength = 10.0
|
|
local minRopeLength = 1.0
|
|
local lengthTick = 0.02
|
|
local enteredCloseVehicle = false
|
|
local closestTrailer = nil
|
|
local closestBoat = nil
|
|
local hasTakenRope = false
|
|
local hookedToBoat = false
|
|
local controlRope = false
|
|
local colObj = nil
|
|
local boatOnTrailer = false
|
|
|
|
local function getTrailerOffset(trailer)
|
|
local model = GetEntityModel(trailer)
|
|
if model == `yftrailer` then
|
|
return vector3(0.0, 1.5, 0.3) -- Angepasste Werte für yftrailer
|
|
else
|
|
return vector3(0.0, 1.8, 0.0) -- Original boattrailer Werte
|
|
end
|
|
end
|
|
|
|
local function getBoatAttachmentOffset(trailer)
|
|
local model = GetEntityModel(trailer)
|
|
if model == `yftrailer` then
|
|
return vector3(0.0, -1.0, 0.25) -- Angepasste Werte für yftrailer
|
|
else
|
|
return vector3(0.0, -1.02, 0.3) -- Original boattrailer Werte
|
|
end
|
|
end
|
|
|
|
local function isSupportedBoat(closest)
|
|
for _, model in pairs(Config.SupportedBoats) do
|
|
if GetEntityModel(closest) == model then
|
|
return true
|
|
end
|
|
end
|
|
end
|
|
|
|
local function isTrailer(vehicle)
|
|
local model = GetEntityModel(vehicle)
|
|
return model == `boattrailer` or model == `yftrailer`
|
|
end
|
|
|
|
local function getClosestVehicle(coords, maxDistance)
|
|
local vehicles = GetGamePool('CVehicle')
|
|
local closestVehicle, closestCoords
|
|
maxDistance = maxDistance or 2.0
|
|
|
|
for i = 1, #vehicles do
|
|
local vehicle = vehicles[i]
|
|
local vehicleCoords = GetEntityCoords(vehicle)
|
|
local distance = #(coords - vehicleCoords)
|
|
|
|
if distance < maxDistance then
|
|
maxDistance = distance
|
|
closestVehicle = vehicle
|
|
closestCoords = vehicleCoords
|
|
end
|
|
end
|
|
|
|
return closestVehicle, closestCoords
|
|
end
|
|
|
|
local function notify(text)
|
|
SetNotificationTextEntry("STRING")
|
|
AddTextComponentString(text)
|
|
DrawNotification(true, false)
|
|
end
|
|
|
|
CreateThread(function()
|
|
while true do
|
|
Wait(1000)
|
|
|
|
local playerPed = PlayerPedId()
|
|
local playerCoords = GetEntityCoords(playerPed)
|
|
local closestVehicle, closestCoords = getClosestVehicle(playerCoords, 3.0)
|
|
|
|
if closestVehicle ~= nil and #(playerCoords - closestCoords) < 3.0 then
|
|
if not enteredCloseVehicle then
|
|
local isBoat = isSupportedBoat(closestVehicle)
|
|
|
|
if isTrailer(closestVehicle) then
|
|
closestTrailer = closestVehicle
|
|
elseif isBoat then
|
|
closestBoat = closestVehicle
|
|
end
|
|
end
|
|
|
|
enteredCloseVehicle = true
|
|
else
|
|
enteredCloseVehicle = false
|
|
end
|
|
end
|
|
end)
|
|
|
|
CreateThread(function()
|
|
if GetResourceState('qb-target') == 'started' then
|
|
exports['qb-target']:AddGlobalVehicle({
|
|
options = {
|
|
{
|
|
type = "client",
|
|
event = "re_boat_winch:client:takeRope",
|
|
icon = 'fas fa-clipboard',
|
|
label = "Take the rope",
|
|
canInteract = function(entity)
|
|
if closestTrailer ~= entity or not isTrailer(entity) then
|
|
return false
|
|
end
|
|
return not boatOnTrailer and not hookedToBoat and not hasTakenRope
|
|
end
|
|
},
|
|
{
|
|
type = "client",
|
|
event = "re_boat_winch:client:returnRope",
|
|
icon = 'fas fa-clipboard',
|
|
label = "Return the rope",
|
|
canInteract = function(entity)
|
|
if closestTrailer ~= entity or not isTrailer(entity) then
|
|
return false
|
|
end
|
|
return hasTakenRope and not hookedToBoat and not boatOnTrailer
|
|
end
|
|
},
|
|
{
|
|
type = "client",
|
|
event = "re_boat_winch:client:controlRope",
|
|
icon = 'fas fa-clipboard',
|
|
label = "Control the rope",
|
|
canInteract = function(entity)
|
|
if closestTrailer ~= entity or not isTrailer(entity) then
|
|
return false
|
|
end
|
|
return not hasTakenRope and hookedToBoat
|
|
end
|
|
},
|
|
{
|
|
type = "client",
|
|
event = "re_boat_winch:client:detachBoat",
|
|
icon = 'fas fa-clipboard',
|
|
label = "Detach boat from trailer",
|
|
canInteract = function(entity)
|
|
if closestTrailer ~= entity or not isTrailer(entity) then
|
|
return false
|
|
end
|
|
return boatOnTrailer
|
|
end
|
|
},
|
|
{
|
|
type = "client",
|
|
event = "re_boat_winch:client:hookUpRope",
|
|
icon = 'fas fa-clipboard',
|
|
label = "Hook up the rope",
|
|
canInteract = function(entity)
|
|
if closestBoat ~= entity or not isSupportedBoat(entity) then
|
|
return false
|
|
end
|
|
return hasTakenRope and not hookedToBoat
|
|
end
|
|
},
|
|
{
|
|
type = "client",
|
|
event = "re_boat_winch:client:unHookRope",
|
|
icon = 'fas fa-clipboard',
|
|
label = "Unhook the rope",
|
|
canInteract = function(entity)
|
|
if closestBoat ~= entity or not isSupportedBoat(entity) then
|
|
return false
|
|
end
|
|
return not hasTakenRope and hookedToBoat and createdRope
|
|
end
|
|
}
|
|
},
|
|
distance = 2.5
|
|
})
|
|
else
|
|
exports.ox_target:addGlobalVehicle({
|
|
{
|
|
event = "re_boat_winch:client:takeRope",
|
|
icon = 'fas fa-clipboard',
|
|
label = "Take the rope",
|
|
name = "re_boat_winch:client:takeRope",
|
|
distance = 2.5,
|
|
canInteract = function(entity)
|
|
if closestTrailer ~= entity or not isTrailer(entity) then
|
|
return false
|
|
end
|
|
return not boatOnTrailer and not hookedToBoat and not hasTakenRope
|
|
end
|
|
},
|
|
{
|
|
event = "re_boat_winch:client:returnRope",
|
|
icon = 'fas fa-clipboard',
|
|
label = "Return the rope",
|
|
name = "re_boat_winch:client:returnRope",
|
|
distance = 2.5,
|
|
canInteract = function(entity)
|
|
if closestTrailer ~= entity or not isTrailer(entity) then
|
|
return false
|
|
end
|
|
return hasTakenRope and not hookedToBoat and not boatOnTrailer
|
|
end
|
|
},
|
|
{
|
|
event = "re_boat_winch:client:controlRope",
|
|
icon = 'fas fa-clipboard',
|
|
label = "Control the rope",
|
|
name = "re_boat_winch:client:controlRope",
|
|
distance = 2.5,
|
|
canInteract = function(entity)
|
|
if closestTrailer ~= entity or not isTrailer(entity) then
|
|
return false
|
|
end
|
|
return not hasTakenRope and hookedToBoat
|
|
end
|
|
},
|
|
{
|
|
event = "re_boat_winch:client:detachBoat",
|
|
icon = 'fas fa-clipboard',
|
|
label = "Detach boat from trailer",
|
|
name = "re_boat_winch:client:detachBoat",
|
|
distance = 2.5,
|
|
canInteract = function(entity)
|
|
if closestTrailer ~= entity or not isTrailer(entity) then
|
|
return false
|
|
end
|
|
return boatOnTrailer
|
|
end
|
|
},
|
|
{
|
|
event = "re_boat_winch:client:hookUpRope",
|
|
icon = 'fas fa-clipboard',
|
|
label = "Hook up the rope",
|
|
name = "re_boat_winch:client:hookUpRope",
|
|
distance = 2.5,
|
|
canInteract = function(entity)
|
|
if closestBoat ~= entity or not isSupportedBoat(entity) then
|
|
return false
|
|
end
|
|
return hasTakenRope and not hookedToBoat
|
|
end
|
|
},
|
|
{
|
|
event = "re_boat_winch:client:unHookRope",
|
|
icon = 'fas fa-clipboard',
|
|
label = "Unhook the rope",
|
|
name = "re_boat_winch:client:unHookRope",
|
|
distance = 2.5,
|
|
canInteract = function(entity)
|
|
if closestBoat ~= entity or not isSupportedBoat(entity) then
|
|
return false
|
|
end
|
|
return not hasTakenRope and hookedToBoat and createdRope
|
|
end
|
|
}
|
|
})
|
|
end
|
|
end)
|
|
|
|
AddEventHandler('onResourceStop', function(resourceName)
|
|
if resourceName ~= "re_boat_winch" then
|
|
return
|
|
end
|
|
|
|
if GetResourceState('qb-target') == 'started' then
|
|
exports['qb-target']:RemoveGlobalVehicle("Nimm das Seil")
|
|
exports['qb-target']:RemoveGlobalVehicle("Häng das SEil zurück")
|
|
exports['qb-target']:RemoveGlobalVehicle("Winde kontrollieren")
|
|
exports['qb-target']:RemoveGlobalVehicle("Boot vom Anhänger lösen")
|
|
exports['qb-target']:RemoveGlobalVehicle("Seil einhängen")
|
|
exports['qb-target']:RemoveGlobalVehicle("Seil aushängen")
|
|
else
|
|
exports.ox_target:removeGlobalVehicle("re_boat_winch:client:takeRope")
|
|
exports.ox_target:removeGlobalVehicle("re_boat_winch:client:returnRope")
|
|
exports.ox_target:removeGlobalVehicle("re_boat_winch:client:controlRope")
|
|
exports.ox_target:removeGlobalVehicle("re_boat_winch:client:detachBoat")
|
|
exports.ox_target:removeGlobalVehicle("re_boat_winch:client:hookUpRope")
|
|
exports.ox_target:removeGlobalVehicle("re_boat_winch:client:unHookRope")
|
|
end
|
|
end)
|
|
|
|
local function createRope(obj1, obj2, obj1Coords, obj2Coords, lenght)
|
|
DeleteRope(createdRope)
|
|
|
|
RopeLoadTextures()
|
|
while not RopeAreTexturesLoaded() do
|
|
Wait(0)
|
|
RopeLoadTextures()
|
|
end
|
|
|
|
RopeLoadTextures()
|
|
|
|
createdRope = AddRope(obj1Coords.x, obj1Coords.y, obj1Coords.z, 0.0, 0.0, 0.0, lenght, 1, Config.MaxRopeLength, 1.0,
|
|
1.0, false, true, false, 5.0, false, 0)
|
|
|
|
while not createdRope do
|
|
Wait(0)
|
|
end
|
|
|
|
ActivatePhysics(createdRope)
|
|
|
|
Wait(50)
|
|
|
|
AttachEntitiesToRope(createdRope, obj1, obj2, obj1Coords.x, obj1Coords.y, obj1Coords.z, obj2Coords.x, obj2Coords.y,
|
|
obj2Coords.z, lenght, false, false, nil, nil)
|
|
end
|
|
|
|
RegisterNetEvent('re_boat_winch:client:unHookRope', function()
|
|
hookedToBoat = false
|
|
controlRope = false
|
|
hasTakenRope = true
|
|
|
|
notify("Du hast das Seil ausgehakt")
|
|
|
|
local playerPed = PlayerPedId()
|
|
local trailerOffset = getTrailerOffset(closestTrailer)
|
|
local trailerCoords = GetOffsetFromEntityInWorldCoords(closestTrailer, trailerOffset.x, trailerOffset.y, trailerOffset.z)
|
|
local boneIndex = GetPedBoneIndex(playerPed, 0x49D9)
|
|
|
|
ropeLength = 5.0
|
|
colObj = CreateObject(`xm3_prop_xm3_hook_01a`, 0, 0, 0, true, true, true)
|
|
|
|
AttachEntityToEntity(colObj, playerPed, boneIndex, 0.11, 0.02, 0.02, -80.0, -90.0, 15.0, true,
|
|
true, false, true, 1, true)
|
|
|
|
local objCoords = GetEntityCoords(colObj)
|
|
|
|
createRope(closestTrailer, colObj, trailerCoords, objCoords, ropeLength)
|
|
end)
|
|
|
|
RegisterNetEvent('re_boat_winch:client:returnRope', function()
|
|
hasTakenRope = false
|
|
|
|
DeleteEntity(colObj)
|
|
DeleteRope(createdRope)
|
|
end)
|
|
|
|
RegisterNetEvent('re_boat_winch:client:detachBoat', function()
|
|
boatOnTrailer = false
|
|
|
|
DetachEntity(closestBoat, true, true)
|
|
|
|
local trailerOffset = getTrailerOffset(closestTrailer)
|
|
local trailerCoords = GetOffsetFromEntityInWorldCoords(closestTrailer, 0.0, -8.0, 0.0)
|
|
|
|
SetEntityCoords(closestBoat, trailerCoords.x, trailerCoords.y, trailerCoords.z)
|
|
end)
|
|
|
|
RegisterNetEvent('re_boat_winch:client:takeRope', function()
|
|
hasTakenRope = true
|
|
|
|
FreezeEntityPosition(closestTrailer, true)
|
|
SetEntityInvincible(closestTrailer, true)
|
|
|
|
local playerPed = PlayerPedId()
|
|
local playerCoords = GetEntityCoords(playerPed)
|
|
local trailerOffset = getTrailerOffset(closestTrailer)
|
|
local trailerCoords = GetOffsetFromEntityInWorldCoords(closestTrailer, trailerOffset.x, trailerOffset.y, trailerOffset.z)
|
|
local coordsDiff = #(trailerCoords - playerCoords)
|
|
local boneIndex = GetPedBoneIndex(playerPed, 0x49D9)
|
|
|
|
ropeLength = coordsDiff
|
|
colObj = CreateObject(`xm3_prop_xm3_hook_01a`, 0, 0, 0, true, true, true)
|
|
|
|
AttachEntityToEntity(colObj, playerPed, boneIndex, 0.11, 0.02, 0.02, -80.0, -90.0, 15.0, true, true, false, true, 1,
|
|
true)
|
|
|
|
local objCoords = GetEntityCoords(colObj)
|
|
|
|
createRope(closestTrailer, colObj, trailerCoords, objCoords, ropeLength)
|
|
end)
|
|
|
|
RegisterNetEvent('re_boat_winch:client:hookUpRope', function()
|
|
hookedToBoat = true
|
|
hasTakenRope = false
|
|
|
|
notify("Du hast den Haken genommen")
|
|
|
|
local trailerOffset = getTrailerOffset(closestTrailer)
|
|
local trailerCoords = GetOffsetFromEntityInWorldCoords(closestTrailer, trailerOffset.x, trailerOffset.y, trailerOffset.z)
|
|
local boatCoords = GetOffsetFromEntityInWorldCoords(closestBoat, 0.0, 3.9, 0.9)
|
|
local coordsDiff = #(trailerCoords - boatCoords)
|
|
|
|
ropeLength = coordsDiff
|
|
|
|
SetEntityInvincible(closestBoat, true)
|
|
DeleteEntity(colObj)
|
|
|
|
createRope(closestTrailer, closestBoat, trailerCoords, boatCoords, ropeLength)
|
|
end)
|
|
|
|
RegisterNetEvent('re_boat_winch:client:controlRope', function()
|
|
controlRope = true
|
|
|
|
notify("Du kontrollierst die Winde")
|
|
end)
|
|
|
|
local function attachBoatToTrailer()
|
|
if not DoesEntityExist(closestTrailer) or not DoesEntityExist(closestBoat) then
|
|
return
|
|
end
|
|
|
|
local attachOffset = getBoatAttachmentOffset(closestTrailer)
|
|
AttachEntityToEntity(closestBoat, closestTrailer, 0, attachOffset.x, attachOffset.y, attachOffset.z, 0.0, 0.0, 0.0, false, false, false, false, 2, true)
|
|
|
|
DeleteRope(createdRope)
|
|
FreezeEntityPosition(closestTrailer, false)
|
|
SetEntityInvincible(closestTrailer, false)
|
|
SetEntityInvincible(closestBoat, false)
|
|
|
|
hasTakenRope = false
|
|
hookedToBoat = false
|
|
controlRope = false
|
|
createdRope = nil
|
|
colObj = nil
|
|
boatOnTrailer = true
|
|
end
|
|
|
|
CreateThread(function()
|
|
while true do
|
|
Wait(createdRope and controlRope and 0 or 1000)
|
|
|
|
if createdRope and controlRope then
|
|
if ropeLength == 1.0 then
|
|
attachBoatToTrailer()
|
|
ropeLength = 10.0
|
|
end
|
|
|
|
if IsControlPressed(0, 172) then
|
|
ropeLength = ropeLength + lengthTick
|
|
|
|
if ropeLength > Config.MaxRopeLength then
|
|
ropeLength = Config.MaxRopeLength
|
|
end
|
|
|
|
StopRopeWinding(createdRope)
|
|
StartRopeUnwindingFront(createdRope)
|
|
RopeForceLength(createdRope, ropeLength)
|
|
elseif IsControlJustReleased(0, 172) then
|
|
StopRopeUnwindingFront(createdRope)
|
|
StopRopeWinding(createdRope)
|
|
RopeConvertToSimple(createdRope)
|
|
elseif IsControlPressed(0, 173) then
|
|
ropeLength = ropeLength - lengthTick
|
|
|
|
if ropeLength < minRopeLength then
|
|
ropeLength = minRopeLength
|
|
end
|
|
|
|
StopRopeUnwindingFront(createdRope)
|
|
StartRopeWinding(createdRope)
|
|
RopeForceLength(createdRope, ropeLength)
|
|
elseif IsControlJustReleased(0, 173) then
|
|
StopRopeUnwindingFront(createdRope)
|
|
StopRopeWinding(createdRope)
|
|
RopeConvertToSimple(createdRope)
|
|
end
|
|
end
|
|
|
|
if createdRope and hasTakenRope then
|
|
local playerPed = PlayerPedId()
|
|
local playerCoords = GetEntityCoords(playerPed)
|
|
local trailerOffset = getTrailerOffset(closestTrailer)
|
|
local trailerCoords = GetOffsetFromEntityInWorldCoords(closestTrailer, trailerOffset.x, trailerOffset.y, trailerOffset.z)
|
|
local coordsDiff = #(trailerCoords - playerCoords)
|
|
|
|
if coordsDiff > Config.MaxRopeLength then
|
|
notify("Du bist zu weit vom Anhänger weg")
|
|
|
|
DeleteRope(createdRope)
|
|
DeleteEntity(colObj)
|
|
FreezeEntityPosition(closestTrailer, false)
|
|
SetEntityInvincible(closestTrailer, false)
|
|
SetEntityInvincible(closestBoat, false)
|
|
|
|
closestTrailer = nil
|
|
closestBoat = nil
|
|
hasTakenRope = false
|
|
hookedToBoat = false
|
|
controlRope = false
|
|
colObj = nil
|
|
boatOnTrailer = false
|
|
end
|
|
end
|
|
end
|
|
end)
|
|
|