mirror of
https://github.com/jimathy/jim_bridge.git
synced 2026-08-16 21:46:03 +01:00
I am still alive
This commit is contained in:
@@ -57,6 +57,7 @@ function triggerCallback(callbackName, ...)
|
||||
p:resolve(cbResult)
|
||||
end, ...)
|
||||
result = Citizen.Await(p)
|
||||
Wait(10)
|
||||
elseif isStarted(ESXExport) then
|
||||
local p = promise.new()
|
||||
ESX.TriggerServerCallback(callbackName, function(cbResult)
|
||||
|
||||
@@ -95,7 +95,7 @@ function openMenu(Menu, data)
|
||||
Menu[k].args = Menu[k].params.args or {}
|
||||
end
|
||||
if Menu[k].isMenuHeader then
|
||||
Menu[k].disabled = true
|
||||
Menu[k].readOnly = true
|
||||
end
|
||||
end
|
||||
local menuID = 'Menu'
|
||||
|
||||
@@ -140,7 +140,7 @@ if isStarted(QBXExport) or isStarted(QBExport) then
|
||||
elseif isStarted(OXCoreExport) then
|
||||
Vehicles = {}
|
||||
for k, v in pairs(Ox.GetVehicleData()) do
|
||||
Vehicles[k] = { model = k, price = v.price, name = v.name, brand = v.make }
|
||||
Vehicles[k] = { model = k, hash = GetHashKey(k), price = v.price, name = v.name, brand = v.make }
|
||||
end
|
||||
vehResource = OXCoreExport
|
||||
|
||||
@@ -159,6 +159,7 @@ elseif isStarted(ESXExport) then
|
||||
Vehicles = Vehicles or {}
|
||||
Vehicles[v.model] = {
|
||||
model = v.model,
|
||||
hash = GetHashKey(v.model),
|
||||
price = v.price,
|
||||
name = v.name,
|
||||
brand = GetMakeNameFromVehicleModel(v.model):lower():gsub("^%l", string.upper)
|
||||
|
||||
@@ -12,6 +12,14 @@
|
||||
-------------------------------------------------------------
|
||||
CraftLock = false
|
||||
|
||||
-- helper filter table for crafting menus
|
||||
local excludeKeys = {
|
||||
amount = true, metadata = true, description = true, info = true,
|
||||
job = true, gang = true, oneUse = true, slot = true,
|
||||
blueprintRef = true, craftingLevel = true, craftedItems = true,
|
||||
hasCrafted = true, exp = true, anim = true, time = true,
|
||||
}
|
||||
|
||||
-------------------------------------------------------------
|
||||
-- Crafting Menu
|
||||
-------------------------------------------------------------
|
||||
@@ -73,6 +81,7 @@ function craftingMenu(data)
|
||||
for i = 1, #Recipes do
|
||||
for k in pairs(Recipes[i]) do
|
||||
if k == "hasCrafted" and not data.craftable.craftedItems then
|
||||
-- Retreive list of already crafted items from playermetadata to see if we should class this recipe as "new"
|
||||
craftedItems = GetMetadata(nil, "craftedItems") or {}
|
||||
data.craftable.craftedItems = craftedItems
|
||||
end
|
||||
@@ -88,12 +97,6 @@ function craftingMenu(data)
|
||||
for i = 1, #Recipes do
|
||||
if not Recipes[i]["amount"] then Recipes[i]["amount"] = 1 end
|
||||
for k, _ in pairs(Recipes[i]) do
|
||||
local excludeKeys = {
|
||||
amount = true, metadata = true, description = true, info = true,
|
||||
job = true, gang = true, oneUse = true, slot = true,
|
||||
blueprintRef = true, craftingLevel = true, craftedItems = true,
|
||||
hasCrafted = true, exp = true, anim = true, time = true,
|
||||
}
|
||||
if not excludeKeys[k] then
|
||||
local hasjob = true
|
||||
if Recipes[i].job then
|
||||
@@ -203,48 +206,79 @@ end
|
||||
--- })
|
||||
--- ```
|
||||
function multiCraft(data)
|
||||
local Menu = {}
|
||||
local amounts = Config.Crafting.MultiCraftAmounts
|
||||
local metadata = data.metadata or nil
|
||||
|
||||
-- Header for the multi-craft menu.
|
||||
Menu[#Menu + 1] = {
|
||||
isMenuHeader = true,
|
||||
icon = invImg(metadata and metadata.image or data.item),
|
||||
header = metadata and metadata.label or Items[data.item].label,
|
||||
}
|
||||
|
||||
for k in pairsByKeys(amounts) do
|
||||
local settext = ""
|
||||
local max = 0
|
||||
local stashName = nil
|
||||
for i = 1, 100 do
|
||||
local itemTable = {}
|
||||
for l, b in pairs(data.craft[data.item]) do
|
||||
itemTable[l] = (b * k)
|
||||
settext = settext..(settext ~= "" and br or "")..Items[l].label..(b * k > 1 and " x"..b * k or "")
|
||||
Wait(0)
|
||||
debugPrint("")
|
||||
itemTable[l] = (b * i)
|
||||
end
|
||||
local disable, stashname = checkHasItem(data.stashName, itemTable)
|
||||
Menu[#Menu + 1] = {
|
||||
isMenuHeader = not disable,
|
||||
arrow = disable,
|
||||
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 = stashname,
|
||||
stashTable = data.stashName,
|
||||
onBack = data.onBack,
|
||||
metadata = data.metadata,
|
||||
})
|
||||
end,
|
||||
}
|
||||
|
||||
if data.stashName then
|
||||
debugPrint("")
|
||||
local hasItems, stashname = checkHasItem(data.stashName, itemTable)
|
||||
if hasItems == true then
|
||||
max += 1
|
||||
stashName = stashname
|
||||
else
|
||||
break
|
||||
end
|
||||
else
|
||||
debugPrint("")
|
||||
local has, _ = hasItem(itemTable, nil, nil)
|
||||
if has then
|
||||
max += 1
|
||||
else
|
||||
break
|
||||
end
|
||||
end
|
||||
Wait(10)
|
||||
end
|
||||
|
||||
openMenu(Menu, { header = data.craftable.Header, onBack = function() craftingMenu(data) end })
|
||||
local dialog = createInput(data.craftable.Header, {
|
||||
((Config.System.Menu == "ox") and {
|
||||
type = "slider",
|
||||
label = "How many to craft?",
|
||||
required = true,
|
||||
default = 1,
|
||||
min = 1,
|
||||
max = max
|
||||
}) or nil,
|
||||
((Config.System.Menu == "qb") and {
|
||||
type = "number",
|
||||
label = "How many to craft?"..br.."Max: "..max,
|
||||
name = "amount",
|
||||
isRecuired = true,
|
||||
default = 1,
|
||||
}) or nil,
|
||||
})
|
||||
|
||||
if dialog then
|
||||
if Config.System.Menu == "ox" then
|
||||
|
||||
end
|
||||
if Config.System.Menu == "qb" then
|
||||
if dialog["amount"] > max or dialog["amount"] < 1 or dialog["amount"] == nil or dialog["amount"] == "" then
|
||||
triggerNotify(nil, "Invalid Amount", "error")
|
||||
craftingMenu(data)
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
makeItem({
|
||||
item = data.item,
|
||||
craft = data.craft,
|
||||
craftable = data.craftable,
|
||||
amount = dialog["amount"] or dialog[1],
|
||||
coords = data.coords,
|
||||
stashName = stashName or nil,
|
||||
--stashTable = data.stashName,
|
||||
onBack = data.onBack,
|
||||
metadata = data.metadata,
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
-------------------------------------------------------------
|
||||
@@ -300,12 +334,6 @@ function makeItem(data)
|
||||
|
||||
for i = 1, craftAmount do
|
||||
for k, v in pairs(data.craft) do
|
||||
local excludeKeys = {
|
||||
amount = true, info = true, metadata = true, description = true,
|
||||
job = true, gang = true, oneUse = true, slot = true,
|
||||
blueprintRef = true, craftingLevel = true, craftedItems = true,
|
||||
hasCrafted = true, exp = true, anim = true, time = true,
|
||||
}
|
||||
if not excludeKeys[k] then
|
||||
if type(v) == "table" then
|
||||
for l, b in pairs(v) do
|
||||
@@ -392,6 +420,7 @@ end
|
||||
--- @param craftable table The crafting recipe and details.
|
||||
--- @param stashName string|table The stash name(s) to remove ingredients from.
|
||||
--- @param metadata table (optional) Metadata for the crafted item.
|
||||
--- @usage
|
||||
RegisterNetEvent(getScript()..":Crafting:GetItem", function(ItemMake, craftable, stashName, metadata)
|
||||
local src = source
|
||||
local hasItems, hasTable = hasItem(ItemMake, 1, src)
|
||||
@@ -424,188 +453,6 @@ RegisterNetEvent(getScript()..":Crafting:GetItem", function(ItemMake, craftable,
|
||||
end
|
||||
addItem(ItemMake, craftable.amount or 1, metadata, src)
|
||||
-- Optionally, add experience here:
|
||||
-- for example:
|
||||
-- if isStarted("core_skills") then exports["core_skills"]:AddExperience(src, 2) end
|
||||
end)
|
||||
|
||||
-------------------------------------------------------------
|
||||
-- Selling Menu and Animation
|
||||
-------------------------------------------------------------
|
||||
|
||||
--- Opens a selling menu with available items and prices.
|
||||
---
|
||||
--- @param data table Contains selling menu data:
|
||||
--- - sellTable (`table`) Table with Header and Items (item names and prices).
|
||||
--- - ped (optional) (`number`) Ped entity involved.
|
||||
--- - onBack (optional) (`function`) Callback for returning.
|
||||
--- @usage
|
||||
--- ```lua
|
||||
--- sellMenu({
|
||||
--- sellTable = {
|
||||
--- Header = "Sell Items",
|
||||
--- Items = {
|
||||
--- ["gold_ring"] = 100,
|
||||
--- ["diamond"] = 500,
|
||||
--- },
|
||||
--- },
|
||||
--- ped = pedEntity,
|
||||
--- onBack = function() print("Returning to previous menu") end,
|
||||
--- })
|
||||
--- ```
|
||||
function sellMenu(data)
|
||||
local origData = data
|
||||
local Menu = {}
|
||||
if data.sellTable.Items then
|
||||
local itemList = {}
|
||||
for k, v in pairs(data.sellTable.Items) do itemList[k] = 1 end
|
||||
local _, hasTable = hasItem(itemList)
|
||||
for k, v in pairsByKeys(data.sellTable.Items) do
|
||||
Menu[#Menu + 1] = {
|
||||
isMenuHeader = not hasTable[k].hasItem,
|
||||
icon = invImg(k),
|
||||
header = Items[k].label..(hasTable[k].hasItem and "💰 (x"..hasTable[k].count..")" or ""),
|
||||
txt = Loc[Config.Lan].info["sell_all"]..v.." "..Loc[Config.Lan].info["sell_each"],
|
||||
onSelect = function()
|
||||
sellAnim({ item = k, price = v, ped = data.ped, onBack = function() sellMenu(data) end })
|
||||
end,
|
||||
}
|
||||
end
|
||||
else
|
||||
for k, v in pairsByKeys(data.sellTable) do
|
||||
if type(v) == "table" then
|
||||
Menu[#Menu + 1] = {
|
||||
arrow = true,
|
||||
header = k,
|
||||
txt = "Amount of items: "..countTable(v.Items),
|
||||
onSelect = function()
|
||||
v.onBack = function() sellMenu(origData) end
|
||||
v.sellTable = data.sellTable[k]
|
||||
sellMenu(v)
|
||||
end,
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
openMenu(Menu, {
|
||||
header = data.sellTable.Header or "Amount of items: "..countTable(data.sellTable.Items),
|
||||
headertxt = data.sellTable.Header and "Amount of items: "..countTable(data.sellTable.Items) or "",
|
||||
canClose = true,
|
||||
onBack = data.onBack,
|
||||
})
|
||||
end
|
||||
|
||||
--- Plays the selling animation and processes the sale transaction.
|
||||
---
|
||||
--- Checks if the player has the item, plays animations, triggers the server event for selling,
|
||||
--- and then calls the onBack callback if provided.
|
||||
---
|
||||
--- @param data table Contains:
|
||||
--- `- item: The item to sell.
|
||||
--- `- price: Price per item.
|
||||
--- `- ped (optional): Ped entity involved.
|
||||
--- `- onBack (optional): Callback to call on completion.
|
||||
---@usage
|
||||
--- ```lua
|
||||
--- sellAnim({
|
||||
--- item = "gold_ring",
|
||||
--- price = 100,
|
||||
--- ped = pedEntity,
|
||||
--- onBack = function() sellMenu(data) end,
|
||||
--- })
|
||||
--- ```
|
||||
function sellAnim(data)
|
||||
if not hasItem(data.item, 1) then
|
||||
triggerNotify(nil, Loc[Config.Lan].error["dont_have"].." "..Items[data.item].label, "error")
|
||||
return
|
||||
end
|
||||
|
||||
-- Remove any attached clipboard objects.
|
||||
for _, obj in pairs(GetGamePool('CObject')) do
|
||||
for _, model in pairs({ `p_cs_clipboard` }) do
|
||||
if GetEntityModel(obj) == model and IsEntityAttachedToEntity(data.ped, obj) then
|
||||
DeleteObject(obj)
|
||||
DetachEntity(obj, 0, 0)
|
||||
SetEntityAsMissionEntity(obj, true, true)
|
||||
Wait(100)
|
||||
DeleteEntity(obj)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
TriggerServerEvent(getScript().."Sellitems", data)
|
||||
lookEnt(data.ped)
|
||||
local dict = "mp_common"
|
||||
playAnim(dict, "givetake2_a", 0.3, 2)
|
||||
playAnim(dict, "givetake2_b", 0.3, 2, data.ped)
|
||||
Wait(2000)
|
||||
StopAnimTask(PlayerPedId(), dict, "givetake2_a", 0.5)
|
||||
StopAnimTask(data.ped, dict, "givetake2_b", 0.5)
|
||||
if data.onBack then data.onBack() end
|
||||
end
|
||||
|
||||
--- Server event handler for processing item sales.
|
||||
--- Removes sold items from inventory and funds the player based on the sale.
|
||||
RegisterNetEvent(getScript().."Sellitems", function(data)
|
||||
local src = source
|
||||
local hasItems, hasTable = hasItem(data.item, 1, src)
|
||||
if hasItems then
|
||||
removeItem(data.item, hasTable[data.item].count, src)
|
||||
TriggerEvent(getScript()..":server:FundPlayer", (hasTable[data.item].count * data.price), "cash", src)
|
||||
else
|
||||
triggerNotify(nil, Loc[Config.Lan].error["dont_have"].." "..Items[data.item].label, "error", src)
|
||||
end
|
||||
end)
|
||||
|
||||
-------------------------------------------------------------
|
||||
-- Shop Interface
|
||||
-------------------------------------------------------------
|
||||
|
||||
--- Opens a shop interface for the player.
|
||||
---
|
||||
--- Checks job/gang restrictions, then uses the active inventory system to open the shop.
|
||||
--- @param data table Contains:
|
||||
--- - shop (`string`) The shop identifier.
|
||||
--- - items (`table`) The items available in the shop.
|
||||
--- - coords (`vector3`) where the shop is located.
|
||||
--- - job/gang (optional) (`string`) Job or gang requirements.
|
||||
---@usage
|
||||
--- ```lua
|
||||
--- openShop({
|
||||
--- shop = "weapon_shop",
|
||||
--- items = weaponShopItems,
|
||||
--- coords = vector3(100.0, 200.0, 300.0),
|
||||
--- job = "police",
|
||||
--- })
|
||||
--- ```
|
||||
function openShop(data)
|
||||
if (data.job or data.gang) and not jobCheck(data.job or data.gang) then return end
|
||||
|
||||
if isStarted(OXInv) then
|
||||
exports[OXInv]:openInventory('shop', { type = data.shop })
|
||||
|
||||
elseif isStarted(QBInv) then
|
||||
if QBInvNew then
|
||||
TriggerServerEvent(getScript()..':server:OpenShopNewQB', data.shop)
|
||||
else
|
||||
TriggerServerEvent(Config.General.JimShops and "jim-shops:ShopOpen" or "inventory:server:OpenInventory", "shop", data.items.label, data.items)
|
||||
end
|
||||
|
||||
--elseif isStarted(OrigenInv) then -- Needs testing, not sure if i did this right
|
||||
-- exports[OrigenInv]:openInventory('shop', data.shop, data.items)
|
||||
|
||||
else
|
||||
TriggerServerEvent(Config.General.JimShops and "jim-shops:ShopOpen" or "inventory:server:OpenInventory", "shop", data.items.label, data.items)
|
||||
end
|
||||
lookEnt(data.coords)
|
||||
end
|
||||
|
||||
--- Server event handler for opening a shop using the new QB inventory system.
|
||||
RegisterNetEvent(getScript()..':server:OpenShopNewQB', function(data)
|
||||
exports[QBInv]:OpenShop(source, data)
|
||||
end)
|
||||
|
||||
-------------------------------------------------------------
|
||||
-- Server Callback Registration
|
||||
-------------------------------------------------------------
|
||||
if isServer() then
|
||||
createCallback(getScript()..':server:canCarry', function(source, itemTable) local result = canCarry(itemTable, source) return result end)
|
||||
end
|
||||
end)
|
||||
@@ -515,6 +515,37 @@ function ensureNetToEnt(entNetID)
|
||||
return entity
|
||||
end
|
||||
|
||||
function sendLog(text)
|
||||
local Player = getPlayer()
|
||||
local coords = GetEntityCoords(PlayerPedId())
|
||||
local _, _, _, hour, min, sec = GetLocalTime()
|
||||
local data = {
|
||||
script = debug.getinfo(2, "nSl"),
|
||||
coords = coords,
|
||||
localTime = { hour = hour, min = min, sec = sec },
|
||||
firstname = Player.firstname,
|
||||
lastname = Player.lastname,
|
||||
source = Player.source,
|
||||
id = Player.citizenId,
|
||||
text = text,
|
||||
}
|
||||
|
||||
debugPrint("^5Log Message^7: "..getScript().." - "..Player.firstname.." "..Player.lastname.."("..Player.source..") ["..Player.citizenId.."]", text)
|
||||
TriggerServerEvent(getScript()..":server:sendlog", data)
|
||||
end
|
||||
|
||||
function sendServerLog(data)
|
||||
local hour, min, sec = os.date('%H'), os.date('%M'), os.date('%S')
|
||||
data.serverTime = { house = hour, min = min, sec = sec }
|
||||
--jsonPrint(data)
|
||||
debugPrint("^5Log Message^7: "..getScript().." - "..data.firstname.." "..data.lastname.."("..data.source..") ["..data.id.."]", data.text)
|
||||
|
||||
-- Add your logger here
|
||||
|
||||
end
|
||||
|
||||
RegisterNetEvent(getScript()..":server:sendlog", sendServerLog)
|
||||
|
||||
-------------------------------------------------------------
|
||||
-- Material and Prop Functions
|
||||
-------------------------------------------------------------
|
||||
|
||||
@@ -97,13 +97,34 @@ function createInput(title, opts)
|
||||
default = opts[i].default,
|
||||
}
|
||||
end
|
||||
if opts[i].type == "slider" then
|
||||
options[currentNum] = {
|
||||
type = opts[i].type,
|
||||
label = opts[i].label,
|
||||
isRequired = opts[i].required,
|
||||
min = opts[i].min,
|
||||
max = opts[i].max,
|
||||
default = opts[i].default,
|
||||
}
|
||||
end
|
||||
::skip::
|
||||
end
|
||||
dialog = exports[OXLibExport]:inputDialog(title, options)
|
||||
return dialog
|
||||
elseif Config.System.Menu == "qb" then
|
||||
dialog = exports['qb-input']:ShowInput({ header = title, submitText = "Accept", inputs = opts })
|
||||
for k, v in pairs(opts) do
|
||||
currentNum += 1
|
||||
if opts[k] == nil then
|
||||
currentNum -= 1
|
||||
else
|
||||
options[currentNum] = opts[k]
|
||||
end
|
||||
end
|
||||
dialog = exports['qb-input']:ShowInput(
|
||||
{ header = title, submitText = "Accept", inputs = options }
|
||||
)
|
||||
return dialog
|
||||
|
||||
elseif Config.System.Menu == "gta" then
|
||||
WarMenu.CreateMenu(tostring(opts),
|
||||
title,
|
||||
|
||||
@@ -59,7 +59,11 @@ function hasItem(items, amount, src)
|
||||
debugPrint(foundMessage)
|
||||
hasTable[item] = { hasItem = count >= amt, count = count }
|
||||
end
|
||||
for k, v in pairs(hasTable) do if not v.hasItem then return false, hasTable end end
|
||||
for k, v in pairs(hasTable) do
|
||||
if not v.hasItem then
|
||||
return false, hasTable
|
||||
end
|
||||
end
|
||||
return true, hasTable
|
||||
end
|
||||
end
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
• Granting random rewards from a reward pool.
|
||||
• Checking if a player can carry specific items based on weight.
|
||||
]]
|
||||
validTokens = {}
|
||||
|
||||
-------------------------------------------------------------
|
||||
-- Registering Usable Items
|
||||
@@ -74,7 +75,7 @@ function invImg(item)
|
||||
elseif isStarted(QBInv) then
|
||||
imgLink = "nui://"..QBInv.."/html/images/"..(Items[item].image or "")
|
||||
else
|
||||
print("^4ERROR^7: ^2No Inventory detected for invImg - Check exports.lua")
|
||||
print("^4ERROR^7: ^2No Inventory detected for invImg - Check starter.lua")
|
||||
end
|
||||
end
|
||||
return imgLink
|
||||
@@ -103,7 +104,8 @@ function addItem(item, amount, info, src)
|
||||
if src then
|
||||
TriggerEvent(getScript()..":server:toggleItem", true, item, amount, src, info)
|
||||
else
|
||||
TriggerServerEvent(getScript()..":server:toggleItem", true, item, amount, nil, info)
|
||||
TriggerServerEvent(getScript()..":server:toggleItem", true, item, amount, currentToken, info)
|
||||
currentToken = nil -- clear client cached token
|
||||
end
|
||||
end
|
||||
|
||||
@@ -159,7 +161,25 @@ RegisterNetEvent(getScript()..":server:toggleItem", function(give, item, amount,
|
||||
return
|
||||
end
|
||||
|
||||
local src = newsrc or source
|
||||
local src = source or newsrc
|
||||
if (give == true or give == 1) then
|
||||
if newsrc == nil then -- must be coming from client this would be blank
|
||||
debugPrint("^1Auth^7: ^1No token recieved^7")
|
||||
dupeWarn(src, item, "Auth: Player "..src.." attempted to spawn "..item.." without an auth token")
|
||||
else
|
||||
if type(newsrc) ~= "number" then -- checks if the newsrc is a source or token, if number its coming form the server itself
|
||||
debugPrint("^1Auth^7: ^2Auth token received^7, ^2checking against server cache^7..")
|
||||
if newsrc ~= validTokens[src] then
|
||||
debugPrint("^1Auth^7: ^1Tokens don't match! ^7", newsrc, validTokens[src])
|
||||
dupeWarn(src, item, "Auth: "..src.." attempted to spawn "..item.." with an incorrect auth token")
|
||||
else
|
||||
debugPrint("^1Auth^7: ^2Client and Server Auth tokens match^7!", newsrc, validTokens[src])
|
||||
validTokens[src] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local action = (tostring(give) == "true" and "addItem" or "removeItem")
|
||||
local remamount = amount or 1
|
||||
if item == nil then return end
|
||||
@@ -599,4 +619,62 @@ function canCarry(itemTable, src)
|
||||
end
|
||||
end
|
||||
return resultTable
|
||||
end
|
||||
end
|
||||
|
||||
-------------------------------------------------------------
|
||||
-- Server Callback Registration
|
||||
-------------------------------------------------------------
|
||||
currentToken = nil
|
||||
if isServer() then
|
||||
createCallback(getScript()..":server:canCarry", function(source, itemTable)
|
||||
local result = canCarry(itemTable, source)
|
||||
return result
|
||||
end)
|
||||
|
||||
local AuthEvent = getScript()..":"..keyGen()..keyGen()..keyGen()..keyGen()..":"..keyGen()..keyGen()..keyGen()..keyGen()
|
||||
validTokens = validTokens or {}
|
||||
|
||||
createCallback(AuthEvent, function(source)
|
||||
local src = source
|
||||
local token = keyGen()..keyGen()..keyGen()..keyGen() -- Use a secure random generator here
|
||||
debugPrint("^1Auth^7:^2 Player Source^7: "..src.." ^2requested new token^7:", token)
|
||||
validTokens[src] = token
|
||||
timeOutAuth(validTokens[src], src) -- Give script 10 seconds, then clear token
|
||||
return token
|
||||
end)
|
||||
|
||||
function timeOutAuth(token, src)
|
||||
local token = token
|
||||
SetTimeout(10000, function()
|
||||
if token == validTokens[src] then
|
||||
print("^1--------------------------------------------^7")
|
||||
print("^7Clearing token for player ^1"..src.."^7", token)
|
||||
print("^7This shouldn't happen unless a token has been called by a player or script and it hasn't been used")
|
||||
print("^1--------------------------------------------^7")
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
RegisterNetEvent(getScript()..":clearAuthToken", function()
|
||||
local src = source
|
||||
debugPrint("^1Auth^7: ^2Manually removing token for Player Source^7:", src, validTokens[src])
|
||||
validTokens[src] = nil
|
||||
end)
|
||||
|
||||
receivedEvent = {}
|
||||
createCallback(getScript()..":callback:GetAuthEvent", function(source)
|
||||
local src = source
|
||||
debugPrint("^1Auth^7: ^2Player Source^7: "..src.." ^2requested ^3AuthEvent^7", AuthEvent)
|
||||
if not receivedEvent[src] then receivedEvent[src] = true
|
||||
return AuthEvent
|
||||
else
|
||||
print("^1Auth^7: ^1Player ^7"..src.." ^1tried to request auth token more than once^7")
|
||||
return ""
|
||||
end
|
||||
end)
|
||||
else
|
||||
onResourceStart(function()
|
||||
debugPrint("^1Auth^7: ^2Requesting ^3Auth Event^7")
|
||||
AuthEvent = triggerCallback(getScript()..":callback:GetAuthEvent")
|
||||
end, true)
|
||||
end
|
||||
|
||||
@@ -22,15 +22,21 @@ function createTempCam(ent, coords)
|
||||
triggerNotify(nil, "ModCam Created", "success")
|
||||
end
|
||||
local camCoords = nil
|
||||
local pointCoords = nil
|
||||
if type(ent) ~= "vector3" then
|
||||
camCoords = GetOffsetFromEntityInWorldCoords(ent, 1.0, -0.3, 0.8)
|
||||
else
|
||||
camCoords = ent
|
||||
end
|
||||
-- Create the camera with specified parameters
|
||||
|
||||
cam = CreateCamWithParams("DEFAULT_SCRIPTED_CAMERA", camCoords.x, camCoords.y, camCoords.z + 0.5, 1.0, 0.0, 0.0, 60.00, false, 0)
|
||||
-- Point the camera at the target coordinates
|
||||
PointCamAtCoord(cam, coords)
|
||||
|
||||
if type(coords) == "number" then
|
||||
SetCamCoord(cam, GetCamCoord(cam) + vec3(0, 0, 1.0))
|
||||
PointCamAtEntity(cam, coords)
|
||||
else
|
||||
PointCamAtCoord(cam, coords)
|
||||
end
|
||||
end
|
||||
return cam
|
||||
end
|
||||
|
||||
@@ -137,11 +137,11 @@ end
|
||||
--- ```
|
||||
function loadScriptBank(bank)
|
||||
local timeout = 2000
|
||||
debugPrint("^6Debug^7: ^2Loading ^3Script ^2AudioBank^7...")
|
||||
while not RequestScriptAudioBank(bank, 0) do Wait(10) timeout -= 10 if timeout <= 0 then break end end
|
||||
debugPrint("^6Bridge^7: ^2Loading ^3Script ^2AudioBank^7...")
|
||||
while not RequestScriptAudioBank(bank, false) do Wait(10) timeout -= 10 if timeout <= 0 then break end end
|
||||
|
||||
local success = RequestScriptAudioBank(bank, 0)
|
||||
debugPrint("^6Debug^7: "..(success and "^3Successfully ^2loaded^7: '^4" or "^1Failed to ^2load^7: '^4")..bank.."^7'")
|
||||
local success = RequestScriptAudioBank(bank, false)
|
||||
debugPrint("^6Bridge^7: "..(success and "^3Successfully ^2loaded^7: '^4" or "^1Failed to ^2load^7: '^4")..bank.."^7'")
|
||||
return success
|
||||
end
|
||||
|
||||
@@ -159,14 +159,14 @@ end
|
||||
--- ```
|
||||
function loadAmbientBank(bank)
|
||||
local timeout = 2000
|
||||
debugPrint("^6Debug^7: ^2Loading ^3Ambient ^2AudioBank^7...")
|
||||
debugPrint("^6Bridge^7: ^2Loading ^3Ambient ^2AudioBank^7...")
|
||||
while not RequestAmbientAudioBank(bank, 0) do
|
||||
Wait(10)
|
||||
timeout -= 10
|
||||
if timeout <= 0 then break end
|
||||
end
|
||||
local success = RequestAmbientAudioBank(bank, 0)
|
||||
debugPrint("^6Debug^7: "..(success and "^3Successfully ^2loaded^7: '^4" or "^1Failed to ^2load^7: '^4")..bank.."^7'")
|
||||
debugPrint("^6Bridge^7: "..(success and "^3Successfully ^2loaded^7: '^4" or "^1Failed to ^2load^7: '^4")..bank.."^7'")
|
||||
return success
|
||||
end
|
||||
|
||||
@@ -224,16 +224,18 @@ end
|
||||
--- ```lua
|
||||
--- playGameSound('DLC_HEIST_HACKING_SNAKE_SOUNDS', 'Beep', vector3(0, 0, 0), false, 15.0)
|
||||
--- ```
|
||||
function playGameSound(bank, sound, coords, synced, range)
|
||||
debugPrint("^6Debug^7: ^2Attempting to play: ^3"..sound.." ^7(^4"..bank.."^7')")
|
||||
function playGameSound(audioBank, soundSet, soundRef, coords, synced, range)
|
||||
debugPrint("^6Bridge^7: ^2Attempting to play: ^3"..soundRef.." ^7('^4"..audioBank.."^7')")
|
||||
loadScriptBank(audioBank)
|
||||
local range = range or 10.0
|
||||
local soundId = GetSoundId()
|
||||
while not soundId do Wait(10) end
|
||||
if type(coords) == "vector3" or type(coords) == "vector4" then
|
||||
debugPrint("^6Debug^7: ^2Playing sound from Coord^7: "..formatCoord(coords.xyz))
|
||||
PlaySoundFromCoord(soundId, sound, coords.x, coords.y, coords.z, bank, synced, range, 0)
|
||||
debugPrint("^6Bridge^7: ^2Playing sound from Coord^7: "..formatCoord(coords.xyz))
|
||||
PlaySoundFromCoord(soundId, soundRef, coords.x, coords.y, coords.z, soundSet, synced, range, 0)
|
||||
else
|
||||
debugPrint("^6Debug^7: ^2Playing sound from Entity^7: ^4"..coords.."^7")
|
||||
PlaySoundFromEntity(soundId, sound, coords, bank, synced, 0)
|
||||
debugPrint("^6Bridge^7: ^2Playing sound from Entity^7: ^4"..coords.."^7")
|
||||
PlaySoundFromEntity(soundId, soundRef, coords, soundSet, synced, 1.0)
|
||||
end
|
||||
ReleaseScriptAudioBank(audioBank)
|
||||
end
|
||||
@@ -31,6 +31,60 @@ function makeVeh(model, coords)
|
||||
return veh
|
||||
end
|
||||
|
||||
local distanceVehicles = {}
|
||||
--- Creates a vehicle that spawns when the player enters a designated polyzone area.
|
||||
---
|
||||
--- This function sets up a circular polyzone; when the player enters the zone, the vehicle is spawned,
|
||||
--- and when the player exits, the vehicle is deleted.
|
||||
---
|
||||
---@param data table A table containing vehicle data.
|
||||
--- - **vehicle** `string`: The model name or hash of the vehicle to spawn.
|
||||
--- - **coords** `vector4`: The coordinates where the vehicle will be placed. Should include x, y, z, and w (heading).
|
||||
---@param freeze boolean (optional) Whether to freeze the vehicle in place. Defaults to `false`.
|
||||
---@param synced boolean (optional) Whether the vehicle should be synced across clients. Defaults to `false`.
|
||||
function makeDistVehicle(data, radius, onEnter, onExit)
|
||||
local vehicle = nil
|
||||
local zoneId = keyGen() .. keyGen()
|
||||
local zone = createCirclePoly({
|
||||
name = zoneId,
|
||||
coords = vec3(data.coords.x, data.coords.y, data.coords.z),
|
||||
radius = radius,
|
||||
onEnter = function()
|
||||
vehicle = makeVeh(data.model, data.coords)
|
||||
if onEnter then
|
||||
debugPrint("makeDistVehicle onEnter running")
|
||||
onEnter(vehicle)
|
||||
end
|
||||
end,
|
||||
onExit = function()
|
||||
deleteVehicle(vehicle)
|
||||
if onExit then
|
||||
debugPrint("makeDistVehicle onExit running")
|
||||
onExit(vehicle)
|
||||
end
|
||||
end,
|
||||
debug = debugMode,
|
||||
})
|
||||
distanceVehicles[zoneId] = { zone = zone, vehicle = vehicle }
|
||||
return zoneId
|
||||
end
|
||||
|
||||
--- Removes a specific distance-based vehicle spawning zone.
|
||||
---
|
||||
---@param zoneId string The unique identifier of the zone to remove.
|
||||
function removeDistVehicleZone(zoneId)
|
||||
if distanceVehicles[zoneId].zone then
|
||||
removePolyZone(distanceVehicles[zoneId].zone) -- Adjust this if your polyzone library uses a different removal method.
|
||||
if distanceVehicles[zoneId].vehicle then
|
||||
deleteVehicle(distanceVehicles[zoneId].vehicle)
|
||||
end
|
||||
distanceVehicles[zoneId] = nil
|
||||
print("Removed polyzone for zoneId: " .. zoneId)
|
||||
else
|
||||
print("No zone found with zoneId: " .. zoneId)
|
||||
end
|
||||
end
|
||||
|
||||
--- Attempts to gain network control of a vehicle and set it as a mission entity.
|
||||
---
|
||||
--- This function forces synchronization of a vehicle with other players by requesting network control and setting the vehicle as a mission entity.
|
||||
@@ -67,6 +121,20 @@ function pushVehicle(entity)
|
||||
end
|
||||
end
|
||||
|
||||
--- Deletes a spawned vehicle.
|
||||
---
|
||||
---@param vehicle number The handle of the vehicle entity to delete.
|
||||
function deleteVehicle(vehicle)
|
||||
if vehicle then
|
||||
debugPrint("^6Bridge^7: ^2Destroying Vehicle^7: '^6" .. vehicle .. "^7'")
|
||||
if IsEntityAttachedToEntity(vehicle, PlayerPedId()) then
|
||||
SetEntityAsMissionEntity(vehicle)
|
||||
DetachEntity(vehicle, true, true)
|
||||
end
|
||||
DeleteVehicle(vehicle)
|
||||
end
|
||||
end
|
||||
|
||||
--- Cleans up all created vehicles when the resource stops.
|
||||
onResourceStop(function(r)
|
||||
for i = 1, #Vehicles do DeleteVehicle(Vehicles[i]) end
|
||||
|
||||
@@ -220,7 +220,6 @@ function fundPlayer(fund, moneyType, newsrc)
|
||||
debugPrint("^6Bridge^7: ^2Funding Player: '^2"..fund.."^7'", moneyType, fundResource)
|
||||
end
|
||||
end
|
||||
RegisterNetEvent(getScript()..":server:FundPlayer", fundPlayer)
|
||||
|
||||
-------------------------------------------------------------
|
||||
-- Item Consumption & Effects
|
||||
@@ -458,7 +457,7 @@ function getPlayer(source)
|
||||
--gangBoss = info.gang.isboss,
|
||||
onDuty = info.job.onDuty,
|
||||
--account = info.charinfo.account,
|
||||
--citizenId = info.citizenid,
|
||||
citizenId = info.citizenid,
|
||||
}
|
||||
|
||||
elseif isStarted(OXCoreExport) then
|
||||
@@ -468,9 +467,20 @@ function getPlayer(source)
|
||||
chunk()
|
||||
local player = Ox.GetPlayer(src)
|
||||
Player = {
|
||||
firstname = player.firstName,
|
||||
lastname = player.lastName ,
|
||||
name = ('%s %s'):format(player.firstName, player.lastName),
|
||||
cash = exports[OXInv]:Search(src, 'count', "money"),
|
||||
bank = 0,
|
||||
source = src,
|
||||
--job = OxPlayer.getGroups(),
|
||||
--jobBoss = info.job.isboss,
|
||||
--gang = OxPlayer.getGroups(),
|
||||
--gangBoss = info.gang.isboss,
|
||||
--onDuty = info.job.onduty,
|
||||
--account = info.charinfo.account,
|
||||
citizenId = player.stateId,
|
||||
|
||||
}
|
||||
elseif isStarted(QBXExport) then
|
||||
local info = exports[QBXExport]:GetPlayer(src)
|
||||
@@ -513,7 +523,7 @@ function getPlayer(source)
|
||||
}
|
||||
end
|
||||
else
|
||||
print("^4ERROR^7: ^2No Core detected for getPlayer() - Check exports.lua")
|
||||
print("^4ERROR^7: ^2No Core detected for getPlayer() - Check starter.lua")
|
||||
end
|
||||
else
|
||||
-- Client-side: Get current player info.
|
||||
@@ -527,7 +537,9 @@ function getPlayer(source)
|
||||
Player = {
|
||||
firstname = info.firstName,
|
||||
lastname = info.lastName,
|
||||
|
||||
name = info.firstName.." "..info.lastName,
|
||||
cash = cash,
|
||||
bank = bank,
|
||||
source = GetPlayerServerId(PlayerId()),
|
||||
job = info.job.name,
|
||||
--jobBoss = info.job.isboss,
|
||||
@@ -535,30 +547,23 @@ function getPlayer(source)
|
||||
--gangBoss = info.gang.isboss,
|
||||
onDuty = info.job.onDuty,
|
||||
--account = info.charinfo.account,
|
||||
--citizenId = info.citizenid,
|
||||
|
||||
name = info.firstName.." "..info.lastName,
|
||||
cash = cash,
|
||||
bank = bank,
|
||||
citizenId = info.identifier,
|
||||
}
|
||||
elseif isStarted(OXCoreExport) then
|
||||
--local info = exports[OXCoreExport]:GetPlayerData()
|
||||
|
||||
Player = {
|
||||
firstname = OxPlayer.get("firstName"),
|
||||
lastname = OxPlayer.get("lastName"),
|
||||
name = OxPlayer.get("firstName").." "..OxPlayer.get("lastName"),
|
||||
cash = exports[OXInv]:Search('count', "money"),
|
||||
bank = 0,
|
||||
--source = info.source,
|
||||
source = GetPlayerServerId(PlayerId()),
|
||||
job = OxPlayer.getGroups(),
|
||||
--jobBoss = info.job.isboss,
|
||||
gang = OxPlayer.getGroups(),
|
||||
--gangBoss = info.gang.isboss,
|
||||
--onDuty = info.job.onduty,
|
||||
--account = info.charinfo.account,
|
||||
citizenId = OxPlayer.get("stateId"),
|
||||
|
||||
citizenId = OxPlayer.userId,
|
||||
}
|
||||
elseif isStarted(QBXExport) then
|
||||
local info = exports[QBXExport]:GetPlayerData()
|
||||
|
||||
@@ -31,7 +31,7 @@ function debugScaleForm(textTable, loc)
|
||||
local size = vec2(0.18, totalHeight + boxPadding * 2)
|
||||
|
||||
-- Draw background rectangle.
|
||||
DrawRect(loc.x + size.x / 2, loc.y + size.y / 2, size.x, size.y, 0, 0, 0, 255)
|
||||
DrawRect(loc.x + size.x / 2, loc.y + size.y / 2, size.x, size.y, 0, 0, 0, 200)
|
||||
|
||||
-- Render each line of text.
|
||||
for i = 1, #textTable do
|
||||
|
||||
206
shared/shops.lua
Normal file
206
shared/shops.lua
Normal file
@@ -0,0 +1,206 @@
|
||||
-------------------------------------------------------------
|
||||
-- Selling Menu and Animation
|
||||
-------------------------------------------------------------
|
||||
|
||||
--- Opens a selling menu with available items and prices.
|
||||
---
|
||||
--- @param data table Contains selling menu data:
|
||||
--- - sellTable (`table`) Table with Header and Items (item names and prices).
|
||||
--- - ped (optional) (`number`) Ped entity involved.
|
||||
--- - onBack (optional) (`function`) Callback for returning.
|
||||
--- @usage
|
||||
--- ```lua
|
||||
--- sellMenu({
|
||||
--- sellTable = {
|
||||
--- Header = "Sell Items",
|
||||
--- Items = {
|
||||
--- ["gold_ring"] = 100,
|
||||
--- ["diamond"] = 500,
|
||||
--- },
|
||||
--- },
|
||||
--- ped = pedEntity,
|
||||
--- onBack = function() print("Returning to previous menu") end,
|
||||
--- })
|
||||
--- ```
|
||||
function sellMenu(data)
|
||||
local origData = data
|
||||
local Menu = {}
|
||||
if data.sellTable.Items then
|
||||
local itemList = {}
|
||||
for k, v in pairs(data.sellTable.Items) do itemList[k] = 1 end
|
||||
local _, hasTable = hasItem(itemList)
|
||||
for k, v in pairsByKeys(data.sellTable.Items) do
|
||||
Menu[#Menu + 1] = {
|
||||
isMenuHeader = not hasTable[k].hasItem,
|
||||
icon = invImg(k),
|
||||
header = Items[k].label..(hasTable[k].hasItem and "💰 (x"..hasTable[k].count..")" or ""),
|
||||
txt = Loc[Config.Lan].info["sell_all"]..v.." "..Loc[Config.Lan].info["sell_each"],
|
||||
onSelect = function()
|
||||
sellAnim({ item = k, price = v, ped = data.ped, onBack = function() sellMenu(data) end })
|
||||
end,
|
||||
}
|
||||
end
|
||||
else
|
||||
for k, v in pairsByKeys(data.sellTable) do
|
||||
if type(v) == "table" then
|
||||
Menu[#Menu + 1] = {
|
||||
arrow = true,
|
||||
header = k,
|
||||
txt = "Amount of items: "..countTable(v.Items),
|
||||
onSelect = function()
|
||||
v.onBack = function() sellMenu(origData) end
|
||||
v.sellTable = data.sellTable[k]
|
||||
sellMenu(v)
|
||||
end,
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
openMenu(Menu, {
|
||||
header = data.sellTable.Header or "Amount of items: "..countTable(data.sellTable.Items),
|
||||
headertxt = data.sellTable.Header and "Amount of items: "..countTable(data.sellTable.Items) or "",
|
||||
canClose = true,
|
||||
onBack = data.onBack,
|
||||
})
|
||||
end
|
||||
|
||||
--- Plays the selling animation and processes the sale transaction.
|
||||
---
|
||||
--- Checks if the player has the item, plays animations, triggers the server event for selling,
|
||||
--- and then calls the onBack callback if provided.
|
||||
---
|
||||
--- @param data table Contains:
|
||||
--- `- item: The item to sell.
|
||||
--- `- price: Price per item.
|
||||
--- `- ped (optional): Ped entity involved.
|
||||
--- `- onBack (optional): Callback to call on completion.
|
||||
---@usage
|
||||
--- ```lua
|
||||
--- sellAnim({
|
||||
--- item = "gold_ring",
|
||||
--- price = 100,
|
||||
--- ped = pedEntity,
|
||||
--- onBack = function() sellMenu(data) end,
|
||||
--- })
|
||||
--- ```
|
||||
function sellAnim(data)
|
||||
if not hasItem(data.item, 1) then
|
||||
triggerNotify(nil, Loc[Config.Lan].error["dont_have"].." "..Items[data.item].label, "error")
|
||||
return
|
||||
end
|
||||
|
||||
-- Remove any attached clipboard objects.
|
||||
for _, obj in pairs(GetGamePool('CObject')) do
|
||||
for _, model in pairs({ `p_cs_clipboard` }) do
|
||||
if GetEntityModel(obj) == model and IsEntityAttachedToEntity(data.ped, obj) then
|
||||
DeleteObject(obj)
|
||||
DetachEntity(obj, 0, 0)
|
||||
SetEntityAsMissionEntity(obj, true, true)
|
||||
Wait(100)
|
||||
DeleteEntity(obj)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
TriggerServerEvent(getScript().."Sellitems", data)
|
||||
lookEnt(data.ped)
|
||||
local dict = "mp_common"
|
||||
playAnim(dict, "givetake2_a", 0.3, 2)
|
||||
playAnim(dict, "givetake2_b", 0.3, 2, data.ped)
|
||||
Wait(2000)
|
||||
StopAnimTask(PlayerPedId(), dict, "givetake2_a", 0.5)
|
||||
StopAnimTask(data.ped, dict, "givetake2_b", 0.5)
|
||||
if data.onBack then data.onBack() end
|
||||
end
|
||||
|
||||
--- Server event handler for processing item sales.
|
||||
--- Removes sold items from inventory and funds the player based on the sale.
|
||||
RegisterNetEvent(getScript().."Sellitems", function(data)
|
||||
local src = source
|
||||
local hasItems, hasTable = hasItem(data.item, 1, src)
|
||||
if hasItems then
|
||||
removeItem(data.item, hasTable[data.item].count, src)
|
||||
fundPlayer((hasTable[data.item].count * data.price), "cash", src)
|
||||
else
|
||||
triggerNotify(nil, Loc[Config.Lan].error["dont_have"].." "..Items[data.item].label, "error", src)
|
||||
end
|
||||
end)
|
||||
|
||||
-------------------------------------------------------------
|
||||
-- Shop Interface
|
||||
-------------------------------------------------------------
|
||||
|
||||
--- Opens a shop interface for the player.
|
||||
---
|
||||
--- Checks job/gang restrictions, then uses the active inventory system to open the shop.
|
||||
--- @param data table Contains:
|
||||
--- - shop (`string`) The shop identifier.
|
||||
--- - items (`table`) The items available in the shop.
|
||||
--- - coords (`vector3`) where the shop is located.
|
||||
--- - job/gang (optional) (`string`) Job or gang requirements.
|
||||
---@usage
|
||||
--- ```lua
|
||||
--- openShop({
|
||||
--- shop = "weapon_shop",
|
||||
--- items = weaponShopItems,
|
||||
--- coords = vector3(100.0, 200.0, 300.0),
|
||||
--- job = "police",
|
||||
--- })
|
||||
--- ```
|
||||
function openShop(data)
|
||||
if (data.job or data.gang) and not jobCheck(data.job or data.gang) then return end
|
||||
|
||||
if isStarted(OXInv) then
|
||||
exports[OXInv]:openInventory('shop', { type = data.shop })
|
||||
|
||||
elseif isStarted(QBInv) then
|
||||
if QBInvNew then
|
||||
TriggerServerEvent(getScript()..':server:OpenShopNewQB', data.shop)
|
||||
else
|
||||
TriggerServerEvent(Config.General.JimShops and "jim-shops:ShopOpen" or "inventory:server:OpenInventory", "shop", data.items.label, data.items)
|
||||
end
|
||||
|
||||
--elseif isStarted(OrigenInv) then -- Needs testing, not sure if i did this right
|
||||
-- exports[OrigenInv]:openInventory('shop', data.shop, data.items)
|
||||
|
||||
else
|
||||
TriggerServerEvent(Config.General.JimShops and "jim-shops:ShopOpen" or "inventory:server:OpenInventory", "shop", data.items.label, data.items)
|
||||
end
|
||||
lookEnt(data.coords)
|
||||
end
|
||||
|
||||
--- Server event handler for opening a shop using the new QB inventory system.
|
||||
RegisterNetEvent(getScript()..':server:OpenShopNewQB', function(data)
|
||||
exports[QBInv]:OpenShop(source, data)
|
||||
end)
|
||||
|
||||
--- Registers a shop with the active inventory system.
|
||||
--- Supports either OXInv or QBInv (with QBInvNew flag).
|
||||
---
|
||||
--- @param name string Unique shop identifier.
|
||||
--- @param label string Display name for the shop.
|
||||
--- @param items table List of available shop items.
|
||||
--- @param society string|nil (Optional) Society identifier for shared shops.
|
||||
--- @usage
|
||||
--- ```lua
|
||||
--- registerShop("weaponShop", "Weapon Shop", weaponItems, "society_weapons")
|
||||
--- ```
|
||||
function registerShop(name, label, items, society)
|
||||
if isStarted(OXInv) then
|
||||
debugPrint("^6Bridge^7: ^2Registering ^3OX ^2Store^7:", name, label)
|
||||
exports[OXInv]:RegisterShop(name, {
|
||||
name = label,
|
||||
inventory = items,
|
||||
society = society,
|
||||
})
|
||||
elseif isStarted(QBInv) and QBInvNew then
|
||||
debugPrint("^6Bridge^7: ^2Registering ^3QB ^2Store^7:", name, label)
|
||||
exports[QBInv]:CreateShop({
|
||||
name = name,
|
||||
label = label,
|
||||
slots = #items,
|
||||
items = items,
|
||||
society = society,
|
||||
})
|
||||
end
|
||||
end
|
||||
36
shared/skillcheck.lua
Normal file
36
shared/skillcheck.lua
Normal file
@@ -0,0 +1,36 @@
|
||||
|
||||
|
||||
function skillCheck(data)
|
||||
local result = false
|
||||
|
||||
if Config.System.skillCheck == "qb" then
|
||||
local Skillbar = exports["qb-minigames"]:Skillbar()
|
||||
if Skillbar then
|
||||
result = true
|
||||
else
|
||||
result = false
|
||||
end
|
||||
|
||||
elseif Config.System.skillCheck == "ox" then
|
||||
local Skillbar = exports[OXLibExport]:skillCheck(
|
||||
{
|
||||
"easy",
|
||||
"easy",
|
||||
"easy"
|
||||
},
|
||||
{
|
||||
"1",
|
||||
"2",
|
||||
"3",
|
||||
"4"
|
||||
})
|
||||
if Skillbar then
|
||||
result = true
|
||||
else
|
||||
result = false
|
||||
end
|
||||
else
|
||||
result = true
|
||||
end
|
||||
return result
|
||||
end
|
||||
@@ -99,7 +99,7 @@ function checkHasItem(stashes, itemTable)
|
||||
for item, amount in pairs(itemTable) do
|
||||
debugPrint("^6Bridge^7: ^2Checking "..(name and " '^3"..name.."^7'" or "").." ingredients - ^6"..item.."^7")
|
||||
if stashhasItem(stashCache[name].items, item, amount) then
|
||||
successes = successes + 1
|
||||
successes += 1
|
||||
if successes == itemCount then
|
||||
return true, name
|
||||
end
|
||||
@@ -271,7 +271,6 @@ function stashRemoveItem(stashItems, stashName, items)
|
||||
|
||||
if isStarted(OXInv) then
|
||||
for k, v in pairs(items) do
|
||||
debugPrint("^6Bridge^7: ^2Removing item from ^3Stash^2 with ^7"..OXInv, k, v)
|
||||
if type(stashName) == "table" then
|
||||
for _, name in pairs(stashName) do
|
||||
local success = exports[OXInv]:RemoveItem(name, k, v)
|
||||
|
||||
@@ -119,9 +119,8 @@ function createEntityTarget(entity, opts, dist)
|
||||
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
|
||||
distance = dist,
|
||||
canInteract = opts[i].canInteract or nil,
|
||||
}
|
||||
end
|
||||
exports[OXTargetExport]:addLocalEntity(entity, options)
|
||||
@@ -223,9 +222,8 @@ function createBoxTarget(data, opts, dist)
|
||||
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
|
||||
distance = dist,
|
||||
canInteract = opts[i].canInteract or nil,
|
||||
}
|
||||
end
|
||||
if not data[5].useZ then
|
||||
@@ -324,9 +322,8 @@ function createCircleTarget(data, opts, dist)
|
||||
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
|
||||
end
|
||||
distance = dist,
|
||||
canInteract = opts[i].canInteract or nil,
|
||||
}
|
||||
end
|
||||
local target = exports[OXTargetExport]:addSphereZone({
|
||||
@@ -385,9 +382,8 @@ function createModelTarget(models, opts, dist)
|
||||
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
|
||||
distance = dist,
|
||||
canInteract = opts[i].canInteract or nil,
|
||||
}
|
||||
end
|
||||
exports[OXTargetExport]:addModel(models, options)
|
||||
|
||||
@@ -128,14 +128,15 @@ end
|
||||
function setVehicleProperties(vehicle, props)
|
||||
if checkDifferences(vehicle, props) then
|
||||
if not DoesEntityExist(vehicle) then
|
||||
print("Unable to set vehicle properties for '"..vehicle.."' (entity does not exist)")
|
||||
print("Unable to set vehicle properties for '"..vehicle.."' (^1entity does not exist^7)")
|
||||
end
|
||||
|
||||
if isStarted(QBExport) and not isStarted(QBXExport) then
|
||||
Core.Functions.SetVehicleProperties(vehicle, props)
|
||||
debugPrint("^6Bridge^7: ^2Setting Vehicle Properties ^7[^6"..QBExport.."^7] - [^3"..vehicle.."^7] - [^3"..GetEntityModel(vehicle).."^7/^3"..props.model.."^7] - [^3"..props.plate.."^7]")
|
||||
else
|
||||
TriggerServerEvent(getScript()..":ox:setVehicleProperties", VehToNet(vehicle), props)
|
||||
elseif isStarted(OXLibExport) then
|
||||
lib.setVehicleProperties(vehicle, props, false)
|
||||
debugPrint("^6Bridge^7: ^2Setting Vehicle Properties ^7[^6"..OXLibExport.."^7] - [^3"..vehicle.."^7] - [^3"..GetEntityModel(vehicle).."^7/^3"..props.model.."^7] - [^3"..props.plate.."^7]")
|
||||
end
|
||||
else
|
||||
debugPrint("^6Bridge^7: ^2No Changes Found ^7 [^3"..vehicle.."^7] - [^3"..GetEntityModel(vehicle).."^7/^3"..props.model.."^7] - [^3"..props.plate.."^7]")
|
||||
@@ -158,7 +159,7 @@ end
|
||||
function checkDifferences(vehicle, newProps)
|
||||
local oldProps = getVehicleProperties(vehicle)
|
||||
debugPrint("^6Bridge^7: ^2Finding differences in ^3Vehicle Properties^7")
|
||||
local differencesFound = false
|
||||
local differencesFound = true
|
||||
|
||||
for k in pairs(oldProps) do
|
||||
if json.encode(oldProps[k]) ~= json.encode(newProps[k]) then
|
||||
@@ -199,7 +200,7 @@ AddStateBagChangeHandler(getScript()..':setVehicleProperties', '', function(bagN
|
||||
local networked = not bagName:find('localEntity')
|
||||
debugPrint("^6Bridge^7: ^2Setting Vehicle Properties ^7[^6"..OXLibExport.."^7] - [^3"..entity.."^7] - [^3"..GetEntityModel(entity).."^7] - [^3"..value.plate.."^7]")
|
||||
|
||||
if networked and NetworkGetEntityOwner(entity) ~= cache.playerId then return end
|
||||
if networked then return end
|
||||
|
||||
if lib.setVehicleProperties(entity, value) then
|
||||
Entity(entity).state:set('setVehicleProperties', nil, true)
|
||||
|
||||
@@ -119,7 +119,18 @@ if isServer() then
|
||||
--- ```lua
|
||||
--- TriggerEvent(getScript()..":server:makeOXStash", name, label, slots, weight, owner, coords)
|
||||
--- ```
|
||||
RegisterNetEvent(getScript()..":server:makeOXStash", function(name, label, slots, weight, owner, coords)
|
||||
RegisterNetEvent(getScript()..":server:makeOXStash", function(name, label, slots, weight, owner, coords, token)
|
||||
local src = source or nil
|
||||
if src then
|
||||
debugPrint("^1Auth^7: ^2Auth token received^7, ^2checking against server cache^7..")
|
||||
if token ~= validTokens[src] then
|
||||
debugPrint("^1Auth^7: ^1Tokens don't match! ^7", token, validTokens[src])
|
||||
else
|
||||
debugPrint("^1Auth^7: ^2Client and Server Auth tokens match^7!", token, validTokens[src])
|
||||
validTokens[src] = nil
|
||||
end
|
||||
end
|
||||
|
||||
registerStash(name, label, slots, weight, owner, coords)
|
||||
end)
|
||||
end
|
||||
|
||||
@@ -71,9 +71,11 @@ for _, v in pairs({ -- This is a specific load order
|
||||
'input.lua',
|
||||
'notify.lua',
|
||||
'drawText.lua',
|
||||
'skillcheck.lua',
|
||||
|
||||
-- Crafting / Shops / Stashes
|
||||
'crafting.lua',
|
||||
'shops.lua',
|
||||
'stashcontrol.lua',
|
||||
|
||||
-- Kind of "other"
|
||||
|
||||
@@ -1 +1 @@
|
||||
1.2
|
||||
2.0
|
||||
Reference in New Issue
Block a user