801 lines
		
	
	
	
		
			26 KiB
		
	
	
	
		
			Lua
		
	
	
	
	
	
			
		
		
	
	
			801 lines
		
	
	
	
		
			26 KiB
		
	
	
	
		
			Lua
		
	
	
	
	
	
| 
 | |
| -- error when both menus are enabled
 | |
| if (Config.useContextMenu and Config.useNativeUI) then
 | |
| 	print("^1[ERROR] You can use only one menu or no menu at all. You cannot use both menus."
 | |
| 		.. "\nMake sure to set at least one to false in the config and to edit the fxmanifest accordingly!")
 | |
| end
 | |
| 
 | |
| local keymakers = {}
 | |
| 
 | |
| local lockNotif = nil
 | |
| local createNewKeyNotif = nil
 | |
| 
 | |
| local LockStatus = {
 | |
| 	Unlocked = 1,
 | |
| 	Locked = 2
 | |
| }
 | |
| 
 | |
| local CB = exports["kimi_callbacks"]
 | |
| 
 | |
| local menuPoolNativeUI
 | |
| local keymakerMenuNativeUI
 | |
| local keyInvMenuNativeUI
 | |
| if (Config.useNativeUI) then
 | |
| 	if (NativeUI == nil) then
 | |
| 		print("^1[ERROR] NativeUI was not properly initialized! Make sure to install NativeUI and start it before this resource!")
 | |
| 	end
 | |
| 
 | |
| 	menuPoolNativeUI = NativeUI.CreatePool()
 | |
| 	keymakerMenuNativeUI = NativeUI.CreateMenu(Config.Strings.keymakerTitle, Config.Strings.keymakerSub)
 | |
| 	keyInvMenuNativeUI = NativeUI.CreateMenu(Config.Strings.keyInvTitle, Config.Strings.keyInvSub)
 | |
| end
 | |
| 
 | |
| local isAtKeymaker = false
 | |
| local menuOpen = false
 | |
| 
 | |
| -- create client side peds
 | |
| Citizen.CreateThread(function()
 | |
| 	for i, keymaker in ipairs(Config.Keymakers) do
 | |
| 		RequestModel(keymaker.model) 
 | |
| 		while not HasModelLoaded(keymaker.model) do
 | |
| 			Citizen.Wait(0)
 | |
| 		end
 | |
| 		local ped = CreatePed(0, keymaker.model, keymaker.pos.x, keymaker.pos.y, keymaker.pos.z, keymaker.pos.w, false, true)
 | |
|         
 | |
| 		SetBlockingOfNonTemporaryEvents(ped, true)
 | |
| 		FreezeEntityPosition(ped, true)
 | |
| 		SetEntityInvincible(ped, true)
 | |
| 
 | |
| 		table.insert(keymakers, ped)
 | |
| 
 | |
| 		-- add blip
 | |
|         local blip = AddBlipForCoord(keymaker.pos.x, keymaker.pos.y, keymaker.pos.z)
 | |
| 
 | |
|         SetBlipSprite(blip, 134)
 | |
|         SetBlipColour(blip, 0)
 | |
|         
 | |
|         SetBlipScale(blip, 1.0)
 | |
|         SetBlipDisplay(blip, 2)
 | |
|         SetBlipAsShortRange(blip, true)
 | |
| 
 | |
|         BeginTextCommandSetBlipName('STRING')
 | |
|         AddTextComponentSubstringPlayerName(Config.Strings.keymaker)
 | |
|         EndTextCommandSetBlipName(blip)
 | |
| 	end
 | |
| end)
 | |
| 
 | |
| -- main loop
 | |
| Citizen.CreateThread(function()
 | |
| 	while (true) do
 | |
| 		Citizen.Wait(0)
 | |
| 
 | |
| 		if (Config.useNativeUI) then
 | |
| 			if (menuOpen) then
 | |
| 				menuPoolNativeUI:ProcessMenus()
 | |
| 			end
 | |
| 
 | |
| 			if (isAtKeymaker) then
 | |
| 				if (not menuOpen) then
 | |
| 					ShowHelpText(Config.Strings.helpText)
 | |
| 				end
 | |
| 
 | |
| 				if (IsControlJustPressed(0, 51)) then
 | |
| 					if (menuPoolNativeUI:IsAnyMenuOpen()) then
 | |
| 						menuPoolNativeUI:CloseAllMenus()
 | |
| 						menuOpen = false
 | |
| 					else
 | |
| 						GenerateKeymakerMenuNativeUI()
 | |
| 						keymakerMenuNativeUI:Visible(true)
 | |
| 						menuOpen = true
 | |
| 					end
 | |
| 				end
 | |
| 			end
 | |
| 
 | |
| 
 | |
| 			if (IsControlJustPressed(0, Config.keyMenuKey)) then
 | |
| 				if (menuPoolNativeUI:IsAnyMenuOpen()) then
 | |
| 					menuPoolNativeUI:CloseAllMenus()
 | |
| 					menuOpen = false
 | |
| 				else
 | |
| 					GenerateKeyInventoryNativeUI()
 | |
| 					keyInvMenuNativeUI:Visible(true)
 | |
| 					menuOpen = true
 | |
| 				end
 | |
| 			end
 | |
| 		end
 | |
| 
 | |
| 		-- lock vehicle with key
 | |
| 		if (Config.lockKey and IsControlJustPressed(0, Config.lockKey)) then
 | |
| 			local vehicle = GetClosestVehicle(GetEntityCoords(PlayerPedId()), 10.0)
 | |
| 			if (DoesEntityExist(vehicle) and IsVehicleOrKeyOwner(vehicle)) then
 | |
| 				ToggleLock(vehicle, GetVehicleDoorLockStatus(vehicle) ~= LockStatus.Locked)
 | |
| 			end
 | |
| 		end
 | |
| 	end
 | |
| end)
 | |
