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)
 | |
| 
 | 
