426 lines
14 KiB
Lua
426 lines
14 KiB
Lua
|
function makeEntityFaceEntity(entity1, entity2)
|
||
|
local p1 = GetEntityCoords(entity1, true)
|
||
|
local p2 = GetEntityCoords(entity2, true)
|
||
|
|
||
|
local dx = p2.x - p1.x
|
||
|
local dy = p2.y - p1.y
|
||
|
|
||
|
local heading = GetHeadingFromVector_2d(dx, dy)
|
||
|
SetEntityHeading(entity1, heading)
|
||
|
end
|
||
|
|
||
|
function TaskFollowTargetedPlayer(follower, targetPlayer, distanceToStopAt, skip)
|
||
|
ClearPedTasks(follower)
|
||
|
if skip == false then
|
||
|
TaskGoToCoordAnyMeans(follower, GetEntityCoords(targetPlayer), 10.0, 0, 0, 0, 0)
|
||
|
Wait(5000)
|
||
|
end
|
||
|
TaskFollowToOffsetOfEntity(follower, targetPlayer, 2.5, 2.5, 2.5, 5.0, 10.0, distanceToStopAt, 1)
|
||
|
return true
|
||
|
end
|
||
|
|
||
|
function wanderAroundWithDuration(ped, coord, radius, minimalLength, timeBetweenWalks)
|
||
|
local duration = 10
|
||
|
CreateThread(function()
|
||
|
local count = 0
|
||
|
local continue = true
|
||
|
while continue and DoesEntityExist(ped) do
|
||
|
Wait(1000)
|
||
|
count = count + 1
|
||
|
if not GetIsTaskActive(ped, 222) then
|
||
|
TaskWanderInArea(ped, coord, radius, minimalLength, timeBetweenWalks)
|
||
|
end
|
||
|
if count >= duration then
|
||
|
continue = false
|
||
|
ClearPedTasks(ped)
|
||
|
end
|
||
|
end
|
||
|
end)
|
||
|
end
|
||
|
|
||
|
--- remove Relationship againt player.
|
||
|
---@param ped 'ped'
|
||
|
function removeRelationship(ped)
|
||
|
if not ped then
|
||
|
return
|
||
|
end
|
||
|
RemovePedFromGroup(ped)
|
||
|
end
|
||
|
|
||
|
--- set relationship with ped againt player. and disable Friendly fire when fighting againt player.
|
||
|
---@param ped 'ped'
|
||
|
function SetRelationshipBetweenPed(ped)
|
||
|
if not ped then
|
||
|
return
|
||
|
end
|
||
|
-- note: if we don't do this they will star fighting among themselves!
|
||
|
RemovePedFromGroup(ped)
|
||
|
SetPedRelationshipGroupHash(ped, GetHashKey(ped))
|
||
|
SetCanAttackFriendly(ped, false, false)
|
||
|
end
|
||
|
|
||
|
function whistleAnimation(ped, timeout)
|
||
|
CreateThread(function()
|
||
|
waitForAnimation('rcmnigel1c')
|
||
|
TaskPlayAnim(ped, "rcmnigel1c", "hailing_whistle_waive_a", 2.7, 2.7, -1, 49, 0, 0, 0, 0)
|
||
|
Wait(timeout)
|
||
|
ClearPedTasks(ped)
|
||
|
end)
|
||
|
end
|
||
|
|
||
|
--- wait until animation is loaded
|
||
|
---@param animation any
|
||
|
function waitForAnimation(animation)
|
||
|
RequestAnimDict(animation)
|
||
|
while not HasAnimDictLoaded(animation) do
|
||
|
Citizen.Wait(100)
|
||
|
end
|
||
|
return true
|
||
|
end
|
||
|
|
||
|
--- wait until model loaded
|
||
|
---@param model 'model'
|
||
|
function waitForModel(model)
|
||
|
RequestModel(model)
|
||
|
while not HasModelLoaded(model) do
|
||
|
Citizen.Wait(1)
|
||
|
end
|
||
|
return true
|
||
|
end
|
||
|
|
||
|
--- make blip
|
||
|
---@param data table
|
||
|
function createBlip(data)
|
||
|
local blip = nil
|
||
|
if data.petShop ~= nil then
|
||
|
-- make blip for shop
|
||
|
blip = AddBlipForCoord(data.petShop.x, data.petShop.y, data.petShop.z)
|
||
|
elseif data.entity ~= nil then
|
||
|
-- make blip for entities
|
||
|
blip = AddBlipForEntity(data.entity)
|
||
|
end
|
||
|
if data.shortRange ~= nil and data.shortRange == true then
|
||
|
SetBlipAsShortRange(blip, true)
|
||
|
elseif data.shortRange == false then
|
||
|
SetBlipAsShortRange(blip, false)
|
||
|
end
|
||
|
|
||
|
SetBlipSprite(blip, data.sprite)
|
||
|
SetBlipColour(blip, data.colour)
|
||
|
BeginTextCommandSetBlipName("STRING")
|
||
|
AddTextComponentString(data.text)
|
||
|
EndTextCommandSetBlipName(blip)
|
||
|
return blip
|
||
|
end
|
||
|
|
||
|
function DeletePed(ped)
|
||
|
if DoesEntityExist(ped) then
|
||
|
DeleteEntity(ped)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
function CreateAPed(hash, pos)
|
||
|
local ped = nil
|
||
|
waitForModel(hash)
|
||
|
|
||
|
ped = CreatePed(5, hash, pos.x, pos.y, pos.z, 0.0, true, false)
|
||
|
|
||
|
while not DoesEntityExist(ped) do
|
||
|
Wait(10)
|
||
|
end
|
||
|
|
||
|
SetBlockingOfNonTemporaryEvents(ped, true)
|
||
|
SetPedFleeAttributes(ped, 0, 0)
|
||
|
SetModelAsNoLongerNeeded(ped)
|
||
|
return ped
|
||
|
end
|
||
|
|
||
|
--- creates laser and force ped to move toward coord
|
||
|
---@param ped 'ped'
|
||
|
function goThere(ped)
|
||
|
while true do
|
||
|
local color = { r = 2, g = 241, b = 181, a = 200 }
|
||
|
local plyped = PlayerPedId()
|
||
|
local position = GetEntityCoords(plyped)
|
||
|
local coords, entity = RayCastGamePlayCamera(1000.0)
|
||
|
Draw2DText('Tryk ~g~E~w~ for at gå derhen', 4, { 255, 255, 255 }, 0.4, 0.43, 0.888 + 0.025)
|
||
|
if IsControlJustReleased(0, 38) then
|
||
|
TaskGoToCoordAnyMeans(ped, coords, 10.0, 0, 0, 0, 0)
|
||
|
return
|
||
|
end
|
||
|
DrawLine(position.x, position.y, position.z, coords.x, coords.y, coords.z, color.r, color.g, color.b, color.a)
|
||
|
DrawMarker(28, coords.x, coords.y, coords.z, 0.0, 0.0, 0.0, 0.0, 180.0, 0.0, 0.1, 0.1, 0.1, color.r, color.g,
|
||
|
color.b, color.a, false, true, 2, nil, nil, false)
|
||
|
Wait(0)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
--- logic to warp peds inside vehicles
|
||
|
function getIntoCar()
|
||
|
local plyped = PlayerPedId()
|
||
|
local ped = ActivePed:read().entity
|
||
|
local player_coord = GetEntityCoords(plyped)
|
||
|
local pet_coord = GetEntityCoords(ped)
|
||
|
local distance = #(player_coord - pet_coord)
|
||
|
if not IsPedSittingInAnyVehicle(plyped) then
|
||
|
QBCore.Functions.Notify(Lang:t('error.need_to_be_inside_car'), "error", 1500)
|
||
|
return
|
||
|
end
|
||
|
if distance > 8 then
|
||
|
QBCore.Functions.Notify(Lang:t('error.to_far'), "error", 1500)
|
||
|
return
|
||
|
end
|
||
|
local vehicle = GetVehiclePedIsUsing(plyped)
|
||
|
local seatEmpty = 6
|
||
|
|
||
|
for i = 1, 5, 1 do
|
||
|
if IsVehicleSeatFree(vehicle, i - 2) then
|
||
|
SetPedIntoVehicle(ped, vehicle, i - 2)
|
||
|
Animator(ped, ActivePed.read().model, 'siting', {
|
||
|
c_timings = 'REPEAT'
|
||
|
})
|
||
|
seatEmpty = i - 2
|
||
|
break
|
||
|
end
|
||
|
end
|
||
|
|
||
|
if seatEmpty == 6 then
|
||
|
QBCore.Functions.Notify(Lang:t('error.no_empty_seat'), "error", 1500)
|
||
|
return
|
||
|
end
|
||
|
end
|
||
|
|
||
|
function attackLogic(alreadyHunting)
|
||
|
while true do
|
||
|
Wait(0)
|
||
|
local color = {
|
||
|
r = 2,
|
||
|
g = 241,
|
||
|
b = 181,
|
||
|
a = 200
|
||
|
}
|
||
|
local plyped = PlayerPedId()
|
||
|
local position = GetEntityCoords(plyped)
|
||
|
local coords, entity = RayCastGamePlayCamera(1000.0)
|
||
|
Draw2DText('Tryk ~g~E~w~ for at angribe', 4, { 255, 255, 255 }, 0.4, 0.43, 0.888 + 0.025)
|
||
|
if IsControlJustReleased(0, 38) then
|
||
|
ClearPedTasks(ActivePed:read().entity)
|
||
|
if IsEntityAPed(entity) ~= 1 then
|
||
|
return false
|
||
|
end
|
||
|
|
||
|
local pet = ActivePed:read().entity
|
||
|
local chaseDistance = Config.Settings.chaseDistance
|
||
|
local indicator = Config.Settings.chaseIndicator
|
||
|
AttackTargetedPed(pet, entity)
|
||
|
alreadyHunting.state = true
|
||
|
while IsPedDeadOrDying(entity) == false do
|
||
|
-- draw every frame
|
||
|
Wait(5)
|
||
|
local pedCoord = GetEntityCoords(entity)
|
||
|
local petCoord = GetEntityCoords(pet)
|
||
|
local distance = GetDistanceBetweenCoords(pedCoord, petCoord)
|
||
|
|
||
|
DrawMarker(2, pedCoord.x, pedCoord.y, pedCoord.z + 2, 0.0, 0.0, 0.0, 0.0, 180.0, 0.0, 1.0, 1.0,
|
||
|
1.0, 255, 128, 0, 50, false, true, 2, nil, nil, false)
|
||
|
|
||
|
if indicator ~= false and IsPedDeadOrDying(entity) ~= false then
|
||
|
alreadyHunting.state = false
|
||
|
return true
|
||
|
end
|
||
|
if distance >= chaseDistance then
|
||
|
alreadyHunting.state = false
|
||
|
return true
|
||
|
end
|
||
|
end
|
||
|
-- later ask server to give xp
|
||
|
alreadyHunting.state = false
|
||
|
return true
|
||
|
end
|
||
|
-- target
|
||
|
DrawLine(position.x, position.y, position.z, coords.x, coords.y, coords.z, color.r, color.g, color.b, color.a)
|
||
|
DrawMarker(28, coords.x, coords.y, coords.z, 0.0, 0.0, 0.0, 0.0, 180.0, 0.0, 0.1, 0.1, 0.1, color.r, color.g,
|
||
|
color.b, color.a, false, true, 2, nil, nil, false)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
function HuntandGrab(plyped, activePed)
|
||
|
while true do
|
||
|
Wait(0)
|
||
|
local color = { r = 2, g = 241, b = 181, a = 200 }
|
||
|
local position = GetEntityCoords(plyped)
|
||
|
local coords, entity = RayCastGamePlayCamera(1000.0)
|
||
|
Draw2DText('Tryk ~g~E~w~ for at gå derhen', 4, { 255, 255, 255 }, 0.4, 0.43, 0.888 + 0.025)
|
||
|
if IsControlJustReleased(0, 38) then
|
||
|
local pet = activePed.entity
|
||
|
if IsPedAPlayer(entity) == 1 or IsEntityAPed(entity) == false or entity == pet then
|
||
|
QBCore.Functions.Notify(Lang:t('error.could_not_do_that'), "error", 1500)
|
||
|
return
|
||
|
end
|
||
|
|
||
|
TaskFollowToOffsetOfEntity(pet, entity, 0.0, 0.0, 0.0, 5.0, 10.0, 1.0, 1)
|
||
|
while true do
|
||
|
local pedCoord = GetEntityCoords(entity)
|
||
|
local petCoord = GetEntityCoords(pet)
|
||
|
local distance = GetDistanceBetweenCoords(pedCoord, petCoord)
|
||
|
if distance >= 50.0 then
|
||
|
-- skip when to much distance
|
||
|
break
|
||
|
else
|
||
|
AttackTargetedPed(pet, entity)
|
||
|
-- wait until pet kills target
|
||
|
while IsPedDeadOrDying(entity) == false do
|
||
|
Wait(250)
|
||
|
end
|
||
|
-- drag dead body
|
||
|
SetEntityCoords(entity, GetOffsetFromEntityInWorldCoords(pet, 0.0, 0.25, 0.0))
|
||
|
AttachEntityToEntity(entity, pet, 11816, 0.05, 0.05, 0.5, 0.0, 0.0, 0.0, false, false,
|
||
|
false, false, 2, true)
|
||
|
-- finish loop
|
||
|
break
|
||
|
end
|
||
|
Wait(500)
|
||
|
end
|
||
|
-- Detach entity when it has to much distance or it's near player
|
||
|
|
||
|
TaskFollowToOffsetOfEntity(pet, plyped, 2.0, 2.0, 2.0, 1.0, 10.0, 3.0, 1)
|
||
|
while true do
|
||
|
local pedCoord = GetEntityCoords(plyped)
|
||
|
local petCoord = GetEntityCoords(pet)
|
||
|
local distance = GetDistanceBetweenCoords(pedCoord, petCoord)
|
||
|
if entity ~= nil and distance < 3.0 or distance > 50.0 then
|
||
|
DetachEntity(entity, true, false)
|
||
|
ClearPedSecondaryTask(pet)
|
||
|
return
|
||
|
end
|
||
|
Wait(1000)
|
||
|
end
|
||
|
return -- just incase
|
||
|
end
|
||
|
DrawLine(position.x, position.y, position.z, coords.x, coords.y, coords.z, color.r, color.g, color.b, color.a)
|
||
|
DrawMarker(28, coords.x, coords.y, coords.z, 0.0, 0.0, 0.0, 0.0, 180.0, 0.0, 0.1, 0.1, 0.1, color.r, color.g,
|
||
|
color.b, color.a, false, true, 2, nil, nil, false)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
function get_player_cid()
|
||
|
local players = GetActivePlayers()
|
||
|
|
||
|
for _, player in pairs(players) do
|
||
|
if player == PlayerId() then
|
||
|
return _
|
||
|
end
|
||
|
end
|
||
|
return false
|
||
|
end
|
||
|
|
||
|
function SearchLogic(plyped, activePed)
|
||
|
if not PlayerJob then return end
|
||
|
if not (PlayerJob.name == 'police') then
|
||
|
QBCore.Functions.Notify('Dette må du ikke', "error", 1500)
|
||
|
return
|
||
|
end
|
||
|
|
||
|
if not PlayerJob.onduty == true then
|
||
|
QBCore.Functions.Notify('Dette må du ikke', "error", 1500)
|
||
|
return
|
||
|
end
|
||
|
|
||
|
ClearPedTasks(ActivePed:read().entity)
|
||
|
local pedCoord = GetEntityCoords(PlayerPedId())
|
||
|
local closestPlayer = QBCore.Functions.GetClosestPlayer(pedCoord)
|
||
|
if closestPlayer == -1 then
|
||
|
return
|
||
|
end
|
||
|
local pedplayer = GetPlayerPed(closestPlayer)
|
||
|
TaskGoToCoordAnyMeans(activePed.entity, GetEntityCoords(pedplayer), 10.0, 0, 0, 0, 0)
|
||
|
|
||
|
local finished = false
|
||
|
CreateThread(function()
|
||
|
while finished == false do
|
||
|
-- draw every frame
|
||
|
Wait(5)
|
||
|
pedCoord = GetEntityCoords(GetPlayerPed(closestPlayer))
|
||
|
DrawMarker(2, pedCoord.x, pedCoord.y, pedCoord.z + 2, 0.0, 0.0, 0.0, 0.0, 180.0, 0.0, 1.0, 1.0,
|
||
|
1.0, 255, 128, 0, 50, false, true, 2, nil, nil, false)
|
||
|
end
|
||
|
end)
|
||
|
|
||
|
|
||
|
local player_server_id = GetPlayerServerId(closestPlayer)
|
||
|
QBCore.Functions.TriggerCallback('keep-companion:server:search_inventory', function(result)
|
||
|
Wait(5000)
|
||
|
|
||
|
Animator(activePed.entity, activePed.model, 'misc', {
|
||
|
animation = 'indicate_low',
|
||
|
sequentialTimings = {
|
||
|
-- How close the value is to the Timeout value determines how fast the script moves to the next animation.
|
||
|
[1] = 6, -- start animation Timeout ==> 1sec(6s-5s) to loop
|
||
|
[2] = 0, -- loop animation Timeout ==> 6sec(6s-0s) to exit
|
||
|
[3] = 2, -- exit animation Timeout ==> 4sec(6s-2s) to end
|
||
|
step = 1,
|
||
|
Timeout = 6
|
||
|
}
|
||
|
})
|
||
|
Wait(5000)
|
||
|
if result == true then
|
||
|
TriggerEvent('QBCore:Notify', 'K9 fandt noget', 'success', 2500)
|
||
|
SetAnimalMood(activePed.entity, 1)
|
||
|
PlayAnimalVocalization(activePed.entity, 3, 'bark')
|
||
|
Animator(activePed.entity, activePed.model, 'misc', {
|
||
|
animation = 'indicate_high',
|
||
|
sequentialTimings = {
|
||
|
-- How close the value is to the Timeout value determines how fast the script moves to the next animation.
|
||
|
[1] = 6, -- start animation Timeout ==> 1sec(6s-5s) to loop
|
||
|
[2] = 0, -- loop animation Timeout ==> 6sec(6s-0s) to exit
|
||
|
[3] = 2, -- exit animation Timeout ==> 4sec(6s-2s) to end
|
||
|
step = 1,
|
||
|
Timeout = 6
|
||
|
}
|
||
|
})
|
||
|
end
|
||
|
finished = true
|
||
|
end, player_server_id)
|
||
|
end
|
||
|
|
||
|
--- if player is inside a vehicle we need to relocate ped location so they won't sucide
|
||
|
---@param ped 'ped'
|
||
|
function doSomethingIfPedIsInsideVehicle(ped)
|
||
|
local playerped = PlayerPedId()
|
||
|
local coord = getSpawnLocation(playerped)
|
||
|
if IsPedInAnyVehicle(ped, true) then
|
||
|
SetEntityCoords(ped, coord, 1, 0, 0, 1)
|
||
|
end
|
||
|
Wait(75)
|
||
|
end
|
||
|
|
||
|
function getSpawnLocation(plyped)
|
||
|
if IsPedInAnyVehicle(plyped, true) then
|
||
|
return GetOffsetFromEntityInWorldCoords(plyped, -2.0, 1.0, 0.5)
|
||
|
else
|
||
|
return GetOffsetFromEntityInWorldCoords(plyped, 1.0, -1.0, 0.5)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
--- gives ped ability to follow and attack targeted ped
|
||
|
---@param AttackerPed 'ped'
|
||
|
---@param targetPed 'ped'
|
||
|
---@return 'void'
|
||
|
function AttackTargetedPed(AttackerPed, targetPed)
|
||
|
if not AttackerPed and not targetPed then
|
||
|
return false
|
||
|
end
|
||
|
SetPedCombatAttributes(AttackerPed, 46, 1)
|
||
|
TaskGoToEntityWhileAimingAtEntity(AttackerPed, targetPed, targetPed, 8.0, 1, 0, 15, 1, 1, 1566631136)
|
||
|
TaskCombatPed(AttackerPed, targetPed, 0, 16)
|
||
|
SetRelationshipBetweenPed(AttackerPed)
|
||
|
SetPedCombatMovement(AttackerPed, 3)
|
||
|
|
||
|
|
||
|
while IsPedDeadOrDying(targetPed, 0) ~= 1 do
|
||
|
Wait(1000)
|
||
|
-- skip
|
||
|
end
|
||
|
TaskFollowTargetedPlayer(AttackerPed, PlayerPedId(), 3.0, false)
|
||
|
end
|