| 
 | |
| 
 | |
| 
 | |
| -- ContextMenu
 | |
| if (Config.useContextMenu) then
 | |
| 	local menuPool = MenuPool()
 | |
| 	menuPool.OnOpenMenu = function(screenPosition, hitSomething, worldPosition, hitEntity, normalDirection)
 | |
| 		local playerPos = GetEntityCoords(PlayerPedId())
 | |
| 		if (Vdist(worldPosition.x, worldPosition.y, worldPosition.z, playerPos.x, playerPos.y, playerPos.z) < Config.maxDistance) then
 | |
| 			CreateMenu(screenPosition, hitEntity)
 | |
| 		end
 | |
| 	end
 | |
| 
 | |
| 	function CreateMenu(screenPosition, hitEntity)
 | |
| 		menuPool:Reset()
 | |
| 
 | |
| 		if (hitEntity) then
 | |
| 			if (hitEntity == PlayerPedId()) then
 | |
| 				local vehicleData = CB:Trigger("VKC:getPlayerVehicleData")
 | |
| 				local ownedKeys = GetPlayerKeys()
 | |
| 				
 | |
| 				menuPool:Reset()
 | |
| 				
 | |
| 				local playerMenu = menuPool:AddMenu()
 | |
| 
 | |
| 				local ownVehMenu, ownVehMenuItem = menuPool:AddSubmenu(playerMenu, Config.Strings.CM.masterKeysTitle)
 | |
| 				for i, vehicle in ipairs(vehicleData) do
 | |
| 					local plate = vehicle[1]
 | |
| 					local model = GetLabelText(GetDisplayNameFromVehicleModel(vehicle[2]))
 | |
| 					if (model == "NULL") then
 | |
| 						model = GetDisplayNameFromVehicleModel(vehicle[2])
 | |
| 					end
 | |
| 
 | |
| 					local item = ownVehMenu:AddItem(model .. " " .. plate)
 | |
| 				end
 | |
| 				
 | |
| 				local ownKeyMenu, ownKeyMenuItem = menuPool:AddSubmenu(playerMenu, Config.Strings.CM.keysTitle)
 | |
| 				for i, key in ipairs(ownedKeys) do
 | |
| 					local model = GetLabelText(GetDisplayNameFromVehicleModel(key.model))
 | |
| 					if (model == "NULL") then
 | |
| 						model = GetDisplayNameFromVehicleModel(key.model)
 | |
| 					end
 | |
| 
 | |
| 					local item = ownKeyMenu:AddItem(model .. " " .. key.plate)
 | |
| 					item.rightText = Text("x" .. key.count)
 | |
| 				end
 | |
| 
 | |
| 				playerMenu:SetPosition(screenPosition)
 | |
| 				playerMenu:Visible(true)
 | |
| 			elseif (IsEntityAKeymaker(hitEntity)) then
 | |
| 				local vehicleData = GetPlayerVehicleData()
 | |
| 				local ownedKeys = GetPlayerKeys()
 | |
| 				
 | |
| 				menuPool:Reset()
 | |
| 				
 | |
| 				local keymakerMenu = menuPool:AddMenu()
 | |
| 				
 | |
| 				local createKeyMenu, createKeyMenuItem = menuPool:AddSubmenu(keymakerMenu, Config.Strings.CM.createKeyTitle)
 | |
| 				for i, vehicle in ipairs(vehicleData) do
 | |
| 					local plate = vehicle[1]
 | |
| 					local model = GetLabelText(GetDisplayNameFromVehicleModel(vehicle[2]))
 | |
| 					if (model == "NULL") then
 | |
| 						model = GetDisplayNameFromVehicleModel(vehicle[2])
 | |
| 					end
 | |
| 					local keyCount = GetKeyCount(plate, ownedKeys)
 | |
| 
 | |
| 					local keyItem = createKeyMenu:AddItem(model .. " " .. plate)
 | |
| 					keyItem.rightText = Text("x" .. tostring(keyCount))
 | |
| 					keyItem.OnClick = function()
 | |
| 						local result = CB:Trigger("VKC:createNewKey", plate, 1)
 | |
| 						if (type(result) == "boolean" and result == true) then
 | |
| 							Notification(string.format(Config.Strings.createSuccess, model))
 | |
| 
 | |
| 							local oldCount = keyItem.rightText.title:gsub("x", "")
 | |
| 							keyItem.rightText.title = "x" .. tostring(tonumber(oldCount) + 1)
 | |
| 						elseif (type(result) == "string" and result == "noMoney") then
 | |
| 							Notification(string.format(Config.Strings.createNoMoney, model))
 | |
| 						else
 | |
| 							Notification(string.format(Config.Strings.createFailed, model))
 | |
| 						end
 | |
| 					end
 | |
| 				end
 | |
| 				
 | |
