410 lines
		
	
	
	
		
			9.6 KiB
		
	
	
	
		
			Lua
		
	
	
	
	
	
			
		
		
	
	
			410 lines
		
	
	
	
		
			9.6 KiB
		
	
	
	
		
			Lua
		
	
	
	
	
	
local Entity = Entity
 | 
						|
 | 
						|
local function getDoorFromEntity(data)
 | 
						|
	local entity = type(data) == 'table' and data.entity or data
 | 
						|
 | 
						|
	if not entity then return end
 | 
						|
 | 
						|
	local state = Entity(entity)?.state
 | 
						|
	local doorId = state?.doorId
 | 
						|
 | 
						|
	if not doorId then return end
 | 
						|
 | 
						|
	local door = doors[doorId]
 | 
						|
 | 
						|
	if not door then
 | 
						|
		state.doorId = nil
 | 
						|
	end
 | 
						|
 | 
						|
	return door
 | 
						|
end
 | 
						|
 | 
						|
exports('getClosestDoorId', function() return ClosestDoor?.id end)
 | 
						|
exports('getDoorIdFromEntity', function(entityId) return getDoorFromEntity(entityId)?.id end) -- same as Entity(entityId).state.doorId
 | 
						|
 | 
						|
local function entityIsNotDoor(data)
 | 
						|
	local entity = type(data) == 'number' and data or data.entity
 | 
						|
	return not getDoorFromEntity(entity)
 | 
						|
end
 | 
						|
 | 
						|
PickingLock = false
 | 
						|
 | 
						|
local function canPickLock(entity)
 | 
						|
	if PickingLock then return false end
 | 
						|
 | 
						|
	local door = getDoorFromEntity(entity)
 | 
						|
 | 
						|
	return door and door.lockpick and (Config.CanPickUnlockedDoors or door.state == 1)
 | 
						|
end
 | 
						|
 | 
						|
---@param entity number
 | 
						|
local function pickLock(entity)
 | 
						|
	local door = getDoorFromEntity(entity)
 | 
						|
 | 
						|
	if not door or PickingLock or not door.lockpick or (not Config.CanPickUnlockedDoors and door.state == 0) then return end
 | 
						|
 | 
						|
	PickingLock = true
 | 
						|
 | 
						|
	TaskTurnPedToFaceCoord(cache.ped, door.coords.x, door.coords.y, door.coords.z, 4000)
 | 
						|
	Wait(500)
 | 
						|
 | 
						|
	local animDict = lib.requestAnimDict('mp_common_heist')
 | 
						|
 | 
						|
	TaskPlayAnim(cache.ped, animDict, 'pick_door', 3.0, 1.0, -1, 49, 0, true, true, true)
 | 
						|
 | 
						|
	local success = lib.skillCheck(door.lockpickDifficulty or Config.LockDifficulty)
 | 
						|
	local rand = math.random(1, success and 100 or 5)
 | 
						|
 | 
						|
	if success then
 | 
						|
		TriggerServerEvent('ox_doorlock:setState', door.id, door.state == 1 and 0 or 1, true)
 | 
						|
	end
 | 
						|
 | 
						|
	if rand == 1 then
 | 
						|
		TriggerServerEvent('ox_doorlock:breakLockpick')
 | 
						|
		lib.notify({ type = 'error', description = locale('lockpick_broke') })
 | 
						|
	end
 | 
						|
 | 
						|
	StopEntityAnim(cache.ped, 'pick_door', animDict, 0)
 | 
						|
	RemoveAnimDict(animDict)
 | 
						|
 | 
						|
	PickingLock = false
 | 
						|
end
 | 
						|
 | 
						|
exports('pickClosestDoor', function()
 | 
						|
	if not ClosestDoor then return end
 | 
						|
 | 
						|
	pickLock(ClosestDoor.entity)
 | 
						|
end)
 | 
						|
 | 
						|
local tempData = {}
 | 
						|
 | 
						|
local function addDoorlock(data)
 | 
						|
	local entity = type(data) == 'number' and data or data.entity
 | 
						|
	local model = GetEntityModel(entity)
 | 
						|
	local coords = GetEntityCoords(entity)
 | 
						|
 | 
						|
	AddDoorToSystem(`temp`, model, coords.x, coords.y, coords.z, false, false, false)
 | 
						|
	DoorSystemSetDoorState(`temp`, 4, false, false)
 | 
						|
 | 
						|
	coords = GetEntityCoords(entity)
 | 
						|
	tempData[#tempData + 1] = {
 | 
						|
		entity = entity,
 | 
						|
		model = model,
 | 
						|
		coords = coords,
 | 
						|
		heading = math.floor(GetEntityHeading(entity) + 0.5)
 | 
						|
	}
 | 
						|
 | 
						|
	RemoveDoorFromSystem(`temp`)
 | 
						|
