1416 lines
		
	
	
	
		
			41 KiB
		
	
	
	
		
			Lua
		
	
	
	
	
	
			
		
		
	
	
			1416 lines
		
	
	
	
		
			41 KiB
		
	
	
	
		
			Lua
		
	
	
	
	
	
| local GetEntityCoords = GetEntityCoords
 | |
| local Wait = Wait
 | |
| local IsDisabledControlPressed = IsDisabledControlPressed
 | |
| local GetEntityBoneIndexByName = GetEntityBoneIndexByName
 | |
| local GetWorldPositionOfEntityBone = GetWorldPositionOfEntityBone
 | |
| local SetPauseMenuActive = SetPauseMenuActive
 | |
| local DisableAllControlActions = DisableAllControlActions
 | |
| local EnableControlAction = EnableControlAction
 | |
| local NetworkGetEntityIsNetworked = NetworkGetEntityIsNetworked
 | |
| local NetworkGetNetworkIdFromEntity = NetworkGetNetworkIdFromEntity
 | |
| local GetEntityModel = GetEntityModel
 | |
| local IsPedAPlayer = IsPedAPlayer
 | |
| local GetEntityType = GetEntityType
 | |
| local PlayerPedId = PlayerPedId
 | |
| local GetShapeTestResult = GetShapeTestResult
 | |
| local StartShapeTestLosProbe = StartShapeTestLosProbe
 | |
| local SetDrawOrigin = SetDrawOrigin
 | |
| local DrawSprite = DrawSprite
 | |
| local ClearDrawOrigin = ClearDrawOrigin
 | |
| local HasStreamedTextureDictLoaded = HasStreamedTextureDictLoaded
 | |
| local RequestStreamedTextureDict = RequestStreamedTextureDict
 | |
| local HasEntityClearLosToEntity = HasEntityClearLosToEntity
 | |
| local currentResourceName = GetCurrentResourceName()
 | |
| local Config, Types, Players, Entities, Models, Zones, nuiData, sendData, sendDistance = Config, { {}, {}, {} }, {}, {},
 | |
| 	{}, {}, {}, {}, {}
 | |
| local playerPed, targetActive, hasFocus, success, pedsReady, allowTarget = PlayerPedId(), false, false, false, false,
 | |
| 	true
 | |
| local screen = {}
 | |
| local table_wipe = table.wipe
 | |
| local pairs = pairs
 | |
| local pcall = pcall
 | |
| local CheckOptions = CheckOptions
 | |
| local Bones = Load('bones')
 | |
| local listSprite = {}
 | |
| 
 | |
| ---------------------------------------
 | |
| --- Source: https://github.com/citizenfx/lua/blob/luaglm-dev/cfx/libs/scripts/examples/scripting_gta.lua
 | |
| --- Credits to gottfriedleibniz
 | |
| local glm = require 'glm'
 | |
| 
 | |
| -- Cache common functions
 | |
| local glm_rad = glm.rad
 | |
| local glm_quatEuler = glm.quatEulerAngleZYX
 | |
| local glm_rayPicking = glm.rayPicking
 | |
| 
 | |
| -- Cache direction vectors
 | |
| local glm_up = glm.up()
 | |
| local glm_forward = glm.forward()
 | |
| 
 | |
| local function ScreenPositionToCameraRay()
 | |
| 	local pos = GetFinalRenderedCamCoord()
 | |
| 	local rot = glm_rad(GetFinalRenderedCamRot(2))
 | |
| 	local q = glm_quatEuler(rot.z, rot.y, rot.x)
 | |
| 	return pos, glm_rayPicking(
 | |
| 		q * glm_forward,
 | |
| 		q * glm_up,
 | |
| 		glm_rad(screen.fov),
 | |
| 		screen.ratio,
 | |
| 		0.10000, -- GetFinalRenderedCamNearClip(),
 | |
| 		10000.0, -- GetFinalRenderedCamFarClip(),
 | |
| 		0, 0
 | |
| 	)
 | |
| end
 | |
| ---------------------------------------
 | |
| 
 | |
| -- Functions
 | |
| 
 | |
| local function DrawTarget()
 | |
| 	CreateThread(function()
 | |
| 		while not HasStreamedTextureDictLoaded('shared') do
 | |
| 			Wait(10)
 | |
| 			RequestStreamedTextureDict('shared', true)
 | |
| 		end
 | |
| 		local sleep
 | |
| 		local r, g, b, a
 | |
| 		while targetActive do
 | |
| 			sleep = 500
 | |
| 			for _, zone in pairs(listSprite) do
 | |
| 				sleep = 0
 | |
| 
 | |
| 				r = zone.targetoptions.drawColor?[1] or Config.DrawColor[1]
 | |
| 				g = zone.targetoptions.drawColor?[2] or Config.DrawColor[2]
 | |
| 				b = zone.targetoptions.drawColor?[3] or Config.DrawColor[3]
 | |
| 				a = zone.targetoptions.drawColor?[4] or Config.DrawColor[4]
 | |
| 
 | |
| 				if zone.success then
 | |
| 					r = zone.targetoptions.successDrawColor?[1] or Config.SuccessDrawColor[1]
 | |
| 					g = zone.targetoptions.successDrawColor?[2] or Config.SuccessDrawColor[2]
 | |
| 					b = zone.targetoptions.successDrawColor?[3] or Config.SuccessDrawColor[3]
 | |
| 					a = zone.targetoptions.successDrawColor?[4] or Config.SuccessDrawColor[4]
 | |
| 				end
 | |
| 
 | |
| 				SetDrawOrigin(zone.center.x, zone.center.y, zone.center.z, 0)
 | |
| 				DrawSprite('shared', 'emptydot_32', 0, 0, 0.01, 0.02, 0, r, g, b, a)
 | |
| 				ClearDrawOrigin()
 | |
| 			end
 | |
| 			Wait(sleep)
 | |
| 		end
 | |
| 		listSprite = {}
 | |
| 	end)
 | |
| end
 | |
| 
 | |
| local function RaycastCamera(flag, playerCoords)
 | |
| 	if not playerPed then playerPed = PlayerPedId() end
 | |
| 	if not playerCoords then playerCoords = GetEntityCoords(playerPed) end
 | |
| 
 | |
| 	local rayPos, rayDir = ScreenPositionToCameraRay()
 | |
| 	local destination = rayPos + 16 * rayDir
 | |
| 	local rayHandle = StartShapeTestLosProbe(rayPos.x, rayPos.y, rayPos.z, destination.x, destination.y, destination.z,
 | |
| 		flag or -1, playerPed, 4)
 | |
| 
 | |
| 	while true do
 | |
| 		local result, _, endCoords, _, entityHit = GetShapeTestResult(rayHandle)
 | |
| 
 | |
| 		if result ~= 1 then
 | |
| 			local distance = playerCoords and #(playerCoords - endCoords)
 | |
| 
 | |
| 			if flag == 30 and entityHit then
 | |
| 				entityHit = HasEntityClearLosToEntity(entityHit, playerPed, 7) and entityHit
 | |
| 			end
 | |
| 
 | |
| 			local entityType = entityHit and GetEntityType(entityHit)
 | |
| 
 | |
| 			if entityType == 0 and pcall(GetEntityModel, entityHit) then
 | |
| 				entityType = 3
 | |
| 			end
 | |
| 
 | |
| 			return endCoords, distance, entityHit, entityType or 0
 | |
| 		end
 | |
| 
 | |
| 		Wait(0)
 | |
| 	end
 | |
| end
 | |
| 
 | |
| exports('RaycastCamera', RaycastCamera)
 | |
| 
 | |
| local function DisableNUI()
 | |
| 	SetNuiFocus(false, false)
 | |
| 	SetNuiFocusKeepInput(false)
 | |
| 	hasFocus = false
 | |
| end
 | |
| 
 | |
| exports('DisableNUI', DisableNUI)
 | |
| 
 | |
| local function EnableNUI(options)
 | |
| 	if not targetActive or hasFocus then return end
 | |
| 	SetCursorLocation(0.5, 0.5)
 | |
| 	SetNuiFocus(true, true)
 | |
| 	SetNuiFocusKeepInput(true)
 | |
| 	hasFocus = true
 | |
| 	SendNUIMessage({ response = 'validTarget', data = options })
 | |
| end
 | |
| 
 | |
| exports('EnableNUI', EnableNUI)
 | |
| 
 | |
| local function LeftTarget()
 | |
| 	SetNuiFocus(false, false)
 | |