| 				local invalidateKeyMenu, invalidateKeyMenuItem = menuPool:AddSubmenu(keymakerMenu, Config.Strings.CM.invalKeyTitle)
 | |
| 				for i, vehicle in ipairs(vehicleData) do
 | |
| 					local plate = vehicle[1]
 | |
| 					local model = GetLabelText(GetDisplayNameFromVehicleModel(vehicle[2]))
 | |
| 					if (model == "NULL") then
 | |
| 						model = GetDisplayNameFromVehicleModel(vehicle[2])
 | |
| 					end
 | |
| 
 | |
| 					local item = invalidateKeyMenu:AddItem(model .. " " .. plate)
 | |
| 					item.closeMenuOnClick = true
 | |
| 					item.OnClick = function()
 | |
| 						local result = CB:Trigger("VKC:removeAllKeys", plate)
 | |
| 						if (type(result) == "boolean" and result == true) then
 | |
| 							Notification(string.format(Config.Strings.deleteKeys, model))
 | |
| 						elseif (type(result) == "string" and result == "noMoney") then
 | |
| 							Notification(string.format(Config.Strings.removeNoMoney, vehName))
 | |
| 						else
 | |
| 							Notification(string.format(Config.Strings.removeFailed, vehName))
 | |
| 						end
 | |
| 					end
 | |
| 				end
 | |
| 
 | |
| 				keymakerMenu:SetPosition(screenPosition)
 | |
| 				keymakerMenu:Visible(true)
 | |
| 			elseif (IsEntityAPed(hitEntity) and IsPedAPlayer(hitEntity)) then
 | |
| 				local ownedKeys = GetPlayerKeys()
 | |
| 				
 | |
| 				menuPool:Reset()
 | |
| 				
 | |
| 				local interactMenu = menuPool:AddMenu()
 | |
| 				
 | |
| 				local giveKeyMenu, giveKeyMenuItem = menuPool:AddSubmenu(interactMenu, Config.Strings.CM.giveKey)
 | |
| 				for i, key in ipairs(ownedKeys) do
 | |
| 					local model = GetLabelText(GetDisplayNameFromVehicleModel(key.model))
 | |
| 					if (model == "NULL") then
 | |
| 						model = GetDisplayNameFromVehicleModel(key.model)
 | |
| 					end
 | |
| 
 | |
| 					local keyItem = giveKeyMenu:AddItem(model .. " " .. key.plate)
 | |
| 					keyItem.rightText = Text("x" .. key.count)
 | |
| 					keyItem.closeMenuOnClick = true
 | |
| 					keyItem.OnClick = function()
 | |
| 						local players = GetActivePlayers()
 | |
| 						for i, player in ipairs(players) do
 | |
| 							if (GetPlayerPed(player) == hitEntity) then
 | |
| 								local success = CB:Trigger("VKC:giveKeyToPlayer", key.plate, GetPlayerServerId(player))
 | |
| 								if (success) then
 | |
| 									Notification(string.format(Config.Strings.giveSuccess, model))
 | |
| 								else
 | |
| 									Notification(string.format(Config.Strings.giveFailed, model))
 | |
| 								end
 | |
| 
 | |
| 								break
 | |
| 							end
 | |
| 						end
 | |
| 					end
 | |
| 				end
 | |
| 
 | |
| 				interactMenu:SetPosition(screenPosition)
 | |
| 				interactMenu:Visible(true)
 | |
| 			end
 | |
| 		end
 | |
| 	end
 | |
| 
 | |
| 	function IsEntityAKeymaker(entity)
 | |
| 		for i, keymaker in ipairs(keymakers) do
 | |
| 			if (entity == keymaker) then
 | |
| 				return true
 | |
| 			end
 | |
| 		end
 | |
| 
 | |
| 		return false
 | |
| 	end
 | |
| end
 | |
| 
 | |
| 
 | |
| 
 | |
| -- NativeUI
 | |
| function GenerateKeymakerMenuNativeUI()
 | |
| 	keymakerMenuNativeUI:Clear()
 | |
| 	
 | |
| 	local vehicleData = GetPlayerVehicleData()
 | |
| 	local ownedKeys = GetPlayerKeys()
 | |
| 	
 | |
| 	keymakerMenuNativeUI = NativeUI.CreateMenu(Config.Strings.NUI.keymakerMenuTitle, Config.Strings.NUI.keymakerMenuSub)
 | |
| 	menuPoolNativeUI:Add(keymakerMenuNativeUI)
 | |
| 	
 | |
| 	local submenuCreateKey = menuPoolNativeUI:AddSubMenu(keymakerMenuNativeUI, Config.Strings.NUI.createKeyTitle, Config.Strings.NUI.createKeyDesc)
 | |
| 	submenuCreateKey.ParentItem:RightLabel(">")
 | |
| 	submenuCreateKey.Subtitle.Text._Text = "~b~" .. Config.Strings.NUI.createKeyTitle
 | |
| 	for i, vehicle in ipairs(vehicleData) do
 | |
| 		local plate = vehicle[1]
 | |
| 		local model = GetLabelText(GetDisplayNameFromVehicleModel(vehicle[2]))
 | |
| 		if (model == "NULL") then
 | |
| 			model = GetDisplayNameFromVehicleModel(vehicle[2])
 | |
| 		end
 | |
| 		local keyCount = GetKeyCount(plate, ownedKeys)
 | |
| 
 | |
