Compare commits

...

30 Commits

Author SHA1 Message Date
Jim Shield
7738bb4fca Version Bump
`2.1.03` - `2.1.04`
2025-09-30 23:39:55 +01:00
Jim Shield
3ad65810c3 Rework crafting.lua
Changes:
- Crafting prop not spawning
- Crafting "sound" not playing
- `SingleProgress` is now "one progressbar"

I'm working on refactoring crafting table's layout style too

I'm updating my scripts crafting recipes to a new format, this commit basically makes use of it and makes it slightly easier to edit later if needed

It *should* increase readability and users ability to edit these recipes

# "old style" crafting recipes should still be compatible thanks to a wrapper I added so you shouldn't notice a difference.
2025-09-28 14:03:23 +01:00
Jim Shield
45eeaf8f0d update a couple debug prints 2025-09-28 13:48:17 +01:00
Jim Shield
37f7eb1116 add testing code for new crafting table style 2025-09-28 03:22:12 +01:00
Jim Shield
145e3aa156 add new module ropeControl.lua
**Needs work** but adds the ability to easily create ropes/wires from one coord to another
2025-09-27 13:01:09 +01:00
Jim Shield
bb176addbf Create setStress function
This allows per framework stress functions to be set, including ESX

For ESX the math is done in this function as their values are insanely high instead of 0 - 100
2025-09-27 12:35:56 +01:00
Jim Shield
178040348e Rework SingleProgress slightly
Realised it wasn't doing the math to take the correct amount of required items, so this fixes it

also if `SingleProgress` is enabled, it won't show the "Ingredient Progress bars" any more
2025-09-27 12:34:46 +01:00
Jim Shield
ee15f3b076 Version Bump
`2.1.02` - `2.1.03`
2025-09-24 23:12:34 +01:00
Jim Shield
6919f038ee Release Notifier Push 2025-09-24 18:20:02 +01:00
Jim Shield
47029da6ed Revert "Version Bump"
This reverts commit f08638812c.
2025-09-24 14:23:43 +01:00
Jim Shield
e1d292d1bf Remove testing debug print 2025-09-24 14:09:19 +01:00
Jim Shield
f08638812c Version Bump
`2.1.02` - `2.1.03`
2025-09-24 13:36:14 +01:00
Jim Shield
de5424c506 Fix getPlayerInv() for CodeM Inventory 2025-09-24 12:30:08 +01:00
Jim Shield
b46d734442 Testing a rework _loaders.lua
Uses more specific functions per framework now for player loading in and out and optimizes use of them
2025-09-24 12:29:48 +01:00
Jim Shield
92ad96e435 Redo math for ox_inv get player current inv weight 2025-09-24 11:59:44 +01:00
Jim Shield
6166314cbf fix ox_inv current inventory weight check 2025-09-23 15:05:46 +01:00
Jim Shield
9fa8f58cfb Make ox_lib progressbars actually return false
I think this was causing progressbars to return true instead of `nil/false` somehow
this *should* make it more certain
2025-09-23 14:59:16 +01:00
Jim Shield
ed997ad8a2 fix typo breaking qb-core /commands 2025-09-23 12:00:40 +01:00
Jim Shield
20cea95783 Set previous active cam inactive
shouldn't be needed but just in case
2025-09-22 21:10:01 +01:00
Jim Shield
0dc5a45b5d Support for esx_society
`esx_society` requires societies to be registered manually before opening. this forces it

also adds full support for charging, funding and retrieving balances in `esx_society`
2025-09-22 21:08:31 +01:00
Jim Shield
54b1280bef Remove debug print 2025-09-21 12:09:12 +01:00
Jim Shield
3ac65d4630 Add "pre support" for jim-shops exploit security 2025-09-21 12:00:05 +01:00
Jim Shield
ed49876c69 Fix cleanup of targets for qb-target
Realised it was trying to remove `nil` when players were unloading/the scripts were ensured
2025-09-21 10:35:22 +01:00
Jim Shield
69d0f07bb6 Potential fix for playerInfo is nil 2025-09-20 17:56:47 +01:00
Jim Shield
b975f318a0 Fix hunger and thirst events
Missed out the math part when adding hunger and thirst to a player when eating items when I reworked the functions

should fix for all frameworks
2025-09-19 23:06:11 +01:00
Jim Shield
ce1df2c205 Version Bump 2025-09-19 17:54:45 +01:00
Jim Shield
75d8146e24 Fix nil print + use .xy for distance check 2025-09-19 17:22:40 +01:00
Jim Shield
268c95f29a Hotfix for shops and stashes erroring 2025-09-15 22:14:18 +01:00
Jim Shield
91dd069e5a Use the correct illenium appearance trigger 2025-09-15 17:23:30 +01:00
Jim Shield
f96d96f26e adjust stash and store registration
This should fix the `jim_bridge` side of the reports of stores erroring when scripts starts
2025-09-15 16:19:52 +01:00
16 changed files with 991 additions and 448 deletions

71
.github/workflows/notify-release.yml vendored Normal file
View File

@@ -0,0 +1,71 @@
name: Discord Release Notifier
on:
# Manual or UI-published releases
release:
types: [published]
# Releases created by your tag-driven workflow
workflow_run:
workflows: ["Package & Release"] # must match the 'name:' in release.yml
types: [completed]
permissions:
contents: read
jobs:
# 1) Handle manual / UI / non-workflow-created releases
notify-from-release:
if: github.event_name == 'release' && github.event.action == 'published'
runs-on: ubuntu-latest
steps:
- name: Send release payload to Discord Bot
env:
URL: http://${{ secrets.DISCORDBOT }}:3000/github-releases
run: |
curl -sS -X POST "$URL" \
-H 'Content-Type: application/json' \
--data-binary "@$GITHUB_EVENT_PATH"
# 2) Handle releases created by your 'Package & Release' workflow
# (which wont trigger `on: release` when using GITHUB_TOKEN)
notify-from-workflow-run:
if: >
github.event_name == 'workflow_run' &&
github.event.workflow_run.conclusion == 'success'
runs-on: ubuntu-latest
steps:
- name: Install jq
run: sudo apt-get update && sudo apt-get install -y jq
- name: Fetch release JSON by tag
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
set -euo pipefail
OWNER="${GITHUB_REPOSITORY%/*}"
REPO="${GITHUB_REPOSITORY#*/}"
TAG="${{ github.event.workflow_run.head_branch }}"
# head_branch is the tag name for a tag push workflow_run
curl -fsSL -H "Authorization: Bearer $GH_TOKEN" \
-H "Accept: application/vnd.github+json" \
"https://api.github.com/repos/$OWNER/$REPO/releases/tags/$TAG" \
> release.json
- name: Wrap as 'release' event payload & notify bot
env:
URL: http://${{ secrets.DISCORDBOT }}:3000/github-releases
run: |
set -euo pipefail
jq -n --slurpfile rel release.json \
--arg repo "$GITHUB_REPOSITORY" \
--arg repo_url "https://github.com/$GITHUB_REPOSITORY" \
--arg action "published" '
{ action: $action,
repository: { full_name: $repo, html_url: $repo_url },
release: $rel[0],
sender: { login: "github-actions[bot]" } }' > payload.json
curl -sS -X POST "$URL" \
-H 'Content-Type: application/json' \
--data-binary "@payload.json"

View File

@@ -1,6 +1,6 @@
name "Jim_Bridge" name "Jim_Bridge"
author "Jimathy" author "Jimathy"
version "2.1.0" version "2.1.04"
description "Framework Bridge By Jimathy" description "Framework Bridge By Jimathy"
fx_version "cerulean" fx_version "cerulean"
rdr3_warning 'I acknowledge that this is a prerelease build of RedM, and I am aware my resources *will* become incompatible once RedM ships.' rdr3_warning 'I acknowledge that this is a prerelease build of RedM, and I am aware my resources *will* become incompatible once RedM ships.'

View File

@@ -124,7 +124,6 @@ end
function distExploitCheck(table, src) function distExploitCheck(table, src)
if forceDisableExplotProtection == true then return true end if forceDisableExplotProtection == true then return true end
if not table then if not table then
print("^1Error^7: ^1This wasn^7'^1t reigstered correctly or this is an exploit attempt^1") print("^1Error^7: ^1This wasn^7'^1t reigstered correctly or this is an exploit attempt^1")
return false return false
@@ -135,7 +134,7 @@ function distExploitCheck(table, src)
local allow = false local allow = false
for i = 1, #table do for i = 1, #table do
if #(table[i].xyz - srcCoords) <= 10 then if #(table[i].xy - srcCoords.xy) <= 10 then
return true return true
else else
allow = false allow = false
@@ -143,7 +142,7 @@ function distExploitCheck(table, src)
end end
if not allow then if not allow then
print(src and ("^1Src ^3"..src.." ").."^1Tried to open a registered shop/stash from over the distance limit^7") print(src and ("^1Src ^3"..src.." ") or "", "^1Tried to open a registered shop/stash from over the distance limit^7")
return false return false
end end

View File