| 	SetNuiFocusKeepInput(false)
 | |
| 	success, hasFocus = false, false
 | |
| 	table_wipe(sendData)
 | |
| 	SendNUIMessage({ response = 'leftTarget' })
 | |
| end
 | |
| 
 | |
| exports('LeftTarget', LeftTarget)
 | |
| 
 | |
| local function DisableTarget(forcedisable)
 | |
| 	if (not targetActive and hasFocus and not Config.Toggle) or not forcedisable then return end
 | |
| 	SetNuiFocus(false, false)
 | |
| 	SetNuiFocusKeepInput(false)
 | |
| 	Wait(100)
 | |
| 	targetActive, success, hasFocus = false, false, false
 | |
| 	SendNUIMessage({ response = 'closeTarget' })
 | |
| end
 | |
| 
 | |
| exports('DisableTarget', DisableTarget)
 | |
| 
 | |
| local function DrawOutlineEntity(entity, bool)
 | |
| 	if not Config.EnableOutline or IsEntityAPed(entity) then return end
 | |
| 	SetEntityDrawOutline(entity, bool)
 | |
| 	SetEntityDrawOutlineColor(Config.OutlineColor[1], Config.OutlineColor[2], Config.OutlineColor[3], Config.OutlineColor[4])
 | |
| end
 | |
| 
 | |
| exports('DrawOutlineEntity', DrawOutlineEntity)
 | |
| 
 | |
| local function SetupOptions(datatable, entity, distance, isZone)
 | |
| 	if not isZone then table_wipe(sendDistance) end
 | |
| 	table_wipe(nuiData)
 | |
| 	local slot = 0
 | |
| 	for _, data in pairs(datatable) do
 | |
| 		if CheckOptions(data, entity, distance) then
 | |
| 			slot = data.num or slot + 1
 | |
| 			sendData[slot] = data
 | |
| 			sendData[slot].entity = entity
 | |
| 			nuiData[slot] = {
 | |
| 				icon = data.icon,
 | |
| 				targeticon = data.targeticon,
 | |
| 				label = data.label
 | |
| 			}
 | |
| 			if not isZone then
 | |
| 				sendDistance[data.distance] = true
 | |
| 			end
 | |
| 		else
 | |
| 			if not isZone then
 | |
| 				sendDistance[data.distance] = false
 | |
| 			end
 | |
| 		end
 | |
| 	end
 | |
| 	return slot
 | |
| end
 | |
| 
 | |
| local function CheckEntity(flag, datatable, entity, distance)
 | |
| 	if not next(datatable) then return end
 | |
| 	local slot = SetupOptions(datatable, entity, distance)
 | |
| 	if not next(nuiData) then
 | |
| 		LeftTarget()
 | |
| 		DrawOutlineEntity(entity, false)
 | |
| 		return
 | |
| 	end
 | |
| 	success = true
 | |
| 	SendNUIMessage({ response = 'foundTarget', data = nuiData[slot].targeticon, options = nuiData })
 | |
| 	DrawOutlineEntity(entity, true)
 | |
| 	while targetActive and success do
 | |
| 		local _, dist, entity2 = RaycastCamera(flag)
 | |
| 		if entity ~= entity2 then
 | |
| 			LeftTarget()
 | |
| 			DrawOutlineEntity(entity, false)
 | |
| 			break
 | |
| 		elseif not hasFocus and IsDisabledControlPressed(0, Config.MenuControlKey) then
 | |
| 			EnableNUI(nuiData)
 | |
| 			DrawOutlineEntity(entity, false)
 | |
| 		else
 | |
| 			for k, v in pairs(sendDistance) do
 | |
| 				if v and dist > k then
 | |
| 					LeftTarget()
 | |
| 					DrawOutlineEntity(entity, false)
 | |
| 					break
 | |
| 				end
 | |
| 			end
 | |
| 		end
 | |
| 		Wait(0)
 | |
| 	end
 | |
| 	LeftTarget()
 | |
| 	DrawOutlineEntity(entity, false)
 | |
| end
 | |
| 
 | |
| exports('CheckEntity', CheckEntity)
 | |
| 
 | |
| local function CheckBones(coords, entity, bonelist)
 | |
| 	local closestBone = -1
 | |
| 	local closestDistance = 20
 | |
| 	local closestPos, closestBoneName
 | |
| 	for _, v in pairs(bonelist) do
 | |
| 		if Bones.Options[v] then
 | |
| 			local boneId = GetEntityBoneIndexByName(entity, v)
 | |
| 			local bonePos = GetWorldPositionOfEntityBone(entity, boneId)
 | |
| 			local distance = #(coords - bonePos)
 | |
| 			if closestBone == -1 or distance < closestDistance then
 | |
| 				closestBone, closestDistance, closestPos, closestBoneName = boneId, distance, bonePos, v
 | |
| 			end
 | |
| 		end
 | |
| 	end
 | |
| 	if closestBone ~= -1 then
 | |
| 		return closestBone, closestPos, closestBoneName
 | |
| 	else
 | |
| 		return false
 | |
| 	end
 | |
| end
 | |
| 
 | |
| exports('CheckBones', CheckBones)
 | |
| 
 | |
| local function EnableTarget()
 | |
| 	if not allowTarget or success or (not Config.Standalone and not LocalPlayer.state['isLoggedIn']) or IsNuiFocused() or (Config.DisableInVehicle and IsPedInAnyVehicle(playerPed or PlayerPedId(), false)) then return end
 | |
| 	if targetActive then return end
 | |
| 
 | |
| 	targetActive = true
 | |
| 	playerPed = PlayerPedId()
 | |
| 	screen.ratio = GetAspectRatio(true)
 | |
| 	screen.fov = GetFinalRenderedCamFov()
 | |
| 	if Config.DrawSprite then DrawTarget() end
 | |
| 
 | |
| 	SendNUIMessage({ response = 'openTarget' })
 | |
| 	CreateThread(function()
 | |
| 		repeat
 | |
| 			SetPauseMenuActive(false)
 | |
| 			if Config.DisableControls then
 | |
| 				DisableAllControlActions(0)
 | |
| 			else
 | |
| 				DisableControlAction(0, 1, true) -- look left/right
 | |
| 				DisableControlAction(0, 2, true) -- look up/down
 | |
| 				DisableControlAction(0, 4, true) -- look down only
 | |
| 				DisableControlAction(0, 5, true) -- look left only
 | |
| 				DisableControlAction(0, 6, true) -- look right only
 | |
| 				DisableControlAction(0, 25, true) -- input aim
 | |
| 				DisableControlAction(0, 24, true) -- attack
 | |
| 			end
 | |
| 			EnableControlAction(0, 30, true) -- move left/right
 | |
| 			EnableControlAction(0, 31, true) -- move forward/back
 | |
| 
 | |
| 			if not hasFocus then
 | |
| 				EnableControlAction(0, 1, true) -- look left/right
 | |
| 				EnableControlAction(0, 2, true) -- look up/down
 | |
| 			end
 | |
| 
 | |
| 			Wait(0)
 | |
| 		until not targetActive
 | |
| 	end)
 | |
| 
 | |
| 	local flag = 30
 | |
| 
 | |
| 	while targetActive do
 | |
| 		local sleep = 0
 | |
| 		if flag == 30 then flag = -1 else flag = 30 end
 | |
| 
 | |
| 		local coords, distance, entity, entityType = RaycastCamera(flag)
 | |
| 		if distance <= Config.MaxDistance then
 | |
| 			if entityType > 0 then
 | |
| 				-- Local(non-net) entity targets
 | |
| 				if Entities[entity] then
 | |
| 					CheckEntity(flag, Entities[entity], entity, distance)
 | |
| 				end
 | |
| 
 | |
| 				-- Owned entity targets
 | |
| 				if NetworkGetEntityIsNetworked(entity) then
 | |
| 					local data = Entities[NetworkGetNetworkIdFromEntity(entity)]
 | |
| 					if data then CheckEntity(flag, data, entity, distance) end
 | |
| 				end
 | |
| 
 | |
| 				-- Player and Ped targets
 | |
| 				if entityType == 1 then
 | |
| 					local data = Models[GetEntityModel(entity)]
 | |
| 					if IsPedAPlayer(entity) then data = Players end
 | |
| 					if data and next(data) then CheckEntity(flag, data, entity, distance) end
 | |
| 
 | |
| 					-- Vehicle bones and models
 | |
| 				elseif entityType == 2 then
 | |