| 		local vehItem = NativeUI.CreateItem(model .. " " .. plate, string.format(Config.Strings.NUI.createVehicleKey, model, plate))
 | |
| 		vehItem:RightLabel("x" .. tostring(keyCount))
 | |
| 
 | |
| 		submenuCreateKey:AddItem(vehItem)
 | |
| 	end
 | |
| 	submenuCreateKey.OnItemSelect = function(menu, item, index)
 | |
| 		Citizen.CreateThread(function()
 | |
| 			local model = GetLabelText(GetDisplayNameFromVehicleModel(vehicleData[index][2]))
 | |
| 			if (model == "NULL") then
 | |
| 				model = GetDisplayNameFromVehicleModel(vehicleData[index][2])
 | |
| 			end
 | |
| 
 | |
| 			local result = CB:Trigger("VKC:createNewKey", vehicleData[index][1], 1)
 | |
| 			if (type(result) == "boolean" and result == true) then
 | |
| 				Notification(string.format(Config.Strings.createSuccess, model))
 | |
| 
 | |
| 				if (submenuCreateKey:Visible()) then
 | |
| 					local oldCount = item.Label.Text._Text:gsub("x", "")
 | |
| 					item:RightLabel("x" .. tostring(tonumber(oldCount) + 1))
 | |
| 				end
 | |
| 			elseif (type(result) == "string" and result == "noMoney") then
 | |
| 				Notification(string.format(Config.Strings.createNoMoney, model))
 | |
| 			else
 | |
| 				Notification(string.format(Config.Strings.createFailed, model))
 | |
| 			end
 | |
| 		end)
 | |
| 	end
 | |
| 
 | |
| 	local submenuInvalidateKey = menuPoolNativeUI:AddSubMenu(keymakerMenuNativeUI, Config.Strings.NUI.invalKeyTitle, Config.Strings.NUI.invalKeyDesc)
 | |
| 	submenuInvalidateKey.ParentItem:RightLabel(">")
 | |
| 	submenuInvalidateKey.Subtitle.Text._Text = "~b~" .. Config.Strings.NUI.invalKeyTitle
 | |
| 	for i, vehicle in ipairs(vehicleData) do
 | |
| 		local plate = vehicle[1]
 | |
| 		local model = GetLabelText(GetDisplayNameFromVehicleModel(vehicle[2]))
 | |
| 		if (model == "NULL") then
 | |
| 			model = GetDisplayNameFromVehicleModel(vehicle[2])
 | |
| 		end
 | |
| 
 | |
| 		local keyItem = NativeUI.CreateItem(model .. " " .. plate, string.format(Config.Strings.NUI.invalVehicleKey, model, plate))
 | |
| 		submenuInvalidateKey:AddItem(keyItem)
 | |
| 	end
 | |
| 	submenuInvalidateKey.OnItemSelect = function(menu, item, index)
 | |
| 		Citizen.CreateThread(function()
 | |
| 			local result = CB:Trigger("VKC:removeAllKeys", vehicleData[index][1])
 | |
| 			
 | |
| 			if (type(result) == "boolean" and result == true) then
 | |
| 				local model = GetLabelText(GetDisplayNameFromVehicleModel(vehicleData[index][2]))
 | |
| 				if (model == "NULL") then
 | |
| 					model = GetDisplayNameFromVehicleModel(vehicleData[index][2])
 | |
| 				end
 | |
| 				Notification(string.format(Config.Strings.deleteKeys, model))
 | |
| 			elseif (type(result) == "string" and result == "noMoney") then
 | |
| 				Notification(string.format(Config.Strings.removeNoMoney, vehName))
 | |
| 			else
 | |
| 				Notification(string.format(Config.Strings.removeFailed, vehName))
 | |
| 			end
 | |
| 		end)
 | |
| 	end
 | |
| 	
 | |
| 	keymakerMenuNativeUI.OnMenuClosed = function(menu)
 | |
| 		menuOpen = false
 | |
| 	end
 | |
| 
 | |
| 	menuPoolNativeUI:ControlDisablingEnabled(false)
 | |
| 	menuPoolNativeUI:MouseControlsEnabled(false)
 | |
| 
 | |
| 	menuPoolNativeUI:RefreshIndex()
 | |
| end
 | |
| 
 | |
| function GenerateKeyInventoryNativeUI()
 | |
| 	keyInvMenuNativeUI:Clear()
 | |
| 	
 | |
| 	local vehicleData = GetPlayerVehicleData()
 | |
| 	local ownedKeys = GetPlayerKeys()
 | |
| 	
 | |
| 	keyInvMenuNativeUI = NativeUI.CreateMenu(Config.Strings.NUI.keyInventoryTitle, Config.Strings.NUI.keyInventorySub)
 | |
| 	menuPoolNativeUI:Add(keyInvMenuNativeUI)
 | |
| 	
 | |
| 	local submenuShowMasterKeys = menuPoolNativeUI:AddSubMenu(keyInvMenuNativeUI, Config.Strings.NUI.masterKeysTitle, Config.Strings.NUI.masterKeysDesc)
 | |
| 	submenuShowMasterKeys.ParentItem:RightLabel(">")
 | |
| 	submenuShowMasterKeys.Subtitle.Text._Text = "~b~" .. Config.Strings.NUI.masterKeysTitle
 | |
| 	for i, vehicle in ipairs(vehicleData) do
 | |