end
 | 
						|
 | 
						|
local isAddingDoorlock = false
 | 
						|
 | 
						|
RegisterNUICallback('notify', function(data, cb)
 | 
						|
	cb(1)
 | 
						|
	lib.notify({ title = data })
 | 
						|
end)
 | 
						|
 | 
						|
RegisterNUICallback('createDoor', function(data, cb)
 | 
						|
	cb(1)
 | 
						|
	SetNuiFocus(false, false)
 | 
						|
 | 
						|
	data.state = data.state and 1 or 0
 | 
						|
 | 
						|
	if data.items and not next(data.items) then
 | 
						|
		data.items = nil
 | 
						|
	end
 | 
						|
 | 
						|
	if data.characters and not next(data.characters) then
 | 
						|
		data.characters = nil
 | 
						|
	end
 | 
						|
 | 
						|
	if data.lockpickDifficulty and not next(data.lockpickDifficulty) then
 | 
						|
		data.lockpickDifficulty = nil
 | 
						|
	end
 | 
						|
 | 
						|
	if data.groups and not next(data.groups) then
 | 
						|
		data.groups = nil
 | 
						|
	end
 | 
						|
 | 
						|
	if not data.id then
 | 
						|
		isAddingDoorlock = true
 | 
						|
		local doorCount = data.doors and 2 or 1
 | 
						|
		local lastEntity = 0
 | 
						|
 | 
						|
		lib.showTextUI(locale('add_door_textui'))
 | 
						|
 | 
						|
		repeat
 | 
						|
			DisablePlayerFiring(cache.playerId, true)
 | 
						|
			DisableControlAction(0, 25, true)
 | 
						|
 | 
						|
			local hit, entity, coords = lib.raycast.cam(1|16)
 | 
						|
			local changedEntity = lastEntity ~= entity
 | 
						|
			local doorA = tempData[1]?.entity
 | 
						|
 | 
						|
			if changedEntity and lastEntity ~= doorA then
 | 
						|
				SetEntityDrawOutline(lastEntity, false)
 | 
						|
			end
 | 
						|
 | 
						|
			lastEntity = entity
 | 
						|
 | 
						|
			if hit then
 | 
						|
				---@diagnostic disable-next-line: param-type-mismatch
 | 
						|
				DrawMarker(28, coords.x, coords.y, coords.z, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.2, 0.2, 0.2, 255, 42, 24,
 | 
						|
					100, false, false, 0, true, false, false, false)
 | 
						|
			end
 | 
						|
 | 
						|
			if hit and entity > 0 and GetEntityType(entity) == 3 and (doorCount == 1 or doorA ~= entity) and entityIsNotDoor(entity) then
 | 
						|
				if changedEntity then
 | 
						|
					SetEntityDrawOutline(entity, true)
 | 
						|
				end
 | 
						|
 | 
						|
				if IsDisabledControlJustPressed(0, 24) then
 | 
						|
					addDoorlock(entity)
 | 
						|
				end
 | 
						|
			end
 | 
						|
 | 
						|
			if IsDisabledControlJustPressed(0, 25) then
 | 
						|
				SetEntityDrawOutline(entity, false)
 | 
						|
 | 
						|
				if not doorA then
 | 
						|
					isAddingDoorlock = false
 | 
						|
					return lib.hideTextUI()
 | 
						|
				end
 | 
						|
 | 
						|
				SetEntityDrawOutline(doorA, false)
 | 
						|
				table.wipe(tempData)
 | 
						|
			end
 | 
						|
		until tempData[doorCount]
 | 
						|
 | 
						|
		lib.hideTextUI()
 | 
						|
		SetEntityDrawOutline(tempData[1].entity, false)
 | 
						|
 | 
						|
		if data.doors then
 | 
						|
			SetEntityDrawOutline(tempData[2].entity, false)
 | 
						|
			tempData[1].entity = nil
 | 
						|
			tempData[2].entity = nil
 | 
						|
			data.doors = tempData
 | 
						|
		else
 | 
						|
			data.model = tempData[1].model
 | 
						|
			data.coords = tempData[1].coords
 | 
						|
			data.heading = tempData[1].heading
 | 
						|
		end
 | 
						|
	else
 | 
						|
		if data.doors then
 | 
						|
			for i = 1, 2 do
 | 
						|
				local coords = data.doors[i].coords
 | 
						|
				data.doors[i].coords = vector3(coords.x, coords.y, coords.z)
 | 
						|
				data.doors[i].entity = nil
 | 
						|
			end
 | 
						|
		else
 | 
						|
			data.entity = nil
 | 
						|
		end
 | 
						|
 | 
						|
		data.coords = vector3(data.coords.x, data.coords.y, data.coords.z)
 | 
						|
		data.distance = nil
 | 
						|
		data.zone = nil
 | 
						|
	end
 | 
						|
 | 
						|
	isAddingDoorlock = false
 | 
						|
 | 
						|
	------------------------------------
 | 
						|
	------- Brutal Housing Editing -----
 | 
						|
	------------------------------------
 | 
						|
	if PropertyID ~= nil then
 | 
						|
		if data.name:match("^(.-)_") == nil or data.name:match("^(.-)_") ~= PropertyID then
 | 
						|
			data.name = PropertyID.."_"..data.name
 | 
						|
		end
 | 
						|
 | 
						|
		local coords = data.coords or data.doors[1].coords
 | 
						|
		if coords ~= nil then
 | 
						|
			if #(coords - vector3(PropertyCoords.x, PropertyCoords.y, PropertyCoords.z)) > MaxDoorlockDistance then
 | 
						|
				TriggerEvent('brutal_housing:client:SendNotifyNumber', 75)
 | 
						|
				return
 | 
						|
			end
 | 
						|
		else
 | 
						|
			return
 | 
						|
		end
 | 
						|
 | 
						|
		PropertyID = nil
 | 
						|
		PropertyCoords = nil
 | 
						|
	end
 | 
						|
	------------------------------------
 | 
						|
	------- Brutal Housing Editing -----
 | 
						|
	------------------------------------
 | 
						|
 | 
						|
	TriggerServerEvent('ox_doorlock:editDoorlock', data.id or false, data)
 | 
						|
	table.wipe(tempData)
 | 
						|
end)
 | 
						|
 | 
						|