| 					local closestBone, _, closestBoneName = CheckBones(coords, entity, Bones.Vehicle)
 | |
| 					local datatable = Bones.Options[closestBoneName]
 | |
| 
 | |
| 					if datatable and next(datatable) and closestBone then
 | |
| 						local slot = SetupOptions(datatable, entity, distance)
 | |
| 						if next(nuiData) then
 | |
| 							success = true
 | |
| 							SendNUIMessage({ response = 'foundTarget', data = nuiData[slot].targeticon, options = nuiData })
 | |
| 							DrawOutlineEntity(entity, true)
 | |
| 							while targetActive and success do
 | |
| 								local coords2, dist, entity2 = RaycastCamera(flag)
 | |
| 								if entity == entity2 then
 | |
| 									local closestBone2 = CheckBones(coords2, entity, Bones.Vehicle)
 | |
| 									if closestBone ~= closestBone2 then
 | |
| 										LeftTarget()
 | |
| 										DrawOutlineEntity(entity, false)
 | |
| 										break
 | |
| 									elseif not hasFocus and IsDisabledControlPressed(0, Config.MenuControlKey) then
 | |
| 										EnableNUI(nuiData)
 | |
| 										DrawOutlineEntity(entity, false)
 | |
| 									else
 | |
| 										for k, v in pairs(sendDistance) do
 | |
| 											if v and dist > k then
 | |
| 												LeftTarget()
 | |
| 												DrawOutlineEntity(entity, false)
 | |
| 												break
 | |
| 											end
 | |
| 										end
 | |
| 									end
 | |
| 								else
 | |
| 									LeftTarget()
 | |
| 									DrawOutlineEntity(entity, false)
 | |
| 									break
 | |
| 								end
 | |
| 								Wait(0)
 | |
| 							end
 | |
| 							LeftTarget()
 | |
| 							DrawOutlineEntity(entity, false)
 | |
| 						end
 | |
| 					end
 | |
| 
 | |
| 					-- Vehicle model targets
 | |
| 					local data = Models[GetEntityModel(entity)]
 | |
| 					if data then CheckEntity(flag, data, entity, distance) end
 | |
| 
 | |
| 					-- Entity targets
 | |
| 				elseif entityType > 2 then
 | |
| 					local data = Models[GetEntityModel(entity)]
 | |
| 					if data then CheckEntity(flag, data, entity, distance) end
 | |
| 				end
 | |
| 
 | |
| 				-- Generic targets
 | |
| 				if not success then
 | |
| 					local data = Types[entityType]
 | |
| 					if data and next(data) then CheckEntity(flag, data, entity, distance) end
 | |
| 				end
 | |
| 			else
 | |
| 				sleep = sleep + 20
 | |
| 			end
 | |
| 			if not success then
 | |
| 				-- Zone targets
 | |
| 				local closestDis, closestZone
 | |
| 				for k, zone in pairs(Zones) do
 | |
| 					if distance < (closestDis or Config.MaxDistance) and distance <= zone.targetoptions.distance and zone:isPointInside(coords) then
 | |
| 						closestDis = distance
 | |
| 						closestZone = zone
 | |
| 					end
 | |
| 					if Config.DrawSprite then
 | |
| 						local testCentre = type(zone.center) == 'vector2' and vector3(zone.center.x, zone.center.y, zone.maxZ) or zone.center
 | |
| 						if #(coords - testCentre) < (zone.targetoptions.drawDistance or Config.DrawDistance) then
 | |
| 							listSprite[k] = zone
 | |
| 						else
 | |
| 							listSprite[k] = nil
 | |
| 						end
 | |
| 					end
 | |
| 				end
 | |
| 				if closestZone then
 | |
| 					local slot = SetupOptions(closestZone.targetoptions.options, entity, distance, true)
 | |
| 					if next(nuiData) then
 | |
| 						success = true
 | |
| 						SendNUIMessage({ response = 'foundTarget', data = nuiData[slot].targeticon, options = nuiData })
 | |
| 						if Config.DrawSprite then
 | |
| 							listSprite[closestZone.name].success = true
 | |
| 						end
 | |
| 						DrawOutlineEntity(entity, true)
 | |
| 						while targetActive and success do
 | |
| 							local newCoords, dist = RaycastCamera(flag)
 | |
| 							if not closestZone:isPointInside(newCoords) or dist > closestZone.targetoptions.distance then
 | |
| 								LeftTarget()
 | |
| 								DrawOutlineEntity(entity, false)
 | |
| 								break
 | |
| 							elseif not hasFocus and IsDisabledControlPressed(0, Config.MenuControlKey) then
 | |
| 								EnableNUI(nuiData)
 | |
| 								DrawOutlineEntity(entity, false)
 | |
| 							end
 | |
| 							Wait(0)
 | |
| 						end
 | |
| 						if Config.DrawSprite and listSprite[closestZone.name] then -- Check for when the targetActive is false and it removes the zone from listSprite
 | |
| 							listSprite[closestZone.name].success = false
 | |
| 						end
 | |
| 						LeftTarget()
 | |
| 						DrawOutlineEntity(entity, false)
 | |
| 					end
 | |
| 				else
 | |
| 					sleep = sleep + 20
 | |
| 				end
 | |
| 			else
 | |
| 				LeftTarget()
 | |
| 				DrawOutlineEntity(entity, false)
 | |
| 			end
 | |
| 		else
 | |
| 			sleep = sleep + 20
 | |
| 		end
 | |
| 		Wait(sleep)
 | |
| 	end
 | |
| 	DisableTarget(false)
 | |
| end
 | |
| 
 | |
| local function AddCircleZone(name, center, radius, options, targetoptions)
 | |
| 	local centerType = type(center)
 | |
| 	center = (centerType == 'table' or centerType == 'vector4') and vec3(center.x, center.y, center.z) or center
 | |
| 	Zones[name] = CircleZone:Create(center, radius, options)
 | |
| 	targetoptions.distance = targetoptions.distance or Config.MaxDistance
 | |
| 	Zones[name].targetoptions = targetoptions
 | |
| 	return Zones[name]
 | |
| end
 | |
| 
 | |
| exports('AddCircleZone', AddCircleZone)
 | |
| 
 | |
| local function AddBoxZone(name, center, length, width, options, targetoptions)
 | |
| 	local centerType = type(center)
 | |
| 	center = (centerType == 'table' or centerType == 'vector4') and vec3(center.x, center.y, center.z) or center
 | |
| 	Zones[name] = BoxZone:Create(center, length, width, options)
 | |
| 	targetoptions.distance = targetoptions.distance or Config.MaxDistance
 | |
| 	Zones[name].targetoptions = targetoptions
 | |
| 	return Zones[name]
 | |
| end
 | |
| 
 | |
| exports('AddBoxZone', AddBoxZone)
 | |
| 
 | |
| local function AddPolyZone(name, points, options, targetoptions)
 | |
| 	local _points = {}
 | |
| 	local pointsType = type(points[1])
 | |
| 	if pointsType == 'table' or pointsType == 'vector3' or pointsType == 'vector4' then
 | |
| 		for i = 1, #points do
 | |
| 			_points[i] = vec2(points[i].x, points[i].y)
 | |
| 		end
 | |
| 	end
 | |
