459 lines
15 KiB
Lua
459 lines
15 KiB
Lua
|
local QBCore = exports['qb-core']:GetCoreObject()
|
||
|
local PlayerData = QBCore.Functions.GetPlayerData()
|
||
|
local marketItems, orderLocation, tabletProp, currentMoney
|
||
|
local targetZones = {}
|
||
|
local displayingUI = false
|
||
|
|
||
|
local function removeTargetZones()
|
||
|
for i=1, #targetZones do
|
||
|
exports['qb-target']:RemoveZone(targetZones[i])
|
||
|
end
|
||
|
end
|
||
|
|
||
|
local function tabletAnim(state)
|
||
|
local ped = PlayerPedId()
|
||
|
if state then
|
||
|
local tabletHash = joaat(Config.tabletAnim.prop)
|
||
|
loadModel(tabletHash)
|
||
|
loadAnimDict(Config.tabletAnim.dict)
|
||
|
|
||
|
tabletProp = CreateObject(tabletHash, GetEntityCoords(ped), true, true, false)
|
||
|
AttachEntityToEntity(tabletProp, ped, GetPedBoneIndex(ped, 28422), -0.05, 0.0, 0.0, 0.0, 0.0, 0.0, true, true, false, true, 1, true)
|
||
|
SetModelAsNoLongerNeeded(tabletHash)
|
||
|
|
||
|
TaskPlayAnim(ped, Config.tabletAnim.dict, Config.tabletAnim.anim, 1.0, 1.0, -1, 51, 0, 0, 0, 0)
|
||
|
else
|
||
|
DeleteObject(tabletProp)
|
||
|
ClearPedTasks(ped)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
local function displayUI(state)
|
||
|
displayingUI = state
|
||
|
tabletAnim(state)
|
||
|
if state then
|
||
|
SendNUIMessage({
|
||
|
action = "setVisible",
|
||
|
data = true,
|
||
|
})
|
||
|
else
|
||
|
SendNUIMessage({
|
||
|
action = "setVisible",
|
||
|
data = false,
|
||
|
})
|
||
|
end
|
||
|
SetNuiFocus(state, state)
|
||
|
end
|
||
|
|
||
|
local function tabletNotification(text, notifType)
|
||
|
SendNUIMessage({
|
||
|
action = "notification",
|
||
|
data = {
|
||
|
text = text,
|
||
|
notifType = notifType,
|
||
|
}
|
||
|
})
|
||
|
end
|
||
|
|
||
|
local function doContainerAnim(index, containerNetId, lockNetId, collisionNetId)
|
||
|
local container = NetworkGetEntityFromNetworkId(containerNetId)
|
||
|
local lock = NetworkGetEntityFromNetworkId(lockNetId)
|
||
|
local collision = NetworkGetEntityFromNetworkId(collisionNetId)
|
||
|
|
||
|
NetworkRequestControlOfEntity(container)
|
||
|
NetworkRequestControlOfEntity(lock)
|
||
|
local timer = GetGameTimer()
|
||
|
while not NetworkHasControlOfEntity(container) or not NetworkHasControlOfEntity(lock) do
|
||
|
Wait(0)
|
||
|
if GetGameTimer() - timer > 5000 then
|
||
|
printError("Failed to get control of object")
|
||
|
break
|
||
|
end
|
||
|
end
|
||
|
|
||
|
loadAnimDict(Config.containerAnim.dict)
|
||
|
loadPtfx(Config.containerAnim.ptfx)
|
||
|
loadAudio(Config.containerAnim.audioBank)
|
||
|
|
||
|
local grinderHash = joaat(Config.props.grinder)
|
||
|
local bagHash = joaat(Config.props.bag)
|
||
|
loadModel(grinderHash)
|
||
|
loadModel(bagHash)
|
||
|
|
||
|
local ped = PlayerPedId()
|
||
|
local containerCoords = GetEntityCoords(container)
|
||
|
local containerRot = GetEntityRotation(container)
|
||
|
local playerCoords = GetEntityCoords(ped)
|
||
|
local grinder = CreateObject(grinderHash, playerCoords, true, true, false)
|
||
|
local bag = CreateObject(bagHash, playerCoords, true, true, false)
|
||
|
SetEntityCollision(bag, false, false)
|
||
|
|
||
|
FreezeEntityPosition(ped, true)
|
||
|
|
||
|
local containerScene = NetworkCreateSynchronisedScene(containerCoords, containerRot, 2, true, false, 1.0, 0.0, 1.0)
|
||
|
NetworkAddPedToSynchronisedScene(ped, containerScene, Config.containerAnim.dict, Config.containerAnim.player, 10.0, 10.0, 0, 0, 1000.0, 0)
|
||
|
NetworkAddEntityToSynchronisedScene(lock, containerScene, Config.containerAnim.dict, Config.containerAnim.lock, 2.0, -4.0, 134149)
|
||
|
NetworkAddEntityToSynchronisedScene(grinder, containerScene, Config.containerAnim.dict, Config.containerAnim.grinder, 2.0, -4.0, 134149)
|
||
|
NetworkAddEntityToSynchronisedScene(bag, containerScene, Config.containerAnim.dict, Config.containerAnim.bag, 2.0, -4.0, 134149)
|
||
|
NetworkStartSynchronisedScene(containerScene)
|
||
|
|
||
|
PlayEntityAnim(container, Config.containerAnim.container, Config.containerAnim.dict, 8.0, false, true, false, 0, 0)
|
||
|
|
||
|
CreateThread(function()
|
||
|
while NetworkGetLocalSceneFromNetworkId(containerScene) == -1 do Wait(0) end
|
||
|
local localScene = NetworkGetLocalSceneFromNetworkId(containerScene)
|
||
|
local ptfx
|
||
|
|
||
|
while IsSynchronizedSceneRunning(localScene) do
|
||
|
if HasAnimEventFired(ped, -1953940906) then
|
||
|
UseParticleFxAsset("scr_tn_tr")
|
||
|
ptfx = StartNetworkedParticleFxLoopedOnEntity("scr_tn_tr_angle_grinder_sparks", grinder, 0.0, 0.25, 0.0, 0.0, 0.0, 0.0, 1.0, false, false, false, 1065353216, 1065353216, 1065353216, 1)
|
||
|
elseif HasAnimEventFired(ped, -258875766) then
|
||
|
StopParticleFxLooped(ptfx, false)
|
||
|
end
|
||
|
Wait(0)
|
||
|
end
|
||
|
end)
|
||
|
|
||
|
Wait(GetAnimDuration(Config.containerAnim.dict, Config.containerAnim.container) * 1000)
|
||
|
|
||
|
FreezeEntityPosition(ped, false)
|
||
|
NetworkStopSynchronisedScene(containerScene)
|
||
|
|
||
|
DeleteObject(grinder)
|
||
|
DeleteObject(lock)
|
||
|
DeleteObject(bag)
|
||
|
ClearPedTasks(ped)
|
||
|
|
||
|
TriggerServerEvent("qb-blackmarket_sv:openContainer", index)
|
||
|
|
||
|
DisposeSynchronizedScene(containerScene)
|
||
|
RemoveNamedPtfxAsset(Config.containerAnim.ptfx)
|
||
|
ReleaseNamedScriptAudioBank(Config.containerAnim.audioBank)
|
||
|
RemoveAnimDict(Config.containerAnim.dict)
|
||
|
end
|
||
|
|
||
|
local function spawnObject(model, coords)
|
||
|
local propHash = type(model) == 'string' and joaat(model) or model
|
||
|
loadModel(propHash)
|
||
|
local object = CreateObject(propHash, coords.xyz, true, true, false)
|
||
|
while not DoesEntityExist(object) do
|
||
|
Wait(10)
|
||
|
end
|
||
|
|
||
|
SetEntityAsMissionEntity(object, true, true)
|
||
|
FreezeEntityPosition(object, true)
|
||
|
SetEntityHeading(object, coords.w)
|
||
|
|
||
|
SetModelAsNoLongerNeeded(propHash)
|
||
|
return object
|
||
|
end
|
||
|
|
||
|
local function spawnContainer(coords)
|
||
|
loadAnimDict(Config.containerAnim.dict)
|
||
|
local container = spawnObject(Config.props.container, vector4(coords.x, coords.y, coords.z - 1, coords.w - 180))
|
||
|
local containerCoords = GetEntityCoords(container)
|
||
|
|
||
|
local lockCoords = GetAnimInitialOffsetPosition(Config.containerAnim.dict, Config.containerAnim.lock, GetEntityCoords(container), GetEntityRotation(container), 0.0, 0)
|
||
|
local lock = spawnObject(Config.props.lock, vector4(lockCoords, coords.w - 180))
|
||
|
SetEntityCoords(lock, lockCoords)
|
||
|
|
||
|
local crateCoords = GetObjectOffsetFromCoords(coords, 0.0, -0.6, -0.8)
|
||
|
local crate = spawnObject(Config.props.crate, vector4(crateCoords, coords.w + 90))
|
||
|
|
||
|
local collision = spawnObject(Config.props.containerCollison, vector4(containerCoords, coords.w - 180))
|
||
|
SetEntityCoords(collision, containerCoords, false, false, false)
|
||
|
SetEntityCollision(collision, false, false)
|
||
|
|
||
|
local props = {
|
||
|
container = container,
|
||
|
lock = lock,
|
||
|
crate = crate,
|
||
|
collision = collision,
|
||
|
}
|
||
|
return props
|
||
|
end
|
||
|
|
||
|
RegisterNetEvent("qb-blackmarket_cl:openUI", function()
|
||
|
displayUI(true)
|
||
|
end)
|
||
|
|
||
|
RegisterNetEvent("qb-blackmarket_cl:updateMarketItems", function(items)
|
||
|
marketItems = items
|
||
|
|
||
|
SendNUIMessage({
|
||
|
action = "updateMarketItems",
|
||
|
data = items
|
||
|
})
|
||
|
end)
|
||
|
|
||
|
RegisterNetEvent("qb-blackmarket_cl:updateStock", function(items, orderSrc)
|
||
|
marketItems = items
|
||
|
if displayingUI then
|
||
|
local isOwner = false
|
||
|
if orderSrc == GetPlayerServerId(PlayerId()) then
|
||
|
isOwner = true
|
||
|
end
|
||
|
SendNUIMessage({
|
||
|
action = "updateStock",
|
||
|
data = {
|
||
|
items = items,
|
||
|
notif = Config.notifText.stockUpdate,
|
||
|
isOwner = isOwner,
|
||
|
},
|
||
|
})
|
||
|
end
|
||
|
end)
|
||
|
|
||
|
RegisterNetEvent("qb-blackmarket_cl:orderReady", function(index, coords)
|
||
|
orderLocation = coords
|
||
|
local props = spawnContainer(orderLocation)
|
||
|
local netIds = {}
|
||
|
for k, v in pairs(props) do
|
||
|
netIds[k] = NetworkGetNetworkIdFromEntity(v)
|
||
|
end
|
||
|
|
||
|
TriggerServerEvent("qb-blackmarket_sv:propsSpawned", netIds, index)
|
||
|
|
||
|
if not displayingUI then
|
||
|
QBCore.Functions.Notify(Config.notifText.orderReady, "success")
|
||
|
else
|
||
|
tabletNotification(Config.notifText.orderReady, "success")
|
||
|
end
|
||
|
|
||
|
SendNUIMessage({
|
||
|
action = "orderReady",
|
||
|
})
|
||
|
|
||
|
if math.random() <= Config.policeNotifChance then
|
||
|
Config.policeNotify(orderLocation)
|
||
|
end
|
||
|
end)
|
||
|
|
||
|
RegisterNetEvent("qb-blackmarket_cl:addLockTarget", function(index, coords)
|
||
|
local zoneName = "bm_lock_"..index
|
||
|
|
||
|
for i=1, #targetZones do
|
||
|
if targetZones[i] == zoneName then print("lock exists") return end
|
||
|
end
|
||
|
|
||
|
local min, max = GetModelDimensions(joaat(Config.props.lock))
|
||
|
local lockDimensions = max - min
|
||
|
exports["qb-target"]:AddBoxZone(zoneName, coords.xyz, lockDimensions.y, lockDimensions.x, {
|
||
|
name = zoneName,
|
||
|
heading = coords.w,
|
||
|
debugPoly = false,
|
||
|
minZ = coords.z - lockDimensions.z/2,
|
||
|
maxZ = coords.z + lockDimensions.z/2,
|
||
|
}, {
|
||
|
options = {
|
||
|
{
|
||
|
icon = "fa-solid fa-unlock",
|
||
|
label = "Åben",
|
||
|
action = function()
|
||
|
TriggerServerEvent("qb-blackmarket_sv:attemptContainer", index)
|
||
|
end
|
||
|
}
|
||
|
},
|
||
|
distance = 2.0
|
||
|
})
|
||
|
targetZones[#targetZones + 1] = zoneName
|
||
|
end)
|
||
|
|
||
|
|
||
|
RegisterNetEvent("qb-blackmarket_cl:openContainer", function(index, propIds)
|
||
|
doContainerAnim(index, propIds.container, propIds.lock, propIds.collision)
|
||
|
end)
|
||
|
|
||
|
RegisterNetEvent("qb-blackmarket_cl:updateOpenContainer", function(index, containerNetId, collisionNetId, crateCoords, removeLockTarget)
|
||
|
local container = NetworkGetEntityFromNetworkId(containerNetId)
|
||
|
local collision = NetworkGetEntityFromNetworkId(collisionNetId)
|
||
|
SetEntityCollision(collision, true, true)
|
||
|
SetEntityCompletelyDisableCollision(container, false, false)
|
||
|
|
||
|
if removeLockTarget then
|
||
|
exports['qb-target']:RemoveZone("bm_lock_"..index)
|
||
|
for i=1, #targetZones do
|
||
|
if targetZones[i] == "bm_lock_"..index then
|
||
|
table.remove(targetZones, i)
|
||
|
break
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
local zoneName = "bm_crate_"..index
|
||
|
local min, max = GetModelDimensions(joaat(Config.props.crate))
|
||
|
local crateDimensions = max - min
|
||
|
exports["qb-target"]:AddBoxZone(zoneName, crateCoords.xyz, crateDimensions.y, crateDimensions.x, {
|
||
|
name = zoneName,
|
||
|
heading = crateCoords.w,
|
||
|
debugPoly = false,
|
||
|
minZ = crateCoords.z,
|
||
|
maxZ = crateCoords.z + crateDimensions.z,
|
||
|
}, {
|
||
|
options = {
|
||
|
{
|
||
|
icon = "fa-solid fa-boxes-stacked",
|
||
|
label = "Tag",
|
||
|
action = function()
|
||
|
TriggerServerEvent("qb-blackmarket_sv:attemptLoot", index)
|
||
|
end
|
||
|
}
|
||
|
},
|
||
|
distance = 2.0
|
||
|
})
|
||
|
targetZones[#targetZones + 1] = zoneName
|
||
|
end)
|
||
|
|
||
|
RegisterNetEvent("qb-blackmarket_cl:removeLockTarget", function(index)
|
||
|
print("removing lock target ", index)
|
||
|
exports['qb-target']:RemoveZone("bm_lock_"..index)
|
||
|
for i=1, #targetZones do
|
||
|
if targetZones[i] == "bm_lock_"..index then
|
||
|
table.remove(targetZones, i)
|
||
|
break
|
||
|
end
|
||
|
end
|
||
|
end)
|
||
|
|
||
|
RegisterNetEvent("qb-blackmarket_cl:removeLootTarget", function(index)
|
||
|
exports['qb-target']:RemoveZone("bm_crate_"..index)
|
||
|
for i=1, #targetZones do
|
||
|
if targetZones[i] == "bm_crate_"..index then
|
||
|
table.remove(targetZones, i)
|
||
|
break
|
||
|
end
|
||
|
end
|
||
|
end)
|
||
|
|
||
|
RegisterNetEvent("qb-blackmarket_cl:lootContainer", function(index)
|
||
|
local ped = PlayerPedId()
|
||
|
loadAnimDict(Config.lootAnim.dict)
|
||
|
TaskPlayAnim(ped, Config.lootAnim.dict, Config.lootAnim.anim, 1.0, 1.0, -1, 1, 0, 0, 0, 0)
|
||
|
QBCore.Functions.Progressbar("looting_crate", "Tager ting..", Config.lootTime, false, true, {
|
||
|
disableMovement = true,
|
||
|
disableCarMovement = true,
|
||
|
disableMouse = false,
|
||
|
disableCombat = true
|
||
|
}, {}, {}, {}, function() -- Done
|
||
|
TriggerServerEvent("qb-blackmarket_sv:finishLooting", index)
|
||
|
end, function() -- Cancel
|
||
|
TriggerServerEvent("qb-blackmarket_sv:cancelLooting", index)
|
||
|
QBCore.Functions.Notify("Annulleret", "error")
|
||
|
end)
|
||
|
end)
|
||
|
|
||
|
RegisterNetEvent("qb-blackmarket_cl:orderComplete", function()
|
||
|
SendNUIMessage({
|
||
|
action = "clearOrder"
|
||
|
})
|
||
|
end)
|
||
|
|
||
|
RegisterNetEvent("qb-blackmarket_cl:hasPendingOrder", function(items, order, epochTime)
|
||
|
SendNUIMessage({
|
||
|
action = "loadPendingOrder",
|
||
|
data = {
|
||
|
marketItems = items,
|
||
|
order = order,
|
||
|
epochTime = epochTime,
|
||
|
}
|
||
|
})
|
||
|
end)
|
||
|
|
||
|
RegisterNetEvent("qb-blackmarket_cl:enableLocateButton", function(index)
|
||
|
orderLocation = Config.deliveryLocations[index]
|
||
|
SendNUIMessage({
|
||
|
action = "orderReady",
|
||
|
})
|
||
|
end)
|
||
|
|
||
|
RegisterNUICallback("getClientData", function(data, cb)
|
||
|
currentMoney = PlayerData.money[Config.paymentType]
|
||
|
if not marketItems then
|
||
|
QBCore.Functions.TriggerCallback("qb-blackmarket_sv:getMarketItems", function(items)
|
||
|
marketItems = items
|
||
|
cb({ marketItems = marketItems, currencyAmt = currentMoney })
|
||
|
end)
|
||
|
else
|
||
|
cb({ marketItems = marketItems, currencyAmt = currentMoney })
|
||
|
end
|
||
|
end)
|
||
|
|
||
|
RegisterNUICallback("submitOrder", function(data, cb)
|
||
|
QBCore.Functions.TriggerCallback("qb-blackmarket_sv:attemptOrder", function(result)
|
||
|
cb(result)
|
||
|
if result.notif then
|
||
|
if result.success then
|
||
|
tabletNotification(result.notif, "success")
|
||
|
else
|
||
|
tabletNotification(result.notif, "error")
|
||
|
end
|
||
|
end
|
||
|
if result.error then
|
||
|
printError(result.error)
|
||
|
end
|
||
|
end, (data))
|
||
|
end)
|
||
|
|
||
|
RegisterNUICallback("deliveryLocation", function(data, cb)
|
||
|
if orderLocation then
|
||
|
SetNewWaypoint(orderLocation.x, orderLocation.y)
|
||
|
tabletNotification(Config.notifText.gpsSet, "success")
|
||
|
end
|
||
|
cb({})
|
||
|
end)
|
||
|
|
||
|
RegisterNUICallback("close", function(data, cb)
|
||
|
displayUI(false)
|
||
|
cb({})
|
||
|
end)
|
||
|
|
||
|
RegisterNUICallback("fetchConfig", function(data, cb)
|
||
|
cb({
|
||
|
configData = {
|
||
|
inventory = Config.inventory,
|
||
|
paymentType = Config.paymentType,
|
||
|
acronym = Config.cryptoAcronym,
|
||
|
cryptoIcon = Config.cryptoIcon,
|
||
|
estDeliveryTime = tostring(math.floor((Config.deliveryTime.min + Config.deliveryTime.max)/2)),
|
||
|
tabletColour = Config.tabletColour,
|
||
|
},
|
||
|
notifData = Config.notifs,
|
||
|
})
|
||
|
end)
|
||
|
|
||
|
RegisterNetEvent('QBCore:Player:SetPlayerData', function(val)
|
||
|
PlayerData = val
|
||
|
if displayingUI then
|
||
|
if PlayerData.money[Config.paymentType] ~= currentMoney then
|
||
|
SendNUIMessage({
|
||
|
action = "updateCash",
|
||
|
data = PlayerData.money[Config.paymentType]
|
||
|
})
|
||
|
end
|
||
|
end
|
||
|
end)
|
||
|
|
||
|
RegisterNetEvent('QBCore:Client:OnPlayerLoaded', function()
|
||
|
PlayerData = QBCore.Functions.GetPlayerData()
|
||
|
TriggerServerEvent("qb-blackmarket_sv:initPendingOrders")
|
||
|
end)
|
||
|
|
||
|
RegisterNetEvent('QBCore:Client:OnPlayerUnload', function()
|
||
|
PlayerData = nil
|
||
|
removeTargetZones()
|
||
|
targetZones = {}
|
||
|
SendNUIMessage({
|
||
|
SendNUIMessage({
|
||
|
action = "clearOrder"
|
||
|
})
|
||
|
})
|
||
|
end)
|
||
|
|
||
|
AddEventHandler('onResourceStop', function(resourceName)
|
||
|
if resourceName ~= GetCurrentResourceName() then return end
|
||
|
for i=1, #targetZones do
|
||
|
exports['qb-target']:RemoveZone(targetZones[i])
|
||
|
end
|
||
|
targetZones = {}
|
||
|
end)
|