(Beta) Fixes for multiframework support

This commit is contained in:
Jim Shield
2025-03-01 12:58:43 +00:00
committed by GitHub
parent f9812a689e
commit 8eb98bff29
39 changed files with 7372 additions and 7188 deletions

View File

@@ -1,14 +1,14 @@
name "Jim_Bridge" name "Jim_Bridge"
author "Jimathy" author "Jimathy"
version "2.0" version "2.0"
description "Framework Bridge By Jimathy" description "Framework Bridge By Jimathy"
fx_version "cerulean" fx_version "cerulean"
game "gta5" game "gta5"
lua54 'yes' lua54 'yes'
files { files {
'starter.lua', 'starter.lua',
'shared/*.lua', 'shared/*.lua',
'shared/make/*.lua', 'shared/make/*.lua',
'shared/scaleforms/*.lua', 'shared/scaleforms/*.lua',
} }

View File

@@ -1,149 +1,149 @@
-- IN NO WAY PERFECT -- ** Experimental debugging -- IN NO WAY PERFECT -- ** Experimental debugging
function toggleDebug() function toggleDebug()
Config.System.Debug = not Config.System.Debug Config.System.Debug = not Config.System.Debug
print("Debug Prints = "..tostring(Config.System.Debug)) print("Debug Prints = "..tostring(Config.System.Debug))
end end
exports("toggleDebug", toggleDebug) exports("toggleDebug", toggleDebug)
function getDebug() return Config.System.Debug end function getDebug() return Config.System.Debug end
exports("getDebug", getDebug) exports("getDebug", getDebug)
local origRegisterNetEvent = RegisterNetEvent local origRegisterNetEvent = RegisterNetEvent
local origTriggerEvent = TriggerEvent local origTriggerEvent = TriggerEvent
local origTriggerServerEvent = TriggerServerEvent local origTriggerServerEvent = TriggerServerEvent
local origTriggerClientEvent = TriggerClientEvent local origTriggerClientEvent = TriggerClientEvent
local origExecuteCommand = ExecuteCommand local origExecuteCommand = ExecuteCommand
local origRegisterCommand = RegisterCommand local origRegisterCommand = RegisterCommand
local origPairs = pairs local origPairs = pairs
local origiPairs = ipairs local origiPairs = ipairs
function getDebugInfo(info) function getDebugInfo(info)
local info = info local info = info
local level = 2 local level = 2
if info and info.short_src:match("scheduler.lua") then if info and info.short_src:match("scheduler.lua") then
repeat repeat
info = debug.getinfo(level, "nSl") info = debug.getinfo(level, "nSl")
level += 1 level += 1
local found = false local found = false
for _, v in pairs({ for _, v in pairs({
"deffered.lua", "deffered.lua",
"scheduler.lua", "scheduler.lua",
"_eventDebug.lua", "_eventDebug.lua",
"targets.lua", "targets.lua",
"init.lua", "init.lua",
"MySQL.lua", "MySQL.lua",
"helpers.lua", "helpers.lua",
}) do }) do
if info and info.short_src:match(v) then if info and info.short_src:match(v) then
found = true found = true
end end
end end
until not info or (info.short_src and found == false) until not info or (info.short_src and found == false)
end end
return " ^7[^3"..(info and info.short_src:match("^.+/(.+)$") or "unknown").."^7:^3"..(info and info.currentline or "unknown").."^7]" return " ^7[^3"..(info and info.short_src:match("^.+/(.+)$") or "unknown").."^7:^3"..(info and info.currentline or "unknown").."^7]"
end end
--This is just a for debugging, not important, just announces which events are being registered triggered when these functions are used --This is just a for debugging, not important, just announces which events are being registered triggered when these functions are used
function RegisterNetEvent(name, funct) function RegisterNetEvent(name, funct)
if Config.System.EventDebug then if Config.System.EventDebug then
if name:find("__ox_cb_") then if name:find("__ox_cb_") then
print("^6Bridge^7: ^2Registered ^3"..(isServer() and "Server" or "Client").." ^2Callback^7: ^6"..name:gsub("__ox_cb_", ""):gsub("%:", "^7:^4").."^7"..getDebugInfo(debug.getinfo(2, "nSl"))) print("^6Bridge^7: ^2Registered ^3"..(isServer() and "Server" or "Client").." ^2Callback^7: ^6"..name:gsub("__ox_cb_", ""):gsub("%:", "^7:^4").."^7"..getDebugInfo(debug.getinfo(2, "nSl")))
else else
print("^6Bridge^7: ^2Registering ^3"..(isServer() and "Server" or "Client").." ^2Net event^7: ^6"..name:gsub("%:", "^7:^4").."^7"..getDebugInfo(debug.getinfo(2, "nSl"))) print("^6Bridge^7: ^2Registering ^3"..(isServer() and "Server" or "Client").." ^2Net event^7: ^6"..name:gsub("%:", "^7:^4").."^7"..getDebugInfo(debug.getinfo(2, "nSl")))
end end
end end
origRegisterNetEvent(name, funct) origRegisterNetEvent(name, funct)
end end
function TriggerEvent(name, ...) function TriggerEvent(name, ...)
local data = {...} local data = {...}
if Config.System.EventDebug then if Config.System.EventDebug then
if name:find("__cfx_export") then if name:find("__cfx_export") then
print("^6Bridge^7: "..GetPrintTime().." ^2Triggering ^3"..(isServer() and "Server" or "Client").." ^2Export^7: ^6"..name:gsub("__cfx_export_", ""):gsub("%:", "^7:^4").."^7"..getDebugInfo(debug.getinfo(2, "nSl"))) print("^6Bridge^7: "..GetPrintTime().." ^2Triggering ^3"..(isServer() and "Server" or "Client").." ^2Export^7: ^6"..name:gsub("__cfx_export_", ""):gsub("%:", "^7:^4").."^7"..getDebugInfo(debug.getinfo(2, "nSl")))
else else
print("^6Bridge^7: "..GetPrintTime().." ^2Triggering ^3"..(isServer() and "Server" or "Client").." ^2Net event^7: ^6"..name:gsub("%:", "^7:^4").."^7"..getDebugInfo(debug.getinfo(2, "nSl"))) print("^6Bridge^7: "..GetPrintTime().." ^2Triggering ^3"..(isServer() and "Server" or "Client").." ^2Net event^7: ^6"..name:gsub("%:", "^7:^4").."^7"..getDebugInfo(debug.getinfo(2, "nSl")))
end end
for i, value in ipairs(data) do for i, value in ipairs(data) do
if value then if value then
local valueStr = (type(value) == "table" and json.encode(value) or tostring(value)) local valueStr = (type(value) == "table" and json.encode(value) or tostring(value))
print(string.format("^6Bridge^7: ^7[^3%d^7]: ^7(^5%s^7): %s".."^7", i, type(value), valueStr)) print(string.format("^6Bridge^7: ^7[^3%d^7]: ^7(^5%s^7): %s".."^7", i, type(value), valueStr))
end end
end end end end
origTriggerEvent(name, ...) origTriggerEvent(name, ...)
end end
function TriggerServerEvent(name, ...) -- Client side, trigger a server event function TriggerServerEvent(name, ...) -- Client side, trigger a server event
local data = {...} local data = {...}
if Config.System.EventDebug then if Config.System.EventDebug then
if name:find("__ox_cb") then if name:find("__ox_cb") then
print("^6Bridge^7: "..GetPrintTime().." ^2Triggered ^3Server ^2Callback: ^6"..name:gsub("__ox_cb_", "").."^7"..getDebugInfo(debug.getinfo(2, "nSl"))) print("^6Bridge^7: "..GetPrintTime().." ^2Triggered ^3Server ^2Callback: ^6"..name:gsub("__ox_cb_", "").."^7"..getDebugInfo(debug.getinfo(2, "nSl")))
else else
print("^6Bridge^7: "..GetPrintTime().." ^2Triggering ^3Server ^2Net event^7: ^6"..name:gsub("%:", "^7:^4").."^7"..getDebugInfo(debug.getinfo(2, "nSl"))) print("^6Bridge^7: "..GetPrintTime().." ^2Triggering ^3Server ^2Net event^7: ^6"..name:gsub("%:", "^7:^4").."^7"..getDebugInfo(debug.getinfo(2, "nSl")))
end end
for i, value in ipairs(data) do for i, value in ipairs(data) do
if value then if value then
local valueStr = (type(value) == "table" and json.encode(value) or tostring(value)) local valueStr = (type(value) == "table" and json.encode(value) or tostring(value))
print(string.format("^6Bridge^7: ^7[^3%d^7]: ^7(^5%s^7): %s".."^7", i, type(value), valueStr)) print(string.format("^6Bridge^7: ^7[^3%d^7]: ^7(^5%s^7): %s".."^7", i, type(value), valueStr))
end end
end end end end
origTriggerServerEvent(name, ...) origTriggerServerEvent(name, ...)
end end
function TriggerClientEvent(name, ...) -- Server side, trigger a client event function TriggerClientEvent(name, ...) -- Server side, trigger a client event
local data = {...} local data = {...}
if Config.System.EventDebug then if Config.System.EventDebug then
if name:find("__ox_cb") then if name:find("__ox_cb") then
print("^6Bridge^7: "..GetPrintTime().." ^2Triggered ^3Client ^2Callback: ^6"..name:gsub("__ox_cb_", "").."^7"..getDebugInfo(debug.getinfo(2, "nSl"))) print("^6Bridge^7: "..GetPrintTime().." ^2Triggered ^3Client ^2Callback: ^6"..name:gsub("__ox_cb_", "").."^7"..getDebugInfo(debug.getinfo(2, "nSl")))
else else
print("^6Bridge^7: "..GetPrintTime().." ^2Triggering ^3Client ^2Net event^7: ^6"..name:gsub("%:", "^7:^4").."^7"..getDebugInfo(debug.getinfo(2, "nSl"))) print("^6Bridge^7: "..GetPrintTime().." ^2Triggering ^3Client ^2Net event^7: ^6"..name:gsub("%:", "^7:^4").."^7"..getDebugInfo(debug.getinfo(2, "nSl")))
end end
for i, value in ipairs(data) do for i, value in ipairs(data) do
if value then if value then
local valueStr = (type(value) == "table" and json.encode(value) or tostring(value)) local valueStr = (type(value) == "table" and json.encode(value) or tostring(value))
print(string.format("^6Bridge^7: ^7[^3%d^7]: ^7(^5%s^7): %s".."^7", i, type(value), valueStr)) print(string.format("^6Bridge^7: ^7[^3%d^7]: ^7(^5%s^7): %s".."^7", i, type(value), valueStr))
end end
end end end end
origTriggerClientEvent(name, ...) origTriggerClientEvent(name, ...)
end end
function RegisterCommand(command, funct, restrict) function RegisterCommand(command, funct, restrict)
if Config.System.EventDebug then if Config.System.EventDebug then
print("^6Bridge^7: ^2Registering ^2Command^7: /"..command.." ^7| ^4Funct^7: "..tostring(funct):gsub("function: ", "").." ^7| ^4Admin^7: "..(restict and "true" or "false")..getDebugInfo(debug.getinfo(2, "nSl"))) print("^6Bridge^7: ^2Registering ^2Command^7: /"..command.." ^7| ^4Funct^7: "..tostring(funct):gsub("function: ", "").." ^7| ^4Admin^7: "..(restict and "true" or "false")..getDebugInfo(debug.getinfo(2, "nSl")))
end end
origRegisterCommand(command, funct, restrict) origRegisterCommand(command, funct, restrict)
end end
function ExecuteCommand(comm) -- Client side, execute /command function ExecuteCommand(comm) -- Client side, execute /command
if Config.System.EventDebug then if Config.System.EventDebug then
print("^6Bridge^7: "..GetPrintTime().." ^2Triggering ^3ExecuteCommand^7: /"..comm..getDebugInfo(debug.getinfo(2, "nSl"))) print("^6Bridge^7: "..GetPrintTime().." ^2Triggering ^3ExecuteCommand^7: /"..comm..getDebugInfo(debug.getinfo(2, "nSl")))
end end
origExecuteCommand(comm) origExecuteCommand(comm)
end end
function pairs(tbl) function pairs(tbl)
if not tbl then if not tbl then
print("^1Error^7: ^1nil ^2for ^3pairs^7(), ^2setting to ^7{} ^2to prevent break^7"..getDebugInfo(debug.getinfo(2, "nSl"))) print("^1Error^7: ^1nil ^2for ^3pairs^7(), ^2setting to ^7{} ^2to prevent break^7"..getDebugInfo(debug.getinfo(2, "nSl")))
return origPairs({}) return origPairs({})
end end
return origPairs(tbl) return origPairs(tbl)
end end
function ipairs(tbl) function ipairs(tbl)
local tbl = tbl local tbl = tbl
if not tbl then if not tbl then
if Config.System.EventDebug then if Config.System.EventDebug then
print("^1Error^7: ^3iPairs^7() ^1nil ^2recieved^7, ^2setting to ^7{} ^2to prevent break^7"..getDebugInfo(debug.getinfo(2, "nSl"))) print("^1Error^7: ^3iPairs^7() ^1nil ^2recieved^7, ^2setting to ^7{} ^2to prevent break^7"..getDebugInfo(debug.getinfo(2, "nSl")))
end end
tbl = {} tbl = {}
end end
return pairsByKeys(tbl) -- change to pairsByKeys for less errors return pairsByKeys(tbl) -- change to pairsByKeys for less errors
end end
--[[ --[[
local origPrint = print local origPrint = print
function print(...) function print(...)
origPrint(getDebugInfo(debug.getinfo(2, "nSl"))..":") origPrint(getDebugInfo(debug.getinfo(2, "nSl"))..":")
origPrint(...) origPrint(...)
end end
]] ]]

View File

@@ -1,110 +1,121 @@
--- Executes a function when the player character is loaded into the game. --- Executes a function when the player character is loaded into the game.
--- ---
--- This function sets up event listeners for player loading based on the game framework detected (e.g., QB, ESX, OX). --- This function sets up event listeners for player loading based on the game framework detected (e.g., QB, ESX, OX).
--- ---
--- If `onStart` is `true`, it will also attempt to execute the function on resource start after ensuring the player is logged in. (Helpful for debugging) --- If `onStart` is `true`, it will also attempt to execute the function on resource start after ensuring the player is logged in. (Helpful for debugging)
--- ---
--- @param func function The function to execute when the player is loaded. --- @param func function The function to execute when the player is loaded.
--- @param onStart boolean (optional) If `true`, the function will also execute on resource start. Default is `false`. --- @param onStart boolean (optional) If `true`, the function will also execute on resource start. Default is `false`.
--- ---
--- @usage --- @usage
--- ```lua --- ```lua
--- onPlayerLoaded(function() --- onPlayerLoaded(function()
--- -- Your code here --- -- Your code here
--- end, true) --- end, true)
--- ``` --- ```
function onPlayerLoaded(func, onStart) function onPlayerLoaded(func, onStart)
local onPlayerName = "" local onPlayerName = ""
local loaded = false local loaded = false
if onStart then if onStart then
onResourceStart(function() onResourceStart(function()
if not LocalPlayer.state.isLoggedIn then if not LocalPlayer.state.isLoggedIn then
Wait(3000) Wait(3000)
if not LocalPlayer.state.isLoggedIn then -- If the player is not logged in after waiting, skip execution if not LocalPlayer.state.isLoggedIn then -- If the player is not logged in after waiting, skip execution
return return
end end
end end
loaded = true -- Mark as already loaded loaded = true -- Mark as already loaded
debugPrint("^6Bridge^7: ^2Loading ^3onResourceStart^7() ^2through ^3onPlayerLoaded^7()") debugPrint("^6Bridge^7: ^2Loading ^3onResourceStart^7() ^2through ^3onPlayerLoaded^7()")
Wait(2000) Wait(2000)
func() func()
end, true) end, true)
end end
if not loaded then if not loaded then
local tempFunc = function() local tempFunc = function()
debugPrint("^6Bridge^7: ^2Executing ^3onPlayerLoaded^7()") debugPrint("^6Bridge^7: ^2Executing ^3onPlayerLoaded^7()")
func() func()
end end
if isStarted(QBExport) or isStarted(QBXExport) then onPlayerName = QBExport if isStarted(QBExport) or isStarted(QBXExport) then onPlayerName = QBExport
AddEventHandler('QBCore:Client:OnPlayerLoaded', tempFunc) AddEventHandler('QBCore:Client:OnPlayerLoaded', tempFunc)
elseif isStarted(ESXExport) then onPlayerName = ESXExport elseif isStarted(ESXExport) then onPlayerName = ESXExport
AddEventHandler('esx:playerLoaded', tempFunc) AddEventHandler('esx:playerLoaded', tempFunc)
elseif isStarted(OXCoreExport) then onPlayerName = OXCoreExport elseif isStarted(OXCoreExport) then onPlayerName = OXCoreExport
AddEventHandler('ox:playerLoaded', tempFunc) AddEventHandler('ox:playerLoaded', tempFunc)
end end
if onPlayerName ~= "" then if onPlayerName ~= "" then
debugPrint("^6Bridge^7: ^2Registering ^3onPlayerLoaded^2 with ^7"..onPlayerName) debugPrint("^6Bridge^7: ^2Registering ^3onPlayerLoaded^2 with ^7"..onPlayerName)
else else
print("^4ERROR^7: ^2No Core detected for onPlayerLoaded ^7- ^2Check ^3exports^1.^2lua^7") print("^4ERROR^7: ^2No Core detected for onPlayerLoaded ^7- ^2Check ^3exports^1.^2lua^7")
end end
end end
end end
--- Executes a function when the resource starts. --trying to add unload functions for when players switch ped
--- function onPlayerUnload(func)
--- This function wraps the `onResourceStart` event, allowing you to execute code when the resource starts. AddEventHandler('QBCore:Client:OnPlayerUnload', function()
--- func()
--- @param func function The function to execute on resource start. end)
--- @param thisScript boolean (optional) If `true`, only runs the function when this resource starts. Default is `true`. AddEventHandler('ox:playerLogout', function()
--- func()
--- @usage end)
--- ```lua end
--- onResourceStart(function()
--- -- Your code here
--- end, true) --- Executes a function when the resource starts.
--- ``` ---
function onResourceStart(func, thisScript) --- This function wraps the `onResourceStart` event, allowing you to execute code when the resource starts.
debugPrint("^6Bridge^7: ^2Registering ^3onResourceStart^2") ---
AddEventHandler('onResourceStart', function(resourceName) --- @param func function The function to execute on resource start.
if getScript() == resourceName and (thisScript or true) then --- @param thisScript boolean (optional) If `true`, only runs the function when this resource starts. Default is `true`.
func() ---
end --- @usage
end) --- ```lua
end --- onResourceStart(function()
--- -- Your code here
--- Executes a function when the resource stops. --- end, true)
--- --- ```
--- This function wraps the `onResourceStop` event, allowing you to execute code when the resource stops. function onResourceStart(func, thisScript)
--- debugPrint("^6Bridge^7: ^2Registering ^3onResourceStart^2")
--- @param func function The function to execute on resource stop. AddEventHandler('onResourceStart', function(resourceName)
--- @param thisScript boolean (optional) If `true`, only runs the function when this resource stops. Default is `true`. if getScript() == resourceName and (thisScript or true) then
--- func()
--- @usage end
--- ```lua end)
--- onResourceStop(function() end
--- -- Cleanup code here
--- end, true) --- Executes a function when the resource stops.
--- ``` ---
function onResourceStop(func, thisScript) --- This function wraps the `onResourceStop` event, allowing you to execute code when the resource stops.
debugPrint("^6Bridge^7: ^2Registering ^3onResourceStop^2") ---
AddEventHandler('onResourceStop', function(resourceName) --- @param func function The function to execute on resource stop.
if getScript() == resourceName and (thisScript or true) then --- @param thisScript boolean (optional) If `true`, only runs the function when this resource stops. Default is `true`.
func() ---
end --- @usage
end) --- ```lua
end --- onResourceStop(function()
--- -- Cleanup code here
--- Waits until the player is logged in before continuing execution. --- end, true)
--- --- ```
--- This function blocks execution until `LocalPlayer.state.isLoggedIn` is `true`. function onResourceStop(func, thisScript)
--- debugPrint("^6Bridge^7: ^2Registering ^3onResourceStop^2")
---@usage AddEventHandler('onResourceStop', function(resourceName)
--- ```lua if getScript() == resourceName and (thisScript or true) then
--- waitForLogin() func()
--- ``` end
function waitForLogin() end)
while not LocalPlayer.state.isLoggedIn do end
debugPrint("Waiting")
Wait(100) --- Waits until the player is logged in before continuing execution.
end ---
--- This function blocks execution until `LocalPlayer.state.isLoggedIn` is `true`.
---
---@usage
--- ```lua
--- waitForLogin()
--- ```
function waitForLogin()
while not LocalPlayer.state.isLoggedIn do
debugPrint("Waiting")
Wait(100)
end
end end

View File

@@ -1,68 +1,68 @@
--- Registers a callback function with the appropriate framework. --- Registers a callback function with the appropriate framework.
--- ---
--- This function checks which framework is started (e.g., OX, QB, ESX) and registers the callback accordingly. --- This function checks which framework is started (e.g., OX, QB, ESX) and registers the callback accordingly.
--- It adapts the callback function to match the expected signature for the framework. --- It adapts the callback function to match the expected signature for the framework.
--- ---
---@param callbackName string The name of the callback to register. ---@param callbackName string The name of the callback to register.
---@param funct function The function to be called when the callback is triggered. ---@param funct function The function to be called when the callback is triggered.
--- ---
---@usage ---@usage
--- ```lua --- ```lua
--- createCallback('myCallback', function(source, ...) --- createCallback('myCallback', function(source, ...)
--- -- Your callback code here --- -- Your callback code here
--- end) --- end)
--- ``` --- ```
function createCallback(callbackName, funct) function createCallback(callbackName, funct)
if isStarted(OXLibExport) then if isStarted(OXLibExport) then
lib.callback.register(callbackName, funct) lib.callback.register(callbackName, funct)
else else
local adaptedFunction = function(source, cb, ...) local adaptedFunction = function(source, cb, ...)
local result = funct(source, ...) local result = funct(source, ...)
cb(result) cb(result)
end end
if isStarted(QBExport) then if isStarted(QBExport) then
Core = Core or exports[QBExport]:GetCoreObject() Core = Core or exports[QBExport]:GetCoreObject()
Core.Functions.CreateCallback(callbackName, adaptedFunction) Core.Functions.CreateCallback(callbackName, adaptedFunction)
elseif isStarted(ESXExport) then elseif isStarted(ESXExport) then
ESX.RegisterServerCallback(callbackName, adaptedFunction) ESX.RegisterServerCallback(callbackName, adaptedFunction)
else else
print("^6Bridge^7: ^1ERROR^7: ^3Can't find any script to register callback with", callbackName) print("^6Bridge^7: ^1ERROR^7: ^3Can't find any script to register callback with", callbackName)
end end
end end
end end
--- Triggers a server callback and returns the result. --- Triggers a server callback and returns the result.
--- ---
--- This function triggers a server callback using the appropriate framework's method and awaits the result. --- This function triggers a server callback using the appropriate framework's method and awaits the result.
--- ---
---@param callbackName string The name of the callback to trigger. ---@param callbackName string The name of the callback to trigger.
---@param ... any Additional arguments to pass to the callback. ---@param ... any Additional arguments to pass to the callback.
--- ---
---@return any any The result returned by the callback function. ---@return any any The result returned by the callback function.
--- ---
---@usage ---@usage
--- ```lua --- ```lua
--- local result = triggerCallback('myCallback', arg1, arg2) --- local result = triggerCallback('myCallback', arg1, arg2)
--- ``` --- ```
function triggerCallback(callbackName, ...) function triggerCallback(callbackName, ...)
local result = nil local result = nil
if isStarted(OXLibExport) then if isStarted(OXLibExport) then
result = lib.callback.await(callbackName, false, ...) result = lib.callback.await(callbackName, false, ...)
elseif isStarted(QBExport) then elseif isStarted(QBExport) then
local p = promise.new() local p = promise.new()
Core.Functions.TriggerCallback(callbackName, function(cbResult) Core.Functions.TriggerCallback(callbackName, function(cbResult)
p:resolve(cbResult) p:resolve(cbResult)
end, ...) end, ...)
result = Citizen.Await(p) result = Citizen.Await(p)
elseif isStarted(ESXExport) then elseif isStarted(ESXExport) then
local p = promise.new() local p = promise.new()
ESX.TriggerServerCallback(callbackName, function(cbResult) ESX.TriggerServerCallback(callbackName, function(cbResult)
p:resolve(cbResult) p:resolve(cbResult)
end, ...) end, ...)
result = Citizen.Await(p) result = Citizen.Await(p)
else else
print("^6Bridge^7: ^1ERROR^7: ^3Can't find any script to trigger callback with", callbackName) print("^6Bridge^7: ^1ERROR^7: ^3Can't find any script to trigger callback with", callbackName)
end end
return result return result
end end

View File

@@ -1,290 +1,290 @@
--- Opens a menu using the configured menu system. --- Opens a menu using the configured menu system.
--- ---
--- This function translates code and creates menus in several different menu scripts, depending on the configured menu system specified in `Config.System.Menu`. --- This function translates code and creates menus in several different menu scripts, depending on the configured menu system specified in `Config.System.Menu`.
--- ---
---@param Menu table A table containing the menu options to display. ---@param Menu table A table containing the menu options to display.
--- Each menu item can include: --- Each menu item can include:
--- - **header** (`string`): The text to display for the menu item. --- - **header** (`string`): The text to display for the menu item.
--- - **txt** (`string`, optional): Additional text or description. --- - **txt** (`string`, optional): Additional text or description.
--- - **icon** (`string`, optional): Icon to display with the menu item. --- - **icon** (`string`, optional): Icon to display with the menu item.
--- - **onSelect** (`function`, optional): Function to execute when the menu item is selected. --- - **onSelect** (`function`, optional): Function to execute when the menu item is selected.
--- - **arrow** (`boolean`, optional): Whether to display an arrow next to the item (for certain menus). --- - **arrow** (`boolean`, optional): Whether to display an arrow next to the item (for certain menus).
--- - **params** (`table`, optional): Additional parameters, such as events and arguments. --- - **params** (`table`, optional): Additional parameters, such as events and arguments.
--- - **isMenuHeader** (`boolean`, optional): Marks the item as a header. --- - **isMenuHeader** (`boolean`, optional): Marks the item as a header.
--- - **disabled** (`boolean`, optional): Disables the menu item if `true`. --- - **disabled** (`boolean`, optional): Disables the menu item if `true`.
--- ---
---@param data table A table containing configuration data for the menu. ---@param data table A table containing configuration data for the menu.
--- - **header** (`string`): The header/title of the menu. --- - **header** (`string`): The header/title of the menu.
--- - **headertxt** (`string`, optional): Additional header text. --- - **headertxt** (`string`, optional): Additional header text.
--- - **onBack** (`function`, optional): Function to call when the "Return" option is selected. --- - **onBack** (`function`, optional): Function to call when the "Return" option is selected.
--- - **onExit** (`function`, optional): Function to call when the menu is exited. --- - **onExit** (`function`, optional): Function to call when the menu is exited.
--- - **onSelected** (`function`, optional): Function to call when a menu item is selected (for certain menu systems). --- - **onSelected** (`function`, optional): Function to call when a menu item is selected (for certain menu systems).
--- - **canClose** (`boolean`, optional): Whether the menu can be closed by the user. --- - **canClose** (`boolean`, optional): Whether the menu can be closed by the user.
--- ---
---@usage ---@usage
--- ```lua --- ```lua
--- openMenu({ --- openMenu({
--- { header = "Option 1", txt = "Description 1", onSelect = function() print("Option 1 selected") end }, --- { header = "Option 1", txt = "Description 1", onSelect = function() print("Option 1 selected") end },
--- { header = "Option 2", txt = "Description 2", onSelect = function() print("Option 2 selected") end }, --- { header = "Option 2", txt = "Description 2", onSelect = function() print("Option 2 selected") end },
--- }, { --- }, {
--- header = "Main Menu", --- header = "Main Menu",
--- headertxt = "Select an option", --- headertxt = "Select an option",
--- onBack = function() print("Return selected") end, --- onBack = function() print("Return selected") end,
--- onExit = function() print("Menu closed") end, --- onExit = function() print("Menu closed") end,
--- canClose = true, --- canClose = true,
--- }) --- })
--- ``` --- ```
function openMenu(Menu, data) function openMenu(Menu, data)
if Config.System.Menu == "jim" then if Config.System.Menu == "jim" then
if data.onBack then if data.onBack then
table.insert(Menu, 1, { table.insert(Menu, 1, {
icon = "fas fa-circle-arrow-left", icon = "fas fa-circle-arrow-left",
title = "Return", title = "Return",
onSelect = data.onBack, onSelect = data.onBack,
}) })
end end
exports["jim-nui"]:openMenu({ exports["jim-nui"]:openMenu({
title = data.header..(data.headertxt and " -- "..data.headertxt or ""), title = data.header..(data.headertxt and " -- "..data.headertxt or ""),
canClose = data.canClose and data.canClose or nil, canClose = data.canClose and data.canClose or nil,
onClose = (data.onBack and data.onBack) or (data.onExit and data.onExit) or nil, onClose = (data.onBack and data.onBack) or (data.onExit and data.onExit) or nil,
onExit = data.onExit and data.onExit or nil, onExit = data.onExit and data.onExit or nil,
options = Menu, options = Menu,
}) })
elseif Config.System.Menu == "ox" then elseif Config.System.Menu == "ox" then
local index = nil local index = nil
if data.onBack and not data.onSelected then if data.onBack and not data.onSelected then
table.insert(Menu, 1, { table.insert(Menu, 1, {
icon = "fas fa-circle-arrow-left", icon = "fas fa-circle-arrow-left",
title = "Return", title = "Return",
onSelect = data.onBack, onSelect = data.onBack,
label = "Return", label = "Return",
}) })
end end
for k in pairs(Menu) do for k in pairs(Menu) do
if data.onSelected and Menu[k].arrow then if data.onSelected and Menu[k].arrow then
Menu[k].icon = "fas fa-angle-right" Menu[k].icon = "fas fa-angle-right"
end end
if not Menu[k].title then if not Menu[k].title then
if Menu[k].header ~= nil and Menu[k].header ~= "" then if Menu[k].header ~= nil and Menu[k].header ~= "" then
Menu[k].title = Menu[k].header Menu[k].title = Menu[k].header
Menu[k].label = Menu[k].header Menu[k].label = Menu[k].header
if Menu[k].txt then Menu[k].description = Menu[k].txt else Menu[k].description = "" end if Menu[k].txt then Menu[k].description = Menu[k].txt else Menu[k].description = "" end
else else
Menu[k].title = Menu[k].txt Menu[k].title = Menu[k].txt
Menu[k].label = Menu[k].txt Menu[k].label = Menu[k].txt
end end
end end
if Menu[k].params then if Menu[k].params then
Menu[k].event = Menu[k].params.event Menu[k].event = Menu[k].params.event
Menu[k].args = Menu[k].params.args or {} Menu[k].args = Menu[k].params.args or {}
end end
if Menu[k].isMenuHeader then if Menu[k].isMenuHeader then
Menu[k].disabled = true Menu[k].disabled = true
end end
end end
local menuID = 'Menu' local menuID = 'Menu'
(data.onSelected and lib.registerMenu or lib.registerContext)({ (data.onSelected and lib.registerMenu or lib.registerContext)({
id = menuID, id = menuID,
title = data.header..br..br..(data.headertxt and data.headertxt or ""), title = data.header..br..br..(data.headertxt and data.headertxt or ""),
position = 'top-right', position = 'top-right',
options = Menu, options = Menu,
canClose = data.canClose and data.canClose or nil, canClose = data.canClose and data.canClose or nil,
onClose = (data.onBack and data.onBack) or (data.onExit and data.onExit) or nil, onClose = (data.onBack and data.onBack) or (data.onExit and data.onExit) or nil,
onExit = data.onExit and data.onExit or nil, onExit = data.onExit and data.onExit or nil,
onSelected = data.onSelected and (function(selected) index = selected end) or nil, onSelected = data.onSelected and (function(selected) index = selected end) or nil,
}, data.onSelected and (function(x, y, args) }, data.onSelected and (function(x, y, args)
if Menu[x].refresh then if Menu[x].refresh then
if Menu[x].onSelect then if Menu[x].onSelect then
Menu[x].onSelect() Menu[x].onSelect()
end end
lib.showMenu(menuID, index) lib.showMenu(menuID, index)
else else
if Menu[x].onSelect then if Menu[x].onSelect then
Menu[x].onSelect() Menu[x].onSelect()
else else
lib.showMenu(menuID, index) lib.showMenu(menuID, index)
end end
end end
end) or nil) end) or nil)
if data.onSelected then if data.onSelected then
lib.showMenu(menuID, 1) lib.showMenu(menuID, 1)
else else
lib.showContext(menuID) lib.showContext(menuID)
end end
elseif Config.System.Menu == "qb" then elseif Config.System.Menu == "qb" then
if data.onBack then if data.onBack then
table.insert(Menu, 1, { table.insert(Menu, 1, {
icon = "fas fa-circle-arrow-left", icon = "fas fa-circle-arrow-left",
header = " ", header = " ",
txt = "Return", txt = "Return",
params = { params = {
isAction = true, isAction = true,
event = data.onBack, event = data.onBack,
}, },
}) })
elseif data.canClose then elseif data.canClose then
table.insert(Menu, 1, { table.insert(Menu, 1, {
icon = "fas fa-circle-xmark", icon = "fas fa-circle-xmark",
header = " ", header = " ",
txt = "Close", txt = "Close",
params = { params = {
isAction = true, isAction = true,
event = data.onExit and data.onExit or (function() exports[QBMenuExport]:closeMenu() end), event = data.onExit and data.onExit or (function() exports[QBMenuExport]:closeMenu() end),
}, },
}) })
end end
if data.header ~= nil then if data.header ~= nil then
local tempMenu = {} local tempMenu = {}
for k, v in pairs(Menu) do tempMenu[k + 1] = v end for k, v in pairs(Menu) do tempMenu[k + 1] = v end
tempMenu[1] = { header = data.header, txt = data.headertxt or "", isMenuHeader = true } tempMenu[1] = { header = data.header, txt = data.headertxt or "", isMenuHeader = true }
Menu = tempMenu Menu = tempMenu
end end
for k in pairs(Menu) do for k in pairs(Menu) do
if not Menu[k].params or not Menu[k].params.event then if not Menu[k].params or not Menu[k].params.event then
if Menu[k].onSelect then if Menu[k].onSelect then
Menu[k].params = { Menu[k].params = {
isAction = true, isAction = true,
event = Menu[k].onSelect, event = Menu[k].onSelect,
} }
else else
Menu[k].params = { Menu[k].params = {
isAction = true, isAction = true,
event = function() end, event = function() end,
} }
end end
end end
if not Menu[k].header then Menu[k].header = " " end if not Menu[k].header then Menu[k].header = " " end
if Menu[k].arrow then Menu[k].icon = "fas fa-angle-right" end if Menu[k].arrow then Menu[k].icon = "fas fa-angle-right" end
end end
exports[QBMenuExport]:openMenu(Menu) exports[QBMenuExport]:openMenu(Menu)
elseif Config.System.Menu == "gta" then elseif Config.System.Menu == "gta" then
WarMenu.CreateMenu(tostring(Menu), WarMenu.CreateMenu(tostring(Menu),
data.header, data.header,
data.headertxt or " ", data.headertxt or " ",
{ {
titleColor = { 222, 255, 255 }, titleColor = { 222, 255, 255 },
maxOptionCountOnScreen = 15, maxOptionCountOnScreen = 15,
width = 0.25, width = 0.25,
x = 0.7, x = 0.7,
}) })
if WarMenu.IsAnyMenuOpened() then return end if WarMenu.IsAnyMenuOpened() then return end
WarMenu.OpenMenu(tostring(Menu)) WarMenu.OpenMenu(tostring(Menu))
CreateThread(function() CreateThread(function()
local close = true local close = true
while true do while true do
if WarMenu.Begin(tostring(Menu)) then if WarMenu.Begin(tostring(Menu)) then
if data.onBack then if data.onBack then
if WarMenu.SpriteButton("Return", 'commonmenu', "arrowleft", 127, 127, 127) then if WarMenu.SpriteButton("Return", 'commonmenu', "arrowleft", 127, 127, 127) then
WarMenu.CloseMenu() WarMenu.CloseMenu()
Wait(10) Wait(10)
data.onBack() data.onBack()
end end
end end
for k in pairs(Menu) do for k in pairs(Menu) do
local pressed = WarMenu.Button(Menu[k].header) local pressed = WarMenu.Button(Menu[k].header)
if not Menu[k].header then if not Menu[k].header then
Menu[k].header = Menu[k].txt Menu[k].header = Menu[k].txt
Menu[k].txt = nil Menu[k].txt = nil
end end
if Menu[k].txt and Menu[k].txt ~= "" and WarMenu.IsItemHovered() then if Menu[k].txt and Menu[k].txt ~= "" and WarMenu.IsItemHovered() then
if Menu[k].disabled or Menu[k].isMenuHeader then if Menu[k].disabled or Menu[k].isMenuHeader then
WarMenu.ToolTip("~r~"..Menu[k].txt, 0.18, true) WarMenu.ToolTip("~r~"..Menu[k].txt, 0.18, true)
else else
WarMenu.ToolTip( WarMenu.ToolTip(
(Menu[k].blip and "~BLIP_".."8".."~ " or "").. (Menu[k].blip and "~BLIP_".."8".."~ " or "")..
Menu[k].txt:gsub("%:", ":~g~"):gsub("%\n", "\n~s~"), 0.18, Menu[k].txt:gsub("%:", ":~g~"):gsub("%\n", "\n~s~"), 0.18,
true) true)
end end
end end
if pressed and not Menu[k].isMenuHeader then if pressed and not Menu[k].isMenuHeader then
WarMenu.CloseMenu() WarMenu.CloseMenu()
close = false close = false
Menu[k].onSelect() Menu[k].onSelect()
end end
end end
WarMenu.End() WarMenu.End()
else else
return return
end end
if not WarMenu.IsAnyMenuOpened() and close then if not WarMenu.IsAnyMenuOpened() and close then
stopTempCam(cam) stopTempCam(cam)
if data.onExit then data.onExit() end if data.onExit then data.onExit() end
end end
Wait(0) Wait(0)
end end
end) end)
elseif Config.System.Menu == "esx" then elseif Config.System.Menu == "esx" then
for k in pairs(Menu) do for k in pairs(Menu) do
Menu[k].label = Menu[k].header Menu[k].label = Menu[k].header
Menu[k].name = "button"..k Menu[k].name = "button"..k
end end
if data.canClose then if data.canClose then
table.insert(Menu, 1, { table.insert(Menu, 1, {
icon = "fas fa-circle-xmark", icon = "fas fa-circle-xmark",
label = "Close", label = "Close",
name = "close", name = "close",
onSelect = data.onExit, onSelect = data.onExit,
}) })
end end
if data.onBack then if data.onBack then
table.insert(Menu, 1, { table.insert(Menu, 1, {
icon = "fas fa-circle-arrow-left", icon = "fas fa-circle-arrow-left",
label = "Return", label = "Return",
name = "return", name = "return",
onSelect = data.onBack, onSelect = data.onBack,
}) })
end end
ESX.UI.Menu.Open("default", getScript(), "Example_Menu", { ESX.UI.Menu.Open("default", getScript(), "Example_Menu", {
title = data.header, title = data.header,
align = 'top-right', align = 'top-right',
elements = Menu, elements = Menu,
}, },
function(menuData, menu) function(menuData, menu)
for k in pairs(Menu) do for k in pairs(Menu) do
if menuData.current.name == Menu[k].name then if menuData.current.name == Menu[k].name then
menu.close() menu.close()
Wait(10) Wait(10)
Menu[k].onSelect() Menu[k].onSelect()
end end
end end
end, end,
function(data, menu) function(data, menu)
menu.close() menu.close()
end) end)
end end
end end
--- A line break constant used for formatting menu headers. --- A line break constant used for formatting menu headers.
br = (Config.System.Menu == "ox" or Config.System.Menu == "gta") and "\n" or "<br>" br = (Config.System.Menu == "ox" or Config.System.Menu == "gta") and "\n" or "<br>"
--- Checks if the menu system is classified as 'ox' or 'gta'. --- Checks if the menu system is classified as 'ox' or 'gta'.
--- ---
--- This function is used to decide how to make line breaks in menu headers. --- This function is used to decide how to make line breaks in menu headers.
--- ---
--- @return boolean Returns `true` if the menu system is 'ox' or 'gta'; otherwise, `false`. --- @return boolean Returns `true` if the menu system is 'ox' or 'gta'; otherwise, `false`.
--- ---
--- @usage --- @usage
--- ```lua --- ```lua
--- if isOx() then --- if isOx() then
--- -- Use specific formatting --- -- Use specific formatting
--- end --- end
--- ``` --- ```
function isOx() return (Config.System.Menu == "ox" or Config.System.Menu == "gta") end function isOx() return (Config.System.Menu == "ox" or Config.System.Menu == "gta") end
--- Checks if any WarMenu menu is currently open. --- Checks if any WarMenu menu is currently open.
--- ---
--- @return boolean Returns `true` if a WarMenu menu is open; otherwise, `false`. --- @return boolean Returns `true` if a WarMenu menu is open; otherwise, `false`.
--- ---
--- @usage --- @usage
--- ```lua --- ```lua
--- if isWarMenuOpen() then --- if isWarMenuOpen() then
--- -- Do something --- -- Do something
--- end --- end
--- ``` --- ```
function isWarMenuOpen() if Config.System.Menu == "gta" then return WarMenu.IsAnyMenuOpened() else return false end end function isWarMenuOpen() if Config.System.Menu == "gta" then return WarMenu.IsAnyMenuOpened() else return false end end

View File

@@ -1,170 +1,197 @@
-- Create empty Variables -- -- Create empty Variables --
Items, Vehicles, Jobs, Gangs, Core, ESX = {}, nil, nil, nil, nil, nil Items, Vehicles, Jobs, Gangs, Core, ESX = {}, nil, nil, nil, nil, nil
-- Correct QB inventory export (if needed) from 'qb-inventory' to 'ps-inventory' or 'lj-inventory' -- -- Correct QB inventory export (if needed) from 'qb-inventory' to 'ps-inventory' or 'lj-inventory' --
Exports.QBInv = (isStarted("ps-inventory") and "ps-inventory") or (isStarted("lj-inventory") and "lj-inventory") or Exports.QBInv Exports.QBInv = (isStarted("ps-inventory") and "ps-inventory") or (isStarted("lj-inventory") and "lj-inventory") or Exports.QBInv
-- Create simple variables based on the corresponding framework exports -- -- Create simple variables based on the corresponding framework exports --
OXLibExport, QBXExport, QBExport, ESXExport, OXCoreExport = Exports.OXLibExport or "", Exports.QBXExport or "", Exports.QBExport or "", Exports.ESXExport or "", Exports.OXCoreExport or "" OXLibExport, QBXExport, QBExport, ESXExport, OXCoreExport = Exports.OXLibExport or "", Exports.QBXExport or "", Exports.QBExport or "", Exports.ESXExport or "", Exports.OXCoreExport or ""
-- Create simple variables based on the corresponding inventory names -- -- Create simple variables based on the corresponding inventory names --
OXInv, QBInv, PSInv, QSInv, CoreInv, CodeMInv, OrigenInv = Exports.OXInv or "", Exports.QBInv or "", Exports.PSInv or "", Exports.QSInv or "", Exports.CoreInv or "", Exports.CodeMInv or "", Exports.OrigenInv or "" OXInv, QBInv, PSInv, QSInv, CoreInv, CodeMInv, OrigenInv = Exports.OXInv or "", Exports.QBInv or "", Exports.PSInv or "", Exports.QSInv or "", Exports.CoreInv or "", Exports.CodeMInv or "", Exports.OrigenInv or ""
-- QB-Menu export name grabbed from exports.lua -- -- QB-Menu export name grabbed from exports.lua --
QBMenuExport = Exports.QBMenuExport or "" QBMenuExport = Exports.QBMenuExport or ""
-- Target exports based on what is loaded -- -- Target exports based on what is loaded --
QBTargetExport, OXTargetExport = Exports.QBTargetExport or "", Exports.OXTargetExport or "" QBTargetExport, OXTargetExport = Exports.QBTargetExport or "", Exports.OXTargetExport or ""
-- If Debug mode is on in the loading script, print the list of found exports -- -- If Debug mode is on in the loading script, print the list of found exports --
-- Some may "lie", 'ox_target' attempts to use 'qb-target' exports and this print will say its loaded (which is technically true) -- -- Some may "lie", 'ox_target' attempts to use 'qb-target' exports and this print will say its loaded (which is technically true) --
for _, v in pairs(Exports) do for _, v in pairs(Exports) do
if isStarted(v) then debugPrint("^6Bridge^7: '^3"..v.."^7' ^2export found ^7") end if isStarted(v) then debugPrint("^6Bridge^7: '^3"..v.."^7' ^2export found ^7") end
end end
local itemResource, jobResource, vehResource = "", "", "" local itemResource, jobResource, vehResource = "", "", ""
-- Load item lists -- -- Load item lists --
-- Complies the items from ox_inventory, qb-core or esx into 'Items' and loads them in a layout similar to qb-core's Shared items.lua -- -- Complies the items from ox_inventory, qb-core or esx into 'Items' and loads them in a layout similar to qb-core's Shared items.lua --
-- For example this makes it so instead of QBCore.Shared.Items[item], you can load 'Item[item]' in the script -- -- For example this makes it so instead of QBCore.Shared.Items[item], you can load 'Item[item]' in the script --
if isStarted(OXInv) then itemResource = OXInv if isStarted(OXInv) then
Items = exports[OXInv]:Items() itemResource = OXInv
for k, v in pairs(Items) do Items = exports[OXInv]:Items()
if v.client and v.client.image then for k, v in pairs(Items) do
Items[k].image = (v.client.image):gsub("nui://"..OXInv.."/web/images/", "") if v.client and v.client.image then
else Items[k].image = (v.client.image):gsub("nui://"..OXInv.."/web/images/", "")
Items[k].image = k..".png" else
end Items[k].image = k..".png"
Items[k].hunger = v.client and v.client.hunger or nil end
Items[k].thirst = v.client and v.client.thirst or nil Items[k].hunger = v.client and v.client.hunger or nil
end Items[k].thirst = v.client and v.client.thirst or nil
end
elseif isStarted(QBExport) then itemResource = QBExport
Core = Core or exports[QBExport]:GetCoreObject() elseif isStarted(QBExport) then
Items = Core and Core.Shared.Items or nil itemResource = QBExport
if isStarted(QBExport) and not isStarted(QBXExport) then Core = Core or exports[QBExport]:GetCoreObject()
RegisterNetEvent('QBCore:Client:UpdateObject', function() Items = Core and Core.Shared.Items or nil
Core = Core or exports[QBExport]:GetCoreObject() if isStarted(QBExport) and not isStarted(QBXExport) then
Items = Core and Core.Shared.Items or nil RegisterNetEvent('QBCore:Client:UpdateObject', function()
end) Core = Core or exports[QBExport]:GetCoreObject()
end Items = Core and Core.Shared.Items or nil
end)
elseif isStarted(ESXExport) then itemResource = ESXExport end
ESX = exports[ESXExport]:getSharedObject()
Items = ESX and ESX.Items or nil elseif isStarted(ESXExport) then
end itemResource = ESXExport
-- If it fails to load items, then it will print the error below -- ESX = exports[ESXExport]:getSharedObject()
-- If it loads them and debug is on, print how many items and where from -- --Items = ESX and ESX.Items or nil
if not Items then while ESX == nil do
print("^4ERROR^7: ^2No Core Items detected ^7- ^2Check ^3exports^1.^2lua^7") print("Waiting for ESX")
else Wait(0)
debugPrint("^6Bridge^7: ^2Loading ^6"..countTable(Items).." ^3Items^2 from ^7" .. itemResource) end
end if isServer() then
Items = ESX.GetItems()
-- Load Vehicles -- debugPrint("^6Bridge^7: ^2Loading ^6"..countTable(Items).." ^3Items^2 from ^7" .. itemResource)
-- Complies the vehicles from the detected frameworks into a table in the style of qb-cores shared vehicles.lua -- end
-- For example, instead of using QBCore.Shared.Vehicles[vehicle] you can load 'Vehicles[vehicle]' in the script -- CreateThread(function()
if isStarted(QBXExport) or isStarted(QBExport) then while not ESX do Wait(0) end
Core = Core or exports[QBExport]:GetCoreObject() if isServer() then
Vehicles = Core and Core.Shared.Vehicles createCallback(getScript()..":getItems", function(source)
if isStarted(QBExport) and not isStarted(QBXExport) then return Items
RegisterNetEvent('QBCore:Client:UpdateObject', function() end)
Core = Core or exports[QBExport]:GetCoreObject() end
Vehicles = Core and Core.Shared.Vehicles if not isServer() then
end) Items = triggerCallback(getScript()..":getItems")
end debugPrint("^6Bridge^7: ^2Loading ^6"..countTable(Items).." ^3Items^2 from ^7" .. itemResource)
vehResource = QBExport end
elseif isStarted(OXCoreExport) then end)
Vehicles = {}
for k, v in pairs(Ox.GetVehicleData()) do
Vehicles[k] = { model = k, price = v.price, name = v.name, brand = v.make } end
end -- If it fails to load items, then it will print the error below --
vehResource = OXCoreExport -- If it loads them and debug is on, print how many items and where from --
elseif isStarted(ESXExport) then if not isStarted(ESXExport) then
-- print("^6Bridge^7: ^2Loading ^3Vehicles^2 from ^7"..ESXExport) if not Items then
-- print("^6Bridge^7: ^2Loading ^6"..countTable(Vehicles).." ^3Vehicles^2 from ^7"..ESXExport) print("^4ERROR^7: ^2No Core Items detected ^7- ^2Check ^3exports^1.^2lua^7")
CreateThread(function() else
if isServer() then debugPrint("^6Bridge^7: ^2Loading ^6"..countTable(Items).." ^3Items^2 from ^7" .. itemResource)
createCallback(getScript()..":getVehiclesPrices", function(source) end
Vehicles = MySQL.query.await('SELECT model, price, name FROM vehicles') end
vehResource = ESXExport
return Vehicles -- Load Vehicles --
end) -- Complies the vehicles from the detected frameworks into a table in the style of qb-cores shared vehicles.lua --
end -- For example, instead of using QBCore.Shared.Vehicles[vehicle] you can load 'Vehicles[vehicle]' in the script --
if not isServer() then if isStarted(QBXExport) or isStarted(QBExport) then
local TempVehicles = triggerCallback(getScript()..":getVehiclesPrices") Core = Core or exports[QBExport]:GetCoreObject()
for _, v in pairs(TempVehicles) do Vehicles = Core and Core.Shared.Vehicles
Vehicles = Vehicles or {} if isStarted(QBExport) and not isStarted(QBXExport) then
Vehicles[v.model] = { model = v.model, price = v.price, name = v.name, brand = GetMakeNameFromVehicleModel(v.model):lower():gsub("^%l", string.upper) } RegisterNetEvent('QBCore:Client:UpdateObject', function()
end Core = Core or exports[QBExport]:GetCoreObject()
end Vehicles = Core and Core.Shared.Vehicles
end) end)
end end
if vehResource == nil then vehResource = QBExport
print("^4ERROR^7: ^2No Vehicle info detected ^7- ^2Check ^3exports^1.^2lua^7") elseif isStarted(OXCoreExport) then
else Vehicles = {}
debugPrint("^6Bridge^7: ^2Loading ^6"..countTable(Vehicles).." ^3Vehicles^2 from ^7"..vehResource) for k, v in pairs(Ox.GetVehicleData()) do
end Vehicles[k] = { model = k, price = v.price, name = v.name, brand = v.make }
end
-- Load Jobs -- vehResource = OXCoreExport
-- Attempts to load the details of jobs and gangs and compile into tables -- elseif isStarted(ESXExport) then
-- For example, instead of using QBCore.Shared.Jobs[job] you can load 'Jobs[job]' in the script -- -- print("^6Bridge^7: ^2Loading ^3Vehicles^2 from ^7"..ESXExport)
if isStarted(QBXExport) then jobResource = QBXExport -- print("^6Bridge^7: ^2Loading ^6"..countTable(Vehicles).." ^3Vehicles^2 from ^7"..ESXExport)
Core = Core or exports[QBExport]:GetCoreObject() CreateThread(function()
Jobs, Gangs = exports[QBXExport]:GetJobs(), exports[QBXExport]:GetGangs() if isServer() then
createCallback(getScript()..":getVehiclesPrices", function(source)
elseif isStarted(OXCoreExport) then jobResource = OXExport Vehicles = MySQL.query.await('SELECT model, price, name FROM vehicles')
CreateThread(function() vehResource = ESXExport
if isServer() then return Vehicles
createCallback(getScript()..":getOxGroups", function(source) end)
Jobs = MySQL.query.await('SELECT * FROM `ox_groups`') return Jobs end
end) if not isServer() then
else local TempVehicles = triggerCallback(getScript()..":getVehiclesPrices")
local TempJobs = triggerCallback(getScript()..":getOxGroups") for _, v in pairs(TempVehicles) do
Jobs = TempJobs or {} Vehicles = Vehicles or {}
for k, v in pairs(TempJobs) do Vehicles[v.model] = { model = v.model, price = v.price, name = v.name, brand = GetMakeNameFromVehicleModel(v.model):lower():gsub("^%l", string.upper) }
local grades = {} end
for i = 1, #v.grades do grades[i] = { name = v.grades[i], isboss = (i == #v.grades)} end end
Jobs[v.name] = { label = v.label, grades = grades } end)
end end
Gangs = Jobs if vehResource == nil then
end print("^4ERROR^7: ^2No Vehicle info detected ^7- ^2Check ^3exports^1.^2lua^7")
end) else
debugPrint("^6Bridge^7: ^2Loading ^6"..countTable(Vehicles).." ^3Vehicles^2 from ^7"..vehResource)
elseif isStarted(QBExport) then jobResource = QBExport end
Core = Core or exports[QBExport]:GetCoreObject()
Jobs, Gangs = Core.Shared.Jobs, Core.Shared.Gangs -- Load Jobs --
if isStarted(QBExport) and not isStarted(QBXExport) then -- Attempts to load the details of jobs and gangs and compile into tables --
RegisterNetEvent('QBCore:Client:UpdateObject', function() -- For example, instead of using QBCore.Shared.Jobs[job] you can load 'Jobs[job]' in the script --
Core = exports[QBExport]:GetCoreObject() if isStarted(QBXExport) then jobResource = QBXExport
Jobs, Gangs = Core.Shared.Jobs, Core.Shared.Gangs Core = Core or exports[QBExport]:GetCoreObject()
end) Jobs, Gangs = exports[QBXExport]:GetJobs(), exports[QBXExport]:GetGangs()
end
elseif isStarted(OXCoreExport) then jobResource = OXExport
elseif isStarted(ESXExport) then CreateThread(function()
--print("^6Bridge^7: ^2Loading ^3Jobs^7/^3Gangs^2 from ^7"..ESXExport) if isServer() then
ESX = exports[ESXExport]:getSharedObject() createCallback(getScript()..":getOxGroups", function(source)
if isServer() then Jobs = MySQL.query.await('SELECT * FROM `ox_groups`') return Jobs
Jobs = ESX.GetJobs() end)
for k, v in pairs(Jobs) do else
local count = countTable(Jobs[k].grades)-1 local TempJobs = triggerCallback(getScript()..":getOxGroups")
Jobs[k].grades[tostring(count)].isBoss = true Jobs = TempJobs or {}
end for k, v in pairs(TempJobs) do
Gangs = Jobs local grades = {}
end for i = 1, #v.grades do grades[i] = { name = v.grades[i], isboss = (i == #v.grades)} end
CreateThread(function() Jobs[v.name] = { label = v.label, grades = grades }
while not ESX do Wait(0) end end
if isServer() then Gangs = Jobs
createCallback(getScript()..":getJobs", function(source) end
return Jobs end)
end)
end elseif isStarted(QBExport) then jobResource = QBExport
if not isServer() then Core = Core or exports[QBExport]:GetCoreObject()
Jobs = triggerCallback(getScript()..":getJobs") Jobs, Gangs = Core.Shared.Jobs, Core.Shared.Gangs
Gangs = Jobs if isStarted(QBExport) and not isStarted(QBXExport) then
end RegisterNetEvent('QBCore:Client:UpdateObject', function()
end) Core = exports[QBExport]:GetCoreObject()
end Jobs, Gangs = Core.Shared.Jobs, Core.Shared.Gangs
if not isStarted(ESXExport) and Jobs then end)
debugPrint("^6Bridge^7: ^2Loading ^6"..countTable(Jobs).." ^3Jobs^2 from ^7"..jobResource, "^6Bridge^7: ^2Loading ^6"..countTable(Gangs).." ^3Gangs^2 from ^7"..jobResource) end
elseif isStarted(ESXExport) then
--print("^6Bridge^7: ^2Loading ^3Jobs^7/^3Gangs^2 from ^7"..ESXExport)
ESX = exports[ESXExport]:getSharedObject()
if isServer() then
Jobs = ESX.GetJobs()
for k, v in pairs(Jobs) do
local count = countTable(Jobs[k].grades)-1
Jobs[k].grades[tostring(count)].isBoss = true
end
Gangs = Jobs
end
CreateThread(function()
while not ESX do Wait(0) end
if isServer() then
createCallback(getScript()..":getJobs", function(source)
return Jobs
end)
end
if not isServer() then
Jobs = triggerCallback(getScript()..":getJobs")
Gangs = Jobs
end
end)
end
if not isStarted(ESXExport) and Jobs then
debugPrint("^6Bridge^7: ^2Loading ^6"..countTable(Jobs).." ^3Jobs^2 from ^7"..jobResource, "^6Bridge^7: ^2Loading ^6"..countTable(Gangs).." ^3Gangs^2 from ^7"..jobResource)
end end

View File

@@ -1,481 +1,481 @@
local CraftLock = false local CraftLock = false
--- Opens a crafting menu based on the provided data. --- Opens a crafting menu based on the provided data.
--- ---
--- This function checks job requirements, prepares the menu options, and opens the crafting menu. --- This function checks job requirements, prepares the menu options, and opens the crafting menu.
--- It handles item availability, crafting recipes, and displays appropriate icons and labels. --- It handles item availability, crafting recipes, and displays appropriate icons and labels.
--- ---
---@param data table A table containing crafting menu data. ---@param data table A table containing crafting menu data.
--- - **craftable** (`table`): The crafting options and settings. --- - **craftable** (`table`): The crafting options and settings.
--- - **Header** (`string`): The header/title of the crafting menu. --- - **Header** (`string`): The header/title of the crafting menu.
--- - **Recipes** (`table`): A list of crafting recipes. --- - **Recipes** (`table`): A list of crafting recipes.
--- - **coords** (`vector3`): The coordinates where the crafting menu is being opened. --- - **coords** (`vector3`): The coordinates where the crafting menu is being opened.
--- - **stashTable** (`string` or `table`, optional): The stash name(s) to check for item availability. --- - **stashTable** (`string` or `table`, optional): The stash name(s) to check for item availability.
--- - **stashName** (`string` or `table`, optional): Alias for `stashTable`. --- - **stashName** (`string` or `table`, optional): Alias for `stashTable`.
--- - **job** (`string` or `table`, optional): Job(s) required to access the crafting menu. --- - **job** (`string` or `table`, optional): Job(s) required to access the crafting menu.
--- - **gang** (`string` or `table`, optional): Gang(s) required to access the crafting menu. --- - **gang** (`string` or `table`, optional): Gang(s) required to access the crafting menu.
--- - **onBack** (`function`, optional): Function to call when returning from the menu. --- - **onBack** (`function`, optional): Function to call when returning from the menu.
--- ---
---@usage ---@usage
--- ```lua --- ```lua
--- craftingMenu({ --- craftingMenu({
--- craftable = { --- craftable = {
--- Header = "Weapon Crafting", --- Header = "Weapon Crafting",
--- Recipes = { --- Recipes = {
--- [1] = { --- [1] = {
--- ["weapon_pistol"] = { ["steel"] = 5, ["plastic"] = 2 }, --- ["weapon_pistol"] = { ["steel"] = 5, ["plastic"] = 2 },
--- amount = 1, --- amount = 1,
--- }, --- },
--- -- More recipes... --- -- More recipes...
--- }, --- },
--- Anims = { --- Anims = {
--- animDict = "amb@prop_human_parking_meter@male@idle_a", --- animDict = "amb@prop_human_parking_meter@male@idle_a",
--- anim = "idle_a", --- anim = "idle_a",
--- }, --- },
--- }, --- },
--- coords = vector3(100.0, 200.0, 300.0), --- coords = vector3(100.0, 200.0, 300.0),
--- stashTable = "crafting_stash", --- stashTable = "crafting_stash",
--- job = "mechanic", -- Optional --- job = "mechanic", -- Optional
--- 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
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
if Config.System.Menu == "jim" then if Config.System.Menu == "jim" then
triggerNotify(nil, "Thinking", "info") triggerNotify(nil, "Thinking", "info")
else else
openMenu({ { header = "Thinking...", icon = "fas fa-hourglass-end", isMenuHeader = true } }, { header = "Crafting Menu" } ) openMenu({ { header = "Thinking...", icon = "fas fa-hourglass-end", isMenuHeader = true } }, { header = "Crafting Menu" } )
end end
if data.stashTable then data.stashName = data.stashTable end if data.stashTable then data.stashName = data.stashTable end
local Menu, hasjob = {}, false local Menu, hasjob = {}, false
local Recipes = data.craftable.Recipes local Recipes = data.craftable.Recipes
local tempCarryTable = {} local tempCarryTable = {}
for i = 1, #Recipes do for i = 1, #Recipes do
for k in pairs(Recipes[i]) do for k in pairs(Recipes[i]) do
if k ~= "amount" and k ~= "metadata" and k ~= "job" and k ~= "gang" then if k ~= "amount" and k ~= "metadata" and k ~= "job" and k ~= "gang" then
tempCarryTable[k] = Recipes[i].amount or 1 tempCarryTable[k] = Recipes[i].amount or 1
end end
end end
end end
local canCarryTable = triggerCallback(getScript()..':server:canCarry', tempCarryTable) local canCarryTable = triggerCallback(getScript()..':server:canCarry', tempCarryTable)
for i = 1, #Recipes do for i = 1, #Recipes do
if not Recipes[i]["amount"] then Recipes[i]["amount"] = 1 end if not Recipes[i]["amount"] then Recipes[i]["amount"] = 1 end
for k, v in pairs(Recipes[i]) do for k, v in pairs(Recipes[i]) do
if k ~= "amount" and k ~= "metadata" and k ~= "job" and k ~= "gang" then if k ~= "amount" and k ~= "metadata" and k ~= "job" and k ~= "gang" then
if Recipes[i].job then if Recipes[i].job then
for l, b in pairs(Recipes[i].job) do for l, b in pairs(Recipes[i].job) do
hasjob = hasJob(l, nil, b) hasjob = hasJob(l, nil, b)
if hasjob == true then break end if hasjob == true then break end
end end
else hasjob = true end else hasjob = true end
local setheader, settext, disable, metadata = "", "", false, (Recipes[i]["metadata"] or nil) local setheader, settext, disable, metadata = "", "", false, (Recipes[i]["metadata"] or nil)
if hasjob then if hasjob then
local itemTable = {} local itemTable = {}
local metaTable = {} local metaTable = {}
for l, b in pairs(Recipes[i][tostring(k)]) do for l, b in pairs(Recipes[i][tostring(k)]) do
settext = settext..(settext ~= "" and br or "")..(Items[l] and Items[l].label or "error - "..l)..(b > 1 and " x"..b or "") settext = settext..(settext ~= "" and br or "")..(Items[l] and Items[l].label or "error - "..l)..(b > 1 and " x"..b or "")
metaTable[Items[l] and Items[l].label or "error - "..l] = b metaTable[Items[l] and Items[l].label or "error - "..l] = b
itemTable[l] = b itemTable[l] = b
Wait(0) Wait(0)
end end
while not canCarryTable do Wait(0) end while not canCarryTable do Wait(0) end
disable = not checkHasItem(data.stashName, itemTable) disable = not checkHasItem(data.stashName, itemTable)
setheader = ((metadata and metadata.label) or (Items[tostring(k)] and Items[tostring(k)].label) or "error - " .. tostring(k)) .. (Recipes[i]["amount"] > 1 and " x" .. Recipes[i]["amount"] or "") setheader = ((metadata and metadata.label) or (Items[tostring(k)] and Items[tostring(k)].label) or "error - " .. tostring(k)) .. (Recipes[i]["amount"] > 1 and " x" .. Recipes[i]["amount"] or "")
if not disable then if not disable then
if not canCarryTable[k] then setheader = setheader .. " 📦" if not canCarryTable[k] then setheader = setheader .. " 📦"
else setheader = setheader .. " ✔️" end else setheader = setheader .. " ✔️" end
elseif not canCarryTable[k] then setheader = setheader .. " 📦" end elseif not canCarryTable[k] then setheader = setheader .. " 📦" end
Menu[#Menu + 1] = { Menu[#Menu + 1] = {
arrow = not disable and canCarryTable[k], arrow = not disable and canCarryTable[k],
disable = isStarted(QBMenuExport) and disable and not canCarryTable[k], disable = isStarted(QBMenuExport) and disable and not canCarryTable[k],
icon = invImg((metadata and metadata.image) or tostring(k)), icon = invImg((metadata and metadata.image) or tostring(k)),
image = invImg((metadata and metadata.image) or tostring(k)), image = invImg((metadata and metadata.image) or tostring(k)),
header = setheader..((disable or not canCarryTable[k]) and "" or ""), header = setheader..((disable or not canCarryTable[k]) and "" or ""),
txt = isStarted(QBMenuExport) and settext or nil, txt = isStarted(QBMenuExport) and settext or nil,
--metadata = debugMode and Recipes[i]["metadata"] or nil, --metadata = debugMode and Recipes[i]["metadata"] or nil,
metadata = metaTable, metadata = metaTable,
onSelect = ((not disable and canCarryTable[k]) and (function() 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 = Recipes[i]["metadata"] } local transdata = { item = k, craft = data.craftable.Recipes[i], craftable = data.craftable, coords = data.coords, stashName = data.stashName, onBack = data.onBack, metadata = Recipes[i]["metadata"] }
if Config.Crafting.MultiCraft then multiCraft(transdata) else makeItem(transdata) end if Config.Crafting.MultiCraft then multiCraft(transdata) else makeItem(transdata) end
end) or nil), end) or nil),
} }
end end
end end
Wait(0) Wait(0)
end end
end end
openMenu(Menu, { header = data.craftable.Header, onBack = data.onBack or nil, canClose = true, onExit = function() end, }) openMenu(Menu, { header = data.craftable.Header, onBack = data.onBack or nil, canClose = true, onExit = function() end, })
lookEnt(data.coords) lookEnt(data.coords)
end end
--- Opens a menu for selecting the quantity to craft. --- Opens a menu for selecting the quantity to craft.
--- ---
--- This function presents the player with options to craft multiple quantities of an item, based on `Config.Crafting.MultiCraftAmounts`. --- This function presents the player with options to craft multiple quantities of an item, based on `Config.Crafting.MultiCraftAmounts`.
--- ---
---@param data table A table containing crafting data. ---@param data table A table containing crafting data.
--- - **item** (`string`): The item to craft. --- - **item** (`string`): The item to craft.
--- - **craft** (`table`): The crafting recipe for the item. --- - **craft** (`table`): The crafting recipe for the item.
--- - **craftable** (`table`): The crafting options and settings. --- - **craftable** (`table`): The crafting options and settings.
--- - **coords** (`vector3`): The coordinates where the crafting is taking place. --- - **coords** (`vector3`): The coordinates where the crafting is taking place.
--- - **stashName** (`string` or `table`, optional): The stash name(s) to check for item availability. --- - **stashName** (`string` or `table`, optional): The stash name(s) to check for item availability.
--- - **onBack** (`function`, optional): Function to call when returning from the menu. --- - **onBack** (`function`, optional): Function to call when returning from the menu.
--- - **metadata** (`table`, optional): Metadata for the crafted item. --- - **metadata** (`table`, optional): Metadata for the crafted item.
--- ---
---@usage ---@usage
--- ```lua --- ```lua
--- multiCraft({ --- multiCraft({
--- item = "weapon_pistol", --- item = "weapon_pistol",
--- craft = { ["weapon_pistol"] = { ["steel"] = 5, ["plastic"] = 2 }, amount = 1 }, --- craft = { ["weapon_pistol"] = { ["steel"] = 5, ["plastic"] = 2 }, amount = 1 },
--- craftable = craftingOptions, --- craftable = craftingOptions,
--- coords = vector3(100.0, 200.0, 300.0), --- coords = vector3(100.0, 200.0, 300.0),
--- stashName = "crafting_stash", --- stashName = "crafting_stash",
--- onBack = function() craftingMenu(data) end, --- onBack = function() craftingMenu(data) end,
--- metadata = { label = "Custom Pistol", image = "custom_pistol.png" }, --- metadata = { label = "Custom Pistol", image = "custom_pistol.png" },
--- }) --- })
--- ``` --- ```
function multiCraft(data) function multiCraft(data)
local Menu = {} local Menu = {}
local success = Config.Crafting.MultiCraftAmounts local success = Config.Crafting.MultiCraftAmounts
local metadata = data.metadata or nil local metadata = data.metadata or nil
Menu[#Menu+1] = { Menu[#Menu+1] = {
isMenuHeader = true, isMenuHeader = true,
icon = invImg(metadata and metadata.image or data.item), icon = invImg(metadata and metadata.image or data.item),
header = metadata and metadata.label or Items[data.item].label, header = metadata and metadata.label or Items[data.item].label,
} }
for k in pairsByKeys(success) do for k in pairsByKeys(success) do
local settext = "" local settext = ""
local itemTable = {} local itemTable = {}
for l, b in pairs(data.craft[data.item]) do for l, b in pairs(data.craft[data.item]) do
itemTable[l] = (b * k) itemTable[l] = (b * k)
settext = settext..(settext ~= "" and br or "")..Items[l].label..(b*k > 1 and "- x"..b*k or "") settext = settext..(settext ~= "" and br or "")..Items[l].label..(b*k > 1 and "- x"..b*k or "")
Wait(0) Wait(0)
end end
local disable, stashname = checkHasItem(data.stashName, itemTable) local disable, stashname = checkHasItem(data.stashName, itemTable)
Menu[#Menu + 1] = { Menu[#Menu + 1] = {
isMenuHeader = not disable, isMenuHeader = not disable,
arrow = disable, arrow = disable,
header = "Craft - x"..k * data.craft.amount, header = "Craft - x"..k * data.craft.amount,
txt = settext, txt = settext,
onSelect = function () 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 }) 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, end,
} }
end end
openMenu(Menu, { header = data.craftable.Header, onBack = function() craftingMenu(data) end, }) openMenu(Menu, { header = data.craftable.Header, onBack = function() craftingMenu(data) end, })
end end
--- Initiates the crafting process for a specified item. --- Initiates the crafting process for a specified item.
--- ---
--- This function handles the crafting animation, progress bar, item removal, and item creation. --- This function handles the crafting animation, progress bar, item removal, and item creation.
--- ---
---@param data table A table containing crafting data. ---@param data table A table containing crafting data.
--- - **item** (`string`): The item to craft. --- - **item** (`string`): The item to craft.
--- - **craft** (`table`): The crafting recipe for the item. --- - **craft** (`table`): The crafting recipe for the item.
--- - **craftable** (`table`): The crafting options and settings. --- - **craftable** (`table`): The crafting options and settings.
--- - **amount** (`number`, optional): The quantity to craft. Default is `1`. --- - **amount** (`number`, optional): The quantity to craft. Default is `1`.
--- - **coords** (`vector3`): The coordinates where the crafting is taking place. --- - **coords** (`vector3`): The coordinates where the crafting is taking place.
--- - **stashName** (`string` or `table`, optional): The stash name(s) to remove items from. --- - **stashName** (`string` or `table`, optional): The stash name(s) to remove items from.
--- - **stashTable** (`string` or `table`, optional): Alias for `stashName`. --- - **stashTable** (`string` or `table`, optional): Alias for `stashName`.
--- - **onBack** (`function`, optional): Function to call when returning from the menu. --- - **onBack** (`function`, optional): Function to call when returning from the menu.
--- - **metadata** (`table`, optional): Metadata for the crafted item. --- - **metadata** (`table`, optional): Metadata for the crafted item.
--- ---
---@usage ---@usage
--- ```lua --- ```lua
--- makeItem({ --- makeItem({
--- item = "weapon_pistol", --- item = "weapon_pistol",
--- craft = { ["weapon_pistol"] = { ["steel"] = 5, ["plastic"] = 2 }, amount = 1 }, --- craft = { ["weapon_pistol"] = { ["steel"] = 5, ["plastic"] = 2 }, amount = 1 },
--- craftable = craftingOptions, --- craftable = craftingOptions,
--- amount = 2, --- amount = 2,
--- coords = vector3(100.0, 200.0, 300.0), --- coords = vector3(100.0, 200.0, 300.0),
--- stashName = "crafting_stash", --- stashName = "crafting_stash",
--- onBack = function() craftingMenu(data) end, --- onBack = function() craftingMenu(data) end,
--- metadata = { label = "Custom Pistol", image = "custom_pistol.png" }, --- metadata = { label = "Custom Pistol", image = "custom_pistol.png" },
--- }) --- })
--- ``` --- ```
function makeItem(data) function makeItem(data)
if CraftLock then return end if CraftLock then return end
CraftLock = true CraftLock = true
if data.stashTable then data.stashName = data.stashTable end if data.stashTable then data.stashName = data.stashTable end
local bartime = data.craftable.progressBar and data.craftable.progressBar.time or 5000 local bartime = data.craftable.progressBar and data.craftable.progressBar.time or 5000
local bartext = (data.craftable.progressBar and data.craftable.progressBar.label) or (Loc[Config.Lan].progressbar and Loc[Config.Lan].progressbar["progress_make"]) or "Making a" local bartext = (data.craftable.progressBar and data.craftable.progressBar.label) or (Loc[Config.Lan].progressbar and Loc[Config.Lan].progressbar["progress_make"]) or "Making a"
local animDict = data.craftable.Anims and data.craftable.Anims.animDict or "amb@prop_human_parking_meter@male@idle_a" local animDict = data.craftable.Anims and data.craftable.Anims.animDict or "amb@prop_human_parking_meter@male@idle_a"
local anim = data.craftable.Anims and data.craftable.Anims.anim or "idle_a" local anim = data.craftable.Anims and data.craftable.Anims.anim or "idle_a"
local amount = data.amount and (data.amount ~= 1) and data.amount or 1 local amount = 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
local crafted, crafting = true, true local crafted, crafting = true, true
local cam = createTempCam(PlayerPedId(), data.coords) local cam = createTempCam(PlayerPedId(), data.coords)
startTempCam(cam) startTempCam(cam)
for i = 1, amount do for i = 1, amount do
for k, v in pairs(data.craft) do for k, v in pairs(data.craft) do
if k ~= "amount" and k ~= "metadata" and k ~= "job" and k ~= "gang" then if k ~= "amount" and k ~= "metadata" and k ~= "job" and k ~= "gang" then
if type(v) == "table" then if type(v) == "table" then
for l, b in pairs(v) do for l, b in pairs(v) do
if crafting and progressBar({ if crafting and progressBar({
label = "Using "..b.." "..Items[l].label, label = "Using "..b.." "..Items[l].label,
time = 1000, time = 1000,
cancel = true, cancel = true,
dict = 'pickup_object', dict = 'pickup_object',
anim = "putdown_low", anim = "putdown_low",
flag = 48, flag = 48,
icon = l, icon = l,
}) then }) then
TriggerEvent((isStarted(QBInv) and QBInvNew and "qb-" or "").."inventory:client:ItemBox", Items[l], "use", b) -- Show item box for each item TriggerEvent((isStarted(QBInv) and QBInvNew and "qb-" or "").."inventory:client:ItemBox", Items[l], "use", b) -- Show item box for each item
else else
crafted, crafting = false, false crafted, crafting = false, false
break break
end end
Wait(200) Wait(200)
end end
if crafted then if crafted then
local craftProp = nil local craftProp = nil
if prop then if prop then
local model, pos, rot, bone = prop.model, prop.pos, prop.rot, prop.bone local model, pos, rot, bone = prop.model, prop.pos, prop.rot, prop.bone
craftProp = makeProp({ prop = model, coords = vec4(0, 0, 0, 0), true, true }) craftProp = makeProp({ prop = model, coords = vec4(0, 0, 0, 0), true, true })
AttachEntityToEntity(craftProp, PlayerPedId(), GetPedBoneIndex(PlayerPedId(), bone), pos.x, pos.y, pos.z, rot.x, rot.y, rot.z, true, true, false, true, 1, true) AttachEntityToEntity(craftProp, PlayerPedId(), GetPedBoneIndex(PlayerPedId(), bone), pos.x, pos.y, pos.z, rot.x, rot.y, rot.z, true, true, false, true, 1, true)
end end
if crafting and progressBar({ if crafting and progressBar({
label = bartext..((metadata and metadata.label) or Items[data.item].label), label = bartext..((metadata and metadata.label) or Items[data.item].label),
time = bartime, time = bartime,
cancel = true, cancel = true,
dict = animDict, dict = animDict,
anim = anim, anim = anim,
flag = 49, flag = 49,
icon = data.item, icon = data.item,
}) then }) then
TriggerServerEvent(getScript()..":Crafting:GetItem", data.item, data.craft, data.stashName, metadata) TriggerServerEvent(getScript()..":Crafting:GetItem", data.item, data.craft, data.stashName, metadata)
else else
crafting = false crafting = false
break break
end end
if craftProp then destroyProp(craftProp) end if craftProp then destroyProp(craftProp) end
end end
end end
end end
end end
Wait(500) Wait(500)
end end
stopTempCam() stopTempCam()
CraftLock = false CraftLock = false
lockInv(false) lockInv(false)
craftingMenu(data) craftingMenu(data)
ClearPedTasks(PlayerPedId()) ClearPedTasks(PlayerPedId())
end end
--- Server event handler for giving the crafted item to the player. --- Server event handler for giving the crafted item to the player.
--- ---
--- This event is triggered when the crafting process is completed successfully. --- This event is triggered when the crafting process is completed successfully.
--- ---
--- @param ItemMake string The item being crafted. --- @param ItemMake string The item being crafted.
--- @param craftable table The crafting recipe and details. --- @param craftable table The crafting recipe and details.
--- @param stashName string|table The stash name(s) to remove items from. --- @param stashName string|table The stash name(s) to remove items from.
--- @param metadata table (optional) Metadata for the crafted item. --- @param metadata table (optional) Metadata for the crafted item.
RegisterNetEvent(getScript()..":Crafting:GetItem", function(ItemMake, craftable, stashName, metadata) RegisterNetEvent(getScript()..":Crafting:GetItem", function(ItemMake, craftable, stashName, metadata)
local src, amount, stashItems = source, craftable and craftable.amount or 1, nil local src, amount, stashItems = source, craftable and craftable.amount or 1, nil
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[ItemMake] or {}) do
for _, b in pairs(stashItems or {}) do for _, b in pairs(stashItems or {}) do
if k == b.name then itemRemove[k] = v end if k == b.name then itemRemove[k] = v end
end end
end end
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[ItemMake] or {}) do
for _, b in pairs(stashItems or {}) do for _, b in pairs(stashItems or {}) do
if k == b.name then itemRemove[k] = v end if k == b.name then itemRemove[k] = v end
end end
end end
end end
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[ItemMake] or {}) do
TriggerEvent(getScript()..":server:toggleItem", false, tostring(k), v, src) TriggerEvent(getScript()..":server:toggleItem", false, tostring(k), v, src)
end end
end end
end end
TriggerEvent(getScript()..":server:toggleItem", true, ItemMake, amount, src, metadata) TriggerEvent(getScript()..":server:toggleItem", true, ItemMake, amount, src, metadata)
--if isStarted("core_skills") then exports["core_skills"]:AddExperience(src, 2) end --if isStarted("core_skills") then exports["core_skills"]:AddExperience(src, 2) end
end) end)
--- Opens a selling menu based on the provided data. --- Opens a selling menu based on the provided data.
--- ---
--- This function checks available items to sell, prepares the menu options, and opens the selling menu. --- This function checks available items to sell, prepares the menu options, and opens the selling menu.
--- ---
---@param data table A table containing selling menu data. ---@param data table A table containing selling menu data.
--- - **sellTable** (`table`): The selling options and settings. --- - **sellTable** (`table`): The selling options and settings.
--- - **Items** (`table`): A list of items that can be sold with their prices. --- - **Items** (`table`): A list of items that can be sold with their prices.
--- - **Header** (`string`, optional): The header/title of the selling menu. --- - **Header** (`string`, optional): The header/title of the selling menu.
--- - **ped** (`number`, optional): The ped entity involved in the selling interaction. --- - **ped** (`number`, optional): The ped entity involved in the selling interaction.
--- - **onBack** (`function`, optional): Function to call when returning from the menu. --- - **onBack** (`function`, optional): Function to call when returning from the menu.
--- ---
---@usage ---@usage
--- ```lua --- ```lua
--- sellMenu({ --- sellMenu({
--- sellTable = { --- sellTable = {
--- Header = "Sell Items", --- Header = "Sell Items",
--- Items = { --- Items = {
--- ["gold_ring"] = 100, --- ["gold_ring"] = 100,
--- ["diamond"] = 500, --- ["diamond"] = 500,
--- }, --- },
--- }, --- },
--- ped = pedEntity, --- ped = pedEntity,
--- onBack = function() print("Returning to previous menu") end, --- onBack = function() print("Returning to previous menu") end,
--- }) --- })
--- ``` --- ```
function sellMenu(data) function sellMenu(data)
local origData = data local origData = data
local Menu = {} local Menu = {}
if data.sellTable.Items then if data.sellTable.Items then
local itemList = {} local itemList = {}
for k, v in pairs(data.sellTable.Items) do itemList[k] = 1 end for k, v in pairs(data.sellTable.Items) do itemList[k] = 1 end
local _, hasTable = hasItem(itemList) local _, hasTable = hasItem(itemList)
for k, v in pairsByKeys(data.sellTable.Items) do for k, v in pairsByKeys(data.sellTable.Items) do
Menu[#Menu +1] = { Menu[#Menu +1] = {
isMenuHeader = not hasTable[k].hasItem, isMenuHeader = not hasTable[k].hasItem,
icon = invImg(k), icon = invImg(k),
header = Items[k].label.. (hasTable[k].hasItem and "💰 (x"..hasTable[k].count..")" or ""), 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"], txt = Loc[Config.Lan].info["sell_all"]..v.." "..Loc[Config.Lan].info["sell_each"],
onSelect = function() onSelect = function()
sellAnim({ item = k, price = v, ped = data.ped, onBack = function() sellMenu(data) end }) sellAnim({ item = k, price = v, ped = data.ped, onBack = function() sellMenu(data) end })
end, end,
} }
end end
else else
for k, v in pairsByKeys(data.sellTable) do for k, v in pairsByKeys(data.sellTable) do
if type(v) == "table" then if type(v) == "table" then
Menu[#Menu +1] = { Menu[#Menu +1] = {
arrow = true, arrow = true,
header = k, header = k,
txt = "Amount of items: "..countTable(v.Items), txt = "Amount of items: "..countTable(v.Items),
onSelect = function() onSelect = function()
v.onBack = function() sellMenu(origData) end v.onBack = function() sellMenu(origData) end
v.sellTable = data.sellTable[k] v.sellTable = data.sellTable[k]
sellMenu(v) sellMenu(v)
end, end,
} }
end end
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 }) 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 end
--- Handles the selling animation and item transaction. --- Handles the selling animation and item transaction.
--- ---
--- This function plays the selling animation, removes the item from the player's inventory, and gives the player money. --- This function plays the selling animation, removes the item from the player's inventory, and gives the player money.
--- ---
---@param data table A table containing selling data. ---@param data table A table containing selling data.
--- - **item** (`string`): The item to sell. --- - **item** (`string`): The item to sell.
--- - **price** (`number`): The price per item. --- - **price** (`number`): The price per item.
--- - **ped** (`number`, optional): The ped entity involved in the selling interaction. --- - **ped** (`number`, optional): The ped entity involved in the selling interaction.
--- - **onBack** (`function`, optional): Function to call when returning from the menu. --- - **onBack** (`function`, optional): Function to call when returning from the menu.
--- ---
---@usage ---@usage
--- ```lua --- ```lua
--- sellAnim({ --- sellAnim({
--- item = "gold_ring", --- item = "gold_ring",
--- price = 100, --- price = 100,
--- ped = pedEntity, --- ped = pedEntity,
--- onBack = function() sellMenu(data) end, --- onBack = function() sellMenu(data) end,
--- }) --- })
--- ``` --- ```
function sellAnim(data) function sellAnim(data)
if not hasItem(data.item, 1) then if not hasItem(data.item, 1) then
triggerNotify(nil, Loc[Config.Lan].error["dont_have"].." "..Items[data.item].label, "error") triggerNotify(nil, Loc[Config.Lan].error["dont_have"].." "..Items[data.item].label, "error")
return return
end end
for k, v in pairs(GetGamePool('CObject')) do for k, v in pairs(GetGamePool('CObject')) do
for _, model in pairs({`p_cs_clipboard`}) do for _, model in pairs({`p_cs_clipboard`}) do
if GetEntityModel(v) == model then if GetEntityModel(v) == model then
if IsEntityAttachedToEntity(data.ped, v) then if IsEntityAttachedToEntity(data.ped, v) then
DeleteObject(v) DetachEntity(v, 0, 0) SetEntityAsMissionEntity(v, true, true) DeleteObject(v) DetachEntity(v, 0, 0) SetEntityAsMissionEntity(v, true, true)
Wait(100) DeleteEntity(v) Wait(100) DeleteEntity(v)
end end
end end
end end
end end
TriggerServerEvent(getScript().."Sellitems", data) TriggerServerEvent(getScript().."Sellitems", data)
lookEnt(data.ped) lookEnt(data.ped)
local dict = "mp_common" local dict = "mp_common"
playAnim(dict, "givetake2_a", 0.3, 2) playAnim(dict, "givetake2_a", 0.3, 2)
playAnim(dict, "givetake2_b", 0.3, 2, data.ped) playAnim(dict, "givetake2_b", 0.3, 2, data.ped)
Wait(2000) Wait(2000)
StopAnimTask(PlayerPedId(), dict, "givetake2_a", 0.5) StopAnimTask(PlayerPedId(), dict, "givetake2_a", 0.5)
StopAnimTask(data.ped, dict, "givetake2_b", 0.5) StopAnimTask(data.ped, dict, "givetake2_b", 0.5)
if data.onBack then data.onBack() end if data.onBack then data.onBack() end
end end
--- Server event handler for processing the item sale. --- Server event handler for processing the item sale.
--- ---
--- This event removes the sold item from the player's inventory and adds money to their account. --- This event removes the sold item from the player's inventory and adds money to their account.
--- ---
---@param data table The data containing item and price information. ---@param data table The data containing item and price information.
RegisterNetEvent(getScript().."Sellitems", function(data) RegisterNetEvent(getScript().."Sellitems", function(data)
local src = source local src = source
local hasItems, hasTable = hasItem(data.item, 1, src) local hasItems, hasTable = hasItem(data.item, 1, src)
if hasItems then if hasItems then
TriggerEvent(getScript()..":server:toggleItem", false, data.item, hasTable[data.item].count, src) TriggerEvent(getScript()..":server:toggleItem", false, data.item, hasTable[data.item].count, src)
TriggerEvent(getScript()..":server:FundPlayer", (hasTable[data.item].count * data.price), "cash", src) TriggerEvent(getScript()..":server:FundPlayer", (hasTable[data.item].count * data.price), "cash", src)
else else
triggerNotify(nil, Loc[Config.Lan].error["dont_have"].." "..Items[data.item].label, "error", src) triggerNotify(nil, Loc[Config.Lan].error["dont_have"].." "..Items[data.item].label, "error", src)
end end
end) end)
--- Opens a shop interface for the player. --- Opens a shop interface for the player.
--- ---
--- This function checks job requirements and opens the shop using the appropriate inventory system. --- This function checks job requirements and opens the shop using the appropriate inventory system.
--- ---
---@param data table A table containing shop data. ---@param data table A table containing shop data.
--- - **shop** (`string`): The shop identifier. --- - **shop** (`string`): The shop identifier.
--- - **items** (`table`): The items available in the shop. --- - **items** (`table`): The items available in the shop.
--- - **coords** (`vector3`): The coordinates where the shop interaction is happening. --- - **coords** (`vector3`): The coordinates where the shop interaction is happening.
--- - **job** (`string` or `table`, optional): Job(s) required to access the shop. --- - **job** (`string` or `table`, optional): Job(s) required to access the shop.
--- - **gang** (`string` or `table`, optional): Gang(s) required to access the shop. --- - **gang** (`string` or `table`, optional): Gang(s) required to access the shop.
--- ---
---@usage ---@usage
--- ```lua --- ```lua
--- openShop({ --- openShop({
--- shop = "weapon_shop", --- shop = "weapon_shop",
--- items = weaponShopItems, --- items = weaponShopItems,
--- coords = vector3(100.0, 200.0, 300.0), --- coords = vector3(100.0, 200.0, 300.0),
--- job = "police", --- job = "police",
--- }) --- })
--- ``` --- ```
function openShop(data) function openShop(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
if isStarted(OXInv) then if isStarted(OXInv) then
exports[OXInv]:openInventory('shop', { type = data.shop }) exports[OXInv]:openInventory('shop', { type = data.shop })
elseif isStarted(QBInv) then elseif isStarted(QBInv) then
if QBInvNew then if QBInvNew then
TriggerServerEvent(getScript()..':server:OpenShopNewQB', data.shop) -- i hate qb-inv TriggerServerEvent(getScript()..':server:OpenShopNewQB', data.shop) -- i hate qb-inv
else else
TriggerServerEvent(Config.General.JimShops and "jim-shops:ShopOpen" or "inventory:server:OpenInventory", "shop", data.items.label, data.items) TriggerServerEvent(Config.General.JimShops and "jim-shops:ShopOpen" or "inventory:server:OpenInventory", "shop", data.items.label, data.items)
end end
else else
TriggerServerEvent(Config.General.JimShops and "jim-shops:ShopOpen" or "inventory:server:OpenInventory", "shop", data.items.label, data.items) TriggerServerEvent(Config.General.JimShops and "jim-shops:ShopOpen" or "inventory:server:OpenInventory", "shop", data.items.label, data.items)
end end
lookEnt(data.coords) lookEnt(data.coords)
end end
--- Server event handler for opening a new QB inventory shop. --- Server event handler for opening a new QB inventory shop.
--- ---
--- This event is triggered when using the new QB inventory system. --- This event is triggered when using the new QB inventory system.
--- ---
---@param data table The shop data to open. ---@param data table The shop data to open.
RegisterNetEvent(getScript()..':server:OpenShopNewQB', function(data) RegisterNetEvent(getScript()..':server:OpenShopNewQB', function(data)
exports[QBInv]:OpenShop(source, data) exports[QBInv]:OpenShop(source, data)
end) end)
--- Server-side callback registration for checking if the player can carry items. --- Server-side callback registration for checking if the player can carry items.
if isServer() then if isServer() then
createCallback(getScript()..':server:canCarry', function(source, itemTable) local result = canCarry(itemTable, source) return result end) createCallback(getScript()..':server:canCarry', function(source, itemTable) local result = canCarry(itemTable, source) return result end)
end end

View File

@@ -1,61 +1,61 @@
local radarTable = {} local radarTable = {}
--- Displays text on the screen using the configured draw text system. --- Displays text on the screen using the configured draw text system.
--- ---
--- This function handles displaying text with optional images or icons using different frameworks like 'qb', 'ox', 'gta', and 'esx'. --- This function handles displaying text with optional images or icons using different frameworks like 'qb', 'ox', 'gta', and 'esx'.
--- ---
---@param image string|nil An optional image or icon to display with the text. Can be a URL, path, or a reference to an icon. ---@param image string|nil An optional image or icon to display with the text. Can be a URL, path, or a reference to an icon.
---@param input table A table of strings, each representing a line of text to display. ---@param input table A table of strings, each representing a line of text to display.
---@param style string|nil An optional style code for default GTA popups (e.g., '~g~' for green text). ---@param style string|nil An optional style code for default GTA popups (e.g., '~g~' for green text).
---@param oxStyleTable table|nil An optional table specifying style parameters for the 'ox' draw text system. ---@param oxStyleTable table|nil An optional table specifying style parameters for the 'ox' draw text system.
--- ---
---@usage ---@usage
--- ```lua --- ```lua
--- drawText("img_link", { "Test line 1", "Test Line 2" }, "~g~") --- drawText("img_link", { "Test line 1", "Test Line 2" }, "~g~")
--- ``` --- ```
function drawText(image, input, style, oxStyleTable) local text = "" function drawText(image, input, style, oxStyleTable) local text = ""
if Config.System.drawText == "qb" then if Config.System.drawText == "qb" then
for i = 1, #input do for i = 1, #input do
text = text..input[i].."</span>"..(input[i+1] ~= nil and "<br>" or "") end text = text..input[i].."</span>"..(input[i+1] ~= nil and "<br>" or "") end
local text = text:gsub("%:", ":<span style='color:yellow'>") local text = text:gsub("%:", ":<span style='color:yellow'>")
if image then if image then
text = '<img src="'..(radarTable[image] or nil)..'" style="width:12px;height:12px">'..text text = '<img src="'..(radarTable[image] or nil)..'" style="width:12px;height:12px">'..text
end end
exports[QBExport]:DrawText(text, 'left') exports[QBExport]:DrawText(text, 'left')
elseif Config.System.drawText == "ox" then elseif Config.System.drawText == "ox" then
for k, v in pairs(input) do for k, v in pairs(input) do
input[k] = v.." \n" input[k] = v.." \n"
end end
lib.showTextUI(table.concat(input), { icon = (image and radarTable[image] or image) or nil, position = 'left-center', style = oxStyleTable}) lib.showTextUI(table.concat(input), { icon = (image and radarTable[image] or image) or nil, position = 'left-center', style = oxStyleTable})
elseif Config.System.drawText == "gta" then elseif Config.System.drawText == "gta" then
for i = 1, #input do if input[i] ~= "" then text = text..input[i].."\n~s~" end end for i = 1, #input do if input[i] ~= "" then text = text..input[i].."\n~s~" end end
if image then text = "~BLIP_"..image.."~ "..text end if image then text = "~BLIP_"..image.."~ "..text end
DisplayHelpMsg(text:gsub("%:", ":~"..(style or "g").."~")) DisplayHelpMsg(text:gsub("%:", ":~"..(style or "g").."~"))
elseif Config.System.drawText == "esx" then elseif Config.System.drawText == "esx" then
for i = 1, #input do for i = 1, #input do
text = text..input[i].."</span>"..(input[i+1] ~= nil and "<br>" or "") end text = text..input[i].."</span>"..(input[i+1] ~= nil and "<br>" or "") end
local text = text:gsub("%:", ":<span style='color:yellow'>") local text = text:gsub("%:", ":<span style='color:yellow'>")
if image then if image then
text = '<img src="'..radarTable[image]..'" style="width:12px;height:12px">'..text text = '<img src="'..radarTable[image]..'" style="width:12px;height:12px">'..text
end end
ESX.TextUI(text, nil) ESX.TextUI(text, nil)
end end
end end
--- Hides any text currently being displayed on the screen. --- Hides any text currently being displayed on the screen.
--- ---
--- This function clears the text displayed by the `drawText` function, using the appropriate method based on the configured draw text system. --- This function clears the text displayed by the `drawText` function, using the appropriate method based on the configured draw text system.
function hideText() function hideText()
if Config.System.drawText == "qb" then if Config.System.drawText == "qb" then
exports[QBExport]:HideText() exports[QBExport]:HideText()
elseif Config.System.drawText == "ox" then elseif Config.System.drawText == "ox" then
lib.hideTextUI() lib.hideTextUI()
elseif Config.System.drawText == "gta" then elseif Config.System.drawText == "gta" then
ClearAllHelpMessages() ClearAllHelpMessages()
elseif Config.System.drawText == "esx" then elseif Config.System.drawText == "esx" then
ESX.HideUI() ESX.HideUI()
end end
end end

View File

@@ -1,122 +1,122 @@
-- DUI STUFF -- * Experimental * -- -- DUI STUFF -- * Experimental * --
scriptTxd = not isServer() and CreateRuntimeTxd(getScript()..'scriptTxd') or nil scriptTxd = not isServer() and CreateRuntimeTxd(getScript()..'scriptTxd') or nil
customDUIList = {} customDUIList = {}
-- DUI CLIENT -- DUI CLIENT
function createDui(name, http, size, txd) function createDui(name, http, size, txd)
--print(name, http, size, txd) --print(name, http, size, txd)
if not customDUIList[name] then if not customDUIList[name] then
local newTxt = CreateDui(http, math.floor(size.x), math.floor(size.y)) local newTxt = CreateDui(http, math.floor(size.x), math.floor(size.y))
while not GetDuiHandle(newTxt) do Wait(0) end while not GetDuiHandle(newTxt) do Wait(0) end
CreateRuntimeTextureFromDuiHandle(txd, name, GetDuiHandle(newTxt)) CreateRuntimeTextureFromDuiHandle(txd, name, GetDuiHandle(newTxt))
customDUIList[name] = newTxt customDUIList[name] = newTxt
SetDuiUrl(customDUIList[name], http) SetDuiUrl(customDUIList[name], http)
else else
SetDuiUrl(customDUIList[name], http) SetDuiUrl(customDUIList[name], http)
end end
end end
function DuiSelect(data) function DuiSelect(data)
local image = "" local image = ""
for k, v in pairs(duiList[data.name]) do for k, v in pairs(duiList[data.name]) do
if v.tex.texn == data.texn then if v.tex.texn == data.texn then
if duiList[data.name][k] then if duiList[data.name][k] then
image = "<center>- Current Image -<br>".. image = "<center>- Current Image -<br>"..
"<img src="..duiList[data.name][k].url.." width=150px><br>".. "<img src="..duiList[data.name][k].url.." width=150px><br>"..
"Size: ["..math.floor(data.size.x)..", "..math.floor(data.size.y).."]<br><br>" "Size: ["..math.floor(data.size.x)..", "..math.floor(data.size.y).."]<br><br>"
end end
end end
end end
local dialog = exports['qb-input']:ShowInput({ local dialog = exports['qb-input']:ShowInput({
header = image..Loc[Config.Lan].menu["dui_new"], header = image..Loc[Config.Lan].menu["dui_new"],
submitText = Loc[Config.Lan].menu["dui_change"], submitText = Loc[Config.Lan].menu["dui_change"],
inputs = { { type = 'text', isRequired = true, name = 'url', text = Loc[Config.Lan].menu["dui_url"] } } }) inputs = { { type = 'text', isRequired = true, name = 'url', text = Loc[Config.Lan].menu["dui_url"] } } })
if dialog then if dialog then
if not dialog.url then return end if not dialog.url then return end
data.url = dialog.url data.url = dialog.url
--Scan the link to see if it has an image extention otherwise, stop here. --Scan the link to see if it has an image extention otherwise, stop here.
local searchList = { "png", "jpg", "jpeg", "gif", "webp", "bmp" } local searchList = { "png", "jpg", "jpeg", "gif", "webp", "bmp" }
--Scan the link for certain terms that will flag it and refuse to show it --Scan the link for certain terms that will flag it and refuse to show it
local banList = { "porn" } -- I dunno, let me know what links people manage to find local banList = { "porn" } -- I dunno, let me know what links people manage to find
local searchFound = false local searchFound = false
for k, v in pairs(searchList) do for k, v in pairs(searchList) do
if string.find(tostring(data.url), tostring(v))then if string.find(tostring(data.url), tostring(v))then
searchFound = true searchFound = true
end end
end end
for k, v in pairs(banList) do for k, v in pairs(banList) do
if string.find(tostring(data.url), tostring(v)) then if string.find(tostring(data.url), tostring(v)) then
searchFound = false print("BANNED WORD: "..v) searchFound = false print("BANNED WORD: "..v)
end end
end end
if searchFound then if searchFound then
TriggerServerEvent(getScript()..":Server:ChangeDUI", data) TriggerServerEvent(getScript()..":Server:ChangeDUI", data)
end end
end end
end end
RegisterNetEvent(getScript()..":Client:ChangeDUI", function(data) RegisterNetEvent(getScript()..":Client:ChangeDUI", function(data)
debugPrint("^6Bridge^7: ^2Recieving new DUI ^7- ^6"..data.url.."^7") debugPrint("^6Bridge^7: ^2Recieving new DUI ^7- ^6"..data.url.."^7")
if tostring(data.url) ~= "-" then if tostring(data.url) ~= "-" then
createDui(data.texn, tostring(data.url), data.size, scriptTxd) createDui(data.texn, tostring(data.url), data.size, scriptTxd)
AddReplaceTexture(tostring(data.texd), tostring(data.texn), getScript()..'scriptTxd', tostring(data.texn)) AddReplaceTexture(tostring(data.texd), tostring(data.texn), getScript()..'scriptTxd', tostring(data.texn))
end end
end) end)
RegisterNetEvent(getScript()..":Client:ClearDUI", function(data) RegisterNetEvent(getScript()..":Client:ClearDUI", function(data)
if customDUIList[tostring(data.texn)] then if customDUIList[tostring(data.texn)] then
RemoveReplaceTexture(tostring(data.texd), tostring(data.texn)) RemoveReplaceTexture(tostring(data.texd), tostring(data.texn))
if IsDuiAvailable(customDUIList[tostring(data.texn)]) then if IsDuiAvailable(customDUIList[tostring(data.texn)]) then
SetDuiUrl(customDUIList[data.name], nil) SetDuiUrl(customDUIList[data.name], nil)
end end
end end
end) end)
-- DUI SERVER -- DUI SERVER
RegisterNetEvent(getScript()..":Server:ChangeDUI", function(data) RegisterNetEvent(getScript()..":Server:ChangeDUI", function(data)
-- if no url given, "reset" it back to preset -- if no url given, "reset" it back to preset
if not data.url then if not data.url then
for k, v in pairs(duiList[data.name]) do for k, v in pairs(duiList[data.name]) do
if v.tex.texn == data.texn then if v.tex.texn == data.texn then
debugPrint("^6Bridge^7: ^2Preset^7: ^6"..tostring(duiList[data.name][k].preset).."^7") debugPrint("^6Bridge^7: ^2Preset^7: ^6"..tostring(duiList[data.name][k].preset).."^7")
data.url = duiList[data.name][k].preset data.url = duiList[data.name][k].preset
end end
end end
end end
-- if it has a url, update server DUI list and send to players -- if it has a url, update server DUI list and send to players
for k, v in pairs(duiList[data.name]) do for k, v in pairs(duiList[data.name]) do
if v.tex.texn == data.texn then if v.tex.texn == data.texn then
duiList[data.name][k].url = data.url duiList[data.name][k].url = data.url
end end
end end
debugPrint("^6Bridge^7: ^3DUI^2 Sending new DUI to all players^7 - ^6"..data.url.."^7") debugPrint("^6Bridge^7: ^3DUI^2 Sending new DUI to all players^7 - ^6"..data.url.."^7")
TriggerClientEvent(getScript()..":Client:ChangeDUI", -1, data) TriggerClientEvent(getScript()..":Client:ChangeDUI", -1, data)
end) end)
RegisterNetEvent(getScript()..":Server:ClearDUI", function(data) RegisterNetEvent(getScript()..":Server:ClearDUI", function(data)
if data.url == "-" then if data.url == "-" then
for k, v in pairs(duiList[data.name]) do for k, v in pairs(duiList[data.name]) do
if v.tex.texn == data.texn then if v.tex.texn == data.texn then
duiList[data.name][k].url = "-" duiList[data.name][k].url = "-"
end end
end end
end end
-- Clear the DUI from loading -- Clear the DUI from loading
TriggerClientEvent(getScript()..":Client:ClearDUI", -1, data) TriggerClientEvent(getScript()..":Client:ClearDUI", -1, data)
--duiList[tostring(data.tex)].url = "" --duiList[tostring(data.tex)].url = ""
end) end)
AddEventHandler('onResourceStop', function(r) if r ~= getScript() then return end AddEventHandler('onResourceStop', function(r) if r ~= getScript() then return end
for k, v in pairs(duiList or {}) do for k, v in pairs(duiList or {}) do
for i = 1, #v do for i = 1, #v do
RemoveReplaceTexture(tostring(v[i].tex.texd), tostring(v[i].tex.texn)) RemoveReplaceTexture(tostring(v[i].tex.texd), tostring(v[i].tex.texn))
end end
end end
end) end)
if isServer() then if isServer() then
createCallback(getScript()..":Server:duiList", function(source) createCallback(getScript()..":Server:duiList", function(source)
return duiList return duiList
end) end)
end end

View File

@@ -1,190 +1,190 @@
--Screen Effects --Screen Effects
local alienEffect = false local alienEffect = false
function AlienEffect() function AlienEffect()
if alienEffect then return else alienEffect = true end if alienEffect then return else alienEffect = true end
debugPrint("^5Debug^7: ^3AlienEffect^7() ^2activated") debugPrint("^5Debug^7: ^3AlienEffect^7() ^2activated")
AnimpostfxPlay("DrugsMichaelAliensFightIn", 3.0, 0) AnimpostfxPlay("DrugsMichaelAliensFightIn", 3.0, 0)
Wait(math.random(5000, 8000)) Wait(math.random(5000, 8000))
local Ped = PlayerPedId() local Ped = PlayerPedId()
local animDict = "MOVE_M@DRUNK@VERYDRUNK" local animDict = "MOVE_M@DRUNK@VERYDRUNK"
loadAnimDict(animDict) loadAnimDict(animDict)
SetPedCanRagdoll(Ped, true) SetPedCanRagdoll(Ped, true)
ShakeGameplayCam('DRUNK_SHAKE', 2.80) ShakeGameplayCam('DRUNK_SHAKE', 2.80)
SetTimecycleModifier("Drunk") SetTimecycleModifier("Drunk")
SetPedMovementClipset(Ped, animDict, 1) SetPedMovementClipset(Ped, animDict, 1)
SetPedMotionBlur(Ped, true) SetPedMotionBlur(Ped, true)
SetPedIsDrunk(Ped, true) SetPedIsDrunk(Ped, true)
Wait(1500) Wait(1500)
SetPedToRagdoll(Ped, 5000, 1000, 1, 0, 0, 0) SetPedToRagdoll(Ped, 5000, 1000, 1, 0, 0, 0)
Wait(13500) Wait(13500)
SetPedToRagdoll(Ped, 5000, 1000, 1, 0, 0, 0) SetPedToRagdoll(Ped, 5000, 1000, 1, 0, 0, 0)
Wait(120500) Wait(120500)
ClearTimecycleModifier() ClearTimecycleModifier()
ResetScenarioTypesEnabled() ResetScenarioTypesEnabled()
ResetPedMovementClipset(Ped, 0) ResetPedMovementClipset(Ped, 0)
SetPedIsDrunk(Ped, false) SetPedIsDrunk(Ped, false)
SetPedMotionBlur(Ped, false) SetPedMotionBlur(Ped, false)
AnimpostfxStopAll() AnimpostfxStopAll()
ShakeGameplayCam('DRUNK_SHAKE', 0.0) ShakeGameplayCam('DRUNK_SHAKE', 0.0)
AnimpostfxPlay("DrugsMichaelAliensFight", 3.0, 0) AnimpostfxPlay("DrugsMichaelAliensFight", 3.0, 0)
Wait(math.random(45000, 60000)) Wait(math.random(45000, 60000))
AnimpostfxPlay("DrugsMichaelAliensFightOut", 3.0, 0) AnimpostfxPlay("DrugsMichaelAliensFightOut", 3.0, 0)
AnimpostfxStop("DrugsMichaelAliensFightIn") AnimpostfxStop("DrugsMichaelAliensFightIn")
AnimpostfxStop("DrugsMichaelAliensFight") AnimpostfxStop("DrugsMichaelAliensFight")
AnimpostfxStop("DrugsMichaelAliensFightOut") AnimpostfxStop("DrugsMichaelAliensFightOut")
alienEffect = false alienEffect = false
debugPrint("^5Debug^7: ^3AlienEffect^7() ^2stopped") debugPrint("^5Debug^7: ^3AlienEffect^7() ^2stopped")
end end
local weedEffect = false local weedEffect = false
function WeedEffect() function WeedEffect()
if weedEffect then return else weedEffect = true end if weedEffect then return else weedEffect = true end
debugPrint("^5Debug^7: ^3WeedEffect^7() ^2activated") debugPrint("^5Debug^7: ^3WeedEffect^7() ^2activated")
AnimpostfxPlay("DrugsMichaelAliensFightIn", 3.0, 0) AnimpostfxPlay("DrugsMichaelAliensFightIn", 3.0, 0)
Wait(math.random(3000, 20000)) Wait(math.random(3000, 20000))
AnimpostfxPlay("DrugsMichaelAliensFight", 3.0, 0) AnimpostfxPlay("DrugsMichaelAliensFight", 3.0, 0)
Wait(math.random(15000, 20000)) Wait(math.random(15000, 20000))
AnimpostfxPlay("DrugsMichaelAliensFightOut", 3.0, 0) AnimpostfxPlay("DrugsMichaelAliensFightOut", 3.0, 0)
AnimpostfxStop("DrugsMichaelAliensFightIn") AnimpostfxStop("DrugsMichaelAliensFightIn")
AnimpostfxStop("DrugsMichaelAliensFight") AnimpostfxStop("DrugsMichaelAliensFight")
AnimpostfxStop("DrugsMichaelAliensFightOut") AnimpostfxStop("DrugsMichaelAliensFightOut")
weedEffect = false weedEffect = false
debugPrint("^5Debug^7: ^3WeedEffect^7() ^2stopped") debugPrint("^5Debug^7: ^3WeedEffect^7() ^2stopped")
end end
local trevorEffect = false local trevorEffect = false
function TrevorEffect() function TrevorEffect()
if trevorEffect then return else trevorEffect = true end if trevorEffect then return else trevorEffect = true end
debugPrint("^5Debug^7: ^3TrevorEffect^7() ^2activated") debugPrint("^5Debug^7: ^3TrevorEffect^7() ^2activated")
AnimpostfxPlay("DrugsTrevorClownsFightIn", 3.0, 0) AnimpostfxPlay("DrugsTrevorClownsFightIn", 3.0, 0)
Wait(3000) Wait(3000)
AnimpostfxPlay("DrugsTrevorClownsFight", 3.0, 0) AnimpostfxPlay("DrugsTrevorClownsFight", 3.0, 0)
Wait(30000) Wait(30000)
AnimpostfxPlay("DrugsTrevorClownsFightOut", 3.0, 0) AnimpostfxPlay("DrugsTrevorClownsFightOut", 3.0, 0)
AnimpostfxStop("DrugsTrevorClownsFight") AnimpostfxStop("DrugsTrevorClownsFight")
AnimpostfxStop("DrugsTrevorClownsFightIn") AnimpostfxStop("DrugsTrevorClownsFightIn")
AnimpostfxStop("DrugsTrevorClownsFightOut") AnimpostfxStop("DrugsTrevorClownsFightOut")
trevorEffect = false trevorEffect = false
debugPrint("^5Debug^7: ^3TrevorEffect^7() ^2stopped") debugPrint("^5Debug^7: ^3TrevorEffect^7() ^2stopped")
end end
local turboEffect = false local turboEffect = false
function TurboEffect() function TurboEffect()
if turboEffect then return else turboEffect = true end if turboEffect then return else turboEffect = true end
debugPrint("^5Debug^7: ^3TurboEffect^7() ^2activated") debugPrint("^5Debug^7: ^3TurboEffect^7() ^2activated")
AnimpostfxPlay('RaceTurbo', 0, true) AnimpostfxPlay('RaceTurbo', 0, true)
SetTimecycleModifier('rply_motionblur') SetTimecycleModifier('rply_motionblur')
ShakeGameplayCam('SKY_DIVING_SHAKE', 0.25) ShakeGameplayCam('SKY_DIVING_SHAKE', 0.25)
Wait(30000) Wait(30000)
StopGameplayCamShaking(true) StopGameplayCamShaking(true)
SetTransitionTimecycleModifier('default', 0.35) SetTransitionTimecycleModifier('default', 0.35)
Wait(1000) Wait(1000)
ClearTimecycleModifier() ClearTimecycleModifier()
AnimpostfxStop('RaceTurbo') AnimpostfxStop('RaceTurbo')
turboEffect = false turboEffect = false
debugPrint("^5Debug^7: ^3TurboEffect^7() ^2stopped") debugPrint("^5Debug^7: ^3TurboEffect^7() ^2stopped")
end end
local rampageEffect = false local rampageEffect = false
function RampageEffect() function RampageEffect()
if rampageEffect then return else rampageEffect = true end if rampageEffect then return else rampageEffect = true end
debugPrint("^5Debug^7: ^3RampageEffect^7() ^2activated") debugPrint("^5Debug^7: ^3RampageEffect^7() ^2activated")
AnimpostfxPlay('Rampage', 0, true) AnimpostfxPlay('Rampage', 0, true)
SetTimecycleModifier('rply_motionblur') SetTimecycleModifier('rply_motionblur')
ShakeGameplayCam('SKY_DIVING_SHAKE', 0.25) ShakeGameplayCam('SKY_DIVING_SHAKE', 0.25)
Wait(30000) Wait(30000)
StopGameplayCamShaking(true) StopGameplayCamShaking(true)
SetTransitionTimecycleModifier('default', 0.35) SetTransitionTimecycleModifier('default', 0.35)
Wait(1000) Wait(1000)
ClearTimecycleModifier() ClearTimecycleModifier()
AnimpostfxStop('Rampage') AnimpostfxStop('Rampage')
rampageEffect = false rampageEffect = false
debugPrint("^5Debug^7: ^3RampageEffect^7() ^2stopped") debugPrint("^5Debug^7: ^3RampageEffect^7() ^2stopped")
end end
local focusEffect = false local focusEffect = false
function FocusEffect() function FocusEffect()
if focusEffect then return else focusEffect = true end if focusEffect then return else focusEffect = true end
debugPrint("^5Debug^7: ^3FocusEffect^7() ^2activated") debugPrint("^5Debug^7: ^3FocusEffect^7() ^2activated")
Wait(1000) Wait(1000)
AnimpostfxPlay('FocusIn', 0, true) AnimpostfxPlay('FocusIn', 0, true)
Wait(30000) Wait(30000)
AnimpostfxStop('FocusIn') AnimpostfxStop('FocusIn')
focusEffect = false focusEffect = false
debugPrint("^5Debug^7: ^3FocusEffect^7() ^2stopped") debugPrint("^5Debug^7: ^3FocusEffect^7() ^2stopped")
end end
local nightVisionEffect = false local nightVisionEffect = false
function NightVisionEffect() function NightVisionEffect()
if nightVisionEffect then return else nightVisionEffect = true end if nightVisionEffect then return else nightVisionEffect = true end
debugPrint("^5Debug^7: ^3NightVisionEffect^7() ^2activated") debugPrint("^5Debug^7: ^3NightVisionEffect^7() ^2activated")
SetNightvision(true) SetNightvision(true)
Wait(math.random(3000, 4000)) -- FEEL FREE TO CHANGE THIS Wait(math.random(3000, 4000)) -- FEEL FREE TO CHANGE THIS
SetNightvision(false) SetNightvision(false)
SetSeethrough(false) SetSeethrough(false)
nightVisionEffect = false nightVisionEffect = false
debugPrint("^5Debug^7: ^3NightVisionEffect^7() ^2stopped") debugPrint("^5Debug^7: ^3NightVisionEffect^7() ^2stopped")
end end
local thermalEffect = false local thermalEffect = false
function ThermalEffect() function ThermalEffect()
if thermalEffect then return else thermalEffect = true end if thermalEffect then return else thermalEffect = true end
debugPrint("^5Debug^7: ^3ThermalEffect^7() ^2activated") debugPrint("^5Debug^7: ^3ThermalEffect^7() ^2activated")
SetNightvision(true) SetNightvision(true)
SetSeethrough(true) SetSeethrough(true)
Wait(math.random(2000, 3000)) -- FEEL FREE TO CHANGE THIS Wait(math.random(2000, 3000)) -- FEEL FREE TO CHANGE THIS
SetNightvision(false) SetNightvision(false)
SetSeethrough(false) SetSeethrough(false)
thermalEffect = false thermalEffect = false
debugPrint("^5Debug^7: ^3ThermalEffect^7() ^2stopped") debugPrint("^5Debug^7: ^3ThermalEffect^7() ^2stopped")
end end
--Built-in Buff effects --Built-in Buff effects
local healEffect = false local healEffect = false
function HealEffect(data) function HealEffect(data)
if healEffect then return end if healEffect then return end
debugPrint("^5Debug^7: ^3HealEffect^7() ^2activated") debugPrint("^5Debug^7: ^3HealEffect^7() ^2activated")
healEffect = true healEffect = true
local count = (data[1] / 1000) local count = (data[1] / 1000)
while count > 0 do while count > 0 do
Wait(1000) Wait(1000)
count -= 1 count -= 1
SetEntityHealth(PlayerPedId(), GetEntityHealth(PlayerPedId()) + data[2]) SetEntityHealth(PlayerPedId(), GetEntityHealth(PlayerPedId()) + data[2])
end end
healEffect = false healEffect = false
debugPrint("^5Debug^7: ^3HealEffect^7() ^2stopped") debugPrint("^5Debug^7: ^3HealEffect^7() ^2stopped")
end end
local staminaEffect = false local staminaEffect = false
function StaminaEffect(data) function StaminaEffect(data)
if staminaEffect then return end if staminaEffect then return end
debugPrint("^5Bridge^7: ^3StaminaEffect^7() ^2activated") debugPrint("^5Bridge^7: ^3StaminaEffect^7() ^2activated")
staminaEffect = true staminaEffect = true
local startStamina = (data[1] / 1000) local startStamina = (data[1] / 1000)
SetRunSprintMultiplierForPlayer(PlayerId(), 1.49) SetRunSprintMultiplierForPlayer(PlayerId(), 1.49)
while startStamina > 0 do while startStamina > 0 do
Wait(1000) Wait(1000)
if math.random(5, 100) < 10 then RestorePlayerStamina(PlayerId(), data[2]) end if math.random(5, 100) < 10 then RestorePlayerStamina(PlayerId(), data[2]) end
startStamina -= 1 startStamina -= 1
if math.random(5, 100) < 51 then end if math.random(5, 100) < 51 then end
end end
startStamina = 0 startStamina = 0
SetRunSprintMultiplierForPlayer(PlayerId(), 1.0) SetRunSprintMultiplierForPlayer(PlayerId(), 1.0)
staminaEffect = false staminaEffect = false
debugPrint("^5Bridge^7: ^3StaminaEffect^7() ^2stopped") debugPrint("^5Bridge^7: ^3StaminaEffect^7() ^2stopped")
end end
function StopEffects() -- Used to clear up any effects stuck on screen function StopEffects() -- Used to clear up any effects stuck on screen
debugPrint("^5Bridge^7: ^2All screen effects stopped") debugPrint("^5Bridge^7: ^2All screen effects stopped")
ShakeGameplayCam('DRUNK_SHAKE', 0.0) ShakeGameplayCam('DRUNK_SHAKE', 0.0)
SetPedToRagdoll(PlayerPedId(), 5000, 1000, 1, 0, 0, 0) SetPedToRagdoll(PlayerPedId(), 5000, 1000, 1, 0, 0, 0)
ClearTimecycleModifier() ClearTimecycleModifier()
ResetScenarioTypesEnabled() ResetScenarioTypesEnabled()
ResetPedMovementClipset(PlayerPedId(), 0) ResetPedMovementClipset(PlayerPedId(), 0)
SetPedIsDrunk(PlayerPedId(), false) SetPedIsDrunk(PlayerPedId(), false)
SetPedMotionBlur(PlayerPedId(), false) SetPedMotionBlur(PlayerPedId(), false)
SetNightvision(false) SetNightvision(false)
SetSeethrough(false) SetSeethrough(false)
AnimpostfxStop("DrugsMichaelAliensFightIn") AnimpostfxStop("DrugsMichaelAliensFightIn")
AnimpostfxStop("DrugsMichaelAliensFight") AnimpostfxStop("DrugsMichaelAliensFight")
AnimpostfxStop("DrugsMichaelAliensFightOut") AnimpostfxStop("DrugsMichaelAliensFightOut")
AnimpostfxStop("DrugsTrevorClownsFight") AnimpostfxStop("DrugsTrevorClownsFight")
AnimpostfxStop("DrugsTrevorClownsFightIn") AnimpostfxStop("DrugsTrevorClownsFightIn")
AnimpostfxStop("DrugsTrevorClownsFightOut") AnimpostfxStop("DrugsTrevorClownsFightOut")
AnimpostfxStop('RaceTurbo') AnimpostfxStop('RaceTurbo')
AnimpostfxStop('FocusIn') AnimpostfxStop('FocusIn')
AnimpostfxStop('Rampage') AnimpostfxStop('Rampage')
end end

File diff suppressed because it is too large Load Diff

View File

@@ -1,156 +1,191 @@
-- INPUT -- -- INPUT --
-- Multiscript input script function to create simple input text boxes -- -- Multiscript input script function to create simple input text boxes --
--- Creates a simple input dialog compatible with multiple menu systems. --- Creates a simple input dialog compatible with multiple menu systems.
--- ---
--- This function generates input dialogs for different frameworks (OX, QB, GTA) based on the configuration. --- This function generates input dialogs for different frameworks (OX, QB, GTA) based on the configuration.
--- It supports various input types such as radio buttons, numbers, text, and select dropdowns. --- It supports various input types such as radio buttons, numbers, text, and select dropdowns.
--- ---
---@param title string The title/header of the input dialog. ---@param title string The title/header of the input dialog.
---@param opts table A table containing input options. Each option should have a `type` and other relevant fields based on the type. ---@param opts table A table containing input options. Each option should have a `type` and other relevant fields based on the type.
--- - **type** (`string`): The type of input. Supported types: "radio", "number", "text", "select". --- - **type** (`string`): The type of input. Supported types: "radio", "number", "text", "select".
--- - **label** (`string`, optional): The label for the input (used for "radio" and "select" types in OX). --- - **label** (`string`, optional): The label for the input (used for "radio" and "select" types in OX).
--- - **text** (`string`, optional): The text prompt for the input. --- - **text** (`string`, optional): The text prompt for the input.
--- - **name** (`string`): The identifier name for the input. --- - **name** (`string`): The identifier name for the input.
--- - **isRequired** (`boolean`, optional): Whether the input is required. --- - **isRequired** (`boolean`, optional): Whether the input is required.
--- - **default** (`any`, optional): The default value for the input. --- - **default** (`any`, optional): The default value for the input.
--- - **options** (`table`, optional): A table of options for "radio" and "select" types. --- - **options** (`table`, optional): A table of options for "radio" and "select" types.
--- - **min** (`number`, optional): The minimum value (used for "select" type). --- - **min** (`number`, optional): The minimum value (used for "select" type).
--- - **max** (`number`, optional): The maximum value (used for "number" and "select" types). --- - **max** (`number`, optional): The maximum value (used for "number" and "select" types).
--- - **txt** (`string`, optional): Additional text or description for the input. --- - **txt** (`string`, optional): Additional text or description for the input.
--- ---
---@return table|nil table Returns the user's input as a table if the dialog is submitted, otherwise returns `nil`. ---@return table|nil table Returns the user's input as a table if the dialog is submitted, otherwise returns `nil`.
--- ---
---@usage ---@usage
--- ```lua --- ```lua
--- local userInput = createInput("Enter Details", { --- local userInput = createInput("Enter Details", {
--- { type = "text", text = "Name", name = "playerName", isRequired = true }, --- { type = "text", text = "Name", name = "playerName", isRequired = true },
--- { type = "number", text = "Age", name = "playerAge", min = 18, max = 99 }, --- { type = "number", text = "Age", name = "playerAge", min = 18, max = 99 },
--- { type = "radio", label = "Gender", name = "playerGender", options = { --- { type = "radio", label = "Gender", name = "playerGender", options = {
--- { text = "Male", value = "male" }, --- { text = "Male", value = "male" },
--- { text = "Female", value = "female" }, --- { text = "Female", value = "female" },
--- { text = "Other", value = "other" }, --- { text = "Other", value = "other" },
--- }}, --- }},
--- }) --- })
--- ``` --- ```
function createInput(title, opts) function createInput(title, opts)
local dialog = nil local dialog = nil
local options = {} local options = {}
if Config.System.Menu == "ox" then if Config.System.Menu == "ox" then
for i = 1, #opts do for i = 1, #opts do
if opts[i].type == "radio" then if opts[i].type == "radio" then
-- Convert radio options to select type for OX -- Convert radio options to select type for OX
for k in pairs(opts[i].options) do for k in pairs(opts[i].options) do
opts[i].options[k].label = opts[i].options[k].text opts[i].options[k].label = opts[i].options[k].text
end end
options[i] = { options[i] = {
type = "select", type = "select",
isRequired = opts[i].isRequired, isRequired = opts[i].isRequired,
label = opts[i].label or opts[i].text, label = opts[i].label or opts[i].text,
name = opts[i].name, name = opts[i].name,
default = opts[i].default or opts[i].options[1].value, default = opts[i].default or opts[i].options[1].value,
options = opts[i].options, options = opts[i].options,
} }
end end
if opts[i].type == "number" then if opts[i].type == "number" then
options[i] = { options[i] = {
type = "number", type = "number",
label = opts[i].text..(opts[i].txt and " - "..opts[i].txt or ""), label = (opts[i].label or opts[i].text)..(opts[i].txt and " - "..opts[i].txt or ""),
isRequired = opts[i].isRequired, isRequired = opts[i].isRequired,
name = opts[i].name, name = opts[i].name,
options = opts[i].options, options = opts[i].options,
} }
end end
if opts[i].type == "text" then if opts[i].type == "text" then
options[i] = { options[i] = {
type = "input", type = "input",
label = opts[i].text..(opts[i].txt and " - "..opts[i].txt or ""), label = opts[i].text..(opts[i].txt and " - "..opts[i].txt or ""),
default = opts[i].default, default = opts[i].default,
isRequired = opts[i].isRequired, isRequired = opts[i].isRequired,
} }
end end
if opts[i].type == "select" then if opts[i].type == "select" then
options[i] = { options[i] = {
type = "select", type = "select",
label = opts[i].text..(opts[i].txt and " - "..opts[i].txt or ""), label = opts[i].text..(opts[i].txt and " - "..opts[i].txt or ""),
isRequired = opts[i].isRequired, isRequired = opts[i].isRequired,
name = opts[i].name, name = opts[i].name,
options = opts[i].options, options = opts[i].options,
min = opts[i].min, min = opts[i].min,
max = opts[i].max, max = opts[i].max,
default = opts[i].default, default = opts[i].default,
} }
end end
end end
dialog = exports[OXLibExport]:inputDialog(title, options) dialog = exports[OXLibExport]:inputDialog(title, options)
return dialog return dialog
end elseif Config.System.Menu == "qb" then
dialog = exports['qb-input']:ShowInput({ header = title, submitText = "Accept", inputs = opts })
if Config.System.Menu == "qb" then return dialog
dialog = exports['qb-input']:ShowInput({ header = title, submitText = "Accept", inputs = opts }) elseif Config.System.Menu == "gta" then
return dialog WarMenu.CreateMenu(tostring(opts),
end title,
" ",
if Config.System.Menu == "gta" then {
WarMenu.CreateMenu(tostring(opts), titleColor = { 222, 255, 255 },
title, maxOptionCountOnScreen = 15,
" ", width = 0.25,
{ x = 0.7,
titleColor = { 222, 255, 255 }, })
maxOptionCountOnScreen = 15, if WarMenu.IsAnyMenuOpened() then return end
width = 0.25, WarMenu.OpenMenu(tostring(opts))
x = 0.7,
}) local close = true
if WarMenu.IsAnyMenuOpened() then return end local _comboBoxItems = {}
WarMenu.OpenMenu(tostring(opts)) local _comboBoxIndex = { 1, 1 }
local close = true while true do
local _comboBoxItems = {} if WarMenu.Begin(tostring(opts)) then
local _comboBoxIndex = { 1, 1 } for i = 1, #opts do
if opts[i].type == "radio" then
while true do for k in pairs(opts[i].options) do
if WarMenu.Begin(tostring(opts)) then if not _comboBoxItems[i] then _comboBoxItems[i] = {} end
for i = 1, #opts do _comboBoxItems[i][k] = opts[i].options[k].text
if opts[i].type == "radio" then end
for k in pairs(opts[i].options) do local _, comboBoxIndex = WarMenu.ComboBox(opts[i].label, _comboBoxItems[i], _comboBoxIndex[i])
if not _comboBoxItems[i] then _comboBoxItems[i] = {} end if _comboBoxIndex[i] ~= comboBoxIndex then
_comboBoxItems[i][k] = opts[i].options[k].text _comboBoxIndex[i] = comboBoxIndex
end end
local _, comboBoxIndex = WarMenu.ComboBox(opts[i].label, _comboBoxItems[i], _comboBoxIndex[i]) end
if _comboBoxIndex[i] ~= comboBoxIndex then if opts[i].type == "number" then
_comboBoxIndex[i] = comboBoxIndex for b = 1, opts[i].max do
end if not _comboBoxItems[i] then _comboBoxItems[i] = {} end
end _comboBoxItems[i][b] = b
if opts[i].type == "number" then end
for b = 1, opts[i].max do local _, comboBoxIndex = WarMenu.ComboBox(opts[i].text, _comboBoxItems[i], _comboBoxIndex[i])
if not _comboBoxItems[i] then _comboBoxItems[i] = {} end if _comboBoxIndex[i] ~= comboBoxIndex then
_comboBoxItems[i][b] = b _comboBoxIndex[i] = comboBoxIndex
end end
local _, comboBoxIndex = WarMenu.ComboBox(opts[i].text, _comboBoxItems[i], _comboBoxIndex[i]) end
if _comboBoxIndex[i] ~= comboBoxIndex then end
_comboBoxIndex[i] = comboBoxIndex local pressed = WarMenu.Button("Pay")
end if pressed then
end WarMenu.CloseMenu()
end close = false
local pressed = WarMenu.Button("Pay") local result = {}
if pressed then for i = 1, #_comboBoxIndex do
WarMenu.CloseMenu() result[i] = _comboBoxItems[i][_comboBoxIndex[i]]
close = false end
local result = {} return result
for i = 1, #_comboBoxIndex do end
result[i] = _comboBoxItems[i][_comboBoxIndex[i]] WarMenu.End()
end else
return result return
end end
WarMenu.End() if not WarMenu.IsAnyMenuOpened() and close then
else if data.onExit then data.onExit() end
return end
end Wait(0)
if not WarMenu.IsAnyMenuOpened() and close then end
if data.onExit then data.onExit() end elseif Config.System.Menu == "esx" then -- horrible input dialog, not even worth using, get OX
end
Wait(0) local results = {}
end for i, opt in ipairs(opts) do
end local prompt = opt.text or opt.label or "Enter value"
-- For radio/select types, append available options in the prompt.
if (opt.type == "radio" or opt.type == "select") and opt.options then
local choices = ""
for j, choice in ipairs(opt.options) do
choices = choices .. choice.text .. " (" .. tostring(choice.value) .. ")"
if j < #opt.options then choices = choices .. ", " end
end
prompt = prompt .. " [" .. choices .. "]"
elseif opt.type == "number" then
prompt = prompt .. " (number between " .. (opt.min or 0) .. " and " .. (opt.max or 100) .. ")"
end
local value = nil
ESX.UI.Menu.Open('dialog', getScript(), 'input_' .. i, {
title = prompt
}, function(data, menu)
value = data.value
menu.close()
end, function(data, menu)
menu.close()
end)
-- Wait until the player submits a value.
while value == nil do
Wait(0)
end
-- Convert to a number if needed.
if opt.type == "number" then
value = tonumber(value)
end
results[opt.name or i] = value
end
return results
end
end end

View File

@@ -1,442 +1,442 @@
isCat, isDog, isBigDog, isSmallDog, isCoyote, isAnimal = false, false, false, false, false, false isCat, isDog, isBigDog, isSmallDog, isCoyote, isAnimal = false, false, false, false, false, false
if not isServer() then if not isServer() then
onPlayerLoaded(function() onPlayerLoaded(function()
Wait(2000) Wait(2000)
isCat, isDog, isBigDog, isSmallDog, isCoyote = false, false, false, false, false isCat, isDog, isBigDog, isSmallDog, isCoyote = false, false, false, false, false
isPedAnimal() isPedAnimal()
if isAnimal then if isAnimal then
local ped = PlayerPedId() local ped = PlayerPedId()
local pedModel = GetEntityModel(ped) local pedModel = GetEntityModel(ped)
isCat = (isCat(ped) or pedModel == `ft-raccoon`) and (pedModel ~= `ft-sphynx`) isCat = (isCat(ped) or pedModel == `ft-raccoon`) and (pedModel ~= `ft-sphynx`)
isDog, isBigDog = isDog(ped) isDog, isBigDog = isDog(ped)
isSmallDog = not isBigDog isSmallDog = not isBigDog
if isDog and pedModel == `a_c_coyote` then isDog = false end if isDog and pedModel == `a_c_coyote` then isDog = false end
isCoyote = (pedModel == `ft-sphynx` or pedModel == `a_c_coyote`) isCoyote = (pedModel == `ft-sphynx` or pedModel == `a_c_coyote`)
if pedModel == `ft-capmonkey2` then isDog = true end if pedModel == `ft-capmonkey2` then isDog = true end
end end
end, true) end, true)
--- Determines if a given Ped is classified as an animal. --- Determines if a given Ped is classified as an animal.
--- ---
--- This function checks whether the specified Ped (or the player's Ped if none is provided) --- This function checks whether the specified Ped (or the player's Ped if none is provided)
--- is listed within the predefined `AnimalPeds` tables. It iterates through all animal types --- is listed within the predefined `AnimalPeds` tables. It iterates through all animal types
--- to verify if the Ped's model hash matches any known animal models. --- to verify if the Ped's model hash matches any known animal models.
--- ---
---@param ped number|nil Optional. The Ped entity to check. Defaults to the player's Ped (`PlayerPedId()`). ---@param ped number|nil Optional. The Ped entity to check. Defaults to the player's Ped (`PlayerPedId()`).
--- ---
---@return boolean `true` if the Ped is an animal, otherwise `false`. ---@return boolean `true` if the Ped is an animal, otherwise `false`.
--- ---
--- @usage --- @usage
--- ```lua --- ```lua
--- local isPlayerAnimal = isAnimal() --- local isPlayerAnimal = isAnimal()
--- local isSpecificPedAnimal = isAnimal(somePedEntity) --- local isSpecificPedAnimal = isAnimal(somePedEntity)
--- ``` --- ```
function isPedAnimal(ped) function isPedAnimal(ped)
local PedModel = GetEntityModel(ped or PlayerPedId()) local PedModel = GetEntityModel(ped or PlayerPedId())
for _, animalTypeTable in pairs(AnimalPeds) do for _, animalTypeTable in pairs(AnimalPeds) do
for animalModelHash, _ in pairs(animalTypeTable) do for animalModelHash, _ in pairs(animalTypeTable) do
if PedModel == animalModelHash then if PedModel == animalModelHash then
isAnimal = true isAnimal = true
break break
end end
end end
if isAnimal then if isAnimal then
debugPrint("^6Debug^7: ^2Ped is Animal^1") debugPrint("^6Debug^7: ^2Ped is Animal^1")
break break
end end
end end
return isAnimal return isAnimal
end end
--- Checks if a given Ped is classified specifically as a cat. --- Checks if a given Ped is classified specifically as a cat.
--- ---
--- This function verifies whether the specified Ped (or the player's Ped if none is provided) --- This function verifies whether the specified Ped (or the player's Ped if none is provided)
--- matches any of the model hashes listed under `AnimalPeds.CatPeds`. It returns `true` if a match is found. --- matches any of the model hashes listed under `AnimalPeds.CatPeds`. It returns `true` if a match is found.
--- ---
---@param ped number|nil Optional. The Ped entity to check. Defaults to the player's Ped (`PlayerPedId()`). ---@param ped number|nil Optional. The Ped entity to check. Defaults to the player's Ped (`PlayerPedId()`).
--- ---
---@return boolean `true` if the Ped is a cat, otherwise `false`. ---@return boolean `true` if the Ped is a cat, otherwise `false`.
--- ---
---@usage ---@usage
--- ```lua --- ```lua
--- if isCat() then --- if isCat() then
--- print("Player is a cat!") --- print("Player is a cat!")
--- end --- end
--- ---
--- local anotherPed = GetPedInVehicleSeat(vehicle, -1) --- local anotherPed = GetPedInVehicleSeat(vehicle, -1)
--- if isCat(anotherPed) then --- if isCat(anotherPed) then
--- print("Driver is a cat!") --- print("Driver is a cat!")
--- end --- end
--- ``` --- ```
function isCat(ped) function isCat(ped)
local PedModel = GetEntityModel(ped or PlayerPedId()) local PedModel = GetEntityModel(ped or PlayerPedId())
for k, v in pairs(AnimalPeds.CatPeds) do for k, v in pairs(AnimalPeds.CatPeds) do
if PedModel == k then if PedModel == k then
return true return true
end end
end end
return false return false
end end
--- Determines if a given Ped is classified as a dog and identifies its size category. --- Determines if a given Ped is classified as a dog and identifies its size category.
--- ---
--- This function checks whether the specified Ped (or the player's Ped if none is provided) --- This function checks whether the specified Ped (or the player's Ped if none is provided)
--- matches any model hashes listed under `AnimalPeds.BigDogs` or `AnimalPeds.SmallDogs`. It returns --- matches any model hashes listed under `AnimalPeds.BigDogs` or `AnimalPeds.SmallDogs`. It returns
--- two values: the first indicates if the Ped is a dog, and the second specifies whether it's a --- two values: the first indicates if the Ped is a dog, and the second specifies whether it's a
--- large dog (`true`) or a small dog (`false`). If the Ped is not a dog, the second return value is `nil`. --- large dog (`true`) or a small dog (`false`). If the Ped is not a dog, the second return value is `nil`.
--- ---
---@param ped number|nil Optional. The Ped entity to check. Defaults to the player's Ped (`PlayerPedId()`). ---@param ped number|nil Optional. The Ped entity to check. Defaults to the player's Ped (`PlayerPedId()`).
--- ---
---@return boolean, boolean|nil Returns `true` and `true` if the Ped is a big dog, ---@return boolean, boolean|nil Returns `true` and `true` if the Ped is a big dog,
--- `true` and `false` if it's a small dog, --- `true` and `false` if it's a small dog,
--- or `false` and `nil` if it's not a dog. --- or `false` and `nil` if it's not a dog.
--- ---
---@usage ---@usage
--- ```lua --- ```lua
--- local isDog, isBigDog = isDog() --- local isDog, isBigDog = isDog()
--- if isDog then --- if isDog then
--- if isBigDog then --- if isBigDog then
--- print("Player is a big dog!") --- print("Player is a big dog!")
--- else --- else
--- print("Player is a small dog!") --- print("Player is a small dog!")
--- end --- end
--- else --- else
--- print("Player is not a dog.") --- print("Player is not a dog.")
--- end --- end
--- ---
--- local somePed = GetPedInVehicleSeat(vehicle, 0) --- local somePed = GetPedInVehicleSeat(vehicle, 0)
--- local isPetDog, isLargeDog = isDog(somePed) --- local isPetDog, isLargeDog = isDog(somePed)
--- if isPetDog then --- if isPetDog then
--- if isLargeDog then --- if isLargeDog then
--- print("Passenger is a big dog!") --- print("Passenger is a big dog!")
--- else --- else
--- print("Passenger is a small dog!") --- print("Passenger is a small dog!")
--- end --- end
--- end --- end
--- ``` --- ```
function isDog(ped) function isDog(ped)
local PedModel = GetEntityModel(ped or PlayerPedId()) local PedModel = GetEntityModel(ped or PlayerPedId())
for k, v in pairs(AnimalPeds.BigDogs) do for k, v in pairs(AnimalPeds.BigDogs) do
if PedModel == k then if PedModel == k then
return true, true return true, true
end end
end end
for k, v in pairs(AnimalPeds.SmallDogs) do for k, v in pairs(AnimalPeds.SmallDogs) do
if PedModel == k then if PedModel == k then
return true, false return true, false
end end
end end
return false, nil return false, nil
end end
--- Retrieves a list of all animal model hashes. --- Retrieves a list of all animal model hashes.
--- ---
--- This function compiles and returns a flat table containing all model hashes --- This function compiles and returns a flat table containing all model hashes
--- from the various animal categories defined within the `AnimalPeds` table. --- from the various animal categories defined within the `AnimalPeds` table.
--- It's useful for iterating over or performing bulk operations on all animal models. --- It's useful for iterating over or performing bulk operations on all animal models.
--- ---
---@return table table A table containing all animal model hashes. ---@return table table A table containing all animal model hashes.
--- ---
---@usage ---@usage
--- ```lua --- ```lua
--- local allAnimalModels = getAnimalModels() --- local allAnimalModels = getAnimalModels()
--- for _, modelHash in ipairs(allAnimalModels) do --- for _, modelHash in ipairs(allAnimalModels) do
--- print("Animal Model Hash:", modelHash) --- print("Animal Model Hash:", modelHash)
--- end --- end
--- ``` --- ```
function getAnimalModels() function getAnimalModels()
local animalTable = {} local animalTable = {}
for k in pairs(AnimalPeds) do for k in pairs(AnimalPeds) do
for v in pairs(AnimalPeds[k]) do for v in pairs(AnimalPeds[k]) do
animalTable[#animalTable+1] = v animalTable[#animalTable+1] = v
end end
end end
return animalTable return animalTable
end end
end end
AnimalPeds = { AnimalPeds = {
BigDogs = { BigDogs = {
-- Big Dogs -- Big Dogs
[`a_c_chop`] = { [`a_c_chop`] = {
deathAnim = "dead_right", deathDict = "creatures@chop@move", deathAnim = "dead_right", deathDict = "creatures@chop@move",
exitAnim = "getup_r", exitDict = "creatures@chop@getup", exitAnim = "getup_r", exitDict = "creatures@chop@getup",
sitAnim = "sit", sitDict = "creatures@rottweiler@in_vehicle@std_car" sitAnim = "sit", sitDict = "creatures@rottweiler@in_vehicle@std_car"
}, },
[`a_c_k9`] = { [`a_c_k9`] = {
deathAnim = "dead_right", deathDict = "creatures@chop@move", deathAnim = "dead_right", deathDict = "creatures@chop@move",
exitAnim = "getup_r", exitDict = "creatures@chop@getup", exitAnim = "getup_r", exitDict = "creatures@chop@getup",
sitAnim = "sit", sitDict = "creatures@rottweiler@in_vehicle@std_car" sitAnim = "sit", sitDict = "creatures@rottweiler@in_vehicle@std_car"
}, },
[`a_c_husky`] = { [`a_c_husky`] = {
deathAnim = "dead_right", deathDict = "creatures@rottweiler@move", deathAnim = "dead_right", deathDict = "creatures@rottweiler@move",
exitAnim = "getup_r", exitDict = "creatures@rottweiler@getup", exitAnim = "getup_r", exitDict = "creatures@rottweiler@getup",
sitAnim = "sit", sitDict = "creatures@rottweiler@in_vehicle@std_car" sitAnim = "sit", sitDict = "creatures@rottweiler@in_vehicle@std_car"
}, },
[`a_c_retriever`] = { [`a_c_retriever`] = {
deathAnim = "dead_right", deathDict = "creatures@rottweiler@move", deathAnim = "dead_right", deathDict = "creatures@rottweiler@move",
exitAnim = "getup_r", exitDict = "creatures@rottweiler@getup", exitAnim = "getup_r", exitDict = "creatures@rottweiler@getup",
sitAnim = "sit", sitDict = "creatures@rottweiler@in_vehicle@std_car" sitAnim = "sit", sitDict = "creatures@rottweiler@in_vehicle@std_car"
}, },
[`a_c_shepherd`] = { [`a_c_shepherd`] = {
deathAnim = "dead_right", deathDict = "creatures@rottweiler@move", deathAnim = "dead_right", deathDict = "creatures@rottweiler@move",
exitAnim = "getup_r", exitDict = "creatures@rottweiler@getup", exitAnim = "getup_r", exitDict = "creatures@rottweiler@getup",
sitAnim = "sit", sitDict = "creatures@rottweiler@in_vehicle@std_car" sitAnim = "sit", sitDict = "creatures@rottweiler@in_vehicle@std_car"
}, },
[`a_c_rottweiler`] = { [`a_c_rottweiler`] = {
deathAnim = "dead_right", deathDict = "creatures@rottweiler@move", deathAnim = "dead_right", deathDict = "creatures@rottweiler@move",
exitAnim = "getup_r", exitDict = "creatures@rottweiler@getup", exitAnim = "getup_r", exitDict = "creatures@rottweiler@getup",
sitAnim = "sit", sitDict = "creatures@rottweiler@in_vehicle@std_car" sitAnim = "sit", sitDict = "creatures@rottweiler@in_vehicle@std_car"
}, },
[`ft-aushep`] = { [`ft-aushep`] = {
deathAnim = "dead_right", deathDict = "creatures@rottweiler@move", deathAnim = "dead_right", deathDict = "creatures@rottweiler@move",
exitAnim = "getup_r", exitDict = "creatures@rottweiler@getup", exitAnim = "getup_r", exitDict = "creatures@rottweiler@getup",
sitAnim = "sit", sitDict = "creatures@rottweiler@in_vehicle@std_car" sitAnim = "sit", sitDict = "creatures@rottweiler@in_vehicle@std_car"
}, },
[`golden_r`] = { [`golden_r`] = {
deathAnim = "dead_right", deathDict = "creatures@rottweiler@move", deathAnim = "dead_right", deathDict = "creatures@rottweiler@move",
exitAnim = "getup_r", exitDict = "creatures@rottweiler@getup", exitAnim = "getup_r", exitDict = "creatures@rottweiler@getup",
sitAnim = "sit", sitDict = "creatures@rottweiler@in_vehicle@std_car" sitAnim = "sit", sitDict = "creatures@rottweiler@in_vehicle@std_car"
}, },
[`ft-dobermanv2`] = { [`ft-dobermanv2`] = {
deathAnim = "dead_right", deathDict = "creatures@rottweiler@move", deathAnim = "dead_right", deathDict = "creatures@rottweiler@move",
exitAnim = "getup_r", exitDict = "creatures@rottweiler@getup", exitAnim = "getup_r", exitDict = "creatures@rottweiler@getup",
sitAnim = "sit", sitDict = "creatures@rottweiler@in_vehicle@std_car" sitAnim = "sit", sitDict = "creatures@rottweiler@in_vehicle@std_car"
}, },
[`doberman`] = { [`doberman`] = {
deathAnim = "dead_right", deathDict = "creatures@rottweiler@move", deathAnim = "dead_right", deathDict = "creatures@rottweiler@move",
exitAnim = "getup_r", exitDict = "creatures@rottweiler@getup", exitAnim = "getup_r", exitDict = "creatures@rottweiler@getup",
sitAnim = "sit", sitDict = "creatures@rottweiler@in_vehicle@std_car" sitAnim = "sit", sitDict = "creatures@rottweiler@in_vehicle@std_car"
}, },
[`ft-gs`] = { [`ft-gs`] = {
deathAnim = "dead_right", deathDict = "creatures@rottweiler@move", deathAnim = "dead_right", deathDict = "creatures@rottweiler@move",
exitAnim = "getup_r", exitDict = "creatures@rottweiler@getup", exitAnim = "getup_r", exitDict = "creatures@rottweiler@getup",
sitAnim = "sit", sitDict = "creatures@rottweiler@in_vehicle@std_car" sitAnim = "sit", sitDict = "creatures@rottweiler@in_vehicle@std_car"
}, },
[`k9_husky`] = { [`k9_husky`] = {
deathAnim = "dead_right", deathDict = "creatures@rottweiler@move", deathAnim = "dead_right", deathDict = "creatures@rottweiler@move",
exitAnim = "getup_r", exitDict = "creatures@rottweiler@getup", exitAnim = "getup_r", exitDict = "creatures@rottweiler@getup",
sitAnim = "sit", sitDict = "creatures@rottweiler@in_vehicle@std_car" sitAnim = "sit", sitDict = "creatures@rottweiler@in_vehicle@std_car"
}, },
[`ft-bloodhound`] = { [`ft-bloodhound`] = {
deathAnim = "dead_right", deathDict = "creatures@rottweiler@move", deathAnim = "dead_right", deathDict = "creatures@rottweiler@move",
exitAnim = "getup_r", exitDict = "creatures@rottweiler@getup", exitAnim = "getup_r", exitDict = "creatures@rottweiler@getup",
sitAnim = "sit", sitDict = "creatures@rottweiler@in_vehicle@std_car" sitAnim = "sit", sitDict = "creatures@rottweiler@in_vehicle@std_car"
}, },
[`bernard`] = { [`bernard`] = {
deathAnim = "dead_right", deathDict = "creatures@rottweiler@move", deathAnim = "dead_right", deathDict = "creatures@rottweiler@move",
exitAnim = "getup_r", exitDict = "creatures@rottweiler@getup", exitAnim = "getup_r", exitDict = "creatures@rottweiler@getup",
sitAnim = "sit", sitDict = "creatures@rottweiler@in_vehicle@std_car" sitAnim = "sit", sitDict = "creatures@rottweiler@in_vehicle@std_car"
}, },
[`ft-pterrier`] = { [`ft-pterrier`] = {
deathAnim = "dead_right", deathDict = "creatures@rottweiler@move", deathAnim = "dead_right", deathDict = "creatures@rottweiler@move",
exitAnim = "getup_r", exitDict = "creatures@rottweiler@getup", exitAnim = "getup_r", exitDict = "creatures@rottweiler@getup",
sitAnim = "sit", sitDict = "creatures@rottweiler@in_vehicle@std_car" sitAnim = "sit", sitDict = "creatures@rottweiler@in_vehicle@std_car"
}, },
[`ft-labrador`] = { [`ft-labrador`] = {
deathAnim = "dead_right", deathDict = "creatures@rottweiler@move", deathAnim = "dead_right", deathDict = "creatures@rottweiler@move",
exitAnim = "getup_r", exitDict = "creatures@rottweiler@getup", exitAnim = "getup_r", exitDict = "creatures@rottweiler@getup",
sitAnim = "sit", sitDict = "creatures@rottweiler@in_vehicle@std_car" sitAnim = "sit", sitDict = "creatures@rottweiler@in_vehicle@std_car"
}, },
[`dane`] = { [`dane`] = {
deathAnim = "dead_right", deathDict = "creatures@rottweiler@move", deathAnim = "dead_right", deathDict = "creatures@rottweiler@move",
exitAnim = "getup_r", exitDict = "creatures@rottweiler@getup", exitAnim = "getup_r", exitDict = "creatures@rottweiler@getup",
sitAnim = "sit", sitDict = "creatures@rottweiler@in_vehicle@std_car" sitAnim = "sit", sitDict = "creatures@rottweiler@in_vehicle@std_car"
}, },
[`ft_malinois`] = { [`ft_malinois`] = {
deathAnim = "dead_right", deathDict = "creatures@rottweiler@move", deathAnim = "dead_right", deathDict = "creatures@rottweiler@move",
exitAnim = "getup_r", exitDict = "creatures@rottweiler@getup", exitAnim = "getup_r", exitDict = "creatures@rottweiler@getup",
sitAnim = "sit", sitDict = "creatures@rottweiler@in_vehicle@std_car" sitAnim = "sit", sitDict = "creatures@rottweiler@in_vehicle@std_car"
}, },
[`abdog`] = { [`abdog`] = {
deathAnim = "dead_right", deathDict = "creatures@rottweiler@move", deathAnim = "dead_right", deathDict = "creatures@rottweiler@move",
exitAnim = "getup_r", exitDict = "creatures@rottweiler@getup", exitAnim = "getup_r", exitDict = "creatures@rottweiler@getup",
sitAnim = "sit", sitDict = "creatures@rottweiler@in_vehicle@std_car" sitAnim = "sit", sitDict = "creatures@rottweiler@in_vehicle@std_car"
}, },
[`dalmatian`] = { [`dalmatian`] = {
deathAnim = "dead_right", deathDict = "creatures@rottweiler@move", deathAnim = "dead_right", deathDict = "creatures@rottweiler@move",
exitAnim = "getup_r", exitDict = "creatures@rottweiler@getup", exitAnim = "getup_r", exitDict = "creatures@rottweiler@getup",
sitAnim = "sit", sitDict = "creatures@rottweiler@in_vehicle@std_car" sitAnim = "sit", sitDict = "creatures@rottweiler@in_vehicle@std_car"
}, },
[`a_c_dalmatian`] = { [`a_c_dalmatian`] = {
deathAnim = "dead_right", deathDict = "creatures@rottweiler@move", deathAnim = "dead_right", deathDict = "creatures@rottweiler@move",
exitAnim = "getup_r", exitDict = "creatures@rottweiler@getup", exitAnim = "getup_r", exitDict = "creatures@rottweiler@getup",
sitAnim = "sit", sitDict = "creatures@rottweiler@in_vehicle@std_car" sitAnim = "sit", sitDict = "creatures@rottweiler@in_vehicle@std_car"
}, },
[`ft-boxer`] = { [`ft-boxer`] = {
deathAnim = "dead_right", deathDict = "creatures@rottweiler@move", deathAnim = "dead_right", deathDict = "creatures@rottweiler@move",
exitAnim = "getup_r", exitDict = "creatures@rottweiler@getup", exitAnim = "getup_r", exitDict = "creatures@rottweiler@getup",
sitAnim = "sit", sitDict = "creatures@rottweiler@in_vehicle@std_car" sitAnim = "sit", sitDict = "creatures@rottweiler@in_vehicle@std_car"
}, },
[`ft-bs`] = { [`ft-bs`] = {
deathAnim = "dead_right", deathDict = "creatures@rottweiler@move", deathAnim = "dead_right", deathDict = "creatures@rottweiler@move",
exitAnim = "getup_r", exitDict = "creatures@rottweiler@getup", exitAnim = "getup_r", exitDict = "creatures@rottweiler@getup",
sitAnim = "sit", sitDict = "creatures@rottweiler@in_vehicle@std_car" sitAnim = "sit", sitDict = "creatures@rottweiler@in_vehicle@std_car"
}, },
[`chowchow`] = { [`chowchow`] = {
deathAnim = "dead_right", deathDict = "creatures@rottweiler@move", deathAnim = "dead_right", deathDict = "creatures@rottweiler@move",
exitAnim = "getup_r", exitDict = "creatures@rottweiler@getup", exitAnim = "getup_r", exitDict = "creatures@rottweiler@getup",
sitAnim = "sit", sitDict = "creatures@rottweiler@in_vehicle@std_car" sitAnim = "sit", sitDict = "creatures@rottweiler@in_vehicle@std_car"
}, },
[`a_c_coyote`] = { [`a_c_coyote`] = {
deathAnim = "dead_right", deathDict = "creatures@coyote@move", deathAnim = "dead_right", deathDict = "creatures@coyote@move",
exitAnim = "getup_r", exitDict = "creatures@coyote@getup", exitAnim = "getup_r", exitDict = "creatures@coyote@getup",
sitAnim = "base", sitDict = "creatures@coyote@amb@world_coyote_howl@base" sitAnim = "base", sitDict = "creatures@coyote@amb@world_coyote_howl@base"
}, },
[`a_c_coyote_02`] = { [`a_c_coyote_02`] = {
deathAnim = "dead_right", deathDict = "creatures@coyote@move", deathAnim = "dead_right", deathDict = "creatures@coyote@move",
exitAnim = "getup_r", exitDict = "creatures@coyote@getup", exitAnim = "getup_r", exitDict = "creatures@coyote@getup",
sitAnim = "base", sitDict = "creatures@coyote@amb@world_coyote_howl@base" sitAnim = "base", sitDict = "creatures@coyote@amb@world_coyote_howl@base"
}, },
}, },
SmallDogs = { SmallDogs = {
-- Small Dogs -- Small Dogs
[`a_c_poodle`] = { [`a_c_poodle`] = {
deathAnim = "dead_right", deathDict = "creatures@pug@move", deathAnim = "dead_right", deathDict = "creatures@pug@move",
exitAnim = "getup_r", exitDict = "creatures@pug@getup", exitAnim = "getup_r", exitDict = "creatures@pug@getup",
sitAnim = "base", sitDict = "creatures@pug@amb@world_dog_sitting@base" sitAnim = "base", sitDict = "creatures@pug@amb@world_dog_sitting@base"
}, },
[`ft-chihuahua`] = { [`ft-chihuahua`] = {
deathAnim = "dead_right", deathDict = "creatures@pug@move", deathAnim = "dead_right", deathDict = "creatures@pug@move",
exitAnim = "getup_r", exitDict = "creatures@pug@getup", exitAnim = "getup_r", exitDict = "creatures@pug@getup",
sitAnim = "base", sitDict = "creatures@pug@amb@world_dog_sitting@base" sitAnim = "base", sitDict = "creatures@pug@amb@world_dog_sitting@base"
}, },
[`a_c_pug`] = { [`a_c_pug`] = {
deathAnim = "dead_right", deathDict = "creatures@pug@move", deathAnim = "dead_right", deathDict = "creatures@pug@move",
exitAnim = "getup_r", exitDict = "creatures@pug@getup", exitAnim = "getup_r", exitDict = "creatures@pug@getup",
sitAnim = "base", sitDict = "creatures@pug@amb@world_dog_sitting@base" sitAnim = "base", sitDict = "creatures@pug@amb@world_dog_sitting@base"
}, },
[`a_c_pug_02`] = { [`a_c_pug_02`] = {
deathAnim = "dead_right", deathDict = "creatures@pug@move", deathAnim = "dead_right", deathDict = "creatures@pug@move",
exitAnim = "getup_r", exitDict = "creatures@pug@getup", exitAnim = "getup_r", exitDict = "creatures@pug@getup",
sitAnim = "base", sitDict = "creatures@pug@amb@world_dog_sitting@base" sitAnim = "base", sitDict = "creatures@pug@amb@world_dog_sitting@base"
}, },
[`a_c_westy`] = { [`a_c_westy`] = {
deathAnim = "dead_right", deathDict = "creatures@pug@move", deathAnim = "dead_right", deathDict = "creatures@pug@move",
exitAnim = "getup_r", exitDict = "creatures@pug@getup", exitAnim = "getup_r", exitDict = "creatures@pug@getup",
sitAnim = "base", sitDict = "creatures@pug@amb@world_dog_sitting@base" sitAnim = "base", sitDict = "creatures@pug@amb@world_dog_sitting@base"
}, },
[`ft-pretriever`] = { [`ft-pretriever`] = {
deathAnim = "dead_right", deathDict = "creatures@pug@move", deathAnim = "dead_right", deathDict = "creatures@pug@move",
exitAnim = "getup_r", exitDict = "creatures@pug@getup", exitAnim = "getup_r", exitDict = "creatures@pug@getup",
sitAnim = "base", sitDict = "creatures@pug@amb@world_dog_sitting@base" sitAnim = "base", sitDict = "creatures@pug@amb@world_dog_sitting@base"
}, },
[`ft-shepk9`] = { [`ft-shepk9`] = {
deathAnim = "dead_right", deathDict = "creatures@pug@move", deathAnim = "dead_right", deathDict = "creatures@pug@move",
exitAnim = "getup_r", exitDict = "creatures@pug@getup", exitAnim = "getup_r", exitDict = "creatures@pug@getup",
sitAnim = "base", sitDict = "creatures@pug@amb@world_dog_sitting@base" sitAnim = "base", sitDict = "creatures@pug@amb@world_dog_sitting@base"
}, },
}, },
CatPeds = { CatPeds = {
-- Cat -- Cat
[`bshorthair`] = { [`bshorthair`] = {
deathAnim = "dead_right", deathDict = "creatures@cat@move", deathAnim = "dead_right", deathDict = "creatures@cat@move",
exitAnim = "getup_r", exitDict = "creatures@cat@getup", exitAnim = "getup_r", exitDict = "creatures@cat@getup",
sitAnim = "base", sitDict = "creatures@cat@amb@world_cat_sleeping_ledge@base" sitAnim = "base", sitDict = "creatures@cat@amb@world_cat_sleeping_ledge@base"
}, },
[`a_c_cat_01`] = { [`a_c_cat_01`] = {
deathAnim = "dead_right", deathDict = "creatures@cat@move", deathAnim = "dead_right", deathDict = "creatures@cat@move",
exitAnim = "getup_r", exitDict = "creatures@cat@getup", exitAnim = "getup_r", exitDict = "creatures@cat@getup",
sitAnim = "base", sitDict = "creatures@cat@amb@world_cat_sleeping_ledge@base" sitAnim = "base", sitDict = "creatures@cat@amb@world_cat_sleeping_ledge@base"
}, },
[`ft-sphynx`] = { [`ft-sphynx`] = {
deathAnim = "dead_right", deathDict = "creatures@coyote@move", deathAnim = "dead_right", deathDict = "creatures@coyote@move",
exitAnim = "getup_r", exitDict = "creatures@coyote@getup", exitAnim = "getup_r", exitDict = "creatures@coyote@getup",
sitAnim = "base", sitDict = "creatures@coyote@amb@world_coyote_howl@base" sitAnim = "base", sitDict = "creatures@coyote@amb@world_coyote_howl@base"
}, },
}, },
OtherPeds = { OtherPeds = {
-- Other Animals -- Other Animals
[`ft-raccoon`] = { [`ft-raccoon`] = {
deathAnim = "dead_right", deathDict = "creatures@cat@move", deathAnim = "dead_right", deathDict = "creatures@cat@move",
exitAnim = "getup_r", exitDict = "creatures@cat@getup", exitAnim = "getup_r", exitDict = "creatures@cat@getup",
sitAnim = "base", sitDict = "creatures@cat@amb@world_cat_sleeping_ledge@base" sitAnim = "base", sitDict = "creatures@cat@amb@world_cat_sleeping_ledge@base"
}, },
[`a_c_hen`] = { [`a_c_hen`] = {
deathAnim = "dead_right", deathDict = "creatures@hen@move", deathAnim = "dead_right", deathDict = "creatures@hen@move",
exitAnim = "getup_r", exitDict = "creatures@hen@getup" exitAnim = "getup_r", exitDict = "creatures@hen@getup"
}, },
[`a_c_rabbit_01`] = { [`a_c_rabbit_01`] = {
deathAnim = "dead_right", deathDict = "creatures@rabbit@move", deathAnim = "dead_right", deathDict = "creatures@rabbit@move",
exitAnim = "getup_r", exitDict = "creatures@rabbit@getup", exitAnim = "getup_r", exitDict = "creatures@rabbit@getup",
sitAnim = "idle_c", sitDict = "creatures@coyote@amb@world_coyote_howl@base" sitAnim = "idle_c", sitDict = "creatures@coyote@amb@world_coyote_howl@base"
}, },
[`a_c_rabbit_02`] = { [`a_c_rabbit_02`] = {
deathAnim = "dead_right", deathDict = "creatures@rabbit@move", deathAnim = "dead_right", deathDict = "creatures@rabbit@move",
exitAnim = "getup_r", exitDict = "creatures@rabbit@getup", exitAnim = "getup_r", exitDict = "creatures@rabbit@getup",
sitAnim = "idle_c", sitDict = "creatures@coyote@amb@world_coyote_howl@base" sitAnim = "idle_c", sitDict = "creatures@coyote@amb@world_coyote_howl@base"
}, },
[`a_c_rat`] = { [`a_c_rat`] = {
deathAnim = "dead_right", deathDict = "creatures@rat@move", deathAnim = "dead_right", deathDict = "creatures@rat@move",
exitAnim = "getup_r", exitDict = "creatures@rat@getup" exitAnim = "getup_r", exitDict = "creatures@rat@getup"
}, },
[`a_c_deer`] = { [`a_c_deer`] = {
deathAnim = "dead_right", deathDict = "creatures@deer@move", deathAnim = "dead_right", deathDict = "creatures@deer@move",
exitAnim = "getup_r", exitDict = "creatures@deer@getup" exitAnim = "getup_r", exitDict = "creatures@deer@getup"
}, },
[`a_c_boar`] = { [`a_c_boar`] = {
deathAnim = "dead_right", deathDict = "creatures@boar@move", deathAnim = "dead_right", deathDict = "creatures@boar@move",
exitAnim = "getup_r", exitDict = "creatures@boar@getup" exitAnim = "getup_r", exitDict = "creatures@boar@getup"
}, },
[`a_c_boar_02`] = { [`a_c_boar_02`] = {
deathAnim = "dead_right", deathDict = "creatures@boar@move", deathAnim = "dead_right", deathDict = "creatures@boar@move",
exitAnim = "getup_r", exitDict = "creatures@boar@getup" exitAnim = "getup_r", exitDict = "creatures@boar@getup"
}, },
[`a_c_chicken`] = { [`a_c_chicken`] = {
deathAnim = "dead_right", deathDict = "creatures@chicken@move", deathAnim = "dead_right", deathDict = "creatures@chicken@move",
exitAnim = "getup_r", exitDict = "creatures@chicken@getup" exitAnim = "getup_r", exitDict = "creatures@chicken@getup"
}, },
[`a_c_pig`] = { [`a_c_pig`] = {
deathAnim = "dead_right", deathDict = "creatures@pig@move", deathAnim = "dead_right", deathDict = "creatures@pig@move",
exitAnim = "getup_r", exitDict = "creatures@pig@getup" exitAnim = "getup_r", exitDict = "creatures@pig@getup"
}, },
[`a_c_sharkhammer`] = { [`a_c_sharkhammer`] = {
deathAnim = "dead_right", deathDict = "creatures@sharkhammer@move", deathAnim = "dead_right", deathDict = "creatures@sharkhammer@move",
exitAnim = "getup_r", exitDict = "creatures@sharkhammer@getup" exitAnim = "getup_r", exitDict = "creatures@sharkhammer@getup"
}, },
[`a_c_sharktiger`] = { [`a_c_sharktiger`] = {
deathAnim = "dead_right", deathDict = "creatures@sharktiger@move", deathAnim = "dead_right", deathDict = "creatures@sharktiger@move",
exitAnim = "getup_r", exitDict = "creatures@sharktiger@getup" exitAnim = "getup_r", exitDict = "creatures@sharktiger@getup"
}, },
[`a_c_crow`] = { [`a_c_crow`] = {
deathAnim = "dead_down", deathDict = "creatures@crow@move", deathAnim = "dead_down", deathDict = "creatures@crow@move",
exitAnim = "nill", exitDict = "creatures@pug@move", -- no get up anim exitAnim = "nill", exitDict = "creatures@pug@move", -- no get up anim
}, },
[`a_c_pigeon`] = { [`a_c_pigeon`] = {
deathAnim = "dead_down", deathDict = "creatures@pigeon@move", deathAnim = "dead_down", deathDict = "creatures@pigeon@move",
exitAnim = "nill", exitDict = "creatures@pug@move", -- no get up anim exitAnim = "nill", exitDict = "creatures@pug@move", -- no get up anim
}, },
}, },
Monekys = { Monekys = {
[`ft-chimpanzee`] = { [`ft-chimpanzee`] = {
deathAnim = "dead", deathDict = "dead_a", deathAnim = "dead", deathDict = "dead_a",
exitAnim = "get_up@sat_on_floor@to_stand", exitDict = "getup_0" exitAnim = "get_up@sat_on_floor@to_stand", exitDict = "getup_0"
}, },
[`a_c_chimp`] = { [`a_c_chimp`] = {
deathAnim = "dead", deathDict = "dead_a", deathAnim = "dead", deathDict = "dead_a",
exitAnim = "get_up@sat_on_floor@to_stand", exitDict = "getup_0" exitAnim = "get_up@sat_on_floor@to_stand", exitDict = "getup_0"
}, },
[`a_c_chimp_02`] = { [`a_c_chimp_02`] = {
deathAnim = "dead", deathDict = "dead_a", deathAnim = "dead", deathDict = "dead_a",
exitAnim = "get_up@sat_on_floor@to_stand", exitDict = "getup_0" exitAnim = "get_up@sat_on_floor@to_stand", exitDict = "getup_0"
}, },
[`a_c_rhesus`] = { [`a_c_rhesus`] = {
deathAnim = "dead", deathDict = "dead_a", deathAnim = "dead", deathDict = "dead_a",
exitAnim = "get_up@sat_on_floor@to_stand", exitDict = "getup_0" exitAnim = "get_up@sat_on_floor@to_stand", exitDict = "getup_0"
}, },
[`ft-capmonkey2`] = { [`ft-capmonkey2`] = {
deathAnim = "dead_right", deathDict = "creatures@pug@move", deathAnim = "dead_right", deathDict = "creatures@pug@move",
exitAnim = "getup_r", exitDict = "creatures@pug@getup", exitAnim = "getup_r", exitDict = "creatures@pug@getup",
sitAnim = "base", sitDict = "creatures@pug@amb@world_dog_sitting@base" sitAnim = "base", sitDict = "creatures@pug@amb@world_dog_sitting@base"
}, },
} }
} }

File diff suppressed because it is too large Load Diff

View File

@@ -1,196 +1,196 @@
-- Global variable to track duty status -- Global variable to track duty status
onDuty = false onDuty = false
--- Scans the 'Jobs' and 'Gangs' tables to identify roles classified as Bosses. --- Scans the 'Jobs' and 'Gangs' tables to identify roles classified as Bosses.
--- ---
--- This function iterates through the specified role's grades within the `Jobs` or `Gangs` tables. --- This function iterates through the specified role's grades within the `Jobs` or `Gangs` tables.
--- It identifies which grades are marked as bosses (`isboss`) or have bank authorization (`bankAuth`). --- It identifies which grades are marked as bosses (`isboss`) or have bank authorization (`bankAuth`).
--- The function returns a table where each role maps to the lowest grade number that qualifies as a boss. --- The function returns a table where each role maps to the lowest grade number that qualifies as a boss.
--- ---
---@param role string The name of the job or gang role to check for boss grades. ---@param role string The name of the job or gang role to check for boss grades.
--- ---
---@return table table A table containing roles mapped to their respective boss grade numbers. ---@return table table A table containing roles mapped to their respective boss grade numbers.
--- ---
---@usage ---@usage
--- ```lua --- ```lua
--- local bosses = makeBossRoles("police") --- local bosses = makeBossRoles("police")
--- if bosses["police"] then --- if bosses["police"] then
--- print("Police role has a boss grade.") --- print("Police role has a boss grade.")
--- end --- end
--- ``` --- ```
function makeBossRoles(role) function makeBossRoles(role)
local boss = {} local boss = {}
local data = (Jobs and Jobs[role]) or (Gangs and Gangs[role]) local data = (Jobs and Jobs[role]) or (Gangs and Gangs[role])
if data then if data then
for grade, info in pairs(data.grades) do for grade, info in pairs(data.grades) do
if info.isboss or info.bankAuth then if info.isboss or info.bankAuth then
boss[role] = boss[role] and math.min(boss[role], tonumber(grade)) or tonumber(grade) boss[role] = boss[role] and math.min(boss[role], tonumber(grade)) or tonumber(grade)
end end
end end
end end
return boss return boss
end end
--- Checks if the player has a specific job and is on duty. --- Checks if the player has a specific job and is on duty.
--- ---
--- This function verifies whether the player possesses the specified job and, if applicable, --- This function verifies whether the player possesses the specified job and, if applicable,
--- whether they are currently on duty. It provides a notification if the player fails these checks. --- whether they are currently on duty. It provides a notification if the player fails these checks.
--- ---
---@param job string The name of the job or gang to check. ---@param job string The name of the job or gang to check.
--- ---
---@return boolean Returns `true` if the player has the job (and is on duty if required), otherwise `false`. ---@return boolean Returns `true` if the player has the job (and is on duty if required), otherwise `false`.
--- ---
---@usage ---@usage
--- ```lua --- ```lua
--- if jobCheck("mechanic") then --- if jobCheck("mechanic") then
--- -- Allow access to mechanic-related features --- -- Allow access to mechanic-related features
--- else --- else
--- -- Deny access or notify the player --- -- Deny access or notify the player
--- end --- end
--- ``` --- ```
function jobCheck(job) function jobCheck(job)
canDo = true canDo = true
if Jobs[job] then if Jobs[job] then
if not hasJob(job) or not onDuty then if not hasJob(job) or not onDuty then
triggerNotify(nil, Loc[Config.Lan].error["not_clockedin"]) triggerNotify(nil, Loc[Config.Lan].error["not_clockedin"])
canDo = false canDo = false
end end
end end
if Gangs[job] then if Gangs[job] then
if not hasJob(job) then if not hasJob(job) then
canDo = false canDo = false
end end
end end
return canDo return canDo
end end
--- Toggles the player's duty status. --- Toggles the player's duty status.
--- ---
--- This function switches the player's duty state between on-duty and off-duty. --- This function switches the player's duty state between on-duty and off-duty.
--- It integrates with QBcore's duty system if available; otherwise, it manually toggles the `onDuty` variable --- It integrates with QBcore's duty system if available; otherwise, it manually toggles the `onDuty` variable
--- and sends a notification to the player about their new duty status. --- and sends a notification to the player about their new duty status.
--- ---
---@usage ---@usage
--- ```lua --- ```lua
--- toggleDuty() --- toggleDuty()
--- -- Player will receive a notification indicating their new duty status --- -- Player will receive a notification indicating their new duty status
--- ``` --- ```
function toggleDuty() function toggleDuty()
if isStarted(QBExport) or isStarted(QBXExport) then if isStarted(QBExport) or isStarted(QBXExport) then
TriggerServerEvent("QBCore:ToggleDuty") TriggerServerEvent("QBCore:ToggleDuty")
else else
onDuty = not onDuty onDuty = not onDuty
if onDuty then if onDuty then
triggerNotify(nil, "Now on duty", "success") triggerNotify(nil, "Now on duty", "success")
else else
triggerNotify(nil, "Now off duty", "success") triggerNotify(nil, "Now off duty", "success")
end end
end end
end end
--- Initiates the hand-washing action for the player. --- Initiates the hand-washing action for the player.
--- ---
--- This function triggers an animation and a progress bar to simulate the player washing their hands. --- This function triggers an animation and a progress bar to simulate the player washing their hands.
--- Upon completion, it sends a success notification. If the action is canceled, it notifies the player of the cancellation. --- Upon completion, it sends a success notification. If the action is canceled, it notifies the player of the cancellation.
--- ---
---@param data table A table containing the coordinates where the hand-washing action takes place. ---@param data table A table containing the coordinates where the hand-washing action takes place.
--- - **coords** (`vector3`): The position where the hand-washing animation and camera are focused. --- - **coords** (`vector3`): The position where the hand-washing animation and camera are focused.
--- ---
---@return void ---@return void
--- ---
---@usage ---@usage
--- ```lua --- ```lua
--- washHands({ coords = vector3(200.0, 300.0, 40.0) }) --- washHands({ coords = vector3(200.0, 300.0, 40.0) })
--- -- Player will perform the hand-washing animation at the specified location --- -- Player will perform the hand-washing animation at the specified location
--- ``` --- ```
function washHands(data) local ped = PlayerPedId() function washHands(data) local ped = PlayerPedId()
lookEnt(data.coords) lookEnt(data.coords)
local cam = createTempCam(ped, data.coords) local cam = createTempCam(ped, data.coords)
if progressBar({ if progressBar({
label = Loc[Config.Lan].progressbar["progress_washing"], label = Loc[Config.Lan].progressbar["progress_washing"],
time = 5000, time = 5000,
cancel = true, cancel = true,
dict = "mp_arresting", dict = "mp_arresting",
anim = "a_uncuff", anim = "a_uncuff",
flag = 32, flag = 32,
icon = "fas fa-hand-holding-droplet", icon = "fas fa-hand-holding-droplet",
cam = cam cam = cam
}) then }) then
triggerNotify(nil, Loc[Config.Lan].success["washed_hands"], "success") triggerNotify(nil, Loc[Config.Lan].success["washed_hands"], "success")
else else
triggerNotify(nil, Loc[Config.Lan].error["cancel"], 'error') triggerNotify(nil, Loc[Config.Lan].error["cancel"], 'error')
end end
ClearPedTasks(ped) ClearPedTasks(ped)
end end
--- Handles the player's interaction with a toilet or urinal. --- Handles the player's interaction with a toilet or urinal.
--- ---
--- This function manages the animations and progress bars associated with using a toilet or urinal. --- This function manages the animations and progress bars associated with using a toilet or urinal.
--- Depending on whether the interaction is with a urinal (`data.urinal`), it plays the appropriate animation --- Depending on whether the interaction is with a urinal (`data.urinal`), it plays the appropriate animation
--- and triggers server events upon successful completion. If the action is canceled, it notifies the player. --- and triggers server events upon successful completion. If the action is canceled, it notifies the player.
--- ---
---@param data table A table containing data about the toilet interaction. ---@param data table A table containing data about the toilet interaction.
--- - **urinal** (`boolean`): Indicates whether the interaction is with a urinal (`true`) or a toilet (`false`). --- - **urinal** (`boolean`): Indicates whether the interaction is with a urinal (`true`) or a toilet (`false`).
--- - **sitcoords** (`vector4`): The coordinates and heading for the seating animation when using a toilet. --- - **sitcoords** (`vector4`): The coordinates and heading for the seating animation when using a toilet.
--- ---
---@usage ---@usage
--- ```lua --- ```lua
--- useToilet({ urinal = true }) --- useToilet({ urinal = true })
--- -- Player uses a urinal with corresponding animations and notifications --- -- Player uses a urinal with corresponding animations and notifications
--- ---
--- useToilet({ urinal = false, sitcoords = vector4(215.76, -810.12, 29.73, 90.0) }) --- useToilet({ urinal = false, sitcoords = vector4(215.76, -810.12, 29.73, 90.0) })
--- -- Player sits down to use a toilet with corresponding animations and notifications --- -- Player sits down to use a toilet with corresponding animations and notifications
--- ``` --- ```
function useToilet(data) function useToilet(data)
if data.urinal then if data.urinal then
if progressBar({ if progressBar({
label = "Using Urinal", label = "Using Urinal",
time = 5000, time = 5000,
cancel = true, cancel = true,
dict = "misscarsteal2peeing", dict = "misscarsteal2peeing",
anim = "peeing_loop", anim = "peeing_loop",
flag = 32 flag = 32
}) then }) then
TriggerServerEvent(getScript().."server:Urinal") TriggerServerEvent(getScript().."server:Urinal")
else else
lockInv(false) lockInv(false)
triggerNotify(nil, Loc[Config.Lan].error["cancelled"], 'error') triggerNotify(nil, Loc[Config.Lan].error["cancelled"], 'error')
end end
else else
TaskStartScenarioAtPosition(PlayerPedId(), "PROP_HUMAN_SEAT_CHAIR_MP_PLAYER", data.sitcoords.x, data.sitcoords.y, data.sitcoords.z, data.sitcoords[4], 0, 1, true) TaskStartScenarioAtPosition(PlayerPedId(), "PROP_HUMAN_SEAT_CHAIR_MP_PLAYER", data.sitcoords.x, data.sitcoords.y, data.sitcoords.z, data.sitcoords[4], 0, 1, true)
if progressBar({ if progressBar({
label = "Using Toilet", label = "Using Toilet",
time = 10000, time = 10000,
cancel = true cancel = true
}) then }) then
TriggerServerEvent(getScript().."server:Urinal") TriggerServerEvent(getScript().."server:Urinal")
ClearPedTasks(PlayerPedId()) ClearPedTasks(PlayerPedId())
else else
lockInv(false) lockInv(false)
triggerNotify(nil, Loc[Config.Lan].error["cancelled"], 'error') triggerNotify(nil, Loc[Config.Lan].error["cancelled"], 'error')
end end
end end
end end
--- Teleports the player to specified coordinates with a fade effect. --- Teleports the player to specified coordinates with a fade effect.
--- ---
--- This function fades the screen out, moves the player to the target coordinates (`data.telecoords`), --- This function fades the screen out, moves the player to the target coordinates (`data.telecoords`),
--- sets the player's heading, and then fades the screen back in. It's commonly used for door interactions --- sets the player's heading, and then fades the screen back in. It's commonly used for door interactions
--- or teleportation points within the game. --- or teleportation points within the game.
--- ---
---@param data table A table containing teleportation data. ---@param data table A table containing teleportation data.
--- - **telecoords** (`vector4`): The target coordinates and heading for the teleportation. --- - **telecoords** (`vector4`): The target coordinates and heading for the teleportation.
--- ---
---@usage ---@usage
--- ```lua --- ```lua
--- useDoor({ telecoords = vector4(215.76, -810.12, 29.73, 90.0) }) --- useDoor({ telecoords = vector4(215.76, -810.12, 29.73, 90.0) })
--- -- Player is teleported to the specified coordinates with a fade effect --- -- Player is teleported to the specified coordinates with a fade effect
--- ``` --- ```
function useDoor(data) function useDoor(data)
DoScreenFadeOut(500) DoScreenFadeOut(500)
while not IsScreenFadedOut() do Wait(10) end while not IsScreenFadedOut() do Wait(10) end
SetEntityCoords(PlayerPedId(), data.telecoords.xyz, 0, 0, 0, false) SetEntityCoords(PlayerPedId(), data.telecoords.xyz, 0, 0, 0, false)
SetEntityHeading(PlayerPedId(), data.telecoords.w) SetEntityHeading(PlayerPedId(), data.telecoords.w)
DoScreenFadeIn(1000) DoScreenFadeIn(1000)
Wait(100) Wait(100)
end end

View File

@@ -1,75 +1,75 @@
--- Creates a temporary camera at a specified position, pointing towards given coordinates. --- Creates a temporary camera at a specified position, pointing towards given coordinates.
-- --
-- This function creates a camera at a position relative to an entity or at a specified position and orients it to look at the target coordinates. -- This function creates a camera at a position relative to an entity or at a specified position and orients it to look at the target coordinates.
-- The camera is only created if `Config.Crafting.craftCam` is enabled in the configuration. -- The camera is only created if `Config.Crafting.craftCam` is enabled in the configuration.
-- --
---@param ent entityId|coords The base position for the camera. Can be an entity handle or a `vector3` position. ---@param ent entityId|coords The base position for the camera. Can be an entity handle or a `vector3` position.
-- If `ent` is an entity, the camera position is calculated as an offset from the entity's position using `GetOffsetFromEntityInWorldCoords`. -- If `ent` is an entity, the camera position is calculated as an offset from the entity's position using `GetOffsetFromEntityInWorldCoords`.
-- If `ent` is a `vector3`, it is used directly as the camera's position. -- If `ent` is a `vector3`, it is used directly as the camera's position.
-- --
---@param coords vector3 The target `vector3` coordinates that the camera will point at. ---@param coords vector3 The target `vector3` coordinates that the camera will point at.
-- --
---@return cam camID The handle of the created camera, or `nil` if the camera was not created (e.g., if `Config.Crafting.craftCam` is `false`). ---@return cam camID The handle of the created camera, or `nil` if the camera was not created (e.g., if `Config.Crafting.craftCam` is `false`).
-- --
---@usage ---@usage
-- ```lua -- ```lua
-- local cam = createTempCam(entity, targetCoords) -- local cam = createTempCam(entity, targetCoords)
-- ``` -- ```
function createTempCam(ent, coords) function createTempCam(ent, coords)
local cam = nil local cam = nil
if Config.Crafting.craftCam then if Config.Crafting.craftCam then
if debugMode then if debugMode then
triggerNotify(nil, "ModCam Created", "success") triggerNotify(nil, "ModCam Created", "success")
end end
local camCoords = nil local camCoords = nil
if type(ent) ~= "vector3" then if type(ent) ~= "vector3" then
camCoords = GetOffsetFromEntityInWorldCoords(ent, 1.0, -0.3, 0.8) camCoords = GetOffsetFromEntityInWorldCoords(ent, 1.0, -0.3, 0.8)
else else
camCoords = ent camCoords = ent
end end
-- Create the camera with specified parameters -- 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) 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 -- Point the camera at the target coordinates
PointCamAtCoord(cam, coords) PointCamAtCoord(cam, coords)
end end
return cam return cam
end end
--- Activates and starts rendering the temporary camera. --- Activates and starts rendering the temporary camera.
-- --
-- This function sets the specified camera as active and begins rendering it with a smooth transition. -- This function sets the specified camera as active and begins rendering it with a smooth transition.
-- The camera is only activated if `Config.Crafting.craftCam` is enabled in the configuration. -- The camera is only activated if `Config.Crafting.craftCam` is enabled in the configuration.
-- --
---@param cam camID The handle of the camera to activate and render. ---@param cam camID The handle of the camera to activate and render.
-- --
---@usage ---@usage
-- ```lua -- ```lua
-- startTempCam(cam) -- startTempCam(cam)
-- ``` -- ```
function startTempCam(cam) function startTempCam(cam)
if Config.Crafting.craftCam then if Config.Crafting.craftCam then
SetCamActive(cam, true) SetCamActive(cam, true)
RenderScriptCams(true, true, 1000, true, true) RenderScriptCams(true, true, 1000, true, true)
end end
end end
--- Deactivates the temporary camera and stops rendering. --- Deactivates the temporary camera and stops rendering.
-- --
-- This function waits for one second, then stops rendering script cameras and destroys all cameras. -- This function waits for one second, then stops rendering script cameras and destroys all cameras.
-- The delay allows for any transitions or animations to complete. -- The delay allows for any transitions or animations to complete.
-- --
-- The camera is only deactivated if `Config.Crafting.craftCam` is enabled in the configuration. -- The camera is only deactivated if `Config.Crafting.craftCam` is enabled in the configuration.
-- --
---@usage ---@usage
-- ```lua -- ```lua
-- stopTempCam() -- stopTempCam()
-- ``` -- ```
function stopTempCam() function stopTempCam()
if Config.Crafting.craftCam then if Config.Crafting.craftCam then
CreateThread(function() CreateThread(function()
Wait(1000) Wait(1000)
RenderScriptCams(false, true, 500, true, true) RenderScriptCams(false, true, 500, true, true)
DestroyAllCams() DestroyAllCams()
end) end)
end end
end end

View File

@@ -1,239 +1,239 @@
local time = 500 local time = 500
--- Loads a specified model into memory. --- Loads a specified model into memory.
--- ---
--- This function checks if the model is valid and not already loaded. --- This function checks if the model is valid and not already loaded.
--- If not loaded, it requests the model and waits until it is loaded or times out. --- If not loaded, it requests the model and waits until it is loaded or times out.
--- ---
---@param model string|number The name or hash of the model to load. ---@param model string|number The name or hash of the model to load.
--- ---
---@usage ---@usage
--- ```lua --- ```lua
--- loadModel('prop_chair_01a') --- loadModel('prop_chair_01a')
--- ``` --- ```
function loadModel(model) function loadModel(model)
if not IsModelValid(model) then print("^6Bridge^7: ^1ERROR^7: ^2Model^7 - '^6"..model.."^7' ^2does not exist in server") return if not IsModelValid(model) then print("^6Bridge^7: ^1ERROR^7: ^2Model^7 - '^6"..model.."^7' ^2does not exist in server") return
else else
if not HasModelLoaded(model) then if not HasModelLoaded(model) then
debugPrint("^6Bridge^7: ^2Loading Model^7: '^6"..model.."^7'") debugPrint("^6Bridge^7: ^2Loading Model^7: '^6"..model.."^7'")
while not HasModelLoaded(model) and time > 0 do time -= 1 RequestModel(model) Wait(0) end while not HasModelLoaded(model) and time > 0 do time -= 1 RequestModel(model) Wait(0) end
if not HasModelLoaded(model) then print("^6Bridge^7: ^3LoadModel^7: ^2Timed out loading model ^7'^6"..model.."^7'") end if not HasModelLoaded(model) then print("^6Bridge^7: ^3LoadModel^7: ^2Timed out loading model ^7'^6"..model.."^7'") end
end end
time = 500 time = 500
end end
end end
--- Unloads a model from memory. --- Unloads a model from memory.
--- ---
--- This function marks a model as no longer needed, allowing the game to free up memory. --- This function marks a model as no longer needed, allowing the game to free up memory.
--- ---
---@param model string|number The name or hash of the model to unload. ---@param model string|number The name or hash of the model to unload.
--- ---
---@usage ---@usage
--- ```lua --- ```lua
--- unloadModel('prop_chair_01a') --- unloadModel('prop_chair_01a')
--- ``` --- ```
function unloadModel(model) function unloadModel(model)
debugPrint("^6Bridge^7: ^2Removing Model from memory cache^7: '^6"..model.."^7'") debugPrint("^6Bridge^7: ^2Removing Model from memory cache^7: '^6"..model.."^7'")
SetModelAsNoLongerNeeded(model) SetModelAsNoLongerNeeded(model)
end end
--- Loads an animation dictionary into memory. --- Loads an animation dictionary into memory.
--- ---
--- This function checks if the animation dictionary exists and requests it. --- This function checks if the animation dictionary exists and requests it.
--- It waits until the animation dictionary is loaded before proceeding. --- It waits until the animation dictionary is loaded before proceeding.
--- ---
---@param animDict string The name of the animation dictionary to load. ---@param animDict string The name of the animation dictionary to load.
--- ---
---@usage ---@usage
--- ```lua --- ```lua
--- loadAnimDict('amb@world_human_hang_out_street@male_c@base') --- loadAnimDict('amb@world_human_hang_out_street@male_c@base')
--- ``` --- ```
function loadAnimDict(animDict) function loadAnimDict(animDict)
if not DoesAnimDictExist(animDict) then if not DoesAnimDictExist(animDict) then
print("^6Bridge^7: ^1ERROR^7: ^2Anim Dictionary^7 - '^6"..animDict.."^7' ^2does not exist in server") return print("^6Bridge^7: ^1ERROR^7: ^2Anim Dictionary^7 - '^6"..animDict.."^7' ^2does not exist in server") return
else else
debugPrint("^6Bridge^7: ^2Loading Anim Dictionary^7: '^6"..animDict.."^7'") debugPrint("^6Bridge^7: ^2Loading Anim Dictionary^7: '^6"..animDict.."^7'")
while not HasAnimDictLoaded(animDict) do RequestAnimDict(animDict) Wait(5) end while not HasAnimDictLoaded(animDict) do RequestAnimDict(animDict) Wait(5) end
end end
end end
--- Unloads an animation dictionary from memory. --- Unloads an animation dictionary from memory.
--- ---
--- This function removes the animation dictionary from the game's memory cache. --- This function removes the animation dictionary from the game's memory cache.
--- ---
---@param animDict string The name of the animation dictionary to unload. ---@param animDict string The name of the animation dictionary to unload.
--- ---
---@usage ---@usage
---@ ---@
--- ```lua --- ```lua
--- unloadAnimDict('amb@world_human_hang_out_street@male_c@base') --- unloadAnimDict('amb@world_human_hang_out_street@male_c@base')
--- ``` --- ```
function unloadAnimDict(animDict) function unloadAnimDict(animDict)
debugPrint("^6Bridge^7: ^2Removing Anim Dictionary from memory cache^7: '^6"..animDict.."^7'") debugPrint("^6Bridge^7: ^2Removing Anim Dictionary from memory cache^7: '^6"..animDict.."^7'")
RemoveAnimDict(animDict) RemoveAnimDict(animDict)
end end
--- Loads a particle effects (ptfx) dictionary into memory. --- Loads a particle effects (ptfx) dictionary into memory.
--- ---
--- This function requests the named particle effects asset and waits until it's loaded. --- This function requests the named particle effects asset and waits until it's loaded.
--- ---
---@param ptFxName string The name of the particle effects dictionary to load. ---@param ptFxName string The name of the particle effects dictionary to load.
--- ---
---@usage ---@usage
--- ```lua --- ```lua
--- loadPtfxDict('core') --- loadPtfxDict('core')
--- ``` --- ```
function loadPtfxDict(ptFxName) function loadPtfxDict(ptFxName)
if not HasNamedPtfxAssetLoaded(ptFxName) then if not HasNamedPtfxAssetLoaded(ptFxName) then
debugPrint("^6Bridge^7: ^2Loading Ptfx Dictionary^7: '^6"..ptFxName.."^7'") debugPrint("^6Bridge^7: ^2Loading Ptfx Dictionary^7: '^6"..ptFxName.."^7'")
while not HasNamedPtfxAssetLoaded(ptFxName) do RequestNamedPtfxAsset(ptFxName) Wait(5) end while not HasNamedPtfxAssetLoaded(ptFxName) do RequestNamedPtfxAsset(ptFxName) Wait(5) end
end end
end end
--- Unloads a particle effects (ptfx) dictionary from memory. --- Unloads a particle effects (ptfx) dictionary from memory.
--- ---
--- This function removes the named particle effects asset from the game's memory cache. --- This function removes the named particle effects asset from the game's memory cache.
--- ---
---@param dict string The name of the particle effects dictionary to unload. ---@param dict string The name of the particle effects dictionary to unload.
--- ---
---@usage ---@usage
--- ```lua --- ```lua
--- unloadPtfxDict('core') --- unloadPtfxDict('core')
--- ``` --- ```
function unloadPtfxDict(dict) function unloadPtfxDict(dict)
debugPrint("^6Bridge^7: ^2Removing Ptfx Dictionary^7: '^6"..dict.."^7'") debugPrint("^6Bridge^7: ^2Removing Ptfx Dictionary^7: '^6"..dict.."^7'")
RemoveNamedPtfxAsset(dict) RemoveNamedPtfxAsset(dict)
end end
--- Loads a texture dictionary into memory. --- Loads a texture dictionary into memory.
--- ---
--- This function requests the streamed texture dictionary and waits until it's loaded. --- This function requests the streamed texture dictionary and waits until it's loaded.
--- ---
---@param dict string The name of the texture dictionary to load. ---@param dict string The name of the texture dictionary to load.
--- ---
---@usage ---@usage
--- ```lua --- ```lua
--- loadTextureDict('commonmenu') --- loadTextureDict('commonmenu')
--- ``` --- ```
function loadTextureDict(dict) function loadTextureDict(dict)
if not HasStreamedTextureDictLoaded(dict) then if not HasStreamedTextureDictLoaded(dict) then
debugPrint("^6Bridge^7: ^2Loading Texture Dictionary^7: '^6"..dict.."^7'") debugPrint("^6Bridge^7: ^2Loading Texture Dictionary^7: '^6"..dict.."^7'")
while not HasStreamedTextureDictLoaded(dict) do RequestStreamedTextureDict(dict) Wait(5) end while not HasStreamedTextureDictLoaded(dict) do RequestStreamedTextureDict(dict) Wait(5) end
end end
end end
--- Loads a script audio bank into memory. --- Loads a script audio bank into memory.
--- ---
--- This function requests a script audio bank and waits until it's loaded or times out. --- This function requests a script audio bank and waits until it's loaded or times out.
--- ---
---@param bank string The name of the script audio bank to load. ---@param bank string The name of the script audio bank to load.
--- ---
---@return boolean `true` if the audio bank was successfully loaded; otherwise, `false`. ---@return boolean `true` if the audio bank was successfully loaded; otherwise, `false`.
--- ---
---@usage ---@usage
--- ```lua --- ```lua
--- local success = loadScriptBank('DLC_HEISTS_GENERAL_FRONTEND_SOUNDS') --- local success = loadScriptBank('DLC_HEISTS_GENERAL_FRONTEND_SOUNDS')
--- ``` --- ```
function loadScriptBank(bank) function loadScriptBank(bank)
local timeout = 2000 local timeout = 2000
debugPrint("^6Debug^7: ^2Loading ^3Script ^2AudioBank^7...") debugPrint("^6Debug^7: ^2Loading ^3Script ^2AudioBank^7...")
while not RequestScriptAudioBank(bank, 0) do Wait(10) timeout -= 10 if timeout <= 0 then break end end while not RequestScriptAudioBank(bank, 0) do Wait(10) timeout -= 10 if timeout <= 0 then break end end
local success = RequestScriptAudioBank(bank, 0) local success = RequestScriptAudioBank(bank, 0)
debugPrint("^6Debug^7: "..(success and "^3Successfully ^2loaded^7: '^4" or "^1Failed to ^2load^7: '^4")..bank.."^7'") debugPrint("^6Debug^7: "..(success and "^3Successfully ^2loaded^7: '^4" or "^1Failed to ^2load^7: '^4")..bank.."^7'")
return success return success
end end
--- Loads an ambient audio bank into memory. --- Loads an ambient audio bank into memory.
--- ---
--- This function requests an ambient audio bank and waits until it's loaded or times out. --- This function requests an ambient audio bank and waits until it's loaded or times out.
--- ---
---@param bank string The name of the ambient audio bank to load. ---@param bank string The name of the ambient audio bank to load.
--- ---
---@return boolean `true` if the audio bank was successfully loaded; otherwise, `false`. ---@return boolean `true` if the audio bank was successfully loaded; otherwise, `false`.
--- ---
---@usage ---@usage
--- ```lua --- ```lua
--- local success = loadAmbientBank('AMB_REVERB_GENERIC') --- local success = loadAmbientBank('AMB_REVERB_GENERIC')
--- ``` --- ```
function loadAmbientBank(bank) function loadAmbientBank(bank)
local timeout = 2000 local timeout = 2000
debugPrint("^6Debug^7: ^2Loading ^3Ambient ^2AudioBank^7...") debugPrint("^6Debug^7: ^2Loading ^3Ambient ^2AudioBank^7...")
while not RequestAmbientAudioBank(bank, 0) do while not RequestAmbientAudioBank(bank, 0) do
Wait(10) Wait(10)
timeout -= 10 timeout -= 10
if timeout <= 0 then break end if timeout <= 0 then break end
end end
local success = RequestAmbientAudioBank(bank, 0) local success = RequestAmbientAudioBank(bank, 0)
debugPrint("^6Debug^7: "..(success and "^3Successfully ^2loaded^7: '^4" or "^1Failed to ^2load^7: '^4")..bank.."^7'") debugPrint("^6Debug^7: "..(success and "^3Successfully ^2loaded^7: '^4" or "^1Failed to ^2load^7: '^4")..bank.."^7'")
return success return success
end end
--- Plays an animation on a specified ped. --- Plays an animation on a specified ped.
--- ---
--- This function loads the animation dictionary and instructs the ped to play the animation. --- This function loads the animation dictionary and instructs the ped to play the animation.
--- ---
---@param animDict string The name of the animation dictionary. ---@param animDict string The name of the animation dictionary.
---@param animName string The name of the animation within the dictionary. ---@param animName string The name of the animation within the dictionary.
---@param duration number (optional) The duration to play the animation in milliseconds. Default is `30000`. ---@param duration number (optional) The duration to play the animation in milliseconds. Default is `30000`.
---@param flag number (optional) The animation flag controlling how the animation is played. Default is `50`. ---@param flag number (optional) The animation flag controlling how the animation is played. Default is `50`.
---@param ped number (optional) The ped on which to play the animation. Defaults to the player's ped if not specified. ---@param ped number (optional) The ped on which to play the animation. Defaults to the player's ped if not specified.
---@param speed number (optional) The speed multiplier for the animation. Default is `8.0`. ---@param speed number (optional) The speed multiplier for the animation. Default is `8.0`.
--- ---
---@usage ---@usage
--- ```lua --- ```lua
--- playAnim('amb@world_human_hang_out_street@male_c@base', 'base', 5000, 1, PlayerPedId(), 1.0) --- playAnim('amb@world_human_hang_out_street@male_c@base', 'base', 5000, 1, PlayerPedId(), 1.0)
--- ``` --- ```
function playAnim(animDict, animName, duration, flag, ped, speed) function playAnim(animDict, animName, duration, flag, ped, speed)
loadAnimDict(animDict) loadAnimDict(animDict)
debugPrint("Attempting to make player play anim", animDict, animName) debugPrint("Attempting to make player play anim", animDict, animName)
TaskPlayAnim(ped and ped or PlayerPedId(), animDict, animName, speed or 8.0, speed or -8.0, duration or 30000, flag or 50, 1, false, false, false) TaskPlayAnim(ped and ped or PlayerPedId(), animDict, animName, speed or 8.0, speed or -8.0, duration or 30000, flag or 50, 1, false, false, false)
end end
--- Stops a specified animation on a ped. --- Stops a specified animation on a ped.
--- ---
--- This function stops the animation and unloads the animation dictionary from memory. --- This function stops the animation and unloads the animation dictionary from memory.
--- ---
---@param animDict string The name of the animation dictionary. ---@param animDict string The name of the animation dictionary.
---@param animName string The name of the animation within the dictionary. ---@param animName string The name of the animation within the dictionary.
---@param ped number (optional) The ped on which to stop the animation. Defaults to the player's ped if not specified. ---@param ped number (optional) The ped on which to stop the animation. Defaults to the player's ped if not specified.
--- ---
---@usage ---@usage
--- ```lua --- ```lua
--- stopAnim('amb@world_human_hang_out_street@male_c@base', 'base', PlayerPedId()) --- stopAnim('amb@world_human_hang_out_street@male_c@base', 'base', PlayerPedId())
--- ``` --- ```
function stopAnim(animDict, animName, ped) function stopAnim(animDict, animName, ped)
debugPrint("Stopping anim for "..(ped or PlayerPedId())) debugPrint("Stopping anim for "..(ped or PlayerPedId()))
StopAnimTask(ped or PlayerPedId(), animDict, animName, 0.5) StopAnimTask(ped or PlayerPedId(), animDict, animName, 0.5)
StopAnimTask(ped or PlayerPedId(), animName, animDict, 0.5) StopAnimTask(ped or PlayerPedId(), animName, animDict, 0.5)
unloadAnimDict(animDict) unloadAnimDict(animDict)
end end
--- Plays a game sound from a specified coordinate or entity. --- Plays a game sound from a specified coordinate or entity.
--- ---
--- This function attempts to play a sound from either a coordinate or an entity, using the specified audio bank and sound name. --- This function attempts to play a sound from either a coordinate or an entity, using the specified audio bank and sound name.
--- ---
---@param bank string The name of the audio bank containing the sound. ---@param bank string The name of the audio bank containing the sound.
---@param sound string The name of the sound to play. ---@param sound string The name of the sound to play.
---@param coords vector3|number A `vector3` coordinate or an entity handle from which to play the sound. ---@param coords vector3|number A `vector3` coordinate or an entity handle from which to play the sound.
---@param synced boolean A boolean indicating whether the sound is synced across clients. ---@param synced boolean A boolean indicating whether the sound is synced across clients.
---@param range number (optional) The maximum range at which the sound can be heard. Default is `10.0`. ---@param range number (optional) The maximum range at which the sound can be heard. Default is `10.0`.
--- ---
---@usage ---@usage
--- ```lua --- ```lua
--- playGameSound('DLC_HEIST_HACKING_SNAKE_SOUNDS', 'Beep', vector3(0, 0, 0), false, 15.0) --- playGameSound('DLC_HEIST_HACKING_SNAKE_SOUNDS', 'Beep', vector3(0, 0, 0), false, 15.0)
--- ``` --- ```
function playGameSound(bank, sound, coords, synced, range) function playGameSound(bank, sound, coords, synced, range)
debugPrint("^6Debug^7: ^2Attempting to play: ^3"..sound.." ^7(^4"..bank.."^7')") debugPrint("^6Debug^7: ^2Attempting to play: ^3"..sound.." ^7(^4"..bank.."^7')")
local range = range or 10.0 local range = range or 10.0
local soundId = GetSoundId() local soundId = GetSoundId()
while not soundId do Wait(10) end while not soundId do Wait(10) end
if type(coords) == "vector3" or type(coords) == "vector4" then if type(coords) == "vector3" or type(coords) == "vector4" then
debugPrint("^6Debug^7: ^2Playing sound from Coord^7: "..formatCoord(coords.xyz)) debugPrint("^6Debug^7: ^2Playing sound from Coord^7: "..formatCoord(coords.xyz))
PlaySoundFromCoord(soundId, sound, coords.x, coords.y, coords.z, bank, synced, range, 0) PlaySoundFromCoord(soundId, sound, coords.x, coords.y, coords.z, bank, synced, range, 0)
else else
debugPrint("^6Debug^7: ^2Playing sound from Entity^7: ^4"..coords.."^7") debugPrint("^6Debug^7: ^2Playing sound from Entity^7: ^4"..coords.."^7")
PlaySoundFromEntity(soundId, sound, coords, bank, synced, 0) PlaySoundFromEntity(soundId, sound, coords, bank, synced, 0)
end end
end end

View File

@@ -1,119 +1,119 @@
--- Creates a blip at specified coordinates with given properties. --- Creates a blip at specified coordinates with given properties.
-- --
-- This function adds a map blip at the provided coordinates and sets various display properties such as sprite, color, scale, and more. -- This function adds a map blip at the provided coordinates and sets various display properties such as sprite, color, scale, and more.
-- It also handles attaching a preview image to the blip if certain resources are running and a preview is provided. -- It also handles attaching a preview image to the blip if certain resources are running and a preview is provided.
-- --
---@param data A table containing blip data and properties. ---@param data A table containing blip data and properties.
-- - **coords**: A `vector3` containing x, y, z coordinates where the blip will be placed. -- - **coords**: A `vector3` containing x, y, z coordinates where the blip will be placed.
-- - **sprite** (optional): The blip sprite/icon ID. Default is `106`. -- - **sprite** (optional): The blip sprite/icon ID. Default is `106`.
-- - **col** (optional): The color ID of the blip. Default is `5`. -- - **col** (optional): The color ID of the blip. Default is `5`.
-- - **scale** (optional): The scale of the blip. Default is `0.7`. -- - **scale** (optional): The scale of the blip. Default is `0.7`.
-- - **disp** (optional): The display option of the blip. Default is `6`. -- - **disp** (optional): The display option of the blip. Default is `6`.
-- - **category** (optional): The category ID for the blip. -- - **category** (optional): The category ID for the blip.
-- - **name**: The name of the blip, used for display on the map. -- - **name**: The name of the blip, used for display on the map.
-- - **preview** (optional): A URL or image path for a preview image to display with the blip. -- - **preview** (optional): A URL or image path for a preview image to display with the blip.
-- --
---@return blip blipID The handle of the created blip. ---@return blip blipID The handle of the created blip.
-- --
---@usage ---@usage
-- ```lua -- ```lua
-- local blipData = { -- local blipData = {
-- coords = vector3(123.4, 567.8, 90.1), -- coords = vector3(123.4, 567.8, 90.1),
-- sprite = 1, -- sprite = 1,
-- col = 2, -- col = 2,
-- scale = 0.8, -- scale = 0.8,
-- disp = 4, -- disp = 4,
-- category = 7, -- category = 7,
-- name = "My Blip", -- name = "My Blip",
-- preview = "http://example.com/preview.png" -- preview = "http://example.com/preview.png"
-- } -- }
-- local blip = makeBlip(blipData) -- local blip = makeBlip(blipData)
-- ``` -- ```
function makeBlip(data) function makeBlip(data)
local blip = AddBlipForCoord(vec3(data.coords.x, data.coords.y, data.coords.z)) local blip = AddBlipForCoord(vec3(data.coords.x, data.coords.y, data.coords.z))
SetBlipCoords(blip, data.coords.x, data.coords.y, data.coords.z) -- Manually set blip coordinates again as sometimes it just refuses SetBlipCoords(blip, data.coords.x, data.coords.y, data.coords.z) -- Manually set blip coordinates again as sometimes it just refuses
SetBlipAsShortRange(blip, true) SetBlipAsShortRange(blip, true)
SetBlipSprite(blip, data.sprite or 106) SetBlipSprite(blip, data.sprite or 106)
SetBlipColour(blip, data.col or 5) SetBlipColour(blip, data.col or 5)
SetBlipScale(blip, data.scale or 0.7) SetBlipScale(blip, data.scale or 0.7)
SetBlipDisplay(blip, data.disp or 6) SetBlipDisplay(blip, data.disp or 6)
if data.category then SetBlipCategory(blip, data.category) end if data.category then SetBlipCategory(blip, data.category) end
BeginTextCommandSetBlipName('STRING') BeginTextCommandSetBlipName('STRING')
AddTextComponentString(tostring(data.name)) AddTextComponentString(tostring(data.name))
EndTextCommandSetBlipName(blip) EndTextCommandSetBlipName(blip)
-- Handle preview image if certain resources are running -- Handle preview image if certain resources are running
if isStarted("fs_smallresources") or isStarted("blip_info") or isStarted("blipinfo") then if isStarted("fs_smallresources") or isStarted("blip_info") or isStarted("blipinfo") then
if data.preview then if data.preview then
local txname = string.gsub(tostring(data.name..'preview'..string.gsub(data.coords.z, "%.", "")), "[ ()~]", "") local txname = string.gsub(tostring(data.name..'preview'..string.gsub(data.coords.z, "%.", "")), "[ ()~]", "")
if data.preview:find("http") or data.preview:find("nui") then if data.preview:find("http") or data.preview:find("nui") then
createDui(txname, data.preview, vec2(512, 256), scriptTxd) createDui(txname, data.preview, vec2(512, 256), scriptTxd)
else else
CreateRuntimeTextureFromImage(scriptTxd, txname, data.preview) CreateRuntimeTextureFromImage(scriptTxd, txname, data.preview)
end end
exports["fs_smallresources"]:SetBlipInfoImage(blip, getScript()..'scriptTxd', txname) exports["fs_smallresources"]:SetBlipInfoImage(blip, getScript()..'scriptTxd', txname)
exports["fs_smallresources"]:SetBlipInfoTitle(blip, data.name, false) exports["fs_smallresources"]:SetBlipInfoTitle(blip, data.name, false)
end end
end end
debugPrint("^6Bridge^7: ^6Blip ^2created^7: '^6"..data.name.."^7' - '"..formatCoord(data.coords).."'") debugPrint("^6Bridge^7: ^6Blip ^2created^7: '^6"..data.name.."^7' - '"..formatCoord(data.coords).."'")
return blip return blip
end end
--- Creates a blip attached to a specified entity with given properties. --- Creates a blip attached to a specified entity with given properties.
-- --
-- This function adds a map blip attached to the provided entity and sets various display properties such as sprite, color, scale, and more. -- This function adds a map blip attached to the provided entity and sets various display properties such as sprite, color, scale, and more.
-- It also handles attaching a preview image to the blip if certain resources are running and a preview is provided. -- It also handles attaching a preview image to the blip if certain resources are running and a preview is provided.
-- --
---@param data table A table containing blip data and properties. ---@param data table A table containing blip data and properties.
-- - **entity**: The entity to which the blip will be attached. -- - **entity**: The entity to which the blip will be attached.
-- - **sprite** (optional): The blip sprite/icon ID. Default is `106`. -- - **sprite** (optional): The blip sprite/icon ID. Default is `106`.
-- - **col** (optional): The color ID of the blip. Default is `5`. -- - **col** (optional): The color ID of the blip. Default is `5`.
-- - **scale** (optional): The scale of the blip. Default is `0.7`. -- - **scale** (optional): The scale of the blip. Default is `0.7`.
-- - **disp** (optional): The display option of the blip. Default is `6`. -- - **disp** (optional): The display option of the blip. Default is `6`.
-- - **category** (optional): The category ID for the blip. -- - **category** (optional): The category ID for the blip.
-- - **name**: The name of the blip, used for display on the map. -- - **name**: The name of the blip, used for display on the map.
-- - **preview** (optional): A URL or image path for a preview image to display with the blip. -- - **preview** (optional): A URL or image path for a preview image to display with the blip.
-- --
-- --
---@return number blipID The handle of the created blip. ---@return number blipID The handle of the created blip.
---@usage ---@usage
-- ```lua -- ```lua
-- local blipData = { -- local blipData = {
-- entity = myEntity, -- entity = myEntity,
-- sprite = 1, -- sprite = 1,
-- col = 2, -- col = 2,
-- scale = 0.8, -- scale = 0.8,
-- disp = 4, -- disp = 4,
-- category = 7, -- category = 7,
-- name = "Entity Blip", -- name = "Entity Blip",
-- preview = "http://example.com/preview.png" -- preview = "http://example.com/preview.png"
-- } -- }
-- local blip = makeEntityBlip(blipData) -- local blip = makeEntityBlip(blipData)
-- ``` -- ```
function makeEntityBlip(data) function makeEntityBlip(data)
AddBlipForEntity(data.entity) AddBlipForEntity(data.entity)
local blip = GetBlipFromEntity(data.entity) local blip = GetBlipFromEntity(data.entity)
SetBlipAsShortRange(blip, true) SetBlipAsShortRange(blip, true)
SetBlipSprite(blip, data.sprite or 106) SetBlipSprite(blip, data.sprite or 106)
SetBlipColour(blip, data.col or 5) SetBlipColour(blip, data.col or 5)
SetBlipScale(blip, data.scale or 0.7) SetBlipScale(blip, data.scale or 0.7)
SetBlipDisplay(blip, data.disp or 6) SetBlipDisplay(blip, data.disp or 6)
if data.category then SetBlipCategory(blip, data.category) end if data.category then SetBlipCategory(blip, data.category) end
BeginTextCommandSetBlipName('STRING') BeginTextCommandSetBlipName('STRING')
AddTextComponentString(tostring(data.name)) AddTextComponentString(tostring(data.name))
EndTextCommandSetBlipName(blip) EndTextCommandSetBlipName(blip)
-- Handle preview image if certain resources are running -- Handle preview image if certain resources are running
if isStarted("fs_smallresources") or isStarted("blip-info") or isStarted("blipinfo") then if isStarted("fs_smallresources") or isStarted("blip-info") or isStarted("blipinfo") then
if data.preview then if data.preview then
local txname = string.gsub(tostring(data.name..'preview'), "[ ()~]", "") local txname = string.gsub(tostring(data.name..'preview'), "[ ()~]", "")
if data.preview:find("http") or data.preview:find("nui") then if data.preview:find("http") or data.preview:find("nui") then
createDui(txname, data.preview, vec2(512, 256), scriptTxd) createDui(txname, data.preview, vec2(512, 256), scriptTxd)
else else
CreateRuntimeTextureFromImage(scriptTxd, txname, data.preview) CreateRuntimeTextureFromImage(scriptTxd, txname, data.preview)
end end
exports["fs_smallresources"]:SetBlipInfoImage(blip, getScript()..'previewTxd', txname) exports["fs_smallresources"]:SetBlipInfoImage(blip, getScript()..'previewTxd', txname)
exports["fs_smallresources"]:SetBlipInfoTitle(blip, data.name, false) exports["fs_smallresources"]:SetBlipInfoTitle(blip, data.name, false)
end end
end end
debugPrint("^6Bridge^7: ^6Blip ^2created for Entity^7: '^6"..data.name.."^7'") debugPrint("^6Bridge^7: ^6Blip ^2created for Entity^7: '^6"..data.name.."^7'")
return blip return blip
end end

View File

@@ -1,230 +1,230 @@
--- A table to keep track of all created Peds. --- A table to keep track of all created Peds.
local Peds = {} local Peds = {}
--- Creates a distance-based Ped (pedestrian) that spawns when the player enters a specified area. --- Creates a distance-based Ped (pedestrian) that spawns when the player enters a specified area.
-- --
-- This function sets up a circular area using `createCirclePoly`. When the player enters this area, a Ped is created using `makePed`. -- This function sets up a circular area using `createCirclePoly`. When the player enters this area, a Ped is created using `makePed`.
-- When the player exits the area, the Ped is deleted. -- When the player exits the area, the Ped is deleted.
-- --
---@param data table A table containing Ped data and properties. Should include at least `model` and `coords`. ---@param data table A table containing Ped data and properties. Should include at least `model` and `coords`.
---@param coords vector4 A `vector3` or `vector4` specifying the coordinates where the Ped will be placed. ---@param coords vector4 A `vector3` or `vector4` specifying the coordinates where the Ped will be placed.
---@param freeze boolean (optional) Boolean indicating whether the Ped should be frozen in place. Default is `true`. ---@param freeze boolean (optional) Boolean indicating whether the Ped should be frozen in place. Default is `true`.
---@param collision boolean (optional) Boolean indicating whether collision with the Ped is enabled. Default is `false`. ---@param collision boolean (optional) Boolean indicating whether collision with the Ped is enabled. Default is `false`.
---@param scenario boolean (optional) String specifying the scenario the Ped should perform. ---@param scenario boolean (optional) String specifying the scenario the Ped should perform.
---@param anim table (optional) A table containing animation dictionary and name `{animDict, animName}`. ---@param anim table (optional) A table containing animation dictionary and name `{animDict, animName}`.
---@param synced boolean (optional) Boolean indicating whether the Ped is synced across clients. Default is `false`. ---@param synced boolean (optional) Boolean indicating whether the Ped is synced across clients. Default is `false`.
-- --
---@usage ---@usage
-- ```lua -- ```lua
-- makeDistPed(pedData, pedCoords, true, false, 'WORLD_HUMAN_STAND_IMPATIENT', nil, true) -- makeDistPed(pedData, pedCoords, true, false, 'WORLD_HUMAN_STAND_IMPATIENT', nil, true)
-- ``` -- ```
function makeDistPed(data, coords, freeze, collision, scenario, anim, synced) function makeDistPed(data, coords, freeze, collision, scenario, anim, synced)
createCirclePoly({ createCirclePoly({
name = keyGen()..keyGen(), name = keyGen()..keyGen(),
coords = vec3(data.coords.x, data.coords.y, data.coords.z - 1.03), coords = vec3(data.coords.x, data.coords.y, data.coords.z - 1.03),
radius = 50.0, radius = 50.0,
onEnter = function() onEnter = function()
Peds[#Peds + 1] = makePed(data, coords, freeze, collision, scenario, anim, synced) Peds[#Peds + 1] = makePed(data, coords, freeze, collision, scenario, anim, synced)
end, end,
onExit = function() onExit = function()
DeletePed(Peds[#Peds]) DeletePed(Peds[#Peds])
end, end,
debug = debugMode, debug = debugMode,
}) })
end end
--- Creates a Ped (pedestrian character) with specified properties. --- Creates a Ped (pedestrian character) with specified properties.
-- --
-- This function creates a Ped at the given coordinates and applies appearance and clothing based on the provided data. -- This function creates a Ped at the given coordinates and applies appearance and clothing based on the provided data.
-- --
-- If `data` is a table with `custom` properties, it customizes the Ped's appearance accordingly. -- If `data` is a table with `custom` properties, it customizes the Ped's appearance accordingly.
-- --
---@param data modelHash|table Either a string/model hash of the Ped model to use, or a table containing `model` and `custom` data. ---@param data modelHash|table Either a string/model hash of the Ped model to use, or a table containing `model` and `custom` data.
---@param coords vector4 `vector3` or `vector4` specifying the coordinates where the Ped will be placed. ---@param coords vector4 `vector3` or `vector4` specifying the coordinates where the Ped will be placed.
---@param freeze boolean (optional) Boolean indicating whether the Ped should be frozen in place. Default is `true`. ---@param freeze boolean (optional) Boolean indicating whether the Ped should be frozen in place. Default is `true`.
---@param collision boolean (optional) Boolean indicating whether collision with the Ped is enabled. Default is `false`. ---@param collision boolean (optional) Boolean indicating whether collision with the Ped is enabled. Default is `false`.
---@param scenario string (optional) String specifying the scenario the Ped should perform. ---@param scenario string (optional) String specifying the scenario the Ped should perform.
---@param anim table (optional) A table containing animation dictionary and name `{animDict, animName}`. ---@param anim table (optional) A table containing animation dictionary and name `{animDict, animName}`.
---@param synced boolean (optional) Boolean indicating whether the Ped is synced across clients. Default is `false`. ---@param synced boolean (optional) Boolean indicating whether the Ped is synced across clients. Default is `false`.
-- --
---@return ped entityID The handle of the created Ped. ---@return ped entityID The handle of the created Ped.
-- --
---@usage ---@usage
-- ```lua -- ```lua
-- local ped = makePed(pedData, pedCoords, true, false, nil, {'animDict', 'animName'}, true) -- local ped = makePed(pedData, pedCoords, true, false, nil, {'animDict', 'animName'}, true)
-- ``` -- ```
function makePed(data, coords, freeze, collision, scenario, anim, synced) function makePed(data, coords, freeze, collision, scenario, anim, synced)
local ped = nil local ped = nil
local model = nil local model = nil
if type(data) == "table" then if type(data) == "table" then
model = data.model model = data.model
loadModel(data.model) loadModel(data.model)
ped = CreatePed(0, model, coords.x, coords.y, coords.z - 1.03, coords.w, synced and synced or false, false) ped = CreatePed(0, model, coords.x, coords.y, coords.z - 1.03, coords.w, synced and synced or false, false)
-- Inheritance -- Inheritance
SetPedHeadBlendData(ped, data.custom.faceFather, data.custom.faceMother, data.custom.raceShape, data.custom.skinFather, data.custom.skinMother, data.custom.raceSkin, data.custom.faceMix or 0, data.custom.skinMix or 0, data.custom.raceMix or 0, false) SetPedHeadBlendData(ped, data.custom.faceFather, data.custom.faceMother, data.custom.raceShape, data.custom.skinFather, data.custom.skinMother, data.custom.raceSkin, data.custom.faceMix or 0, data.custom.skinMix or 0, data.custom.raceMix or 0, false)
-- Face Features -- Face Features
for k, v in pairs({ for k, v in pairs({
"noseWidth", "noseHeight", "noseSize", "noseBoneHeight", "nosePeakHeight", "noseBoneTwist", "noseWidth", "noseHeight", "noseSize", "noseBoneHeight", "nosePeakHeight", "noseBoneTwist",
"eyebrowHeight", "eyebrowDepth", "eyebrowHeight", "eyebrowDepth",
"cheekBoneHeight", "cheekBoneWidth", "cheeckWidth", "cheekBoneHeight", "cheekBoneWidth", "cheeckWidth",
"eyeOpening", "lipThickness", "eyeOpening", "lipThickness",
"jawWidth", "jawSize", "jawWidth", "jawSize",
"chinLowering", "chinLength", "chinSize", "chinHole", "chinLowering", "chinLength", "chinSize", "chinHole",
"neckThickness" "neckThickness"
}) do }) do
SetPedFaceFeature(ped, k - 1, data.custom[v]) SetPedFaceFeature(ped, k - 1, data.custom[v])
end end
-- Appearance -- Appearance
SetPedComponentVariation(ped, 2, data.custom.Hair, 0, 0) SetPedComponentVariation(ped, 2, data.custom.Hair, 0, 0)
SetPedHairColor(ped, data.custom.HairTexture, data.custom.HairHighlight or 0) SetPedHairColor(ped, data.custom.HairTexture, data.custom.HairHighlight or 0)
SetPedHeadOverlay(ped, 2, data.custom.Eyebrows, data.custom.EyebrowsOpacity) SetPedHeadOverlay(ped, 2, data.custom.Eyebrows, data.custom.EyebrowsOpacity)
SetPedHeadOverlayColor(ped, 2, 1, data.custom.EyebrowsColor, 0) SetPedHeadOverlayColor(ped, 2, 1, data.custom.EyebrowsColor, 0)
SetPedEyeColor(ped, data.custom.Eyecolor) SetPedEyeColor(ped, data.custom.Eyecolor)
SetPedHeadOverlay(ped, 4, data.custom.Makeup, data.custom.MakeupOpacity) SetPedHeadOverlay(ped, 4, data.custom.Makeup, data.custom.MakeupOpacity)
SetPedHeadOverlayColor(ped, 4, 1, data.custom.MakeupColor, 0) SetPedHeadOverlayColor(ped, 4, 1, data.custom.MakeupColor, 0)
SetPedHeadOverlay(ped, 8, data.custom.Lipstick, data.custom.LipstickOpacity) SetPedHeadOverlay(ped, 8, data.custom.Lipstick, data.custom.LipstickOpacity)
SetPedHeadOverlayColor(ped, 8, 1, data.custom.LipstickColor, 0) SetPedHeadOverlayColor(ped, 8, 1, data.custom.LipstickColor, 0)
SetPedHeadOverlay(ped, 1, data.custom.Beard, data.custom.BeardOpacity) SetPedHeadOverlay(ped, 1, data.custom.Beard, data.custom.BeardOpacity)
SetPedHeadOverlayColor(ped, 1, 1, data.custom.BeardColor, 0) SetPedHeadOverlayColor(ped, 1, 1, data.custom.BeardColor, 0)
-- Clothes -- Clothes
SetPedComponentVariation(ped, 1, data.custom.Mask, data.custom.MaskVariant, 0) SetPedComponentVariation(ped, 1, data.custom.Mask, data.custom.MaskVariant, 0)
SetPedComponentVariation(ped, 7, data.custom.Scarf, data.custom.ScarfVariant, 0) SetPedComponentVariation(ped, 7, data.custom.Scarf, data.custom.ScarfVariant, 0)
SetPedComponentVariation(ped, 11, data.custom.Jacket, data.custom.JacketVariant, 0) SetPedComponentVariation(ped, 11, data.custom.Jacket, data.custom.JacketVariant, 0)
SetPedComponentVariation(ped, 8, data.custom.Shirt, data.custom.ShirtVariant, 0) SetPedComponentVariation(ped, 8, data.custom.Shirt, data.custom.ShirtVariant, 0)
SetPedComponentVariation(ped, 9, data.custom.Vest, data.custom.VestVariant, 0) SetPedComponentVariation(ped, 9, data.custom.Vest, data.custom.VestVariant, 0)
SetPedComponentVariation(ped, 5, data.custom.Bags, data.custom.BagsVariant, 0) SetPedComponentVariation(ped, 5, data.custom.Bags, data.custom.BagsVariant, 0)
SetPedComponentVariation(ped, 3, data.custom.Arms, data.custom.ArmsVariant, 0) SetPedComponentVariation(ped, 3, data.custom.Arms, data.custom.ArmsVariant, 0)
SetPedComponentVariation(ped, 4, data.custom.Pants, data.custom.PantsVariant, 0) SetPedComponentVariation(ped, 4, data.custom.Pants, data.custom.PantsVariant, 0)
SetPedComponentVariation(ped, 6, data.custom.Shoes, data.custom.ShoesVariant, 0) SetPedComponentVariation(ped, 6, data.custom.Shoes, data.custom.ShoesVariant, 0)
SetPedComponentVariation(ped, 10, data.custom.Decal, data.custom.DecalVariant, 0) SetPedComponentVariation(ped, 10, data.custom.Decal, data.custom.DecalVariant, 0)
-- Accessories -- Accessories
SetPedPropIndex(ped, 0, data.custom.Hat, data.custom.HatVariant, true) SetPedPropIndex(ped, 0, data.custom.Hat, data.custom.HatVariant, true)
SetPedPropIndex(ped, 1, data.custom.Glasses, data.custom.GlassesVariant, true) SetPedPropIndex(ped, 1, data.custom.Glasses, data.custom.GlassesVariant, true)
SetPedPropIndex(ped, 2, data.custom.Ear, data.custom.EarVariant, true) SetPedPropIndex(ped, 2, data.custom.Ear, data.custom.EarVariant, true)
SetPedPropIndex(ped, 6, data.custom.Watches, data.custom.WatchesVariant, true) SetPedPropIndex(ped, 6, data.custom.Watches, data.custom.WatchesVariant, true)
SetPedPropIndex(ped, 7, data.custom.Bracelets, data.custom.BraceletsVariant, true) SetPedPropIndex(ped, 7, data.custom.Bracelets, data.custom.BraceletsVariant, true)
else else
model = data model = data
loadModel(model) loadModel(model)
ped = CreatePed(0, model, coords.x, coords.y, coords.z - 1.03, coords.w, synced or false, false) ped = CreatePed(0, model, coords.x, coords.y, coords.z - 1.03, coords.w, synced or false, false)
end end
SetEntityInvincible(ped, true) SetEntityInvincible(ped, true)
SetBlockingOfNonTemporaryEvents(ped, true) SetBlockingOfNonTemporaryEvents(ped, true)
FreezeEntityPosition(ped, freeze and freeze or true) FreezeEntityPosition(ped, freeze and freeze or true)
if collision then SetEntityNoCollisionEntity(ped, PlayerPedId(), false) end if collision then SetEntityNoCollisionEntity(ped, PlayerPedId(), false) end
if scenario then TaskStartScenarioInPlace(ped, scenario, 0, true) end if scenario then TaskStartScenarioInPlace(ped, scenario, 0, true) end
if anim then if anim then
loadAnimDict(anim[1]) loadAnimDict(anim[1])
TaskPlayAnim(ped, anim[1], anim[2], 0.5, 1.0, -1, 1, 0.2, 0, 0, 0) TaskPlayAnim(ped, anim[1], anim[2], 0.5, 1.0, -1, 1, 0.2, 0, 0, 0)
end end
debugPrint("^6Bridge^7: ^1Ped ^2Created^7: '^6"..ped.."^7' | ^2Hash^7: ^7'^5"..(model).."^7' | ^2Coord^7: "..formatCoord(coords)) debugPrint("^6Bridge^7: ^1Ped ^2Created^7: '^6"..ped.."^7' | ^2Hash^7: ^7'^5"..(model).."^7' | ^2Coord^7: "..formatCoord(coords))
unloadModel(model) unloadModel(model)
Peds[#Peds + 1] = ped Peds[#Peds + 1] = ped
return ped return ped
end end
--- Generates random Ped data by filling in missing customization options with random values. --- Generates random Ped data by filling in missing customization options with random values.
-- --
-- This function takes in a data table that may have some customization options missing in `data.custom`. -- This function takes in a data table that may have some customization options missing in `data.custom`.
-- --
-- It generates random values for any missing options and returns a new data table with complete customization. -- It generates random values for any missing options and returns a new data table with complete customization.
-- --
---@param data table A table containing at least a `model` field, and possibly a `custom` table with customization options. ---@param data table A table containing at least a `model` field, and possibly a `custom` table with customization options.
-- --
---@return generatedTable table A new table containing `model` and `custom` with all customization options filled. ---@return generatedTable table A new table containing `model` and `custom` with all customization options filled.
-- --
---@usage ---@usage
-- ```lua -- ```lua
-- local pedData = GenerateRandomPedData({ model = `MP_M_Freemode_01`, custom = {} }) -- local pedData = GenerateRandomPedData({ model = `MP_M_Freemode_01`, custom = {} })
-- ``` -- ```
function GenerateRandomPedData(data) function GenerateRandomPedData(data)
local newTable = { local newTable = {
model = data.model, model = data.model,
custom = {}, custom = {},
} }
local isMale = data.model == `MP_M_Freemode_01` local isMale = data.model == `MP_M_Freemode_01`
local randomTable = { local randomTable = {
-- Inheritance -- Inheritance
faceFather = math.random(0, 45), faceMother = math.random(0, 45), faceMix = (math.random(0, 9) / 10), faceFather = math.random(0, 45), faceMother = math.random(0, 45), faceMix = (math.random(0, 9) / 10),
skinFather = math.random(0, 45), skinMother = math.random(0, 45), skinMix = (math.random(0, 9) / 10), skinFather = math.random(0, 45), skinMother = math.random(0, 45), skinMix = (math.random(0, 9) / 10),
raceShape = math.random(0, 45), raceSkin = math.random(0, 45), raceMix = (math.random(0, 9) / 10), raceShape = math.random(0, 45), raceSkin = math.random(0, 45), raceMix = (math.random(0, 9) / 10),
-- Face Features -- Face Features
noseWidth = (math.random(0, 9) / 10), noseWidth = (math.random(0, 9) / 10),
noseHeight = (math.random(0, 9) / 10), noseHeight = (math.random(0, 9) / 10),
noseSize = (math.random(0, 9) / 10), noseSize = (math.random(0, 9) / 10),
noseBoneHeight = (math.random(0, 9) / 10), noseBoneHeight = (math.random(0, 9) / 10),
nosePeakHeight = (math.random(0, 9) / 10), nosePeakHeight = (math.random(0, 9) / 10),
noseBoneTwist = (math.random(0, 9) / 10), noseBoneTwist = (math.random(0, 9) / 10),
eyebrowHeight = (math.random(0, 9) / 10), eyebrowHeight = (math.random(0, 9) / 10),
eyebrowDepth = (math.random(0, 9) / 10), eyebrowDepth = (math.random(0, 9) / 10),
cheekBoneHeight = (math.random(0, 9) / 10), cheekBoneHeight = (math.random(0, 9) / 10),
cheekBoneWidth = (math.random(0, 9) / 10), cheekBoneWidth = (math.random(0, 9) / 10),
cheeckWidth = (math.random(0, 9) / 10), cheeckWidth = (math.random(0, 9) / 10),
eyeOpening = (math.random(0, 9) / 10), eyeOpening = (math.random(0, 9) / 10),
lipThickness = (math.random(0, 9) / 10), lipThickness = (math.random(0, 9) / 10),
jawWidth = (math.random(0, 9) / 10), jawWidth = (math.random(0, 9) / 10),
jawSize = (math.random(0, 9) / 10), jawSize = (math.random(0, 9) / 10),
chinLowering = (math.random(0, 9) / 10), chinLowering = (math.random(0, 9) / 10),
chinLength = (math.random(0, 9) / 10), chinLength = (math.random(0, 9) / 10),
chinSize = (math.random(0, 9) / 10), chinSize = (math.random(0, 9) / 10),
chinHole = (math.random(0, 9) / 10), chinHole = (math.random(0, 9) / 10),
neckThickness = (math.random(0, 9) / 10), neckThickness = (math.random(0, 9) / 10),
-- Appearance -- Appearance
Hair = math.random(0, isMale and 147 or 261), HairTexture = math.random(0, 63), HairHighlight = math.random(0, 63), Hair = math.random(0, isMale and 147 or 261), HairTexture = math.random(0, 63), HairHighlight = math.random(0, 63),
Eyebrows = math.random(0, 33), Eyebrows = math.random(0, 33),
EyebrowsOpacity = 0.9, EyebrowsColor = 0, EyebrowsOpacity = 0.9, EyebrowsColor = 0,
Eyecolor = math.random(0, 30), Eyecolor = math.random(0, 30),
Makeup = 0, MakeupOpacity = 0, MakeupColor = 0, Makeup = 0, MakeupOpacity = 0, MakeupColor = 0,
Lipstick = 0, LipstickOpacity = 0, LipstickColor = 0, Lipstick = 0, LipstickOpacity = 0, LipstickColor = 0,
Beard = isMale and math.random(0, 28) or -1, Beard = isMale and math.random(0, 28) or -1,
BeardOpacity = isMale and 0.9 or 0.0, BeardColor = 0, BeardOpacity = isMale and 0.9 or 0.0, BeardColor = 0,
-- Clothing -- Clothing
Mask = math.random(0, 252), MaskVariant = 0, Mask = math.random(0, 252), MaskVariant = 0,
Scarf = math.random(0, isMale and 249 or 198), ScarfVariant = 0, Scarf = math.random(0, isMale and 249 or 198), ScarfVariant = 0,
Jacket = math.random(0, isMale and 634 or 713), JacketVariant = 0, Jacket = math.random(0, isMale and 634 or 713), JacketVariant = 0,
Shirt = math.random(0, isMale and 237 or 299), ShirtVariant = 0, Shirt = math.random(0, isMale and 237 or 299), ShirtVariant = 0,
Vest = math.random(0, isMale and 81 or 91), VestVariant = 0, Vest = math.random(0, isMale and 81 or 91), VestVariant = 0,
Bags = math.random(0, isMale and 138 or 148), BagsVariant = 0, Bags = math.random(0, isMale and 138 or 148), BagsVariant = 0,
Arms = math.random(0, isMale and 224 or 261), ArmsVariant = 0, Arms = math.random(0, isMale and 224 or 261), ArmsVariant = 0,
Pants = math.random(0, isMale and 255 or 275), PantsVariant = 0, Pants = math.random(0, isMale and 255 or 275), PantsVariant = 0,
Shoes = math.random(0, isMale and 157 or 199), ShoesVariant = 0, Shoes = math.random(0, isMale and 157 or 199), ShoesVariant = 0,
Decal = math.random(0, isMale and 238 or 253), DecalVariant = 0, Decal = math.random(0, isMale and 238 or 253), DecalVariant = 0,
-- Accessories -- Accessories
Hat = math.random(0, isMale and 232 or 229), HatVariant = 0, Hat = math.random(0, isMale and 232 or 229), HatVariant = 0,
Glasses = math.random(0, isMale and 68 or 71), GlassesVariant = 0, Glasses = math.random(0, isMale and 68 or 71), GlassesVariant = 0,
Ear = math.random(0, isMale and 51 or 40), EarVariant = 0, Ear = math.random(0, isMale and 51 or 40), EarVariant = 0,
Watches = math.random(0, isMale and 46 or 35), WatchesVariant = 0, Watches = math.random(0, isMale and 46 or 35), WatchesVariant = 0,
Bracelets = math.random(0, isMale and 13 or 20), BraceletsVariant = 0, Bracelets = math.random(0, isMale and 13 or 20), BraceletsVariant = 0,
} }
for option in pairs(randomTable) do for option in pairs(randomTable) do
if not data.custom[option] then if not data.custom[option] then
newTable.custom[option] = randomTable[option] newTable.custom[option] = randomTable[option]
debugPrint("^6Bridge^7: ^2Picking Random Ped option ^7[^5"..option.."^7]: ^6"..newTable.custom[option].."^7") debugPrint("^6Bridge^7: ^2Picking Random Ped option ^7[^5"..option.."^7]: ^6"..newTable.custom[option].."^7")
else else
newTable.custom[option] = data.custom[option] newTable.custom[option] = data.custom[option]
end end
end end
return newTable return newTable
end end
--- Cleans up all created Peds when the resource stops. --- Cleans up all created Peds when the resource stops.
onResourceStop(function() for i = 1, #Peds do DeletePed(Peds[i]) end end, true) onResourceStop(function() for i = 1, #Peds do DeletePed(Peds[i]) end end, true)

View File

@@ -1,90 +1,90 @@
local Props = {} local Props = {}
--- Creates a prop (object) in the game world at specified coordinates. --- Creates a prop (object) in the game world at specified coordinates.
--- ---
--- This function loads the model, creates the object, sets its heading, and freezes it if specified. --- This function loads the model, creates the object, sets its heading, and freezes it if specified.
--- ---
---@param data table A table containing prop data. ---@param data table A table containing prop data.
--- - **prop** `string`: The model name or hash of the prop to create. --- - **prop** `string`: The model name or hash of the prop to create.
--- - **coords** `vector4`: The coordinates where the prop will be placed. Should include x, y, z, and w (heading). --- - **coords** `vector4`: The coordinates where the prop will be placed. Should include x, y, z, and w (heading).
---@param freeze boolean (optional) Whether to freeze the prop in place. Defaults to `false`. ---@param freeze boolean (optional) Whether to freeze the prop in place. Defaults to `false`.
---@param synced boolean (optional) Whether the prop should be synced across clients. Defaults to `false`. ---@param synced boolean (optional) Whether the prop should be synced across clients. Defaults to `false`.
--- ---
---@return number entityID The handle of the created prop object. ---@return number entityID The handle of the created prop object.
--- ---
---@usage ---@usage
--- ```lua --- ```lua
--- local propData = { --- local propData = {
--- prop = 'prop_chair_01a', --- prop = 'prop_chair_01a',
--- coords = vector4(123.4, 567.8, 90.1, 180.0) --- coords = vector4(123.4, 567.8, 90.1, 180.0)
--- } --- }
--- local prop = makeProp(propData, true, false) --- local prop = makeProp(propData, true, false)
--- ``` --- ```
function makeProp(data, freeze, synced) function makeProp(data, freeze, synced)
loadModel(data.prop) loadModel(data.prop)
local prop = CreateObject(data.prop, data.coords.x, data.coords.y, data.coords.z-1.03, synced and synced or false, synced and synced or false, false) local prop = CreateObject(data.prop, data.coords.x, data.coords.y, data.coords.z-1.03, synced and synced or false, synced and synced or false, false)
SetEntityHeading(prop, data.coords.w + 180.0) SetEntityHeading(prop, data.coords.w + 180.0)
FreezeEntityPosition(prop, freeze or false) FreezeEntityPosition(prop, freeze or false)
debugPrint("^6Bridge^7: ^1Prop ^2Created^7: '^6"..prop.."^7' | ^2Hash^7: ^7'^6"..data.prop.."^7' | ^2Coord^7: "..formatCoord(data.coords)) debugPrint("^6Bridge^7: ^1Prop ^2Created^7: '^6"..prop.."^7' | ^2Hash^7: ^7'^6"..data.prop.."^7' | ^2Coord^7: "..formatCoord(data.coords))
SetModelAsNoLongerNeeded(data.prop) SetModelAsNoLongerNeeded(data.prop)
Props[#Props + 1] = prop Props[#Props + 1] = prop
return prop return prop
end end
--- Creates a prop that appears when the player is within a certain distance. --- Creates a prop that appears when the player is within a certain distance.
--- ---
--- This function sets up a proximity area, and when the player enters it, the prop is created. --- This function sets up a proximity area, and when the player enters it, the prop is created.
--- When the player exits the area, the prop is destroyed. --- When the player exits the area, the prop is destroyed.
--- ---
---@param data table A table containing prop data. ---@param data table A table containing prop data.
--- - **prop** `string`: The model name or hash of the prop to create. --- - **prop** `string`: The model name or hash of the prop to create.
--- - **coords** `vector4`: The coordinates where the prop will be placed. Should include x, y, z, and w (heading). --- - **coords** `vector4`: The coordinates where the prop will be placed. Should include x, y, z, and w (heading).
---@param freeze boolean (optional) Whether to freeze the prop in place. Defaults to `false`. ---@param freeze boolean (optional) Whether to freeze the prop in place. Defaults to `false`.
---@param synced boolean (optional) Whether the prop should be synced across clients. Defaults to `false`. ---@param synced boolean (optional) Whether the prop should be synced across clients. Defaults to `false`.
--- ---
---@usage ---@usage
--- ```lua --- ```lua
--- local propData = { --- local propData = {
--- prop = 'prop_chair_01a', --- prop = 'prop_chair_01a',
--- coords = vector4(123.4, 567.8, 90.1, 180.0) --- coords = vector4(123.4, 567.8, 90.1, 180.0)
--- } --- }
--- makeDistProp(propData, true, false) --- makeDistProp(propData, true, false)
--- ``` --- ```
function makeDistProp(data, freeze, synced) function makeDistProp(data, freeze, synced)
local prop = nil local prop = nil
createCirclePoly({ createCirclePoly({
name = keyGen()..keyGen(), name = keyGen()..keyGen(),
coords = vec3(data.coords.x, data.coords.y, data.coords.z - 1.03), coords = vec3(data.coords.x, data.coords.y, data.coords.z - 1.03),
radius = 50.0, radius = 50.0,
onEnter = function() onEnter = function()
prop = makeProp(data, freeze, synced) prop = makeProp(data, freeze, synced)
end, end,
onExit = function() onExit = function()
destroyProp(prop) destroyProp(prop)
end, end,
debug = debugMode, debug = debugMode,
}) })
end end
--- Destroys a prop, detaching it if attached to the player beforehand. --- Destroys a prop, detaching it if attached to the player beforehand.
--- ---
---@param entity number The handle of the prop entity to destroy. ---@param entity number The handle of the prop entity to destroy.
--- ---
---@usage ---@usage
--- ```lua --- ```lua
--- destroyProp(prop) --- destroyProp(prop)
--- ``` --- ```
function destroyProp(entity) function destroyProp(entity)
if entity then if entity then
debugPrint("^6Bridge^7: ^2Destroying Prop^7: '^6"..entity.."^7'") debugPrint("^6Bridge^7: ^2Destroying Prop^7: '^6"..entity.."^7'")
if IsEntityAttachedToEntity(entity, PlayerPedId()) then if IsEntityAttachedToEntity(entity, PlayerPedId()) then
SetEntityAsMissionEntity(entity) SetEntityAsMissionEntity(entity)
DetachEntity(entity, true, true) DetachEntity(entity, true, true)
end end
DeleteObject(entity) DeleteObject(entity)
end end
end end
--- Cleans up all created props when the resource stops. --- Cleans up all created props when the resource stops.
onResourceStop(function() for i = 1, #Props do destroyProp(Props[i]) end end, true) onResourceStop(function() for i = 1, #Props do destroyProp(Props[i]) end end, true)

View File

@@ -1,73 +1,73 @@
local Vehicles = {} local Vehicles = {}
--- Creates a vehicle with the specified model and coordinates. --- Creates a vehicle with the specified model and coordinates.
--- ---
--- This function loads the vehicle model, creates the vehicle in the world at the given coordinates, sets initial properties, and returns the vehicle handle. --- This function loads the vehicle model, creates the vehicle in the world at the given coordinates, sets initial properties, and returns the vehicle handle.
--- ---
---@param model string|number The model name or hash of the vehicle to create. ---@param model string|number The model name or hash of the vehicle to create.
---@param coords vector4 The coordinates where the vehicle will be placed, including x, y, z, and w (heading). ---@param coords vector4 The coordinates where the vehicle will be placed, including x, y, z, and w (heading).
--- ---
---@return number entityID The handle of the created vehicle. ---@return number entityID The handle of the created vehicle.
--- ---
---@usage ---@usage
--- ```lua --- ```lua
--- local vehicle = makeVeh('adder', vector4(123.4, 567.8, 90.1, 180.0)) --- local vehicle = makeVeh('adder', vector4(123.4, 567.8, 90.1, 180.0))
--- ``` --- ```
function makeVeh(model, coords) function makeVeh(model, coords)
loadModel(model) loadModel(model)
local veh = CreateVehicle(model, coords.x, coords.y, coords.z, coords.w, true, false) local veh = CreateVehicle(model, coords.x, coords.y, coords.z, coords.w, true, false)
SetVehicleHasBeenOwnedByPlayer(veh, true) SetVehicleHasBeenOwnedByPlayer(veh, true)
SetNetworkIdCanMigrate(NetworkGetNetworkIdFromEntity(veh), true) SetNetworkIdCanMigrate(NetworkGetNetworkIdFromEntity(veh), true)
Wait(100) Wait(100)
SetVehicleNeedsToBeHotwired(veh, false) SetVehicleNeedsToBeHotwired(veh, false)
SetVehRadioStation(veh, 'OFF') SetVehRadioStation(veh, 'OFF')
SetVehicleFuelLevel(veh, 100.0) SetVehicleFuelLevel(veh, 100.0)
SetVehicleModKit(veh, 0) SetVehicleModKit(veh, 0)
SetVehicleOnGroundProperly(veh) SetVehicleOnGroundProperly(veh)
debugPrint("^6Bridge^7: ^1Veh ^2Created^7: '^6"..veh.."^7' | ^2Hash^7: ^7'^6"..model.."^7' | ^2Coord^7: "..formatCoord(coords)) debugPrint("^6Bridge^7: ^1Veh ^2Created^7: '^6"..veh.."^7' | ^2Hash^7: ^7'^6"..model.."^7' | ^2Coord^7: "..formatCoord(coords))
unloadModel(model) unloadModel(model)
Vehicles[#Vehicles + 1] = veh Vehicles[#Vehicles + 1] = veh
return veh return veh
end end
--- Attempts to gain network control of a vehicle and set it as a mission entity. --- 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. --- This function forces synchronization of a vehicle with other players by requesting network control and setting the vehicle as a mission entity.
--- ---
---@param entity number The handle of the vehicle entity to push. ---@param entity number The handle of the vehicle entity to push.
--- ---
---@usage ---@usage
--- ```lua --- ```lua
--- pushVehicle(vehicle) --- pushVehicle(vehicle)
--- ``` --- ```
function pushVehicle(entity) function pushVehicle(entity)
SetVehicleModKit(entity, 0) SetVehicleModKit(entity, 0)
if entity ~= 0 and DoesEntityExist(entity) then if entity ~= 0 and DoesEntityExist(entity) then
if not NetworkHasControlOfEntity(entity) then if not NetworkHasControlOfEntity(entity) then
debugPrint("^6Bridge^7: ^3pushVehicle^7: ^2Requesting network control of vehicle^7.") debugPrint("^6Bridge^7: ^3pushVehicle^7: ^2Requesting network control of vehicle^7.")
NetworkRequestControlOfEntity(entity) NetworkRequestControlOfEntity(entity)
local timeout = 2000 local timeout = 2000
while timeout > 0 and not NetworkHasControlOfEntity(entity) do while timeout > 0 and not NetworkHasControlOfEntity(entity) do
Wait(100) Wait(100)
timeout -= 100 timeout -= 100
end end
if NetworkHasControlOfEntity(entity) then debugPrint("^6Bridge^7: ^3pushVehicle^7: ^2Network has control of entity^7.") end if NetworkHasControlOfEntity(entity) then debugPrint("^6Bridge^7: ^3pushVehicle^7: ^2Network has control of entity^7.") end
end end
if not IsEntityAMissionEntity(entity) then if not IsEntityAMissionEntity(entity) then
debugPrint("^6Bridge^7: ^3pushVehicle^7: ^2Setting vehicle as a ^7'^2mission^7' ^2entity^7.") debugPrint("^6Bridge^7: ^3pushVehicle^7: ^2Setting vehicle as a ^7'^2mission^7' ^2entity^7.")
SetEntityAsMissionEntity(entity, true, true) SetEntityAsMissionEntity(entity, true, true)
local timeout = 2000 local timeout = 2000
while timeout > 0 and not IsEntityAMissionEntity(entity) do while timeout > 0 and not IsEntityAMissionEntity(entity) do
Wait(100) Wait(100)
timeout -= 100 timeout -= 100
end end
if IsEntityAMissionEntity(entity) then debugPrint("^6Bridge^7: ^3pushVehicle^7: ^2Vehicle is a ^7'^2mission^7'^2 entity^7.") end if IsEntityAMissionEntity(entity) then debugPrint("^6Bridge^7: ^3pushVehicle^7: ^2Vehicle is a ^7'^2mission^7'^2 entity^7.") end
end end
end end
end end
--- Cleans up all created vehicles when the resource stops. --- Cleans up all created vehicles when the resource stops.
onResourceStop(function(r) onResourceStop(function(r)
for i = 1, #Vehicles do DeleteVehicle(Vehicles[i]) end for i = 1, #Vehicles do DeleteVehicle(Vehicles[i]) end
end) end)

View File

@@ -1,209 +1,209 @@
local inProgress = false local inProgress = false
--- Displays a progress bar using the configured progress bar system. --- Displays a progress bar using the configured progress bar system.
--- ---
--- This function handles displaying a progress bar to the player using the specified progress bar system (e.g., ox, qb, esx, gta). --- This function handles displaying a progress bar to the player using the specified progress bar system (e.g., ox, qb, esx, gta).
--- It supports shared progress bars between players, animations, camera effects, and more. --- It supports shared progress bars between players, animations, camera effects, and more.
--- ---
---@param data table A table containing the progress bar configuration. ---@param data table A table containing the progress bar configuration.
--- - **label** (`string`): The text label to display on the progress bar. --- - **label** (`string`): The text label to display on the progress bar.
--- - **time** (`number`): The duration of the progress bar in milliseconds. --- - **time** (`number`): The duration of the progress bar in milliseconds.
--- - **dict** (`string`, optional): The animation dictionary to use. --- - **dict** (`string`, optional): The animation dictionary to use.
--- - **anim** (`string`, optional): The animation name to play. --- - **anim** (`string`, optional): The animation name to play.
--- - **task** (`string`, optional): The task scenario to perform. --- - **task** (`string`, optional): The task scenario to perform.
--- - **flag** (`number`, optional): The animation flag. --- - **flag** (`number`, optional): The animation flag.
--- - **dead** (`boolean`, optional): Whether to allow the progress bar when the player is dead. Default is `false`. --- - **dead** (`boolean`, optional): Whether to allow the progress bar when the player is dead. Default is `false`.
--- - **cancel** (`boolean`, optional): Whether the progress bar can be canceled by the player. Default is `true`. --- - **cancel** (`boolean`, optional): Whether the progress bar can be canceled by the player. Default is `true`.
--- - **icon** (`string`, optional): The icon to display (for qb progress bar). --- - **icon** (`string`, optional): The icon to display (for qb progress bar).
--- - **cam** (`number`, optional): The camera handle to use. --- - **cam** (`number`, optional): The camera handle to use.
--- - **shared** (`table`, optional): Data for shared progress bars. --- - **shared** (`table`, optional): Data for shared progress bars.
--- - **pid** (`number`): The player ID to share the progress bar with. --- - **pid** (`number`): The player ID to share the progress bar with.
--- - **label** (`string`): The label to display on the shared progress bar. --- - **label** (`string`): The label to display on the shared progress bar.
--- ---
--- @return boolean `true` if the progress bar completed successfully, or `false` if it was canceled. --- @return boolean `true` if the progress bar completed successfully, or `false` if it was canceled.
--- ---
---@usage ---@usage
--- ```lua --- ```lua
--- local success = progressBar({ --- local success = progressBar({
--- label = "Processing...", --- label = "Processing...",
--- time = 5000, --- time = 5000,
--- dict = "amb@world_human_hang_out_street@female_hold_arm@base", --- dict = "amb@world_human_hang_out_street@female_hold_arm@base",
--- anim = "base", --- anim = "base",
--- flag = 49, --- flag = 49,
--- cancel = true, --- cancel = true,
--- }) --- })
--- ``` --- ```
function progressBar(data) function progressBar(data)
local ped = PlayerPedId() local ped = PlayerPedId()
if data.shared then if data.shared then
debugPrint("^6Bridge^7: ^6Sharing progressBar to player^7: ^6"..data.shared.pid.."^7") debugPrint("^6Bridge^7: ^6Sharing progressBar to player^7: ^6"..data.shared.pid.."^7")
storedPID = data.shared.pid storedPID = data.shared.pid
TriggerServerEvent(getScript()..":server:sharedProg:Start", data) TriggerServerEvent(getScript()..":server:sharedProg:Start", data)
end end
local result = nil local result = nil
if data.cam then startTempCam(data.cam) end if data.cam then startTempCam(data.cam) end
if Config.System.ProgressBar == "ox" then if Config.System.ProgressBar == "ox" then
if exports[OXLibExport]:progressBar({ if exports[OXLibExport]:progressBar({
duration = debugMode and 1000 or data.time, duration = debugMode and 1000 or data.time,
label = data.label, label = data.label,
useWhileDead = data.dead or false, useWhileDead = data.dead or false,
canCancel = data.cancel and data.cancel or true, canCancel = data.cancel and data.cancel or true,
anim = { anim = {
dict = data.dict, dict = data.dict,
clip = data.anim, clip = data.anim,
flag = (data.flag == 8 and 32 or data.flag) or nil, flag = (data.flag == 8 and 32 or data.flag) or nil,
scenario = data.task scenario = data.task
}, },
disable = { disable = {
combat = true combat = true
}, },
}) then }) then
result = true result = true
else else
result = false result = false
end end
elseif Config.System.ProgressBar == "qb" then elseif Config.System.ProgressBar == "qb" then
Core.Functions.Progressbar("progbar", Core.Functions.Progressbar("progbar",
data.label, data.label,
debugMode and 1000 or data.time, debugMode and 1000 or data.time,
data.dead or false, data.dead or false,
data.cancel or true, data.cancel or true,
{ disableMovement = true, disableCarMovement = true, disableMouse = false, disableCombat = true }, { disableMovement = true, disableCarMovement = true, disableMouse = false, disableCombat = true },
{ animDict = data.dict, anim = data.anim, flags = data.flag or 32, task = data.task }, {}, {}, { animDict = data.dict, anim = data.anim, flags = data.flag or 32, task = data.task }, {}, {},
function() function()
result = true result = true
end, function() end, function()
result = false result = false
end, data.icon) end, data.icon)
elseif Config.System.ProgressBar == "esx" then elseif Config.System.ProgressBar == "esx" then
ESX.Progressbar(data.label, debugMode and 1000 or data.time, { ESX.Progressbar(data.label, debugMode and 1000 or data.time, {
FreezePlayer = true, FreezePlayer = true,
animation = { animation = {
type = data.anim, type = data.anim,
dict = data.dict, dict = data.dict,
scenario = data.task, scenario = data.task,
}, },
onFinish = function() onFinish = function()
result = true result = true
end, end,
onCancel = function() onCancel = function()
result = false result = false
end end
}) })
elseif Config.System.ProgressBar == "gta" then elseif Config.System.ProgressBar == "gta" then
local wait = debugMode and 1000 or data.time local wait = debugMode and 1000 or data.time
inProgress = true inProgress = true
if not (data.dead or false) then if not (data.dead or false) then
lockInv(true) lockInv(true)
displaySpinner(data.label) displaySpinner(data.label)
if data.dict then if data.dict then
playAnim(data.dict, data.anim, -1, (data.flag == 8 and 32 or data.flag) or nil) playAnim(data.dict, data.anim, -1, (data.flag == 8 and 32 or data.flag) or nil)
end end
if data.task then if data.task then
TaskStartScenarioInPlace(ped, data.task, -1, true) TaskStartScenarioInPlace(ped, data.task, -1, true)
end end
while inProgress and wait > 0 do while inProgress and wait > 0 do
wait -= 15 wait -= 15
local waitTimer = 0 local waitTimer = 0
DisablePlayerFiring(ped, true) DisablePlayerFiring(ped, true)
DisableControlAction(0, 25, true) -- Disable aim DisableControlAction(0, 25, true) -- Disable aim
DisableControlAction(0, 21, true) -- Disable sprint DisableControlAction(0, 21, true) -- Disable sprint
DisableControlAction(0, 30, true) -- Disable move left/right DisableControlAction(0, 30, true) -- Disable move left/right
DisableControlAction(0, 31, true) -- Disable move forward/back DisableControlAction(0, 31, true) -- Disable move forward/back
DisableControlAction(0, 36, true) -- Disable stealth DisableControlAction(0, 36, true) -- Disable stealth
if data.cam ~= nil then if data.cam ~= nil then
DisableControlAction(0, 1, true) -- Disable look left/right DisableControlAction(0, 1, true) -- Disable look left/right
DisableControlAction(0, 2, true) -- Disable look up/down DisableControlAction(0, 2, true) -- Disable look up/down
DisableControlAction(0, 106, true) -- Disable vehicle mouse control DisableControlAction(0, 106, true) -- Disable vehicle mouse control
end end
if data.cancel then if data.cancel then
if IsControlJustReleased(0, 202) or IsControlJustReleased(0, 77) then -- Cancel key (Backspace or Delete) if IsControlJustReleased(0, 202) or IsControlJustReleased(0, 77) then -- Cancel key (Backspace or Delete)
inProgress = false inProgress = false
waitTimer = 1500 waitTimer = 1500
displaySpinner(Loc[Config.Lan].error["cancel"]) displaySpinner(Loc[Config.Lan].error["cancel"])
end end
end end
Wait(waitTimer) Wait(waitTimer)
end end
inProgress = false inProgress = false
if data.dict then stopAnim(data.dict, data.anim, ped) end if data.dict then stopAnim(data.dict, data.anim, ped) end
ClearPedTasks(ped) ClearPedTasks(ped)
end end
stopSpinner() stopSpinner()
result = (wait <= 0) result = (wait <= 0)
end end
while result == nil do Wait(10) end while result == nil do Wait(10) end
-- Cleanup -- Cleanup
FreezeEntityPosition(ped, false) FreezeEntityPosition(ped, false)
lockInv(false) lockInv(false)
if data.cam then stopTempCam(data.cam) end if data.cam then stopTempCam(data.cam) end
if result == false and data.shared then if result == false and data.shared then
debugPrint("^6Bridge^7: ^2Sending cancel to ^6"..storedPID.."^7") debugPrint("^6Bridge^7: ^2Sending cancel to ^6"..storedPID.."^7")
TriggerServerEvent(getScript().."server:sharedProg:cancel", storedPID) TriggerServerEvent(getScript().."server:sharedProg:cancel", storedPID)
end end
storedPID = nil storedPID = nil
return result return result
end end
--- Stops the current progress bar. --- Stops the current progress bar.
--- ---
--- This function cancels the progress bar based on the configured progress bar system, handling any necessary cleanup. --- This function cancels the progress bar based on the configured progress bar system, handling any necessary cleanup.
function stopPropgressBar() function stopPropgressBar()
if Config.System.ProgressBar == "ox" then if Config.System.ProgressBar == "ox" then
exports[OXLibExport]:cancelProgress() exports[OXLibExport]:cancelProgress()
elseif Config.System.ProgressBar == "qb" then elseif Config.System.ProgressBar == "qb" then
TriggerEvent("progressbar:client:cancel") TriggerEvent("progressbar:client:cancel")
elseif Config.System.ProgressBar == "gta" then elseif Config.System.ProgressBar == "gta" then
inProgress = false inProgress = false
BusyspinnerOff() BusyspinnerOff()
end end
end end
-- System to handle sending/sharing progress bars between players -- -- System to handle sending/sharing progress bars between players --
-- For example, healing someone -- -- For example, healing someone --
local storedPID = nil local storedPID = nil
--- Server event handler for starting a shared progress bar. --- Server event handler for starting a shared progress bar.
--- This event is triggered when a player wants to start a progress bar on another player. --- This event is triggered when a player wants to start a progress bar on another player.
--- It adjusts the data to prevent loops and sends the data to the target client. --- It adjusts the data to prevent loops and sends the data to the target client.
RegisterNetEvent(getScript()..":server:sharedProg:Start", function(data) RegisterNetEvent(getScript()..":server:sharedProg:Start", function(data)
local pid = data.shared.pid -- Get player ID from the client local pid = data.shared.pid -- Get player ID from the client
data.label = data.shared.label -- Set progress bar label to the shared label data.label = data.shared.label -- Set progress bar label to the shared label
data.cancel = false -- Make it so it can't be canceled data.cancel = false -- Make it so it can't be canceled
data.dead = true -- Allow progress bar even if player is dead data.dead = true -- Allow progress bar even if player is dead
data.shared = nil -- Remove shared info to prevent loops data.shared = nil -- Remove shared info to prevent loops
data.anim = nil -- Remove animation so players don't share it data.anim = nil -- Remove animation so players don't share it
debugPrint("^6Bridge^7: ^6"..source.." ^2is sending shared progressBar to player^7, ^6"..pid.."^7") debugPrint("^6Bridge^7: ^6"..source.." ^2is sending shared progressBar to player^7, ^6"..pid.."^7")
TriggerClientEvent(getScript()..":client:sharedProg:Start", pid, data) TriggerClientEvent(getScript()..":client:sharedProg:Start", pid, data)
end) end)
--- Client event handler for starting a shared progress bar. --- Client event handler for starting a shared progress bar.
--- This event is triggered when the server wants the client to start a shared progress bar. --- This event is triggered when the server wants the client to start a shared progress bar.
RegisterNetEvent(getScript()..":client:sharedProg:Start", function(data) RegisterNetEvent(getScript()..":client:sharedProg:Start", function(data)
debugPrint("^6Bridge^7: ^2You have been sent a progressBar^7") debugPrint("^6Bridge^7: ^2You have been sent a progressBar^7")
progressBar(data) progressBar(data)
end) end)
--- Server event handler for canceling a shared progress bar. --- Server event handler for canceling a shared progress bar.
--- This event is triggered when a progress bar is canceled and the server needs to notify the other player. --- This event is triggered when a progress bar is canceled and the server needs to notify the other player.
RegisterNetEvent(getScript()..":server:sharedProg:Cancel", function(pid) RegisterNetEvent(getScript()..":server:sharedProg:Cancel", function(pid)
debugPrint("^6Bridge^7: ^2Sending cancel progressBar to ^6"..pid.."^7") debugPrint("^6Bridge^7: ^2Sending cancel progressBar to ^6"..pid.."^7")
TriggerClientEvent(getScript()..":client:sharedProg:Cancel", pid) TriggerClientEvent(getScript()..":client:sharedProg:Cancel", pid)
end) end)
--- Client event handler for canceling a shared progress bar. --- Client event handler for canceling a shared progress bar.
--- This event is triggered when the server wants the client to cancel a shared progress bar. --- This event is triggered when the server wants the client to cancel a shared progress bar.
RegisterNetEvent(getScript()..":client:sharedProg:Cancel", function() RegisterNetEvent(getScript()..":client:sharedProg:Cancel", function()
debugPrint("^6Bridge^7: ^2Receiving cancel progressBar^7") debugPrint("^6Bridge^7: ^2Receiving cancel progressBar^7")
stopPropgressBar() stopPropgressBar()
end) end)
--- Cleans up when the resource stops. --- Cleans up when the resource stops.
--- This event handler ensures that any active spinners or progress bars are stopped when the resource is stopped. --- This event handler ensures that any active spinners or progress bars are stopped when the resource is stopped.
onResourceStop(function() stopSpinner() end, true) onResourceStop(function() stopSpinner() end, true)

View File

@@ -1,88 +1,88 @@
-- NOTIFICATIONS -- -- NOTIFICATIONS --
-- This function is widely used to display notifications to the player, can be used server side or client side -- -- This function is widely used to display notifications to the player, can be used server side or client side --
--- Displays notifications to the player using the configured notification system. --- Displays notifications to the player using the configured notification system.
--- ---
--- This function supports multiple notification systems based on the `Config.System.Notify` setting. --- This function supports multiple notification systems based on the `Config.System.Notify` setting.
--- It can be triggered from both client-side and server-side scripts. Depending on the configuration, --- It can be triggered from both client-side and server-side scripts. Depending on the configuration,
--- it utilizes different exports or events to display the notification. --- it utilizes different exports or events to display the notification.
--- ---
---@param title string|nil The title of the notification. Optional, used by certain notification systems. ---@param title string|nil The title of the notification. Optional, used by certain notification systems.
---@param message string The main message content of the notification. ---@param message string The main message content of the notification.
---@param type string The type/category of the notification (e.g., "success", "error", "info"). ---@param type string The type/category of the notification (e.g., "success", "error", "info").
---@param src number|nil Optional. The server ID of the player to send the notification to. If `nil`, the notification is sent to the caller. ---@param src number|nil Optional. The server ID of the player to send the notification to. If `nil`, the notification is sent to the caller.
--- ---
---@usage ---@usage
--- ```lua --- ```lua
--- -- Client-side usage without specifying a player (shows to the current player) --- -- Client-side usage without specifying a player (shows to the current player)
--- triggerNotify("Success", "You have completed the task!", "success") --- triggerNotify("Success", "You have completed the task!", "success")
--- ---
--- -- Server-side usage specifying a player by their server ID --- -- Server-side usage specifying a player by their server ID
--- triggerNotify("Alert", "You have been warned for misconduct.", "error", playerId) --- triggerNotify("Alert", "You have been warned for misconduct.", "error", playerId)
--- ``` --- ```
function triggerNotify(title, message, type, src) function triggerNotify(title, message, type, src)
if Config.System.Notify == "okok" then if Config.System.Notify == "okok" then
if not src then TriggerEvent('okokNotify:Alert', title, message, 6000, type) if not src then TriggerEvent('okokNotify:Alert', title, message, 6000, type)
else TriggerClientEvent('okokNotify:Alert', src, title, message, 6000, type) end else TriggerClientEvent('okokNotify:Alert', src, title, message, 6000, type) end
elseif Config.System.Notify == "qb" then elseif Config.System.Notify == "qb" then
if not src then TriggerEvent("QBCore:Notify", message, type) if not src then TriggerEvent("QBCore:Notify", message, type)
else TriggerClientEvent("QBCore:Notify", src, message, type) end else TriggerClientEvent("QBCore:Notify", src, message, type) end
elseif Config.System.Notify == "ox" then elseif Config.System.Notify == "ox" then
if not src then TriggerEvent('ox_lib:notify', {title = title, description = message, type = type or "success"}) if not src then TriggerEvent('ox_lib:notify', {title = title, description = message, type = type or "success"})
else TriggerClientEvent('ox_lib:notify', src, { type = type or "success", title = title, description = message }) end else TriggerClientEvent('ox_lib:notify', src, { type = type or "success", title = title, description = message }) end
elseif Config.System.Notify == "gta" then elseif Config.System.Notify == "gta" then
if not src then TriggerEvent(getScript()..":DisplayGTANotify", title, message) if not src then TriggerEvent(getScript()..":DisplayGTANotify", title, message)
else TriggerClientEvent(getScript()..":DisplayGTANotify", src, title, message) end else TriggerClientEvent(getScript()..":DisplayGTANotify", src, title, message) end
elseif Config.System.Notify == "esx" then elseif Config.System.Notify == "esx" then
if not src then exports["esx_notify"]:Notify(type, 4000, message) if not src then exports["esx_notify"]:Notify(type, 4000, message)
else TriggerClientEvent(getScript()..":DisplayESXNotify", src, type, title, message) end else TriggerClientEvent(getScript()..":DisplayESXNotify", src, type, title, message) end
end end
end end
--- Registers a server-side event to display ESX notifications to clients. --- Registers a server-side event to display ESX notifications to clients.
--- ---
--- This event listens for `DisplayESXNotify` and triggers the ESX notification on the client side. --- This event listens for `DisplayESXNotify` and triggers the ESX notification on the client side.
--- ---
--- @param type string The type/category of the notification (e.g., "success", "error", "info"). --- @param type string The type/category of the notification (e.g., "success", "error", "info").
--- @param title string The title of the notification. --- @param title string The title of the notification.
--- @param text string The main message content of the notification. --- @param text string The main message content of the notification.
--- ---
--- @usage --- @usage
--- ```lua --- ```lua
--- -- Server-side event trigger --- -- Server-side event trigger
--- TriggerClientEvent(getScript()..":DisplayESXNotify", playerId, "success", "Achievement Unlocked", "You have unlocked a new achievement!") --- TriggerClientEvent(getScript()..":DisplayESXNotify", playerId, "success", "Achievement Unlocked", "You have unlocked a new achievement!")
--- ``` --- ```
RegisterNetEvent(getScript()..":DisplayESXNotify", function(type, title, text) RegisterNetEvent(getScript()..":DisplayESXNotify", function(type, title, text)
exports["esx_notify"]:Notify(type, 4000, text) exports["esx_notify"]:Notify(type, 4000, text)
end) end)
--- Displays default GTA-style text notifications. --- Displays default GTA-style text notifications.
--- ---
--- This event handles displaying text-based notifications using GTA's native functions. --- This event handles displaying text-based notifications using GTA's native functions.
--- It supports specific scenarios by assigning different icons based on the script name. --- It supports specific scenarios by assigning different icons based on the script name.
--- ---
---@param title string The title or identifier for the notification, used to select the appropriate icon. ---@param title string The title or identifier for the notification, used to select the appropriate icon.
---@param text string The main message content of the notification. ---@param text string The main message content of the notification.
--- ---
---@usage ---@usage
--- ```lua --- ```lua
--- -- Client-side event trigger --- -- Client-side event trigger
--- TriggerEvent(getScript()..":DisplayGTANotify", "taxiname", "Taxi service has arrived.") --- TriggerEvent(getScript()..":DisplayGTANotify", "taxiname", "Taxi service has arrived.")
--- ``` --- ```
RegisterNetEvent(getScript()..":DisplayGTANotify", function(title, text) RegisterNetEvent(getScript()..":DisplayGTANotify", function(title, text)
local iconTable = {} local iconTable = {}
if getScript() == "jim-npcservice" then if getScript() == "jim-npcservice" then
iconTable = { iconTable = {
[Loc[Config.Lan].notify["taxiname"]] = "CHAR_TAXI", [Loc[Config.Lan].notify["taxiname"]] = "CHAR_TAXI",
[Loc[Config.Lan].notify["limoname"]] = "CHAR_CASINO", [Loc[Config.Lan].notify["limoname"]] = "CHAR_CASINO",
[Loc[Config.Lan].notify["ambiname"]] = "CHAR_CALL911", [Loc[Config.Lan].notify["ambiname"]] = "CHAR_CALL911",
[Loc[Config.Lan].notify["pilotname"]] = "CHAR_DEFAULT", [Loc[Config.Lan].notify["pilotname"]] = "CHAR_DEFAULT",
[Loc[Config.Lan].notify["planename"]] = "CHAR_BOATSITE2", [Loc[Config.Lan].notify["planename"]] = "CHAR_BOATSITE2",
[Loc[Config.Lan].notify["heliname"]] = "CHAR_BOATSITE2", [Loc[Config.Lan].notify["heliname"]] = "CHAR_BOATSITE2",
} }
end end
BeginTextCommandThefeedPost("STRING") BeginTextCommandThefeedPost("STRING")
AddTextComponentSubstringKeyboardDisplay(text) AddTextComponentSubstringKeyboardDisplay(text)
EndTextCommandThefeedPostMessagetext(iconTable[title] or "CHAR_DEFAULT", iconTable[title] or "CHAR_DEFAULT", true, 1, title, nil, text) EndTextCommandThefeedPostMessagetext(iconTable[title] or "CHAR_DEFAULT", iconTable[title] or "CHAR_DEFAULT", true, 1, title, nil, text)
EndTextCommandThefeedPostTicker(true, false) EndTextCommandThefeedPostTicker(true, false)
end) end)

View File

@@ -475,6 +475,18 @@ function getPlayer(source)
name = info.getName(), name = info.getName(),
cash = info.getMoney(), cash = info.getMoney(),
bank = info.getAccount("bank").money, bank = info.getAccount("bank").money,
firstname = info.variables.firstName,
lastname = info.variables.lastName,
source = info.source,
job = info.job.name,
--jobBoss = info.job.isboss,
--gang = info.gang.name,
--gangBoss = info.gang.isboss,
onDuty = info.job.onDuty,
--account = info.charinfo.account,
--citizenId = info.citizenid,
} }
elseif isStarted(OXCoreExport) then elseif isStarted(OXCoreExport) then
@@ -492,9 +504,19 @@ function getPlayer(source)
elseif isStarted(QBXExport) then elseif isStarted(QBXExport) then
local info = exports[QBXExport]:GetPlayer(src) local info = exports[QBXExport]:GetPlayer(src)
Player = { Player = {
firstname = info.PlayerData.charinfo.firstname,
lastname = info.PlayerData.charinfo.lastname,
name = info.PlayerData.charinfo.firstname.." "..info.PlayerData.charinfo.lastname, name = info.PlayerData.charinfo.firstname.." "..info.PlayerData.charinfo.lastname,
cash = exports[OXInv]:Search(src, 'count', "money"), cash = exports[OXInv]:Search(src, 'count', "money"),
bank = info.Functions.GetMoney("bank"), bank = info.Functions.GetMoney("bank"),
source = info.PlayerData.source,
job = info.PlayerData.job.name,
jobBoss = info.PlayerData.job.isboss,
gang = info.PlayerData.gang.name,
gangBoss = info.PlayerData.gang.isboss,
onDuty = info.PlayerData.job.onduty,
account = info.PlayerData.charinfo.account,
citizenId = info.PlayerData.citizenid,
} }
elseif isStarted(QBExport) and not isStarted(QBXExport) then elseif isStarted(QBExport) and not isStarted(QBXExport) then
@@ -541,13 +563,26 @@ function getPlayer(source)
else else
if isStarted(ESXExport) and ESX ~= nil then if isStarted(ESXExport) and ESX ~= nil then
local info = ESX.GetPlayerData() local info = ESX.GetPlayerData()
--jsonPrint(info)
local cash, bank = 0, 0 local cash, bank = 0, 0
for k, v in pairs(ESX.GetPlayerData().accounts) do for k, v in pairs(ESX.GetPlayerData().accounts) do
if v.name == "money" then cash = v.money end if v.name == "money" then cash = v.money end
if v.name == "bank" then bank = v.money end if v.name == "bank" then bank = v.money end
end end
Player = { Player = {
name = ('%s %s'):format(info.firstName, info.lastName), firstname = info.firstName,
lastname = info.lastName,
source = GetPlayerServerId(PlayerId()),
job = info.job.name,
--jobBoss = info.job.isboss,
--gang = info.gang.name,
--gangBoss = info.gang.isboss,
onDuty = info.job.onDuty,
--account = info.charinfo.account,
--citizenId = info.citizenid,
name = info.firstName.." "..info.lastName,
cash = cash, cash = cash,
bank = bank, bank = bank,
} }

View File

@@ -1,116 +1,116 @@
-- This automatically detects what polyzone script it should use to create a polyzone -- -- This automatically detects what polyzone script it should use to create a polyzone --
-- if ox_lib is detected, it will automatically use that instead of PolyZone -- -- if ox_lib is detected, it will automatically use that instead of PolyZone --
-- createPoly({ name = 'name', debug = true, points = { vec2(), vec2() }, onEnter = function() end, onExit = function() end, }) -- createPoly({ name = 'name', debug = true, points = { vec2(), vec2() }, onEnter = function() end, onExit = function() end, })
--- ---
--- Creates a polygonal zone using the detected polyzone library (ox_lib or PolyZone). --- Creates a polygonal zone using the detected polyzone library (ox_lib or PolyZone).
--- ---
--- This function automatically detects whether `ox_lib` or `PolyZone` is active and creates a polygonal zone accordingly. --- This function automatically detects whether `ox_lib` or `PolyZone` is active and creates a polygonal zone accordingly.
--- It supports setting up entry and exit callbacks for the zone. --- It supports setting up entry and exit callbacks for the zone.
--- ---
---@param data table A table containing the zone configuration. ---@param data table A table containing the zone configuration.
--- - **name** (`string`): The name of the zone. --- - **name** (`string`): The name of the zone.
--- - **debug** (`boolean`): Whether to enable debug mode for the zone. --- - **debug** (`boolean`): Whether to enable debug mode for the zone.
--- - **points** (`table`): A list of `vec2` points defining the polygon. --- - **points** (`table`): A list of `vec2` points defining the polygon.
--- - **onEnter** (`function`): Callback function to execute when a player enters the zone. --- - **onEnter** (`function`): Callback function to execute when a player enters the zone.
--- - **onExit** (`function`): Callback function to execute when a player exits the zone. --- - **onExit** (`function`): Callback function to execute when a player exits the zone.
--- ---
---@return table|nil table Returns the created zone object or `nil` if creation failed. ---@return table|nil table Returns the created zone object or `nil` if creation failed.
--- ---
---@usage ---@usage
--- ```lua --- ```lua
--- createPoly({ --- createPoly({
--- name = 'testZone', --- name = 'testZone',
--- debug = true, --- debug = true,
--- points = { vec2(100.0, 100.0), vec2(200.0, 100.0), vec2(200.0, 200.0), vec2(100.0, 200.0) }, --- points = { vec2(100.0, 100.0), vec2(200.0, 100.0), vec2(200.0, 200.0), vec2(100.0, 200.0) },
--- onEnter = function() print("Entered Test Zone") end, --- onEnter = function() print("Entered Test Zone") end,
--- onExit = function() print("Exited Test Zone") end, --- onExit = function() print("Exited Test Zone") end,
--- }) --- })
--- ``` --- ```
function createPoly(data) function createPoly(data)
local Location = nil local Location = nil
if isStarted(OXLibExport) then -- if it finds ox_lib, use it instead of PolyZone if isStarted(OXLibExport) then -- if it finds ox_lib, use it instead of PolyZone
debugPrint("^6Bridge^7: ^2Creating new poly with ^7'^4"..OXLibExport.."^7': "..data.name) debugPrint("^6Bridge^7: ^2Creating new poly with ^7'^4"..OXLibExport.."^7': "..data.name)
for i = 1, #data.points do for i = 1, #data.points do
data.points[i] = vec3(data.points[i].x, data.points[i].y, 12.0) data.points[i] = vec3(data.points[i].x, data.points[i].y, 12.0)
end end
data.thickness = 1000 data.thickness = 1000
Location = lib.zones.poly(data) Location = lib.zones.poly(data)
elseif isStarted("PolyZone") then elseif isStarted("PolyZone") then
debugPrint("^6Bridge^7: ^2Creating new poly with ^7'^4PolyZone^7': "..data.name) debugPrint("^6Bridge^7: ^2Creating new poly with ^7'^4PolyZone^7': "..data.name)
Location = PolyZone:Create(data.points, { name = data.name, debugPoly = data.debug }) Location = PolyZone:Create(data.points, { name = data.name, debugPoly = data.debug })
Location:onPlayerInOut(function(isPointInside) Location:onPlayerInOut(function(isPointInside)
if isPointInside then data.onEnter() else data.onExit() end if isPointInside then data.onEnter() else data.onExit() end
end) end)
else else
print("^4ERROR^7: ^2No PolyZone creation script detected ^7- ^2Check ^3exports^1.^2lua^7") print("^4ERROR^7: ^2No PolyZone creation script detected ^7- ^2Check ^3exports^1.^2lua^7")
end end
return Location return Location
end end
--- Creates a circular zone using the detected polyzone library (ox_lib or PolyZone). --- Creates a circular zone using the detected polyzone library (ox_lib or PolyZone).
--- ---
--- This function automatically detects whether `ox_lib` or `PolyZone` is active and creates a circular zone accordingly. --- This function automatically detects whether `ox_lib` or `PolyZone` is active and creates a circular zone accordingly.
--- It supports setting up entry and exit callbacks for the zone. --- It supports setting up entry and exit callbacks for the zone.
--- ---
---@param data table A table containing the circular zone configuration. ---@param data table A table containing the circular zone configuration.
--- - **name** (`string`): The name of the circular zone. --- - **name** (`string`): The name of the circular zone.
--- - **coords** (`vector3`): The center coordinates of the circle. --- - **coords** (`vector3`): The center coordinates of the circle.
--- - **radius** (`number`): The radius of the circle. --- - **radius** (`number`): The radius of the circle.
--- - **onEnter** (`function`): Callback function to execute when a player enters the zone. --- - **onEnter** (`function`): Callback function to execute when a player enters the zone.
--- - **onExit** (`function`): Callback function to execute when a player exits the zone. --- - **onExit** (`function`): Callback function to execute when a player exits the zone.
--- ---
---@return table|nil table Returns the created circular zone object or `nil` if creation failed. ---@return table|nil table Returns the created circular zone object or `nil` if creation failed.
--- ---
---@usage ---@usage
--- ```lua --- ```lua
--- createCirclePoly({ --- createCirclePoly({
--- name = 'circleZone', --- name = 'circleZone',
--- coords = vector3(150.0, 150.0, 20.0), --- coords = vector3(150.0, 150.0, 20.0),
--- radius = 50.0, --- radius = 50.0,
--- onEnter = function() print("Entered Circle Zone") end, --- onEnter = function() print("Entered Circle Zone") end,
--- onExit = function() print("Exited Circle Zone") end, --- onExit = function() print("Exited Circle Zone") end,
--- }) --- })
--- ``` --- ```
function createCirclePoly(data) function createCirclePoly(data)
local Location = nil local Location = nil
if isStarted(OXLibExport) then -- if it finds ox_lib, use it instead of PolyZone if isStarted(OXLibExport) then -- if it finds ox_lib, use it instead of PolyZone
debugPrint("^6Bridge^7: ^2Creating new ^3Cricle^2 poly with ^7"..OXLibExport.." "..data.name) debugPrint("^6Bridge^7: ^2Creating new ^3Cricle^2 poly with ^7"..OXLibExport.." "..data.name)
Location = lib.zones.sphere(data) Location = lib.zones.sphere(data)
elseif isStarted("PolyZone") then elseif isStarted("PolyZone") then
debugPrint("^6Bridge^7: ^2Creating new ^3Cricle^2 poly with ^7PolyZone ".. data.name) debugPrint("^6Bridge^7: ^2Creating new ^3Cricle^2 poly with ^7PolyZone ".. data.name)
Location = CircleZone:Create(data.coords, data.radius, { name = data.name, debugPoly = debugMode }) Location = CircleZone:Create(data.coords, data.radius, { name = data.name, debugPoly = debugMode })
Location:onPlayerInOut(function(isPointInside) Location:onPlayerInOut(function(isPointInside)
if isPointInside then if isPointInside then
data.onEnter() data.onEnter()
else else
data.onExit() data.onExit()
end end
end) end)
else else
print("^4ERROR^7: ^2No PolyZone creation script detected ^7- ^2Check ^3exports^1.^2lua^7") print("^4ERROR^7: ^2No PolyZone creation script detected ^7- ^2Check ^3exports^1.^2lua^7")
end end
debugPrint("^6Bridge^7: ^2Zone Stats - Coords: "..formatCoord(data.coords).." Radius: "..data.radius) debugPrint("^6Bridge^7: ^2Zone Stats - Coords: "..formatCoord(data.coords).." Radius: "..data.radius)
return Location return Location
end end
--- Removes a previously created polyzone. --- Removes a previously created polyzone.
--- ---
--- This function detects the active polyzone library (`ox_lib` or `PolyZone`) and removes the specified zone accordingly. --- This function detects the active polyzone library (`ox_lib` or `PolyZone`) and removes the specified zone accordingly.
--- ---
--- @param Location table The zone object to be removed. --- @param Location table The zone object to be removed.
--- ---
--- @usage --- @usage
--- ```lua --- ```lua
--- local zone = createPoly({...}) --- local zone = createPoly({...})
--- -- Later in the code --- -- Later in the code
--- removePolyZone(zone) --- removePolyZone(zone)
--- ``` --- ```
function removePolyZone(Location) function removePolyZone(Location)
if isStarted(OXLibExport) then -- if it finds ox_lib, use it instead of PolyZone if isStarted(OXLibExport) then -- if it finds ox_lib, use it instead of PolyZone
debugPrint("^6Bridge^7: ^2Removing ^2poly with ^7"..OXLibExport) debugPrint("^6Bridge^7: ^2Removing ^2poly with ^7"..OXLibExport)
Location:remove() Location:remove()
elseif isStarted("PolyZone") then elseif isStarted("PolyZone") then
debugPrint("^6Bridge^7: ^2poly with ^7PolyZone") debugPrint("^6Bridge^7: ^2poly with ^7PolyZone")
Location:destroy() Location:destroy()
end end
end end

View File

@@ -1,77 +1,77 @@
local cacheOrigScale = {} local cacheOrigScale = {}
local initialOffset = {} local initialOffset = {}
--- Sets the scale of an entity. --- Sets the scale of an entity.
--- ---
--- This function scales an entity by adjusting its forward, right, and up vectors. --- This function scales an entity by adjusting its forward, right, and up vectors.
--- It also applies an initial offset to maintain the entity's position relative to the ground. --- It also applies an initial offset to maintain the entity's position relative to the ground.
--- ---
---@param entity number The entity ID to scale. ---@param entity number The entity ID to scale.
---@param scale number The scale factor to apply to the entity. ---@param scale number The scale factor to apply to the entity.
--- ---
---@usage ---@usage
--- ```lua --- ```lua
--- -- Scale an entity to twice its original size --- -- Scale an entity to twice its original size
--- SetEntityScale(entityId, 2.0) --- SetEntityScale(entityId, 2.0)
--- ``` --- ```
function SetEntityScale(entity, scale) function SetEntityScale(entity, scale)
local forward, right, up = GetEntityMatrix(entity) local forward, right, up = GetEntityMatrix(entity)
if not cacheOrigScale[entity] then if not cacheOrigScale[entity] then
cacheOrigScale[entity] = { cacheOrigScale[entity] = {
forward = forward, forward = forward,
right = right, right = right,
up = up up = up
} }
end end
local minDim, maxDim = GetModelDimensions(GetEntityModel(entity)) local minDim, maxDim = GetModelDimensions(GetEntityModel(entity))
local originalHeight = maxDim.z - minDim.z local originalHeight = maxDim.z - minDim.z
local newHeight = originalHeight * scale local newHeight = originalHeight * scale
initialOffset[entity] = (newHeight - originalHeight) / 3 initialOffset[entity] = (newHeight - originalHeight) / 3
local forwardTemp = cacheOrigScale[entity].forward * scale local forwardTemp = cacheOrigScale[entity].forward * scale
local rightTemp = cacheOrigScale[entity].right * scale local rightTemp = cacheOrigScale[entity].right * scale
local upTemp = cacheOrigScale[entity].up * scale local upTemp = cacheOrigScale[entity].up * scale
-- Apply the initial offset to the current position -- Apply the initial offset to the current position
local currentPosition = GetEntityCoords(entity) local currentPosition = GetEntityCoords(entity)
local newPosition = vector3(currentPosition.x, currentPosition.y, currentPosition.z + initialOffset[entity]) local newPosition = vector3(currentPosition.x, currentPosition.y, currentPosition.z + initialOffset[entity])
SetEntityMatrix(entity, forwardTemp, rightTemp, upTemp, currentPosition) SetEntityMatrix(entity, forwardTemp, rightTemp, upTemp, currentPosition)
end end
--- Resets the scale of an entity to its original values. --- Resets the scale of an entity to its original values.
--- ---
--- This function restores an entity's original forward, right, and up vectors, --- This function restores an entity's original forward, right, and up vectors,
--- effectively undoing any scaling applied by `SetEntityScale`. --- effectively undoing any scaling applied by `SetEntityScale`.
--- ---
---@param entity number The entity ID to reset. ---@param entity number The entity ID to reset.
--- ---
---@usage ---@usage
--- ```lua --- ```lua
--- -- Reset the scale of an entity --- -- Reset the scale of an entity
--- resetScale(entityId) --- resetScale(entityId)
--- ``` --- ```
function resetScale(entity) function resetScale(entity)
if cacheOrigScale[entity] then if cacheOrigScale[entity] then
SetEntityMatrix(entity, cacheOrigScale[entity].forward, cacheOrigScale[entity].right, cacheOrigScale[entity].up, GetEntityCoords(entity)) SetEntityMatrix(entity, cacheOrigScale[entity].forward, cacheOrigScale[entity].right, cacheOrigScale[entity].up, GetEntityCoords(entity))
cacheOrigScale[entity] = nil cacheOrigScale[entity] = nil
end end
end end
--[[ --[[
CreateThread(function() CreateThread(function()
-- Example usage: -- Example usage:
-- local prop = makeProp({prop = "v_res_r_figcat", coords = vec4(-1025.88, -1417.58, 5.43, 76.30)}, false, false) -- local prop = makeProp({prop = "v_res_r_figcat", coords = vec4(-1025.88, -1417.58, 5.43, 76.30)}, false, false)
-- local ped = makePed(`a_c_cat_01`, vec4(-1022.42, -1429.97, 13.79, 68.36), true, false, nil) -- local ped = makePed(`a_c_cat_01`, vec4(-1022.42, -1429.97, 13.79, 68.36), true, false, nil)
-- SetEntityCollision(prop, false, true) -- SetEntityCollision(prop, false, true)
SetEntityScale(prop, 12) SetEntityScale(prop, 12)
--[[CreateThread(function() --[[CreateThread(function()
while true do while true do
Wait(1000) Wait(1000)
resetScale(prop) resetScale(prop)
Wait(1000) Wait(1000)
end end
end) end)
end) end)
]] ]]

View File

@@ -1,61 +1,61 @@
function makeInstructionalButtons(info) function makeInstructionalButtons(info)
local build = RequestScaleformMovie("instructional_buttons") local build = RequestScaleformMovie("instructional_buttons")
while not HasScaleformMovieLoaded(build) do Wait(0) end while not HasScaleformMovieLoaded(build) do Wait(0) end
DrawScaleformMovieFullscreen(build, 255, 255, 255, 0, 0) DrawScaleformMovieFullscreen(build, 255, 255, 255, 0, 0)
BeginScaleformMovieMethod(build, "CLEAR_ALL") BeginScaleformMovieMethod(build, "CLEAR_ALL")
EndScaleformMovieMethod() EndScaleformMovieMethod()
BeginScaleformMovieMethod(build, "SET_CLEAR_SPACE") BeginScaleformMovieMethod(build, "SET_CLEAR_SPACE")
ScaleformMovieMethodAddParamInt(200) ScaleformMovieMethodAddParamInt(200)
EndScaleformMovieMethod() EndScaleformMovieMethod()
for i = 1, #info do for i = 1, #info do
BeginScaleformMovieMethod(build, "SET_DATA_SLOT") BeginScaleformMovieMethod(build, "SET_DATA_SLOT")
ScaleformMovieMethodAddParamInt(i - 1) ScaleformMovieMethodAddParamInt(i - 1)
for k = 1, #info[i].keys do for k = 1, #info[i].keys do
ScaleformMovieMethodAddParamPlayerNameString(GetControlInstructionalButton(2, info[i].keys[k], true)) ScaleformMovieMethodAddParamPlayerNameString(GetControlInstructionalButton(2, info[i].keys[k], true))
end end
BeginTextCommandScaleformString("STRING") BeginTextCommandScaleformString("STRING")
AddTextComponentSubstringKeyboardDisplay(info[i].text) AddTextComponentSubstringKeyboardDisplay(info[i].text)
EndTextCommandScaleformString() EndTextCommandScaleformString()
EndScaleformMovieMethod() EndScaleformMovieMethod()
end end
BeginScaleformMovieMethod(build, "DRAW_INSTRUCTIONAL_BUTTONS") BeginScaleformMovieMethod(build, "DRAW_INSTRUCTIONAL_BUTTONS")
EndScaleformMovieMethod() EndScaleformMovieMethod()
BeginScaleformMovieMethod(build, "SET_BACKGROUND_COLOUR") BeginScaleformMovieMethod(build, "SET_BACKGROUND_COLOUR")
ScaleformMovieMethodAddParamInt(0) ScaleformMovieMethodAddParamInt(0)
ScaleformMovieMethodAddParamInt(0) ScaleformMovieMethodAddParamInt(0)
ScaleformMovieMethodAddParamInt(0) ScaleformMovieMethodAddParamInt(0)
ScaleformMovieMethodAddParamInt(80) ScaleformMovieMethodAddParamInt(80)
EndScaleformMovieMethod() EndScaleformMovieMethod()
DrawScaleformMovieFullscreen(build, 255, 255, 255, 255, 0) DrawScaleformMovieFullscreen(build, 255, 255, 255, 255, 0)
end end
-- Testing showing variables on the screen instead of only in f8 -- Testing showing variables on the screen instead of only in f8
function debugScaleForm(textTable, loc) function debugScaleForm(textTable, loc)
if debugMode then if debugMode then
-- Define the display position (top left corner) -- Define the display position (top left corner)
local loc = loc or vec2(0.05, 0.65) local loc = loc or vec2(0.05, 0.65)
-- Calculate dynamic height based on the number of lines in the textTable -- Calculate dynamic height based on the number of lines in the textTable
local lineHeight = 0.025 -- Height of each line of text local lineHeight = 0.025 -- Height of each line of text
local totalHeight = #textTable * lineHeight -- Dynamic height based on number of lines local totalHeight = #textTable * lineHeight -- Dynamic height based on number of lines
local boxPadding = 0.01 -- Padding to add around the text inside the box local boxPadding = 0.01 -- Padding to add around the text inside the box
local size = vec2(0.18, totalHeight + boxPadding * 2) -- Width remains fixed, height is dynamic local size = vec2(0.18, totalHeight + boxPadding * 2) -- Width remains fixed, height is dynamic
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, 255)
for i = 1, #textTable do for i = 1, #textTable do
local textLine = textTable[i] local textLine = textTable[i]
SetTextScale(0.30, 0.30) SetTextScale(0.30, 0.30)
BeginTextCommandDisplayText("STRING") BeginTextCommandDisplayText("STRING")
AddTextComponentSubstringKeyboardDisplay(textLine) AddTextComponentSubstringKeyboardDisplay(textLine)
EndTextCommandDisplayText(loc.x + 0.005, loc.y + (i - 1) * lineHeight + 0.01) EndTextCommandDisplayText(loc.x + 0.005, loc.y + (i - 1) * lineHeight + 0.01)
end end
end end
end end

View File

@@ -1,277 +1,277 @@
BigMessage = {} BigMessage = {}
BigMessage.__index = BigMessage BigMessage.__index = BigMessage
function BigMessage:new() function BigMessage:new()
local self = setmetatable({}, BigMessage) local self = setmetatable({}, BigMessage)
self.scaleform = nil self.scaleform = nil
self.startTime = 0 self.startTime = 0
self.duration = 0 self.duration = 0
self.transition = "TRANSITION_OUT" self.transition = "TRANSITION_OUT"
self.transitionDuration = 0.15 self.transitionDuration = 0.15
self.transitionPreventAutoExpansion = false self.transitionPreventAutoExpansion = false
self.transitionExecuted = false self.transitionExecuted = false
self.manualDispose = false self.manualDispose = false
self.isDisplaying = false self.isDisplaying = false
return self return self
end end
function BigMessage:Load() function BigMessage:Load()
if self.scaleform then return end if self.scaleform then return end
self.scaleform = RequestScaleformMovie("MP_BIG_MESSAGE_FREEMODE") self.scaleform = RequestScaleformMovie("MP_BIG_MESSAGE_FREEMODE")
while not HasScaleformMovieLoaded(self.scaleform) do while not HasScaleformMovieLoaded(self.scaleform) do
Wait(0) Wait(0)
end end
end end
-- Dispose of the scaleform -- Dispose of the scaleform
function BigMessage:Dispose() function BigMessage:Dispose()
if not self.scaleform then return end if not self.scaleform then return end
if self.manualDispose then if self.manualDispose then
BeginScaleformMovieMethod(self.scaleform, self.transition) BeginScaleformMovieMethod(self.scaleform, self.transition)
ScaleformMovieMethodAddParamBool(false) ScaleformMovieMethodAddParamBool(false)
ScaleformMovieMethodAddParamFloat(self.transitionDuration) ScaleformMovieMethodAddParamFloat(self.transitionDuration)
ScaleformMovieMethodAddParamBool(self.transitionPreventAutoExpansion) ScaleformMovieMethodAddParamBool(self.transitionPreventAutoExpansion)
EndScaleformMovieMethod() EndScaleformMovieMethod()
Wait((self.transitionDuration * 0.5) * 1000) Wait((self.transitionDuration * 0.5) * 1000)
self.manualDispose = false self.manualDispose = false
end end
self.startTime = 0 self.startTime = 0
self.transitionExecuted = false self.transitionExecuted = false
SetScaleformMovieAsNoLongerNeeded(self.scaleform) SetScaleformMovieAsNoLongerNeeded(self.scaleform)
self.scaleform = nil self.scaleform = nil
self.isDisplaying = false self.isDisplaying = false
end end
function BigMessage:Update() function BigMessage:Update()
if not self.scaleform then return end if not self.scaleform then return end
DrawScaleformMovieFullscreen(self.scaleform, 255, 255, 255, 255, 0) DrawScaleformMovieFullscreen(self.scaleform, 255, 255, 255, 255, 0)
if self.manualDispose then return end if self.manualDispose then return end
if self.startTime ~= 0 and (GetGameTimer() - self.startTime) > self.duration then if self.startTime ~= 0 and (GetGameTimer() - self.startTime) > self.duration then
if not self.transitionExecuted then if not self.transitionExecuted then
BeginScaleformMovieMethod(self.scaleform, self.transition) BeginScaleformMovieMethod(self.scaleform, self.transition)
ScaleformMovieMethodAddParamBool(false) ScaleformMovieMethodAddParamBool(false)
ScaleformMovieMethodAddParamFloat(self.transitionDuration) ScaleformMovieMethodAddParamFloat(self.transitionDuration)
ScaleformMovieMethodAddParamBool(self.transitionPreventAutoExpansion) ScaleformMovieMethodAddParamBool(self.transitionPreventAutoExpansion)
EndScaleformMovieMethod() EndScaleformMovieMethod()
self.transitionExecuted = true self.transitionExecuted = true
self.duration = self.duration + ((self.transitionDuration * 0.5) * 1000) self.duration = self.duration + ((self.transitionDuration * 0.5) * 1000)
else else
self:Dispose() self:Dispose()
end end
end end
end end
function BigMessage:SetTransition(transition, duration, preventAutoExpansion) function BigMessage:SetTransition(transition, duration, preventAutoExpansion)
self.transition = transition or "TRANSITION_OUT" self.transition = transition or "TRANSITION_OUT"
self.transitionDuration = duration or 0.4 self.transitionDuration = duration or 0.4
self.transitionPreventAutoExpansion = preventAutoExpansion or true self.transitionPreventAutoExpansion = preventAutoExpansion or true
end end
function BigMessage:StartUpdate() function BigMessage:StartUpdate()
if self.isDisplaying then return end if self.isDisplaying then return end
self.isDisplaying = true self.isDisplaying = true
CreateThread(function() CreateThread(function()
while self.isDisplaying do while self.isDisplaying do
Wait(0) Wait(0)
self:Update() self:Update()
end end
end) end)
end end
--- Displays a mission passed message. --- Displays a mission passed message.
--- ---
--- @param msg string The main message to display. --- @param msg string The main message to display.
--- @param duration number|nil The duration in milliseconds the message should be displayed. Defaults to 5000. --- @param duration number|nil The duration in milliseconds the message should be displayed. Defaults to 5000.
--- @param manualDispose boolean|nil Whether to manually dispose of the scaleform after the message. Defaults to false. --- @param manualDispose boolean|nil Whether to manually dispose of the scaleform after the message. Defaults to false.
function BigMessage:ShowMissionPassedMessage(msg, duration, manualDispose) function BigMessage:ShowMissionPassedMessage(msg, duration, manualDispose)
duration = duration or 5000 duration = duration or 5000
self:Load() self:Load()
self.startTime = GetGameTimer() self.startTime = GetGameTimer()
self.manualDispose = manualDispose or false self.manualDispose = manualDispose or false
BeginScaleformMovieMethod(self.scaleform, "SHOW_MISSION_PASSED_MESSAGE") BeginScaleformMovieMethod(self.scaleform, "SHOW_MISSION_PASSED_MESSAGE")
ScaleformMovieMethodAddParamPlayerNameString(msg) ScaleformMovieMethodAddParamPlayerNameString(msg)
ScaleformMovieMethodAddParamPlayerNameString("") ScaleformMovieMethodAddParamPlayerNameString("")
ScaleformMovieMethodAddParamInt(100) ScaleformMovieMethodAddParamInt(100)
ScaleformMovieMethodAddParamBool(true) ScaleformMovieMethodAddParamBool(true)
ScaleformMovieMethodAddParamInt(0) ScaleformMovieMethodAddParamInt(0)
ScaleformMovieMethodAddParamBool(true) ScaleformMovieMethodAddParamBool(true)
EndScaleformMovieMethod() EndScaleformMovieMethod()
self.duration = duration self.duration = duration
self:StartUpdate() self:StartUpdate()
end end
--- Displays a colored shard message. --- Displays a colored shard message.
--- ---
--- @param msg string The main message to display. --- @param msg string The main message to display.
--- @param desc string The description text. --- @param desc string The description text.
--- @param textColor number The color index for the text. --- @param textColor number The color index for the text.
--- @param bgColor number The color index for the background. --- @param bgColor number The color index for the background.
--- @param duration number|nil The duration in milliseconds the message should be displayed. Defaults to 5000. --- @param duration number|nil The duration in milliseconds the message should be displayed. Defaults to 5000.
--- @param manualDispose boolean|nil Whether to manually dispose of the scaleform after the message. Defaults to false. --- @param manualDispose boolean|nil Whether to manually dispose of the scaleform after the message. Defaults to false.
function BigMessage:ShowColoredShard(msg, desc, textColor, bgColor, duration, manualDispose) function BigMessage:ShowColoredShard(msg, desc, textColor, bgColor, duration, manualDispose)
duration = duration or 5000 duration = duration or 5000
self:Load() self:Load()
self.startTime = GetGameTimer() self.startTime = GetGameTimer()
self.manualDispose = manualDispose or false self.manualDispose = manualDispose or false
BeginScaleformMovieMethod(self.scaleform, "SHOW_SHARD_CENTERED_MP_MESSAGE") BeginScaleformMovieMethod(self.scaleform, "SHOW_SHARD_CENTERED_MP_MESSAGE")
ScaleformMovieMethodAddParamPlayerNameString(msg) ScaleformMovieMethodAddParamPlayerNameString(msg)
ScaleformMovieMethodAddParamPlayerNameString(desc) ScaleformMovieMethodAddParamPlayerNameString(desc)
ScaleformMovieMethodAddParamInt(bgColor) ScaleformMovieMethodAddParamInt(bgColor)
ScaleformMovieMethodAddParamInt(textColor) ScaleformMovieMethodAddParamInt(textColor)
EndScaleformMovieMethod() EndScaleformMovieMethod()
self.duration = duration self.duration = duration
self:StartUpdate() self:StartUpdate()
end end
--- Displays an old-style mission passed message. --- Displays an old-style mission passed message.
--- ---
--- @param msg string The main message to display. --- @param msg string The main message to display.
--- @param duration number|nil The duration in milliseconds the message should be displayed. Defaults to 5000. --- @param duration number|nil The duration in milliseconds the message should be displayed. Defaults to 5000.
--- @param manualDispose boolean|nil Whether to manually dispose of the scaleform after the message. Defaults to false. --- @param manualDispose boolean|nil Whether to manually dispose of the scaleform after the message. Defaults to false.
--- ---
--- @return void --- @return void
function BigMessage:ShowOldMessage(msg, duration, manualDispose) function BigMessage:ShowOldMessage(msg, duration, manualDispose)
duration = duration or 5000 duration = duration or 5000
self:Load() self:Load()
self.startTime = GetGameTimer() self.startTime = GetGameTimer()
self.manualDispose = manualDispose or false self.manualDispose = manualDispose or false
BeginScaleformMovieMethod(self.scaleform, "SHOW_MISSION_PASSED_MESSAGE") BeginScaleformMovieMethod(self.scaleform, "SHOW_MISSION_PASSED_MESSAGE")
ScaleformMovieMethodAddParamPlayerNameString(msg) ScaleformMovieMethodAddParamPlayerNameString(msg)
EndScaleformMovieMethod() EndScaleformMovieMethod()
self.duration = duration self.duration = duration
self:StartUpdate() self:StartUpdate()
end end
--- Displays a simple shard message. --- Displays a simple shard message.
--- ---
--- @param msg string The main message to display. --- @param msg string The main message to display.
--- @param subtitle string The subtitle text. --- @param subtitle string The subtitle text.
--- @param duration number|nil The duration in milliseconds the message should be displayed. Defaults to 5000. --- @param duration number|nil The duration in milliseconds the message should be displayed. Defaults to 5000.
--- @param manualDispose boolean|nil Whether to manually dispose of the scaleform after the message. Defaults to false. --- @param manualDispose boolean|nil Whether to manually dispose of the scaleform after the message. Defaults to false.
--- ---
--- @return void --- @return void
function BigMessage:ShowSimpleShard(msg, subtitle, duration, manualDispose) function BigMessage:ShowSimpleShard(msg, subtitle, duration, manualDispose)
duration = duration or 5000 duration = duration or 5000
self:Load() self:Load()
self.startTime = GetGameTimer() self.startTime = GetGameTimer()
self.manualDispose = manualDispose or false self.manualDispose = manualDispose or false
BeginScaleformMovieMethod(self.scaleform, "SHOW_SHARD_CREW_RANKUP_MP_MESSAGE") BeginScaleformMovieMethod(self.scaleform, "SHOW_SHARD_CREW_RANKUP_MP_MESSAGE")
ScaleformMovieMethodAddParamPlayerNameString(msg) ScaleformMovieMethodAddParamPlayerNameString(msg)
ScaleformMovieMethodAddParamPlayerNameString(subtitle) ScaleformMovieMethodAddParamPlayerNameString(subtitle)
EndScaleformMovieMethod() EndScaleformMovieMethod()
self.duration = duration self.duration = duration
self:StartUpdate() self:StartUpdate()
end end
--- Displays a rank-up message. --- Displays a rank-up message.
--- ---
--- @param msg string The main message to display. --- @param msg string The main message to display.
--- @param subtitle string The subtitle text. --- @param subtitle string The subtitle text.
--- @param rank number The rank level achieved. --- @param rank number The rank level achieved.
--- @param duration number|nil The duration in milliseconds the message should be displayed. Defaults to 5000. --- @param duration number|nil The duration in milliseconds the message should be displayed. Defaults to 5000.
--- @param manualDispose boolean|nil Whether to manually dispose of the scaleform after the message. Defaults to false. --- @param manualDispose boolean|nil Whether to manually dispose of the scaleform after the message. Defaults to false.
function BigMessage:ShowRankupMessage(msg, subtitle, rank, duration, manualDispose) function BigMessage:ShowRankupMessage(msg, subtitle, rank, duration, manualDispose)
duration = duration or 5000 duration = duration or 5000
self:Load() self:Load()
self.startTime = GetGameTimer() self.startTime = GetGameTimer()
self.manualDispose = manualDispose or false self.manualDispose = manualDispose or false
BeginScaleformMovieMethod(self.scaleform, "SHOW_BIG_MP_MESSAGE") BeginScaleformMovieMethod(self.scaleform, "SHOW_BIG_MP_MESSAGE")
ScaleformMovieMethodAddParamPlayerNameString(msg) ScaleformMovieMethodAddParamPlayerNameString(msg)
ScaleformMovieMethodAddParamPlayerNameString(subtitle) ScaleformMovieMethodAddParamPlayerNameString(subtitle)
ScaleformMovieMethodAddParamInt(rank) ScaleformMovieMethodAddParamInt(rank)
ScaleformMovieMethodAddParamPlayerNameString("") ScaleformMovieMethodAddParamPlayerNameString("")
ScaleformMovieMethodAddParamPlayerNameString("") ScaleformMovieMethodAddParamPlayerNameString("")
EndScaleformMovieMethod() EndScaleformMovieMethod()
self.duration = duration self.duration = duration
self:StartUpdate() self:StartUpdate()
end end
--- Displays a weapon purchased message. --- Displays a weapon purchased message.
--- ---
--- @param bigMessage string The main message to display. --- @param bigMessage string The main message to display.
--- @param weaponName string The name of the weapon purchased. --- @param weaponName string The name of the weapon purchased.
--- @param weaponHash number The hash identifier of the weapon. --- @param weaponHash number The hash identifier of the weapon.
--- @param duration number|nil The duration in milliseconds the message should be displayed. Defaults to 5000. --- @param duration number|nil The duration in milliseconds the message should be displayed. Defaults to 5000.
--- @param manualDispose boolean|nil Whether to manually dispose of the scaleform after the message. Defaults to false. --- @param manualDispose boolean|nil Whether to manually dispose of the scaleform after the message. Defaults to false.
function BigMessage:ShowWeaponPurchasedMessage(bigMessage, weaponName, weaponHash, duration, manualDispose) function BigMessage:ShowWeaponPurchasedMessage(bigMessage, weaponName, weaponHash, duration, manualDispose)
duration = duration or 5000 duration = duration or 5000
self:Load() self:Load()
self.startTime = GetGameTimer() self.startTime = GetGameTimer()
self.manualDispose = manualDispose or false self.manualDispose = manualDispose or false
BeginScaleformMovieMethod(self.scaleform, "SHOW_WEAPON_PURCHASED") BeginScaleformMovieMethod(self.scaleform, "SHOW_WEAPON_PURCHASED")
ScaleformMovieMethodAddParamPlayerNameString(bigMessage) ScaleformMovieMethodAddParamPlayerNameString(bigMessage)
ScaleformMovieMethodAddParamPlayerNameString(weaponName) ScaleformMovieMethodAddParamPlayerNameString(weaponName)
ScaleformMovieMethodAddParamInt(weaponHash) ScaleformMovieMethodAddParamInt(weaponHash)
ScaleformMovieMethodAddParamPlayerNameString("") ScaleformMovieMethodAddParamPlayerNameString("")
ScaleformMovieMethodAddParamInt(100) ScaleformMovieMethodAddParamInt(100)
EndScaleformMovieMethod() EndScaleformMovieMethod()
self.duration = duration self.duration = duration
self:StartUpdate() self:StartUpdate()
end end
--- Displays a large multiplayer message. --- Displays a large multiplayer message.
--- ---
--- @param msg string The main message to display. --- @param msg string The main message to display.
--- @param duration number|nil The duration in milliseconds the message should be displayed. Defaults to 5000. --- @param duration number|nil The duration in milliseconds the message should be displayed. Defaults to 5000.
--- @param manualDispose boolean|nil Whether to manually dispose of the scaleform after the message. Defaults to false. --- @param manualDispose boolean|nil Whether to manually dispose of the scaleform after the message. Defaults to false.
function BigMessage:ShowMpMessageLarge(msg, duration, manualDispose) function BigMessage:ShowMpMessageLarge(msg, duration, manualDispose)
duration = duration or 5000 duration = duration or 5000
self:Load() self:Load()
self.startTime = GetGameTimer() self.startTime = GetGameTimer()
self.manualDispose = manualDispose or false self.manualDispose = manualDispose or false
BeginScaleformMovieMethod(self.scaleform, "SHOW_CENTERED_MP_MESSAGE_LARGE") BeginScaleformMovieMethod(self.scaleform, "SHOW_CENTERED_MP_MESSAGE_LARGE")
ScaleformMovieMethodAddParamPlayerNameString(msg) ScaleformMovieMethodAddParamPlayerNameString(msg)
ScaleformMovieMethodAddParamPlayerNameString("") ScaleformMovieMethodAddParamPlayerNameString("")
ScaleformMovieMethodAddParamInt(100) ScaleformMovieMethodAddParamInt(100)
ScaleformMovieMethodAddParamBool(true) ScaleformMovieMethodAddParamBool(true)
ScaleformMovieMethodAddParamInt(100) ScaleformMovieMethodAddParamInt(100)
EndScaleformMovieMethod() EndScaleformMovieMethod()
BeginScaleformMovieMethod(self.scaleform, "TRANSITION_IN") BeginScaleformMovieMethod(self.scaleform, "TRANSITION_IN")
EndScaleformMovieMethod() EndScaleformMovieMethod()
self.duration = duration self.duration = duration
self:StartUpdate() self:StartUpdate()
end end
--- Displays a "Wasted" multiplayer message. --- Displays a "Wasted" multiplayer message.
--- ---
--- @param msg string The main message to display. --- @param msg string The main message to display.
--- @param subtitle string The subtitle text. --- @param subtitle string The subtitle text.
--- @param duration number|nil The duration in milliseconds the message should be displayed. Defaults to 5000. --- @param duration number|nil The duration in milliseconds the message should be displayed. Defaults to 5000.
--- @param manualDispose boolean|nil Whether to manually dispose of the scaleform after the message. Defaults to false. --- @param manualDispose boolean|nil Whether to manually dispose of the scaleform after the message. Defaults to false.
function BigMessage:ShowMpWastedMessage(msg, subtitle, duration, manualDispose) function BigMessage:ShowMpWastedMessage(msg, subtitle, duration, manualDispose)
duration = duration or 5000 duration = duration or 5000
self:Load() self:Load()
self.startTime = GetGameTimer() self.startTime = GetGameTimer()
self.manualDispose = manualDispose or false self.manualDispose = manualDispose or false
BeginScaleformMovieMethod(self.scaleform, "SHOW_SHARD_WASTED_MP_MESSAGE") BeginScaleformMovieMethod(self.scaleform, "SHOW_SHARD_WASTED_MP_MESSAGE")
ScaleformMovieMethodAddParamPlayerNameString(msg) ScaleformMovieMethodAddParamPlayerNameString(msg)
ScaleformMovieMethodAddParamPlayerNameString(subtitle) ScaleformMovieMethodAddParamPlayerNameString(subtitle)
EndScaleformMovieMethod() EndScaleformMovieMethod()
self.duration = duration self.duration = duration
self:StartUpdate() self:StartUpdate()
end end
return BigMessage return BigMessage

View File

@@ -1,116 +1,116 @@
CountdownHandler = {} CountdownHandler = {}
CountdownHandler.__index = CountdownHandler CountdownHandler.__index = CountdownHandler
function CountdownHandler:new() function CountdownHandler:new()
local self = setmetatable({}, CountdownHandler) local self = setmetatable({}, CountdownHandler)
self.scaleform = nil self.scaleform = nil
self.renderCountdown = false self.renderCountdown = false
self.colour = { r = 255, g = 255, b = 255, a = 255 } self.colour = { r = 255, g = 255, b = 255, a = 255 }
return self return self
end end
function CountdownHandler:Load() function CountdownHandler:Load()
if self.scaleform then return end if self.scaleform then return end
self.scaleform = RequestScaleformMovie("COUNTDOWN") self.scaleform = RequestScaleformMovie("COUNTDOWN")
while not HasScaleformMovieLoaded(self.scaleform) do while not HasScaleformMovieLoaded(self.scaleform) do
Wait(0) Wait(0)
end end
end end
function CountdownHandler:Dispose() function CountdownHandler:Dispose()
if self.scaleform then if self.scaleform then
SetScaleformMovieAsNoLongerNeeded(self.scaleform) SetScaleformMovieAsNoLongerNeeded(self.scaleform)
self.scaleform = nil self.scaleform = nil
end end
end end
function CountdownHandler:Update() function CountdownHandler:Update()
if self.scaleform then if self.scaleform then
DrawScaleformMovieFullscreen(self.scaleform, 255, 255, 255, 255, 0) DrawScaleformMovieFullscreen(self.scaleform, 255, 255, 255, 255, 0)
end end
end end
function CountdownHandler:ShowMessage(message) function CountdownHandler:ShowMessage(message)
local r, g, b, a = self.colour.r, self.colour.g, self.colour.b, self.colour.a local r, g, b, a = self.colour.r, self.colour.g, self.colour.b, self.colour.a
BeginScaleformMovieMethod(self.scaleform, "SET_MESSAGE") BeginScaleformMovieMethod(self.scaleform, "SET_MESSAGE")
ScaleformMovieMethodAddParamPlayerNameString(message) ScaleformMovieMethodAddParamPlayerNameString(message)
ScaleformMovieMethodAddParamInt(r) ScaleformMovieMethodAddParamInt(r)
ScaleformMovieMethodAddParamInt(g) ScaleformMovieMethodAddParamInt(g)
ScaleformMovieMethodAddParamInt(b) ScaleformMovieMethodAddParamInt(b)
ScaleformMovieMethodAddParamBool(true) ScaleformMovieMethodAddParamBool(true)
EndScaleformMovieMethod() EndScaleformMovieMethod()
BeginScaleformMovieMethod(self.scaleform, "FADE_MP") BeginScaleformMovieMethod(self.scaleform, "FADE_MP")
ScaleformMovieMethodAddParamPlayerNameString(message) ScaleformMovieMethodAddParamPlayerNameString(message)
ScaleformMovieMethodAddParamInt(r) ScaleformMovieMethodAddParamInt(r)
ScaleformMovieMethodAddParamInt(g) ScaleformMovieMethodAddParamInt(g)
ScaleformMovieMethodAddParamInt(b) ScaleformMovieMethodAddParamInt(b)
EndScaleformMovieMethod() EndScaleformMovieMethod()
end end
--- Starts the countdown with the specified number and HUD color. --- Starts the countdown with the specified number and HUD color.
--- ---
--- @param number number|nil The starting number for the countdown. Defaults to 3. --- @param number number|nil The starting number for the countdown. Defaults to 3.
--- @param hudColour number|nil The HUD color index. Defaults to 18. --- @param hudColour number|nil The HUD color index. Defaults to 18.
--- ---
--- @return boolean `true` when the countdown has finished. --- @return boolean `true` when the countdown has finished.
--- ---
--- @usage --- @usage
--- ```lua --- ```lua
--- -- Start a countdown of 5 seconds with HUD color 25 --- -- Start a countdown of 5 seconds with HUD color 25
--- if CountdownHandler:Start(5, 25) then --- if CountdownHandler:Start(5, 25) then
--- print("Countdown Complete") --- print("Countdown Complete")
--- end --- end
--- ``` --- ```
function CountdownHandler:Start(number, hudColour) function CountdownHandler:Start(number, hudColour)
local finished = false local finished = false
number = number or 3 number = number or 3
hudColour = hudColour or 18 hudColour = hudColour or 18
local r, g, b, a = GetHudColour(hudColour) local r, g, b, a = GetHudColour(hudColour)
self.colour = { r = r, g = g, b = b, a = a } self.colour = { r = r, g = g, b = b, a = a }
self:Load() self:Load()
self.renderCountdown = true self.renderCountdown = true
CreateThread(function() CreateThread(function()
while self.renderCountdown do while self.renderCountdown do
Wait(0) Wait(0)
self:Update() self:Update()
end end
end) end)
-- Begin the countdown -- Begin the countdown
CreateThread(function() CreateThread(function()
local currentNumber = number local currentNumber = number
while currentNumber > 0 do while currentNumber > 0 do
-- Play countdown sound -- Play countdown sound
playSound("Count") playSound("Count")
self:ShowMessage(tostring(currentNumber)) self:ShowMessage(tostring(currentNumber))
Wait(1000) Wait(1000)
currentNumber = currentNumber - 1 currentNumber = currentNumber - 1
end end
playSound("Go") playSound("Go")
self:ShowMessage("GO") self:ShowMessage("GO")
finished = true finished = true
Wait(1000) Wait(1000)
self.renderCountdown = false self.renderCountdown = false
self:Dispose() self:Dispose()
finished = true finished = true
end) end)
while not finished do Wait(10) end while not finished do Wait(10) end
return true return true
end end
-- Create an instance of CountdownHandler -- Create an instance of CountdownHandler
CountdownHandler = CountdownHandler:new() CountdownHandler = CountdownHandler:new()
-- Optional: Register an event to start the countdown -- Optional: Register an event to start the countdown
RegisterNetEvent(getScript()..":startCountdown", function(number, hudColour) RegisterNetEvent(getScript()..":startCountdown", function(number, hudColour)
CountdownHandler:Start(number, hudColour) CountdownHandler:Start(number, hudColour)
end) end)
return CountdownHandler return CountdownHandler

View File

@@ -1,41 +1,41 @@
--- Displays debug information on the player's screen. --- Displays debug information on the player's screen.
--- ---
--- This function renders a semi-transparent box with multiple lines of text for debugging purposes. --- This function renders a semi-transparent box with multiple lines of text for debugging purposes.
--- It is controlled by the `debugMode` flag and can be positioned dynamically on the screen. --- It is controlled by the `debugMode` flag and can be positioned dynamically on the screen.
--- ---
--- @param textTable table A table containing strings to display. --- @param textTable table A table containing strings to display.
--- @param loc vector2|nil Optional. The screen position to display the debug box. Defaults to `vec2(0.05, 0.65)`. --- @param loc vector2|nil Optional. The screen position to display the debug box. Defaults to `vec2(0.05, 0.65)`.
--- ---
--- @usage --- @usage
--- ```lua --- ```lua
--- debugScaleForm({ --- debugScaleForm({
--- "Player Position: X=123.45 Y=678.90 Z=12.34", --- "Player Position: X=123.45 Y=678.90 Z=12.34",
--- "Current Action: Running", --- "Current Action: Running",
--- }) --- })
--- ``` --- ```
function debugScaleForm(textTable, loc) function debugScaleForm(textTable, loc)
if debugMode then if debugMode then
-- Define the display position (top left corner) -- Define the display position (top left corner)
local loc = loc or vec2(0.05, 0.65) local loc = loc or vec2(0.05, 0.65)
-- Calculate dynamic height based on the number of lines in the textTable -- Calculate dynamic height based on the number of lines in the textTable
local lineHeight = 0.025 -- Height of each line of text local lineHeight = 0.025 -- Height of each line of text
local totalHeight = #textTable * lineHeight -- Dynamic height based on number of lines local totalHeight = #textTable * lineHeight -- Dynamic height based on number of lines
local boxPadding = 0.01 -- Padding to add around the text inside the box local boxPadding = 0.01 -- Padding to add around the text inside the box
local size = vec2(0.18, totalHeight + boxPadding * 2) -- Width remains fixed, height is dynamic local size = vec2(0.18, totalHeight + boxPadding * 2) -- Width remains fixed, height is dynamic
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, 255)
for i = 1, #textTable do for i = 1, #textTable do
local textLine = textTable[i] local textLine = textTable[i]
SetTextScale(0.30, 0.30) SetTextScale(0.30, 0.30)
BeginTextCommandDisplayText("STRING") BeginTextCommandDisplayText("STRING")
AddTextComponentSubstringKeyboardDisplay(textLine) AddTextComponentSubstringKeyboardDisplay(textLine)
EndTextCommandDisplayText(loc.x + 0.005, loc.y + (i - 1) * lineHeight + 0.01) EndTextCommandDisplayText(loc.x + 0.005, loc.y + (i - 1) * lineHeight + 0.01)
end end
end end
end end

View File

@@ -1,50 +1,50 @@
--- Creates instructional buttons using the detected polyzone library (ox_lib or PolyZone). --- Creates instructional buttons using the detected polyzone library (ox_lib or PolyZone).
--- ---
--- This function generates instructional buttons on the player's screen based on the provided information. --- This function generates instructional buttons on the player's screen based on the provided information.
--- It supports different polyzone libraries by automatically detecting which one is active. --- It supports different polyzone libraries by automatically detecting which one is active.
--- ---
---@param info table A table containing the instructional buttons configuration. ---@param info table A table containing the instructional buttons configuration.
--- - **keys** (`table`): A list of control keys to display. --- - **keys** (`table`): A list of control keys to display.
--- - **text** (`string`): The description text for the buttons. --- - **text** (`string`): The description text for the buttons.
--- ---
---@usage ---@usage
--- ```lua --- ```lua
--- makeInstructionalButtons({ --- makeInstructionalButtons({
--- { keys = { 38 }, text = "Interact" }, --- { keys = { 38 }, text = "Interact" },
--- { keys = { 47 }, text = "Pick Up" }, --- { keys = { 47 }, text = "Pick Up" },
--- }) --- })
--- ``` --- ```
function makeInstructionalButtons(info) function makeInstructionalButtons(info)
local build = RequestScaleformMovie("instructional_buttons") local build = RequestScaleformMovie("instructional_buttons")
while not HasScaleformMovieLoaded(build) do Wait(0) end while not HasScaleformMovieLoaded(build) do Wait(0) end
DrawScaleformMovieFullscreen(build, 255, 255, 255, 0, 0) DrawScaleformMovieFullscreen(build, 255, 255, 255, 0, 0)
BeginScaleformMovieMethod(build, "CLEAR_ALL") BeginScaleformMovieMethod(build, "CLEAR_ALL")
EndScaleformMovieMethod() EndScaleformMovieMethod()
BeginScaleformMovieMethod(build, "SET_CLEAR_SPACE") BeginScaleformMovieMethod(build, "SET_CLEAR_SPACE")
ScaleformMovieMethodAddParamInt(200) ScaleformMovieMethodAddParamInt(200)
EndScaleformMovieMethod() EndScaleformMovieMethod()
for i = 1, #info do for i = 1, #info do
BeginScaleformMovieMethod(build, "SET_DATA_SLOT") BeginScaleformMovieMethod(build, "SET_DATA_SLOT")
ScaleformMovieMethodAddParamInt(i - 1) ScaleformMovieMethodAddParamInt(i - 1)
for k = 1, #info[i].keys do for k = 1, #info[i].keys do
ScaleformMovieMethodAddParamPlayerNameString(GetControlInstructionalButton(2, info[i].keys[k], true)) ScaleformMovieMethodAddParamPlayerNameString(GetControlInstructionalButton(2, info[i].keys[k], true))
end end
BeginTextCommandScaleformString("STRING") BeginTextCommandScaleformString("STRING")
AddTextComponentSubstringKeyboardDisplay(info[i].text) AddTextComponentSubstringKeyboardDisplay(info[i].text)
EndTextCommandScaleformString() EndTextCommandScaleformString()
EndScaleformMovieMethod() EndScaleformMovieMethod()
end end
BeginScaleformMovieMethod(build, "DRAW_INSTRUCTIONAL_BUTTONS") BeginScaleformMovieMethod(build, "DRAW_INSTRUCTIONAL_BUTTONS")
EndScaleformMovieMethod() EndScaleformMovieMethod()
BeginScaleformMovieMethod(build, "SET_BACKGROUND_COLOUR") BeginScaleformMovieMethod(build, "SET_BACKGROUND_COLOUR")
ScaleformMovieMethodAddParamInt(0) ScaleformMovieMethodAddParamInt(0)
ScaleformMovieMethodAddParamInt(0) ScaleformMovieMethodAddParamInt(0)
ScaleformMovieMethodAddParamInt(0) ScaleformMovieMethodAddParamInt(0)
ScaleformMovieMethodAddParamInt(80) ScaleformMovieMethodAddParamInt(80)
EndScaleformMovieMethod() EndScaleformMovieMethod()
DrawScaleformMovieFullscreen(build, 255, 255, 255, 255, 0) DrawScaleformMovieFullscreen(build, 255, 255, 255, 255, 0)
end end

View File

@@ -1,60 +1,60 @@
function createTimerHud(title, data, alpha) function createTimerHud(title, data, alpha)
loadTextureDict("timerbars") loadTextureDict("timerbars")
local loc = vec2(0.89, 0.90) local loc = vec2(0.89, 0.90)
alpha = alpha or 255 -- Default to fully opaque if alpha is not provided alpha = alpha or 255 -- Default to fully opaque if alpha is not provided
if title then if title then
local x = loc.x+0.037 local x = loc.x+0.037
local y = 0.1 local y = 0.1
DrawSprite("timerbars", "all_black_bg", x, y, 0.12, 0.05, 0.0, 255, 255, 255, alpha) DrawSprite("timerbars", "all_black_bg", x, y, 0.12, 0.05, 0.0, 255, 255, 255, alpha)
SetTextScale(0.80, 0.80) SetTextScale(0.80, 0.80)
SetTextWrap(0.75, 0.985) SetTextWrap(0.75, 0.985)
SetTextJustification(2) SetTextJustification(2)
SetTextFont(4) SetTextFont(4)
SetTextColour(255, 255, 255, alpha) SetTextColour(255, 255, 255, alpha)
BeginTextCommandDisplayText("STRING") BeginTextCommandDisplayText("STRING")
AddTextComponentSubstringKeyboardDisplay("~y~"..title) AddTextComponentSubstringKeyboardDisplay("~y~"..title)
EndTextCommandDisplayText(x+0.06, y - 0.026) EndTextCommandDisplayText(x+0.06, y - 0.026)
end end
local displayIndex = 0 local displayIndex = 0
for i = #data, 1, -1 do for i = #data, 1, -1 do
local space = 0.044 * displayIndex local space = 0.044 * displayIndex
DrawSprite("timerbars", "all_black_bg", loc.x+0.02, loc.y - space, 0.15, 0.04, 0.0, 255, 255, 255, alpha) DrawSprite("timerbars", "all_black_bg", loc.x+0.02, loc.y - space, 0.15, 0.04, 0.0, 255, 255, 255, alpha)
SetTextScale(0.0, 0.35) SetTextScale(0.0, 0.35)
SetTextWrap(0.5, 0.92) SetTextWrap(0.5, 0.92)
SetTextJustification(2) SetTextJustification(2)
SetTextColour(255, 255, 255, alpha) SetTextColour(255, 255, 255, alpha)
BeginTextCommandDisplayText("STRING") BeginTextCommandDisplayText("STRING")
AddTextComponentSubstringKeyboardDisplay(data[i].stat:upper()) AddTextComponentSubstringKeyboardDisplay(data[i].stat:upper())
EndTextCommandDisplayText(loc.x-0.05, (loc.y - space) - 0.0125) EndTextCommandDisplayText(loc.x-0.05, (loc.y - space) - 0.0125)
SetTextScale(0.55, 0.55) SetTextScale(0.55, 0.55)
SetTextWrap(0.85, 0.98 - (data[i].multi and 0.026 or 0.0)) SetTextWrap(0.85, 0.98 - (data[i].multi and 0.026 or 0.0))
SetTextFont(4) SetTextFont(4)
SetTextJustification(2) SetTextJustification(2)
SetTextColour(255, 255, 255, alpha) SetTextColour(255, 255, 255, alpha)
if data[i].multi then if data[i].multi then
local startX = 0.071 local startX = 0.071
DrawSprite("timerbars", "circle_checkpoints", DrawSprite("timerbars", "circle_checkpoints",
loc.x + startX, (loc.y - space)+0.005, loc.x + startX, (loc.y - space)+0.005,
0.011, 0.018, 0.0, 255, 191, 0, 200) 0.011, 0.018, 0.0, 255, 191, 0, 200)
DrawSprite("timerbars", "circle_checkpoints", DrawSprite("timerbars", "circle_checkpoints",
loc.x + (startX + 0.008), (loc.y - space)+0.005, loc.x + (startX + 0.008), (loc.y - space)+0.005,
0.011, 0.018, 0.0, 255, 191, 0, data[i].multi > 1 and 200 or 75) 0.011, 0.018, 0.0, 255, 191, 0, data[i].multi > 1 and 200 or 75)
DrawSprite("timerbars", "circle_checkpoints", DrawSprite("timerbars", "circle_checkpoints",
loc.x + (startX + 0.016), (loc.y - space)+0.005, loc.x + (startX + 0.016), (loc.y - space)+0.005,
0.011, 0.018, 0.0, 255, 191, 0, data[i].multi > 2 and 200 or 75) 0.011, 0.018, 0.0, 255, 191, 0, data[i].multi > 2 and 200 or 75)
end end
BeginTextCommandDisplayText("STRING") BeginTextCommandDisplayText("STRING")
AddTextComponentSubstringKeyboardDisplay(data[i].value) AddTextComponentSubstringKeyboardDisplay(data[i].value)
EndTextCommandDisplayText(loc.x - 0.02, (loc.y - space) - 0.017) EndTextCommandDisplayText(loc.x - 0.02, (loc.y - space) - 0.017)
displayIndex += 1 displayIndex += 1
end end
makeInstructionalButtons({ { text = "Exit", keys = { 194 }}}) makeInstructionalButtons({ { text = "Exit", keys = { 194 }}})
end end

View File

@@ -1,271 +1,271 @@
if isServer() then if isServer() then
createCallback(getScript()..':server:GetStashItems', function(source, stashName) local stash = getStash(stashName) return stash end) createCallback(getScript()..':server:GetStashItems', function(source, stashName) local stash = getStash(stashName) return stash end)
end end
local stashCache ={} local stashCache ={}
function GetStashTimeout(stashName, stop) function GetStashTimeout(stashName, stop)
if stop then stashCache = {} return end if stop then stashCache = {} return end
local stash = stashCache[stashName] local stash = stashCache[stashName]
if not stash then if not stash then
stashCache[stashName] = { items = {}, timeout = 0 } stashCache[stashName] = { items = {}, timeout = 0 }
stash = stashCache[stashName] stash = stashCache[stashName]
end end
if #stash.items > 0 then return true end if #stash.items > 0 then return true end
if stash.timeout <= 0 then if stash.timeout <= 0 then
stash.items = triggerCallback(getScript()..':server:GetStashItems', stashName) stash.items = triggerCallback(getScript()..':server:GetStashItems', stashName)
stash.timeout = 10000 stash.timeout = 10000
CreateThread(function() CreateThread(function()
while stash.timeout > 0 do stash.timeout -= 1000 Wait(1000) end while stash.timeout > 0 do stash.timeout -= 1000 Wait(1000) end
stashCache[stashName] = nil stashCache[stashName] = nil
end) end)
end end
return false return false
end end
function checkHasItem(stashes, itemTable) function checkHasItem(stashes, itemTable)
if not stashes then return hasItem(itemTable), nil end if not stashes then return hasItem(itemTable), nil end
if type(stashes) == "table" then if type(stashes) == "table" then
local succeses = 0 local succeses = 0
local itemCount = 0 local itemCount = 0
for _, item in pairs(itemTable) do itemCount += 1 end for _, item in pairs(itemTable) do itemCount += 1 end
for _, name in pairs(stashes) do for _, name in pairs(stashes) do
GetStashTimeout(name) GetStashTimeout(name)
for item, amount in pairs(itemTable) do for item, amount in pairs(itemTable) do
debugPrint("^6Bridge^7: ^2Checking"..(name and " ^7'^6"..name.."^7'" or "").." ^2ingredients^7 - ^6"..item.."^7") debugPrint("^6Bridge^7: ^2Checking"..(name and " ^7'^6"..name.."^7'" or "").." ^2ingredients^7 - ^6"..item.."^7")
if stashhasItem(stashCache[name].items, item, amount) then if stashhasItem(stashCache[name].items, item, amount) then
succeses += 1 succeses += 1
if succeses == itemCount then return true, name end if succeses == itemCount then return true, name end
end end
end end
end end
else else
debugPrint("^6Bridge^7: ^2Checking"..(stashes and " ^7'^6"..stashes.."^7'" or "").." ^2ingredients^7 - ^6"..k.."^7") debugPrint("^6Bridge^7: ^2Checking"..(stashes and " ^7'^6"..stashes.."^7'" or "").." ^2ingredients^7 - ^6"..k.."^7")
GetStashTimeout(stashes) GetStashTimeout(stashes)
return stashhasItem(stashCache[stashes].items, itemTable), stashes return stashhasItem(stashCache[stashes].items, itemTable), stashes
end end
return false, nil return false, nil
end end
-- Stash Items -- Stash Items
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
if isStarted(OXInv) then if isStarted(OXInv) then
exports[OXInv]:openInventory('stash', data.stash) exports[OXInv]:openInventory('stash', data.stash)
elseif isStarted(CodeMInv) then elseif isStarted(CodeMInv) then
exports[CodeMInv]:OpenStash(data.stash, StashWeight, 100) exports[CodeMInv]:OpenStash(data.stash, StashWeight, 100)
elseif isStarted(QBInv) then elseif isStarted(QBInv) then
if QBInvNew then if QBInvNew then
TriggerServerEvent(getScript()..':server:OpenStashQB', { stashName = data.stash, label = data.label, maxweight = data.maxWeight or 600000, slots = data.slots or 40 }) TriggerServerEvent(getScript()..':server:OpenStashQB', { stashName = data.stash, label = data.label, maxweight = data.maxWeight or 600000, slots = data.slots or 40 })
else else
TriggerEvent("inventory:client:SetCurrentStash", data.stash) TriggerEvent("inventory:client:SetCurrentStash", data.stash)
TriggerServerEvent("inventory:server:OpenInventory", "stash", data.stash, data.stashOptions) TriggerServerEvent("inventory:server:OpenInventory", "stash", data.stash, data.stashOptions)
end end
else else
TriggerEvent("inventory:client:SetCurrentStash", data.stash) TriggerEvent("inventory:client:SetCurrentStash", data.stash)
TriggerServerEvent("inventory:server:OpenInventory", "stash", data.stash, data.stashOptions) TriggerServerEvent("inventory:server:OpenInventory", "stash", data.stash, data.stashOptions)
end end
lookEnt(data.coords) lookEnt(data.coords)
end end
RegisterNetEvent(getScript()..':server:OpenStashQB', function(data) RegisterNetEvent(getScript()..':server:OpenStashQB', function(data)
exports[QBInv]:OpenInventory(source, data.stashName, data) exports[QBInv]:OpenInventory(source, data.stashName, data)
end) end)
function getStash(stashName) local stashResource = "" function getStash(stashName) local stashResource = ""
if type(stashName) ~= "string" then return print("Stash name was not a string %s(%s)", stashName, type(stashName)) end if type(stashName) ~= "string" then return print("Stash name was not a string %s(%s)", stashName, type(stashName)) end
local stashItems, items = {}, {} local stashItems, items = {}, {}
if isStarted(OXInv) then stashResource = OXInv if isStarted(OXInv) then stashResource = OXInv
stashItems = exports[OXInv]:Inventory(stashName).items stashItems = exports[OXInv]:Inventory(stashName).items
elseif isStarted(QSInv) then stashResource = QSInv elseif isStarted(QSInv) then stashResource = QSInv
stashItems = exports[QSInv]:GetStashItems(stashName) stashItems = exports[QSInv]:GetStashItems(stashName)
elseif isStarted(CoreInv) then stashResource = CoreInv elseif isStarted(CoreInv) then stashResource = CoreInv
stashItems = exports[CoreInv]:getInventory(stashName) stashItems = exports[CoreInv]:getInventory(stashName)
elseif isStarted(CodeMInv) then stashResource = CodeMInv elseif isStarted(CodeMInv) then stashResource = CodeMInv
stashItems = exports[CodeMInv]:GetInventoryItems('Stash', stashName) stashItems = exports[CodeMInv]:GetInventoryItems('Stash', stashName)
elseif isStarted(OrigenInv) then stashResource = OrigenInv elseif isStarted(OrigenInv) then stashResource = OrigenInv
stashItems = exports[OrigenInv]:GetStashItems(stashName) stashItems = exports[OrigenInv]:GetStashItems(stashName)
elseif isStarted(PSInv) then stashResource = PSInv elseif isStarted(PSInv) then stashResource = PSInv
local result = MySQL.scalar.await('SELECT items FROM stashitems WHERE stash = ?', { stashName }) local result = MySQL.scalar.await('SELECT items FROM stashitems WHERE stash = ?', { stashName })
if result then stashItems = json.decode(result) end if result then stashItems = json.decode(result) end
elseif isStarted(QBInv) then stashResource = QBInv elseif isStarted(QBInv) then stashResource = QBInv
local result = MySQL.scalar.await("SELECT items FROM "..(QBInvNew and "inventories" or "stashitem").." WHERE identifier = ?", { stashName }) local result = MySQL.scalar.await("SELECT items FROM "..(QBInvNew and "inventories" or "stashitem").." WHERE identifier = ?", { stashName })
if result then stashItems = json.decode(result) end if result then stashItems = json.decode(result) end
end end
debugPrint("^6Bridge^7: ^2Retrieving ^3Stash^2 with ^7"..stashResource) debugPrint("^6Bridge^7: ^2Retrieving ^3Stash^2 with ^7"..stashResource)
if stashItems then if stashItems then
for _, item in pairs(stashItems) do for _, item in pairs(stashItems) do
local itemInfo = Items[item.name:lower()] local itemInfo = Items[item.name:lower()]
if itemInfo then if itemInfo then
local indexNum = #items+1 -- Added to help recreate missing slot numbers local indexNum = #items+1 -- Added to help recreate missing slot numbers
items[(item.slot and item.slot) or indexNum] = { items[(item.slot and item.slot) or indexNum] = {
name = itemInfo.name or nil, name = itemInfo.name or nil,
amount = tonumber(item.amount) or tonumber(item.count), amount = tonumber(item.amount) or tonumber(item.count),
info = item.info or "", info = item.info or "",
label = itemInfo.label or nil, label = itemInfo.label or nil,
description = itemInfo.description or "", description = itemInfo.description or "",
weight = itemInfo.weight or nil, weight = itemInfo.weight or nil,
type = itemInfo.type or nil, type = itemInfo.type or nil,
unique = itemInfo.unique or nil, unique = itemInfo.unique or nil,
useable = itemInfo.useable or nil, useable = itemInfo.useable or nil,
image = itemInfo.image or nil, image = itemInfo.image or nil,
slot = (item.slot and item.slot) or indexNum, slot = (item.slot and item.slot) or indexNum,
metadata = (item.metadata and item.metadata) or nil, metadata = (item.metadata and item.metadata) or nil,
} }
end end
end end
debugPrint("^6Bridge^7: ^3GetStashItems^7: ^2Stash information for ^7'^6"..stashName.."^7' ^2retrieved^7") debugPrint("^6Bridge^7: ^3GetStashItems^7: ^2Stash information for ^7'^6"..stashName.."^7' ^2retrieved^7")
end end
return items return items
end end
function stashRemoveItem(stashItems, stashName, items) local amount = amount and amount or 1 function stashRemoveItem(stashItems, stashName, items) local amount = amount and amount or 1
-- print("stashItems: "..json.encode(stashItems, { indent = true})) -- print("stashItems: "..json.encode(stashItems, { indent = true}))
-- print("stashName: "..json.encode(stashName, { indent = true})) -- print("stashName: "..json.encode(stashName, { indent = true}))
-- print("items: "..json.encode(items, { indent = true})) -- print("items: "..json.encode(items, { indent = true}))
if isStarted(OXInv) then if isStarted(OXInv) then
for k, v in pairs(items) do for k, v in pairs(items) do
debugPrint("^6Bridge^7: ^2Removing item from ^3Stash^2 with ^7"..OXInv, k, v) debugPrint("^6Bridge^7: ^2Removing item from ^3Stash^2 with ^7"..OXInv, k, v)
if type(stashName) == "table" then if type(stashName) == "table" then
for _, name in pairs(stashName) do for _, name in pairs(stashName) do
local success = exports[OXInv]:RemoveItem(name, k, v) local success = exports[OXInv]:RemoveItem(name, k, v)
if success then if success then
debugPrint("^6Bridge^7: ^2Removing item from ^3Stash^2 with ^7"..OXInv, k, v) debugPrint("^6Bridge^7: ^2Removing item from ^3Stash^2 with ^7"..OXInv, k, v)
break break
end end
end end
else else
exports[OXInv]:RemoveItem(stashName, k, v) exports[OXInv]:RemoveItem(stashName, k, v)
end end
end end
elseif isStarted(QSInv) then elseif isStarted(QSInv) then
for k, v in pairs(items) do for k, v in pairs(items) do
for l in pairs(stashItems) do for l in pairs(stashItems) do
if stashItems[l].name == k then if stashItems[l].name == k then
if (stashItems[l].amount - v) <= 0 then if (stashItems[l].amount - v) <= 0 then
debugPrint("^6Bridge^7: ^2None of this item left in stash ^3Stash^7", k, v) debugPrint("^6Bridge^7: ^2None of this item left in stash ^3Stash^7", k, v)
stashItems[l] = nil stashItems[l] = nil
else else
debugPrint("^6Bridge^7: ^2Removing item from ^3Stash^2 with ^7"..QBInv, k, v) debugPrint("^6Bridge^7: ^2Removing item from ^3Stash^2 with ^7"..QBInv, k, v)
exports[QSInv]:RemoveItemIntoStash(stashName, k, v, l) exports[QSInv]:RemoveItemIntoStash(stashName, k, v, l)
end end
end end
end end
end end
elseif isStarted(CoreInv) then elseif isStarted(CoreInv) then
for k, v in pairs(items) do for k, v in pairs(items) do
exports[CoreInv]:removeItemExact(stashName, k, v) exports[CoreInv]:removeItemExact(stashName, k, v)
debugPrint("^6Bridge^7: ^2Removing item from ^3Stash^2 with ^7"..CoreInv, k, v) debugPrint("^6Bridge^7: ^2Removing item from ^3Stash^2 with ^7"..CoreInv, k, v)
end end
elseif isStarted(CodeMInv) then elseif isStarted(CodeMInv) then
for k, v in pairs(items) do for k, v in pairs(items) do
for l in pairs(stashItems) do for l in pairs(stashItems) do
if stashItems[l].name == k then if stashItems[l].name == k then
if (stashItems[l].amount - v) <= 0 then if (stashItems[l].amount - v) <= 0 then
debugPrint("^6Bridge^7: ^2None of this item left in stash ^3Stash^7", k, v) debugPrint("^6Bridge^7: ^2None of this item left in stash ^3Stash^7", k, v)
stashItems[l] = nil stashItems[l] = nil
else else
debugPrint("^6Bridge^7: ^2Removing item from ^3Stash^2 with ^7"..CodeMInv, k, v) debugPrint("^6Bridge^7: ^2Removing item from ^3Stash^2 with ^7"..CodeMInv, k, v)
stashItems[l].amount -= v stashItems[l].amount -= v
end end
end end
end end
end end
debugPrint("^6Bridge^7: ^3saveStash^7: ^2Saving ^3QB^2 stash ^7'^6"..stashName.."^7'") debugPrint("^6Bridge^7: ^3saveStash^7: ^2Saving ^3QB^2 stash ^7'^6"..stashName.."^7'")
elseif isStarted(OrigenInv) then elseif isStarted(OrigenInv) then
for k, v in pairs(items) do for k, v in pairs(items) do
exports[OrigenInv]:RemoveFromStash(stashName, k, v) exports[OrigenInv]:RemoveFromStash(stashName, k, v)
debugPrint("^6Bridge^7: ^2Removing item from ^3Stash^2 with ^7"..OrigenInv, k, v) debugPrint("^6Bridge^7: ^2Removing item from ^3Stash^2 with ^7"..OrigenInv, k, v)
end end
elseif isStarted(PSInv) then elseif isStarted(PSInv) then
for k, v in pairs(items) do for k, v in pairs(items) do
for l in pairs(stashItems) do for l in pairs(stashItems) do
if stashItems[l].name == k then if stashItems[l].name == k then
if (stashItems[l].amount - v) <= 0 then if (stashItems[l].amount - v) <= 0 then
debugPrint("^6Bridge^7: ^2None of this item left in stash ^3Stash^7", k, v) debugPrint("^6Bridge^7: ^2None of this item left in stash ^3Stash^7", k, v)
stashItems[l] = nil stashItems[l] = nil
else else
debugPrint("^6Bridge^7: ^2Removing item from ^3Stash^2 with ^7"..QBInv, k, v) debugPrint("^6Bridge^7: ^2Removing item from ^3Stash^2 with ^7"..QBInv, k, v)
stashItems[l].amount -= v stashItems[l].amount -= v
end end
end end
end end
end end
debugPrint("^6Bridge^7: ^3saveStash^7: ^2Saving ^3QB^2 stash ^7'^6"..stashName.."^7'") debugPrint("^6Bridge^7: ^3saveStash^7: ^2Saving ^3QB^2 stash ^7'^6"..stashName.."^7'")
MySQL.Async.insert('INSERT INTO stashitems (stash, items) VALUES (:stash, :items) ON DUPLICATE KEY UPDATE items = :items', { ['stash'] = stashName, ['items'] = json.encode(stashItems) }) MySQL.Async.insert('INSERT INTO stashitems (stash, items) VALUES (:stash, :items) ON DUPLICATE KEY UPDATE items = :items', { ['stash'] = stashName, ['items'] = json.encode(stashItems) })
elseif isStarted(QBInv) then elseif isStarted(QBInv) then
if QBInvNew then if QBInvNew then
for k, v in pairs(items) do for k, v in pairs(items) do
exports[QBInv]:RemoveItem(stashName[1], k, v, false, 'crafting') exports[QBInv]:RemoveItem(stashName[1], k, v, false, 'crafting')
debugPrint("^6Bridge^7: ^2Removing item from ^3Stash^2 with ^7"..QBInv, k, v) debugPrint("^6Bridge^7: ^2Removing item from ^3Stash^2 with ^7"..QBInv, k, v)
end end
debugPrint("^6Bridge^7: ^3saveStash^7: ^2Saving ^3QB^2 stash ^7'^6"..stashName[1].."^7'") debugPrint("^6Bridge^7: ^3saveStash^7: ^2Saving ^3QB^2 stash ^7'^6"..stashName[1].."^7'")
MySQL.Async.insert('INSERT INTO inventories (identifier, items) VALUES (:stash, :items) ON DUPLICATE KEY UPDATE items = :items', { ['stash'] = stashName[1], ['items'] = json.encode(stashItems) }) MySQL.Async.insert('INSERT INTO inventories (identifier, items) VALUES (:stash, :items) ON DUPLICATE KEY UPDATE items = :items', { ['stash'] = stashName[1], ['items'] = json.encode(stashItems) })
else else
for k, v in pairs(items) do for k, v in pairs(items) do
for l in pairs(stashItems) do for l in pairs(stashItems) do
if stashItems[l].name == k then if stashItems[l].name == k then
if (stashItems[l].amount - v) <= 0 then if (stashItems[l].amount - v) <= 0 then
if Config.System.Debug then if Config.System.Debug then
print("^6Bridge^7: ^2None of this item left in stash ^3Stash^7", k, v) print("^6Bridge^7: ^2None of this item left in stash ^3Stash^7", k, v)
end end
stashItems[l] = nil stashItems[l] = nil
else else
if Config.System.Debug then if Config.System.Debug then
print("^6Bridge^7: ^2Removing item from ^3Stash^2 with ^7"..QBInv, k, v) print("^6Bridge^7: ^2Removing item from ^3Stash^2 with ^7"..QBInv, k, v)
end end
stashItems[l].amount -= v stashItems[l].amount -= v
end end
end end
end end
end end
debugPrint("^6Bridge^7: ^3saveStash^7: ^2Saving ^3QB^2 stash ^7'^6"..stashName.."^7'") debugPrint("^6Bridge^7: ^3saveStash^7: ^2Saving ^3QB^2 stash ^7'^6"..stashName.."^7'")
MySQL.Async.insert('INSERT INTO stashitems (stash, items) VALUES (:stash, :items) ON DUPLICATE KEY UPDATE items = :items', { ['stash'] = stashName, ['items'] = json.encode(stashItems) }) MySQL.Async.insert('INSERT INTO stashitems (stash, items) VALUES (:stash, :items) ON DUPLICATE KEY UPDATE items = :items', { ['stash'] = stashName, ['items'] = json.encode(stashItems) })
end end
else else
print("^4ERROR^7: ^2No Inventory detected ^7- ^2Check ^3exports^1.^2lua^7") print("^4ERROR^7: ^2No Inventory detected ^7- ^2Check ^3exports^1.^2lua^7")
end end
end end
RegisterNetEvent(getScript()..":server:stashRemoveItem", stashRemoveItem) RegisterNetEvent(getScript()..":server:stashRemoveItem", stashRemoveItem)
function stashhasItem(stashItems, items, amount) function stashhasItem(stashItems, items, amount)
local invs = {OXInv, QSInv, CoreInv, CodeMInv, OrigenInv, QBInv, PSInv} local invs = {OXInv, QSInv, CoreInv, CodeMInv, OrigenInv, QBInv, PSInv}
local foundInv = "" local foundInv = ""
for _, inv in ipairs(invs) do for _, inv in ipairs(invs) do
if isStarted(inv) then if isStarted(inv) then
foundInv = inv:gsub("%-", "^7-^6"):gsub("%_", "^7_^6") foundInv = inv:gsub("%-", "^7-^6"):gsub("%_", "^7_^6")
break break
end end
end end
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 = {}
for item, amount in pairs(items) do for item, amount in pairs(items) do
local count = 0 local count = 0
for _, itemData in pairs(stashItems) do for _, itemData in pairs(stashItems) do
if itemData and (itemData.name == item) then if itemData and (itemData.name == item) then
count += (itemData.amount or 1) count += (itemData.amount or 1)
end end
end end
local debugMsg = string.format("^6Bridge^7: ^3stashHasItem^7[^6%s^7]: %s '%s' ^3%d^7/^3%d^7", foundInv, (count >= amount and "^5FOUND^7" or "^1NOT FOUND^7"), item, count, amount) local debugMsg = string.format("^6Bridge^7: ^3stashHasItem^7[^6%s^7]: %s '%s' ^3%d^7/^3%d^7", foundInv, (count >= amount and "^5FOUND^7" or "^1NOT FOUND^7"), item, count, amount)
debugPrint(debugMsg) debugPrint(debugMsg)
hasTable[item] = { hasItem = (count >= amount), count = count } hasTable[item] = { hasItem = (count >= amount), count = count }
end end
for k, v in pairs(hasTable) do if v.hasItem == false then return false, hasTable end end for k, v in pairs(hasTable) do if v.hasItem == false then return false, hasTable end end
return true, hasTable return true, hasTable
end end

View File

@@ -1,404 +1,457 @@
-- This is for experimental targets based on GTA in-world text prompts -- -- This is for experimental targets based on GTA in-world text prompts --
local TextTargets = {} local TextTargets = {}
local Keys = { local Keys = {
[322] = "ESC", [288] = "F1", [289] = "F2", [170] = "F3", [166] = "F5", [322] = "ESC", [288] = "F1", [289] = "F2", [170] = "F3", [166] = "F5",
[167] = "F6", [168] = "F7", [169] = "F8", [56] = "F9", [57] = "F10", [167] = "F6", [168] = "F7", [169] = "F8", [56] = "F9", [57] = "F10",
[243] = "~", [157] = "1", [158] = "2", [160] = "3", [164] = "4", [165] = "5", [243] = "~", [157] = "1", [158] = "2", [160] = "3", [164] = "4", [165] = "5",
[159] = "6", [161] = "7", [162] = "8", [163] = "9", [84] = "-", [83] = "=", [159] = "6", [161] = "7", [162] = "8", [163] = "9", [84] = "-", [83] = "=",
[177] = "BACKSPACE", [37] = "TAB", [177] = "BACKSPACE", [37] = "TAB",
[44] = "Q", [32] = "W", [38] = "E", [45] = "R", [245] = "T", [246] = "Y", [44] = "Q", [32] = "W", [38] = "E", [45] = "R", [245] = "T", [246] = "Y",
[303] = "U", [199] = "P", [303] = "U", [199] = "P",
[39] = "[", [40] = "]", [18] = "ENTER", [137] = "CAPS", [39] = "[", [40] = "]", [18] = "ENTER", [137] = "CAPS",
[34] = "A", [8] = "S", [9] = "D", [23] = "F", [47] = "G", [34] = "A", [8] = "S", [9] = "D", [23] = "F", [47] = "G",
[74] = "H", [311] = "K", [182] = "L", [21] = "LEFTSHIFT", [74] = "H", [311] = "K", [182] = "L", [21] = "LEFTSHIFT",
[20] = "Z", [73] = "X", [26] = "C", [0] = "V", [29] = "B", [249] = "N", [20] = "Z", [73] = "X", [26] = "C", [0] = "V", [29] = "B", [249] = "N",
[244] = "M", [82] = ",", [81] = "." [244] = "M", [82] = ",", [81] = "."
} }
-- Target Creation -- -- Target Creation --
-- Target Entities, this is more based on qb-target's style of target creation, and translates those into ox or qb-target code -- -- Target Entities, this is more based on qb-target's style of target creation, and translates those into ox or qb-target code --
local targetEntities = {} local targetEntities = {}
--- Creates a target for an entity with specified options and interaction distance. --- Creates a target for an entity with specified options and interaction distance.
--- ---
--- This function supports different targeting systems (OX Target, QB Target, or custom DrawText3D targets) --- This function supports different targeting systems (OX Target, QB Target, or custom DrawText3D targets)
--- based on the server configuration. It translates qb-target style options into the appropriate format --- based on the server configuration. It translates qb-target style options into the appropriate format
--- for the detected targeting system. --- for the detected targeting system.
--- ---
---@param entity number The entity ID to create a target for. ---@param entity number The entity ID to create a target for.
---@param opts table A table of option configurations for the target. ---@param opts table A table of option configurations for the target.
--- - **icon** (`string`): The icon to display for the option. --- - **icon** (`string`): The icon to display for the option.
--- - **label** (`string`): The label text for the option. --- - **label** (`string`): The label text for the option.
--- - **item** (`string|nil`): (Optional) The item associated with the option. --- - **item** (`string|nil`): (Optional) The item associated with the option.
--- - **job** (`string|nil`): (Optional) The job required to interact with the option. --- - **job** (`string|nil`): (Optional) The job required to interact with the option.
--- - **gang** (`string|nil`): (Optional) The gang required to interact with the option. --- - **gang** (`string|nil`): (Optional) The gang required to interact with the option.
--- - **action** (`function|nil`): (Optional) The function to execute when the option is selected. --- - **action** (`function|nil`): (Optional) The function to execute when the option is selected.
---@param dist number The interaction distance for the target. ---@param dist number The interaction distance for the target.
--- ---
---@usage ---@usage
--- ```lua --- ```lua
--- createEntityTarget(entityId, { --- createEntityTarget(entityId, {
--- { icon = "fas fa-car", label = "Open Vehicle", action = openVehicle }, --- { icon = "fas fa-car", label = "Open Vehicle", action = openVehicle },
--- { icon = "fas fa-lock", label = "Lock Vehicle", action = lockVehicle } --- { icon = "fas fa-lock", label = "Lock Vehicle", action = lockVehicle }
--- }, 2.5) --- }, 2.5)
--- ``` --- ```
function createEntityTarget(entity, opts, dist) function createEntityTarget(entity, opts, dist)
targetEntities[#targetEntities + 1] = entity targetEntities[#targetEntities + 1] = entity
local entityCoords = GetEntityCoords(entity) local entityCoords = GetEntityCoords(entity)
if Config.System.DontUseTarget then if Config.System.DontUseTarget or (not isStarted(OXTargetExport) and not isStarted(QBTargetExport)) then
debugPrint("^6Bridge^7: ^2Creating new ^3Entity^2 target with ^6DrawText ^7"..entity) debugPrint("^6Bridge^7: ^2Creating new ^3Entity^2 target with ^6DrawText ^7"..entity)
local existingTarget = nil local existingTarget = nil
for key, target in pairs(TextTargets) do for key, target in pairs(TextTargets) do
if #(target.coords - entityCoords) < 0.01 then -- Adjust the threshold for coordinate matching if #(target.coords - entityCoords) < 0.01 then -- Adjust the threshold for coordinate matching
existingTarget = target existingTarget = target
break break
end end
end end
if existingTarget then if existingTarget then
-- Combine options -- Combine options
local keyTable = { 38, 29, 303, 45, 46, 47, 48 } -- Extend key table as needed local keyTable = { 38, 29, 303, 45, 46, 47, 48 } -- Extend key table as needed
for i = 1, #opts do for i = 1, #opts do
local key = keyTable[#existingTarget.options + i] local key = keyTable[#existingTarget.options + i]
opts[i].key = key opts[i].key = key
existingTarget.buttontext[#existingTarget.buttontext + 1] = " ~b~[~w~"..Keys[key].."~b~] ~w~"..opts[i].label existingTarget.buttontext[#existingTarget.buttontext + 1] = " ~b~[~w~"..Keys[key].."~b~] ~w~"..opts[i].label
existingTarget.options[#existingTarget.options + 1] = opts[i] existingTarget.options[#existingTarget.options + 1] = opts[i]
end end
else else
-- Create new target -- Create new target
local tempText = {} local tempText = {}
local keyTable = { 38, 29, 303, 45, 46, 47, 48 } local keyTable = { 38, 29, 303, 45, 46, 47, 48 }
for i = 1, #opts do for i = 1, #opts do
opts[i].key = keyTable[i] opts[i].key = keyTable[i]
tempText[#tempText + 1] = " ~b~[~w~"..Keys[opts[i].key].."~b~] ~w~"..opts[i].label tempText[#tempText + 1] = " ~b~[~w~"..Keys[opts[i].key].."~b~] ~w~"..opts[i].label
end end
TextTargets[entity] = { coords = vec3(entityCoords.x, entityCoords.y, entityCoords.z), buttontext = tempText, options = opts, dist = dist } TextTargets[entity] = { coords = vec3(entityCoords.x, entityCoords.y, entityCoords.z), buttontext = tempText, options = opts, dist = dist }
end end
elseif isStarted(OXTargetExport) then elseif isStarted(OXTargetExport) then
debugPrint("^6Bridge^7: ^2Creating new ^3Entity^2 target with ^6"..OXTargetExport.." ^7"..entity) debugPrint("^6Bridge^7: ^2Creating new ^3Entity^2 target with ^6"..OXTargetExport.." ^7"..entity)
local options = {} local options = {}
for i = 1, #opts do for i = 1, #opts do
options[i] = { options[i] = {
icon = opts[i].icon, icon = opts[i].icon,
label = opts[i].label, label = opts[i].label,
item = opts[i].item or nil, item = opts[i].item or nil,
groups = opts[i].job or opts[i].gang, groups = opts[i].job or opts[i].gang,
onSelect = opts[i].action, onSelect = opts[i].action,
canInteract = function(_, distance) canInteract = function(_, distance)
return distance < dist and true or false return distance < dist and true or false
end end
} }
end end
exports[OXTargetExport]:addLocalEntity(entity, options) exports[OXTargetExport]:addLocalEntity(entity, options)
elseif isStarted(QBTargetExport) then elseif isStarted(QBTargetExport) then
debugPrint("^6Bridge^7: ^2Creating new ^3Entity^2 target with ^6"..QBTargetExport.." ^7"..entity) debugPrint("^6Bridge^7: ^2Creating new ^3Entity^2 target with ^6"..QBTargetExport.." ^7"..entity)
local options = { options = opts, distance = dist } local options = { options = opts, distance = dist }
exports[QBTargetExport]:AddTargetEntity(entity, options) exports[QBTargetExport]:AddTargetEntity(entity, options)
end end
end end
local boxTargets = {} local boxTargets = {}
--- Creates a box-shaped target zone with specified options and interaction distance. --- Creates a box-shaped target zone with specified options and interaction distance.
--- ---
--- This function supports different targeting systems (OX Target, QB Target, or custom DrawText3D targets) --- This function supports different targeting systems (OX Target, QB Target, or custom DrawText3D targets)
--- based on the server configuration. It translates qb-target style options into the appropriate format --- based on the server configuration. It translates qb-target style options into the appropriate format
--- for the detected targeting system. --- for the detected targeting system.
--- ---
---@param data table A table containing the box zone configuration. ---@param data table A table containing the box zone configuration.
--- - **name** (`string`): The name identifier for the zone. --- - **name** (`string`): The name identifier for the zone.
--- - **coords** (`vector3`): The center coordinates of the box. --- - **coords** (`vector3`): The center coordinates of the box.
--- - **width** (`number`): The width of the box. --- - **width** (`number`): The width of the box.
--- - **height** (`number`): The height of the box. --- - **height** (`number`): The height of the box.
--- - **options** (`table`): A table with additional options: --- - **options** (`table`): A table with additional options:
--- - **heading** (`number`): The rotation angle of the box. --- - **heading** (`number`): The rotation angle of the box.
--- - **debugPoly** (`boolean`): Whether to enable debug mode for the zone. --- - **debugPoly** (`boolean`): Whether to enable debug mode for the zone.
--- ---
---@param opts table A table of option configurations for the target. ---@param opts table A table of option configurations for the target.
--- - **icon** (`string`): The icon to display for the option. --- - **icon** (`string`): The icon to display for the option.
--- - **label** (`string`): The label text for the option. --- - **label** (`string`): The label text for the option.
--- - **item** (`string|nil`): (Optional) The item associated with the option. --- - **item** (`string|nil`): (Optional) The item associated with the option.
--- - **job** (`string|nil`): (Optional) The job required to interact with the option. --- - **job** (`string|nil`): (Optional) The job required to interact with the option.
--- - **gang** (`string|nil`): (Optional) The gang required to interact with the option. --- - **gang** (`string|nil`): (Optional) The gang required to interact with the option.
--- - **onSelect** (`function|nil`): (Optional) The function to execute when the option is selected. --- - **onSelect** (`function|nil`): (Optional) The function to execute when the option is selected.
---@param dist number The interaction distance for the target. ---@param dist number The interaction distance for the target.
--- ---
---@return string|table name identifier or target object of the created zone. ---@return string|table name identifier or target object of the created zone.
--- ---
---@usage ---@usage
--- ```lua --- ```lua
--- createBoxTarget({ --- createBoxTarget({
--- name = 'storageBox', --- name = 'storageBox',
--- coords = vector3(100.0, 200.0, 30.0), --- coords = vector3(100.0, 200.0, 30.0),
--- width = 2.0, --- width = 2.0,
--- height = 2.0, --- height = 2.0,
--- options = { heading = 0, debugPoly = false } --- options = { heading = 0, debugPoly = false }
--- }, { --- }, {
--- { icon = "fas fa-box", label = "Open Storage", action = openStorage } --- { icon = "fas fa-box", label = "Open Storage", action = openStorage }
--- }, 1.5) --- }, 1.5)
--- ``` --- ```
function createBoxTarget(data, opts, dist) function createBoxTarget(data, opts, dist)
if Config.System.DontUseTarget then if Config.System.DontUseTarget or (not isStarted(OXTargetExport) and not isStarted(QBTargetExport)) then
debugPrint("^6Bridge^7: ^2Creating new ^3Box^2 target with ^6DrawText ^7"..data[1]) debugPrint("^6Bridge^7: ^2Creating new ^3Box^2 target with ^6DrawText ^7"..data[1])
local existingTarget = nil local existingTarget = nil
for key, target in pairs(TextTargets) do for key, target in pairs(TextTargets) do
if #(target.coords - data[2]) < 0.01 then -- Adjust the threshold as needed for coordinate precision if #(target.coords - data[2]) < 0.01 then -- Adjust the threshold as needed for coordinate precision
existingTarget = target existingTarget = target
break break
end end
end end
local keyTable = { 38, 29, 303, 45, 46, 47, 48 } local keyTable = { 38, 29, 303, 45, 46, 47, 48 }
if existingTarget then if existingTarget then
-- Combine options -- Combine options
for i = 1, #opts do for i = 1, #opts do
local key = keyTable[#existingTarget.options + i] local key = keyTable[#existingTarget.options + i]
opts[i].key = key opts[i].key = key
existingTarget.buttontext[#existingTarget.buttontext+1] = " ~b~[~w~"..Keys[key].."~b~] ~w~"..opts[i].label existingTarget.buttontext[#existingTarget.buttontext+1] = " ~b~[~w~"..Keys[key].."~b~] ~w~"..opts[i].label
existingTarget.options[#existingTarget.options+1] = opts[i] existingTarget.options[#existingTarget.options+1] = opts[i]
end end
else else
-- Create new target -- Create new target
local tempText = {} local tempText = {}
for i = 1, #opts do for i = 1, #opts do
opts[i].key = keyTable[i] opts[i].key = keyTable[i]
tempText[#tempText+1] = " ~b~[~w~"..Keys[opts[i].key].."~b~] ~w~"..opts[i].label tempText[#tempText+1] = " ~b~[~w~"..Keys[opts[i].key].."~b~] ~w~"..opts[i].label
end end
TextTargets[data[1]] = { coords = data[2], buttontext = tempText, options = opts, dist = 1.5 } TextTargets[data[1]] = { coords = data[2], buttontext = tempText, options = opts, dist = 1.5 }
end end
return data[1] return data[1]
elseif isStarted(OXTargetExport) then elseif isStarted(OXTargetExport) then
debugPrint("^6Bridge^7: ^2Creating new ^3Box^2 target with ^6"..OXTargetExport.." ^7"..data[1]) debugPrint("^6Bridge^7: ^2Creating new ^3Box^2 target with ^6"..OXTargetExport.." ^7"..data[1])
local options = {} local options = {}
for i = 1, #opts do for i = 1, #opts do
options[i] = { options[i] = {
icon = opts[i].icon, icon = opts[i].icon,
label = opts[i].label, label = opts[i].label,
item = opts[i].item or nil, item = opts[i].item or nil,
groups = opts[i].job or opts[i].gang, groups = opts[i].job or opts[i].gang,
onSelect = opts[i].onSelect or opts[i].action, onSelect = opts[i].onSelect or opts[i].action,
canInteract = function(_, distance) canInteract = function(_, distance)
return distance < dist and true or false return distance < dist and true or false
end end
} }
end end
if not data[5].useZ then if not data[5].useZ then
local z = data[2].z + math.abs(data[5].maxZ - data[5].minZ) / 2 local z = data[2].z + math.abs(data[5].maxZ - data[5].minZ) / 2
data[2] = vec3(data[2].x, data[2].y, z) data[2] = vec3(data[2].x, data[2].y, z)
end end
local target = exports[OXTargetExport]:addBoxZone({ local target = exports[OXTargetExport]:addBoxZone({
coords = data[2], coords = data[2],
size = vec3(data[4], data[3], (data[5].useZ or not data[5].maxZ) and data[2].z or math.abs(data[5].maxZ - data[5].minZ)), size = vec3(data[4], data[3], (data[5].useZ or not data[5].maxZ) and data[2].z or math.abs(data[5].maxZ - data[5].minZ)),
rotation = data[5].heading, rotation = data[5].heading,
debug = data[5].debugPoly, debug = data[5].debugPoly,
options = options options = options
}) })
boxTargets[#boxTargets+1] = target boxTargets[#boxTargets+1] = target
return target return target
elseif isStarted(QBTargetExport) then elseif isStarted(QBTargetExport) then
debugPrint("^6Bridge^7: ^2Creating new ^3Box^2 target with ^6"..QBTargetExport.." ^7"..data[1]) debugPrint("^6Bridge^7: ^2Creating new ^3Box^2 target with ^6"..QBTargetExport.." ^7"..data[1])
local options = { options = opts, distance = dist } local options = { options = opts, distance = dist }
local target = exports[QBTargetExport]:AddBoxZone(data[1], data[2], data[3], data[4], data[5], options) local target = exports[QBTargetExport]:AddBoxZone(data[1], data[2], data[3], data[4], data[5], options)
boxTargets[#boxTargets+1] = target boxTargets[#boxTargets+1] = target
return data[1] return data[1]
end end
end end
local circleTargets = {} local circleTargets = {}
--- Creates a circular target zone with specified options and interaction distance. --- Creates a circular target zone with specified options and interaction distance.
--- ---
--- This function supports different targeting systems (OX Target, QB Target, or custom DrawText3D targets) --- This function supports different targeting systems (OX Target, QB Target, or custom DrawText3D targets)
--- based on the server configuration. It translates qb-target style options into the appropriate format --- based on the server configuration. It translates qb-target style options into the appropriate format
--- for the detected targeting system. --- for the detected targeting system.
--- ---
---@param data table A table containing the circle zone configuration. ---@param data table A table containing the circle zone configuration.
--- - **name** (`string`): The name identifier for the zone. --- - **name** (`string`): The name identifier for the zone.
--- - **coords** (`vector3`): The center coordinates of the circle. --- - **coords** (`vector3`): The center coordinates of the circle.
--- - **radius** (`number`): The radius of the circle. --- - **radius** (`number`): The radius of the circle.
--- - **options** (`table`): A table with additional options: --- - **options** (`table`): A table with additional options:
--- - **debugPoly** (`boolean`): Whether to enable debug mode for the zone. --- - **debugPoly** (`boolean`): Whether to enable debug mode for the zone.
--- ---
---@param opts table A table of option configurations for the target. ---@param opts table A table of option configurations for the target.
--- - **icon** (`string`): The icon to display for the option. --- - **icon** (`string`): The icon to display for the option.
--- - **label** (`string`): The label text for the option. --- - **label** (`string`): The label text for the option.
--- - **item** (`string|nil`): (Optional) The item associated with the option. --- - **item** (`string|nil`): (Optional) The item associated with the option.
--- - **job** (`string|nil`): (Optional) The job required to interact with the option. --- - **job** (`string|nil`): (Optional) The job required to interact with the option.
--- - **gang** (`string|nil`): (Optional) The gang required to interact with the option. --- - **gang** (`string|nil`): (Optional) The gang required to interact with the option.
--- - **onSelect** (`function|nil`): (Optional) The function to execute when the option is selected. --- - **onSelect** (`function|nil`): (Optional) The function to execute when the option is selected.
---@param dist number The interaction distance for the target. ---@param dist number The interaction distance for the target.
--- ---
---@return string|table name identifier or target object of the created zone. ---@return string|table name identifier or target object of the created zone.
--- ---
---@usage ---@usage
--- ```lua --- ```lua
--- createCircleTarget({ --- createCircleTarget({
--- name = 'centralPark', --- name = 'centralPark',
--- coords = vector3(200.0, 300.0, 40.0), --- coords = vector3(200.0, 300.0, 40.0),
--- radius = 50.0, --- radius = 50.0,
--- options = { debugPoly = false } --- options = { debugPoly = false }
--- }, { --- }, {
--- { icon = "fas fa-tree", label = "Relax", action = relaxAction } --- { icon = "fas fa-tree", label = "Relax", action = relaxAction }
--- }, 2.0) --- }, 2.0)
--- ``` --- ```
function createCircleTarget(data, opts, dist) function createCircleTarget(data, opts, dist)
if Config.System.DontUseTarget then if Config.System.DontUseTarget then
debugPrint("^6Bridge^7: ^2Creating new ^3Circle^2 target with ^6DrawText ^7"..data[1]) debugPrint("^6Bridge^7: ^2Creating new ^3Circle^2 target with ^6DrawText ^7"..data[1])
local existingTarget = nil local existingTarget = nil
for key, target in pairs(TextTargets) do for key, target in pairs(TextTargets) do
if #(target.coords - data[2]) < 0.01 then -- Adjust the threshold for precision if #(target.coords - data[2]) < 0.01 then -- Adjust the threshold for precision
existingTarget = target existingTarget = target
break break
end end
end end
if existingTarget then if existingTarget then
-- Combine options -- Combine options
local keyTable = { 38, 29, 303, 45, 46, 47, 48 } -- Extend key table as needed local keyTable = { 38, 29, 303, 45, 46, 47, 48 } -- Extend key table as needed
for i = 1, #opts do for i = 1, #opts do
local key = keyTable[#existingTarget.options + i] local key = keyTable[#existingTarget.options + i]
opts[i].key = key opts[i].key = key
existingTarget.buttontext[#existingTarget.buttontext+1] = " ~b~[~w~"..Keys[key].."~b~] ~w~"..opts[i].label existingTarget.buttontext[#existingTarget.buttontext+1] = " ~b~[~w~"..Keys[key].."~b~] ~w~"..opts[i].label
existingTarget.options[#existingTarget.options+1] = opts[i] existingTarget.options[#existingTarget.options+1] = opts[i]
end end
else else
-- Create new target -- Create new target
local tempText = "" local tempText = ""
local keyTable = { 38, 29, 303, 45, 46, 47, 48 } local keyTable = { 38, 29, 303, 45, 46, 47, 48 }
for i = 1, #opts do for i = 1, #opts do
opts[i].key = keyTable[i] opts[i].key = keyTable[i]
tempText[#tempText+1] = " ~b~[~w~"..Keys[opts[i].key].."~b~] ~w~"..opts[i].label tempText[#tempText+1] = " ~b~[~w~"..Keys[opts[i].key].."~b~] ~w~"..opts[i].label
end end
TextTargets[data[1]] = { coords = data[2], buttontext = tempText, options = opts, dist = dist } TextTargets[data[1]] = { coords = data[2], buttontext = tempText, options = opts, dist = dist }
end end
return data[1] return data[1]
elseif isStarted(OXTargetExport) then elseif isStarted(OXTargetExport) then
debugPrint("^6Bridge^7: ^2Creating new ^3Sphere^2 target with ^6"..OXTargetExport.." ^7"..data[1]) debugPrint("^6Bridge^7: ^2Creating new ^3Sphere^2 target with ^6"..OXTargetExport.." ^7"..data[1])
local options = {} local options = {}
for i = 1, #opts do for i = 1, #opts do
options[i] = { options[i] = {
icon = opts[i].icon, icon = opts[i].icon,
label = opts[i].label, label = opts[i].label,
item = opts[i].item or nil, item = opts[i].item or nil,
groups = opts[i].job or opts[i].gang, groups = opts[i].job or opts[i].gang,
onSelect = opts[i].onSelect or opts[i].action, onSelect = opts[i].onSelect or opts[i].action,
canInteract = function(_, distance) canInteract = function(_, distance)
return distance < dist and true or false return distance < dist and true or false
end end
} }
end end
local target = exports[OXTargetExport]:addSphereZone({ local target = exports[OXTargetExport]:addSphereZone({
coords = data[2], coords = data[2],
radius = data[3], radius = data[3],
debug = data[4].debugPoly, debug = data[4].debugPoly,
options = options options = options
}) })
circleTargets[#circleTargets+1] = target circleTargets[#circleTargets+1] = target
return target return target
elseif isStarted(QBTargetExport) then elseif isStarted(QBTargetExport) then
debugPrint("^6Bridge^7: ^2Creating new ^3Circle^2 target with ^6"..QBTargetExport.." ^7"..data[1]) debugPrint("^6Bridge^7: ^2Creating new ^3Circle^2 target with ^6"..QBTargetExport.." ^7"..data[1])
local options = { options = opts, distance = dist } local options = { options = opts, distance = dist }
local target = exports[QBTargetExport]:AddCircleZone(data[1], data[2], data[3], data[4], options) local target = exports[QBTargetExport]:AddCircleZone(data[1], data[2], data[3], data[4], options)
circleTargets[#circleTargets+1] = target circleTargets[#circleTargets+1] = target
return data[1] return data[1]
end end
end end
-- Simple function to remove an entity target created within the script -- local targetEntities = {}
--- Removes a previously created entity target.
--- --- Creates a target for an entity with specified options and interaction distance.
--- This function removes the target associated with the specified entity based on the active targeting system. ---
--- --- This function supports different targeting systems (OX Target, QB Target, or custom DrawText3D targets)
--- @param entity number The entity ID whose target should be removed. --- based on the server configuration. It translates qb-target style options into the appropriate format
--- --- for the detected targeting system.
--- @usage ---
--- removeEntityTarget(entityId) ---@param entity number The entity ID to create a target for.
function removeEntityTarget(entity) ---@param opts table A table of option configurations for the target.
if isStarted(QBTargetExport) then exports[QBTargetExport]:RemoveTargetEntity(entity) end --- - **icon** (`string`): The icon to display for the option.
if isStarted(OXTargetExport) then exports[OXTargetExport]:removeLocalEntity(entity, nil) end --- - **label** (`string`): The label text for the option.
if Config.System.DontUseTarget then TextTargets[entity] = nil end --- - **item** (`string|nil`): (Optional) The item associated with the option.
end --- - **job** (`string|nil`): (Optional) The job required to interact with the option.
--- - **gang** (`string|nil`): (Optional) The gang required to interact with the option.
-- Simple function to remove circle or box targets in the script -- --- - **action** (`function|nil`): (Optional) The function to execute when the option is selected.
--- Removes a previously created zone target. ---@param dist number The interaction distance for the target.
--- ---
--- This function removes the target associated with the specified zone based on the active targeting system. ---@usage
--- --- ```lua
--- @param target string|table The name identifier or target object of the zone to remove. --- createEntityTarget(entityId, {
--- --- { icon = "fas fa-car", label = "Open Vehicle", action = openVehicle },
--- @usage --- { icon = "fas fa-lock", label = "Lock Vehicle", action = lockVehicle }
--- ```lua --- }, 2.5)
--- removeZoneTarget('centralPark') --- ```
--- removeZoneTarget(targetObject) function createModelTarget(models, opts, dist)
--- ``` if Config.System.DontUseTarget or (not isStarted(OXTargetExport) and not isStarted(QBTargetExport)) then
function removeZoneTarget(target) --
if isStarted(QBTargetExport) then exports[QBTargetExport]:RemoveZone(target) end elseif isStarted(OXTargetExport) then
if isStarted(OXTargetExport) then exports[OXTargetExport]:removeZone(target, true) end debugPrint("^6Bridge^7: ^2Creating new ^3Model^2 target with ^6"..OXTargetExport)
if Config.System.DontUseTarget then TextTargets[target] = nil end local options = {}
end for i = 1, #opts do
options[i] = {
-- If no target script is found, default to DrawText3D targets -- * experimental * icon = opts[i].icon,
if Config.System.DontUseTarget and not isServer() then label = opts[i].label,
CreateThread(function() item = opts[i].item or nil,
while true do groups = opts[i].job or opts[i].gang,
local pedCoords = GetEntityCoords(PlayerPedId()) onSelect = opts[i].action,
local camCoords = GetGameplayCamCoord() canInteract = function(_, distance)
local camRotation = GetGameplayCamRot(2) -- Get camera rotation in degrees return distance < dist and true or false
local camForwardVector = RotationToDirection(camRotation) -- Convert rotation to direction vector end
}
local closestTarget = nil end
local closestDist = math.huge exports[OXTargetExport]:addModel(models, options)
elseif isStarted(QBTargetExport) then
for k, v in pairs(TextTargets) do debugPrint("^6Bridge^7: ^2Creating new ^3Entity^2 target with ^6"..QBTargetExport)
local targetCoords = v.coords local options = { options = opts, distance = dist }
local dist = #(pedCoords - targetCoords) exports[QBTargetExport]:AddTargetModel(models, options)
local vecToTarget = targetCoords - camCoords end
end
-- Normalize the vector to the target
local vecToTargetNormalized = normalizeVector(vecToTarget)
-- Dot product to check if facing the target -- Simple function to remove an entity target created within the script --
local dot = camForwardVector.x * vecToTargetNormalized.x + camForwardVector.y * vecToTargetNormalized.y + camForwardVector.z * vecToTargetNormalized.z --- Removes a previously created entity target.
---
local isFacingTarget = dot > 0.5 -- Adjust threshold as needed --- This function removes the target associated with the specified entity based on the active targeting system.
---
if dist <= v.dist and isFacingTarget then --- @param entity number The entity ID whose target should be removed.
if dist < closestDist then ---
closestDist = dist --- @usage
closestTarget = v --- removeEntityTarget(entityId)
end function removeEntityTarget(entity)
end if isStarted(QBTargetExport) then exports[QBTargetExport]:RemoveTargetEntity(entity) end
end if isStarted(OXTargetExport) then exports[OXTargetExport]:removeLocalEntity(entity, nil) end
if (Config.System.DontUseTarget or (not isStarted(OXTargetExport) and not isStarted(QBTargetExport))) then TextTargets[entity] = nil end
for k, v in pairs(TextTargets) do end
local isClosest = (v == closestTarget)
if #(pedCoords - v.coords) <= v.dist then -- Simple function to remove circle or box targets in the script --
for i = 1, #v.options do --- Removes a previously created zone target.
if IsControlJustPressed(0, v.options[i].key) and isClosest then ---
if v.options[i].onSelect then v.options[i].onSelect() end --- This function removes the target associated with the specified zone based on the active targeting system.
if v.options[i].action then v.options[i].action() end ---
end --- @param target string|table The name identifier or target object of the zone to remove.
end ---
DrawText3D(vec3(v.coords.x, v.coords.y, v.coords.z + 0.7), concatenateText(v.buttontext), isClosest) --- @usage
end --- ```lua
end --- removeZoneTarget('centralPark')
Wait(0) --- removeZoneTarget(targetObject)
end --- ```
end) function removeZoneTarget(target)
end if isStarted(QBTargetExport) then exports[QBTargetExport]:RemoveZone(target) end
if isStarted(OXTargetExport) then exports[OXTargetExport]:removeZone(target, true) end
-- If the current loaded script is stopped, automatically remove targets -- if (Config.System.DontUseTarget or (not isStarted(OXTargetExport) and not isStarted(QBTargetExport))) then TextTargets[target] = nil end
onResourceStop(function() end
for i = 1, #targetEntities do
if isStarted(OXTargetExport) then exports[OXTargetExport]:removeLocalEntity(targetEntities[i], nil) -- If no target script is found, default to DrawText3D targets -- * experimental *
elseif isStarted(QBTargetExport) then exports[QBTargetExport]:RemoveTargetEntity(targetEntities[i]) end if (Config.System.DontUseTarget or (not isStarted(OXTargetExport) and not isStarted(QBTargetExport))) and not isServer() then
end CreateThread(function()
for i = 1, #boxTargets do while true do
if isStarted(OXTargetExport) then exports[OXTargetExport]:removeZone(boxTargets[i], true) local pedCoords = GetEntityCoords(PlayerPedId())
elseif isStarted(QBTargetExport) then exports[QBTargetExport]:RemoveZone(boxTargets[i].name) end local camCoords = GetGameplayCamCoord()
end local camRotation = GetGameplayCamRot(2) -- Get camera rotation in degrees
for i = 1, #circleTargets do local camForwardVector = RotationToDirection(camRotation) -- Convert rotation to direction vector
if isStarted(OXTargetExport) then exports[OXTargetExport]:removeZone(circleTargets[i], true)
elseif isStarted(QBTargetExport) then exports[QBTargetExport]:RemoveZone(circleTargets[i].name) end local closestTarget = nil
end local closestDist = math.huge
for k, v in pairs(TextTargets) do
local targetCoords = v.coords
local dist = #(pedCoords - targetCoords)
local vecToTarget = targetCoords - camCoords
-- Normalize the vector to the target
local vecToTargetNormalized = normalizeVector(vecToTarget)
-- Dot product to check if facing the target
local dot = camForwardVector.x * vecToTargetNormalized.x + camForwardVector.y * vecToTargetNormalized.y + camForwardVector.z * vecToTargetNormalized.z
local isFacingTarget = dot > 0.5 -- Adjust threshold as needed
if dist <= v.dist and isFacingTarget then
if dist < closestDist then
closestDist = dist
closestTarget = v
end
end
end
for k, v in pairs(TextTargets) do
local isClosest = (v == closestTarget)
if #(pedCoords - v.coords) <= v.dist then
for i = 1, #v.options do
if IsControlJustPressed(0, v.options[i].key) and isClosest then
if v.options[i].onSelect then v.options[i].onSelect() end
if v.options[i].action then v.options[i].action() end
end
end
DrawText3D(vec3(v.coords.x, v.coords.y, v.coords.z + 0.7), concatenateText(v.buttontext), isClosest)
end
end
Wait(0)
end
end)
end
-- If the current loaded script is stopped, automatically remove targets --
onResourceStop(function()
for i = 1, #targetEntities do
if isStarted(OXTargetExport) then exports[OXTargetExport]:removeLocalEntity(targetEntities[i], nil)
elseif isStarted(QBTargetExport) then exports[QBTargetExport]:RemoveTargetEntity(targetEntities[i]) end
end
for i = 1, #boxTargets do
if isStarted(OXTargetExport) then exports[OXTargetExport]:removeZone(boxTargets[i], true)
elseif isStarted(QBTargetExport) then exports[QBTargetExport]:RemoveZone(boxTargets[i].name) end
end
for i = 1, #circleTargets do
if isStarted(OXTargetExport) then exports[OXTargetExport]:removeZone(circleTargets[i], true)
elseif isStarted(QBTargetExport) then exports[QBTargetExport]:RemoveZone(circleTargets[i].name) end
end
end, true) end, true)

View File

@@ -1,250 +1,250 @@
-- Get Vehicle Info -- -- Get Vehicle Info --
local lastCar = nil local lastCar = nil
local carInfo = {} local carInfo = {}
--- Searches the 'Vehicles' table for a specific vehicle's 'name', 'price', and 'class'. --- Searches the 'Vehicles' table for a specific vehicle's 'name', 'price', and 'class'.
--- ---
--- This function checks if the provided vehicle is different from the last searched vehicle. --- This function checks if the provided vehicle is different from the last searched vehicle.
--- If it's a new vehicle, it retrieves its model and searches the 'Vehicles' table for matching entries. --- If it's a new vehicle, it retrieves its model and searches the 'Vehicles' table for matching entries.
--- It populates the `carInfo` table with the vehicle's name, price, and class. --- It populates the `carInfo` table with the vehicle's name, price, and class.
--- If the vehicle is not found in the table, it defaults to using the vehicle's display name and sets the price to 0. --- If the vehicle is not found in the table, it defaults to using the vehicle's display name and sets the price to 0.
--- ---
---@param vehicle number The entity ID of the vehicle to search for. ---@param vehicle number The entity ID of the vehicle to search for.
--- ---
---@return table|nil table containing the vehicle's `name`, `price`, and `class`, or `nil` if the vehicle is invalid. ---@return table|nil table containing the vehicle's `name`, `price`, and `class`, or `nil` if the vehicle is invalid.
--- ---
---@usage ---@usage
--- ```lua --- ```lua
--- local info = searchCar(vehicleEntity) --- local info = searchCar(vehicleEntity)
--- print(info.name, info.price, info.class) --- print(info.name, info.price, info.class)
--- ``` --- ```
function searchCar(vehicle) function searchCar(vehicle)
if lastCar ~= vehicle then -- If same car, use previous info if lastCar ~= vehicle then -- If same car, use previous info
lastCar = vehicle lastCar = vehicle
carInfo = {} carInfo = {}
local model = GetEntityModel(vehicle) local model = GetEntityModel(vehicle)
local classlist = { local classlist = {
"Compacts", --1 "Compacts", --1
"Sedans", --2 "Sedans", --2
"SUVs", --3 "SUVs", --3
"Coupes", --4 "Coupes", --4
"Muscle", --5 "Muscle", --5
"Sports Classics", --6 "Sports Classics", --6
"Sports", --7 "Sports", --7
"Super", --8 "Super", --8
"Motorcycles", --9 "Motorcycles", --9
"Off-road", --10 "Off-road", --10
"Industrial", --11 "Industrial", --11
"Utility", --12 "Utility", --12
"Vans", --13 "Vans", --13
"Cycles", --14 "Cycles", --14
"Boats", --15 "Boats", --15
"Helicopters", --16 "Helicopters", --16
"Planes", --17 "Planes", --17
"Service", --18 "Service", --18
"Emergency", --19 "Emergency", --19
"Military", --20 "Military", --20
"Commercial", --21 "Commercial", --21
"Trains", --22 "Trains", --22
} }
if Vehicles then if Vehicles then
for k, v in pairs(Vehicles) do for k, v in pairs(Vehicles) do
if tonumber(v.hash) == model or GetHashKey(v.hash) == model or GetHashKey(v.model) == model then if tonumber(v.hash) == model or GetHashKey(v.hash) == model or GetHashKey(v.model) == model then
debugPrint("^6Bridge^7: ^2Vehicle info found in^7 ^4Vehicles^7 ^2table^7: ^6"..(v.hash and v.hash or v.model).. " ^7(^6"..Vehicles[k].name.."^7)") debugPrint("^6Bridge^7: ^2Vehicle info found in^7 ^4Vehicles^7 ^2table^7: ^6"..(v.hash and v.hash or v.model).. " ^7(^6"..Vehicles[k].name.."^7)")
carInfo.name = Vehicles[k].name.." "..Vehicles[k].brand carInfo.name = Vehicles[k].name.." "..Vehicles[k].brand
carInfo.price = Vehicles[k].price carInfo.price = Vehicles[k].price
carInfo.class = classlist[GetVehicleClass(vehicle) + 1], GetVehicleClass(vehicle) carInfo.class = classlist[GetVehicleClass(vehicle) + 1], GetVehicleClass(vehicle)
break break
end end
end end
if not carInfo.name then if not carInfo.name then
debugPrint("^6Bridge^7: ^2Vehicle ^1not ^2found in ^4vehicles^7 ^2table^7: ^6"..model.." ^7(^6"..GetDisplayNameFromVehicleModel(model):lower().."^7)") debugPrint("^6Bridge^7: ^2Vehicle ^1not ^2found in ^4vehicles^7 ^2table^7: ^6"..model.." ^7(^6"..GetDisplayNameFromVehicleModel(model):lower().."^7)")
carInfo.name = string.upper(GetMakeNameFromVehicleModel(model).." "..GetDisplayNameFromVehicleModel(model)) carInfo.name = string.upper(GetMakeNameFromVehicleModel(model).." "..GetDisplayNameFromVehicleModel(model))
carInfo.price = 0 carInfo.price = 0
carInfo.class = classlist[GetVehicleClass(vehicle) + 1], GetVehicleClass(vehicle) carInfo.class = classlist[GetVehicleClass(vehicle) + 1], GetVehicleClass(vehicle)
end end
return carInfo return carInfo
else else
if not carInfo.name then if not carInfo.name then
debugPrint("^6Bridge^7: ^2Vehicle ^1not ^2found in ^4vehicles^7 ^2table^7: ^6"..model.." ^7(^6"..GetDisplayNameFromVehicleModel(model):lower().."^7)") debugPrint("^6Bridge^7: ^2Vehicle ^1not ^2found in ^4vehicles^7 ^2table^7: ^6"..model.." ^7(^6"..GetDisplayNameFromVehicleModel(model):lower().."^7)")
carInfo.name = string.upper(GetMakeNameFromVehicleModel(model).." "..GetDisplayNameFromVehicleModel(model)) carInfo.name = string.upper(GetMakeNameFromVehicleModel(model).." "..GetDisplayNameFromVehicleModel(model))
carInfo.price = 0 carInfo.price = 0
carInfo.class = classlist[GetVehicleClass(vehicle) + 1], GetVehicleClass(vehicle) carInfo.class = classlist[GetVehicleClass(vehicle) + 1], GetVehicleClass(vehicle)
end end
end end
else else
return carInfo return carInfo
end end
end end
-- Vehicle Properties -- -- Vehicle Properties --
--- Retrieves the properties of a given vehicle. --- Retrieves the properties of a given vehicle.
--- ---
--- This function fetches the vehicle's properties based on the active framework (QBCore or ox). --- This function fetches the vehicle's properties based on the active framework (QBCore or ox).
--- It utilizes the framework's native functions or events to obtain the vehicle's mod list and other details. --- It utilizes the framework's native functions or events to obtain the vehicle's mod list and other details.
--- ---
--- @param vehicle number The entity ID of the vehicle. --- @param vehicle number The entity ID of the vehicle.
--- ---
--- @return table|nil table containing the vehicle's properties, or `nil` if the vehicle is invalid or the framework is not detected. --- @return table|nil table containing the vehicle's properties, or `nil` if the vehicle is invalid or the framework is not detected.
--- ---
--- @usage --- @usage
--- ```lua --- ```lua
--- local props = getVehicleProperties(vehicleEntity) --- local props = getVehicleProperties(vehicleEntity)
--- if props then --- if props then
--- -- Manipulate vehicle properties --- -- Manipulate vehicle properties
--- end --- end
--- ``` --- ```
function getVehicleProperties(vehicle) function getVehicleProperties(vehicle)
local properties = {} local properties = {}
if vehicle == nil then return nil end if vehicle == nil then return nil end
if isStarted(QBExport) and not isStarted(QBXExport) then if isStarted(QBExport) and not isStarted(QBXExport) then
properties = Core.Functions.GetVehicleProperties(vehicle) properties = Core.Functions.GetVehicleProperties(vehicle)
debugPrint("^6Bridge^7: ^2Getting Vehicle Properties ^7[^6"..QBExport.."^7] - [^3"..vehicle.."^7] - [^3"..GetEntityModel(vehicle).."^7/^3"..properties.model.."^7] - [^3"..properties.plate.."^7]") debugPrint("^6Bridge^7: ^2Getting Vehicle Properties ^7[^6"..QBExport.."^7] - [^3"..vehicle.."^7] - [^3"..GetEntityModel(vehicle).."^7/^3"..properties.model.."^7] - [^3"..properties.plate.."^7]")
elseif isStarted(OXLibExport) then elseif isStarted(OXLibExport) then
properties = lib.getVehicleProperties(vehicle) properties = lib.getVehicleProperties(vehicle)
debugPrint("^6Bridge^7: ^2Getting Vehicle Properties ^7[^6"..OXLibExport.."^7] - [^3"..vehicle.."^7] - [^3"..GetEntityModel(vehicle).."^7/^3"..properties.model.."^7] - [^3"..properties.plate.."^7]") debugPrint("^6Bridge^7: ^2Getting Vehicle Properties ^7[^6"..OXLibExport.."^7] - [^3"..vehicle.."^7] - [^3"..GetEntityModel(vehicle).."^7/^3"..properties.model.."^7] - [^3"..properties.plate.."^7]")
end end
return properties return properties
end end
--- Sets the properties of a given vehicle. --- Sets the properties of a given vehicle.
--- ---
--- This function applies the provided properties to the vehicle using the active framework's functions or events. --- This function applies the provided properties to the vehicle using the active framework's functions or events.
--- It first retrieves the current properties and checks for differences before applying the new ones. --- It first retrieves the current properties and checks for differences before applying the new ones.
--- ---
---@param vehicle number The entity ID of the vehicle. ---@param vehicle number The entity ID of the vehicle.
---@param props table The properties to set on the vehicle. ---@param props table The properties to set on the vehicle.
--- ---
---@usage ---@usage
--- ```lua --- ```lua
--- setVehicleProperties(vehicleEntity, newProperties) --- setVehicleProperties(vehicleEntity, newProperties)
--- ``` --- ```
function setVehicleProperties(vehicle, props) function setVehicleProperties(vehicle, props)
local oldProps = getVehicleProperties(vehicle) local oldProps = getVehicleProperties(vehicle)
if checkDifferences(vehicle, props) then if checkDifferences(vehicle, props) then
--if debugMode then debugDifferences(vehicle, props) end --if debugMode then debugDifferences(vehicle, props) end
if not DoesEntityExist(vehicle) then if not DoesEntityExist(vehicle) then
print(("Unable to set vehicle properties for '%s' (entity does not exist)"):format(vehicle)) print(("Unable to set vehicle properties for '%s' (entity does not exist)"):format(vehicle))
end end
if isStarted(QBExport) and not isStarted(QBXExport) then if isStarted(QBExport) and not isStarted(QBXExport) then
Core.Functions.SetVehicleProperties(vehicle, props) 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]") 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 else
TriggerServerEvent(getScript()..":ox:setVehicleProperties", VehToNet(vehicle), props) TriggerServerEvent(getScript()..":ox:setVehicleProperties", VehToNet(vehicle), props)
end end
else else
debugPrint("^6Bridge^7: ^2No Changes Found ^7 [^3"..vehicle.."^7] - [^3"..GetEntityModel(vehicle).."^7/^3"..props.model.."^7] - [^3"..props.plate.."^7]") debugPrint("^6Bridge^7: ^2No Changes Found ^7 [^3"..vehicle.."^7] - [^3"..GetEntityModel(vehicle).."^7/^3"..props.model.."^7] - [^3"..props.plate.."^7]")
end end
end end
--- Checks for differences between the current and new vehicle properties. --- Checks for differences between the current and new vehicle properties.
--- ---
--- This function compares each property of the vehicle to determine if any changes have been made. --- This function compares each property of the vehicle to determine if any changes have been made.
--- It logs the differences for debugging purposes. --- It logs the differences for debugging purposes.
--- ---
---@param vehicle number The entity ID of the vehicle. ---@param vehicle number The entity ID of the vehicle.
---@param newProps table The new properties to compare against the current ones. ---@param newProps table The new properties to compare against the current ones.
--- ---
---@return boolean `true` if differences are found, `false` otherwise. ---@return boolean `true` if differences are found, `false` otherwise.
--- ---
---@usage ---@usage
--- ```lua --- ```lua
--- if checkDifferences(vehicleEntity, newProperties) then --- if checkDifferences(vehicleEntity, newProperties) then
--- setVehicleProperties(vehicleEntity, newProperties) --- setVehicleProperties(vehicleEntity, newProperties)
--- end --- end
--- ``` --- ```
function checkDifferences(vehicle, newProps) function checkDifferences(vehicle, newProps)
local oldProps = getVehicleProperties(vehicle) local oldProps = getVehicleProperties(vehicle)
debugPrint("^6Bridge^7: ^2Finding differences in ^3Vehicle Properties^7") debugPrint("^6Bridge^7: ^2Finding differences in ^3Vehicle Properties^7")
local allow = false local allow = false
for k in pairs(oldProps) do for k in pairs(oldProps) do
if json.encode(oldProps[k]) ~= json.encode(newProps[k]) then if json.encode(oldProps[k]) ~= json.encode(newProps[k]) then
allow = true allow = true
debugPrint("^6Bridge^7: ^5Old ^7[^3"..k.."^7] - "..json.encode(oldProps[k], { indent = true })) debugPrint("^6Bridge^7: ^5Old ^7[^3"..k.."^7] - "..json.encode(oldProps[k], { indent = true }))
debugPrint("^6Bridge^7: ^5New ^7[^3"..k.."^7] - "..json.encode(newProps[k], { indent = true })) debugPrint("^6Bridge^7: ^5New ^7[^3"..k.."^7] - "..json.encode(newProps[k], { indent = true }))
end end
end end
return allow return allow
end end
--- Handles setting vehicle properties received from the server. --- Handles setting vehicle properties received from the server.
--- ---
--- This event listens for the `ox:setVehicleProperties` event and applies the received properties to the vehicle. --- This event listens for the `ox:setVehicleProperties` event and applies the received properties to the vehicle.
--- ---
---@event ---@event
---@param netId number The network ID of the vehicle. ---@param netId number The network ID of the vehicle.
---@param props table The properties to set on the vehicle. ---@param props table The properties to set on the vehicle.
--- ---
---@usage ---@usage
--- -- Server-side: TriggerClientEvent(getScript()..":ox:setVehicleProperties", netId, properties) --- -- Server-side: TriggerClientEvent(getScript()..":ox:setVehicleProperties", netId, properties)
RegisterNetEvent(getScript()..":ox:setVehicleProperties", function(netId, props) RegisterNetEvent(getScript()..":ox:setVehicleProperties", function(netId, props)
local vehicle = NetworkGetEntityFromNetworkId(netId) local vehicle = NetworkGetEntityFromNetworkId(netId)
local value = props local value = props
Entity(vehicle).state[getScript()..':setVehicleProperties'] = value Entity(vehicle).state[getScript()..':setVehicleProperties'] = value
end) end)
--- Handles state bag changes for setting vehicle properties. --- Handles state bag changes for setting vehicle properties.
--- ---
--- This handler listens for changes to the vehicle's state bag and applies the new properties accordingly. --- This handler listens for changes to the vehicle's state bag and applies the new properties accordingly.
--- ---
---@param bagName string The name of the state bag. ---@param bagName string The name of the state bag.
---@param key string The key that changed. ---@param key string The key that changed.
---@param value table The new value of the state. ---@param value table The new value of the state.
--- ---
---@usage ---@usage
--- -- Automatically handled when the state bag changes --- -- Automatically handled when the state bag changes
AddStateBagChangeHandler(getScript()..':setVehicleProperties', '', function(bagName, _, value) AddStateBagChangeHandler(getScript()..':setVehicleProperties', '', function(bagName, _, value)
if not value or not GetEntityFromStateBagName then return end if not value or not GetEntityFromStateBagName then return end
local entity = GetEntityFromStateBagName(bagName) local entity = GetEntityFromStateBagName(bagName)
local networked = not bagName:find('localEntity') 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]") 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 and NetworkGetEntityOwner(entity) ~= cache.playerId then return end
if lib.setVehicleProperties(entity, value) then if lib.setVehicleProperties(entity, value) then
Entity(entity).state:set('setVehicleProperties', nil, true) Entity(entity).state:set('setVehicleProperties', nil, true)
end end
end) end)
--- Pushes a vehicle to other players by syncing it. --- Pushes a vehicle to other players by syncing it.
--- ---
--- This function ensures that the vehicle is controlled by the current player and is set as a mission entity. --- This function ensures that the vehicle is controlled by the current player and is set as a mission entity.
--- It requests network control and sets the vehicle accordingly to synchronize changes across clients. --- It requests network control and sets the vehicle accordingly to synchronize changes across clients.
--- ---
---@param entity number The entity ID of the vehicle to push. ---@param entity number The entity ID of the vehicle to push.
--- ---
---@usage ---@usage
--- ```lua --- ```lua
--- pushVehicle(vehicleEntity) --- pushVehicle(vehicleEntity)
--- ``` --- ```
function pushVehicle(entity) function pushVehicle(entity)
SetVehicleModKit(entity, 0) SetVehicleModKit(entity, 0)
if entity ~= 0 and DoesEntityExist(entity) then if entity ~= 0 and DoesEntityExist(entity) then
if not NetworkHasControlOfEntity(entity) then if not NetworkHasControlOfEntity(entity) then
debugPrint("^6Bridge^7: ^3pushVehicle^7: ^2Requesting network control of vehicle^7.") debugPrint("^6Bridge^7: ^3pushVehicle^7: ^2Requesting network control of vehicle^7.")
NetworkRequestControlOfEntity(entity) NetworkRequestControlOfEntity(entity)
local timeout = 2000 local timeout = 2000
while timeout > 0 and not NetworkHasControlOfEntity(entity) do while timeout > 0 and not NetworkHasControlOfEntity(entity) do
Wait(100) Wait(100)
timeout = timeout - 100 timeout = timeout - 100
end end
if NetworkHasControlOfEntity(entity) then if NetworkHasControlOfEntity(entity) then
debugPrint("^6Bridge^7: ^3pushVehicle^7: ^2Network has control of entity^7.") debugPrint("^6Bridge^7: ^3pushVehicle^7: ^2Network has control of entity^7.")
end end
end end
if not IsEntityAMissionEntity(entity) then if not IsEntityAMissionEntity(entity) then
debugPrint("^6Bridge^7: ^3pushVehicle^7: ^2Setting vehicle as a ^7'^2mission^7' &2entity^7.") debugPrint("^6Bridge^7: ^3pushVehicle^7: ^2Setting vehicle as a ^7'^2mission^7' &2entity^7.")
SetEntityAsMissionEntity(entity, true, true) SetEntityAsMissionEntity(entity, true, true)
local timeout = 2000 local timeout = 2000
while timeout > 0 and not IsEntityAMissionEntity(entity) do while timeout > 0 and not IsEntityAMissionEntity(entity) do
Wait(100) Wait(100)
timeout = timeout - 100 timeout = timeout - 100
end end
if IsEntityAMissionEntity(entity) then if IsEntityAMissionEntity(entity) then
debugPrint("^6Bridge^7: ^3pushVehicle^7: ^2Vehicle is a ^7'^2mission^7'^2 entity^7.") debugPrint("^6Bridge^7: ^3pushVehicle^7: ^2Vehicle is a ^7'^2mission^7'^2 entity^7.")
end end
end end
end end
end end

View File

@@ -1,47 +1,47 @@
-- Version check for jim_bridge -- -- Version check for jim_bridge --
function CheckBridgeVersion() function CheckBridgeVersion()
if isServer() then if isServer() then
local currentVersion = "^3"..GetResourceMetadata("jim_bridge", 'version'):gsub("%.", "^7.^3").."^7" local currentVersion = "^3"..GetResourceMetadata("jim_bridge", 'version'):gsub("%.", "^7.^3").."^7"
PerformHttpRequest('https://raw.githubusercontent.com/jimathy/jim_bridge/master/version.txt', function(err, newestVersion, headers) PerformHttpRequest('https://raw.githubusercontent.com/jimathy/jim_bridge/master/version.txt', function(err, newestVersion, headers)
if not newestVersion then print("^1Currently unable to run a version check for ^7'^3jim_bridge^7' ("..currentVersion.."^7)") return end if not newestVersion then print("^1Currently unable to run a version check for ^7'^3jim_bridge^7' ("..currentVersion.."^7)") return end
newestVersion = "^3"..newestVersion:sub(1, -2):gsub("%.", "^7.^3"):gsub("%\r", "").."^7" newestVersion = "^3"..newestVersion:sub(1, -2):gsub("%.", "^7.^3"):gsub("%\r", "").."^7"
print(newestVersion == currentVersion and "^7'^3jim_bridge^7' - ^6You are running the latest version.^7 ("..currentVersion..")" or "^7'^3jim_bridge^7' - ^1You are currently running an outdated version^7, ^1please update^7!") print(newestVersion == currentVersion and "^7'^3jim_bridge^7' - ^6You are running the latest version.^7 ("..currentVersion..")" or "^7'^3jim_bridge^7' - ^1You are currently running an outdated version^7, ^1please update^7!")
end) end)
end end
end end
--CheckBridgeVersion() --CheckBridgeVersion()
-- Print Script names -- Print Script names
function capitalize(str) function capitalize(str)
return (str:gsub("^%l", string.upper):gsub("%-%l", function(letter) return "-" .. string.upper(letter:sub(2)) end)) return (str:gsub("^%l", string.upper):gsub("%-%l", function(letter) return "-" .. string.upper(letter:sub(2)) end))
end end
local scriptName = ("^2"..capitalize(getScript()):gsub("%-", "^7-^2"):gsub("%_", "^7_^2")) or "" local scriptName = ("^2"..capitalize(getScript()):gsub("%-", "^7-^2"):gsub("%_", "^7_^2")) or ""
local scriptVersion = ("^5"..GetResourceMetadata(getScript(), 'version', nil):gsub("%.", "^7.^5")) or "" local scriptVersion = ("^5"..GetResourceMetadata(getScript(), 'version', nil):gsub("%.", "^7.^5")) or ""
local scriptDescription = ("^2"..GetResourceMetadata(getScript(), 'description', nil)) or "" local scriptDescription = ("^2"..GetResourceMetadata(getScript(), 'description', nil)) or ""
local scriptAuthor = ("^2by ^4"..GetResourceMetadata(getScript(), 'author', nil):gsub("%and", "^7and^4")) or "" local scriptAuthor = ("^2by ^4"..GetResourceMetadata(getScript(), 'author', nil):gsub("%and", "^7and^4")) or ""
print(scriptName.." ^7v"..scriptVersion.."^7 - "..scriptDescription.." "..scriptAuthor.."^7") print(scriptName.." ^7v"..scriptVersion.."^7 - "..scriptDescription.." "..scriptAuthor.."^7")
-- Loaded script Version Check, requires CheckVersion() to be placed in a server file -- Loaded script Version Check, requires CheckVersion() to be placed in a server file
function CheckVersion() function CheckVersion()
if isServer() then if isServer() then
local currentVersion = "^3"..GetResourceMetadata(getScript(), 'version'):gsub("%.", "^7.^3").."^7" local currentVersion = "^3"..GetResourceMetadata(getScript(), 'version'):gsub("%.", "^7.^3").."^7"
PerformHttpRequest('https://raw.githubusercontent.com/jimathy/UpdateVersions/master/'..getScript()..'.txt', function(err, newestVersion, headers) PerformHttpRequest('https://raw.githubusercontent.com/jimathy/UpdateVersions/master/'..getScript()..'.txt', function(err, newestVersion, headers)
if not newestVersion then if not newestVersion then
PerformHttpRequest('https://raw.githubusercontent.com/jimathy/'..getScript()..'/master/version.txt', function(err, freeVersion, headers) PerformHttpRequest('https://raw.githubusercontent.com/jimathy/'..getScript()..'/master/version.txt', function(err, freeVersion, headers)
if not freeVersion then print("^1Currently unable to run a version check for ^7'^3"..getScript().."^7' ("..currentVersion.."^7)") return end if not freeVersion then print("^1Currently unable to run a version check for ^7'^3"..getScript().."^7' ("..currentVersion.."^7)") return end
local currentVersion = "^3"..GetResourceMetadata(getScript(), 'version'):gsub("%.", "^7.^3").."^7" local currentVersion = "^3"..GetResourceMetadata(getScript(), 'version'):gsub("%.", "^7.^3").."^7"
freeVersion = "^3"..freeVersion:sub(1, -2):gsub("%.", "^7.^3"):gsub("%\r", "").."^7" freeVersion = "^3"..freeVersion:sub(1, -2):gsub("%.", "^7.^3"):gsub("%\r", "").."^7"
print("^6Version Check^7: ^2Running^7: "..currentVersion.." ^2Latest^7: "..freeVersion) print("^6Version Check^7: ^2Running^7: "..currentVersion.." ^2Latest^7: "..freeVersion)
print(freeVersion == currentVersion and "^7'^3"..getScript().."^7' - ^6You are running the latest version.^7 ("..currentVersion..")" or "^7'^3"..getScript().."^7' - ^1You are currently running an outdated version^7, ^1please update^7!") print(freeVersion == currentVersion and "^7'^3"..getScript().."^7' - ^6You are running the latest version.^7 ("..currentVersion..")" or "^7'^3"..getScript().."^7' - ^1You are currently running an outdated version^7, ^1please update^7!")
end) end)
else else
newestVersion = "^3"..newestVersion:sub(1, -2):gsub("%.", "^7.^3"):gsub("%\r", "").."^7" newestVersion = "^3"..newestVersion:sub(1, -2):gsub("%.", "^7.^3"):gsub("%\r", "").."^7"
print("^6Version Check^7: ^2Running^7: "..currentVersion.." ^2Latest^7: "..newestVersion) print("^6Version Check^7: ^2Running^7: "..currentVersion.." ^2Latest^7: "..newestVersion)
print(newestVersion == currentVersion and '^6You are running the latest version.^7 ('..currentVersion..')' or "^1You are currently running an outdated version^7, ^1please update^7!") print(newestVersion == currentVersion and '^6You are running the latest version.^7 ('..currentVersion..')' or "^1You are currently running an outdated version^7, ^1please update^7!")
end end
end) end)
end end
end end
--CheckVersion() --CheckVersion()

View File

@@ -1,260 +1,265 @@
-- Phone Mails -- Phone Mails
--- Sends a phone mail using the detected phone system. --- Sends a phone mail using the detected phone system.
--- ---
--- This function detects the active phone resource (e.g., gksphone, yflip-phone, qb-phone, etc.) --- This function detects the active phone resource (e.g., gksphone, yflip-phone, qb-phone, etc.)
--- and sends a mail using the appropriate method for that phone system. --- and sends a mail using the appropriate method for that phone system.
--- ---
--- @param data table A table containing the mail data. --- @param data table A table containing the mail data.
--- - **subject** (`string`): The subject of the email. --- - **subject** (`string`): The subject of the email.
--- - **sender** (`string`): The sender of the email. --- - **sender** (`string`): The sender of the email.
--- - **message** (`string`): The body content of the email. --- - **message** (`string`): The body content of the email.
--- - **actions** (`table|nil`): (Optional) Action buttons associated with the email. --- - **actions** (`table|nil`): (Optional) Action buttons associated with the email.
--- ---
--- @usage --- @usage
--- ```lua --- ```lua
--- sendPhoneMail({ --- sendPhoneMail({
--- subject = "Welcome!", --- subject = "Welcome!",
--- sender = "Admin", --- sender = "Admin",
--- message = "Thank you for joining our server.", --- message = "Thank you for joining our server.",
--- actions = { --- actions = {
--- { label = "Reply", action = replyFunction } --- { label = "Reply", action = replyFunction }
--- } --- }
--- }) --- })
--- ``` --- ```
function sendPhoneMail(data) local phoneResource = "" function sendPhoneMail(data) local phoneResource = ""
if isStarted("gksphone") then phoneResource = "gksphone" if isStarted("gksphone") then phoneResource = "gksphone"
exports["gksphone"]:SendNewMail(data) exports["gksphone"]:SendNewMail(data)
elseif isStarted("yflip-phone") then phoneResource = "yflip-phone" elseif isStarted("yflip-phone") then phoneResource = "yflip-phone"
TriggerServerEvent(getScript()..":yflip:SendMail", data) TriggerServerEvent(getScript()..":yflip:SendMail", data)
elseif isStarted("qs-smartphone") then phoneResource = "qs-smartphone" elseif isStarted("qs-smartphone") then phoneResource = "qs-smartphone"
TriggerServerEvent('qs-smartphone:server:sendNewMail', data) TriggerServerEvent('qs-smartphone:server:sendNewMail', data)
elseif isStarted("qs-smartphone-pro") then phoneResource = "qs-smartphone-pro" elseif isStarted("qs-smartphone-pro") then phoneResource = "qs-smartphone-pro"
TriggerServerEvent('phone:sendNewMail', data) TriggerServerEvent('phone:sendNewMail', data)
elseif isStarted("roadphone") then phoneResource = "roadphone" elseif isStarted("roadphone") then phoneResource = "roadphone"
data.message = data.message:gsub("%<br>", "\n") data.message = data.message:gsub("%<br>", "\n")
exports['roadphone']:sendMail(data) exports['roadphone']:sendMail(data)
elseif isStarted("lb-phone") then phoneResource = "lb-phone" elseif isStarted("lb-phone") then phoneResource = "lb-phone"
data.message = data.message:gsub("%<br>", "\n") data.message = data.message:gsub("%<br>", "\n")
TriggerServerEvent(getScript()..":lbphone:SendMail", data) TriggerServerEvent(getScript()..":lbphone:SendMail", data)
elseif isStarted("qb-phone") then phoneResource = "qb-phone" elseif isStarted("qb-phone") then phoneResource = "qb-phone"
TriggerServerEvent('qb-phone:server:sendNewMail', data) TriggerServerEvent('qb-phone:server:sendNewMail', data)
elseif isStarted("jpr-phonesystem") then phoneResource = "jpr-phonesystem" elseif isStarted("jpr-phonesystem") then phoneResource = "jpr-phonesystem"
TriggerServerEvent(getScript()..":jpr:SendMail", data) TriggerServerEvent(getScript()..":jpr:SendMail", data)
end end
if phoneResource ~= "" then debugPrint("^6Bridge^7[^3"..phoneResource.."^7]: ^2Sending mail to player") if phoneResource ~= "" then debugPrint("^6Bridge^7[^3"..phoneResource.."^7]: ^2Sending mail to player")
else print("^6Bridge^7: ^1ERROR ^2Sending mail to player ^7 - ^2No supported phone found") end else print("^6Bridge^7: ^1ERROR ^2Sending mail to player ^7 - ^2No supported phone found") end
end end
--- Handles sending mail for lb-phone. --- Handles sending mail for lb-phone.
--- ---
--- This event listens for the `lbphone:SendMail` event and sends an email using lb-phone's API. --- This event listens for the `lbphone:SendMail` event and sends an email using lb-phone's API.
--- ---
--- @event --- @event
--- @param data table The mail data. --- @param data table The mail data.
--- - **subject** (`string`): The subject of the email. --- - **subject** (`string`): The subject of the email.
--- - **message** (`string`): The body content of the email. --- - **message** (`string`): The body content of the email.
--- - **buttons** (`table|nil`): (Optional) Action buttons associated with the email. --- - **buttons** (`table|nil`): (Optional) Action buttons associated with the email.
--- ---
--- @usage --- @usage
--- ``` --- ```
--- -- Server-side: --- -- Server-side:
--- TriggerClientEvent(getScript()..":lbphone:SendMail", data) --- TriggerClientEvent(getScript()..":lbphone:SendMail", data)
--- ``` --- ```
RegisterNetEvent(getScript()..":lbphone:SendMail", function(data) RegisterNetEvent(getScript()..":lbphone:SendMail", function(data)
local src = source local src = source
local phoneNumber = exports["lb-phone"]:GetEquippedPhoneNumber(src) local phoneNumber = exports["lb-phone"]:GetEquippedPhoneNumber(src)
local emailAddress = exports["lb-phone"]:GetEmailAddress(phoneNumber) local emailAddress = exports["lb-phone"]:GetEmailAddress(phoneNumber)
if data.actions then data.buttons = data.actions end if data.actions then data.buttons = data.actions end
exports["lb-phone"]:SendMail({ exports["lb-phone"]:SendMail({
to = emailAddress, to = emailAddress,
subject = data.subject, subject = data.subject,
message = data.message, message = data.message,
actions = data.buttons, actions = data.buttons,
}) })
end) end)
--- Handles sending mail for yflip-phone. --- Handles sending mail for yflip-phone.
--- ---
--- This event listens for the `yflip:SendMail` event and sends an email using yflip-phone's API. --- This event listens for the `yflip:SendMail` event and sends an email using yflip-phone's API.
--- ---
--- @event --- @event
--- @param data table The mail data. --- @param data table The mail data.
--- - **subject** (`string`): The subject of the email. --- - **subject** (`string`): The subject of the email.
--- - **sender** (`string`): The sender of the email. --- - **sender** (`string`): The sender of the email.
--- - **message** (`string`): The body content of the email. --- - **message** (`string`): The body content of the email.
--- - **buttons** (`table|nil`): (Optional) Action buttons associated with the email. --- - **buttons** (`table|nil`): (Optional) Action buttons associated with the email.
--- ---
--- @usage --- @usage
--- ```lua --- ```lua
--- -- Server-side: --- -- Server-side:
--- TriggerClientEvent(getScript()..":yflip:SendMail", data) --- TriggerClientEvent(getScript()..":yflip:SendMail", data)
--- ``` --- ```
RegisterNetEvent(getScript()..":yflip:SendMail", function(data) RegisterNetEvent(getScript()..":yflip:SendMail", function(data)
local src = source local src = source
exports["yflip-phone"]:SendMail({ exports["yflip-phone"]:SendMail({
title = data.subject, title = data.subject,
sender = data.sender, sender = data.sender,
senderDisplayName = data.sender, senderDisplayName = data.sender,
content = data.message, content = data.message,
actions = data.buttons, actions = data.buttons,
}, 'source', src) }, 'source', src)
end) end)
--- Handles sending mail for jpr-phonesystem. --- Handles sending mail for jpr-phonesystem.
--- ---
--- This event listens for the `jpr:SendMail` event and sends an email using jpr-phonesystem's API. --- This event listens for the `jpr:SendMail` event and sends an email using jpr-phonesystem's API.
--- ---
--- @event --- @event
--- @param data table The mail data. --- @param data table The mail data.
--- - **subject** (`string`): The subject of the email. --- - **subject** (`string`): The subject of the email.
--- - **sender** (`string`): The sender of the email. --- - **sender** (`string`): The sender of the email.
--- - **message** (`string`): The body content of the email. --- - **message** (`string`): The body content of the email.
--- - **buttons** (`table|nil`): (Optional) Action buttons associated with the email. --- - **buttons** (`table|nil`): (Optional) Action buttons associated with the email.
--- ---
--- @return void --- @return void
--- ---
--- @usage --- @usage
--- ```lua --- ```lua
--- -- Server-side: --- -- Server-side:
--- TriggerClientEvent(getScript()..":jpr:SendMail", data) --- TriggerClientEvent(getScript()..":jpr:SendMail", data)
--- ``` --- ```
RegisterNetEvent(getScript()..":jpr:SendMail", function(data) RegisterNetEvent(getScript()..":jpr:SendMail", function(data)
local src = source local src = source
local Player = Core.Functions.GetPlayer(src) local Player = Core.Functions.GetPlayer(src)
TriggerEvent('jpr-phonesystem:server:sendEmail', { TriggerEvent('jpr-phonesystem:server:sendEmail', {
Assunto = data.subject, -- Subject Assunto = data.subject, -- Subject
Conteudo = data.message, -- Content Conteudo = data.message, -- Content
Enviado = data.sender, -- Submitted by Enviado = data.sender, -- Submitted by
Destinatario = Player.PlayerData.citizenid, -- Target Destinatario = Player.PlayerData.citizenid, -- Target
Event = {}, -- Optional Event = {}, -- Optional
}) })
end) end)
-- Server-Side Functions for Registering Commands, Stashes, and Shops -- Server-Side Functions for Registering Commands, Stashes, and Shops
--- Registers a command with the active command system. --- Registers a command with the active command system.
--- ---
--- This function detects whether the server is using OXLib or qb-core for command registration --- This function detects whether the server is using OXLib or qb-core for command registration
--- and registers the command accordingly. --- and registers the command accordingly.
--- ---
--- @param command string The name of the command to register. --- @param command string The name of the command to register.
--- @param options table A table containing command options. --- @param options table A table containing command options.
--- - **help** (`string`): The help description for the command. --- - **help** (`string`): The help description for the command.
--- - **params** (`table`): A table of parameters for the command. --- - **params** (`table`): A table of parameters for the command.
--- - **callback** (`function`): The function to execute when the command is called. --- - **callback** (`function`): The function to execute when the command is called.
--- - **autocomplete** (`function|nil`): (Optional) A function for autocompletion. --- - **autocomplete** (`function|nil`): (Optional) A function for autocompletion.
--- - **restrictedGroup** (`string|nil`): (Optional) The user group required to execute the command. --- - **restrictedGroup** (`string|nil`): (Optional) The user group required to execute the command.
--- ---
--- @usage --- @usage
--- ````lua --- ````lua
--- -- Server Side: --- -- Server Side:
--- registerCommand("greet", { --- registerCommand("greet", {
--- "Greets the player", --- "Greets the player",
--- { name = "name", help = "Name of the player to greet" }, --- { name = "name", help = "Name of the player to greet" },
--- function(source, args) print("Hello, " .. args[1] .. "!") end, --- function(source, args) print("Hello, " .. args[1] .. "!") end,
--- nil, --- nil,
--- "admin" --- "admin"
--- }) --- })
--- ``` --- ```
function registerCommand(command, options) function registerCommand(command, options)
if isStarted(OXLibExport) then if isStarted(OXLibExport) then
debugPrint("^6Bridge^7: ^2Registering ^3Command^2 with ^7"..OXLibExport, command) debugPrint("^6Bridge^7: ^2Registering ^3Command^2 with ^7"..OXLibExport, command)
lib.addCommand(command, { help = options[1], restricted = options[5] and "group."..options[5] or nil }, options[4]) lib.addCommand(command, { help = options[1], restricted = options[5] and "group."..options[5] or nil }, options[4])
elseif isStarted(QBExport) and not isStarted(QBXExport) then elseif isStarted(QBExport) and not isStarted(QBXExport) then
debugPrint("^6Bridge^7: ^2Registering ^3Command^2 with ^7 "..QBExport, command) debugPrint("^6Bridge^7: ^2Registering ^3Command^2 with ^7 "..QBExport, command)
Core.Commands.Add(command, options[1], options[2], options[3], options[4], options[5] and options[5] or nil) Core.Commands.Add(command, options[1], options[2], options[3], options[4], options[5] and options[5] or nil)
end elseif isStarted(ESXExport) then
end debugPrint("^6Bridge^7: ^2Registering ^3Command^2 with ^7 ESX Legacy", command)
ESX.RegisterCommand(command, options[5] or 'admin', function(xPlayer, args, showError)
--- Registers a stash with the active inventory system. options[4](xPlayer.source, args, showError)
--- end, false, { help = options[1] })
--- This function detects whether the server is using OXInv or QSInv and registers the stash accordingly. end
--- end
--- @param name string The unique identifier for the stash.
--- @param label string The display name for the stash. --- Registers a stash with the active inventory system.
--- @param slots number|nil (Optional) The number of slots in the stash. Defaults to 50. ---
--- @param weight number|nil (Optional) The maximum weight the stash can hold. Defaults to 4,000,000. --- This function detects whether the server is using OXInv or QSInv and registers the stash accordingly.
--- @param owner string|nil (Optional) The owner identifier for personal stashes. ---
--- @param coords table|nil (Optional) The coordinates for the stash location. --- @param name string The unique identifier for the stash.
--- --- @param label string The display name for the stash.
--- @usage --- @param slots number|nil (Optional) The number of slots in the stash. Defaults to 50.
--- ```lua --- @param weight number|nil (Optional) The maximum weight the stash can hold. Defaults to 4,000,000.
--- registerStash("playerStash", "Player Stash", 100, 8000000, "player123", { x = 100.0, y = 200.0, z = 30.0 }) --- @param owner string|nil (Optional) The owner identifier for personal stashes.
--- ``` --- @param coords table|nil (Optional) The coordinates for the stash location.
function registerStash(name, label, slots, weight, owner, coords) ---
if isStarted(OXInv) then --- @usage
debugPrint("^6Bridge^7: ^2Registering ^3OX ^2Stash^7:", name, label, owner or nil) --- ```lua
exports[OXInv]:RegisterStash(name, label, slots or 50, weight or 4000000, owner or nil) --- registerStash("playerStash", "Player Stash", 100, 8000000, "player123", { x = 100.0, y = 200.0, z = 30.0 })
elseif isStarted(QSInv) then --- ```
debugPrint("^6Bridge^7: ^2Registering ^3QS ^2Stash^7:", name, label) function registerStash(name, label, slots, weight, owner, coords)
exports[QSInv]:RegisterStash(name, slots or 50, weight or 4000000) if isStarted(OXInv) then
end debugPrint("^6Bridge^7: ^2Registering ^3OX ^2Stash^7:", name, label, owner or nil)
end exports[OXInv]:RegisterStash(name, label, slots or 50, weight or 4000000, owner or nil)
elseif isStarted(QSInv) then
--- Registers a shop with the active inventory system. debugPrint("^6Bridge^7: ^2Registering ^3QS ^2Stash^7:", name, label)
--- exports[QSInv]:RegisterStash(name, slots or 50, weight or 4000000)
--- This function detects whether the server is using OXInv or QBInv and registers the shop accordingly. end
--- end
--- @param name string The unique identifier for the shop.
--- @param label string The display name for the shop. --- Registers a shop with the active inventory system.
--- @param items table The list of items available in the shop. ---
--- @param society string|nil (Optional) The society identifier for shared shops. --- This function detects whether the server is using OXInv or QBInv and registers the shop accordingly.
--- ---
--- @usage --- @param name string The unique identifier for the shop.
--- ```lua --- @param label string The display name for the shop.
--- registerShop("weaponShop", "Weapon Shop", weaponItems, "society_weapons") --- @param items table The list of items available in the shop.
--- ``` --- @param society string|nil (Optional) The society identifier for shared shops.
function registerShop(name, label, items, society) ---
if isStarted(OXInv) then --- @usage
debugPrint("^6Bridge^7: ^2Registering ^3OX ^2Store^7:", name, label) --- ```lua
exports[OXInv]:RegisterShop( --- registerShop("weaponShop", "Weapon Shop", weaponItems, "society_weapons")
name, { --- ```
name = label, function registerShop(name, label, items, society)
inventory = items, if isStarted(OXInv) then
society = society, debugPrint("^6Bridge^7: ^2Registering ^3OX ^2Store^7:", name, label)
} exports[OXInv]:RegisterShop(
) name, {
elseif isStarted(QBInv) and QBInvNew then name = label,
debugPrint("^6Bridge^7: ^2Registering ^3QB ^2Store^7:", name, label) inventory = items,
print(json.encode(items, {indent = true})) society = society,
exports[QBInv]:CreateShop({ }
name = name, )
label = label, elseif isStarted(QBInv) and QBInvNew then
slots = #items, debugPrint("^6Bridge^7: ^2Registering ^3QB ^2Store^7:", name, label)
items = items, print(json.encode(items, {indent = true}))
society = society, exports[QBInv]:CreateShop({
}) name = name,
end label = label,
end slots = #items,
items = items,
-- Server-Side Event Registration society = society,
})
if isServer() then end
--- Registers an event to create an OX stash from the server. end
---
--- @event -- Server-Side Event Registration
--- @param name string The unique identifier for the stash.
--- @param label string The display name for the stash. if isServer() then
--- @param slots number|nil (Optional) The number of slots in the stash. --- Registers an event to create an OX stash from the server.
--- @param weight number|nil (Optional) The maximum weight the stash can hold. ---
--- @param owner string|nil (Optional) The owner identifier for personal stashes. --- @event
--- @param coords table|nil (Optional) The coordinates for the stash location. --- @param name string The unique identifier for the stash.
--- --- @param label string The display name for the stash.
--- @usage --- @param slots number|nil (Optional) The number of slots in the stash.
--- ```lua --- @param weight number|nil (Optional) The maximum weight the stash can hold.
--- -- Server-side: --- @param owner string|nil (Optional) The owner identifier for personal stashes.
--- TriggerEvent(getScript()..":server:makeOXStash", name, label, slots, weight, owner, coords) --- @param coords table|nil (Optional) The coordinates for the stash location.
--- ``` ---
RegisterNetEvent(getScript()..":server:makeOXStash", function(name, label, slots, weight, owner, coords) --- @usage
registerStash(name, label, slots, weight, owner, coords) --- ```lua
end) --- -- Server-side:
--- TriggerEvent(getScript()..":server:makeOXStash", name, label, slots, weight, owner, coords)
--- ```
RegisterNetEvent(getScript()..":server:makeOXStash", function(name, label, slots, weight, owner, coords)
registerStash(name, label, slots, weight, owner, coords)
end)
end end

View File

@@ -1,89 +1,89 @@
Exports = { Exports = {
QBExport = "qb-core", QBExport = "qb-core",
QBXExport = "qbx_core", QBXExport = "qbx_core",
ESXExport = "es_extended", ESXExport = "es_extended",
OXCoreExport = "ox_core", OXCoreExport = "ox_core",
OXInv = "ox_inventory", OXInv = "ox_inventory",
QBInv = "qb-inventory", QBInv = "qb-inventory",
PSInv = "ps-inventory", PSInv = "ps-inventory",
QSInv = "qs-inventory", QSInv = "qs-inventory",
CoreInv = "core_inventory", CoreInv = "core_inventory",
CodeMInv = "codem-inventory", CodeMInv = "codem-inventory",
OrigenInv = "origen_inventory", OrigenInv = "origen_inventory",
OXLibExport = "ox_lib", OXLibExport = "ox_lib",
QBMenuExport = "qb-menu", QBMenuExport = "qb-menu",
QBTargetExport = "qb-target", QBTargetExport = "qb-target",
OXTargetExport = "ox_target" OXTargetExport = "ox_target"
} }
-- Required variables -- Required variables
debugMode = Config.System.Debug debugMode = Config.System.Debug
QBInvNew = true QBInvNew = true
InventoryWeight = 120000 InventoryWeight = 120000
-- Load files here into the invoking script -- Load files here into the invoking script
for _, v in pairs({ -- This is a specific load order for _, v in pairs({ -- This is a specific load order
'helpers.lua', -- needs to be first 'helpers.lua', -- needs to be first
'_loaders.lua', '_loaders.lua',
'_eventDebug.lua', '_eventDebug.lua',
'coreloader.lua', -- needs to be second to load all core related stuff before everything else 'coreloader.lua', -- needs to be second to load all core related stuff before everything else
'callback.lua', 'callback.lua',
'duifunctions.lua', 'duifunctions.lua',
-- Native Scaleforms -- Native Scaleforms
'scaleforms/bigMessageInstance.lua', 'scaleforms/bigMessageInstance.lua',
'scaleforms/countDownHandler.lua', 'scaleforms/countDownHandler.lua',
'scaleforms/debugScaleform.lua', 'scaleforms/debugScaleform.lua',
'scaleforms/instructionalButtons.lua', 'scaleforms/instructionalButtons.lua',
'scaleforms/timerBars.lua', 'scaleforms/timerBars.lua',
-- Required functions -- Required functions
'make/loaders.lua', 'make/loaders.lua',
'make/makeBlip.lua', 'make/makeBlip.lua',
'make/makePed.lua', 'make/makePed.lua',
'make/makeProp.lua', 'make/makeProp.lua',
'make/makeVeh.lua', 'make/makeVeh.lua',
'make/cameras.lua', 'make/cameras.lua',
'make/progressBars.lua', 'make/progressBars.lua',
'wrapperfunctions.lua', 'wrapperfunctions.lua',
'polyZone.lua', 'polyZone.lua',
'itemcontrol.lua', 'itemcontrol.lua',
'playerfunctions.lua', 'playerfunctions.lua',
'jobfunctions.lua', 'jobfunctions.lua',
-- Interactions -- Interactions
'targets.lua', 'targets.lua',
'contextmenus.lua', 'contextmenus.lua',
'input.lua', 'input.lua',
'notify.lua', 'notify.lua',
'drawText.lua', 'drawText.lua',
-- Crafting / Shops / Stashes -- Crafting / Shops / Stashes
'crafting.lua', 'crafting.lua',
'stashcontrol.lua', 'stashcontrol.lua',
-- Kind of "other" -- Kind of "other"
'isAnimal.lua', 'isAnimal.lua',
'scaleEntity.lua', 'scaleEntity.lua',
'vehicles.lua', 'vehicles.lua',
'effects.lua', 'effects.lua',
'versioncheck.lua' 'versioncheck.lua'
}) do }) do
if debugMode then if debugMode then
print("^5Loading^7: 'jim_bridge/shared/"..v.."' ^2into ^7'"..GetCurrentResourceName().."' ...") print("^5Loading^7: 'jim_bridge/shared/"..v.."' ^2into ^7'"..GetCurrentResourceName().."' ...")
end end
local fileLoader = assert(load(LoadResourceFile('jim_bridge', ('shared/'..v)), ('@@jim_bridge/shared/'..v))) local fileLoader = assert(load(LoadResourceFile('jim_bridge', ('shared/'..v)), ('@@jim_bridge/shared/'..v)))
fileLoader() fileLoader()
if debugMode then if debugMode then
print("^5Success^7: ^2loaded file^7: 'jim_bridge/shared/"..v.."'!") print("^5Success^7: ^2loaded file^7: 'jim_bridge/shared/"..v.."'!")
end end
end end

View File

@@ -1 +1 @@
1.2 1.2