| 	Zones[name] = PolyZone:Create(#_points > 0 and _points or points, options)
 | |
| 	targetoptions.distance = targetoptions.distance or Config.MaxDistance
 | |
| 	Zones[name].targetoptions = targetoptions
 | |
| 	return Zones[name]
 | |
| end
 | |
| 
 | |
| exports('AddPolyZone', AddPolyZone)
 | |
| 
 | |
| local function AddComboZone(zones, options, targetoptions)
 | |
| 	Zones[options.name] = ComboZone:Create(zones, options)
 | |
| 	targetoptions.distance = targetoptions.distance or Config.MaxDistance
 | |
| 	Zones[options.name].targetoptions = targetoptions
 | |
| 	return Zones[options.name]
 | |
| end
 | |
| 
 | |
| exports('AddComboZone', AddComboZone)
 | |
| 
 | |
| local function AddEntityZone(name, entity, options, targetoptions)
 | |
| 	Zones[name] = EntityZone:Create(entity, options)
 | |
| 	targetoptions.distance = targetoptions.distance or Config.MaxDistance
 | |
| 	Zones[name].targetoptions = targetoptions
 | |
| 	return Zones[name]
 | |
| end
 | |
| 
 | |
| exports('AddEntityZone', AddEntityZone)
 | |
| 
 | |
| local function RemoveZone(name)
 | |
| 	if not Zones[name] then return end
 | |
| 	if Zones[name].destroy then Zones[name]:destroy() end
 | |
| 	Zones[name] = nil
 | |
| end
 | |
| 
 | |
| exports('RemoveZone', RemoveZone)
 | |
| 
 | |
| local function SetOptions(tbl, distance, options)
 | |
| 	for _, v in pairs(options) do
 | |
| 		if v.required_item then
 | |
| 			v.item = v.required_item
 | |
| 			v.required_item = nil
 | |
| 		end
 | |
| 		if not v.distance or v.distance > distance then v.distance = distance end
 | |
| 		tbl[v.label] = v
 | |
| 	end
 | |
| end
 | |
| 
 | |
| local function AddTargetBone(bones, parameters)
 | |
| 	local distance, options = parameters.distance or Config.MaxDistance, parameters.options
 | |
| 	if type(bones) == 'table' then
 | |
| 		for _, bone in pairs(bones) do
 | |
| 			if not Bones.Options[bone] then Bones.Options[bone] = {} end
 | |
| 			SetOptions(Bones.Options[bone], distance, options)
 | |
| 		end
 | |
| 	elseif type(bones) == 'string' then
 | |
| 		if not Bones.Options[bones] then Bones.Options[bones] = {} end
 | |
| 		SetOptions(Bones.Options[bones], distance, options)
 | |
| 	end
 | |
| end
 | |
| 
 | |
| exports('AddTargetBone', AddTargetBone)
 | |
| 
 | |
| local function RemoveTargetBone(bones, labels)
 | |
| 	if type(bones) == 'table' then
 | |
| 		for _, bone in pairs(bones) do
 | |
| 			if labels then
 | |
| 				if type(labels) == 'table' then
 | |
| 					for _, v in pairs(labels) do
 | |
| 						if Bones.Options[bone] then
 | |
| 							Bones.Options[bone][v] = nil
 | |
| 						end
 | |
| 					end
 | |
| 				elseif type(labels) == 'string' then
 | |
| 					if Bones.Options[bone] then
 | |
| 						Bones.Options[bone][labels] = nil
 | |
| 					end
 | |
| 				end
 | |
| 			else
 | |
| 				Bones.Options[bone] = nil
 | |
| 			end
 | |
| 		end
 | |
| 	else
 | |
| 		if labels then
 | |
| 			if type(labels) == 'table' then
 | |
| 				for _, v in pairs(labels) do
 | |
| 					if Bones.Options[bones] then
 | |
| 						Bones.Options[bones][v] = nil
 | |
| 					end
 | |
| 				end
 | |
| 			elseif type(labels) == 'string' then
 | |
| 				if Bones.Options[bones] then
 | |
| 					Bones.Options[bones][labels] = nil
 | |
| 				end
 | |
| 			end
 | |
| 		else
 | |
| 			Bones.Options[bones] = nil
 | |
| 		end
 | |
| 	end
 | |
| end
 | |
| 
 | |
| exports('RemoveTargetBone', RemoveTargetBone)
 | |
| 
 | |
| local function AddTargetEntity(entities, parameters)
 | |
| 	local distance, options = parameters.distance or Config.MaxDistance, parameters.options
 | |
| 	if type(entities) == 'table' then
 | |
| 		for _, entity in pairs(entities) do
 | |
| 			if NetworkGetEntityIsNetworked(entity) then entity = NetworkGetNetworkIdFromEntity(entity) end -- Allow non-networked entities to be targeted
 | |
| 			if not Entities[entity] then Entities[entity] = {} end
 | |
| 			SetOptions(Entities[entity], distance, options)
 | |
| 		end
 | |
| 	elseif type(entities) == 'number' then
 | |
| 		if NetworkGetEntityIsNetworked(entities) then entities = NetworkGetNetworkIdFromEntity(entities) end -- Allow non-networked entities to be targeted
 | |
| 		if not Entities[entities] then Entities[entities] = {} end
 | |
| 		SetOptions(Entities[entities], distance, options)
 | |
| 	end
 | |
| end
 | |
| 
 | |
| exports('AddTargetEntity', AddTargetEntity)
 | |
| 
 | |
| local function RemoveTargetEntity(entities, labels)
 | |
| 	if type(entities) == 'table' then
 | |
| 		for _, entity in pairs(entities) do
 | |
| 			if NetworkGetEntityIsNetworked(entity) then entity = NetworkGetNetworkIdFromEntity(entity) end -- Allow non-networked entities to be targeted
 | |
| 			if labels then
 | |
| 				if type(labels) == 'table' then
 | |
| 					for _, v in pairs(labels) do
 | |
| 						if Entities[entity] then
 | |
| 							Entities[entity][v] = nil
 | |
| 						end
 | |
| 					end
 | |
| 				elseif type(labels) == 'string' then
 | |
| 					if Entities[entity] then
 | |
| 						Entities[entity][labels] = nil
 | |
| 					end
 | |
| 				end
 | |
| 			else
 | |
| 				Entities[entity] = nil
 | |
| 			end
 | |
| 		end
 | |
| 	elseif type(entities) == 'number' then
 | |
| 		if NetworkGetEntityIsNetworked(entities) then entities = NetworkGetNetworkIdFromEntity(entities) end -- Allow non-networked entities to be targeted
 | |
| 		if labels then
 | |
| 			if type(labels) == 'table' then
 | |
| 				for _, v in pairs(labels) do
 | |
| 					if Entities[entities] then
 | |
| 						Entities[entities][v] = nil
 | |
| 					end
 | |
| 				end
 | |
| 			elseif type(labels) == 'string' then
 | |
| 				if Entities[entities] then
 | |
| 					Entities[entities][labels] = nil
 | |
| 				end
 | |
| 			end
 | |
| 		else
 | |
| 			Entities[entities] = nil
 | |
| 		end
 | |
| 	end
 | |
| end
 | |
| 
 | |
| exports('RemoveTargetEntity', RemoveTargetEntity)
 | |
| 
 | |
| local function AddTargetModel(models, parameters)
 | |
| 	local distance, options = parameters.distance or Config.MaxDistance, parameters.options
 | |
| 	if type(models) == 'table' then
 | |
| 		for _, model in pairs(models) do
 | |
| 			if type(model) == 'string' then model = joaat(model) end
 | |
| 			if not Models[model] then Models[model] = {} end
 | |
| 			SetOptions(Models[model], distance, options)
 | |
| 		end
 | |
| 	else
 | |
| 		if type(models) == 'string' then models = joaat(models) end
 | |
| 		if not Models[models] then Models[models] = {} end
 | |
| 		SetOptions(Models[models], distance, options)
 | |
| 	end
 | |
| end
 | |
| 
 | |
| exports('AddTargetModel', AddTargetModel)
 | |
| 
 | |
| local function RemoveTargetModel(models, labels)
 | |
| 	if type(models) == 'table' then
 | |
| 		for _, model in pairs(models) do
 | |
| 			if type(model) == 'string' then model = joaat(model) end
 | |
| 			if labels then
 | |
| 				if type(labels) == 'table' then
 | |
| 					for _, v in pairs(labels) do
 | |
| 						if Models[model] then
 | |
| 							Models[model][v] = nil
 | |
| 						end
 | |
| 					end
 | |
| 				elseif type(labels) == 'string' then
 | |
| 					if Models[model] then
 | |
| 						Models[model][labels] = nil
 | |
| 					end
 | |
| 				end
 | |
| 			else
 | |
| 				Models[model] = nil
 | |
| 			end
 | |
| 		end
 | |
| 	else
 | |
| 		if type(models) == 'string' then models = joaat(models) end
 | |
| 		if labels then
 | |
| 			if type(labels) == 'table' then
 | |
| 				for _, v in pairs(labels) do
 | |
| 					if Models[models] then
 | |
| 						Models[models][v] = nil
 | |
| 					end
 | |
| 				end
 | |
| 			elseif type(labels) == 'string' then
 | |
| 				if Models[models] then
 | |
| 					Models[models][labels] = nil
 | |
| 				end
 | |
| 			end
 | |
| 		else
 | |
| 			Models[models] = nil
 | |
| 		end
 | |
| 	end
 | |
| end
 | |
| 
 | |
| exports('RemoveTargetModel', RemoveTargetModel)
 | |
| 
 | |
| local function AddGlobalType(type, parameters)
 | |
| 	local distance, options = parameters.distance or Config.MaxDistance, parameters.options
 | |
| 	SetOptions(Types[type], distance, options)
 | |
| end
 | |
| 
 | |
| exports('AddGlobalType', AddGlobalType)
 | |
| 
 | |
| local function AddGlobalPed(parameters) AddGlobalType(1, parameters) end
 | |
| 
 | |
| exports('AddGlobalPed', AddGlobalPed)
 | |
| 
 | |
| local function AddGlobalVehicle(parameters) AddGlobalType(2, parameters) end
 | |
| 
 | |
| exports('AddGlobalVehicle', AddGlobalVehicle)
 | |
| 
 | |
| local function AddGlobalObject(parameters) AddGlobalType(3, parameters) end
 | |
| 
 | |
| exports('AddGlobalObject', AddGlobalObject)
 | |
| 
 | |
| local function AddGlobalPlayer(parameters)
 | |
| 	local distance, options = parameters.distance or Config.MaxDistance, parameters.options
 | |
| 	SetOptions(Players, distance, options)
 | |
| end
 | |
| 
 | |
| exports('AddGlobalPlayer', AddGlobalPlayer)
 | |
| 
 | |
| local function RemoveGlobalType(typ, labels)
 | |
| 	if labels then
 | |
| 		if type(labels) == 'table' then
 | |
| 			for _, v in pairs(labels) do
 | |
| 				Types[typ][v] = nil
 | |
| 			end
 | |
| 		elseif type(labels) == 'string' then
 | |
| 			Types[typ][labels] = nil
 | |
| 		end
 | |
| 	else
 | |
| 		Types[typ] = {}
 | |
| 	end
 | |
| end
 | |
| 
 | |
| exports('RemoveGlobalType', RemoveGlobalType)
 | |
| 
 | |
| local function RemoveGlobalPlayer(labels)
 | |
| 	if labels then
 | |
| 		if type(labels) == 'table' then
 | |
| 			for _, v in pairs(labels) do
 | |
| 				Players[v] = nil
 | |
| 			end
 | |
| 		elseif type(labels) == 'string' then
 | |
| 			Players[labels] = nil
 | |
| 		end
 | |
| 	else
 | |
| 		Players = {}
 | |
| 	end
 | |
| end
 | |
| 
 | |
| exports('RemoveGlobalPlayer', RemoveGlobalPlayer)
 | |
| 
 | |
| function SpawnPeds()
 | |
| 	if pedsReady or not next(Config.Peds) then return end
 | |
| 	for k, v in pairs(Config.Peds) do
 | |
| 		if not v.currentpednumber or v.currentpednumber == 0 then
 | |
| 			local spawnedped
 | |
| 			RequestModel(v.model)
 | |
| 			while not HasModelLoaded(v.model) do
 | |
| 				Wait(0)
 | |
| 			end
 | |
| 
 | |
| 			if type(v.model) == 'string' then v.model = joaat(v.model) end
 | |
| 
 | |
| 			if v.minusOne then
 | |
| 				spawnedped = CreatePed(0, v.model, v.coords.x, v.coords.y, v.coords.z - 1.0, v.coords.w,
 | |
| 					v.networked or false, false)
 | |
| 			else
 | |
| 				spawnedped = CreatePed(0, v.model, v.coords.x, v.coords.y, v.coords.z, v.coords.w, v.networked or false,
 | |
| 					false)
 | |
| 			end
 | |
| 
 | |
| 			if v.freeze then
 | |
| 				FreezeEntityPosition(spawnedped, true)
 | |
| 			end
 | |
| 
 | |
| 			if v.invincible then
 | |
| 				SetEntityInvincible(spawnedped, true)
 | |
| 			end
 | |
| 
 | |
| 			if v.blockevents then
 | |
| 				SetBlockingOfNonTemporaryEvents(spawnedped, true)
 | |
| 			end
 | |
| 
 | |
| 			if v.animDict and v.anim then
 | |
| 				RequestAnimDict(v.animDict)
 | |
| 				while not HasAnimDictLoaded(v.animDict) do
 | |
| 					Wait(0)
 | |
| 				end
 | |
| 
 | |
| 				TaskPlayAnim(spawnedped, v.animDict, v.anim, 8.0, 0, -1, v.flag or 1, 0, false, false, false)
 | |
| 			end
 | |
| 
 | |
| 			if v.scenario then
 | |
| 				SetPedCanPlayAmbientAnims(spawnedped, true)
 | |
| 				TaskStartScenarioInPlace(spawnedped, v.scenario, 0, true)
 | |
| 			end
 | |
| 
 | |
| 			if v.pedrelations then
 | |
| 				if type(v.pedrelations.groupname) ~= 'string' then error(v.pedrelations.groupname .. ' is not a string') end
 | |
| 
 | |
| 				local pedgrouphash = joaat(v.pedrelations.groupname)
 | |
| 
 | |
| 				if not DoesRelationshipGroupExist(pedgrouphash) then
 | |
| 					AddRelationshipGroup(v.pedrelations.groupname)
 | |
| 				end
 | |
| 
 | |
| 				SetPedRelationshipGroupHash(spawnedped, pedgrouphash)
 | |
| 				if v.pedrelations.toplayer then
 | |
| 					SetRelationshipBetweenGroups(v.pedrelations.toplayer, pedgrouphash, joaat('PLAYER'))
 | |
| 				end
 | |
| 
 | |
| 				if v.pedrelations.toowngroup then
 | |
| 					SetRelationshipBetweenGroups(v.pedrelations.toowngroup, pedgrouphash, pedgrouphash)
 | |
| 				end
 | |
| 			end
 | |
| 
 | |
| 			if v.weapon then
 | |
| 				if type(v.weapon.name) == 'string' then v.weapon.name = joaat(v.weapon.name) end
 | |
| 
 | |
| 				if IsWeaponValid(v.weapon.name) then
 | |
| 					SetCanPedEquipWeapon(spawnedped, v.weapon.name, true)
 | |
| 					GiveWeaponToPed(spawnedped, v.weapon.name, v.weapon.ammo, v.weapon.hidden or false, true)
 | |
| 					SetPedCurrentWeaponVisible(spawnedped, not v.weapon.hidden or false, true)
 | |
| 				end
 | |
| 			end
 | |
| 
 | |
| 			if v.target then
 | |
| 				if v.target.useModel then
 | |
| 					AddTargetModel(v.model, {
 | |
| 						options = v.target.options,
 | |
| 						distance = v.target.distance
 | |
| 					})
 | |
| 				else
 | |
| 					AddTargetEntity(spawnedped, {
 | |
| 						options = v.target.options,
 | |
| 						distance = v.target.distance
 | |
| 					})
 | |
| 				end
 | |
| 			end
 | |
| 
 | |
| 			if v.action then
 | |
| 				v.action(v)
 | |
| 			end
 | |
| 
 | |
| 			Config.Peds[k].currentpednumber = spawnedped
 | |
| 		end
 | |
| 	end
 | |
| 	pedsReady = true
 | |
| end
 | |
| 
 | |
| function DeletePeds()
 | |
| 	if not pedsReady or not next(Config.Peds) then return end
 | |
| 	for k, v in pairs(Config.Peds) do
 | |
| 		DeletePed(v.currentpednumber)
 | |
| 		Config.Peds[k].currentpednumber = 0
 | |
| 	end
 | |
| 	pedsReady = false
 | |
| end
 | |
| 
 | |
| exports('DeletePeds', DeletePeds)
 | |
| 
 | |
| local function SpawnPed(data)
 | |
| 	local spawnedped
 | |
| 	local key, value = next(data)
 | |
| 	if type(value) == 'table' and type(key) ~= 'string' then
 | |
| 		for _, v in pairs(data) do
 | |
| 			if v.spawnNow then
 | |
| 				RequestModel(v.model)
 | |
| 				while not HasModelLoaded(v.model) do
 | |
| 					Wait(0)
 | |
| 				end
 | |
| 
 | |
| 				if type(v.model) == 'string' then v.model = joaat(v.model) end
 | |
| 
 | |
| 				if v.minusOne then
 | |
| 					spawnedped = CreatePed(0, v.model, v.coords.x, v.coords.y, v.coords.z - 1.0, v.coords.w or 0.0,
 | |
| 						v.networked or false, true)
 | |
| 				else
 | |
| 					spawnedped = CreatePed(0, v.model, v.coords.x, v.coords.y, v.coords.z, v.coords.w or 0.0,
 | |
| 						v.networked or false, true)
 | |
| 				end
 | |
| 
 | |
| 				if v.freeze then
 | |
| 					FreezeEntityPosition(spawnedped, true)
 | |
| 				end
 | |
| 
 | |
| 				if v.invincible then
 | |
| 					SetEntityInvincible(spawnedped, true)
 | |
| 				end
 | |
| 
 | |
| 				if v.blockevents then
 | |
| 					SetBlockingOfNonTemporaryEvents(spawnedped, true)
 | |
| 				end
 | |
| 
 | |
| 				if v.animDict and v.anim then
 | |
| 					RequestAnimDict(v.animDict)
 | |
| 					while not HasAnimDictLoaded(v.animDict) do
 | |
| 						Wait(0)
 | |
| 					end
 | |
| 
 | |
| 					TaskPlayAnim(spawnedped, v.animDict, v.anim, 8.0, 0, -1, v.flag or 1, 0, false, false, false)
 | |
| 				end
 | |
| 
 | |
| 				if v.scenario then
 | |
| 					SetPedCanPlayAmbientAnims(spawnedped, true)
 | |
| 					TaskStartScenarioInPlace(spawnedped, v.scenario, 0, true)
 | |
| 				end
 | |
| 
 | |
| 				if v.pedrelations and type(v.pedrelations.groupname) == 'string' then
 | |
| 					if type(v.pedrelations.groupname) ~= 'string' then
 | |
| 						error(v.pedrelations.groupname ..
 | |
| 							' is not a string')
 | |
| 					end
 | |
| 
 | |
| 					local pedgrouphash = joaat(v.pedrelations.groupname)
 | |
| 
 | |
| 					if not DoesRelationshipGroupExist(pedgrouphash) then
 | |
| 						AddRelationshipGroup(v.pedrelations.groupname)
 | |
| 					end
 | |
| 
 | |
| 					SetPedRelationshipGroupHash(spawnedped, pedgrouphash)
 | |
| 					if v.pedrelations.toplayer then
 | |
| 						SetRelationshipBetweenGroups(v.pedrelations.toplayer, pedgrouphash, joaat('PLAYER'))
 | |
| 					end
 | |
| 
 | |
| 					if v.pedrelations.toowngroup then
 | |
| 						SetRelationshipBetweenGroups(v.pedrelations.toowngroup, pedgrouphash, pedgrouphash)
 | |
| 					end
 | |
| 				end
 | |
| 
 | |
| 				if v.weapon then
 | |
| 					if type(v.weapon.name) == 'string' then v.weapon.name = joaat(v.weapon.name) end
 | |
| 
 | |
| 					if IsWeaponValid(v.weapon.name) then
 | |
| 						SetCanPedEquipWeapon(spawnedped, v.weapon.name, true)
 | |
| 						GiveWeaponToPed(spawnedped, v.weapon.name, v.weapon.ammo, v.weapon.hidden or false, true)
 | |
| 						SetPedCurrentWeaponVisible(spawnedped, not v.weapon.hidden or false, true)
 | |
| 					end
 | |
| 				end
 | |
| 
 | |
| 				if v.target then
 | |
| 					if v.target.useModel then
 | |
| 						AddTargetModel(v.model, {
 | |
| 							options = v.target.options,
 | |
| 							distance = v.target.distance
 | |
| 						})
 | |
| 					else
 | |
| 						AddTargetEntity(spawnedped, {
 | |
| 							options = v.target.options,
 | |
| 							distance = v.target.distance
 | |
| 						})
 | |
| 					end
 | |
| 				end
 | |
| 
 | |
| 				v.currentpednumber = spawnedped
 | |
| 
 | |
| 				if v.action then
 | |
| 					v.action(v)
 | |
| 				end
 | |
| 			end
 | |
| 
 | |
| 			local nextnumber = #Config.Peds + 1
 | |
| 			if nextnumber <= 0 then nextnumber = 1 end
 | |
| 
 | |
| 			Config.Peds[nextnumber] = v
 | |
| 		end
 | |
| 	else
 | |
| 		if data.spawnNow then
 | |
| 			RequestModel(data.model)
 | |
| 			while not HasModelLoaded(data.model) do
 | |
| 				Wait(0)
 | |
| 			end
 | |
| 
 | |
| 			if type(data.model) == 'string' then data.model = joaat(data.model) end
 | |
| 
 | |
| 			if data.minusOne then
 | |
| 				spawnedped = CreatePed(0, data.model, data.coords.x, data.coords.y, data.coords.z - 1.0, data.coords.w,
 | |
| 					data.networked or false, true)
 | |
| 			else
 | |
| 				spawnedped = CreatePed(0, data.model, data.coords.x, data.coords.y, data.coords.z, data.coords.w,
 | |
| 					data.networked or false, true)
 | |
| 			end
 | |
| 
 | |
| 			if data.freeze then
 | |
| 				FreezeEntityPosition(spawnedped, true)
 | |
| 			end
 | |
| 
 | |
| 			if data.invincible then
 | |
| 				SetEntityInvincible(spawnedped, true)
 | |
| 			end
 | |
| 
 | |
| 			if data.blockevents then
 | |
| 				SetBlockingOfNonTemporaryEvents(spawnedped, true)
 | |
| 			end
 | |
| 
 | |
| 			if data.animDict and data.anim then
 | |
| 				RequestAnimDict(data.animDict)
 | |
| 				while not HasAnimDictLoaded(data.animDict) do
 | |
| 					Wait(0)
 | |
| 				end
 | |
| 
 | |
| 				TaskPlayAnim(spawnedped, data.animDict, data.anim, 8.0, 0, -1, data.flag or 1, 0, false, false, false)
 | |
| 			end
 | |
| 
 | |
| 			if data.scenario then
 | |
| 				SetPedCanPlayAmbientAnims(spawnedped, true)
 | |
| 				TaskStartScenarioInPlace(spawnedped, data.scenario, 0, true)
 | |
| 			end
 | |
| 
 | |
| 			if data.pedrelations then
 | |
| 				if type(data.pedrelations.groupname) ~= 'string' then
 | |
| 					error(data.pedrelations.groupname ..
 | |
| 						' is not a string')
 | |
| 				end
 | |
| 
 | |
| 				local pedgrouphash = joaat(data.pedrelations.groupname)
 | |
| 
 | |
| 				if not DoesRelationshipGroupExist(pedgrouphash) then
 | |
| 					AddRelationshipGroup(data.pedrelations.groupname)
 | |
| 				end
 | |
| 
 | |
| 				SetPedRelationshipGroupHash(spawnedped, pedgrouphash)
 | |
| 				if data.pedrelations.toplayer then
 | |
| 					SetRelationshipBetweenGroups(data.pedrelations.toplayer, pedgrouphash, joaat('PLAYER'))
 | |
| 				end
 | |
| 
 | |
| 				if data.pedrelations.toowngroup then
 | |
| 					SetRelationshipBetweenGroups(data.pedrelations.toowngroup, pedgrouphash, pedgrouphash)
 | |
| 				end
 | |
| 			end
 | |
| 
 | |
| 			if data.weapon then
 | |
| 				if type(data.weapon.name) == 'string' then data.weapon.name = joaat(data.weapon.name) end
 | |
| 
 | |
| 				if IsWeaponValid(data.weapon.name) then
 | |
| 					SetCanPedEquipWeapon(spawnedped, data.weapon.name, true)
 | |
| 					GiveWeaponToPed(spawnedped, data.weapon.name, data.weapon.ammo, data.weapon.hidden or false, true)
 | |
| 					SetPedCurrentWeaponVisible(spawnedped, not data.weapon.hidden or false, true)
 | |
| 				end
 | |
| 			end
 | |
| 
 | |
| 			if data.target then
 | |
| 				if data.target.useModel then
 | |
| 					AddTargetModel(data.model, {
 | |
| 						options = data.target.options,
 | |
| 						distance = data.target.distance
 | |
| 					})
 | |
| 				else
 | |
| 					AddTargetEntity(spawnedped, {
 | |
| 						options = data.target.options,
 | |
| 						distance = data.target.distance
 | |
| 					})
 | |
| 				end
 | |
| 			end
 | |
| 
 | |
| 			data.currentpednumber = spawnedped
 | |
| 
 | |
| 			if data.action then
 | |
| 				data.action(data)
 | |
| 			end
 | |
| 		end
 | |
| 
 | |
| 		local nextnumber = #Config.Peds + 1
 | |
| 		if nextnumber <= 0 then nextnumber = 1 end
 | |
| 
 | |
| 		Config.Peds[nextnumber] = data
 | |
| 	end
 | |
| end
 | |
| 
 | |
| exports('SpawnPed', SpawnPed)
 | |
| 
 | |
| local function RemovePed(peds)
 | |
| 	if type(peds) == 'table' then
 | |
| 		for k, v in pairs(peds) do
 | |
| 			DeletePed(v)
 | |
| 			if Config.Peds[k] then Config.Peds[k].currentpednumber = 0 end
 | |
| 		end
 | |
| 	elseif type(peds) == 'number' then
 | |
| 		DeletePed(peds)
 | |
| 	end
 | |
| end
 | |
| 
 | |
| exports('RemoveSpawnedPed', RemovePed)
 | |
| 
 | |
| -- Misc. Exports
 | |
| 
 | |
| local function RemoveGlobalPed(labels) RemoveGlobalType(1, labels) end
 | |
| exports('RemoveGlobalPed', RemoveGlobalPed)
 | |
| 
 | |
| local function RemoveGlobalVehicle(labels) RemoveGlobalType(2, labels) end
 | |
| exports('RemoveGlobalVehicle', RemoveGlobalVehicle)
 | |
| 
 | |
| local function RemoveGlobalObject(labels) RemoveGlobalType(3, labels) end
 | |
| exports('RemoveGlobalObject', RemoveGlobalObject)
 | |
| 
 | |
| local function IsTargetActive() return targetActive end
 | |
| exports('IsTargetActive', IsTargetActive)
 | |
| 
 | |
| local function IsTargetSuccess() return success end
 | |
| exports('IsTargetSuccess', IsTargetSuccess)
 | |
| 
 | |
| local function GetGlobalTypeData(type, label) return Types[type][label] end
 | |
| exports('GetGlobalTypeData', GetGlobalTypeData)
 | |
| 
 | |
| local function GetZoneData(name) return Zones[name] end
 | |
| exports('GetZoneData', GetZoneData)
 | |
| 
 | |
| local function GetTargetBoneData(bone, label) return Bones.Options[bone][label] end
 | |
| exports('GetTargetBoneData', GetTargetBoneData)
 | |
| 
 | |
| local function GetTargetEntityData(entity, label) return Entities[entity][label] end
 | |
| exports('GetTargetEntityData', GetTargetEntityData)
 | |
| 
 | |
| local function GetTargetModelData(model, label) return Models[model][label] end
 | |
| exports('GetTargetModelData', GetTargetModelData)
 | |
| 
 | |
| local function GetGlobalPedData(label) return Types[1][label] end
 | |
| exports('GetGlobalPedData', GetGlobalPedData)
 | |
| 
 | |
| local function GetGlobalVehicleData(label) return Types[2][label] end
 | |
| exports('GetGlobalVehicleData', GetGlobalVehicleData)
 | |
| 
 | |
| local function GetGlobalObjectData(label) return Types[3][label] end
 | |
| exports('GetGlobalObjectData', GetGlobalObjectData)
 | |
| 
 | |
| local function GetGlobalPlayerData(label) return Players[label] end
 | |
| exports('GetGlobalPlayerData', GetGlobalPlayerData)
 | |
| 
 | |
| local function UpdateGlobalTypeData(type, label, data) Types[type][label] = data end
 | |
| exports('UpdateGlobalTypeData', UpdateGlobalTypeData)
 | |
| 
 | |
| local function UpdateZoneData(name, data)
 | |
| 	data.distance = data.distance or Config.MaxDistance
 | |
| 	Zones[name].targetoptions = data
 | |
| end
 | |
| exports('UpdateZoneData', UpdateZoneData)
 | |
| 
 | |
| local function UpdateTargetBoneData(bone, label, data) Bones.Options[bone][label] = data end
 | |
| exports('UpdateTargetBoneData', UpdateTargetBoneData)
 | |
| 
 | |
| local function UpdateTargetEntityData(entity, label, data) Entities[entity][label] = data end
 | |
| exports('UpdateTargetEntityData', UpdateTargetEntityData)
 | |
| 
 | |
| local function UpdateTargetModelData(model, label, data) Models[model][label] = data end
 | |
| exports('UpdateTargetModelData', UpdateTargetModelData)
 | |
| 
 | |
| local function UpdateGlobalPedData(label, data) Types[1][label] = data end
 | |
| exports('UpdateGlobalPedData', UpdateGlobalPedData)
 | |
| 
 | |
| local function UpdateGlobalVehicleData(label, data) Types[2][label] = data end
 | |
| exports('UpdateGlobalVehicleData', UpdateGlobalVehicleData)
 | |
| 
 | |
| local function UpdateGlobalObjectData(label, data) Types[3][label] = data end
 | |
| exports('UpdateGlobalObjectData', UpdateGlobalObjectData)
 | |
| 
 | |
| local function UpdateGlobalPlayerData(label, data) Players[label] = data end
 | |
| exports('UpdateGlobalPlayerData', UpdateGlobalPlayerData)
 | |
| 
 | |
| local function GetPeds() return Config.Peds end
 | |
| exports('GetPeds', GetPeds)
 | |
| 
 | |
| local function UpdatePedsData(index, data) Config.Peds[index] = data end
 | |
| exports('UpdatePedsData', UpdatePedsData)
 | |
| 
 | |
| local function AllowTargeting(bool)
 | |
| 	allowTarget = bool
 | |
| 
 | |
| 	if allowTarget then return end
 | |
| 
 | |
| 	DisableTarget(true)
 | |
| end
 | |
| exports('AllowTargeting', AllowTargeting)
 | |
| 
 | |
| -- NUI Callbacks
 | |
| 
 | |
| RegisterNUICallback('selectTarget', function(option, cb)
 | |
| 	option = tonumber(option) or option
 | |
| 	SetNuiFocus(false, false)
 | |
| 	SetNuiFocusKeepInput(false)
 | |
| 	Wait(100)
 | |
| 	targetActive, success, hasFocus = false, false, false
 | |
| 	if not next(sendData) then return end
 | |
| 	local data = sendData[option]
 | |
| 	if not data then return end
 | |
| 	table_wipe(sendData)
 | |
| 	CreateThread(function()
 | |
| 		Wait(0)
 | |
| 		if data.entity ~= nil then
 | |
| 			data.coords = GetEntityCoords(data.entity)
 | |
| 		end
 | |
| 		if data.action then
 | |
| 			data.action(data.entity)
 | |
| 		elseif data.event then
 | |
| 			if data.type == 'client' then
 | |
| 				TriggerEvent(data.event, data)
 | |
| 			elseif data.type == 'server' then
 | |
| 				TriggerServerEvent(data.event, data)
 | |
| 			elseif data.type == 'command' then
 | |
| 				ExecuteCommand(data.event)
 | |
| 			elseif data.type == 'qbcommand' then
 | |
| 				TriggerServerEvent('QBCore:CallCommand', data.event, data)
 | |
| 			else
 | |
| 				TriggerEvent(data.event, data)
 | |
| 			end
 | |
| 		else
 | |
| 			error('No trigger setup')
 | |
| 		end
 | |
| 	end)
 | |
| 	cb('ok')
 | |
| end)
 | |
| 
 | |
| RegisterNUICallback('closeTarget', function(_, cb)
 | |
| 	SetNuiFocus(false, false)
 | |
| 	SetNuiFocusKeepInput(false)
 | |
| 	Wait(100)
 | |
| 	targetActive, success, hasFocus = false, false, false
 | |
| 	cb('ok')
 | |
| end)
 | |
| 
 | |
| RegisterNUICallback('leftTarget', function(_, cb)
 | |
| 	if Config.Toggle then
 | |
| 		SetNuiFocus(false, false)
 | |
| 		SetNuiFocusKeepInput(false)
 | |
| 		Wait(100)
 | |
| 		table_wipe(sendData)
 | |
| 		success, hasFocus = false, false
 | |
| 	else
 | |
| 		DisableTarget(true)
 | |
| 	end
 | |
| 	cb('ok')
 | |
| end)
 | |
| 
 | |
| -- Startup thread
 | |
| 
 | |
| CreateThread(function()
 | |
| 	if Config.Toggle then
 | |
| 		RegisterCommand('playerTarget', function()
 | |
| 			if targetActive then
 | |
| 				DisableTarget(true)
 | |
| 			else
 | |
| 				CreateThread(EnableTarget)
 | |
| 			end
 | |
| 		end, false)
 | |
| 		RegisterKeyMapping('playerTarget', 'Toggle targeting', 'keyboard', Config.OpenKey)
 | |
| 		TriggerEvent('chat:removeSuggestion', '/playerTarget')
 | |
| 	else
 | |
| 		RegisterCommand('+playerTarget', function()
 | |
| 			CreateThread(EnableTarget)
 | |
| 		end, false)
 | |
| 		RegisterCommand('-playerTarget', DisableTarget, false)
 | |
| 		RegisterKeyMapping('+playerTarget', 'Enable targeting', 'keyboard', Config.OpenKey)
 | |
| 		TriggerEvent('chat:removeSuggestion', '/+playerTarget')
 | |
| 		TriggerEvent('chat:removeSuggestion', '/-playerTarget')
 | |
| 	end
 | |
| 
 | |
| 	if table.type(Config.CircleZones) ~= 'empty' then
 | |
| 		for _, v in pairs(Config.CircleZones) do
 | |
| 			AddCircleZone(v.name, v.coords, v.radius, {
 | |
| 				name = v.name,
 | |
| 				debugPoly = v.debugPoly,
 | |
| 				useZ = v.useZ,
 | |
| 			}, {
 | |
| 				options = v.options,
 | |
| 				distance = v.distance
 | |
| 			})
 | |
| 		end
 | |
| 	end
 | |
| 
 | |
| 	if table.type(Config.BoxZones) ~= 'empty' then
 | |
| 		for _, v in pairs(Config.BoxZones) do
 | |
| 			AddBoxZone(v.name, v.coords, v.length, v.width, {
 | |
| 				name = v.name,
 | |
| 				heading = v.heading,
 | |
| 				debugPoly = v.debugPoly,
 | |
| 				minZ = v.minZ,
 | |
| 				maxZ = v.maxZ
 | |
| 			}, {
 | |
| 				options = v.options,
 | |
| 				distance = v.distance
 | |
| 			})
 | |
| 		end
 | |
| 	end
 | |
| 
 | |
| 	if table.type(Config.PolyZones) ~= 'empty' then
 | |
| 		for _, v in pairs(Config.PolyZones) do
 | |
| 			AddPolyZone(v.name, v.points, {
 | |
| 				name = v.name,
 | |
| 				debugPoly = v.debugPoly,
 | |
| 				minZ = v.minZ,
 | |
| 				maxZ = v.maxZ
 | |
| 			}, {
 | |
| 				options = v.options,
 | |
| 				distance = v.distance
 | |
| 			})
 | |
| 		end
 | |
| 	end
 | |
| 
 | |
| 	if table.type(Config.TargetBones) ~= 'empty' then
 | |
| 		for _, v in pairs(Config.TargetBones) do
 | |
| 			AddTargetBone(v.bones, {
 | |
| 				options = v.options,
 | |
| 				distance = v.distance
 | |
| 			})
 | |
| 		end
 | |
| 	end
 | |
| 
 | |
| 	if table.type(Config.TargetModels) ~= 'empty' then
 | |
| 		for _, v in pairs(Config.TargetModels) do
 | |
| 			AddTargetModel(v.models, {
 | |
| 				options = v.options,
 | |
| 				distance = v.distance
 | |
| 			})
 | |
| 		end
 | |
| 	end
 | |
| 
 | |
| 	if table.type(Config.GlobalPedOptions) ~= 'empty' then
 | |
| 		AddGlobalPed(Config.GlobalPedOptions)
 | |
| 	end
 | |
| 
 | |
| 	if table.type(Config.GlobalVehicleOptions) ~= 'empty' then
 | |
| 		AddGlobalVehicle(Config.GlobalVehicleOptions)
 | |
| 	end
 | |
| 
 | |
| 	if table.type(Config.GlobalObjectOptions) ~= 'empty' then
 | |
| 		AddGlobalObject(Config.GlobalObjectOptions)
 | |
| 	end
 | |
| 
 | |
| 	if table.type(Config.GlobalPlayerOptions) ~= 'empty' then
 | |
| 		AddGlobalPlayer(Config.GlobalPlayerOptions)
 | |
| 	end
 | |
| end)
 | |
| 
 | |
| -- Events
 | |
| 
 | |
| -- This is to make sure the peds spawn on restart too instead of only when you load/log-in.
 | |
| AddEventHandler('onResourceStart', function(resource)
 | |
| 	if resource ~= currentResourceName then return end
 | |
| 	SpawnPeds()
 | |
| end)
 | |
| 
 | |
| -- This will delete the peds when the resource stops to make sure you don't have random peds walking
 | |
| AddEventHandler('onResourceStop', function(resource)
 | |
| 	if resource ~= currentResourceName then return end
 | |
| 	DeletePeds()
 | |
| end)
 | |
| 
 | |
| -- Debug Option
 | |
| 
 | |
| if Config.Debug then Load('debug') end
 | |
| 
 | |
| -- qtarget interoperability
 | |
| 
 | |
| local qtargetExports = {
 | |
| 	['raycast'] = RaycastCamera,
 | |
| 	['DisableNUI'] = DisableNUI,
 | |
| 	['LeaveTarget'] = LeftTarget,
 | |
| 	['DisableTarget'] = DisableTarget,
 | |
| 	['DrawOutlineEntity'] = DrawOutlineEntity,
 | |
| 	['CheckEntity'] = CheckEntity,
 | |
| 	['CheckBones'] = CheckBones,
 | |
| 	['AddCircleZone'] = AddCircleZone,
 | |
| 	['AddBoxZone'] = AddBoxZone,
 | |
| 	['AddPolyZone'] = AddPolyZone,
 | |
| 	['AddComboZone'] = AddComboZone,
 | |
| 	['AddEntityZone'] = AddEntityZone,
 | |
| 	['RemoveZone'] = RemoveZone,
 | |
| 	['AddTargetBone'] = AddTargetBone,
 | |
| 	['RemoveTargetBone'] = RemoveTargetBone,
 | |
| 	['AddTargetEntity'] = AddTargetEntity,
 | |
| 	['RemoveTargetEntity'] = RemoveTargetEntity,
 | |
| 	['AddTargetModel'] = AddTargetModel,
 | |
| 	['RemoveTargetModel'] = RemoveTargetModel,
 | |
| 	['Ped'] = AddGlobalPed,
 | |
| 	['Vehicle'] = AddGlobalVehicle,
 | |
| 	['Object'] = AddGlobalObject,
 | |
| 	['Player'] = AddGlobalPlayer,
 | |
| 	['RemovePed'] = RemoveGlobalPed,
 | |
| 	['RemoveVehicle'] = RemoveGlobalVehicle,
 | |
| 	['RemoveObject'] = RemoveGlobalObject,
 | |
| 	['RemovePlayer'] = RemoveGlobalPlayer,
 | |
| 	['IsTargetActive'] = IsTargetActive,
 | |
| 	['IsTargetSuccess'] = IsTargetSuccess,
 | |
| 	['GetType'] = GetGlobalTypeData,
 | |
| 	['GetZone'] = GetZoneData,
 | |
| 	['GetTargetBone'] = GetTargetBoneData,
 | |
| 	['GetTargetEntity'] = GetTargetEntityData,
 | |
| 	['GetTargetModel'] = GetTargetModelData,
 | |
| 	['GetPed'] = GetGlobalPedData,
 | |
| 	['GetVehicle'] = GetGlobalVehicleData,
 | |
| 	['GetObject'] = GetGlobalObjectData,
 | |
| 	['GetPlayer'] = GetGlobalPlayerData,
 | |
| 	['UpdateType'] = UpdateGlobalTypeData,
 | |
| 	['UpdateZoneOptions'] = UpdateZoneData,
 | |
| 	['UpdateTargetBone'] = UpdateTargetBoneData,
 | |
| 	['UpdateTargetEntity'] = UpdateTargetEntityData,
 | |
| 	['UpdateTargetModel'] = UpdateTargetModelData,
 | |
| 	['UpdatePed'] = UpdateGlobalPedData,
 | |
| 	['UpdateVehicle'] = UpdateGlobalVehicleData,
 | |
| 	['UpdateObject'] = UpdateGlobalObjectData,
 | |
| 	['UpdatePlayer'] = UpdateGlobalPlayerData,
 | |
| 	['AllowTargeting'] = AllowTargeting
 | |
| }
 | |
| 
 | |
| for exportName, func in pairs(qtargetExports) do
 | |
| 	AddEventHandler(('__cfx_export_qtarget_%s'):format(exportName), function(setCB)
 | |
| 		setCB(func)
 | |
| 	end)
 | |
| end
 | 