RegisterNUICallback('deleteDoor', function(id, cb)
 | 
						|
	cb(1)
 | 
						|
	TriggerServerEvent('ox_doorlock:editDoorlock', id)
 | 
						|
end)
 | 
						|
 | 
						|
RegisterNUICallback('teleportToDoor', function(id, cb)
 | 
						|
	cb(1)
 | 
						|
	SetNuiFocus(false, false)
 | 
						|
	local doorCoords = doors[id].coords
 | 
						|
	if not doorCoords then return end
 | 
						|
	SetEntityCoords(cache.ped, doorCoords.x, doorCoords.y, doorCoords.z, false, false, false, false)
 | 
						|
end)
 | 
						|
 | 
						|
RegisterNUICallback('exit', function(_, cb)
 | 
						|
	cb(1)
 | 
						|
	SetNuiFocus(false, false)
 | 
						|
end)
 | 
						|
 | 
						|
------------------------------------
 | 
						|
------- Brutal Housing Editing -----
 | 
						|
------------------------------------
 | 
						|
 | 
						|
PropertyID = nil
 | 
						|
PropertyCoords = nil
 | 
						|
MaxDoorlockDistance = 50.0
 | 
						|
 | 
						|
RegisterNetEvent("ox_doorlock:dataFromHousing")
 | 
						|
AddEventHandler("ox_doorlock:dataFromHousing", function(propertyID, coords, maxdoorlockdistance)
 | 
						|
	PropertyID = propertyID
 | 
						|
	PropertyCoords = coords
 | 
						|
	MaxDoorlockDistance = maxdoorlockdistance
 | 
						|
 | 
						|
	if isAddingDoorlock then return end
 | 
						|
 | 
						|
	NuiHasLoaded = true
 | 
						|
 | 
						|
	local allowedDoors = {}
 | 
						|
	for k,v in pairs(doors) do
 | 
						|
		print(v.name:match("^(.-)_"), PropertyID)
 | 
						|
		if v.name:match("^(.-)_") == PropertyID then
 | 
						|
			table.insert(allowedDoors, v)
 | 
						|
		end
 | 
						|
	end
 | 
						|
 | 
						|
	SendNuiMessage(json.encode({
 | 
						|
		action = 'updateDoorData',
 | 
						|
		data = allowedDoors
 | 
						|
	}, { with_hole = false }))
 | 
						|
	Wait(100)
 | 
						|
 | 
						|
	SendNUIMessage({
 | 
						|
		action = 'setSoundFiles',
 | 
						|
		data = lib.callback.await('ox_doorlock:getSounds', false)
 | 
						|
	})
 | 
						|
 | 
						|
	SetNuiFocus(true, true)
 | 
						|
	SendNuiMessage(json.encode({
 | 
						|
		action = 'setVisible',
 | 
						|
		data = id
 | 
						|
	}))
 | 
						|
end)
 | 
						|
 | 
						|
