forked from Simnation/Main
411 lines
9.6 KiB
Lua
411 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)
|