From 6c3c55080028032498158196456b937a900d033e Mon Sep 17 00:00:00 2001 From: Jim Shield Date: Thu, 11 Jan 2024 17:06:33 +0000 Subject: [PATCH] Inital Commit and Release --- README.md | 28 +- crafting.lua | 501 ++++++++++++++++++++++++ exports.lua | 19 + functions.lua | 784 +++++++++++++++++++++++++++++++++++++ fxmanifest.lua | 14 + wrapper.lua | 1009 ++++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 2353 insertions(+), 2 deletions(-) create mode 100644 crafting.lua create mode 100644 exports.lua create mode 100644 functions.lua create mode 100644 fxmanifest.lua create mode 100644 wrapper.lua diff --git a/README.md b/README.md index 0eb0c9b..7b7ea0f 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,26 @@ -# jim_bridge -Framework bridge script +# Jim_Bridge + +This script is intended to be used with my all my scripts (soon) + +It was started due to wanting to bring the same features from some scripts into others with minimal work and multiple updates +- Having certain functions in one place(this script) makes it easier to update, enchance and fix things +- This brings the possibility of branching to mutliple frameworks as I've added some already: + - `"qb-core"` + - `"qbx-core"` + - `"ox_core"` + - `"es_extended"` (requires ox_lib and ox_inventory) + +All the next updates of my scripts will use this script and be added as a dependancy + +------ + +It was a tough decision to put it up on github instead of tebex and encrypted + +But I want this script to grow with help of others who know more about other cores + +--- + +The installation of this script is simple +- it just needs to start before any script that requires it +- it can start before core scripts if you want +- for `qb-core` I personally place this script in `resources > [standalone]` \ No newline at end of file diff --git a/crafting.lua b/crafting.lua new file mode 100644 index 0000000..414ea97 --- /dev/null +++ b/crafting.lua @@ -0,0 +1,501 @@ +if GetResourceState(OXLibExport):find("start") then + createCallback(GetCurrentResourceName()..':server:GetStashItems', function(source, stashName) local stash = getStash(stashName) return stash end) +else + createCallback(GetCurrentResourceName()..':server:GetStashItems', function(source, cb, stashName) local stash = getStash(stashName) cb(stash) end) +end + +local timeout = 0 +local timing = false +local stashItems = {} +function GetStashTimeout(stashName, stop) + if stop then stashItems = {} timing = false timeout = 0 return end + if stashItems[1] then return true else + if timeout <= 0 then + stashItems = triggerCallback(GetCurrentResourceName()..':server:GetStashItems', stashName) + timeout = 15000 + if not timing then + CreateThread(function() + timing = true + while timeout > 0 do timeout -= 1000 Wait(1000) end + timing = false stashItems = {} timeout = 0 + end) + end + end + return false + end +end + +local CraftLock = false +function craftingMenu(data) + if CraftLock then return end + if data.stashName and not GetStashTimeout(data.stashName) then + --triggerNotify(nil, "Chacking", "success") + end + if (data.job or data.gang) and not jobCheck(data.job or data.gang) then return end + local Menu = {} + local Recipes = data.craftable.Recipes + for i = 1, #Recipes do + for k, v in pairs(Recipes[i]) do + if k ~= "amount" and k ~= "job" and k ~= "gang" then + if Recipes[i].job then hasjob = false + for l, b in pairs(data.craftable[i]["job"]) do + hasjob = hasJob(l) + end + end + local setheader, settext = "", "" + local text = "" + local disable = false + local checktable = {} + if Recipes[i].job and hasjob == false then else + for l, b in pairs(Recipes[i][tostring(k)]) do + if not Items[l] then print("^3Error^7: ^2Script can't find ingredient item in Shared Items - ^1"..l.."^7") return end + settext = settext..(settext ~= "" and br or "")..Items[l].label..(b > 1 and " x"..b or "") + if data.stashName then checktable[l] = stashhasItem(stashItems, l, b) + else checktable[l] = hasItem(l, b) end + Wait(0) + end + for _, v in pairs(checktable) do + if not v then + disable = true + break + end + end + setheader = Items[tostring(k)].label..(Recipes[i]["amount"] > 1 and " x"..Recipes[i]["amount"] or "")..(not disable and " ✔️" or "") + Menu[#Menu + 1] = { + isMenuHeader = disable, + icon = invImg(tostring(k)), + header = setheader, txt = settext, + onSelect = function() + local transdata = { item = k, craft = data.craftable.Recipes[i], craftable = data.craftable, coords = data.coords, stashName = data.stashName, onBack = data.onBack } + if Config.Crafting.MultiCraft then + multiCraft(transdata) + else + makeItem(transdata) + end + end, + } + end + end + end + end + openMenu(Menu, { header = data.craftable.Header, onBack = data.onBack or nil, canClose = true, onExit = function() end, }) + lookEnt(data.coords) +end + +function multiCraft(data) local Menu = {} + local success = Config.Crafting.MultiCraftAmounts + if data.stashName and not GetStashTimeout(data.stashName) then + --triggerNotify(nil, "Refreshing stashinfo", "success") + end + Menu[#Menu+1] = { + isMenuHeader = true, + icon = invImg(data.item), + header = Items[data.item].label, + } + for k in pairsByKeys(success) do + local settext = "" + for l, b in pairs(data.craft[data.item]) do + if data.stashName then + success[k] = stashhasItem(stashItems, l, (b * k)) + else + success[k] = hasItem(l, (b * k)) + end + settext = settext..(settext ~= "" and br or "")..Items[l].label..(b*k > 1 and "- x"..b*k or "") + Wait(0) + end + Menu[#Menu + 1] = { + isMenuHeader = not success[k], + header = "Craft - x"..k * data.craft.amount, + txt = settext, + onSelect = function () + makeItem({item = data.item, craft = data.craft, craftable = data.craftable, amount = k, coords = data.coords, stashName = data.stashName, onBack = data.onBack }) + end, + } + end + openMenu(Menu, { header = data.craftable.Header, onBack = function() craftingMenu(data) end, }) +end + +function makeItem(data) + if not CraftLock then CraftLock = true else return end + local bartime, bartext, animDict, anim = nil, nil, nil, nil + if data.craftable.progressBar then + bartime = data.craftable.progressBar.time + bartext = data.craftable.progressBar.label + else + bartime = 5000 + bartext = Loc[Config.Lan].progressbar["progress_make"] + end + animDict = data.craftable.Anims.animDict or "amb@prop_human_parking_meter@male@idle_a" + anim = data.craftable.Anims.anim or "idle_a" + + local amount = (data.amount and data.amount ~= 1) and data.amount or 1 + + local crafted = true + local crafting = true + + local cam = createTempCam(PlayerPedId(), data.coords) + startTempCam(cam) + + for i = 1, amount do + for _, v in pairs(data.craft) do + if type(v) == "table" then + for l, b in pairs(v) do + if crafting and progressBar({ + label = "Using "..b.." "..Items[l].label, + time = 1000, + cancel = true, + dict = 'pickup_object', + anim = "putdown_low", + flag = 48, + icon = l, + }) then + --TriggerEvent('inventory:client:ItemBox', Items[l], "use", b) -- Show item box for each item + else + crafted = false + crafting = false + break + end + Wait(200) + end + if crafted then + if crafting and progressBar({ + label = bartext..Items[data.item].label, + time = bartime, + cancel = true, + dict = animDict, + anim = anim, + flag = 8, + icon = data.item, + }) then + TriggerServerEvent(GetCurrentResourceName()..":Crafting:GetItem", data.item, data.craft, data.stashName) + else + crafting = false + break + end + end + end + end + Wait(500) + end + stopTempCam() + CraftLock = false + lockInv(false) + craftingMenu(data) + ClearPedTasks(PlayerPedId()) +end + +RegisterNetEvent(GetCurrentResourceName()..":Crafting:GetItem", function(ItemMake, craftable, stashName) + local src = source + local amount = 1 + if stashName then + local stashItems = getStash(stashName) + if craftable["amount"] then amount = craftable["amount"] end + local itemRemove = {} + for k, v in pairs(craftable[ItemMake]) do + for l, b in pairs(stashItems) do + if k == b.name then + itemRemove[k] = v + end + end + end + stashRemoveItem(stashItems, stashName, itemRemove) + else + if craftable then + if craftable["amount"] then amount = craftable["amount"] end + for k, v in pairs(craftable[ItemMake]) do + TriggerEvent(GetCurrentResourceName()..":server:toggleItem", false, tostring(k), v, src) + end + end + end + TriggerEvent(GetCurrentResourceName()..":server:toggleItem", true, ItemMake, amount, src) +end) + +--[[SHOPS]]-- +function openShop(data) + if (data.job or data.gang) and not jobCheck(data.job or data.gang) then return end + if GetResourceState(OXInv):find("start") then + exports[OXInv]:openInventory('shop', { type = data.shop }) + else + TriggerServerEvent(Config.JimShops and "jim-shops:ShopOpen" or "inventory:server:OpenInventory", "shop", data.shop, data.items) + end + lookEnt(data.coords) +end + +-- Client & Server side +function hasItem(items, amount, src) local amount, count = amount and amount or 1, 0 + if src then + if GetResourceState(OXInv):find("start") then + local item = exports[OXInv]:GetItem(src, items) + local amount = (amount or 1) + if item.count >= amount then + if Config.System.Debug then print("^6Bridge^7: ^3HasItem^7: ^5FOUND^7 ^3"..item.count.."^7/^3"..amount.." "..tostring(items)) end + return true + else if Config.System.Debug then + print("^6Bridge^7: ^3HasItem^7: ^2"..tostring(items).." ^1NOT FOUND^7") end + return false + end + + elseif GetResourceState(QSInv):find("start") then + for _, itemData in pairs(exports[QSInv]:GetInventory(src)) do + if itemData and (itemData.name == items) then + --if Config.System.Debug then print("^6Bridge^7: ^3HasItem^7: ^2Item^7: '^3"..tostring(items).."^7' ^2Slot^7: ^3"..itemData.slot.." ^7x(^3"..tostring(itemData.amount).."^7)") end + count += (itemData.amount or 1) + end + end + if count >= amount then + if Config.System.Debug then print("^6Bridge^7: ^3HasItem^7: ^5FOUND^7 ^3"..count.."^7/^3"..amount.." "..tostring(items)) end + return true + else + if Config.System.Debug then print("^6Bridge^7: ^3HasItem^7: ^2"..tostring(items).." ^1NOT FOUND^7") end + return false + end + + elseif GetResourceState(CoreInv):find("start") then + local item = exports[CoreInv]:getItems('primary-'..src, items) + + if item.amount >= amount then + if Config.System.Debug then print("^6Bridge^7: ^3HasItem^7: ^5FOUND^7 ^3"..item.amount.."^7/^3"..amount.." "..tostring(items)) end + return true + else if Config.System.Debug then + print("^6Bridge^7: ^3HasItem^7: ^2"..tostring(items).." ^1NOT FOUND^7") end + return false + end + + elseif GetResourceState(CodeMInv):find("start") then + local success = exports["codem-inventory"]:CheckItemValid(src, items, amount) + if success then + if Config.System.Debug then print("^6Bridge^7: ^3HasItem^7: ^5FOUND^7 ^3"..amount.." "..tostring(items)) end + return true + end + + elseif GetResourceState(CodeMInv):find("start") then + for _, itemData in pairs(exports[CodeMInv]:GetUserInventory(src)) do + if itemData and (itemData.name == items) then + if Config.System.Debug then print("^6Bridge^7: ^3HasItem^7: ^2Item^7: '^3"..tostring(items).."^7' ^2Slot^7: ^3"..itemData.slot.." ^7x(^3"..tostring(itemData.amount).."^7)") end + count += (itemData.amount or 1) + end + end + if count >= amount then + if Config.System.Debug then print("^6Bridge^7: ^3HasItem^7: ^5FOUND^7 ^3"..count.."^7/^3"..amount.." "..tostring(items)) end + return true + else + if Config.System.Debug then print("^6Bridge^7: ^3HasItem^7: ^2"..tostring(items).." ^1NOT FOUND^7") end + return false + end + + else + for _, itemData in pairs(Core.Functions.GetPlayer(src).PlayerData.items) do + if itemData and (itemData.name == items) then + if Config.System.Debug then print("^6Bridge^7: ^3HasItem^7: ^2Item^7: '^3"..tostring(items).."^7' ^2Slot^7: ^3"..itemData.slot.." ^7x(^3"..tostring(itemData.amount).."^7)") end + count += (itemData.amount or 1) + end + end + if count >= amount then + if Config.System.Debug then print("^6Bridge^7: ^3HasItem^7: ^5FOUND^7 ^3"..count.."^7/^3"..amount.." "..tostring(items)) end + return true + else + if Config.System.Debug then print("^6Bridge^7: ^3HasItem^7: ^2"..tostring(items).." ^1NOT FOUND^7") end + return false + end + end + else + if GetResourceState(OXInv):find("start") then + local count = tonumber(exports[OXInv]:Search('count', items)) + local amount = (amount or 1) + if count >= amount then if Config.System.Debug then print("^6Bridge^7: ^3HasItem^7: ^5FOUND^7 ^3"..count.."^7/^3"..amount.." "..tostring(items)) end return true + else if Config.System.Debug then print("^6Bridge^7: ^3HasItem^7: ^2"..tostring(items).." ^1NOT FOUND^7") end return false end + + elseif GetResourceState(QSInv):find("start") then + for _, itemData in pairs(exports[QSInv]:GetInventory()) do + if itemData and (itemData.name == items) then + if Config.System.Debug then print("^6Bridge^7: ^3HasItem^7: ^2Item^7: '^3"..tostring(items).."^7' ^2Slot^7: ^3"..itemData.slot.." ^7x(^3"..tostring(itemData.amount).."^7)") end + count += (itemData.amount or 1) + end + end + if count >= amount then + if Config.System.Debug then print("^6Bridge^7: ^3HasItem^7: ^5FOUND^7 ^3"..count.."^7/^3"..amount.." "..tostring(items)) end + return true + else + if Config.System.Debug then print("^6Bridge^7: ^3HasItem^7: ^2"..tostring(items).." ^1NOT FOUND^7") end + return false + end + + elseif GetResourceState(CoreInv):find("start") then + for _, itemData in pairs(exports[CoreInv]:getInventory('primary-'..GetPlayerServerId(PlayerPedId()))) do + if itemData and (itemData.name == items) then + if Config.System.Debug then print("^6Bridge^7: ^3HasItem^7: ^2Item^7: '^3"..tostring(items).."^7' ^2Slot^7: ^3"..itemData.slot.." ^7x(^3"..tostring(itemData.amount).."^7)") end + count += (itemData.amount or 1) + end + end + if count >= amount then + if Config.System.Debug then print("^6Bridge^7: ^3HasItem^7: ^5FOUND^7 ^3"..count.."^7/^3"..amount.." "..tostring(items)) end + return true + else + if Config.System.Debug then print("^6Bridge^7: ^3HasItem^7: ^2"..tostring(items).." ^1NOT FOUND^7") end + return false + end + + elseif GetResourceState(CodeMInv):find("start") then + local success = exports[CodeMInv]:CheckItemValid(items, amount) + if success then + if Config.System.Debug then print("^6Bridge^7: ^3HasItem^7: ^5FOUND^7 ^3"..amount.." "..tostring(items)) end + return true + end + + elseif GetResourceState(QBInv):find("start") then + --if tonumber(GetResourceMetadata(QBInv, 'version')) <= 1.2 then + -- return exports[QBInv]:HasItem(items, amount) + --else + for _, itemData in pairs(Core.Functions.GetPlayerData().items) do + if itemData and (itemData.name == items) then + if Config.System.Debug then print("^6Bridge^7: ^3HasItem^7: ^2Item^7: '^3"..tostring(items).."^7' ^2Slot^7: ^3"..itemData.slot.." ^7x(^3"..tostring(itemData.amount).."^7)") end + count += (itemData.amount or 1) + end + end + if count >= amount then + if Config.System.Debug then + print("^6Bridge^7: ^3HasItem^7: ^5FOUND^7 ^3"..count.."^7/^3"..amount.." "..tostring(items)) + end + return true + else + if Config.System.Debug then + print("^6Bridge^7: ^3HasItem^7: ^2"..tostring(items).." ^1NOT FOUND^7") + end + return false + end + -- end + end + end +end + +-- Stash Items +function openStash(data) + if (data.job or data.gang) and not jobCheck(data.job or data.gang) then return end + if GetResourceState(OXInv):find("start") then + exports[OXInv]:openInventory('stash', data.stash) + elseif GetResourceState(CodeMInv):find("start") then + exports[CodeMInv]:OpenStash(data.stash, 400000, 100) + else + TriggerEvent("inventory:client:SetCurrentStash", data.stash) + TriggerServerEvent("inventory:server:OpenInventory", "stash", data.stash) + end + lookEnt(data.coords) +end + +function getStash(stashName) + local stashItems, items = {}, {} + if GetResourceState(OXInv):find("start") then + if Config.System.Debug then print("^6Bridge^7: ^2Retrieving ^3Stash^2 with ^7ox_inventory") end + stashItems = exports[OXInv]:Inventory(stashName).items + elseif GetResourceState(QSInv):find("start") then + if Config.System.Debug then print("^6Bridge^7: ^2Retrieving ^3Stash^2 with ^7qs-inventory") end + stashItems = exports[QSInv]:GetStashItems(stashName) + elseif GetResourceState(CodeMInv):find("start") then + if Config.System.Debug then print("^6Bridge^7: ^2Retrieving ^3Stash^2 with ^7qs-inventory") end + stashItems = exports[CodeMInv]:GetInventoryItems('Stash', stashName) + elseif GetResourceState(QBInv):find("start") then + if Config.System.Debug then print("^6Bridge^7: ^2Retrieving ^3Stash^2 with ^7qb-inventory") end + local result = MySQL.scalar.await('SELECT items FROM stashitems WHERE stash = ?', { stashName }) + if result then stashItems = json.decode(result) end + end + if stashItems then + for _, item in pairs(stashItems) do + local itemInfo = Items[item.name:lower()] + if itemInfo then + items[item.slot] = { + name = itemInfo["name"], + amount = tonumber(item.amount) or tonumber(item.count), + info = item.info ~= nil and item.info or "", + label = itemInfo["label"], + description = itemInfo["description"] ~= nil and itemInfo["description"] or "", + weight = itemInfo["weight"], + type = itemInfo["type"], + unique = itemInfo["unique"], + useable = itemInfo["useable"], + image = itemInfo["image"], + slot = item.slot, + } + end + end + if Config.System.Debug then print("^6Bridge^7: ^3GetStashItems^7: ^2Stash information for ^7'^6"..stashName.."^7' ^2retrieved^7") end + end + return items +end + +function stashRemoveItem(stashItems, stashName, items) local amount = amount and amount or 1 + if GetResourceState(OXInv):find("start") then + for k, v in pairs(items) do + exports[OXInv]:RemoveItem(stashName, k, v) + if Config.System.Debug then print("^6Bridge^7: ^2Removing item from ^3Stash^2 with ^7"..OXInv, k, v) end + end + elseif GetResourceState(QSInv):find("start") then + for k, v in pairs(items) do + exports[QSInv]:RemoveItemIntoStash(stashName, k, v) + if Config.System.Debug then print("^6Bridge^7: ^2Removing item from ^3Stash^2 with ^7"..QSInv, k, v) end + end + elseif GetResourceState(CodeMInv):find("start") then + for k, v in pairs(items) do + for l in pairs(stashItems) do + if stashItems[l].name == k then + if (stashItems[l].amount - v) <= 0 then + if Config.System.Debug then + print("^6Bridge^7: ^2None of this item left in stash ^3Stash^7", k, v) + end + stashItems[l] = nil + else + if Config.System.Debug then + print("^6Bridge^7: ^2Removing item from ^3Stash^2 with ^7"..CodeMInv, k, v) + end + stashItems[l].amount -= v + end + end + end + end + if Config.System.Debug then + print("^6Bridge^7: ^3saveStash^7: ^2Saving ^3QB^2 stash ^7'^6"..stashName.."^7'") + end + else + for k, v in pairs(items) do + for l in pairs(stashItems) do + if stashItems[l].name == k then + if (stashItems[l].amount - v) <= 0 then + if Config.System.Debug then + print("^6Bridge^7: ^2None of this item left in stash ^3Stash^7", k, v) + end + stashItems[l] = nil + else + if Config.System.Debug then + print("^6Bridge^7: ^2Removing item from ^3Stash^2 with ^7"..QBInv, k, v) + end + stashItems[l].amount -= v + end + end + end + end + if Config.System.Debug then + print("^6Bridge^7: ^3saveStash^7: ^2Saving ^3QB^2 stash ^7'^6"..stashName.."^7'") + end + MySQL.Async.insert('INSERT INTO stashitems (stash, items) VALUES (:stash, :items) ON DUPLICATE KEY UPDATE items = :items', { ['stash'] = stashName, ['items'] = json.encode(stashItems) }) + end +end +RegisterNetEvent(GetCurrentResourceName()..":server:stashRemoveItem", stashRemoveItem) + +function stashhasItem(stashItems, item, amount) local amount, count = amount and amount or 1, 0 + for k, itemData in pairs(stashItems) do + if itemData and (itemData.name == item) then + --if Config.System.Debug then + -- print("^6Bridge^7: ^3stashHasItem^7: ^2Item^7: '^3"..tostring(item).."^7' ^2Slot^7: ^3"..itemData.slot.." ^7x(^3"..tostring(itemData.amount).."^7)") + --end + count += (itemData.amount or 1) + end + end + if count >= amount then + if Config.System.Debug then + print("^6Bridge^7: ^3stashHasItem^7: ^2Items ^3"..item.." ^5FOUND^7 x^3"..count.."^7/^3"..amount.."^7") end + return + true + else + if Config.System.Debug then print("^6Bridge^7: ^3stashHasItem^7: ^2Items ^1NOT FOUND^7 "..json.encode(item)) end + return false + end +end \ No newline at end of file diff --git a/exports.lua b/exports.lua new file mode 100644 index 0000000..1a92d42 --- /dev/null +++ b/exports.lua @@ -0,0 +1,19 @@ +Exports = { + QBExport = "qb-core", + QBXExport = "qbx_core", + ESXExport = "es_extended", + OXCoreExport = "ox_core", + + OXInv = "ox_inventory", + QBInv = "qb-inventory", + QSInv = "qs-inventory", + CoreInv = "core-inventory", + CodeMInv = "codem-inventory", + + OXLibExport = "ox_lib", + + QBMenuExport = "qb-menu", + + QBTargetExport = "qb-target", + OXTargetExport = "ox_target" +} \ No newline at end of file diff --git a/functions.lua b/functions.lua new file mode 100644 index 0000000..c67f984 --- /dev/null +++ b/functions.lua @@ -0,0 +1,784 @@ +onDuty = false +function jobCheck(job) + canDo = true + if not hasJob(job) or not onDuty then + triggerNotify(nil, Loc[Config.Lan].error["not_clockedin"]) + canDo = false + end + return canDo +end + +local time = 100 +function loadModel(model) + if not HasModelLoaded(model) then if Config.System.Debug then print("^6Bridge^7: ^2Loading Model^7: '^6"..model.."^7'") end + while not HasModelLoaded(model) do if time > 0 then time = time - 1 RequestModel(model) + else time = 1000 print("^6Bridge^7: ^3LoadModel^7: ^2Timed out loading model ^7'^6"..model.."^7'") break end + Wait(10) end + end +end +function unloadModel(model) if Config.System.Debug then print("^6Bridge^7: ^2Removing Model^7: '^6"..model.."^7'") end SetModelAsNoLongerNeeded(model) end +function loadAnimDict(dict) if Config.System.Debug then print("^6Bridge^7: ^2Loading Anim Dictionary^7: '^6"..dict.."^7'") end while not HasAnimDictLoaded(dict) do RequestAnimDict(dict) Wait(5) end end +function unloadAnimDict(dict) if Config.System.Debug then print("^6Bridge^7: ^2Removing Anim Dictionary^7: '^6"..dict.."^7'") end RemoveAnimDict(dict) end +function loadPtfxDict(dict) if Config.System.Debug then if not HasNamedPtfxAssetLoaded(dict) then print("^6Bridge^7: ^2Loading Ptfx Dictionary^7: '^6"..dict.."^7'") end end while not HasNamedPtfxAssetLoaded(dict) do RequestNamedPtfxAsset(dict) Wait(5) end end +function unloadPtfxDict(dict) if Config.System.Debug then print("^6Bridge^7: ^2Removing Ptfx Dictionary^7: '^6"..dict.."^7'") end RemoveNamedPtfxAsset(dict) end +function loadTextureDict(dict) if Config.System.Debug then print("^6Bridge^7: ^2Loading Texture Dictionary^7: '^6"..dict.."^7'") end while not HasStreamedTextureDictLoaded(dict) do RequestNamedPtfxAsset(dict) Wait(5) end end + +function countTable(table) local i = 0 for keys in pairs(table) do i += 1 end return i end + +function pairsByKeys(t) local a = {} for n in pairs(t) do a[#a+1] = n end table.sort(a) local i = 0 local iter = function() i += 1 if a[i] == nil then return nil else return a[i], t[a[i]] end end return iter end + +function playAnim(animDict, animName, duration, flag, ped) + loadAnimDict(animDict) + TaskPlayAnim(ped and ped or PlayerPedId(), animDict, animName, 1.0, -1.0, duration or 30000, flag or 50, 1, false, false, false) +end + +function stopAnim(animDict, animName) + StopAnimTask(PlayerPedId(), animName, animDict) + unloadAnimDict(animDict) +end + +function makeVeh(model, coords) + loadModel(model) + local veh = CreateVehicle(model, coords.x, coords.y, coords.z, coords.w, true, false) + SetVehicleHasBeenOwnedByPlayer(veh, true) + SetNetworkIdCanMigrate(NetworkGetNetworkIdFromEntity(veh), true) + Wait(100) + SetVehicleNeedsToBeHotwired(veh, false) + SetVehRadioStation(veh, 'OFF') + SetVehicleFuelLevel(veh, 100.0) + SetVehicleModKit(veh, 0) + SetVehicleOnGroundProperly(veh) + if Config.System.Debug then + local coords = { string.format("%.2f", coords.x), string.format("%.2f", coords.y), string.format("%.2f", coords.z), (string.format("%.2f", coords.w or 0.0)) } + print("^6Bridge^7: ^1Veh ^2Created^7: '^6"..veh.."^7' | ^2Hash^7: ^7'^6"..(model).."^7' | ^2Coord^7: ^5vec4^7(^6"..(coords[1]).."^7, ^6"..(coords[2]).."^7, ^6"..(coords[3]).."^7, ^6"..(coords[4]).."^7)") + end + unloadModel(model) + return veh +end + +local Peds = {} +local Props = {} +function makePed(model, coords, freeze, collision, scenario, anim, synced) + loadModel(model) + local ped = CreatePed(0, model, coords.x, coords.y, coords.z-1.03, coords.w, synced and synced or true, false) + SetEntityInvincible(ped, true) + SetBlockingOfNonTemporaryEvents(ped, true) + FreezeEntityPosition(ped, freeze and freeze or true) + + if collision then SetEntityNoCollisionEntity(ped, PlayerPedId(), false) end + if scenario then TaskStartScenarioInPlace(ped, scenario, 0, true) end + if anim then + loadAnimDict(anim[1]) + TaskPlayAnim(ped, anim[1], anim[2], 0.5, 1.0, -1, 1, 0.2, 0, 0, 0) + end + if Config.System.Debug then + local coords = { string.format("%.2f", coords.x), string.format("%.2f", coords.y), string.format("%.2f", coords.z), (string.format("%.2f", coords.w or 0.0)) } + print("^6Bridge^7: ^1Ped ^2Created^7: '^6"..ped.."^7' | ^2Hash^7: ^7'^6"..(model).."^7' | ^2Coord^7: ^5vec4^7(^6"..(coords[1]).."^7, ^6"..(coords[2]).."^7, ^6"..(coords[3]).."^7, ^6"..(coords[4]).."^7)") + end + unloadModel(model) + Peds[#Peds+1] = ped + return ped +end + +function makeProp(data, freeze, synced) + loadModel(data.prop) + local prop = CreateObject(data.prop, data.coords.x, data.coords.y, data.coords.z-1.03, synced or false, synced or false, false) + SetEntityHeading(prop, data.coords.w + 180.0) + FreezeEntityPosition(prop, freeze and freeze or 0) + if Config.System.Debug then + local coords = { string.format("%.2f", data.coords.x), string.format("%.2f", data.coords.y), string.format("%.2f", data.coords.z), (string.format("%.2f", data.coords.w or 0.0)) } + print("^6Bridge^7: ^1Prop ^2Created^7: '^6"..prop.."^7' | ^2Hash^7: ^7'^6"..(data.prop).."^7' | ^2Coord^7: ^5vec4^7(^6"..(coords[1]).."^7, ^6"..(coords[2]).."^7, ^6"..(coords[3]).."^7, ^6"..(coords[4]).."^7)") + end + unloadModel(data.prop) + Props[#Props+1] = prop + return prop +end + +AddEventHandler('onResourceStop', function(r) + if r ~= GetCurrentResourceName() then return end + stopSpinner() + for i = 1, #Peds do DeletePed(Peds[i]) end + for i = 1, #Props do destroyProp(Props[i]) end +end) + +function instantLookEnt(ent, ent2) + local p1 = GetEntityCoords(ent, true) + local p2 = GetEntityCoords(ent2, true) + + local dx = p2.x - p1.x + local dy = p2.y - p1.y + + local heading = GetHeadingFromVector_2d(dx, dy) + SetEntityHeading( ent, heading ) +end + +function lookEnt(entity) local ped = PlayerPedId() + if entity then + if type(entity) == "vector3" or type(entity) == "vector4" then + if not IsPedHeadingTowardsPosition(ped, entity.xyz, 30.0) then + TaskTurnPedToFaceCoord(ped, entity.xyz, 1500) + if Config.System.Debug then print("^6Bridge^7: ^2Turning Player to^7: '^6"..json.encode(entity).."^7'") end + Wait(1500) + end + else + if DoesEntityExist(entity) then + if not IsPedHeadingTowardsPosition(ped, GetEntityCoords(entity), 30.0) then + TaskTurnPedToFaceCoord(ped, GetEntityCoords(entity), 1500) + if Config.System.Debug then print("^6Bridge^7: ^2Turning Player to^7: '^6"..entity.."^7'") end + Wait(1500) + end + end + end + end +end + +function destroyProp(entity) + if Config.System.Debug then print("^6Bridge^7: ^2Destroying Prop^7: '^6"..entity.."^7'") end + if IsEntityAttachedToEntity(entity, PlayerPedId()) then + SetEntityAsMissionEntity(entity) + DetachEntity(entity, true, true) + end + DeleteObject(entity) +end + +function pushVehicle(entity) + SetVehicleModKit(entity, 0) + if entity ~= 0 and DoesEntityExist(entity) then + if not NetworkHasControlOfEntity(entity) then + if Config.System.Debug then print("^6Bridge^7: ^3pushVehicle^7: ^2Requesting network control of vehicle^7.") end + NetworkRequestControlOfEntity(entity) + local timeout = 2000 + while timeout > 0 and not NetworkHasControlOfEntity(entity) do + Wait(100) + timeout = timeout - 100 + end + if NetworkHasControlOfEntity(entity) and Config.System.Debug then print("^6Bridge^7: ^3pushVehicle^7: ^2Network has control of entity^7.") end + end + if not IsEntityAMissionEntity(entity) then + if Config.System.Debug then print("^6Bridge^7: ^3pushVehicle^7: ^2Setting vehicle as a ^7'^2mission^7' &2entity^7.") end + SetEntityAsMissionEntity(entity, true, true) + local timeout = 2000 + while timeout > 0 and not IsEntityAMissionEntity(entity) do + Wait(100) + timeout = timeout - 100 + end + if IsEntityAMissionEntity(entity) and Config.System.Debug then print("^6Bridge^7: ^3pushVehicle^7: ^2Vehicle is a ^7'^2mission^7'^2 entity^7.") end + end + end +end + +function makeBlip(data) + local blip = AddBlipForCoord(data.coords) + SetBlipAsShortRange(blip, true) + SetBlipSprite(blip, data.sprite or 106) + SetBlipColour(blip, data.col or 5) + SetBlipScale(blip, data.scale or 0.7) + SetBlipDisplay(blip, (data.disp or 6)) + if data.category then SetBlipCategory(blip, data.category) end + BeginTextCommandSetBlipName('STRING') + AddTextComponentString(tostring(data.name)) + EndTextCommandSetBlipName(blip) + if Config.System.Debug then print("^6Bridge^7: ^6Blip ^2created for location^7: '^6"..data.name.."^7'") end + return blip +end + +function makeEntityBlip(data) + AddBlipForEntity(data.entity) + local blip = GetBlipFromEntity(data.entity) + SetBlipAsShortRange(blip, true) + SetBlipSprite(blip, data.sprite or 106) + SetBlipColour(blip, data.col or 5) + SetBlipScale(blip, data.scale or 0.7) + SetBlipDisplay(blip, (data.disp or 6)) + if data.category then SetBlipCategory(blip, data.category) end + BeginTextCommandSetBlipName('STRING') + AddTextComponentString(tostring(data.name)) + EndTextCommandSetBlipName(blip) + if Config.System.Debug then print("^6Bridge^7: ^6Blip ^2created for Entity^7: '^6"..data.name.."^7'") end + return blip +end + +function lockInv(toggle) + FreezeEntityPosition(PlayerPedId(), toggle) + LocalPlayer.state:set("inv_busy", toggle, true) + TriggerEvent('inventory:client:busy:status', toggle) + TriggerEvent('canUseInventoryAndHotbar:toggle', not toggle) +end + +function createTempCam(ent, coords) + local cam = nil + if Config.Crafting.craftCam then + if Config.System.Debug then + triggerNotify(nil, "ModCam Created", "success") + end + local camCoords = GetOffsetFromEntityInWorldCoords(ent, 1.2, -0.3, 0.8) + --local pedCoords = GetEntityCoords(PlayerPedId()) + cam = CreateCamWithParams("DEFAULT_SCRIPTED_CAMERA", camCoords.x, camCoords.y, camCoords.z+0.5, 1.0, 0.0, 0.0, 60.00, false, 0) + PointCamAtCoord(cam, coords) + end + return cam +end + +function keyGen() + local charset = { + "q","w","e","r","t","y","u","i","o","p","a","s","d","f","g","h","j","k","l","z","x","c","v","b","n","m", + "Q","W","E","R","T","Y","U","I","O","P","A","S","D","F","G","H","J","K","L","Z","X","C","V","B","N","M", + "1","2","3","4","5","6","7","8","9","0" + } + local GeneratedID = "" + for i = 1, 3 do GeneratedID = GeneratedID..charset[math.random(1, #charset)] end + return GeneratedID +end + +function startTempCam(cam) + if Config.Crafting.craftCam then + SetCamActive(cam, true) + RenderScriptCams(true, true, 1000, true, true) + end +end +function stopTempCam() + if Config.Crafting.craftCam then + CreateThread(function() + Wait(1000) + RenderScriptCams(false, true, 500, true, true) + DestroyAllCams() + end) + end +end + +local inProgress = false +function progressBar(data) + local result = nil + if data.cam then + startTempCam(data.cam) + end + if Config.System.ProgressBar == "ox" then + if exports[OXLibExport]:progressBar({ + duration = Config.System.Debug and 1000 or data.time, + label = data.label, + useWhileDead = data.dead and data.dead or false, + canCancel = data.cancel and data.cancel or true, + anim = { + dict = data.dict, + clip = data.anim, + flag = (data.flag == 8 and 32 or data.flag) or nil, + scenario = data.task + }, + disable = { + combat = true + }, + }) then + result = true + lockInv(false) + if data.cam then stopTempCam(data.cam) end + else + result = false + lockInv(false) + if data.cam then stopTempCam(data.cam) end + end + elseif Config.System.ProgressBar == "qb" then + Core.Functions.Progressbar("mechbar", + data.label, + Config.System.Debug and 1000 or data.time, + data.dead and data.dead or false, + data.cancel or true, + { disableMovement = true, disableCarMovement = true, disableMouse = false, disableCombat = true, }, + { animDict = data.dict, anim = data.anim, flags = data.flag and data.flag or 32, task = data.task }, {}, {}, + function() + result = true + lockInv(false) + if data.cam then + stopTempCam(data.cam) + end + end, function() + result = false + lockInv(false) + if data.cam then + stopTempCam(data.cam) + end + end, data.icon) + elseif Config.System.ProgressBar == "gta" then + + --local wait, inProgress = (Config.System.Debug and 1000 or data.time), true + local wait = data.time + inProgress = true + if not (data.dead and data.dead or false) then + lockInv(true) + displaySpinner(data.label) + local ped = PlayerPedId() + if data.dict then + playAnim(data.dict, data.anim, -1, (data.flag == 8 and 32 or data.flag) or nil) + end + if data.task then + TaskStartScenarioInPlace(ped, data.task, -1, true) + end + while inProgress and wait > 0 do wait -= 15 + local waitTimer = 0 + DisablePlayerFiring(ped, true) + DisableControlAction(0, 25, true) + DisableControlAction(0, 21, true) + DisableControlAction(0, 30, true) + DisableControlAction(0, 31, true) + DisableControlAction(0, 36, true) + if data.cam ~= nil then + DisableControlAction(0, 1, true) + DisableControlAction(0, 2, true) + DisableControlAction(0, 106, true) + end + if data.cancel then + if IsControlJustReleased(0, 202) or IsControlJustReleased(0, 77) then + inProgress = false + waitTimer = 1500 + displaySpinner(Loc[Config.Lan].error["cancel"]) + end + end + Wait(waitTimer) + end + inProgress = false + if data.cam then stopTempCam(data.cam) end + if data.dict then stopAnim(data.dict, data.anim, ped) end + ClearPedTasks(ped) + end + lockInv(false) + stopSpinner() + result = (wait <= 0) + end + while result == nil do Wait(10) end + return result +end + +function displaySpinner(text) + BeginTextCommandBusyspinnerOn('STRING') + AddTextComponentSubstringPlayerName(text) + EndTextCommandBusyspinnerOn(4) +end + +function stopSpinner() if not IsDuplicityVersion() then BusyspinnerOff() end end + +function stopPropgressBar() + if Config.System.ProgressBar == "ox" then + exports[OXLibExport]:cancelProgress() + elseif Config.System.ProgressBar == "qb" then + TriggerEvent("progressbar:client:cancel") + elseif Config.System.ProgressBar == "gta" then + inProgress = false + BusyspinnerOff() + end +end + +-- [[ OTHER ]] -- +function washHands(data) + lookEnt(data.coords) + local cam = createTempCam(PlayerPedId(), data.coords) + if progressBar({ + label = Loc[Config.Lan].progressbar["progress_washing"], + time = 5000, + cancel = true, + dict = "mp_arresting", + anim = "a_uncuff", + flag = 32, + icon = "fas fa-hand-holding-droplet", + cam = cam + }) then + triggerNotify(nil, Loc[Config.Lan].success["washed_hands"], "success") + else + triggerNotify(nil, Loc[Config.Lan].error["cancel"], 'error') + end + ClearPedTasks(PlayerPedId()) +end + +function useToilet(data) + if data.urinal then + if progressBar({ + label = "Using Urinal", + time = 5000, + cancel = true, + dict = "misscarsteal2peeing", + anim = "peeing_loop", + flag = 32 + }) then + TriggerServerEvent(GetCurrentResourceName().."server:Urinal")else + lockInv(false) + triggerNotify(nil, Loc[Config.Lan].error["cancelled"], 'error') + end + else + TaskStartScenarioAtPosition(PlayerPedId(), "PROP_HUMAN_SEAT_CHAIR_MP_PLAYER", data.sitcoords.x, data.sitcoords.y, data.sitcoords.z, data.sitcoords[4], 0, 1, true) + if progressBar({ + label = "Using Toilet", + time = 10000, + cancel = true + }) then + TriggerServerEvent(GetCurrentResourceName().."server:Urinal") + ClearPedTasks(PlayerPedId()) + else + lockInv(false) + triggerNotify(nil, Loc[Config.Lan].error["cancelled"], 'error') + end + end +end + +RegisterNetEvent(GetCurrentResourceName()..":server:Urinal", function() + local src = source + local Player = getPlayer(src) + local thirstamt = math.random(10,30) + local thirst = Player.thirst - thirstamt + setThirst(src, getPlayer(src).thirst - thirst) +end) + +RegisterNetEvent(GetCurrentResourceName()..":server:setNeed", function(type, amount) local src = source + if type == "thirst" then + setThirst(src, amount) + elseif type == "thirst" then + setHunger(src, amount) + end +end) + +function setThirst(src, thirst) + if GetResourceState(ESXExport):find("start") then + TriggerClientEvent('esx_status:add', src, 'thirst', thirst) + elseif GetResourceState(QBExport):find("start") or GetResourceState(QBXExport):find("start") then + local Player = QBCore.Functions.GetPlayer(src) + Player.Functions.SetMetaData('thirst', thirst) + TriggerClientEvent("hud:client:UpdateNeeds", src, thirst, Player.PlayerData.metadata.thirst) + end +end + +function setHunger(src, hunger) + if GetResourceState(ESXExport):find("start") then + TriggerClientEvent('esx_status:add', src, 'hunger', hunger) + elseif GetResourceState(QBExport):find("start") or GetResourceState(QBXExport):find("start") then + local Player = QBCore.Functions.GetPlayer(src) + Player.Functions.SetMetaData('hunger', hunger) + TriggerClientEvent("hud:client:UpdateNeeds", src, hunger, Player.PlayerData.metadata.hunger) + end +end + +function useDoor(data) + DoScreenFadeOut(500) + while not IsScreenFadedOut() do Wait(10) end + SetEntityCoords(PlayerPedId(), data.telecoords.xyz, 0, 0, 0, false) + SetEntityHeading(PlayerPedId(), data.telecoords.w) + DoScreenFadeIn(1000) + Wait(100) +end + +-- [[CONSUME]] -- +function ConsumeSuccess(itemName, type) + ExecuteCommand("e c") + toggleItem(false, itemName, 1) + if GetResourceState(ESXEport):find("start") then + if Items[itemName].hunger then + TriggerServerEvent(GetCurrentResourceName()..":server:setNeed", "hunger", Items[itemName].hunger * 10000) + end + if Items[itemName].thirst then + TriggerServerEvent(GetCurrentResourceName()..":server:setNeed", "thirst", Items[itemName].thirst * 10000) + end + else + if Items[itemName].hunger then + TriggerServerEvent(GetCurrentResourceName()..":server:setNeed", "hunger", Core.Functions.GetPlayerData().metadata["hunger"] + Items[itemName].hunger) + end + if Items[itemName].thirst then + TriggerServerEvent(GetCurrentResourceName()..":server:setNeed", "thirst", Core.Functions.GetPlayerData().metadata["thirst"] + Items[itemName].thirst) + end + end + if type == "alcohol" then alcoholCount += 1 + if alcoholCount > 1 and alcoholCount < 4 then TriggerEvent("evidence:client:SetStatus", "alcohol", 200) elseif alcoholCount >= 4 then TriggerEvent("evidence:client:SetStatus", "heavyalcohol", 200) AlienEffect() end + end + if Config.RewardItem == itemName then toggleItem(true, Config.RewardPool[math.random(1, #Config.RewardPool)], 1) end +end + +function addItem(item, amount, info) + TriggerServerEvent(GetCurrentResourceName()..":server:toggleItem", true, item, amount) +end + +function removeItem(item, amount) + TriggerServerEvent(GetCurrentResourceName()..":server:toggleItem", false, item, amount) +end + +RegisterNetEvent(GetCurrentResourceName()..":server:toggleItem", function(give, item, amount, newsrc) + local src = newsrc or source + if Config.System.Debug then + print("^6Bridge^7: ^3toggleItem ^2triggered^7: ^6"..(tostring(give) == "true" and "addItem" or "removeItem").."^7 - ['^8"..tostring(item).."^7'] x"..(tostring(amount) or "1")) + end + local remamount = (amount and amount or 1) + if item == nil then return end + if give == 0 or give == false then + if hasItem(item, amount and amount or 1, src) then -- check if you still have the item + if GetResourceState(OXInv):find("start") then + local success = exports[OXInv]:RemoveItem(src, item, (amount and amount or 1), nil) + elseif GetResourceState(QSInv):find("start") then + local success = exports[QSInv]:RemoveItem(src, item, amount) + elseif GetResourceState(CoreInv):find("start") then + local success = exports[CoreInv]:removeItemExact('primary-'..src, item, amount) + elseif GetResourceState(CodeMInv):find("start") then + local success = exports[CodeMInv]:RemoveItem(src, item, amount) + elseif GetResourceState(QBInv):find("start") then + while remamount > 0 do + if Core.Functions.GetPlayer(src).Functions.RemoveItem(item, 1) then end + remamount -= 1 + end + if Config.Crafting.showItemBox then + TriggerClientEvent('inventory:client:ItemBox', src, Items[item], "remove", (amount and amount or 1)) + end + end + if Config.System.Debug then + print("^6Bridge^7: ^1Removing ^2from Player^7(^2"..src.."^7) '^6"..Items[item].label.."^7(^2x^6"..((amount and amount or "1")).."^7)'") + end + else + dupeWarn(src, item) -- if not boot the player + end + else + local amount = amount and amount or 1 + if GetResourceState(OXInv):find("start") then + local success = exports[OXInv]:AddItem(src, item, amount or 1, nil) + if Config.System.Debug then + print("^6Bridge^7: ^4Giving ^2Player^7(^2"..src.."^7) '^6"..Items[item].label.."^7(^2x^6"..((amount and amount or "1")).."^7) ^1OX^7'") + end + elseif GetResourceState(QSInv):find("start") then + local success = exports[QSInv]:AddItem(src, item, amount) + if Config.System.Debug then + print("^6Bridge^7: ^4Giving ^2Player^7(^2"..src.."^7) '^6"..Items[item].label.."^7(^2x^6"..((amount and amount or "1")).."^7) ^1QS^7'") + end + elseif GetResourceState(CoreInv):find("start") then + local success = exports[CoreInv]:addItem('primary-'..src, item, amount) + if Config.System.Debug then + print("^6Bridge^7: ^4Giving ^2Player^7(^2"..src.."^7) '^6"..Items[item].label.."^7(^2x^6"..((amount and amount or "1")).."^7) ^1Core^7'") + end + elseif GetResourceState(CodeMInv):find("start") then + local success = exports[CodeMInv]:AddItem(src, item, amount) + elseif GetResourceState(QBInv):find("start") then + if Core.Functions.GetPlayer(src).Functions.AddItem(item, amount or 1) then + --if Config.Crafting.showItemBox then + TriggerClientEvent("inventory:client:ItemBox", src, Items[item], "add", amount and amount or 1) + --end + end + end + end +end) + +--Item Exploit protection +function dupeWarn(src, item) + print("^5DupeWarn^7: (^1"..tostring(src).."^7) ^2Tried to remove item ^7('^3"..item.."^7')^2 but it wasn't there^7") + if Config.System.Debug == false then + DropPlayer(src, src.." ^1Kicked for attempting to duplicate items") + end + print("^5DupeWarn:^7: (^1"..tostring(src).."^7) ^2Dropped from server for item duplicating^7") +end + + +function toggleDuty() + if GetResourceState(QBExport):find("start") then + TriggerServerEvent("QBCore:ToggleDuty") + else + onDuty = not onDuty + if onDuty then + triggerNotify(nil, "Now on duty", "success") + else + triggerNotify(nil, "Now off duty", "success") + end + end +end + +local function CheckVersion() + if IsDuplicityVersion() then + PerformHttpRequest('https://raw.githubusercontent.com/jimathy/UpdateVersions/master/'..GetCurrentResourceName()..'.txt', function(err, newestVersion, headers) + if not newestVersion then print("Currently unable to run a version check.") return end + local currentVersion = "^3"..GetResourceMetadata(GetCurrentResourceName(), 'version'):gsub("%.", "^7.^3").."^7" + newestVersion = "^3"..newestVersion:sub(1, -2):gsub("%.", "^7.^3").."^7" + print("^6Version Check^7: ^2Running^7: "..currentVersion.." ^2Latest^7: "..newestVersion) + print(newestVersion == currentVersion and '^6You are running the latest version.^7 ('..currentVersion..')' or "^1You are currently running an outdated version^7, ^1please update^7!") + end) + end +end +CheckVersion() + +--Screen Effects +local alienEffect = false +function AlienEffect() + if alienEffect then return else alienEffect = true end + if Config.System.Debug then print("^5Debug^7: ^3AlienEffect^7() ^2activated") end + AnimpostfxPlay("DrugsMichaelAliensFightIn", 3.0, 0) + Wait(math.random(5000, 8000)) + local Ped = PlayerPedId() + local animDict = "MOVE_M@DRUNK@VERYDRUNK" + loadAnimDict(animDict) + SetPedCanRagdoll(Ped, true) + ShakeGameplayCam('DRUNK_SHAKE', 2.80) + SetTimecycleModifier("Drunk") + SetPedMovementClipset(Ped, animDict, 1) + SetPedMotionBlur(Ped, true) + SetPedIsDrunk(Ped, true) + Wait(1500) + SetPedToRagdoll(Ped, 5000, 1000, 1, 0, 0, 0) + Wait(13500) + SetPedToRagdoll(Ped, 5000, 1000, 1, 0, 0, 0) + Wait(120500) + ClearTimecycleModifier() + ResetScenarioTypesEnabled() + ResetPedMovementClipset(Ped, 0) + SetPedIsDrunk(Ped, false) + SetPedMotionBlur(Ped, false) + AnimpostfxStopAll() + ShakeGameplayCam('DRUNK_SHAKE', 0.0) + AnimpostfxPlay("DrugsMichaelAliensFight", 3.0, 0) + Wait(math.random(45000, 60000)) + AnimpostfxPlay("DrugsMichaelAliensFightOut", 3.0, 0) + AnimpostfxStop("DrugsMichaelAliensFightIn") + AnimpostfxStop("DrugsMichaelAliensFight") + AnimpostfxStop("DrugsMichaelAliensFightOut") + alienEffect = false + if Config.System.Debug then print("^5Debug^7: ^3AlienEffect^7() ^2stopped") end +end +local weedEffect = false +function WeedEffect() + if weedEffect then return else weedEffect = true end + if Config.System.Debug then print("^5Debug^7: ^3WeedEffect^7() ^2activated") end + AnimpostfxPlay("DrugsMichaelAliensFightIn", 3.0, 0) + Wait(math.random(3000, 20000)) + AnimpostfxPlay("DrugsMichaelAliensFight", 3.0, 0) + Wait(math.random(15000, 20000)) + AnimpostfxPlay("DrugsMichaelAliensFightOut", 3.0, 0) + AnimpostfxStop("DrugsMichaelAliensFightIn") + AnimpostfxStop("DrugsMichaelAliensFight") + AnimpostfxStop("DrugsMichaelAliensFightOut") + weedEffect = false + if Config.System.Debug then print("^5Debug^7: ^3WeedEffect^7() ^2stopped") end +end +local trevorEffect = false +function TrevorEffect() + if trevorEffect then return else trevorEffect = true end + if Config.System.Debug then print("^5Debug^7: ^3TrevorEffect^7() ^2activated") end + AnimpostfxPlay("DrugsTrevorClownsFightIn", 3.0, 0) + Wait(3000) + AnimpostfxPlay("DrugsTrevorClownsFight", 3.0, 0) + Wait(30000) + AnimpostfxPlay("DrugsTrevorClownsFightOut", 3.0, 0) + AnimpostfxStop("DrugsTrevorClownsFight") + AnimpostfxStop("DrugsTrevorClownsFightIn") + AnimpostfxStop("DrugsTrevorClownsFightOut") + trevorEffect = false + if Config.System.Debug then print("^5Debug^7: ^3TrevorEffect^7() ^2stopped") end +end +local turboEffect = false +function TurboEffect() + if turboEffect then return else turboEffect = true end + if Config.System.Debug then print("^5Debug^7: ^3TurboEffect^7() ^2activated") end + AnimpostfxPlay('RaceTurbo', 0, true) + SetTimecycleModifier('rply_motionblur') + ShakeGameplayCam('SKY_DIVING_SHAKE', 0.25) + Wait(30000) + StopGameplayCamShaking(true) + SetTransitionTimecycleModifier('default', 0.35) + Wait(1000) + ClearTimecycleModifier() + AnimpostfxStop('RaceTurbo') + turboEffect = false + if Config.System.Debug then print("^5Debug^7: ^3TurboEffect^7() ^2stopped") end +end +local rampageEffect = false +function RampageEffect() + if rampageEffect then return else rampageEffect = true end + if Config.System.Debug then print("^5Debug^7: ^3RampageEffect^7() ^2activated") end + AnimpostfxPlay('Rampage', 0, true) + SetTimecycleModifier('rply_motionblur') + ShakeGameplayCam('SKY_DIVING_SHAKE', 0.25) + Wait(30000) + StopGameplayCamShaking(true) + SetTransitionTimecycleModifier('default', 0.35) + Wait(1000) + ClearTimecycleModifier() + AnimpostfxStop('Rampage') + rampageEffect = false + if Config.System.Debug then print("^5Debug^7: ^3RampageEffect^7() ^2stopped") end +end +local focusEffect = false +function FocusEffect() + if focusEffect then return else focusEffect = true end + if Config.System.Debug then print("^5Debug^7: ^3FocusEffect^7() ^2activated") end + Wait(1000) + AnimpostfxPlay('FocusIn', 0, true) + Wait(30000) + AnimpostfxStop('FocusIn') + focusEffect = false + if Config.System.Debug then print("^5Debug^7: ^3FocusEffect^7() ^2stopped") end +end +local NightVisionEffect = false +function NightVisionEffect() + if NightVisionEffect then return else NightVisionEffect = true end + if Config.System.Debug then print("^5Debug^7: ^3NightVisionEffect^7() ^2activated") end + SetNightvision(true) + Wait(math.random(3000, 4000)) -- FEEL FREE TO CHANGE THIS + SetNightvision(false) + SetSeethrough(false) + NightVisionEffect = false + if Config.System.Debug then print("^5Debug^7: ^3NightVisionEffect^7() ^2stopped") end +end +local thermalEffect = false +function ThermalEffect() + if thermalEffect then return else thermalEffect = true end + if Config.System.Debug then print("^5Debug^7: ^3ThermalEffect^7() ^2activated") end + SetNightvision(true) + SetSeethrough(true) + Wait(math.random(2000, 3000)) -- FEEL FREE TO CHANGE THIS + SetNightvision(false) + SetSeethrough(false) + thermalEffect = false + if Config.System.Debug then print("^5Debug^7: ^3ThermalEffect^7() ^2stopped") end +end + +--Built-in Buff effects +local healEffect = false +function HealEffect(data) + if healEffect then return end + if Config.System.Debug then print("^5Debug^7: ^3HealEffect^7() ^2activated") end + healEffect = true + local count = (data[1] / 1000) + while count > 0 do + Wait(1000) + count -= 1 + SetEntityHealth(PlayerPedId(), GetEntityHealth(PlayerPedId()) + data[2]) + end + healEffect = false + if Config.System.Debug then print("^5Debug^7: ^3HealEffect^7() ^2stopped") end +end + +local staminaEffect = false +function StaminaEffect(data) + if staminaEffect then return end + if Config.System.Debug then print("^5Debug^7: ^3StaminaEffect^7() ^2activated") end + staminaEffect = true + local startStamina = (data[1] / 1000) + SetRunSprintMultiplierForPlayer(PlayerId(), 1.49) + while startStamina > 0 do + Wait(1000) + if math.random(5, 100) < 10 then RestorePlayerStamina(PlayerId(), data[2]) end + startStamina -= 1 + if math.random(5, 100) < 51 then end + end + startStamina = 0 + SetRunSprintMultiplierForPlayer(PlayerId(), 1.0) + staminaEffect = false + if Config.System.Debug then print("^5Debug^7: ^3StaminaEffect^7() ^2stopped") end +end + +function StopEffects() -- Used to clear up any effects stuck on screen + if Config.System.Debug then print("^5Debug^7: ^2All screen effects stopped") end + ShakeGameplayCam('DRUNK_SHAKE', 0.0) + SetPedToRagdoll(PlayerPedId(), 5000, 1000, 1, 0, 0, 0) + ClearTimecycleModifier() + ResetScenarioTypesEnabled() + ResetPedMovementClipset(PlayerPedId(), 0) + SetPedIsDrunk(PlayerPedId(), false) + SetPedMotionBlur(PlayerPedId(), false) + SetNightvision(false) + SetSeethrough(false) + AnimpostfxStop("DrugsMichaelAliensFightIn") + AnimpostfxStop("DrugsMichaelAliensFight") + AnimpostfxStop("DrugsMichaelAliensFightOut") + AnimpostfxStop("DrugsTrevorClownsFight") + AnimpostfxStop("DrugsTrevorClownsFightIn") + AnimpostfxStop("DrugsTrevorClownsFightOut") + AnimpostfxStop('RaceTurbo') + AnimpostfxStop('FocusIn') + AnimpostfxStop('Rampage') +end \ No newline at end of file diff --git a/fxmanifest.lua b/fxmanifest.lua new file mode 100644 index 0000000..338c4d3 --- /dev/null +++ b/fxmanifest.lua @@ -0,0 +1,14 @@ +name "Jim_Bridge" +author "Jimathy" +version "help" +description "Framework Bridge By Jimathy" +fx_version "cerulean" +game "gta5" +lua54 'yes' + +files { + 'exports.lua', + 'functions.lua', + 'wrapper.lua', + 'crafting.lua', +} \ No newline at end of file diff --git a/wrapper.lua b/wrapper.lua new file mode 100644 index 0000000..628f772 --- /dev/null +++ b/wrapper.lua @@ -0,0 +1,1009 @@ +Items, Vehicles, Jobs, Gangs, Core, ESX = {}, nil, nil, nil, nil, nil + +OXLibExport = Exports and Exports.OXLibExport or "" + +QBXExport = Exports and Exports.QBXExport or "" +QBExport = Exports and Exports.QBExport or "" +ESXExport = Exports and Exports.ESXExport or "" +OXCoreExport = Exports and Exports.OXCoreExport or "" + +OXInv = Exports and Exports.OXInv or "" +QBInv = Exports and Exports.QBInv or "" +QSInv = Exports and Exports.QSInv or "" +CoreInv = Exports and Exports.CoreInv or "" + +QBMenuExport = Exports and Exports.QBMenuExport or "" + +QBTargetExport = Exports and Exports.QBTargetExport or "" +OXTargetExport = Exports and Exports.OXTargetExport or "" + +for k, v in pairs(Exports) do + if GetResourceState(v):find("start") then print("^6Bridge^7: '^3"..v.."^7' ^2export found ^7") end +end + +-- Load item lists from qb-core or ox_lib +if GetResourceState(OXInv):find("start") then + print("^6Bridge^7: ^2Loading ^3Items^2 from ^7"..OXInv) + Items = exports[OXInv]:Items() + for k, v in pairs(Items) do + if v.client then + if v.client.image then Items[k].image = (Items[k].client.image):gsub("nui://"..OXInv.."/web/images/","") + else Items[k].image = k..".png" end + if v.client.hunger then Items[k].hunger = v.client.hunger end + if v.client.thirst then Items[k].thirst = v.client.thirst end + end + end +elseif GetResourceState(QBExport):find("start") then + print("^6Bridge^7: ^2Loading ^3Items^2 from ^7"..QBExport) + Core = exports[QBExport]:GetCoreObject() + Items = Core.Shared.Items +elseif GetResourceState(ESXExport):find("start") then + print("^6Bridge^7: ^2Loading ^3Items^2 from ^7"..ESXExport) + ESX = exports[ESXExport]:getSharedObject() + Items = ESX.Items +end + +-- Load Vehicles +if GetResourceState(QBXExport):find("start") then + Core = exports[QBExport]:GetCoreObject() + print("^6Bridge^7: ^2Loading ^3Vehicles^2 from ^7"..QBXExport) + Vehicles = exports[QBXExport]:GetVehiclesByHash() +elseif GetResourceState(QBExport):find("start") then + print("^6Bridge^7: ^2Loading ^3Vehicles^2 from ^7"..QBExport) + Core = exports[QBExport]:GetCoreObject() + RegisterNetEvent('QBCore:Client:UpdateObject', function() + Core = exports[QBExport]:GetCoreObject() + end) + Vehicles = Core.Shared.Vehicles +elseif GetResourceState(OXCoreExport):find("start") then + print("^6Bridge^7: ^2Loading ^3Vehicles^2 from ^7"..OXCoreExport) + for k, v in pairs(Ox.GetVehicleData()) do + Vehicles = Vehicles or {} + Vehicles[k] = { model = k, price = v.price, name = v.name, brand = v.make } + end +elseif GetResourceState(ESXExport):find("start") then + print("^6Bridge^7: ^2Loading ^3Vehicles^2 from ^7"..ESXExport) + CreateThread(function() + if IsDuplicityVersion() then + createCallback(GetCurrentResourceName()..":getVehiclesPrices", function(source) + Vehicles = MySQL.query.await('SELECT model, price, name FROM vehicles') + return Vehicles + end) + end + if not IsDuplicityVersion() then + local TempVehicles = triggerCallback(GetCurrentResourceName()..":getVehiclesPrices") + for _, v in pairs(TempVehicles) do + Vehicles = Vehicles or {} + Vehicles[v.model] = { model = v.model, price = v.price, name = v.name, brand = GetMakeNameFromVehicleModel(v.model):lower():gsub("^%l", string.upper) } + end + end + end) +end + +-- Load Jobs +if GetResourceState(QBXExport):find("start") then + Core = exports[QBExport]:GetCoreObject() + print("^6Bridge^7: ^2Loading ^3Jobs^7/^3Gangs^2 from ^7"..QBXExport) + Jobs = exports[QBXExport]:GetJobs() + Gangs = exports[QBXExport]:GetGangs() + +elseif GetResourceState(OXCoreExport):find("start") then + print("^6Bridge^7: ^2Loading ^3Jobs^7/^3Gangs^2 from ^7"..OXCoreExport) + CreateThread(function() + if IsDuplicityVersion() then + createCallback(GetCurrentResourceName()..":getOxGroups", function(source) + Jobs = MySQL.query.await('SELECT * FROM `ox_groups`') + return Jobs + end) + else + local TempJobs = triggerCallback(GetCurrentResourceName()..":getOxGroups") + for k, v in pairs(TempJobs) do + local grades = {} + for i = 1, #v.grades do grades[i] = { name = grades[i], isboss = (i == #v.grades)} end + Jobs = Jobs or {} + Jobs[v.name] = { label = v.label, grades = grades, } + end + end + end) + +elseif GetResourceState(QBExport):find("start") then + print("^6Bridge^7: ^2Loading ^3Jobs^7/^3Gangs^2 from ^7"..QBExport) + Core = Core or exports[QBExport]:GetCoreObject() + RegisterNetEvent('QBCore:Client:UpdateObject', function() Core = exports[QBExport]:GetCoreObject() end) + Jobs = Core.Shared.Jobs + Gangs = Core.Shared.Gangs + +elseif GetResourceState(ESXExport):find("start") then + print("^6Bridge^7: ^2Loading ^3Jobs^7/^3Gangs^2 from ^7"..ESXExport) + ESX = exports[ESXExport]:getSharedObject() + if IsDuplicityVersion() then + Jobs = ESX.GetJobs() + for k, v in pairs(Jobs) do + local count = countTable(Jobs[k].grades)-1 + Jobs[k].grades[tostring(count)].isBoss = true + end + Gangs = Jobs + end + CreateThread(function() + while not ESX do Wait(0) end + if IsDuplicityVersion() then + createCallback(GetCurrentResourceName()..":getJobs", function(source) + return Jobs + end) + end + if not IsDuplicityVersion() then + Jobs = triggerCallback(GetCurrentResourceName()..":getJobs") + Gangs = Jobs + end + end) +end + +function makeBossRoles(role) + local boss = {} + if Jobs and Jobs[role] then + for grade in pairs(Jobs[role].grades) do + if Jobs[role].grades[grade].isboss then + if boss[role] then + if boss[role] > tonumber(grade) then boss[role] = tonumber(grade) end + else boss[role] = tonumber(grade) end + end + end + elseif Gangs and Gangs[role] then + for grade in pairs(Gangs[role].grades) do + if Gangs[role].grades[grade].isboss then + if boss[role] then + if boss[role] > tonumber(grade) then boss[role] = tonumber(grade) end + else boss[role] = tonumber(grade) end + end + end + end + return boss +end + +function createPoly(data) local Location = nil + if GetResourceState(OXLibExport):find("start") then -- if it finds ox_lib, use it instead of PolyZone + if Config.System.Debug then print("^6Bridge^7: ^2Creating new poly with ^7 "..OXLibExport.." "..data.name) end + for i = 1, #data.points do + data.points[i] = vec3(data.points[i].x, data.points[i].y, 12.0) + end + data.thickness = 1000 + Location = lib.zones.poly(data) + elseif GetResourceState("PolyZone"):find("start") then + if Config.System.Debug then print("^6Bridge^7: ^2Creating new poly with ^7PolyZone "..data.name) end + Location = PolyZone:Create(data.points, { name = data.name, debugPoly = data.debug }) + Location:onPlayerInOut(function(isPointInside) + if isPointInside then + data.onEnter() + else + data.onExit() + end + end) + end +end + +function createCirclePoly(data) local Location = nil + if GetResourceState(OXLibExport):find("start") then -- if it finds ox_lib, use it instead of PolyZone + if Config.System.Debug then print("^6Bridge^7: ^2Creating new ^3Cricle^2 poly with ^7"..OXLibExport.." "..data.name) end + Location = lib.zones.sphere(data) + elseif GetResourceState("PolyZone"):find("start") then + if Config.System.Debug then print("^6Bridge^7: ^2Creating new ^3Cricle^2 poly with ^7PolyZone ".. data.name) end + Location = CircleZone:Create(data.coords, data.radius, { name = data.name, debugPoly = Config.System.Debug}) + Location:onPlayerInOut(function(isPointInside) + if isPointInside then + data.onEnter() + else + data.onExit() + end + end) + end +end + +function openMenu(Menu, data) + if Config.System.Menu == "ox" then + if data.onBack then + table.insert(Menu, 1, { icon = "fas fa-circle-arrow-left", + title = "Return", + onSelect = data.onBack, + }) + end + for k in pairs(Menu) do + if not Menu[k].title then + if Menu[k].header ~= nil and Menu[k].header ~= "" then + Menu[k].title = Menu[k].header + if Menu[k].txt then Menu[k].description = Menu[k].txt else Menu[k].description = "" end + else + Menu[k].title = Menu[k].txt + end + end + if Menu[k].params then + Menu[k].event = Menu[k].params.event + Menu[k].args = Menu[k].params.args or {} + end + if Menu[k].isMenuHeader then + Menu[k].disabled = true + end + end + lib.registerContext({id = 'Menu', title = data.header..br..br..(data.headertxt and data.headertxt or ""), position = 'top-right', options = Menu, canClose = data.canClose and data.canClose or nil, onExit = data.onExit and data.onExit or nil, }) + lib.showContext("Menu") + elseif Config.System.Menu == "qb" then + if data.onBack then + table.insert(Menu, 1, { icon = "fas fa-circle-arrow-left", + header = " ", txt = "Return", + params = { + isAction = true, + event = data.onBack, + } + }) + elseif data.canClose then + table.insert(Menu, 1, { icon = "fas fa-circle-xmark", + header = " ", txt = "Close", + params = { + isAction = true, + event = data.onExit and data.onExit or (function() exports[QBMenuExport]:closeMenu() end), + } + }) + end + if data.header ~= nil then + local tempMenu = {} + for k, v in pairs(Menu) do tempMenu[k+1] = v end + tempMenu[1] = { header = data.header, txt = data.headertxt and data.headertxt or "", isMenuHeader = true } + Menu = tempMenu + end + for k in pairs(Menu) do + if Menu[k].onSelect then + Menu[k].params = { + isAction = true, + event = Menu[k].onSelect, + } + end + if not Menu[k].header then Menu[k].header = " " end + if Menu[k].arrow then Menu[k].icon = "fas fa-angle-right" end + end + exports[QBMenuExport]:openMenu(Menu) + elseif Config.System.Menu == "gta" then + WarMenu.CreateMenu(tostring(Menu), + data.header, + data.headertxt or " ", + { titleColor = { 222, 255, 255 }, + maxOptionCountOnScreen = 15, + width = 0.25, + x = 0.7, + }) + if WarMenu.IsAnyMenuOpened() then return end + WarMenu.OpenMenu(tostring(Menu)) + CreateThread(function() + local close = true + while true do + if WarMenu.Begin(tostring(Menu)) then + if data.onBack then + if WarMenu.SpriteButton("Return", 'commonmenu', "arrowleft", 127, 127, 127) then + WarMenu.CloseMenu() + Wait(10) + data.onBack() + end + end + for k in pairs(Menu) do + local pressed = WarMenu.Button(Menu[k].header) + if not Menu[k].header then + Menu[k].header = Menu[k].txt + Menu[k].txt = nil + end + if Menu[k].txt and Menu[k].txt ~= "" and WarMenu.IsItemHovered() then + if Menu[k].disabled or Menu[k].isMenuHeader then + WarMenu.ToolTip("~r~"..Menu[k].txt, 0.18, true) + else + WarMenu.ToolTip( + (Menu[k].blip and "~BLIP_".."8".."~ " or "").. + Menu[k].txt:gsub("%:", ":~g~"):gsub("%\n", "\n~s~"), 0.18, + true) + end + end + if pressed and not Menu[k].isMenuHeader then + WarMenu.CloseMenu() + close = false + Menu[k].onSelect() + end + end + WarMenu.End() + else + return + end + if not WarMenu.IsAnyMenuOpened() and close then + stopTempCam(cam) + if data.onExit then data.onExit() end + end + Wait(0) + end + end) + elseif Config.System.Menu == "esx" then -- can't display more than one line - BIG problem for crafting menus mainly + for k in pairs(Menu) do + Menu[k].label = Menu[k].header + Menu[k].name = "button"..k + end + if data.canClose then + table.insert(Menu, 1, { + icon = "fas fa-circle-xmark", + label = "Close", + name = "close", + onSelect = data.onExit + }) + end + if data.onBack then + table.insert(Menu, 1, { + icon = "fas fa-circle-arrow-left", + label = "Return", + name = "return", + onSelect = data.onback + }) + end + + ESX.UI.Menu.Open("default", GetCurrentResourceName(), "Example_Menu", { + title = data.header, + align = 'top-right', + elements = Menu + }, + function(menuData, menu) -- OnSelect Function + for k in pairs(Menu) do + if menuData.current.name == Menu[k].name then + menu.close() + Wait(10) + Menu[k].onSelect() + end + end + end, + function(data, menu) + menu.close() -- close menu + end) + end +end + +br = (Config.System.Menu == "ox" or Config.System.Menu == "gta") and "\n" or "
" + +function isOx() return (Config.System.Menu == "ox" or Config.System.Menu == "gta") end + +function isWarMenuOpen() if Config.System.Menu == "gta" then return WarMenu.IsAnyMenuOpened() else return false end end + +-- Targets -- +local targetEntities = {} +function createEntityTarget(entity, opts, dist) + targetEntities[#targetEntities+1] = entity + if GetResourceState(OXTargetExport):find("start") then + if Config.System.Debug then + print("^6Bridge^7: ^2Creating new ^3Entity^2 target with ^6"..OXTargetExport.." ^7"..entity) + end + local options = {} + for i = 1, #opts do + options[i] = { + icon = opts[i].icon, + label = opts[i].label, + item = opts[i].item or nil, + groups = opts[i].job or opts[i].gang, + onSelect = opts[i].action, + canInteract = function(_, distance) + return distance < dist and true or false + end + } + end + exports[OXTargetExport]:addLocalEntity(entity, options) + elseif GetResourceState(QBTargetExport):find("start") then + if Config.System.Debug then + print("^6Bridge^7: ^2Creating new ^3Entity^2 target with ^6"..QBTargetExport.." ^7"..entity) + end + local options = { options = opts, distance = dist } + exports[QBTargetExport]:AddTargetEntity(entity, options) + end +end + +local boxTargets = {} +function createBoxTarget(data, opts, dist) + if GetResourceState(OXTargetExport):find("start") then + if Config.System.Debug then + print("^6Bridge^7: ^2Creating new ^3Box^2 target with ^6"..OXTargetExport.." ^7"..data[1]) + end + local options = {} + for i = 1, #opts do + options[i] = { + icon = opts[i].icon, + label = opts[i].label, + item = opts[i].item or nil, + groups = opts[i].job or opts[i].gang, + onSelect = opts[i].onSelect or opts[i].action, + canInteract = function(_, distance) + return distance < dist and true or false + end + } + end + if not data[5].useZ then + local z = data[2].z + math.abs(data[5].maxZ - data[5].minZ) / 2 + data[2] = vec3(data[2].x, data[2].y, z) + end + local target = exports[OXTargetExport]:addBoxZone({ + coords = data[2], + size = vec3(data[4], data[3], (data[5].useZ or not data[5].maxZ) and data[2].z or math.abs(data[5].maxZ - data[5].minZ)), + rotation = data[5].heading, + debug = data[5].debugPoly, + options = options + }) + boxTargets[#boxTargets+1] = target + return target + elseif GetResourceState(QBTargetExport):find("start") then + if Config.System.Debug then + print("^6Bridge^7: ^2Creating new ^3Box^2 target with ^6"..QBTargetExport.." ^7"..data[1]) + end + local options = { options = opts, distance = dist } + local target = exports[QBTargetExport]:AddBoxZone(data[1], data[2], data[3], data[4], data[5], options) + boxTargets[#boxTargets+1] = target + return target + end +end + +function removeEntityTarget(entity) + if GetResourceState(QBTargetExport):find("start") then exports[QBTargetExport]:RemoveTargetEntity(entity) end + if GetResourceState(OXTargetExport):find("start") then exports[OXTargetExport]:removeLocalEntity(entity, nil) end +end + +function removeZoneTarget(target) + if GetResourceState(QBTargetExport):find("start") then exports[QBTargetExport]:RemoveZone(target) end + if GetResourceState(OXTargetExport):find("start") then exports[OXTargetExport]:removeZone(target, true) end +end + +AddEventHandler('onResourceStop', function(r) + if r ~= GetCurrentResourceName() then return end + for i = 1, #targetEntities do + if GetResourceState(OXTargetExport):find("start") then exports[OXTargetExport]:removeLocalEntity(targetEntities[i], nil) + elseif GetResourceState(QBTargetExport):find("start") then exports[QBTargetExport]:RemoveTargetEntity(targetEntities[i]) end + end + for i = 1, #boxTargets do + if GetResourceState(OXTargetExport):find("start") then exports[OXTargetExport]:removeZone(boxTargets[i], true) + elseif GetResourceState(QBTargetExport):find("start") then exports[QBTargetExport]:RemoveZone(boxTargets[i].name) end + end +end) + +-- NOTIFICATIONS -- +function triggerNotify(title, message, type, src) + if Config.System.Notify == "okok" then + if not src then TriggerEvent('okokNotify:Alert', title, message, 6000, type) + else TriggerClientEvent('okokNotify:Alert', src, title, message, 6000, type) end + elseif Config.System.Notify == "qb" then + if not src then TriggerEvent("QBCore:Notify", message, type) + else TriggerClientEvent("QBCore:Notify", src, message, type) end + elseif Config.System.Notify == "ox" then + if not src then TriggerEvent('ox_lib:notify', {title = title, description = message, type = type or "success"}) + else TriggerClientEvent('ox_lib:notify', src, { type = type or "success", title = title, description = message }) end + elseif Config.System.Notify == "gta" then + if not src then TriggerEvent(GetCurrentResourceName()..":DisplayGTANotify", title, message) + else TriggerClientEvent(GetCurrentResourceName()..":DisplayGTANotify", src, title, message) end + elseif Config.System.Notify == "esx" then + if not src then exports["esx_notify"]:Notify(type, 4000, message) + else TriggerClientEvent(GetCurrentResourceName()..":DisplayESXNotify", src, type, title, message) end + end +end + +RegisterNetEvent(GetCurrentResourceName()..":DisplayESXNotify", function(type, title, text) + exports["esx_notify"]:Notify(type, 4000, message) +end) + +RegisterNetEvent(GetCurrentResourceName()..":DisplayGTANotify", function(title, text) local iconTable = {} + if GetCurrentResourceName() == "jim-npcservice" then + iconTable = { + [Loc[Config.Lan].notify["taxiname"]] = "CHAR_TAXI", + [Loc[Config.Lan].notify["limoname"]] = "CHAR_CASINO", + [Loc[Config.Lan].notify["ambiname"]] = "CHAR_CALL911", + [Loc[Config.Lan].notify["pilotname"]] = "CHAR_DEFAULT", + [Loc[Config.Lan].notify["planename"]] = "CHAR_BOATSITE2", + [Loc[Config.Lan].notify["heliname"]] = "CHAR_BOATSITE2", + } + end + BeginTextCommandThefeedPost("STRING") + AddTextComponentSubstringKeyboardDisplay(text) + EndTextCommandThefeedPostMessagetext(iconTable[title] or "CHAR_DEFAULT", iconTable[title] or "CHAR_DEFAULT", true, 1, title, nil, text); + EndTextCommandThefeedPostTicker(true, false) +end) + +--DrawText +function drawText(image, input, style) local text = "" + if Config.System.drawText == "qb" then + for i = 1, #input do + text = text..input[i]..""..(input[i+1] ~= nil and "
" or "") end + local text = text:gsub("%:", ":") + if image then + text = ''..text + end + exports[CoreExport]:DrawText(text, 'left') + + elseif Config.System.drawText == "ox" then + for k, v in pairs(input) do + input[k] = v.." \n" + end + lib.showTextUI(table.concat(input), { icon = radarTable[image], position = 'left-center' }) + + elseif Config.System.drawText == "gta" then + for i = 1, #input do if input[i] ~= "" then text = text..input[i].."\n~s~" end end + if image then text = "~BLIP_"..image.."~ "..text end + + DisplayHelpMsg(text:gsub("%:", ":~"..style.."~")) + elseif Config.System.drawText == "esx" then + for i = 1, #input do + text = text..input[i]..""..(input[i+1] ~= nil and "
" or "") end + local text = text:gsub("%:", ":") + if image then + text = ''..text + end + ESX.TextUI(text, nil) + end +end + +function hideText() + if Config.System.drawText == "qb" then + exports[CoreExport]:HideText() + elseif Config.System.drawText == "ox" then + lib.hideTextUI() + elseif Config.System.drawText == "gta" then + ClearAllHelpMessages() + elseif Config.System.drawText == "esx" then + ESX.HideUI() + end +end + +function DisplayHelpMsg(text) + BeginTextCommandDisplayHelp("STRING") + AddTextComponentScaleform(text) + EndTextCommandDisplayHelp(0, true, false, -1) +end + +-- Callbacks +function createCallback(callbackName, funct) + if GetResourceState(OXLibExport):find("start") then + if Config and Config.System.Debug then print("^6Bridge^7: ^2Registering ^3Callback^2 with ^7"..OXLibExport, callbackName) end + lib.callback.register(callbackName, funct) + elseif GetResourceState(QBExport):find("start") then + if Config and Config.System.Debug then print("^6Bridge^7: ^2Registering ^3Callback^2 with ^7"..QBExport, callbackName) end + Core = exports[QBExport]:GetCoreObject() + Core.Functions.CreateCallback(callbackName, funct) + elseif GetResourceState(ESXExport):find("start") then + if Config and Config.System.Debug then print("^6Bridge^7: ^2Registering ^3Callback^2 with ^7"..ESXExport, callbackName) end + ESX.RegisterServerCallback(callbackName, funct) + else + print("^6Bridge^7: ^1ERROR^7: ^3Can't find any script to register callback with", callbackName) + end +end + +function triggerCallback(callBackName, value) local result = nil + if GetResourceState(OXLibExport):find("start") then + if Config and Config.System.Debug then print("^6Bridge^7: ^2Triggering ^3Callback^2 with ^7"..OXLibExport, callBackName) end + result = lib.callback.await(callBackName, false, value) + elseif GetResourceState(QBExport):find("start") then + if Config and Config.System.Debug then print("^6Bridge^7: ^2Triggering ^3Callback^2 with ^7"..QBExport, callBackName) end + local p = promise.new() + Core.Functions.TriggerCallback(callBackName, function(cb) p:resolve(cb) end, value) + result = Citizen.Await(p) + elseif GetResourceState(ESXExport):find("start") then + if Config and Config.System.Debug then print("^6Bridge^7: ^2Triggering ^3Callback^2 with ^7"..ESXExport, callBackName) end + local p = promise.new() + ESX.TriggerServerCallback(callBackName, function(cb) p:resolve(cb) end, value) + result = Citizen.Await(p) + else + print("^6Bridge^7: ^1ERROR^7: ^3Can't find any script to trigger callback with", callBackName) + end + return result +end + +-- onPlayerLoaded events +function onPlayerLoaded(func) + if GetResourceState(QBExport):find("start") or GetResourceState(QBXExport):find("start") then + if Config.System.Debug then print("^6Bridge^7: ^2Registering ^3onPlayerLoaded^2 with ^7"..QBExport) end + AddEventHandler('QBCore:Client:OnPlayerLoaded', func) + elseif GetResourceState(ESXExport):find("start") then + if Config.System.Debug then print("^6Bridge^7: ^2Registering ^3onPlayerLoaded^2 with ^7"..ESXExport) end + AddEventHandler('esx:playerLoaded', func) + elseif GetResourceState(OXCoreExport):find("start") then + if Config.System.Debug then print("^6Bridge^7: ^2Registering ^3onPlayerLoaded^2 with ^7"..OXLibExport) end + AddEventHandler('ox:playerLoaded', func) + end +end + +-- INPUT -- +function createInput(title, opts) + local dialog = nil + local options = {} + if Config.Input.Menu == "ox" then + for i = 1, #opts do + if opts[i].type == "radio" then + for k in pairs(opts[i].options) do + opts[i].options[k].label = opts[i].options[k].text + end + options[i] = { + type = "select", + isRequired = opts[i].isRequired, + label = opts[i].label, + name = opts[i].name, + default = opts[i].options[1].value, + options = opts[i].options, + } + end + if opts[i].type == "number" then + options[i] = { + type = "number", + label = opts[i].text.." - "..opts[i].txt, + isRequired = opts[i].isRequired, + name = opts[i].name, + options = opts[i].options, + min = opts[i].min, + max = opts[i].max, + default = opts[i].default, + } + end + end + dialog = exports[OXLibExport]:inputDialog(title, options) + return dialog + end + if Config.Input.Menu == "qb" then + dialog = exports['qb-input']:ShowInput({ header = title, submitText = "Pay", inputs = opts }) + return dialog + end + if Config.Input.Menu == "gta" then + WarMenu.CreateMenu(tostring(opts), + title, + " ", + { titleColor = { 222, 255, 255 }, + maxOptionCountOnScreen = 15, + width = 0.25, + x = 0.7, + }) + if WarMenu.IsAnyMenuOpened() then return end + WarMenu.OpenMenu(tostring(opts)) + local close = true + local _comboBoxItems = { } + local _comboBoxIndex = { 1, 1 } + while true do + if WarMenu.Begin(tostring(opts)) then + for i = 1, #opts do + if opts[i].type == "radio" then + for k in pairs(opts[i].options) do + if not _comboBoxItems[i] then _comboBoxItems[i] = {} end + _comboBoxItems[i][k] = opts[i].options[k].text + end + local _, comboBoxIndex = WarMenu.ComboBox(opts[i].label, _comboBoxItems[i], _comboBoxIndex[i]) + if _comboBoxIndex[i] ~= comboBoxIndex then + _comboBoxIndex[i] = comboBoxIndex + end + end + if opts[i].type == "number" then + for b = 1, opts[i].max do + if not _comboBoxItems[i] then _comboBoxItems[i] = {} end + _comboBoxItems[i][b] = b + end + local _, comboBoxIndex = WarMenu.ComboBox(opts[i].text, _comboBoxItems[i], _comboBoxIndex[i]) + if _comboBoxIndex[i] ~= comboBoxIndex then + _comboBoxIndex[i] = comboBoxIndex + end + end + end + local pressed = WarMenu.Button("Pay") + if pressed then + WarMenu.CloseMenu() + close = false + local result = {} + for i = 1, #_comboBoxIndex do + result[i] = _comboBoxItems[i][_comboBoxIndex[i]] + end + return result + end + WarMenu.End() + else + return + end + if not WarMenu.IsAnyMenuOpened() and close then + if data.onExit then data.onExit() end + end + Wait(0) + end + end +end + +-- Get Vehile Info -- +local lastCar = nil +local carInfo = {} +function searchCar(vehicle) + if lastCar ~= vehicle then -- If same car, use previous info + lastCar = vehicle + carInfo = {} + local model = GetEntityModel(vehicle) + local classlist = { + "Compacts", --1 + "Sedans", --2 + "SUVs", --3 + "Coupes", --4 + "Muscle", --5 + "Sports Classics", --6 + "Sports", --7 + "Super", --8 + "Motorcycles", --9 + "Off-road", --10 + "Industrial", --11 + "Utility", --12 + "Vans", --13 + "Cycles", --14 + "Boats", --15 + "Helicopters", --16 + "Planes", --17 + "Service", --18 + "Emergency", --19 + "Military", --20 + "Commercial", --21 + "Trains", --22 + } + if Vehicles then + for k, v in pairs(Vehicles) do + if tonumber(v.hash) == model or GetHashKey(v.hash) == model or GetHashKey(v.model) == model then + if Config.System.Debug then + print("^6Bridge^7: ^2Vehicle info found in^7 ^4Vehicles^7 ^2table^7: ^6"..(v.hash and v.hash or v.model).. " ^7(^6"..Vehicles[k].name.."^7)") + end + carInfo.name = Vehicles[k].name.." "..Vehicles[k].brand + carInfo.price = Vehicles[k].price + carInfo.class = classlist[GetVehicleClass(vehicle) + 1], GetVehicleClass(vehicle) + break + end + end + + if not carInfo.name then + if Config.System.Debug then + print("^6Bridge^7: ^2Vehicle ^1not ^2found in ^4vehicles^7 ^2table^7: ^6"..model.." ^7(^6"..GetDisplayNameFromVehicleModel(model):lower().."^7)") + end + carInfo.name = string.upper(GetMakeNameFromVehicleModel(model).." "..GetDisplayNameFromVehicleModel(model)) + carInfo.price = 0 + carInfo.class = classlist[GetVehicleClass(vehicle) + 1], GetVehicleClass(vehicle) + end + return carInfo + else + if not carInfo.name then + if Config.System.Debug then + print("^6Bridge^7: ^2Vehicle ^1not ^2found in ^4vehicles^7 ^2table^7: ^6"..model.." ^7(^6"..GetDisplayNameFromVehicleModel(model):lower().."^7)") + end + carInfo.name = string.upper(GetMakeNameFromVehicleModel(model).." "..GetDisplayNameFromVehicleModel(model)) + carInfo.price = 0 + carInfo.class = classlist[GetVehicleClass(vehicle) + 1], GetVehicleClass(vehicle) + end + end + else + return carInfo + end +end + +-- Vehicle Properties -- +function getVehicleProperties(vehicle) + local properties = {} + if vehicle == nil then return nil end + if GetResourceState(OXLibExport):find("start") then + properties = lib.getVehicleProperties(vehicle) + elseif GetResourceState(QBExport):find("start") then + properties = Core.Functions.GetVehicleProperties(vehicle) + end + return properties +end + +function setVehicleProperties(vehicle, props) + if not DoesEntityExist(vehicle) then + print(("Unable to set vehicle properties for '%s' (entity does not exist)"): + format(vehicle)) + end + if GetResourceState(OXLibExport):find("start") then + lib.setVehicleProperties(vehicle, props) + elseif GetResourceState(QBExport):find("start") then + Core.Functions.SetVehicleProperties(vehicle, props) + end +end + +RegisterNetEvent(GetCurrentResourceName()..":server:ChargePlayer", function(cost, type) local src = source + if Config.System.Debug then print("^6Bridge^7: ^2Charging ^2Player: '^6"..cost.."^7'", type) end + if type == "cash" then + if GetResourceState(OXInv):find("start") then + exports[OXInv]:RemoveItem(src, "money", cost) + elseif GetResourceState(QBExport):find("start") then + Core.Functions.GetPlayer(src).Functions.RemoveMoney("cash", cost) + elseif GetResourceState(ESXExport):find("start") then + local Player = ESX.GetPlayerFromId(src) + Player.removeMoney(cost, "") + end + end + if type == "bank" then + if GetResourceState(QBExport):find("start") or GetResourceState(QBXExport):find("start") then + Core.Functions.GetPlayer(src).Functions.RemoveMoney("bank", cost) + elseif GetResourceState(ESXExport):find("start") then + local Player = ESX.GetPlayerFromId(src) + Player.removeMoney(cost, "") + end + end +end) + +function createUseableItem(item, funct) + if GetResourceState(ESXExport):find("start") then + if Config.System.Debug then print("^6Bridge^7: ^2Registering item as ^3Useable^2 with ^7es_extended", item) end + while not ESX do Wait(0) end + ESX.RegisterUsableItem(item, funct) + elseif GetResourceState(QBExport):find("start") and not GetResourceState(QBXExport):find("start") then + if Config.System.Debug then print("^6Bridge^7: ^2Registering item as ^3Useable^2 with ^7qb-core", item) end + Core.Functions.CreateUseableItem(item, funct) + elseif GetResourceState(QBXExport):find("start") then + if Config.System.Debug then print("^6Bridge^7: ^2Registering item as ^3Useable^2 with ^7qbx_core", item) end + exports[QBXExport]:CreateUseableItem(item, funct) + end +end + +function hasJob(job, src) local hasJob = false + if src then + if GetResourceState(ESXExport):find("start") then + local info = ESX.GetPlayerFromId(src).job + while not info do + info = ESX.GetPlayerData(src).job + Wait(100) + end + if info.name == job then hasJob = true end + + elseif GetResourceState(OXCoreExport):find("start") then + local chunk = assert(load(LoadResourceFile('ox_core', ('imports/%s.lua'):format('server')), ('@@ox_core/%s'):format(file))) + chunk() + local player = Ox.GetPlayer(tonumber(src)) + for k, v in pairs(player.getGroups()) do + if k == job then hasJob = true end + end + + elseif GetResourceState(QBXExport):find("start") then + local jobinfo = exports[QBXExport]:GetPlayer(src).PlayerData.job + if jobinfo.name == job then hasJob = true end + local ganginfo = exports[QBXExport]:GetPlayer(src).PlayerData.gang + if ganginfo.name == job then hasJob = true end + else + local jobinfo = exports[QBExport]:GetPlayer(src).PlayerData.job + if jobinfo.name == job then hasJob = true end + local ganginfo = exports[QBExport]:GetPlayer(src).PlayerData.gang + if ganginfo.name == job then hasJob = true end + end + else + if GetResourceState(ESXExport):find("start") then + while not ESX do Wait(10) end + local info = ESX.GetPlayerData().job + while not info do + info = ESX.GetPlayerData().job + Wait(100) + end + if info.name == job then hasJob = true end + + elseif GetResourceState(OXCoreExport):find("start") then + for k, v in pairs(exports[OXCoreExport]:GetPlayerData().groups) do + if k == job then hasJob = true end break + end + + elseif GetResourceState(QBXExport):find("start") then + local jobinfo = QBX.PlayerData.job + if jobinfo.name == job then hasJob = true end + local ganginfo = QBX.PlayerData.gang + if ganginfo.name == job then hasJob = true end + else + local info = nil + Core.Functions.GetPlayerData(function(PlayerData) + info = PlayerData + end) + local jobinfo = info.job + if jobinfo.name == job then hasJob = true end + local ganginfo = info.gang + if ganginfo.name == job then hasJob = true end + end + end + return hasJob +end + +function getPlayer(src) local Player = {} + if Config.System.Debug then print("^6Bridge^7: ^2Getting ^3Player^2 info^7") end + if src then -- If called from server + if GetResourceState(ESXExport):find("start") then + local info = ESX.GetPlayerFromId(src) + Player = { + name = info.getName(), + cash = info.getMoney(), + bank = info.getAccount("bank").money, + } + elseif GetResourceState(OXCoreExport):find("start") then + local file = ('imports/%s.lua'):format('server') + local import = LoadResourceFile('ox_core', file) + local chunk = assert(load(import, ('@@ox_core/%s'):format(file))) + chunk() + local player = Ox.GetPlayer(tonumber(src)) + Player = { + name = ('%s %s'):format(player.firstName, player.lastName), + cash = exports[OXInv]:Search(src, 'count', "money"), + bank = 0, + } + elseif GetResourceState(QBXExport):find("start") then + local info = exports[QBXExport]:GetPlayer(src) + Player = { + name = info.PlayerData.charinfo.firstname.." "..info.PlayerData.charinfo.lastname, + cash = exports[OXInv]:Search(src, 'count', "money"), + bank = info.Functions.GetMoney("bank"), + } + elseif GetResourceState(QBExport):find("start") and not GetResourceState(QBXExport):find("start") then + local info = Core.Functions.GetPlayer(tonumber(src)) + Player = { + name = info.PlayerData.charinfo.firstname.." "..info.PlayerData.charinfo.lastname, + cash = info.PlayerData.money["cash"], + bank = info.PlayerData.money["bank"], + } + end + else + if ESX ~= nil then + local info = ESX.GetPlayerData() + local cash, bank = 0, 0 + for k, v in pairs(ESX.GetPlayerData().accounts) do + if v.name == "money" then cash = v.money end + if v.name == "bank" then bank = v.money end + end + Player = { + name = ('%s %s'):format(info.firstName, info.lastName), + cash = cash, + bank = bank, + } + elseif GetResourceState(OXCoreExport):find("start") then + local info = exports[OXCoreExport]:GetPlayerData() + Player = { + name = info.firstName.." "..info.lastName, + cash = exports[OXInv]:Search('count', "money"), + bank = 0, + } + elseif GetResourceState(QBXExport):find("start") then + local info = exports[QBXExport]:GetPlayerData() + Player = { + name = info.charinfo.firstname.." "..info.charinfo.lastname, + cash = info.money["cash"], + bank = info.money["bank"], + } + else + local info = nil + Core.Functions.GetPlayerData(function(PlayerData) + info = PlayerData + end) + Player = { + name = info.charinfo.firstname.." "..info.charinfo.lastname, + cash = info.money["cash"], + bank = info.money["bank"], + } + end + end + return Player +end + +function registerCommand(command, options) + if GetResourceState(OXLibExport):find("start") then + if Config.System.Debug then print("^6Bridge^7: ^2Registering ^3Command^2 with ^7"..OXLibExport, command) end + lib.addCommand(command, { help = options[1], restricted = options[5] and "group."..options[5] or nil }, options[4]) + elseif GetResourceState(QBExport):find("start") and not GetResourceState(QBXExport):find("start") then + if Config.System.Debug then print("^6Bridge^7: ^2Registering ^3Command^2 with ^7qb-core"..QBExport, command) end + Core.Commands.Add(command, options[1], options[2], options[3], options[4], options[5] and options[5] or nil) + end +end + +function invImg(item) + local imgLink = "" + if item ~= "" and Items[item] then + if GetResourceState(OXInv):find("start") then + imgLink = "nui://"..OXInv.."/web/images/"..Items[item].image + elseif GetResourceState(QSInv and QSInv or ""):find("start") then + imgLink = "nui://"..QSInv.."/html/images/"..Items[item].image + elseif GetResourceState(CoreInv and CoreInv or ""):find("start") then + imgLink = "nui://"..CoreInv.."/html/img/"..Items[item].image + elseif GetResourceState(QBInv and QBInv or ""):find("start") then + imgLink = "nui://"..QBInv.."/html/images/"..Items[item].image + end + end + return imgLink +end + +function registerStash(name, label) + if GetResourceState(OXInv):find("start") then + --print("Registering OX Stash:", name, label) + exports[OXInv]:RegisterStash(name, label, 50, 4000000) + elseif GetResourceState(QSInv):find("start") then + --print("Registering QS Stash:", name, label) + exports[QSInv]:RegisterStash(name, 50, 4000000) + end +end +-- IN NO WAY PERFECT -- \ No newline at end of file