------------------------------------
 | 
						|
------- Brutal Housing Editing -----
 | 
						|
------------------------------------
 | 
						|
 | 
						|
local function openUi(id)
 | 
						|
	if source == '' or isAddingDoorlock then return end
 | 
						|
 | 
						|
	------------------------------------
 | 
						|
	------- Brutal Housing Editing -----
 | 
						|
	------------------------------------
 | 
						|
	PropertyID = nil
 | 
						|
	PropertyCoords = nil
 | 
						|
	------------------------------------
 | 
						|
	------- Brutal Housing Editing -----
 | 
						|
	------------------------------------
 | 
						|
 | 
						|
	NuiHasLoaded = true
 | 
						|
 | 
						|
	SendNuiMessage(json.encode({
 | 
						|
		action = 'updateDoorData',
 | 
						|
		data = doors
 | 
						|
	}, { with_hole = false }))
 | 
						|
	Wait(100)
 | 
						|
 | 
						|
	SendNUIMessage({
 | 
						|
		action = 'setSoundFiles',
 | 
						|
		data = lib.callback.await('ox_doorlock:getSounds', false)
 | 
						|
	})
 | 
						|
 | 
						|
	SetNuiFocus(true, true)
 | 
						|
	SendNuiMessage(json.encode({
 | 
						|
		action = 'setVisible',
 | 
						|
		data = id
 | 
						|
	}))
 | 
						|
end
 | 
						|
 | 
						|
RegisterNetEvent('ox_doorlock:triggeredCommand', function(closest)
 | 
						|
	openUi(closest and ClosestDoor?.id or nil)
 | 
						|
end)
 | 
						|
 | 
						|
CreateThread(function()
 | 
						|
	local target
 | 
						|
 | 
						|
	if GetResourceState('ox_target'):find('start') then
 | 
						|
		target = {
 | 
						|
			ox = true,
 | 
						|
			exp = exports.ox_target
 | 
						|
		}
 | 
						|
	elseif GetResourceState('qb-target'):find('start') then
 | 
						|
		target = {
 | 
						|
			qb = true,
 | 
						|
			exp = exports['qb-target']
 | 
						|
		}
 | 
						|
	elseif GetResourceState('qtarget'):find('start') then
 | 
						|
		target = {
 | 
						|
			qt = true,
 | 
						|
			exp = exports.qtarget
 | 
						|
		}
 | 
						|
	end
 | 
						|
 | 
						|
	if not target then return end
 | 
						|
 | 
						|
	if target.ox then
 | 
						|
		target.exp:addGlobalObject({
 | 
						|
			{
 | 
						|
				name = 'pickDoorlock',
 | 
						|
				label = locale('pick_lock'),
 | 
						|
				icon = 'fas fa-user-lock',
 | 
						|
				onSelect = pickLock,
 | 
						|
				canInteract = canPickLock,
 | 
						|
				items = Config.LockpickItems,
 | 
						|
				anyItem = true,
 | 
						|
				distance = 1
 | 
						|
			}
 | 
						|
		})
 | 
						|
	else
 | 
						|
		local options = {
 | 
						|
			{
 | 
						|
				label = locale('pick_lock'),
 | 
						|
				icon = 'fas fa-user-lock',
 | 
						|
				action = pickLock,
 | 
						|
				canInteract = canPickLock,
 | 
						|
				item = Config.LockpickItems[1],
 | 
						|
				distance = 1
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		---@cast target table
 | 
						|
 | 
						|
		if target.qt then
 | 
						|
			target.exp:Object({ options = options })
 | 
						|
		elseif target.qb then
 | 
						|
			target.exp:AddGlobalObject({ options = options })
 | 
						|
		end
 | 
						|
 | 
						|
		options = { locale('pick_lock') }
 | 
						|
 | 
						|
		AddEventHandler('onResourceStop', function(resource)
 | 
						|
			if resource == cache.resource then
 | 
						|
				if target.qt then
 | 
						|
					return target.exp:RemoveObject(options)
 | 
						|
				end
 | 
						|
 | 
						|
				if target.qb then
 | 
						|
					return target.exp:RemoveGlobalObject(options)
 | 
						|
				end
 | 
						|
			end
 | 
						|
		end)
 | 
						|
	end
 | 
						|
end)
 |