@@ -27,6 +27,132 @@ local function _debouncedRun(func)
end) end)
end end
local frameworkLoadFunc = {
{ framework = Exports.QBXExport,
onPlayerLoaded =
function(func)
RegisterNetEvent('QBCore:Client:OnPlayerLoaded', func)
end,
onPlayerUnload =
function(func)
RegisterNetEvent('QBCore:Client:OnPlayerUnload', func)
end,
waitforLogin =
function(timeout)
local startTime = GetGameTimer()
while not LocalPlayer.state.isLoggedIn and (GetGameTimer() - startTime) < timeout do
Wait(100)
end
return LocalPlayer.state.isLoggedIn
end,
},
{ framework = Exports.QBExport,
onPlayerLoaded =
function(func)
RegisterNetEvent('QBCore:Client:OnPlayerLoaded', func)
end,
onPlayerUnload =
function(func)
RegisterNetEvent('QBCore:Client:OnPlayerUnload', func)
end,
waitforLogin =
function(timeout)
local startTime = GetGameTimer()
while not LocalPlayer.state.isLoggedIn and (GetGameTimer() - startTime) < timeout do
Wait(100)
end
return LocalPlayer.state.isLoggedIn
end,
},
{ framework = Exports.ESXExport,
onPlayerLoaded =
function(func)
RegisterNetEvent("esx:playerLoaded", function()
-- make sure shared has loaded (because sql)
if waitForSharedLoad() then func() end
end)
end,
onPlayerUnload =
function(func)
RegisterNetEvent("esx:onPlayerLogout", func)
end,
waitforLogin =
function(timeout)
local startTime = GetGameTimer()
while (GetGameTimer() - startTime) < timeout do
local playerData = ESX.GetPlayerData()
if playerData and playerData.job then
return true
end
Wait(100)
end
end,
},
{ framework = Exports.OXCoreExport,
onPlayerLoaded =
function(func)
RegisterNetEvent('ox:playerLoaded', func)
end,
onPlayerUnload =
function(func)
RegisterNetEvent('ox:playerLogout', func)
end,
waitforLogin =
function(timeout)
if OxPlayer["stateId"] then
return true
end
while not OxPlayer["stateId"] do
Wait(1000)
if OxPlayer.get["stateId"] then
return true
end
end
end,
},
{ framework = Exports.RSGExport,
onPlayerLoaded =
function(func)
RegisterNetEvent('RSGCore:Client:OnPlayerLoaded', func)
end,
onPlayerUnload =
function(func)
RegisterNetEvent('RSGCore:Client:OnPlayerUnload', func)
end,
waitforLogin =
function(timeout)
local startTime = GetGameTimer()
while not LocalPlayer.state.isLoggedIn and (GetGameTimer() - startTime) < timeout do
Wait(100)
end
return LocalPlayer.state.isLoggedIn
end,
},
{ framework = Exports.VorpExport,
onPlayerLoaded =
function(func)
RegisterNetEvent('vorp_core:Client:OnPlayerSpawned', func)
end,
onPlayerUnload =
function(func)
--??
end,
waitforLogin =
function(timeout)
local startTime = GetGameTimer()
while not LocalPlayer.state.IsInSession and (GetGameTimer() - startTime) < timeout do
Wait(100)
end
return LocalPlayer.state.IsInSession
end,
},
}
------------------------------------------------------------- -------------------------------------------------------------
-- Player Loaded and Unloaded Events -- Player Loaded and Unloaded Events
------------------------------------------------------------- -------------------------------------------------------------
@@ -44,9 +170,6 @@ end
--- end, true) --- end, true)
--- ``` --- ```
function onPlayerLoaded(func, onStart) function onPlayerLoaded(func, onStart)
local onPlayerFramework = ""
local loaded = false
if onStart then if onStart then
onResourceStart(function() onResourceStart(function()
if not waitForLogin() then return end if not waitForLogin() then return end
@@ -59,34 +182,16 @@ function onPlayerLoaded(func, onStart)
_debouncedRun(func) _debouncedRun(func)
end end
if isStarted(QBExport) or isStarted(QBXExport) then for i = 1, #frameworkLoadFunc do
onPlayerFramework = QBExport local data = frameworkLoadFunc[i]
RegisterNetEvent('QBCore:Client:OnPlayerLoaded', handler) jsonPrint(data)
if isStarted(data.framework) then
elseif isStarted(ESXExport) then debugPrint("^6Bridge^7: ^2Registering ^3"..data.framework.." ^5onPlayerLoaded^7()")
onPlayerFramework = ESXExport data.onPlayerLoaded(handler)
RegisterNetEvent('esx:playerLoaded', function() return
if waitForSharedLoad() then handler() end end
end)
elseif isStarted(OXCoreExport) then
onPlayerFramework = OXCoreExport
RegisterNetEvent('ox:playerLoaded', handler)
elseif isStarted(RSGExport) then
onPlayerFramework = RSGExport
RegisterNetEvent('RSGCore:Client:OnPlayerLoaded', handler)
elseif isStarted(VorpExport) then
onPlayerFramework = VorpExport
RegisterNetEvent('vorp_core:Client:OnPlayerSpawned', handler)
end
if onPlayerFramework ~= "" then
debugPrint("^6Bridge^7: ^2Registering ^3onPlayerLoaded^7()^2 with ^3" .. onPlayerFramework .. "^7")
else
print("^4ERROR^7: No supported core detected for onPlayerLoaded - Check starter.lua")
end end
print("^1ERROR^7: ^1No supported core detected for onPlayerLoaded - Check starter.lua^7")
end end
--- Executes a function when the player character is unloaded. --- Executes a function when the player character is unloaded.
@@ -99,15 +204,15 @@ end
--- end) --- end)
--- ``` --- ```
function onPlayerUnload(func) function onPlayerUnload(func)
debugPrint("^6Bridge^7: ^2Registering ^3onPlayerUnload^7()") for i = 1, #frameworkLoadFunc do
RegisterNetEvent('QBCore:Client:OnPlayerUnload', function() func() end) local data = frameworkLoadFunc[i]
if isStarted(data.framework) then
RegisterNetEvent('ox:playerLogout', function() func() end) debugPrint("^6Bridge^7: ^2Registering ^3"..data.framework.." ^5onPlayerUnload^7()")
data.onPlayerUnload(func)
RegisterNetEvent('RSGCore:Client:OnPlayerUnload', function() func() end) return
end
RegisterNetEvent('esx:onPlayerLogout', function() func() end) end
print("^1ERROR^7: ^1No supported core detected for onPlayerUnload - Check starter.lua^7")
end end
------------------------------------------------------------- -------------------------------------------------------------
@@ -166,51 +271,18 @@ end
--- @usage --- @usage
--- waitForLogin() --- waitForLogin()
function waitForLogin() function waitForLogin()
local timeout = 10000 -- 10 seconds in milliseconds for i = 1, #frameworkLoadFunc do
local startTime = GetGameTimer() local data = frameworkLoadFunc[i]
local loggedIn = false if isStarted(data.framework) then
debugPrint("^6Bridge^7: ^2Waiting for ^3"..data.framework.."^2 player login^7.")
if isStarted(ESXExport) then local result = data.waitforLogin(10000)
while (GetGameTimer() - startTime) < timeout do if result == true then
local playerData = ESX.GetPlayerData() debugPrint("^6Bridge^7: ^3"..data.framework.."^2 Player Login Detected^7.")
if playerData and playerData.job then else
loggedIn = true print("^4Error^7: ^2Timeout reached while waiting for player login^7.")
break
end end
Wait(100) return result
end end
elseif isStarted(OXCoreExport) then
if OxPlayer["stateId"] then
loggedIn = true
end
while not OxPlayer["stateId"] do
Wait(1000)
debugPrint("Waiting for stateId to class as logged in")
if OxPlayer.get["stateId"] then
loggedIn = true
break
end
end
elseif isStarted(VorpExport) then
-- For other frameworks, use LocalPlayer.state.isLoggedIn.
while not LocalPlayer.state.IsInSession and (GetGameTimer() - startTime) < timeout do
Wait(100)
end
loggedIn = LocalPlayer.state.IsInSession
else
-- For other frameworks, use LocalPlayer.state.isLoggedIn.
while not LocalPlayer.state.isLoggedIn and (GetGameTimer() - startTime) < timeout do
Wait(100)
end
loggedIn = LocalPlayer.state.isLoggedIn
end
if not loggedIn then
print("^4Error^7: ^2Timeout reached while waiting for player login^7.")
return false
else
debugPrint("^6Bridge^7: ^2Player Login Detected^7.")
return true
end end
end end

View File