| 		local plate = vehicle[1]
 | |
| 		local model = GetLabelText(GetDisplayNameFromVehicleModel(vehicle[2]))
 | |
| 		if (model == "NULL") then
 | |
| 			model = GetDisplayNameFromVehicleModel(vehicle[2])
 | |
| 		end
 | |
| 		--local keyCount = GetKeyCount(plate, ownedKeys)
 | |
| 
 | |
| 		local vehItem = NativeUI.CreateItem(model .. " " .. plate, "")
 | |
| 		--vehItem:RightLabel("x" .. tostring(keyCount))
 | |
| 		submenuShowMasterKeys:AddItem(vehItem)
 | |
| 	end
 | |
| 	
 | |
| 	local submenuShowKeys = menuPoolNativeUI:AddSubMenu(keyInvMenuNativeUI, Config.Strings.NUI.keysTitle, Config.Strings.NUI.keysDesc)
 | |
| 	submenuShowKeys.ParentItem:RightLabel(">")
 | |
| 	submenuShowKeys.Subtitle.Text._Text = "~b~" .. Config.Strings.NUI.keysTitle
 | |
| 	for i, key in ipairs(ownedKeys) do
 | |
| 		local model = GetLabelText(GetDisplayNameFromVehicleModel(key.model))
 | |
| 		if (model == "NULL") then
 | |
| 			model = GetDisplayNameFromVehicleModel(key.model)
 | |
| 		end
 | |
| 		
 | |
| 		local submenuKey = menuPoolNativeUI:AddSubMenu(submenuShowKeys, model .. " " .. key.plate, "")
 | |
| 		submenuKey.ParentItem:RightLabel("x" .. tostring(key.count) .. " >")
 | |
| 		submenuKey.Subtitle.Text._Text = "~b~" .. model .. " " .. key.plate
 | |
| 
 | |
| 		local giveItem = NativeUI.CreateItem(Config.Strings.NUI.giveKeyTitle, Config.Strings.NUI.giveKeyDesc)
 | |
| 		submenuKey:AddItem(giveItem)
 | |
| 
 | |
| 		local removeItem = NativeUI.CreateItem(Config.Strings.NUI.removeKeyTitle, Config.Strings.NUI.removeKeyDesc)
 | |
| 		submenuKey:AddItem(removeItem)
 | |
| 
 | |
| 		submenuKey.OnItemSelect = function(menu, item, index)
 | |
| 			if (item == giveItem) then
 | |
| 				Citizen.CreateThread(function()
 | |
| 					local player = GetClosestPlayer(2.0)
 | |
| 					if (player) then
 | |
| 						local success = CB:Trigger("VKC:giveKeyToPlayer", key.plate, GetPlayerServerId(player))
 | |
| 						if (success) then
 | |
| 							Notification(string.format(Config.Strings.giveSuccess, key.plate))
 | |
| 						else
 | |
| 							Notification(string.format(Config.Strings.giveFailed, key.plate))
 | |
| 						end
 | |
| 					else
 | |
| 						Notification(string.format(Config.Strings.giveFailed, key.plate))
 | |
| 					end
 | |
| 				end)
 | |
| 			elseif (item == removeItem) then
 | |
| 				Citizen.CreateThread(function()
 | |
| 					local success = CB:Trigger("VKC:removeKey", key.plate, 1)
 | |
| 					if (success) then
 | |
| 						Notification(string.format(Config.Strings.removeSuccess, key.plate))
 | |
| 						
 | |
| 						if (submenuShowKeys:Visible() or submenuKey:Visible()) then
 | |
| 							local oldCount = submenuKey.ParentItem.Label.Text._Text:gsub("x", "")
 | |
| 							oldCount = oldCount:gsub(" >", "")
 | |
| 							submenuKey.ParentItem:RightLabel("x" .. tostring(tonumber(oldCount) + 1) .. " >")
 | |
| 						end
 | |
| 					else
 | |
| 						Notification(string.format(Config.Strings.removeFailed, key.plate))
 | |
| 					end
 | |
| 				end)
 | |
| 			end
 | |
| 		end
 | |
| 	end
 | |
| 
 | |
| 	keyInvMenuNativeUI.OnMenuClosed = function(menu)
 | |
| 		menuOpen = false
 | |
| 	end
 | |
| 
 | |
| 	menuPoolNativeUI:ControlDisablingEnabled(false)
 | |
| 	menuPoolNativeUI:MouseControlsEnabled(false)
 | |
| 
 | |
| 	menuPoolNativeUI:RefreshIndex()
 | |
| end
 | |
| 
 | |
| if (Config.useNativeUI) then
 | |
| 	Citizen.CreateThread(function()
 | |
| 		while (true) do
 | |
| 			Citizen.Wait(250)
 | |
| 			
 | |
| 			isAtKeymaker = false
 | |
| 
 | |
| 			local pos = GetEntityCoords(PlayerPedId())
 | |
| 			for i, keymaker in ipairs(Config.Keymakers) do
 | |
| 				if (Vdist(pos.x, pos.y, pos.z, keymaker.pos.x, keymaker.pos.y, keymaker.pos.z) < 2.0) then
 | |
| 					isAtKeymaker = true
 | |
| 					break
 | |
| 				end
 | |
| 			end
 | |
| 		end
 | |
| 	end)
 | |
| 	
 | |
| 	if (Config.keyMenuCommand) then
 | |
