---------------------- -- SYNCING ---------------------- function SetNetworkShared(netId) Citizen.CreateThread(function() local timeout = 0 while not NetworkDoesEntityExistWithNetworkId(netId) and timeout < 10 do Citizen.Wait(10) timeout = timeout + 1 end local entity = NetworkGetEntityFromNetworkId(netId) SetEntityAsMissionEntity(entity, 1, 1) NetworkAllowLocalEntityAttachment(entity, true) SetEntityLoadCollisionFlag(entity, not Config.experimentalSync) SetNetworkIdExistsOnAllMachines(netId, true) if Config.experimentalSync then SetNetworkIdAlwaysExistsForPlayer(netId, PlayerId(), true) if IsEntityAVehicle(entity) then SetNetworkVehiclePositionUpdateMultiplier(entity, 2.0) SetNetworkEnableVehiclePositionCorrection(entity, true) end if tonumber(Config.experimentalSync) == 111 then NetworkUseHighPrecisionBlending(netId, false) SetNetworkIdCanMigrate(netId, false) end end --NetworkUseHighPrecisionBlending(netId, true) --SetNetworkIdCanMigrate(netId, false) end) end function SyncToServer() TriggerServerEvent('kq_carheist:heistCreated', heist) end RegisterNetEvent('kq_carheist:syncHeist') AddEventHandler('kq_carheist:syncHeist', function(newHeist) heist = newHeist RemoveRelationshipGroup('kq_carheist_ped') RemoveRelationshipGroup(robberRelationship) SetPedRelationshipGroupDefaultHash(PlayerPedId(), GetHashKey('PLAYER')) AddRelationshipGroup('kq_carheist_ped') _, robberRelationship = AddRelationshipGroup('kq_carheist_robber' .. heist.hash) RemovePoliceTrailerBlip() SetPedsRelationships() Debug(heist.truck) Debug(GetTruck()) Debug(GetEntityCoords(GetTruck())) end) RegisterNetEvent('kq_carheist:syncSellableVehicles') AddEventHandler('kq_carheist:syncSellableVehicles', function(newSellable) sellableVehicles = newSellable end) ---------------------- -- ALARM ---------------------- function CheckAlertness() Debug('Checking alertness') for k, ped in pairs(GetAllHeistPeds()) do if GetPedAlertness(ped) >= 2 then Debug('Peds were alerted. Setting off the alarm') SetOffAlarm() return end end end function SetOffAlarm() if not heist.alarm then heist.alarm = true if Config.useVehicleAlarm then SetVehicleAlarm(GetTrailer(), true) SetVehicleAlarmTimeLeft(GetTruck(), 120000) end TriggerServerEvent('kq_carheist:startAlarm') end for k, ped in pairs(GetAllHeistPeds()) do if ped ~= GetNPC() then local veh = GetSupportVehicle() if GetPedInVehicleSeat(veh, -1) ~= ped then TaskCombatPed(ped, PlayerPedId(), 0, 16) end end end SetRelationshipBetweenGroups(5, 'kq_carheist_ped', robberRelationship) end RegisterNetEvent('kq_carheist:setAlarm') AddEventHandler('kq_carheist:setAlarm', function(trailerCoords) heist.alarm = true if IsPolice() then RefreshPoliceTrailerAlarm(trailerCoords) SendDispatchMessage(L('Our car transport is under attack! Coordinates have been shared!'), L('Robbery in progress')) end end) RegisterNetEvent('kq_carheist:truckArrived') AddEventHandler('kq_carheist:truckArrived', function() if heist.alarm then EndPoliceAlarm() end end) function DoSparkParticle() local dict = 'core' if not HasNamedPtfxAssetLoaded(dict) then RequestNamedPtfxAsset(dict) while not HasNamedPtfxAssetLoaded(dict) do Citizen.Wait(1) end end SetPtfxAssetNextCall(dict) local sparks = StartParticleFxLoopedOnEntityBone("ent_brk_sparking_wires", grinder, 0.0, 0.0, 0.1, 0.0, 0.0, 0.0, 0, 1.3, 1, 1, 1) end ---------------------- -- RAMP OPENING ---------------------- RegisterNetEvent('kq_carheist:startOpeningRamp') AddEventHandler('kq_carheist:startOpeningRamp', function() StartOpeningRamp() end) function StartOpeningRamp() openingRamp = true progress = 0 SetOffAlarm() OnStartOpeningTrailer() local playerPed = PlayerPedId() local playerCoords = GetEntityCoords(playerPed) SetPedRelationshipGroupHash(playerPed, robberRelationship) local bootCoords = GetWorldPositionOfEntityBone(GetTrailer(), GetEntityBoneIndexByName(GetTrailer(), 'boot')) local grinderModel = 'imp_prop_grinder_01a' DoRequestModel(grinderModel) grinder = CreateObject(grinderModel, playerCoords.x, playerCoords.y, playerCoords.z, true, true, 1) local handBone = 6286 local grinderOffset = vector3(0.2, 0.065, -0.015) local grinderRot = vector3(200.0, 265.0, -40.0) local handBoneIndex = GetPedBoneIndex(playerPed, handBone) AttachEntityToEntity(grinder, playerPed, handBoneIndex, grinderOffset.x, grinderOffset.y, grinderOffset.z, grinderRot.x, grinderRot.y, grinderRot.z, true, false, false, false, 2, true) local heading = GetHeadingFromVector_2d(playerCoords.x - bootCoords.x, playerCoords.y - bootCoords.y) + 200 SetEntityHeading(playerPed, heading) TaskStartScenarioInPlace(PlayerPedId(), 'WORLD_HUMAN_WELDING', 10, true) end function FinishOpeningRamp() StopOpeningRamp() heist.rampDown = true Citizen.Wait(1000) OpenTrailer() end function StopOpeningRamp() cutting = false openingRamp = false local playerPed = PlayerPedId() local playerCoords = GetEntityCoords(playerPed) ClearPedTasks(playerPed) Citizen.Wait(50) local welder = GetClosestObjectOfType(playerCoords, 5.0, GetHashKey('prop_weld_torch'), false, false, false) SetEntityAsMissionEntity(welder, true) DeleteEntity(welder) DeleteObject(grinder) end function OpenTrailer() TriggerServerEvent('kq_carheist:openTrailer', heist.trailer) if openingRamp then StopOpeningRamp() end end RegisterNetEvent('kq_carheist:openTrailer') AddEventHandler('kq_carheist:openTrailer', function(networkVehicle) heist.rampDown = true if NetworkDoesEntityExistWithNetworkId(networkVehicle) then SetVehicleDoorOpen(NetworkGetEntityFromNetworkId(networkVehicle), 5, false, false) end if heist.vehicles[3] then DetachVehicle(3, true) end for k, vehicle in pairs(heist.vehicles) do if NetworkDoesEntityExistWithNetworkId(vehicle.vehicle) then local veh = NetworkGetEntityFromNetworkId(vehicle.vehicle) SetVehicleDoorsLocked(veh, 0) SetVehicleDoorsLockedForAllPlayers(veh, false) end end OnTrailerOpened() end) function DetachVehicle(vehicleKey, falling) Citizen.CreateThread(function() if falling then Citizen.Wait(1000) end if NetworkDoesEntityExistWithNetworkId(heist.vehicles[vehicleKey].vehicle) and NetworkHasControlOfEntity(NetworkGetEntityFromNetworkId(heist.vehicles[vehicleKey].vehicle)) then local vehicle = NetworkGetEntityFromNetworkId(heist.vehicles[vehicleKey].vehicle) if Config.useVehicleAlarm then SetVehicleAlarm(vehicle, true) SetVehicleAlarmTimeLeft(vehicle, math.random(25000, 60000)) end DetachEntity(vehicle, 1, 1) SetVehicleSuspensionHeight(vehicle, 0.0) Entity(vehicle).state.ignoreLocks = true OnVehicleDetach(vehicle) if falling then Citizen.Wait(1000) end TriggerServerEvent('kq_carheist:enableCollisions', heist.vehicles[vehicleKey].vehicle) if falling then local falls = 0 while falls < 45 do local vel = GetEntityVelocity(vehicle) SetEntityVelocity(vehicle, vel.x * 0.98, vel.y * 0.98, vel.z + 0.24) falls = falls + 1 Citizen.Wait(100) end end end end) end RegisterNetEvent('kq_carheist:enableCollisions') AddEventHandler('kq_carheist:enableCollisions', function(netVehicle) local vehicle = NetworkGetEntityFromNetworkId(netVehicle) for k, veh in pairs(heist.vehicles) do if NetworkDoesEntityExistWithNetworkId(veh.vehicle) then local otherVeh = NetworkGetEntityFromNetworkId(veh.vehicle) if otherVeh ~= vehicle then SetEntityNoCollisionEntity(vehicle, otherVeh, true) end end end end) ---------------------- -- HEIST CREATION ---------------------- RegisterNetEvent('kq_carheist:startDriver') AddEventHandler('kq_carheist:startDriver', function() StartDriver() end) function StartDriver() if not heist.endLocation then return end local endLoc = heist.endLocation --TaskVehicleDriveWander(GetNPC(), GetTruck(), Config.truckDriveSpeed + 0.0, Config.truckDriveStyle) local coords = GetEntityCoords(GetTruck()) RequestAdditionalCollisionAtCoord(coords) RequestCollisionAtCoord(coords) AddNavmeshRequiredRegion(coords.x, coords.y, 100.0) if GetDistanceBetweenCoords(GetEntityCoords(GetTruck()), endLoc.x, endLoc.y, endLoc.z, true) > 15.0 then TaskVehicleDriveToCoordLongrange(GetNPC(), GetTruck(), endLoc.x, endLoc.y, endLoc.z, Config.truckDriveSpeed + 0.0, Config.truckDriveStyle, 10.0) end end RegisterNetEvent('kq_carheist:createHeist') AddEventHandler('kq_carheist:createHeist', function(newHeist) heist = newHeist CreateHeist() end) function CreateHeist() Citizen.CreateThread(function() heist.truck = NetworkGetNetworkIdFromEntity(CreateTruck()) heist.trailer = NetworkGetNetworkIdFromEntity(CreateTrailer()) heist.npc = NetworkGetNetworkIdFromEntity(CreateDriver()) if heist.passengerEnabled then heist.passenger = NetworkGetNetworkIdFromEntity(CreatePassenger()) end if heist.supportEnabled then Debug('create support') heist.support = CreateSupport() end Citizen.Wait(10) Debug('attach trailer') AttachVehicleToTrailer(GetTruck(), GetTrailer(), 10.0) Citizen.Wait(1000) SyncToServer() end) end function CreateTruck() local availableTrucks = Config.events[heist.event].trucks local model = availableTrucks[math.random(1, #availableTrucks)] DoRequestModel(model) local veh = CreateVehicle(model, heist.startLocation.truck.x, heist.startLocation.truck.y, heist.startLocation.truck.z, heist.startLocation.truck.h, 1, 0) SetEntityAsMissionEntity(veh, true, true) SetNetworkShared(NetworkGetNetworkIdFromEntity(veh), true) if heist.bulletproofTiresEnabled then SetVehicleTyresCanBurst(veh, false) end SetVehicleDoorsLocked(veh, 2) SetVehicleDoorsLockedForAllPlayers(veh, true) SetVehicleCustomPrimaryColour(veh, Config.truckColor.r, Config.truckColor.g, Config.truckColor.b) SetVehicleCustomSecondaryColour(veh, Config.truckColor.r, Config.truckColor.g, Config.truckColor.b) AfterTruckCreated(veh) return veh end function CreateTrailer() local model = Settings.trailer DoRequestModel(model) local veh = CreateVehicle(model, heist.startLocation.truck.x, heist.startLocation.truck.y, heist.startLocation.truck.z + 4.0, 0.0, 1, 0) SetEntityAsMissionEntity(veh, true, true) SetNetworkShared(NetworkGetNetworkIdFromEntity(veh), true) FreezeEntityPosition(veh, true) SetEntityProofs(veh, false, true, true, false, false, true, 1, false) SetVehicleDoorCanBreak(veh, 5, false) SetVehicleDoorCanBreak(veh, 4, false) CreateTrailerVehicles(veh) FreezeEntityPosition(veh, false) if heist.bulletproofTiresEnabled then SetVehicleTyresCanBurst(veh, false) end AfterTrailerCreated(veh) return veh end function CreateTrailerVehicles(trailer) local lastVeh = nil for k, slot in pairs(Settings.trailerSlots) do if heist.vehicles[k] then local vehicle = heist.vehicles[k].data if IsModelValid(vehicle.model) then Debug('created trailer vehicle ' .. vehicle.model) DoRequestModel(vehicle.model) local coords = slot.coords local rot = slot.rot local veh = CreateVehicle(vehicle.model, heist.startLocation.truck.x + coords.x, heist.startLocation.truck.y + coords.y, heist.startLocation.truck.z + 4.0 + coords.z + 0.6, 0.0, 1, 0) SetEntityAsMissionEntity(veh, true, true) SetNetworkShared(NetworkGetNetworkIdFromEntity(veh), true) SetVehicleModKit(veh, 0) SetVehicleLivery(veh, math.random(0, 8)) SetVehicleMod(veh, 48, math.random(0, 8), 1) FreezeEntityPosition(veh, true) heist.vehicles[k] = { data = vehicle, vehicle = NetworkGetNetworkIdFromEntity(veh), tracker = true, trackerLocation = math.random(1,6), slot = slot, hash = heist.hash } SetEntityCoords(veh, heist.startLocation.truck.x + coords.x, heist.startLocation.truck.y + coords.y, heist.startLocation.truck.z + 4.0 + coords.z + 0.5, 0, 0, 0, 0) if DoesEntityExist(veh) then SetVehicleSuspensionHeight(veh, 0.075) end local offset = GetOffsetFromEntityGivenWorldCoords(trailer, GetEntityCoords(veh)) AttachEntityToEntity(veh, trailer, 0, offset.x, offset.y, offset.z, rot.x, rot.y, rot.z, 1, 1, 1, 0, 0, 1) SetVehicleDoorsLocked(veh, 2) SetVehicleDoorsLockedForAllPlayers(veh, true) AfterTrailerVehicleCreated(veh) FreezeEntityPosition(veh, false) if lastVeh then SetEntityNoCollisionEntity(veh, lastVeh, false) end lastVeh = veh end end end Debug('created trailer vehicles') return true end function CreateDriver() local availableNPCs = Config.events[heist.event].npcs local model = availableNPCs[math.random(1, #availableNPCs)] DoRequestModel(model) local driver = CreatePedInsideVehicle(GetTruck(), 0, model, -1, 1, 1) SetNetworkShared(NetworkGetNetworkIdFromEntity(driver), true) SetPedBaseConfig(driver) SetBlockingOfNonTemporaryEvents(driver, true) SetPedMaxHealth(driver, Config.npcHealth) SetEntityHealth(driver, Config.npcHealth) SetPedSuffersCriticalHits(driver, Config.npcSuffersCriticalHits) AfterDriverCreated(driver) return driver end function CreatePassenger() local availableNPCs = Config.events[heist.event].npcs local model = availableNPCs[math.random(1, #availableNPCs)] DoRequestModel(model) local passenger = CreatePedInsideVehicle(GetTruck(), 0, model, 0, 1, 0) SetNetworkShared(NetworkGetNetworkIdFromEntity(passenger), true) SetPedBaseConfig(passenger) SetPedMaxHealth(passenger, 150) SetEntityHealth(passenger, 150) SetPedSuffersCriticalHits(passenger, false) if heist.weaponsEnabled then GiveWeaponToPed(passenger, Config.weapons[math.random(1, #Config.weapons)], 120, false, true) end AfterPassengerCreated(passenger) return passenger end function CreateSupport() local model = Config.supportVehicles[math.random(1, #Config.supportVehicles)] DoRequestModel(model) local veh = CreateVehicle(model, heist.startLocation.support.x, heist.startLocation.support.y, heist.startLocation.support.z, heist.startLocation.support.h, 1, 0) SetEntityAsMissionEntity(veh, true, true) SetNetworkShared(NetworkGetNetworkIdFromEntity(veh), true) if heist.bulletproofTiresEnabled then SetVehicleTyresCanBurst(veh, false) end SetVehicleDoorsLocked(veh, 2) SetVehicleDoorsLockedForAllPlayers(veh, true) SetVehicleModKit(veh, 0) SetVehicleWindowTint(veh, 2) SetVehicleModColor_1(veh, 3, 0, 0) SetVehicleModColor_2(veh, 3, 0, 0) SetVehicleCustomPrimaryColour(veh, Config.supportColor.r, Config.supportColor.g, Config.supportColor.b) SetVehicleCustomSecondaryColour(veh, Config.supportColor.r, Config.supportColor.g, Config.supportColor.b) local supportAmount = math.random(2, GetVehicleModelNumberOfSeats(model)) AfterSupportVehicleCreated(veh) local peds = {} for i = 1, supportAmount, 1 do local pedModel = Config.supportPeds[math.random(1, #Config.supportPeds)] DoRequestModel(pedModel) local ped = CreatePedInsideVehicle(veh, 0, pedModel, i - 2, 1, 1) SetNetworkShared(NetworkGetNetworkIdFromEntity(ped), true) if i == 1 then TaskVehicleEscort(ped, veh, GetTrailer(), -1, Config.truckDriveSpeed * 1.2, Config.truckDriveStyle, 25.0, 25.0) SetBlockingOfNonTemporaryEvents(ped, true) end GiveWeaponToPed(ped, Config.weapons[math.random(1, #Config.weapons)], 120, false, true) SetPedBaseConfig(ped) SetPedMaxHealth(ped, 200) SetEntityHealth(ped, 200) SetPedSuffersCriticalHits(ped, false) table.insert(peds, NetworkGetNetworkIdFromEntity(ped)) AfterSupportPedCreated(ped) end return { vehicle = NetworkGetNetworkIdFromEntity(veh), peds = peds } end function SetPedBaseConfig(ped) SetEntityAlwaysPrerender(ped, true) SetDriverAbility(ped, 100.0) SetDriverAggressiveness(ped, 0.1) SetPedAllowedToDuck(ped, 1) SetPedArmour(ped, 100) SetPedCombatAttributes(ped, 2, true) SetPedCombatAttributes(ped, 3, true) SetTaskVehicleChaseBehaviorFlag(ped, 32, true) SetPedCanBeDraggedOut(ped, false) SetPedKeepTask(ped, true) SetPedCombatRange(ped, 0) SetPedCombatAbility(ped, 0) if Config.npcShootingAccuracy > 30 then SetPedCombatAbility(ped, 1) end if Config.npcShootingAccuracy > 80 then SetPedCombatAbility(ped, 2) end SetPedAccuracy(ped, Config.npcShootingAccuracy) SetPedDropsWeaponsWhenDead(ped, false) end function SetPedsRelationships() SetRelationshipBetweenGroups(0, 'kq_carheist_ped', 'kq_carheist_ped') SetRelationshipBetweenGroups(5, 'kq_carheist_ped', robberRelationship) local friendlyTo = { 'COP', 'SECURITY_GUARD', 'PRIVATE_SECURITY', 'FIREMAN', 'ARMY', 'CIVMALE', 'CIVFEMALE' } for _, group in pairs(friendlyTo) do SetRelationshipBetweenGroups(2, 'kq_carheist_ped', GetHashKey(group)) SetRelationshipBetweenGroups(2, GetHashKey(group), 'kq_carheist_ped') end for k, ped in pairs(GetAllHeistPeds()) do SetPedRelationshipGroupHash(ped, 'kq_carheist_ped') SetPedDropsWeaponsWhenDead(ped, false) end SetRelationshipBetweenGroups(3, 'kq_carheist_ped', GetHashKey('PLAYER')) SetRelationshipBetweenGroups(3, GetHashKey('PLAYER'), 'kq_carheist_ped') SetRelationshipBetweenGroups(1, GetHashKey('PLAYER'), robberRelationship) SetRelationshipBetweenGroups(1, robberRelationship, GetHashKey('PLAYER')) end RegisterNetEvent('kq_carheist:announceHeist') AddEventHandler('kq_carheist:announceHeist', function(coords) if not IsPolice() then SendAnnouncementMessage(L('Car transport truck is currently departing.\nI\'ll pay top dollar if you can get them'), L('Car collector'), coords) end end) function CreateTemporaryBlip(coords, sprite, color, alpha, scale, message, shortRange, noLegend) Citizen.CreateThread(function() local blip = AddBlipForCoord(coords) SetBlipSprite(blip, sprite) SetBlipHighDetail(blip, true) SetBlipColour(blip, color) SetBlipAlpha(blip, alpha) SetBlipScale(blip, scale) BeginTextCommandSetBlipName('STRING') AddTextComponentString(message) EndTextCommandSetBlipName(blip) SetBlipAsShortRange(blip, shortRange) if noLegend then SetBlipDisplay(blip, 8) end Citizen.Wait(Config.announcementBlip.duration or 15000) RemoveBlip(blip) end) end ---------------------- -- TRACKERS ---------------------- function CheckForTracker(vehKey, trackerKey, textCoords, veh) local playerPed = PlayerPedId() local vehCoords = GetEntityCoords(veh) Debug(vehCoords) local playerCoords = GetEntityCoords(playerPed) Debug(playerCoords) local heading = GetHeadingFromVector_2d(playerCoords.x - vehCoords.x, playerCoords.y - vehCoords.y) + 180.0 SetEntityHeading(playerPed, heading) PlayAnim('anim@amb@clubhouse@tutorial@bkr_tut_ig3@', 'machinic_loop_mechandplayer') local searching = true Citizen.CreateThread(function() while searching do Draw3DText(textCoords.x, textCoords.y, textCoords.z + 0.2, L('~w~Searching for a tracking device'), 4, 0.04, 0.04) Draw3DText(textCoords.x, textCoords.y, textCoords.z + 0.1, L('~w~Press [~r~E~w~] to cancel'), 4, 0.035, 0.035) if IsControlJustReleased(0, Keys['E']) or IsPedRagdoll(playerPed) or GetDistanceBetweenCoords(textCoords, playerCoords, true) > 3.0 then searching = false end Citizen.Wait(1) end end) local waits = Config.tracker.searchDuration / 1000 while waits > 0 and searching do Citizen.Wait(1000) waits = waits - 1 end if not searching then ClearPedTasks(playerPed) end if searching then searching = false if sellableVehicles[vehKey].trackerLocation == trackerKey then local removing = true local removalKeybinds = Config.tracker.removalKeybinds local keyKey = #removalKeybinds local progress = 0 while progress < Config.tracker.removalLength and sellableVehicles[vehKey].tracker and removing do local currentKey = Config.tracker.removalKeybinds[keyKey] local text = '~w~' for k, key in pairs(removalKeybinds) do if key ~= currentKey then text = text .. '~w~' .. key if IsControlJustReleased(0, Keys[key]) then progress = progress - 2 currentKey = nil local display = true Citizen.CreateThread(function() while display and removing do Draw3DText(textCoords.x, textCoords.y, textCoords.z, L('~r~You dropped the screwdriver'), 4, 0.04, 0.04) Draw3DText(textCoords.x, textCoords.y, textCoords.z - 0.1, L('~w~Press [~r~E~w~] to cancel'), 4, 0.035, 0.035) if IsControlJustReleased(0, Keys['E']) or IsPedRagdoll(playerPed) or GetDistanceBetweenCoords(textCoords, playerCoords, true) > 3.0 then removing = false ClearPedTasks(playerPed) end Citizen.Wait(1) end end) Citizen.Wait(Config.tracker.removalMessedUpDuration) display = false end else text = text .. '~r~' .. currentKey end end if IsControlJustReleased(0, Keys[currentKey]) then progress = progress + 1 keyKey = keyKey - 1 if keyKey < 1 then keyKey = #removalKeybinds end end Draw3DText(textCoords.x, textCoords.y, textCoords.z + 0.2, L('~g~Tracking device found!'), 4, 0.04, 0.04) Draw3DText(textCoords.x, textCoords.y, textCoords.z, '~w~' .. (L('Press ~w~[{keybinds}~w~] to unscrew')):gsub('{keybinds}', text), 4, 0.04, 0.04) Draw3DText(textCoords.x, textCoords.y, textCoords.z - 0.1, L('~w~Press [~r~E~w~] to cancel'), 4, 0.035, 0.035) if IsControlJustReleased(0, Keys['E']) or IsPedRagdoll(playerPed) or GetDistanceBetweenCoords(textCoords, playerCoords, true) > 3.0 then removing = false ClearPedTasks(playerPed) end Citizen.Wait(1) end if removing then removing = false if sellableVehicles[vehKey].tracker then TriggerServerEvent('kq_carheist:removeTracker', vehKey, textCoords) CreateTrackerObject() end end end end ClearPedTasks(playerPed) end function CreateTrackerObject() local trackerModel = 'prop_cs_mini_tv' DoRequestModel(trackerModel) local playerPed = PlayerPedId() local playerCoords = GetEntityCoords(playerPed) local trackerObj = CreateObject(trackerModel, playerCoords.x, playerCoords.y, playerCoords.z, true, true, 1) SetEntityDynamic(trackerObj, true) end ---------------------- -- DROP OFF ---------------------- function RemoveDropOffs() RemoveDropOffBlips() currentDropOffs = {} end function CreateNewDropOffs(hash) Debug('create dropoff') math.randomseed(hash) local amount = math.random(Config.dropOff.minLocations, Config.dropOff.maxLocations) currentDropOffs = {} while #currentDropOffs < amount do local newLoc = Config.dropOff.locations[math.random(1, #Config.dropOff.locations)] if not Contains(currentDropOffs, newLoc) then table.insert(currentDropOffs, newLoc) end Citizen.Wait(1) end Debug('Got ' .. #currentDropOffs) RemoveDropOffBlips() for k, dropOff in pairs(currentDropOffs) do Debug(json.encode(dropOff)) local blipConf = Config.dropOff.blips.primary local primBlip = CreateDropOffBlip(vector3(dropOff.x, dropOff.y, dropOff.z), blipConf.sprite, blipConf.color, blipConf.alpha, blipConf.scale, L('Stolen vehicle drop off point'), blipConf.shortRange) SetBlipDisplay(primBlip, 8) table.insert(dropOffBlips, primBlip) blipConf = Config.dropOff.blips.secondary local secBlip = CreateDropOffBlip(vector3(dropOff.x, dropOff.y, dropOff.z), blipConf.sprite, blipConf.color, blipConf.alpha, blipConf.scale, L('Stolen vehicle drop off point'), blipConf.shortRange) table.insert(dropOffBlips, secBlip) end math.randomseed(GetGameTimer()) end function RemoveDropOffBlips() for b, blip in pairs(dropOffBlips) do RemoveBlip(blip) end dropOffBlips = {} end function CreateDropOffBlip(coords, sprite, color, alpha, scale, message, shortRange) local blip = AddBlipForCoord(coords) SetBlipSprite(blip, sprite) SetBlipHighDetail(blip, true) SetBlipColour(blip, color) SetBlipAlpha(blip, alpha) SetBlipScale(blip, scale) BeginTextCommandSetBlipName('STRING') AddTextComponentString(message) EndTextCommandSetBlipName(blip) SetBlipAsShortRange(blip, shortRange) return blip end function DropOffVehicle(vehicle, dropCoords) if DoesEntityExist(vehicle) then TriggerServerEvent('kq_carheist:dropOffVehicle', NetworkGetNetworkIdFromEntity(vehicle), dropCoords) if DoesEntityExist(vehicle) then SetVehicleDoorsLocked(vehicle, 2) SetVehicleUndriveable(vehicle, true) SetVehicleAsNoLongerNeeded(vehicle) SetEntityCleanupByEngine(vehicle, true) end end end ---------------------- -- GETTERS ---------------------- function GetTruck() return GetSomething('truck') end function GetTrailer() return GetSomething('trailer') end function GetNPC() return GetSomething('npc') end function GetPassenger() return GetSomething('passenger') end function GetSomething(key) if not heist[key] then return nil end if not NetworkDoesEntityExistWithNetworkId(heist[key]) then return nil end local entity = NetworkGetEntityFromNetworkId(heist[key]) if DoesEntityExist(entity) then return entity end return false end function GetSupportVehicle() if not heist.supportEnabled or not heist.support then return nil end if not NetworkDoesEntityExistWithNetworkId(heist.support.vehicle) then return nil end local entity = NetworkGetEntityFromNetworkId(heist.support.vehicle) if DoesEntityExist(entity) then return entity end return nil end function GetAllHeistPeds() local peds = { GetNPC() } if GetPassenger() then table.insert(peds, GetPassenger()) end if heist.supportEnabled and heist.support and #heist.support.peds then for k, netId in pairs(heist.support.peds) do if NetworkDoesEntityExistWithNetworkId(netId) then local ped = NetworkGetEntityFromNetworkId(netId) table.insert(peds, ped) end end end return peds end function IsHeistVehicle(veh) for k, vehicle in pairs(heist.vehicles) do if NetworkDoesEntityExistWithNetworkId(vehicle.vehicle) then local hVeh = NetworkGetEntityFromNetworkId(vehicle.vehicle) if veh == hVeh then return true end end end return false end function IsOnBike() if IsPedInAnyVehicle(PlayerPedId()) then local veh = GetVehiclePedIsIn(PlayerPedId()) if GetVehicleClass(veh) == 8 or GetVehicleClass(veh) == 13 then return true end end end function IsInsideATunnel(coords) local tunnels = {9, 12, 6, 15, 7, 3, 21, 4, 18, 5} return Contains(tunnels, GetInteriorGroupId(GetInteriorAtCoords(coords))) end ---------------------- -- HELPERS ---------------------- function DoRequestModel(model) local hash = GetHashKey(model) RequestModel(hash) local timeout = 0 while not HasModelLoaded(hash) and timeout < 100 do Citizen.Wait(100) timeout = timeout + 1 end end function Contains(tab, val) for index, value in ipairs(tab) do if value == val then return true end end return false end function DoRequestAnimDict(dict) RequestAnimDict(dict) local timeout = 0 while not HasAnimDictLoaded(dict) do Citizen.Wait(50) timeout = timeout + 1 if timeout > 100 then return end end end function PlayAnim(dict, anim, flag) Citizen.CreateThread(function() RequestAnimDict(dict) local timeout = 0 while not HasAnimDictLoaded(dict) do Citizen.Wait(50) timeout = timeout + 1 if timeout > 100 then return end end TaskPlayAnim(PlayerPedId(), dict, anim, 4.0, 8.0, 5.0, flag or 1, 0, false, false, false) RemoveAnimDict(dict) end) end function Shuffle(tbl) -- suffles numeric indices local len, random = #tbl, math.random; for i = len, 2, -1 do local j = random(1, i); tbl[i], tbl[j] = tbl[j], tbl[i]; end return tbl; end function string.insert(str1, str2, pos) return str1:sub(1, pos) .. str2 .. str1:sub(pos + 1) end function myDot(a, b) return (a[1] * b[1]) + (a[2] * b[2]) + (a[3] * b[3]) end function myMag(a) return math.sqrt((a[1] * a[1]) + (a[2] * a[2]) + (a[3] * a[3])) end RegisterNetEvent('kq_carheist:notify') AddEventHandler('kq_carheist:notify', function(message) ShowTooltip(message) end) function Debug(message) if Config.debug then print(message) end end local alertTitle = nil local alertMessage = nil local alertActive = false function Alert(title, message, duration) Citizen.CreateThread(function() alertTitle = title alertMessage = message alertActive = true Citizen.Wait(duration) alertActive = false end) end Citizen.CreateThread(function() while true do local sleep = 500 if alertActive then sleep = 1 local scaleform = RequestScaleformMovie('MP_BIG_MESSAGE_FREEMODE') while not HasScaleformMovieLoaded(scaleform) do Citizen.Wait(1) end PushScaleformMovieFunction(scaleform, 'SHOW_SHARD_WASTED_MP_MESSAGE') PushScaleformMovieFunctionParameterString(alertTitle) PushScaleformMovieFunctionParameterString(alertMessage) PopScaleformMovieFunctionVoid() DrawScaleformMovieFullscreen(scaleform, 255, 255, 255, 255, 0) end Citizen.Wait(sleep) end end) function L(text) if Locale and Locale[text] then return Locale[text] end return text end