@@ -17,7 +17,8 @@ local excludeKeys = {
amount = true, metadata = true, description = true, info = true, amount = true, metadata = true, description = true, info = true,
job = true, gang = true, oneUse = true, slot = true, job = true, gang = true, oneUse = true, slot = true,
blueprintRef = true, craftingLevel = true, craftedItems = true, blueprintRef = true, craftingLevel = true, craftedItems = true,
hasCrafted = true, exp = true, anim = true, time = true, hasCrafted = true, exp = true, anim = true, time = true, id = true,
ingredients = true,
} }
------------------------------------------------------------- -------------------------------------------------------------
@@ -40,9 +41,14 @@ local excludeKeys = {
--- craftable = { --- craftable = {
--- Header = "Weapon Crafting", --- Header = "Weapon Crafting",
--- Recipes = { --- Recipes = {
--- [1] = { --- weapon_pistol = {
--- ["weapon_pistol"] = { ["steel"] = 5, ["plastic"] = 2 }, --- id = 1,
--- amount = 1, --- ingredients = {
--- steel = 5, plastic = 5,
--- },
--- info = {
--- amount = 1,
--- },
--- }, --- },
--- -- More recipes... --- -- More recipes...
--- }, --- },
@@ -56,6 +62,7 @@ local excludeKeys = {
--- job = "mechanic", --- job = "mechanic",
--- onBack = function() print("Returning to previous menu") end, --- onBack = function() print("Returning to previous menu") end,
--- }) --- })
--- ```
function craftingMenu(data) function craftingMenu(data)
if CraftLock then return end if CraftLock then return end
@@ -72,16 +79,49 @@ function craftingMenu(data)
-- Normalize stash name. -- Normalize stash name.
data.stashName = data.stashTable or data.stashName data.stashName = data.stashTable or data.stashName
-- Wrapper to convert old style crafting recipes to be handled by the menu properly
if data.craftable.Recipes[1] then -- assume old style crafting table
local compatTable = {}
local id = 0
for k, v in ipairs(data.craftable.Recipes) do
local Recipe = v
for l, b in pairs(Recipe) do
id += 1
if doesItemExist(l) then
compatTable[l] = {
ingredients = b,
id = id,
info = {
amount = Recipe.amount or 1,
metadata = Recipe.metadata or nil,
job = Recipe.job or nil,
gang = Recipe.gang or nil,
hasCrafted = Recipe.hasCrafted or nil,
},
}
end
end
end
data.craftable.Recipes = compatTable
end
-- Convert to array
local RecipesArray = {}
for k, v in pairs(data.craftable.Recipes) do
RecipesArray[v.id] = { [k] = v }
end
local Menu = {} local Menu = {}
local Recipes = data.craftable.Recipes local Recipes = data.craftable.Recipes
local craftedItems = {} local craftedItems = {}
local tempCarryTable = {}
-- Build a table of all required ingredients (default quantity is 1). local tempCarryTable = {}
for i = 1, #Recipes do -- Build a temporary table of all required ingredients (default quantity is 1).
for k in pairs(Recipes[i]) do for i = 1, #RecipesArray do
if k ~= "amount" and k ~= "metadata" and k ~= "job" and k ~= "gang" then for k, v in pairs(RecipesArray[i]) do
tempCarryTable[k] = Recipes[i].amount or 1 if doesItemExist(k) then
if not v.info.amount then v.info.amount = 1 end
tempCarryTable[k] = tempCarryTable[k] and (tempCarryTable[k] < v.info.amount) or v.info.amount
end end
end end
end end
@@ -97,75 +137,89 @@ function craftingMenu(data)
disabled = true, disabled = true,
} }
-- Process each recipe to create menu entries. for i = 1, #RecipesArray do
for i = 1, #Recipes do local item = ""
if not Recipes[i]["amount"] then Recipes[i]["amount"] = 1 end for k in pairs(RecipesArray[i]) do
for k, _ in pairs(Recipes[i]) do
if not excludeKeys[k] then if not excludeKeys[k] then
local hasjob = true item = k
if Recipes[i].job then break
for l, b in pairs(Recipes[i].job) do
hasjob = hasJob(l, nil, b)
if hasjob then break end
end
end
if hasjob then
local setheader, settext, disable, metadata = "", "", false, (Recipes[i]["metadata"] or Recipes[i]["info"] or nil)
local itemTable = {}
local metaTable = {}
-- Build ingredient details.
for l, b in pairs(Recipes[i][tostring(k)]) do
local label = getItemLabel(l)
local hasItem = checkStashItem(data.stashName, { [l] = b })
local missingMark = not hasItem and "" or " "
settext = settext..(settext ~= "" and br or "").."[ x"..b.." ] - "..label..missingMark
metaTable[label] = b
itemTable[l] = b
end
while not canCarryTable do
Wait(10)
end
disable = not checkStashItem(data.stashName, itemTable)
setheader = ((metadata and metadata.label) or getItemLabel(k))
..(Recipes[i]["amount"] > 1 and " x"..Recipes[i]["amount"] or "")
local statusEmoji = disable and " " or not canCarryTable[k] and " 📦" or " ✔️"
local isNew = (Recipes[i]["hasCrafted"] ~= nil and craftedItems[k] == nil) and "" or ""
setheader = isNew .. setheader .. statusEmoji
Menu[#Menu + 1] = {
arrow = isOx() and (not disable and canCarryTable[k]),
isMenuHeader = disable or not canCarryTable[k],
icon = invImg((metadata and metadata.image) or tostring(k)),
image = invImg((metadata and metadata.image) or tostring(k)),
header = setheader,
txt = settext or nil,
metadata = metaTable,
onSelect = (not disable and canCarryTable[k]) and function()
local transdata = {
item = k,
craft = data.craftable.Recipes[i],
craftable = data.craftable,
coords = data.coords,
stashName = data.stashName,
onBack = data.onBack,
metadata = metadata,
}
if Config.Crafting.MultiCraft then
multiCraft(transdata)
else
makeItem(transdata)
end
end or nil,
}
end
end end
--Wait(0) end
local Recipe = RecipesArray[i][item]
-- Job Check
local hasGroup = true
if Recipe.info.job then
for l, b in pairs(Recipe.info.job) do
hasGroup = hasJob(l, nil, b)
if hasGroup then goto skipcheck end
end
end
if Recipe.info.gang then
for l, b in pairs(Recipe.info.gang) do
hasGroup = hasJob(l, nil, b)
if hasGroup then goto skipcheck end
end
end
::skipcheck::
-- if has group requirement, continue
if hasGroup then
local setheader, settext, disable, metadata = "", "", false, (Recipe.info.metadata or Recipe.info.info or nil)
local itemTable = {}
local metaTable = {}
-- Build ingredient details.
for l, b in pairs(Recipe.ingredients) do
local label = getItemLabel(l)
local hasItem = checkStashItem(data.stashName, { [l] = b })
local missingMark = not hasItem and "" or " "
settext = settext..(settext ~= "" and br or "").."[ x"..b.." ] - "..label..missingMark
metaTable[label] = b
itemTable[l] = b
end
-- Make sure "canCarryTable" exists
while not canCarryTable do Wait(10) end
disable = not checkStashItem(data.stashName, itemTable)
setheader = ((metadata and metadata.label) or getItemLabel(item))
..(Recipe.info.amount > 1 and " x"..Recipe.info.amount or "")
local statusEmoji = disable and " " or not canCarryTable[item] and " 📦" or " ✔️"
local isNew = (Recipe.info.hasCrafted ~= nil and craftedItems[item] == nil) and "" or ""
setheader = isNew .. setheader .. statusEmoji
-- Build menu option using info
Menu[#Menu + 1] = {
arrow = isOx() and (not disable and canCarryTable[item]),
isMenuHeader = disable or not canCarryTable[item],
icon = invImg((metadata and metadata.image) or item),
image = invImg((metadata and metadata.image) or item),
header = setheader,
txt = settext or nil,
metadata = metaTable,
onSelect = (not disable and canCarryTable[item]) and function()
local transdata = {
item = item,
craft = RecipesArray[i][item],
craftable = data.craftable,
coords = data.coords,
stashName = data.stashName,
onBack = data.onBack,
metadata = metadata,
}
if Config.Crafting.MultiCraft then
multiCraft(transdata)
else
makeItem(transdata)
end
end or nil,
}
end end
end end
-- open context menu
openMenu(Menu, { openMenu(Menu, {
header = data.craftable.Header, header = data.craftable.Header,
headertxt = data.craftable.Headertxt, headertxt = data.craftable.Headertxt,
@@ -216,7 +270,7 @@ function multiCraft(data)
for i = 1, maxCreation do for i = 1, maxCreation do
multiItemTable[i] = {} multiItemTable[i] = {}
for l, b in pairs(data.craft[data.item]) do for l, b in pairs(data.craft.ingredients) do
multiItemTable[i][l] = (b * i) multiItemTable[i][l] = (b * i)
end end
end end
@@ -323,6 +377,7 @@ end
--- ``` --- ```
function makeItem(data) function makeItem(data)
local Ped = PlayerPedId()
if CraftLock then return end if CraftLock then return end
CraftLock = true CraftLock = true
data.stashName = data.stashTable or data.stashName data.stashName = data.stashTable or data.stashName
@@ -336,106 +391,62 @@ function makeItem(data)
local craftAmount = (data.amount and data.amount ~= 1) and data.amount or 1 local craftAmount = (data.amount and data.amount ~= 1) and data.amount or 1
local metadata = data.metadata or nil local metadata = data.metadata or nil
local prop = data.craftable.Anims and data.craftable.Anims.prop or nil local prop = data.craftable.Anims and data.craftable.Anims.prop or nil
jsonPrint(prop)
local canReturn = true local canReturn = true
local crafted, crafting = true, true local crafted, crafting = true, true
local cam = createTempCam(PlayerPedId(), data.coords) local cam = createCam(Ped, data.coords.xyz)
startTempCam(cam) startCam(cam, 5000)
-- Calculate total bartime if SingleProgress is enabled -- Calculate total bartime if SingleProgress is enabled
local totalBartime = bartime * craftAmount local totalBartime = (bartime * craftAmount)
-- Run ingredient check and usage separately first local craftProp = nil
for i = 1, craftAmount do if prop then
for k, v in pairs(data.craft) do craftProp = makeProp({ prop = prop.model, coords = GetEntityCoords(PlayerPedId()), true, true })
if not excludeKeys[k] and type(v) == "table" then AttachEntityToEntity(craftProp, Ped, GetPedBoneIndex(Ped, prop.bone), prop.pos.x, prop.pos.y, prop.pos.z, prop.rot.x, prop.rot.y, prop.rot.z, true, true, false, true, 1, true)
for l, b in pairs(v) do
if isInventoryOpen() then
print("^1Error^7: ^2Inventory is open, you tried to break things")
stopTempCam()
ClearPedTasks(PlayerPedId())
if canReturn then craftingMenu(data) end
CraftLock = false
return
end
if crafting and progressBar({
label = "Using "..b.." "..getItemLabel(l),
time = 1000,
cancel = true,
dict = 'pickup_object',
anim = "putdown_low",
flag = 49,
icon = l,
}) then
TriggerEvent((isStarted(QBInv) and QBInvNew and "qb-" or "")..'inventory:client:ItemBox', Items[l], "use", b)
else
crafted, crafting = false, false
break
end
Wait(200)
end
end
end
end end
if data.sound then
if not crafted then local s = data.sound
stopTempCam() PlaySoundFromEntity(s.soundId, s.audioName, Ped, s.audioRef, true, 0)
ClearPedTasks(PlayerPedId())
if canReturn then craftingMenu(data) end
CraftLock = false
return
end end
if not Config.Crafting.SingleProgress then -- if SingleProgress is disabled, dont do ingredient progressbars
-- Handle SingleProgress option -- Run ingredient check and usage separately first
if Config.Crafting.SingleProgress then
local craftProp = nil
if prop then
craftProp = makeProp({ prop = prop.model, coords = vec4(0, 0, 0, 0), true, true })
AttachEntityToEntity(craftProp, PlayerPedId(), GetPedBoneIndex(PlayerPedId(), prop.bone), prop.pos.x, prop.pos.y, prop.pos.z, prop.rot.x, prop.rot.y, prop.rot.z, true, true, false, true, 1, true)
end
if data.sound then
local s = data.sound
PlaySoundFromEntity(s.soundId, s.audioName, PlayerPedId(), s.audioRef, true, 0)
end
if crafting and progressBar({
label = bartext..((metadata and metadata.label) or getItemLabel(data.item)).." x"..craftAmount,
time = totalBartime,
cancel = true,
dict = animDict,
anim = anim,
flag = 49,
icon = data.item,
request = true,
}) then
data.craft.amount = craftAmount
TriggerServerEvent(getScript()..":Crafting:GetItem", data.item, data.craft, data.stashName, metadata, currentToken)
currentToken = nil -- clear client cached token
-- handle metadata and experience in a single go
if data.craft["hasCrafted"] ~= nil then
data.craftable.craftedItems[data.item] = true
triggerCallback(getScript()..":server:setPlayerMetadata", "craftedItems", data.craftable.craftedItems)
end
if data.craft["exp"] ~= nil then
craftingLevel += data.craft["exp"].give * craftAmount
triggerCallback(getScript()..":server:setPlayerMetadata", "craftingLevel", craftingLevel)
end
if data.craftable.Recipes[1].oneUse == true then
removeItem("craftrecipe", 1, nil, data.craftable.Recipes[1].slot)
local breakId = GetSoundId()
PlaySoundFromEntity(breakId, "Drill_Pin_Break", PlayerPedId(), "DLC_HEIST_FLEECA_SOUNDSET", 1, 0)
canReturn = false
end
if data.sound then
StopSound(data.sound.soundId)
end
if data.requiredItemfunc then
data.requiredItemfunc()
end
end
if craftProp then destroyProp(craftProp) end
else
-- Run the original loop for multiple progress bars
for i = 1, craftAmount do for i = 1, craftAmount do
for k, v in pairs(data.craft.ingredients) do
if isInventoryOpen() then
print("^1Error^7: ^2Inventory is open, you tried to break things")
stopCam(0)
ClearPedTasks(Ped)
if canReturn then craftingMenu(data) end
CraftLock = false
return
end
if crafting and progressBar({
label = "Using "..v.." "..getItemLabel(k),
time = 800,
cancel = true,
dict = 'pickup_object',
anim = "putdown_low",
flag = 49,
icon = k,
}) then
TriggerEvent((isStarted(QBInv) and QBInvNew and "qb-" or "")..'inventory:client:ItemBox', Items[k], "use", v)
else
crafted, crafting = false, false
break
end
Wait(200)
end
if not crafted then
stopCam(0)
ClearPedTasks(Ped)
if canReturn then craftingMenu(data) end
CraftLock = false
return
end
if crafting and progressBar({ if crafting and progressBar({
label = bartext..((metadata and metadata.label) or getItemLabel(data.item)), label = bartext..((metadata and metadata.label) or getItemLabel(data.item)),
time = bartime, time = bartime,
@@ -448,34 +459,76 @@ function makeItem(data)
}) then }) then
TriggerServerEvent(getScript()..":Crafting:GetItem", data.item, data.craft, data.stashName, metadata, currentToken) TriggerServerEvent(getScript()..":Crafting:GetItem", data.item, data.craft, data.stashName, metadata, currentToken)
currentToken = nil currentToken = nil
if data.craft["hasCrafted"] ~= nil then if data.craft.info.hasCrafted ~= nil then
data.craftable.craftedItems[data.item] = true data.craftable.craftedItems[data.item] = true
triggerCallback(getScript()..":server:setPlayerMetadata", "craftedItems", data.craftable.craftedItems) triggerCallback(getScript()..":server:setPlayerMetadata", "craftedItems", data.craftable.craftedItems)
end end
if data.craft["exp"] ~= nil then if data.craft.info.exp ~= nil then
craftingLevel += data.craft["exp"].give craftingLevel += data.craft.exp.give
triggerCallback(getScript()..":server:setPlayerMetadata", "craftingLevel", craftingLevel) triggerCallback(getScript()..":server:setPlayerMetadata", "craftingLevel", craftingLevel)
end end
if data.craftable.Recipes[1].oneUse == true then --if data.craftable.Recipes[1].oneUse == true then
removeItem("craftrecipe", 1, nil, data.craftable.Recipes[1].slot) -- removeItem("craftrecipe", 1, nil, data.craftable.Recipes[1].slot)
local breakId = GetSoundId() -- local breakId = GetSoundId()
PlaySoundFromEntity(breakId, "Drill_Pin_Break", PlayerPedId(), "DLC_HEIST_FLEECA_SOUNDSET", 1, 0) -- PlaySoundFromEntity(breakId, "Drill_Pin_Break", Ped, "DLC_HEIST_FLEECA_SOUNDSET", 1, 0)
canReturn = false -- canReturn = false
end --end
if data.requiredItemfunc then if data.requiredItemfunc then
data.requiredItemfunc() data.requiredItemfunc()
end end
else else
break break
end end
end
else
if crafting and progressBar({
label = bartext..((metadata and metadata.label) or getItemLabel(data.item)).." x"..craftAmount,
time = totalBartime,
cancel = true,
dict = animDict,
anim = anim,
flag = 49,
icon = data.item,
request = true,
}) then
data.craft.info.amount = craftAmount
for k, v in pairs(data.craft.ingredients) do
-- multiply igredient requirement in sent crafting table for removal
data.craft.ingredients[k] = (v * craftAmount)
end
TriggerServerEvent(getScript()..":Crafting:GetItem", data.item, data.craft, data.stashName, metadata, currentToken)
currentToken = nil -- clear client cached token
-- handle metadata and experience in a single go
if data.craft.info.hasCrafted ~= nil then
data.craftable.craftedItems[data.item] = true
triggerCallback(getScript()..":server:setPlayerMetadata", "craftedItems", data.craftable.craftedItems)
end
if data.craft.info.exp ~= nil then
craftingLevel += data.craft["exp"].give * craftAmount
triggerCallback(getScript()..":server:setPlayerMetadata", "craftingLevel", craftingLevel)
end
--if data.craft.Recipes[1].oneUse == true then
-- removeItem("craftrecipe", 1, nil, data.craftable.Recipes[1].slot)
-- local breakId = GetSoundId()
-- PlaySoundFromEntity(breakId, "Drill_Pin_Break", Ped, "DLC_HEIST_FLEECA_SOUNDSET", 1, 0)
-- canReturn = false
--end
if data.sound then
StopSound(data.sound.soundId)
end
if data.requiredItemfunc then
data.requiredItemfunc()
end
end end
end end
if craftProp then destroyProp(craftProp) end
Wait(500) --Wait(500)
stopTempCam() stopCam(0)
CraftLock = false CraftLock = false
if canReturn then craftingMenu(data) end if canReturn then craftingMenu(data) end
ClearPedTasks(PlayerPedId()) ClearPedTasks(Ped)
end end
@@ -505,14 +558,13 @@ RegisterNetEvent(getScript()..":Crafting:GetItem", function(ItemMake, craftable,
return return
end end
local hasItems, hasTable = hasItem(ItemMake, 1, src) local hasItems, hasTable = hasItem(ItemMake, 1, src)
if stashName then if stashName then
local itemRemove = {} local itemRemove = {}
if type(stashName) == "table" then if type(stashName) == "table" then
for _, name in pairs(stashName) do for _, name in pairs(stashName) do
stashItems = getStash(name) stashItems = getStash(name)
for k, v in pairs(craftable[ItemMake] or {}) do for k, v in pairs(craftable.ingredients) do
for _, b in pairs(stashItems or {}) do for _, b in pairs(stashItems or {}) do
if k == b.name then if k == b.name then
itemRemove[k] = v itemRemove[k] = v
@@ -522,7 +574,7 @@ RegisterNetEvent(getScript()..":Crafting:GetItem", function(ItemMake, craftable,
end end
else else
stashItems = getStash(stashName) stashItems = getStash(stashName)
for k, v in pairs(craftable[ItemMake] or {}) do for k, v in pairs(craftable.ingredients) do
for _, b in pairs(stashItems or {}) do for _, b in pairs(stashItems or {}) do
if k == b.name then if k == b.name then
itemRemove[k] = v itemRemove[k] = v
@@ -533,12 +585,12 @@ RegisterNetEvent(getScript()..":Crafting:GetItem", function(ItemMake, craftable,
stashRemoveItem(stashItems, stashName, itemRemove) stashRemoveItem(stashItems, stashName, itemRemove)
else else
if craftable then if craftable then
for k, v in pairs(craftable[ItemMake] or {}) do for k, v in pairs(craftable.ingredients or {}) do
removeItem(tostring(k), v, src) removeItem(tostring(k), v, src)
end end
end end
end end
addItem(ItemMake, craftable.amount or 1, metadata, src) addItem(ItemMake, craftable.info.amount or 1, metadata, src)
-- Optionally, add experience here: -- Optionally, add experience here:
-- for example: -- for example:
-- if isStarted("core_skills") then exports["core_skills"]:AddExperience(src, 2) end -- if isStarted("core_skills") then exports["core_skills"]:AddExperience(src, 2) end

View File

@@ -56,7 +56,7 @@ local InvFunc = {
local weight = 0 local weight = 0
local itemcheck = getPlayerInv(src) local itemcheck = getPlayerInv(src)
for _, v in pairs(itemcheck) do for _, v in pairs(itemcheck) do
weight += ((v.weight * v.amount) or 0) weight += v.weight
end end
return weight return weight
end, end,
@@ -88,7 +88,6 @@ local InvFunc = {
inventory = items, inventory = items,
society = society, society = society,
}) })
debugPrint("^6Bridge^7: ^2Registering ^5"..OXInv.." ^3Store^7:", name, "^4Label^7: "..label)
end, end,
openStash = openStash =
function(data) function(data)
@@ -123,7 +122,6 @@ local InvFunc = {
registerStash = registerStash =
function(name, label, slots, weight, owner, coords) function(name, label, slots, weight, owner, coords)
exports[OXInv]:RegisterStash(name, label, slots or 50, weight or 4000000, owner or nil) exports[OXInv]:RegisterStash(name, label, slots or 50, weight or 4000000, owner or nil)
debugPrint("^6Bridge^7: ^2Registering ^4"..OXInv.." ^3Stash^7:", name, "^4Label^7: "..label)
end, end,
}, },
@@ -322,7 +320,6 @@ local InvFunc = {
registerStash = registerStash =
function(name, label, slots, weight, owner, coords) function(name, label, slots, weight, owner, coords)
exports[OrigenInv]:registerStash(name, label, slots or 50, weight or 4000000) exports[OrigenInv]:registerStash(name, label, slots or 50, weight or 4000000)
debugPrint("^6Bridge^7: ^2Registering ^4"..OrigenInv.." ^3Stash^7:", name, "^4Label^7: "..label)
end, end,
}, },
@@ -344,7 +341,7 @@ local InvFunc = {
local count = 0 local count = 0
for _, itemData in pairs(invCache) do for _, itemData in pairs(invCache) do
if itemData and itemData.name == item then if itemData and itemData.name == item then
count += (itemData.amount or itemData.count or 1) count += (itemData.amount or 0)
end end
end end
return count >= amount, count return count >= amount, count
@@ -387,7 +384,7 @@ local InvFunc = {
if src then if src then
grabInv = exports[CodeMInv]:GetInventory(getPlayer(src).citizenId, src) grabInv = exports[CodeMInv]:GetInventory(getPlayer(src).citizenId, src)
else else
grabInv = exports[CodeMInv]:getUserInventory() grabInv = exports[CodeMInv]:GetClientPlayerInventory()
end end
return grabInv return grabInv
end, end,
@@ -514,7 +511,6 @@ local InvFunc = {
registerShop = registerShop =
function(name, label, items, society) function(name, label, items, society)
exports[TgiannInv]:RegisterShop(name, items) exports[TgiannInv]:RegisterShop(name, items)
debugPrint("^6Bridge^7: ^2Registering ^5"..TgiannInv.." ^3Store^7:", name, "^4Label^7: "..label)
end, end,
openStash = openStash =
function(data) function(data)
@@ -548,7 +544,6 @@ local InvFunc = {
registerStash = registerStash =
function(name, label, slots, weight, owner, coords) function(name, label, slots, weight, owner, coords)
exports[TgiannInv]:RegisterStash(name, label, slots or 50, weight or 4000000) exports[TgiannInv]:RegisterStash(name, label, slots or 50, weight or 4000000)
debugPrint("^6Bridge^7: ^2Registering ^4"..TgiannInv.." ^3Stash^7:", name, "^4Label^7: "..label)
end, end,
}, },
@@ -841,7 +836,6 @@ local InvFunc = {
items = items, items = items,
society = society, society = society,
}) })
debugPrint("^6Bridge^7: ^2Registering ^5"..QBInv.." ^3Store^7:", name, "^4Label^7: "..label)
end end
end, end,
openStash = openStash =
@@ -1040,7 +1034,6 @@ local InvFunc = {
items = items, items = items,
society = society, society = society,
}) })
debugPrint("^6Bridge^7: ^2Registering ^5"..PSInv.." ^3Store^7:", name, "^4Label^7: "..label)
end end
end, end,
openStash = openStash =
@@ -1206,7 +1199,6 @@ local InvFunc = {
items = items, items = items,
society = society, society = society,
}) })
debugPrint("^6Bridge^7: ^2Registering ^5"..RSGInv.." ^3Store^7:", name, "^4Label^7: "..label)
end, end,
openStash = openStash =
function(data) function(data)
@@ -1287,6 +1279,7 @@ end
function hasItem(items, amount, src) function hasItem(items, amount, src)
local amount = amount and amount or 1 local amount = amount and amount or 1
local grabInv, foundInv = getPlayerInv(src) local grabInv, foundInv = getPlayerInv(src)
if type(items) ~= "table" then items = { [items] = amount and amount or 1, } end if type(items) ~= "table" then items = { [items] = amount and amount or 1, } end
local hasTable = {} local hasTable = {}
@@ -1575,7 +1568,7 @@ RegisterNetEvent(getScript()..":server:toggleItem", function(give, item, amount,
end end
else else
debugPrint("^6Bridge^7: ^3"..action.."^7["..invName.."] Player("..src..") "..getItemLabel(item).."("..item..") x"..(amount or 1)) debugPrint("^6Bridge^7: ^3"..action.."^7[^6"..invName.."^7] Player(^3"..src.."^7) "..getItemLabel(item).."("..item..") x"..(amount or 1))
end end
end end
else else
@@ -1600,7 +1593,7 @@ RegisterNetEvent(getScript()..":server:toggleItem", function(give, item, amount,
ESX.GetPlayerFromId(src).addInventoryItem(item, amountToAdd) ESX.GetPlayerFromId(src).addInventoryItem(item, amountToAdd)
end end
else else
debugPrint("^6Bridge^7: ^3"..action.."^7["..invName.."] Player("..src..") "..getItemLabel(item).."("..item..") x"..(amount or 1)) debugPrint("^6Bridge^7: ^3"..action.."^7[^6"..invName.."^7] Player(^3"..src.."^7) "..getItemLabel(item).."("..item..") x"..(amount or 1))
end end
end end
end) end)
@@ -2104,9 +2097,7 @@ end
function openStash(data) function openStash(data)
if (data.job or data.gang) and not jobCheck(data.job or data.gang) then return end if (data.job or data.gang) and not jobCheck(data.job or data.gang) then return end
local p = promise.new() local exploitCheck = triggerCallback(getScript()..":getRegisteredStashLocations", data.stash)
p:resolve(triggerCallback(getScript()..":getRegisteredStashLocations", data.stash))
local exploitCheck = Citizen.Await(p)
if not exploitCheck then if not exploitCheck then
print("^3Warning^7: ^2This isn't a registered stash^1, refusing call^7") print("^3Warning^7: ^2This isn't a registered stash^1, refusing call^7")
@@ -2351,19 +2342,24 @@ end
--- ) --- )
--- ``` --- ```
function registerStash(name, label, slots, weight, owner, coords) function registerStash(name, label, slots, weight, owner, coords)
if coords then
stashExploitCheck[name] = stashExploitCheck[name] or {} -- ensure tables exist
stashExploitCheck[name][#stashExploitCheck[name]+1] = coords stashExploitCheck = stashExploitCheck or {}
else stashExploitCheck[name] = stashExploitCheck[name] or {}
print("^3Warning^7: ^1Stash ^4"..name.." ^1doesn^7'^1t have coords^7, ^1this is exploitable^7, ^1add coords to ^3regiterStash^7()")
end
for i = 1, #InvFunc do for i = 1, #InvFunc do
local inv = InvFunc[i] local inv = InvFunc[i]
if isStarted(inv.invName) then if isStarted(inv.invName) then
inv.registerStash(name, label, slots, weight, owner, coords) inv.registerStash(name, label, slots, weight, owner, coords)
return debugPrint("^6Bridge^7: ^2Registering ^4"..inv.invName.." ^3Stash^7:", name, "^4Label^7: "..label, coords and "- ^4Coord^7: "..formatCoord(coords) or "NO COORD SET")
break
end end
end end
if coords then
stashExploitCheck[name][#stashExploitCheck[name]+1] = coords.xyz
else
print("^3Warning^7: ^1Stash ^4"..name.." ^1doesn^7'^1t have coords^7, ^1this is exploitable^7, ^1add coords to ^3regiterStash^7()")
end
end end
if isServer() then if isServer() then
@@ -2394,17 +2390,17 @@ if isServer() then
end end
RegisterNetEvent(getScript()..":openGrabBox", function(data) RegisterNetEvent(getScript()..":openGrabBox", function(data)
if isStarted(OXInv) then local Ped = PlayerPedId()
return local id = data.metadata and data.metadata.id or data.info and data.info.id or ""
end
local id = "" if isStarted(OXInv) then
if data.metadata then
id = data.metadata.id return
elseif data.info then end
id = data.info.id
end
openStash({ openStash({
stash = id, stash = id,
coords = GetEntityCoords(Ped)
}) })
end) end)
@@ -2485,6 +2481,7 @@ function sellMenu(data)
sellMenu(origData) sellMenu(origData)
end end
v.sellTable = data.sellTable[k] v.sellTable = data.sellTable[k]
v.name = data.name
sellMenu(v) sellMenu(v)
end, end,
} }
@@ -2520,7 +2517,7 @@ end
--- ``` --- ```
function sellAnim(data, token) function sellAnim(data, token)
if not hasItem(data.item, 1) then if not hasItem(data.item, 1) then
triggerNotify(nil, Loc[Config.Lan].error["dont_have"].." "..getItemLabel(data.item), "error") triggerNotify(nil, (Loc[Config.Lan].error["dont_have"] or "You don't have any") .." "..getItemLabel(data.item), "error")
return return
end end
@@ -2587,8 +2584,8 @@ RegisterNetEvent(getScript()..":Sellitems", function(data, token)
end) end)
function registerSellShop(name, coords) function registerSellShop(name, coords)
if coords and type(coords) == "vector3" then if coords then
print("Registered Sell Shop "..name.." Correctly") debugPrint("^6Bridge^7: ^2Registering ^3Sell Store^7: "..name, coords and "- ^4Coord^7: "..formatCoord(coords) or "NO COORD SET")
sellShopExploitCheck[name] = sellShopExploitCheck[name] or {} sellShopExploitCheck[name] = sellShopExploitCheck[name] or {}
sellShopExploitCheck[name][#sellShopExploitCheck[name]+1] = coords sellShopExploitCheck[name][#sellShopExploitCheck[name]+1] = coords
end end
@@ -2688,29 +2685,30 @@ end)
--- registerShop("weaponShop", "Weapon Shop", weaponItems, "society_weapons") --- registerShop("weaponShop", "Weapon Shop", weaponItems, "society_weapons")
--- ``` --- ```
function registerShop(name, label, items, society, coords) function registerShop(name, label, items, society, coords)
local shopResource = "" -- ensure tables exist
shopExploitCheck = shopExploitCheck or {}
shopExploitCheck[name] = shopExploitCheck[name] or {}
if isStarted("jim-shops") then
-- Add support for new jim-shops registration export
if checkExportExists("jim-shops", "registerShop") then
exports["jim-shops"]:registerShop(name, label, items, society, coords)
end
end
for i = 1, #InvFunc do for i = 1, #InvFunc do
local inv = InvFunc[i] local inv = InvFunc[i]
if isStarted(inv.invName) then if isStarted(inv.invName) then
shopResource = inv.invName
inv.registerShop(name, label, items, society) inv.registerShop(name, label, items, society)
debugPrint("^6Bridge^7: ^2Registering ^5"..inv.invName.." ^3Store^7:", name, "^4Label^7: "..label, coords and "- ^4Coord^7: "..formatCoord(coords) or "NO COORD SET")
break break
end end
end end
-- If received coords, pass them to distance check cache -- If received coords, pass them to distance check cache
if coords and type(coords) == "vector3" then if coords then
--print("Registered Shop Correctly")
shopExploitCheck[name] = shopExploitCheck[name] or {}
shopExploitCheck[name][#shopExploitCheck[name]+1] = coords shopExploitCheck[name][#shopExploitCheck[name]+1] = coords
else else
print("^3Warning^7: ^1Store ^4"..name.." ^1doesn^7'^1t have coords^7, ^1this is exploitable^7, ^1add coords to ^3regiterShop^7()") print("^3Warning^7: ^1Store ^4"..name.." ^1doesn^7'^1t have coords^7, ^1this is exploitable^7, ^1add coords to ^3regiterShop^7()")
end end
if shopResource ~= "" then
debugPrint("^6Bridge^7: ^2Registering ^5"..shopResource.." ^3Store^7:", name, "^4Label^7: "..label)
else
-- debugPrint("^1ERROR^7: ^1Couldn't find supported inventory to register shop^7:", name)
end
end end

View File

@@ -33,6 +33,7 @@ local bossMenuFunc = {
{ name = "esx_society", { name = "esx_society",
openBossMenu = function(isGang, group) openBossMenu = function(isGang, group)
TriggerServerEvent(getScript()..":registerESXSociety", isGang, group)
TriggerEvent('esx_society:openBossMenu', group, function() end, { wash = false }) TriggerEvent('esx_society:openBossMenu', group, function() end, { wash = false })
end, end,
}, },
@@ -60,6 +61,20 @@ function openBossMenu(isGang, group)
end end
end end
-- Register ESX Society account in the server
RegisterNetEvent(getScript()..":registerESXSociety", function(group)
local checkExist = exports.esx_society:GetSociety(group)
if checkExist == nil then
exports.esx_society:registerSociety(
group,
Gangs[group] and Gangs[group].label or Jobs[group] and Jobs[group].label,
group,
group,
group,
{type = "public"}
)
end
end)
------------------------------------------------------------- -------------------------------------------------------------
-- Global Duty Status -- Global Duty Status

View File

@@ -71,6 +71,7 @@ function startTempCam(cam, renderTime, loadScene, filter, switchCam)
-- if moving from a cached previous cam, or you've sent a camre id for it to switch from, interpolate to it -- if moving from a cached previous cam, or you've sent a camre id for it to switch from, interpolate to it
if switchCam or cachePrevCam then if switchCam or cachePrevCam then
SetCamActiveWithInterp(cam, cachePrevCam, renderTime or 1000, 0, 0) SetCamActiveWithInterp(cam, cachePrevCam, renderTime or 1000, 0, 0)
SetCamActive(cachePrevCam, false) -- Set previous cam inactive (shouldn't be needed but just in case)
else else
SetCamActive(cam, true) SetCamActive(cam, true)
end end

View File

@@ -52,7 +52,7 @@ local progressFunc = {
if exports[OXLibExport]:progressBar(options) then if exports[OXLibExport]:progressBar(options) then
return true return true
else else
print("^1progressBar was not successful") return false
end end
end end
end, end,

255
shared/make/ropeControl.lua Normal file
View File

@@ -0,0 +1,255 @@
if not isServer() then
local RopeCache = {
nextId = 1,
byId = {},
byHandle = {},
}
function loadRopeTextures()
RopeLoadTextures()
local tries = 0
while not RopeAreTexturesLoaded() and tries < 200 do
Wait(0)
tries += 1
end
return RopeAreTexturesLoaded()
end
function maybeUnloadTextures()
local anyLeft = false
local all = GetAllRopes()
if all and type(all) == "table" then
for _, _ in ipairs(all) do anyLeft = true break end
end
if not anyLeft then
RopeUnloadTextures()
end
end
function registerRope(ropeHandle, startCoords, endCoords, opts)
if not ropeHandle or ropeHandle == 0 then return nil end
local id = RopeCache.nextId
RopeCache.nextId = id + 1
local rec = {
handle = ropeHandle,
startCoords = startCoords,
endCoords = endCoords,
type = opts.ropeType,
rate = opts.lengthChangeRate,
breakable = opts.breakable,
createdAt = GetGameTimer()
}
RopeCache.byId[id] = rec
RopeCache.byHandle[ropeHandle] = id
debugPrint("^5Debug^7: 2Registered Rope^7'^3"..id.."^7' - '^3"..ropeHandle.."^7'")
return id
end
function resolve(id)
if type(id) ~= "number" then return nil, "rope id must be a number" end
local rec = RopeCache.byId[id]
if not rec then return nil, "rope id not found" end
if not DoesRopeExist(rec.handle) then
-- stale; clean mapping
RopeCache.byHandle[rec.handle] = nil
RopeCache.byId[id] = nil
return nil, "rope no longer exists"
end
return rec
end
--- Create a rope pinned between two coordinates.
--- @param startCoords vector3|table start coord
--- @param endCoords vector3|table end coord
--- @param opts table|nil { ropeType=0..7, breakable=false, collision=true, lockFromFront=false, lengthChangeRate=1.0, timeMultiplier=1.0, slack=0.0, preset=nil }
--- @return integer ropeId
function ropeCreateLine(startCoords, endCoords, opts)
startCoords = type(startCoords) == "number" and GetEntityCoords(startCoords) or startCoords
endCoords = type(endCoords) == "number" and GetEntityCoords(endCoords) or endCoords
opts = opts or {}
local length = #(startCoords - endCoords)
local mid = (startCoords + endCoords) * 0.5
local ropeType = opts.ropeType or 1 -- 0..7 (see ropedata.xml types)
local initLength = length + (opts.slack or 0.0)
local maxLength = initLength -- allow droop equal to init
local minLength = 0.0
local lengthChangeRate = opts.lengthChangeRate or 1.0
local collisionOn = (opts.collision ~= false)
local lockFromFront = (opts.lockFromFront == true)
local timeMultiplier = opts.timeMultiplier or 1.0
local breakable = (opts.breakable == true)
local rope = AddRope(mid.x, mid.y, mid.z, 0.0, 0.0, 0.0, maxLength, ropeType, initLength, minLength, lengthChangeRate, false, collisionOn, lockFromFront, timeMultiplier, breakable, 0)
if not rope or rope == 0 or not DoesRopeExist(rope) then
debugPrint("^1AddRope failed")
return nil
end
-- Optional preset (e.g., "ropeFamily3") if provided.
if opts.preset then
-- Best-effort; if invalid it just won't change.
pcall(function() LoadRopeData(rope, tostring(opts.preset)) end)
end
ActivatePhysics(rope)
-- Pin both ends to the given coords.
local count = GetRopeVertexCount(rope)
if count and count >= 2 then
PinRopeVertex(rope, 0, startCoords.x, startCoords.y, startCoords.z)
PinRopeVertex(rope, count - 1, endCoords.x, endCoords.y, endCoords.z)
end
local id = registerRope(rope, startCoords, endCoords, {
ropeType = ropeType,
lengthChangeRate = lengthChangeRate,
breakable = breakable
})
return id
end
--- Delete and unregister a rope.
--- @param id integer
function ropeDelete(id)
local rec, err = resolve(id)
if not rec then return false, err end
local rope = rec.handle
if DoesRopeExist(rope) then
DeleteRope(rope)
end
RopeCache.byHandle[rope] = nil
RopeCache.byId[id] = nil
debugPrint(("deleted rope id=%s"):format(id))
maybeUnloadTextures()
return true
end
--- Force rope to a specific length (instant snap).
--- @param id integer
--- @param newLength number
function ropeSetLength(id, newLength)
local rec, err = resolve(id)
if not rec then return false, err end
RopeForceLength(rec.handle, newLength)
return true
end
--- Smoothly wind the rope (shorten over time).
--- @param id integer
function ropeStartWinding(id)
local rec, err = resolve(id)
if not rec then return false, err end
StartRopeWinding(rec.handle)
return true
end
--- Stop winding (if winding).
function ropeStopWinding(id)
local rec, err = resolve(id)
if not rec then return false, err end
StopRopeWinding(rec.handle)
return true
end
--- Smoothly unwind the rope from the front (lengthen over time).
function ropeStartUnwinding(id)
local rec, err = resolve(id)
if not rec then return false, err end
StartRopeUnwindingFront(rec.handle)
return true
end
--- Stop unwinding (if unwinding).
function ropeStopUnwinding(id)
local rec, err = resolve(id)
if not rec then return false, err end
StopRopeUnwindingFront(rec.handle)
return true
end
--- Change the wind speed (length change rate).
--- @param id integer
--- @param rate number (units per sec; try 0.5..5.0)
function ropeSetRate(id, rate)
local rec, err = resolve(id)
if not rec then return false, err end
SetRopeLengthChangeRate(rec.handle, rate)
rec.rate = rate
return true
end
--- Move end endpoint to a new coordinate (re-pins the vertex).
--- @param id integer
--- @param pos vector3|table
function ropeMoveEnd(id, pos)
local rec, err = resolve(id)
if not rec then return false, err end
pos = type(pos) == "number" and GetEntityCoords(pos) or pos
local rope = rec.handle
local count = GetRopeVertexCount(rope)
if not count or count < 2 then return false, "invalid vertex count" end
PinRopeVertex(rope, count - 1, pos.x, pos.y, pos.z)
rec.endCoord = pos
return true
end
--- Move start endpoint to a new coordinate (re-pins the vertex).
--- @param id integer
--- @param pos vector3|table
function ropeMoveStart(id, pos)
local rec, err = resolve(id)
if not rec then return false, err end
pos = type(pos) == "number" and GetEntityCoords(pos) or pos
local rope = rec.handle
local count = GetRopeVertexCount(rope)
if not count or count < 2 then return false, "invalid vertex count" end
PinRopeVertex(rope, 0, pos.x, pos.y, pos.z)
rec.startCoord = pos
return true
end
--- Re-pin both endpoints in one call.
function ropeSetEnds(ropeId, startCoord, endCoord)
startCoord = type(startCoord) == "number" and GetEntityCoords(startCoord) or startCoord
endCoord = type(endCoord) == "number" and GetEntityCoords(endCoord) or endCoord
local rec, err = resolve(ropeId)
if not rec then return false, err end
local rope = rec.handle
local count = GetRopeVertexCount(rope)
if not count or count < 2 then
return false, "invalid vertex count"
end
PinRopeVertex(rope, 0, startCoord.x, startCoord.y, startCoord.z)
PinRopeVertex(rope, count - 1, endCoord.x, endCoord.y, endCoord.z)
rec.startCoord = startCoord
rec.endCoord = endCoord
return true
end
function ropeExists(id)
local rec = RopeCache.byId[id]
return rec and DoesRopeExist(rec.handle) or false
end
onResourceStart(function()
loadRopeTextures()
end)
onResourceStop(function()
for id, rec in pairs(RopeCache.byId) do
if rec.handle and DoesRopeExist(rec.handle) then
DeleteRope(rec.handle)
end
RopeCache.byHandle[rec.handle] = nil
RopeCache.byId[id] = nil
end
maybeUnloadTextures()
end)
end

View File

@@ -16,14 +16,26 @@ local hungerThirstFunc = {
setThirst = setThirst =
function(src, thirst) function(src, thirst)
local Player = Core.Functions.GetPlayer(src) local Player = Core.Functions.GetPlayer(src)
Player.Functions.SetMetaData('thirst', thirst) local newThirst = Player.PlayerData.metadata.thirst + thirst
TriggerClientEvent("hud:client:UpdateNeeds", src, Player.PlayerData.metadata.hunger, thirst) newThirst = (newThirst >= 100.0 and 100.0) or (newThirst <= 0 and 0) or newThirst
Player.Functions.SetMetaData('thirst', newThirst)
TriggerClientEvent("hud:client:UpdateNeeds", src, Player.PlayerData.metadata.hunger, newThirst)
end, end,
setHunger = setHunger =
function(src, hunger) function(src, hunger)
local Player = Core.Functions.GetPlayer(src) local Player = Core.Functions.GetPlayer(src)
Player.Functions.SetMetaData('hunger', hunger) local newHunger = Player.PlayerData.metadata.hunger + hunger
TriggerClientEvent("hud:client:UpdateNeeds", src, hunger, Player.PlayerData.metadata.thirst) newHunger = (newHunger >= 100.0 and 100.0) or (newHunger <= 0 and 0) or newHunger
Player.Functions.SetMetaData('hunger', newHunger)
TriggerClientEvent("hud:client:UpdateNeeds", src, newHunger, Player.PlayerData.metadata.thirst)
end,
setStress =
function(src, stress)
local Player = Core.Functions.GetPlayer(src)
local newStress = Player.PlayerData.metadata.stress + stress
newStress = (newStress >= 100.0 and 100.0)or (newStress <= 0 and 0) or newStress
Player.Functions.SetMetaData('stress', newStress)
TriggerClientEvent('hud:client:UpdateStress', src, newStress)
end, end,
}, },
@@ -31,14 +43,26 @@ local hungerThirstFunc = {
setThirst = setThirst =
function(src, thirst) function(src, thirst)
local Player = Core.Functions.GetPlayer(src) local Player = Core.Functions.GetPlayer(src)
Player.Functions.SetMetaData('thirst', thirst) local newThirst = Player.PlayerData.metadata.thirst + thirst
TriggerClientEvent("hud:client:UpdateNeeds", src, Player.PlayerData.metadata.hunger, thirst) newThirst = (newThirst >= 100.0 and 100.0) or (newThirst <= 0 and 0) or newThirst
Player.Functions.SetMetaData('thirst', newThirst)
TriggerClientEvent("hud:client:UpdateNeeds", src, Player.PlayerData.metadata.hunger, newThirst)
end, end,
setHunger = setHunger =
function(src, hunger) function(src, hunger)
local Player = Core.Functions.GetPlayer(src) local Player = Core.Functions.GetPlayer(src)
Player.Functions.SetMetaData('hunger', hunger) local newHunger = Player.PlayerData.metadata.hunger + hunger
TriggerClientEvent("hud:client:UpdateNeeds", src, hunger, Player.PlayerData.metadata.thirst) newHunger = (newHunger >= 100.0 and 100.0) or (newHunger <= 0 and 0) or newHunger
Player.Functions.SetMetaData('hunger', newHunger)
TriggerClientEvent("hud:client:UpdateNeeds", src, newHunger, Player.PlayerData.metadata.thirst)
end,
setStress =
function(src, stress)
local Player = Core.Functions.GetPlayer(src)
local newStress = Player.PlayerData.metadata.stress + stress
newStress = (newStress >= 100.0 and 100.0)or (newStress <= 0 and 0) or newStress
Player.Functions.SetMetaData('stress', newStress)
TriggerClientEvent('hud:client:UpdateStress', src, newStress)
end, end,
}, },
@@ -46,25 +70,41 @@ local hungerThirstFunc = {
setThirst = setThirst =
function(src, thirst) function(src, thirst)
local Player = Core.Functions.GetPlayer(src) local Player = Core.Functions.GetPlayer(src)
Player.Functions.SetMetaData('thirst', thirst) local newThirst = Player.PlayerData.metadata.thirst + thirst
TriggerClientEvent("hud:client:UpdateNeeds", src, Player.PlayerData.metadata.hunger, thirst) newThirst = (newThirst >= 100.0 and 100.0) or (newThirst <= 0 and 0) or newThirst
Player.Functions.SetMetaData('thirst', newThirst)
TriggerClientEvent("hud:client:UpdateNeeds", src, Player.PlayerData.metadata.hunger, newThirst)
end, end,
setHunger = setHunger =
function(src, hunger) function(src, hunger)
local Player = Core.Functions.GetPlayer(src) local Player = Core.Functions.GetPlayer(src)
Player.Functions.SetMetaData('hunger', hunger) local newHunger = Player.PlayerData.metadata.hunger + hunger
TriggerClientEvent("hud:client:UpdateNeeds", src, hunger, Player.PlayerData.metadata.thirst) newHunger = (newHunger >= 100.0 and 100.0) or (newHunger <= 0 and 0) or newHunger
Player.Functions.SetMetaData('hunger', newHunger)
TriggerClientEvent("hud:client:UpdateNeeds", src, newHunger, Player.PlayerData.metadata.thirst)
end,
setStress =
function(src, stress)
local Player = Core.Functions.GetPlayer(src)
local newStress = Player.PlayerData.metadata.stress + stress
newStress = (newStress >= 100.0 and 100.0) or (newStress <= 0 and 0) or newStress
Player.Functions.SetMetaData('stress', newStress)
TriggerClientEvent('hud:client:UpdateStress', src, newStress)
end, end,
}, },
{ framework = ESXExport, { framework = ESXExport,
setThirst = setThirst =
function(src, thirst) function(src, thirst)
TriggerClientEvent('esx_status:add', src, 'thirst', thirst) TriggerClientEvent('esx_status:add', src, 'thirst', tonumber(thirst) * 10000)
end, end,
setHunger = setHunger =
function(src, hunger) function(src, hunger)
TriggerClientEvent('esx_status:add', src, 'hunger', hunger) TriggerClientEvent('esx_status:add', src, 'hunger', tonumber(hunger) * 10000)
end,
setStress =
function(src, stress)
TriggerClientEvent("esx_status:add", src, "stress", tonumber(stress) * 10000)
end, end,
}, },
} }
@@ -114,6 +154,26 @@ function setHunger(src, hunger)
end end
end end
--- Sets the player's stress level.
---
--- @param src number The player's server ID.
--- @param stress number The new stress level.
---
--- @usage
--- ```lua
--- setStress(playerId, 60)
--- ```
function setStress(src, stress)
for i = 1, #hungerThirstFunc do
local framework = hungerThirstFunc[i]
if isStarted(framework.framework) then
debugPrint("^4Debug^7: ^2Adding ^3"..framework.framework.." ^2stress^7: ^3"..stress.." ^2to player^7: ^3"..src.."^7")
framework.setStress(src, stress)
return
end
end
end
--- Server event handler for urinal usage. --- Server event handler for urinal usage.
--- Decreases player's thirst by a random amount. --- Decreases player's thirst by a random amount.
RegisterNetEvent(getScript()..":server:Urinal", function() RegisterNetEvent(getScript()..":server:Urinal", function()
@@ -372,19 +432,21 @@ local hasGroupFunc = {
local hasJobFlag, duty = false, true local hasJobFlag, duty = false, true
local playerInfo = GetPlayer(src) local playerInfo = GetPlayer(src)
local jobinfo = playerInfo.job or playerInfo.PlayerData.job local jobinfo = playerInfo.job or playerInfo.PlayerData.job
if jobinfo.name == group then if jobinfo and jobinfo.name == group then
hasJobFlag = true hasJobFlag = true
duty = jobinfo.onduty duty = jobinfo.onduty
if grade and not (grade <= jobinfo.grade.level) then if grade and not (grade <= jobinfo.grade.level) then
hasJobFlag = false hasJobFlag = false
end end
return hasJobFlag, duty
end end
local ganginfo = playerInfo.gang or playerInfo.PlayerData.gang local ganginfo = playerInfo.gang or playerInfo.PlayerData.gang
if ganginfo.name == group then if ganginfo and ganginfo.name == group then
hasJobFlag = true hasJobFlag = true
if grade and not (grade <= ganginfo.grade.level) then if grade and not (grade <= ganginfo.grade.level) then
hasJobFlag = false hasJobFlag = false
end end
return hasJobFlag, duty
end end
return hasJobFlag, duty return hasJobFlag, duty
end, end,
@@ -396,7 +458,7 @@ local hasGroupFunc = {
local hasJobFlag, duty = false, true local hasJobFlag, duty = false, true
local playerInfo = GetPlayer(src) local playerInfo = GetPlayer(src)
local jobinfo = playerInfo.job or playerInfo.PlayerData.job local jobinfo = playerInfo.job or playerInfo.PlayerData.job
if jobinfo.name == group then if jobinfo and jobinfo.name == group then
hasJobFlag = true hasJobFlag = true
duty = jobinfo.onduty duty = jobinfo.onduty
if grade and not (grade <= jobinfo.grade.level) then if grade and not (grade <= jobinfo.grade.level) then
@@ -404,7 +466,7 @@ local hasGroupFunc = {
end end
end end
local ganginfo = playerInfo.gang or playerInfo.PlayerData.gang local ganginfo = playerInfo.gang or playerInfo.PlayerData.gang
if ganginfo.name == group then if ganginfo and ganginfo.name == group then
hasJobFlag = true hasJobFlag = true
if grade and not (grade <= ganginfo.grade.level) then if grade and not (grade <= ganginfo.grade.level) then
hasJobFlag = false hasJobFlag = false
@@ -434,26 +496,6 @@ local hasGroupFunc = {
end, end,
}, },
{ framework = OXCoreExport,
hasGroup =
function(group, grade, src)
local hasJobFlag, duty = false, true
if src then
local chunk = assert(load(LoadResourceFile('ox_core', ('imports/%s.lua'):format('server')), ('@@ox_core/%s'):format(file)))
chunk()
local player = Ox.GetPlayer(src)
for k, v in pairs(player.getGroups()) do
if k == group then hasJobFlag = true end
end
end
local info = OxPlayer.getGroups()
for k, v in pairs(info) do
if k == group then hasJobFlag = true break end
end
return hasJobFlag, duty
end,
},
{ framework = ESXExport, { framework = ESXExport,
hasGroup = hasGroup =
function(group, grade, src) function(group, grade, src)
@@ -479,7 +521,7 @@ local hasGroupFunc = {
local hasJobFlag, duty = false, true local hasJobFlag, duty = false, true
local playerInfo = GetPlayer(src) local playerInfo = GetPlayer(src)
local jobinfo = playerInfo.job or playerInfo.PlayerData.job local jobinfo = playerInfo.job or playerInfo.PlayerData.job
if jobinfo.name == group then if jobinfo and jobinfo.name == group then
hasJobFlag = true hasJobFlag = true
duty = jobinfo.onduty duty = jobinfo.onduty
if grade and not (grade <= jobinfo.grade.level) then if grade and not (grade <= jobinfo.grade.level) then
@@ -487,7 +529,7 @@ local hasGroupFunc = {
end end
end end
local ganginfo = playerInfo.gang or playerInfo.PlayerData.gang local ganginfo = playerInfo.gang or playerInfo.PlayerData.gang
if ganginfo.name == group then if ganginfo and ganginfo.name == group then
hasJobFlag = true hasJobFlag = true
if grade and not (grade <= ganginfo.grade.level) then if grade and not (grade <= ganginfo.grade.level) then
hasJobFlag = false hasJobFlag = false
@@ -920,17 +962,10 @@ local wardrobeFunc = {
end) end)
end, end,
}, },
{ name = "illenium-appearance", {
name = "illenium-appearance",
openWardrobe = function() openWardrobe = function()
exports['illenium-appearance']:startPlayerCustomization(function(appearance) TriggerEvent("illenium-appearance:client:openOutfitMenu")
if appearance then
TriggerServerEvent("illenium-appearance:server:saveAppearance", appearance)
end
end, {
components = true, componentConfig = { masks = true, upperBody = true, lowerBody = true, bags = true, shoes = true, scarfAndChains = true, bodyArmor = true, shirts = true, decals = true, jackets = true },
props = true, propConfig = { hats = true, glasses = true, ear = true, watches = true, bracelets = true },
enableExit = true,
})
end, end,
}, },
} }

View File

@@ -12,52 +12,6 @@
]] ]]
local societyFunc = { local societyFunc = {
{ bankName = "qb-banking",
getAccount =
function(society)
if not exports["qb-banking"]:GetAccount(society) then
if Jobs[society] then
print("^6Bridge^7: ^2Making new bank account in ^7'^3qb-banking^7' ^2for ^7'^3"..society.."^7'")
exports["qb-banking"]:CreateJobAccount(society, 0)
Wait(150)
elseif Gangs[society] then
print("^6Bridge^7: ^2Making new bank account in ^7'^3qb-banking^7' ^2for ^7'^3"..society.."^7'")
exports["qb-banking"]:CreateGangAccount(society, 0)
Wait(150)
end
end
return exports["qb-banking"]:GetAccountBalance(society)
end,
chargeSociety =
function(society, amount)
if not exports["qb-banking"]:GetAccount(society) then
if Jobs[society] then
print("^6Bridge^7: ^2Making new bank account in ^7'^3qb-banking^7' ^2for ^7'^3"..society.."^7'")
exports["qb-banking"]:CreateJobAccount(society, 0) Wait(150) -- make new account if return "null"
elseif Gangs[society] then
print("^6Bridge^7: ^2Making new bank account in ^7'^3qb-banking^7' ^2for ^7'^3"..society.."^7'")
exports["qb-banking"]:CreateGangAccount(society, 0) Wait(150) -- make new account if return "null"
end
end
exports["qb-banking"]:RemoveMoney(society, amount)
end,
fundSociety =
function(society, amount)
if not exports["qb-banking"]:GetAccount(society) then
if Jobs[society] then
print("^6Bridge^7: ^2Making new bank account in ^7'^3qb-banking^7' ^2for ^7'^3"..society.."^7'")
exports["qb-banking"]:CreateJobAccount(society, 0)
Wait(150)
elseif Gangs[society] then
print("^6Bridge^7: ^2Making new bank account in ^7'^3qb-banking^7' ^2for ^7'^3"..society.."^7'")
exports["qb-banking"]:CreateGangAccount(society, 0)
Wait(150)
end
end
exports["qb-banking"]:AddMoney(society, amount)
end,
},
{ bankName = "Renewed-Banking", { bankName = "Renewed-Banking",
getAccount = getAccount =
function(society) function(society)
@@ -129,6 +83,115 @@ local societyFunc = {
end end
end, end,
}, },
{ bankName = "qb-banking",
getAccount =
function(society)
if not exports["qb-banking"]:GetAccount(society) then
if Jobs[society] then
print("^6Bridge^7: ^2Making new bank account in ^7'^3qb-banking^7' ^2for ^7'^3"..society.."^7'")
exports["qb-banking"]:CreateJobAccount(society, 0)
Wait(150)
elseif Gangs[society] then
print("^6Bridge^7: ^2Making new bank account in ^7'^3qb-banking^7' ^2for ^7'^3"..society.."^7'")
exports["qb-banking"]:CreateGangAccount(society, 0)
Wait(150)
end
end
return exports["qb-banking"]:GetAccountBalance(society)
end,
chargeSociety =
function(society, amount)
if not exports["qb-banking"]:GetAccount(society) then
if Jobs[society] then
print("^6Bridge^7: ^2Making new bank account in ^7'^3qb-banking^7' ^2for ^7'^3"..society.."^7'")
exports["qb-banking"]:CreateJobAccount(society, 0) Wait(150) -- make new account if return "null"
elseif Gangs[society] then
print("^6Bridge^7: ^2Making new bank account in ^7'^3qb-banking^7' ^2for ^7'^3"..society.."^7'")
exports["qb-banking"]:CreateGangAccount(society, 0) Wait(150) -- make new account if return "null"
end
end
exports["qb-banking"]:RemoveMoney(society, amount)
end,
fundSociety =
function(society, amount)
if not exports["qb-banking"]:GetAccount(society) then
if Jobs[society] then
print("^6Bridge^7: ^2Making new bank account in ^7'^3qb-banking^7' ^2for ^7'^3"..society.."^7'")
exports["qb-banking"]:CreateJobAccount(society, 0)
Wait(150)
elseif Gangs[society] then
print("^6Bridge^7: ^2Making new bank account in ^7'^3qb-banking^7' ^2for ^7'^3"..society.."^7'")
exports["qb-banking"]:CreateGangAccount(society, 0)
Wait(150)
end
end
exports["qb-banking"]:AddMoney(society, amount)
end,
},
{ bankName = "esx_society",
getAccount =
function(society)
local checkExist = exports.esx_society:GetSociety(society)
if checkExist == nil then
print("^6Bridge^7: ^2Making new bank account in ^7'^3esx_society^7' ^2for ^7'^3"..society.."^7'")
exports.esx_society:registerSociety(
society,
Gangs[society] and Gangs[society].label or Jobs[society] and Jobs[society].label,
society,
society,
society,
{type = "public"}
)
end
local p = promise.new()
TriggerEvent('esx_addonaccount:getSharedAccount', checkExist.account, function(account)
p:resolve(account.money)
end)
local newAmount = Citizen.Await(p)
return newAmount
end,
chargeSociety =
function(society, amount)
local checkExist = exports.esx_society:GetSociety(society)
if checkExist == nil then
print("^6Bridge^7: ^2Making new bank account in ^7'^3esx_society^7' ^2for ^7'^3"..society.."^7'")
exports.esx_society:registerSociety(
society,
Gangs[society] and Gangs[society].label or Jobs[society] and Jobs[society].label,
society,
society,
society,
{type = "public"}
)
end
TriggerEvent('esx_addonaccount:getSharedAccount', checkExist.account, function(account)
if amount > 0 and account.money >= amount then
account.removeMoney(amount)
end
end)
end,
fundSociety =
function(society, amount)
local checkExist = exports.esx_society:GetSociety(society)
if checkExist == nil then
print("^6Bridge^7: ^2Making new bank account in ^7'^3esx_society^7' ^2for ^7'^3"..society.."^7'")
exports.esx_society:registerSociety(
society,
Gangs[society] and Gangs[society].label or Jobs[society] and Jobs[society].label,
society,
society,
society,
{type = "public"}
)
end
TriggerEvent('esx_addonaccount:getSharedAccount', checkExist.account, function(account)
account.addMoney(amount)
end)
end,
},
} }
@@ -200,14 +263,4 @@ function fundSociety(society, amount)
end end
print("^1Error^7: ^3FundSociety^7: ^2No supported banking script found") print("^1Error^7: ^3FundSociety^7: ^2No supported banking script found")
end
-- other
if isStarted("esx_society") then
createCallback(getScript()..":getESXSocietyAccount", function(source, society)
-- Example query adjust table/field names to match your esx_society implementation.
local result = MySQL.scalar.await('SELECT money FROM society_money WHERE society = ?', { society })
return result or 0
end)
end end

View File

@@ -33,7 +33,7 @@ local targetFunc = {
canInteract = opts[i].canInteract or nil, canInteract = opts[i].canInteract or nil,
} }
end end
exports[OXTargetExport]:addLocalEntity(entity, options) return exports[OXTargetExport]:addLocalEntity(entity, options)
end, end,
boxTarget = boxTarget =
@@ -105,7 +105,7 @@ local targetFunc = {
canInteract = opts[i].canInteract or nil, canInteract = opts[i].canInteract or nil,
} }
end end
exports[OXTargetExport]:addModel(models, options) return exports[OXTargetExport]:addModel(models, options)
end, end,
removeTargetEntity = removeTargetEntity =
@@ -128,7 +128,7 @@ local targetFunc = {
entityTarget = entityTarget =
function(entity, opts, dist) function(entity, opts, dist)
local options = { options = opts, distance = dist } local options = { options = opts, distance = dist }
exports[QBTargetExport]:AddTargetEntity(entity, options) return exports[QBTargetExport]:AddTargetEntity(entity, options)
end, end,
boxTarget = boxTarget =
@@ -148,7 +148,7 @@ local targetFunc = {
modelTarget = modelTarget =
function(models, opts, dist) function(models, opts, dist)
local options = { options = opts, distance = dist } local options = { options = opts, distance = dist }
exports[QBTargetExport]:AddTargetModel(models, options) return exports[QBTargetExport]:AddTargetModel(models, options)
end, end,
removeTargetEntity = removeTargetEntity =
@@ -213,11 +213,10 @@ local targetFunc = {
-- Tables for storing created targets for the fallback system and zone management. -- Tables for storing created targets for the fallback system and zone management.
local TextTargets = {} -- For fallback DrawText3D targets.
local targetEntities = {} -- For entity targets. local targetEntities = {} -- For entity targets.
local boxTargets = {} -- For box-shaped zone targets. local boxTargets = {} -- For box-shaped zone targets.
local circleTargets = {} -- For circular zone targets. local circleTargets = {} -- For circular zone targets.
local modelTargets = {}
------------------------------------------------------------- -------------------------------------------------------------
-- Entity Target Creation -- Entity Target Creation
------------------------------------------------------------- -------------------------------------------------------------
@@ -442,7 +441,7 @@ function createModelTarget(models, opts, dist)
if isStarted(script.targetName) then if isStarted(script.targetName) then
debugPrint("^6Bridge^7: ^2Creating new ^3Model ^2target with ^6"..script.targetName.."^7") debugPrint("^6Bridge^7: ^2Creating new ^3Model ^2target with ^6"..script.targetName.."^7")
local target = script.modelTarget(models, opts, dist) local target = script.modelTarget(models, opts, dist)
circleTargets[#circleTargets + 1] = target modelTargets[#modelTargets + 1] = target
return target return target
end end
end end
@@ -553,7 +552,7 @@ local function CleanupTargets()
if isStarted(OXTargetExport) then if isStarted(OXTargetExport) then
exports[OXTargetExport]:removeZone(boxTargets[i], true) exports[OXTargetExport]:removeZone(boxTargets[i], true)
elseif isStarted(QBTargetExport) then elseif isStarted(QBTargetExport) then
exports[QBTargetExport]:RemoveZone(boxTargets[i].name) exports[QBTargetExport]:RemoveZone(boxTargets[i])
end end
end end
-- Remove circle zone targets. -- Remove circle zone targets.
@@ -561,7 +560,7 @@ local function CleanupTargets()
if isStarted(OXTargetExport) then if isStarted(OXTargetExport) then
exports[OXTargetExport]:removeZone(circleTargets[i], true) exports[OXTargetExport]:removeZone(circleTargets[i], true)
elseif isStarted(QBTargetExport) then elseif isStarted(QBTargetExport) then
exports[QBTargetExport]:RemoveZone(circleTargets[i].name) exports[QBTargetExport]:RemoveZone(circleTargets[i])
end end
end end
end end

View File

@@ -1,4 +1,3 @@
--- Registers a command with the active command system. --- Registers a command with the active command system.
--- This function supports multiple command systems (OXLib, qb-core, ESX Legacy). --- This function supports multiple command systems (OXLib, qb-core, ESX Legacy).
--- ---
@@ -47,7 +46,7 @@ function registerCommand(command, options)
optionTable.helpInfo, optionTable.helpInfo,
optionTable.subText, optionTable.subText,
optionTable.argsRequired, optionTable.argsRequired,
optionTable.funt, optionTable.funct,
optionTable.restriction or nil optionTable.restriction or nil
) )
@@ -57,7 +56,7 @@ function registerCommand(command, options)
optionTable.helpInfo, optionTable.helpInfo,
optionTable.subText, optionTable.subText,
optionTable.argsRequired, optionTable.argsRequired,
optionTable.funt, optionTable.funct,
optionTable.restriction or nil optionTable.restriction or nil
) )

View File

@@ -176,6 +176,7 @@ for _, v in pairs({ -- This is a specific load order
'scaleEntity.lua', 'scaleEntity.lua',
'vehicles.lua', 'vehicles.lua',
'effects.lua', 'effects.lua',
'make/ropeControl.lua',
--'warmenu.lua', --'warmenu.lua',
'_authToken.lua', '_authToken.lua',

View File

@@ -1,16 +1,9 @@
2.1.0 2.1.04
- Script Overhaul, replace whole script - Crafting fixes (prop/sound/remove ingredients)
- Very alpha support for VorpCore - "SingleProgress" is now one progressbar
- Improve security - Add ropeControl.lua - to help create and edit custom ropes/wires
- Removal of Quasar Script Support - Support for new crafting recipe style
- Support Tgiann-inv's new item system - create setStress() multiframework function
- Refactor most multi-functions to be more optimized and smarter
- Added multifunction bossmenu and clothing functions
- Added ability to supress update notifcations in fxmanfiest.lua
- Added coordinate checks to registerStash, registerShop and sellShop
- Optimize and Enhance built-in progressbar + target functions
- Improve weird multicharacter issue triggering onPlayerLoaded more than once
- Scripts that use this will need updating too, as things like stashes won't open
https://github.com/jimathy/jim_bridge/releases/latest https://github.com/jimathy/jim_bridge/releases/latest