| 		RegisterCommand(Config.keyMenuCommand, function(source, args, raw)
 | |
| 			if (menuPoolNativeUI:IsAnyMenuOpen()) then
 | |
| 				menuPoolNativeUI:CloseAllMenus()
 | |
| 			end
 | |
| 
 | |
| 			GenerateKeyInventoryNativeUI()
 | |
| 			keyInvMenuNativeUI:Visible(true)
 | |
| 			menuOpen = true
 | |
| 		end, false)
 | |
| 	end
 | |
| end
 | |
| 
 | |
| 
 | |
| 
 | |
| -- lock vehicle
 | |
| if (Config.lockCommand) then
 | |
| 	RegisterCommand(Config.lockCommand, function(source, args, raw)
 | |
| 		local vehicle = GetClosestVehicle(GetEntityCoords(PlayerPedId()), 10.0)
 | |
| 		if (DoesEntityExist(vehicle) and IsVehicleOrKeyOwner(vehicle)) then
 | |
| 			ToggleLock(vehicle, GetVehicleDoorLockStatus(vehicle) ~= LockStatus.Locked)
 | |
| 		end
 | |
| 	end, false)
 | |
| end
 | |
| 
 | |
| function ToggleLock(vehicle, lock)
 | |
| 	local lockStatus = GetVehicleDoorLockStatus(vehicle)
 | |
| 
 | |
| 	if (NetworkHasControlOfEntity(vehicle)) then
 | |
| 		ToggleLockOnVehicle(vehicle, lock)
 | |
| 	else
 | |
| 		TriggerServerEvent("VKC:toggleLockNet", NetworkGetNetworkIdFromEntity(vehicle), lock)
 | |
| 	end
 | |
| 
 | |
| 	-- play sound
 | |
| 	TriggerServerEvent("VKC:playDoorLockSoundNet", NetworkGetNetworkIdFromEntity(vehicle), lock)
 | |
| 
 | |
| 	-- play remote animation
 | |
| 	if (not IsPedInAnyVehicle(PlayerPedId(), false)) then
 | |
| 		PlayRemoteAnimation()
 | |
| 	end
 | |
| 
 | |
| 	-- show notification
 | |
| 	--[[
 | |
| 		if (lockNotif) then
 | |
| 		RemoveNotification(lockNotif)
 | |
| 	end
 | |
| 	lockNotif = Notification(lockStatus == LockStatus.Locked and Config.Strings.unlockNotif or Config.Strings.lockNotif)
 | |
| 	]]
 | |
| end
 | |
| 
 | |
| function ToggleLockOnVehicle(vehicle, lock)
 | |
| 	if (lock) then
 | |
| 		SetVehicleDoorsShut(vehicle, false)
 | |
| 		SetVehicleDoorsLocked(vehicle, LockStatus.Locked)
 | |
| 		exports['okokNotify']:Alert("Fahrzeug", "Du hast dein Fahrzeug Abgeschlossen", 3000, 'error')
 | |
| 
 | |
| 
 | |
| 		SetVehicleLights(vehicle, 2)
 | |
| 		Citizen.Wait(150)
 | |
| 		SetVehicleLights(vehicle, 0)
 | |
| 		Citizen.Wait(150)
 | |
| 		SetVehicleLights(vehicle, 2)
 | |
| 		Citizen.Wait(150)
 | |
| 		SetVehicleLights(vehicle, 0)
 | |
| 	else
 | |
| 		SetVehicleDoorsLocked(vehicle, LockStatus.Unlocked)
 | |
| 		exports['okokNotify']:Alert("Fahrzeug", "Du hast dein Fahrzeug Aufgeschlossen", 3000, 'success')
 | |
| 
 | |
| 		SetVehicleLights(vehicle, 2)
 | |
| 		Citizen.Wait(150)
 | |
| 		SetVehicleLights(vehicle, 0)
 | |
| 		Citizen.Wait(150)
 | |
| 		SetVehicleLights(vehicle, 2)
 | |
| 		Citizen.Wait(150)
 | |
| 		SetVehicleLights(vehicle, 0)
 | |
| 		Citizen.Wait(150)
 | |
| 		SetVehicleLights(vehicle, 2)
 | |
| 		Citizen.Wait(150)
 | |
| 		SetVehicleLights(vehicle, 0)
 | |
| 		Citizen.Wait(150)
 | |
| 		SetVehicleLights(vehicle, 2)
 | |
| 		Citizen.Wait(150)
 | |
| 		SetVehicleLights(vehicle, 0)
 | |
| 		Citizen.Wait(150)
 | |
| 		SetVehicleLights(vehicle, 2)
 | |
| 		Citizen.Wait(150)
 | |
| 		SetVehicleLights(vehicle, 0)
 | |
| 	end
 | |
| end
 | |
| 
 | |
| function PlayDoorLockSound(vehicle, lock)
 | |
| 	if (lock) then
 | |
| 		PlayVehicleDoorCloseSound(vehicle, 0)
 | |
| 	else
 | |
| 		PlayVehicleDoorOpenSound(vehicle, 0)
 | |
| 	end
 | |
| end
 | |
| 
 | |
| if (Config.lockCommand or Config.lockKey) then
 | |
| 	RegisterNetEvent("VKC:toggleLockOnPlayer")
 | |
| 	AddEventHandler("VKC:toggleLockOnPlayer", function(vehicleNetId, unlocked)
 | |
| 		local vehicle = NetworkGetEntityFromNetworkId(vehicleNetId)
 | |
| 		if (DoesEntityExist(vehicle) and NetworkHasControlOfEntity(vehicle)) then
 | |
| 			local lockStatus = GetVehicleDoorLockStatus(vehicle)
 | |
| 			ToggleLockOnVehicle(vehicle, unlocked)
 | |
| 		end
 | |
| 	end)
 | |
| 
 | |
| 	RegisterNetEvent("VKC:playDoorLockSound")
 | |
| 	AddEventHandler("VKC:playDoorLockSound", function(vehicleNetId, lock)
 | |
| 		local vehicle = NetworkGetEntityFromNetworkId(vehicleNetId)
 | |
| 		if (DoesEntityExist(vehicle)) then
 | |
| 			PlayDoorLockSound(vehicle, lock)
 | |
| 		end
 | |
| 	end)
 | |
| end
 | |
| 
 | |
| 
 | |
| 
 | |
| RegisterNetEvent("VKC:giveKeyNotif")
 | |
| AddEventHandler("VKC:giveKeyNotif", function(plate)
 | |
| 	Notification(string.format(Config.Strings.giveSuccessPly, plate))
 | |
| end)
 | |
| 
 | |
| 
 | |
| 
 | |
| function IsVehicleOwner(vehicle)
 | |
| 	if (not DoesEntityExist(vehicle)) then
 | |
| 		print("^1[ERROR] Parameter \"vehicle\" was nil or vehicle did not exist while triggering export \"IsVehicleOwner\"!")
 | |
| 		return
 | |
| 	end
 | |
| 
 | |
| 	return CB:Trigger("VKC:isVehicleOwner", GetVehicleNumberPlateText(vehicle))
 | |
| end
 | |
| 
 | |
| function IsKeyOwner(vehicle)
 | |
| 	if (not DoesEntityExist(vehicle)) then
 | |
| 		print("^1[ERROR] Parameter \"vehicle\" was nil or vehicle did not exist while triggering export \"IsKeyOwner\"!")
 | |
| 		return
 | |
| 	end
 | |
| 
 | |
| 	return CB:Trigger("VKC:isKeyOwner", GetVehicleNumberPlateText(vehicle), GetEntityModel(vehicle))
 | |
| end
 | |
| 
 | |
| function IsVehicleOrKeyOwner(vehicle)
 | |
| 	if (not DoesEntityExist(vehicle)) then
 | |
| 		print("^1[ERROR] Parameter \"vehicle\" was nil or vehicle did not exist while triggering export \"IsVehicleOrKeyOwner\"!")
 | |
| 		return
 | |
| 	end
 | |
| 
 | |
| 	return CB:Trigger("VKC:isVehicleOrKeyOwner", GetVehicleNumberPlateText(vehicle), GetEntityModel(vehicle))
 | |
| end
 | |
| 
 | |
| function GetPlayerKeys()
 | |
| 	return CB:Trigger("VKC:getPlayerKeys")
 | |
| end
 | |
| 
 | |
| function GetPlayerVehicleData()
 | |
| 	return CB:Trigger("VKC:getPlayerVehicleData")
 | |
| end
 | |
| 
 | |
| 
 | |
| 
 | |
| -- play lock animation
 | |
| function PlayRemoteAnimation()
 | |
|     Citizen.CreateThread(function()
 | |
|         RequestModel(keyPropHash)
 | |
|         RequestAnimDict("anim@mp_player_intmenu@key_fob@")
 | |
|         while (not HasModelLoaded(keyPropHash) and not HasAnimDictLoaded("anim@mp_player_intmenu@key_fob@")) do
 | |
|             Citizen.Wait(0)
 | |
|         end
 | |
|         
 | |
|         local playerPed = PlayerPedId()
 | |
|         local playerPos = GetEntityCoords(playerPed)
 | |
| 
 | |
|         local keyObj = CreateObjectNoOffset(keyPropHash, playerPos.x, playerPos.y, playerPos.z, true, true, false)
 | |
|         SetModelAsNoLongerNeeded(keyPropHash)
 | |
| 
 | |
|         local boneIndex = GetEntityBoneIndexByName(playerPed, "IK_R_Hand")
 | |
|         local offset = vector3(0.08, 0.025, -0.01)
 | |
|         local rotOffset = vector3(0, 70, 140)
 | |
|         AttachEntityToEntity(keyObj, playerPed, boneIndex, offset.x, offset.y, offset.z, rotOffset.x, rotOffset.y, rotOffset.z, false, false, true, false, 2, true)
 | |
| 
 | |
|         TaskPlayAnim(playerPed, "anim@mp_player_intmenu@key_fob@", "fob_click_fp", 8.0, 8.0, -1, 48, 1, false, false, false)
 | |
|         RemoveAnimDict("anim@mp_player_intmenu@key_fob@")
 | |
| 
 | |
|         Citizen.Wait(1500)
 | |
| 
 | |
|         DeleteEntity(keyObj)
 | |
|     end)
 | |
| end
 | |
| 
 | |
| -- show text in upper left corner
 | |
| function ShowHelpText(text)
 | |
| 	BeginTextCommandDisplayHelp('STRING')
 | |
| 	AddTextComponentSubstringPlayerName(text)
 | |
| 	EndTextCommandDisplayHelp(0, false, true, -1)
 | |
| end
 | |
| 
 | |
| -- displays a notification and returns its handle
 | |
| function Notification(text)
 | |
|     SetNotificationTextEntry('STRING')
 | |
|     AddTextComponentSubstringPlayerName(text)
 | |
|     return DrawNotification(false, true)
 | |
| end
 | |
| 
 | |
| -- get key count
 | |
| function GetKeyCount(plate, keyArray)
 | |
| 	for i, key in ipairs(keyArray) do
 | |
| 		if (plate == key.plate) then
 | |
| 			return key.count
 | |
| 		end
 | |
| 	end
 | |
| 
 | |
| 	return 0
 | |
| end
 | |
| 
 | |
| -- get all players
 | |
| function GetAllPlayers()
 | |
|     local players = {}
 | |
| 
 | |
| 	for k, v in ipairs(GetActivePlayers()) do
 | |
|         table.insert(players, v)
 | |
| 	end
 | |
| 
 | |
|     return players
 | |
| end
 | |
| 
 | |
| -- get the closest player
 | |
| function GetClosestPlayer(maxRange)
 | |
|     local playerPed     = PlayerPedId()
 | |
|     local players       = GetAllPlayers()
 | |
| 
 | |
|     local playerCoords  = GetEntityCoords(playerPed)
 | |
| 
 | |
|     local closestDistance   = maxRange
 | |
|     local closestPlayer     = nil
 | |
| 
 | |
|     for i=1, #players, 1 do
 | |
|         local coords    = GetEntityCoords(GetPlayerPed(players[i]))
 | |
|         local dist      = Vdist(playerCoords.x, playerCoords.y, playerCoords.z, coords.x, coords.y, coords.z)
 | |
|         if (dist < closestDistance and players[i] ~= PlayerId()) then
 | |
|             closestDistance = dist
 | |
|             closestPlayer   = players[i]
 | |
|         end
 | |
|     end
 | |
| 
 | |
|     if (closestPlayer ~= nil and DoesEntityExist(GetPlayerPed(closestPlayer))) then
 | |
|         return closestPlayer
 | |
|     else
 | |
|         return nil
 | |
|     end
 | |
| end
 | |
| 
 | |
| -- Return closest loaded vehicle entity or nil if no vehicle is found
 | |
| function GetClosestVehicle(position, maxRadius)
 | |
|     local vehicles       = GetAllVehicles()
 | |
|     local dist           = maxRadius
 | |
|     local closestVehicle = nil
 | |
|     
 | |
|     for i=1, #vehicles, 1 do
 | |
|         local vehicleCoords = GetEntityCoords(vehicles[i])
 | |
|         local tempDist = Vdist(vehicleCoords.x, vehicleCoords.y, vehicleCoords.z, position.x, position.y, position.z)
 | |
|         if (tempDist < dist) then
 | |
|             dist = tempDist
 | |
|             closestVehicle = vehicles[i]
 | |
|         end
 | |
|     end
 | |
|     
 | |
|     if (closestVehicle ~= nil and DoesEntityExist(closestVehicle)) then
 | |
|         return closestVehicle
 | |
|     else
 | |
|         return nil
 | |
|     end
 | |
| end
 | |
| 
 | |
| -- Returns all loaded vehicles on client side
 | |
| function GetAllVehicles()
 | |
|     local vehicles = {}
 | |
|     
 | |
|     for vehicle in EnumerateVehicles() do
 | |
|         table.insert(vehicles, vehicle)
 | |
|     end
 | |
|     
 | |
|     return vehicles
 | |
| end
 | |
| 
 | |
| -- getting all vehicles
 | |
| function EnumerateVehicles()
 | |
|     return EnumerateEntities(FindFirstVehicle, FindNextVehicle, EndFindVehicle)
 | |
| end
 | |
| function EnumerateEntities(initFunc, moveFunc, disposeFunc)
 | |
|     return coroutine.wrap(function()
 | |
|         local iter, id = initFunc()
 | |
|         if not id or id == 0 then
 | |
|             disposeFunc(iter)
 | |
|             return
 | |
|         end
 | |
| 
 | |
|         local enum = {handle = iter, destructor = disposeFunc}
 | |
|         setmetatable(enum, entityEnumerator)
 | |
| 
 | |
|         local next = true
 | |
|         repeat
 | |
|             coroutine.yield(id)
 | |
|             next, id = moveFunc(iter)
 | |
|         until not next
 | |
| 
 | |
|         enum.destructor, enum.handle = nil, nil
 | |
|         disposeFunc(iter)
 | |
|     end)
 | |
| end
 | |
| local entityEnumerator = {
 | |
|     __gc = function(enum)
 | |
|         if enum.destructor and enum.handle then
 | |
|             enum.destructor(enum.handle)
 | |
|         end
 | |
|         enum.destructor = nil
 | |
|         enum.handle = nil
 | |
|     end
 | |
| }
 | |
| 
 | |
| --[[
 | |
| 	RegisterCommand("plate", function(source, args, raw)
 | |
| 		local vehicle = GetClosestVehicle(GetEntityCoords(PlayerPedId()), 10.0)
 | |
| 		if (DoesEntityExist(vehicle)) then
 | |
| 			SetVehicleNumberPlateText(vehicle, args[1])
 | |
| 		end
 | |
| 	end, false)
 | |
| ]]
 | 
