Main/resources/[jobs]/[mechanic]/jg-mechanic/client/cl-shops-stashes.lua
2025-06-07 08:51:21 +02:00

308 lines
No EOL
9.5 KiB
Lua

local shopZones, shopPeds, shopPoints = {}, {}, {}
local stashZones, stashPeds, stashPoints = {}, {}, {}
local function drawMarkerOnFrame(coords, marker)
---@diagnostic disable-next-line: missing-parameter
DrawMarker(marker.id, coords.x, coords.y, coords.z, 0, 0, 0, 0, 0, 0, marker.size.x, marker.size.y, marker.size.z, marker.color.r, marker.color.g, marker.color.b, marker.color.a, marker.bobUpAndDown, marker.faceCamera, 0, marker.rotate, marker.drawOnEnts)
end
local function drawCustomMarker(center, marker, shopDistance, mechanicId, shopName, stashName)
if not marker then
if shopName and not stashName then
debugPrint("Marker is not setup for [SHOPS] ".. shopName .. " for location: " .. mechanicId, "warning")
elseif stashName then
debugPrint("Marker is not setup for [STASHES] " .. stashName .. " for location: " .. mechanicId, "warning")
end
return
end
local point = lib.points.new({
coords = center,
distance = shopDistance or 20,
})
function point:nearby()
drawMarkerOnFrame(center, marker)
end
return point
end
local function openShop(mechanicId, shopIndex)
local mechanicConfig = Config.MechanicLocations[mechanicId]
if not mechanicConfig or not mechanicConfig.shops or not mechanicConfig.shops[shopIndex] then
Framework.Client.Notify("Shop not found: " .. mechanicId .. " .. index: " .. shopIndex, "error")
return
end
local shop = mechanicConfig.shops[shopIndex]
local shopItems = shop.items or {}
local options = {}
for index, v in pairs(shopItems) do
table.insert(options, {
title = v.label,
icon = "box",
description = ("Buy for %d %s"):format(v.price, Config.Currency),
event = "jg-mechanic:client:input-shop-purchase-qty",
args = { shopIndex = shopIndex, itemIndex = index, item = v.name, price = v.price, mechanicId = mechanicId }
})
end
local context = {
id = "shop_" .. mechanicId .. "_" .. shopIndex,
title = shop.name .. " Shop",
options = options
}
lib.registerContext(context)
lib.showContext("shop_" .. mechanicId .. "_" .. shopIndex)
end
RegisterNetEvent("jg-mechanic:client:input-shop-purchase-qty", function(args)
local input = lib.inputDialog("Enter the amount you want to buy", { "Amount" })
if not input then
Framework.Client.Notify("Invalid amount", "error")
return
end
local qty = tonumber(input[1])
if qty == nil or qty <= 0 then
Framework.Client.Notify("Invalid amount entered", "error")
return
end
TriggerServerEvent("jg-mechanic:server:buy-item", args.shopIndex, args.itemIndex, qty, args.mechanicId)
end)
function createMechanicShops()
for _, zone in pairs(shopZones) do
if zone and zone.remove then zone:remove() end
end
for _, ped in pairs(shopPeds) do
if ped then DeleteEntity(ped) end
end
for _, point in pairs(shopPoints) do
if point and point.remove then point:remove() end
end
shopZones, shopPeds, shopPoints = {}, {}, {}
for mechanicId, mechanicConfig in pairs(Config.MechanicLocations) do
local isMechanicEmployee = lib.callback.await("jg-mechanic:server:is-mechanic-employee", false, mechanicId)
if not isMechanicEmployee then goto continue end
if not mechanicConfig.shops then
debugPrint(("No shops defined for '%s' in Config.MechanicLocations"):format(mechanicId), "warning")
goto continue
end
for shopIndex, shop in ipairs(mechanicConfig.shops) do
if shop.type == "self-service" then
debugPrint(("Skipping self-service shop for '%s' (index: %d)"):format(mechanicId, shopIndex), "debug")
goto shop_continue
end
if not shop.coords or not shop.size then
debugPrint(("Invalid shop data for '%s' (index: %d) - missing coords or size"):format(mechanicId, shopIndex), "warning")
end
if shop.usePed then
local ped = createPedForTarget(shop.pedModel or "s_m_m_lathandy_01", shop.coords.xyz)
shopPeds[#shopPeds+1] = ped
-- If vec4, set heading
if shop.coords.w then
SetEntityHeading(ped, shop.coords.w or 0)
end
if Config.Target == "qb-target" then
exports["qb-target"]:AddTargetEntity(ped, {
options = {
{
label = "Access Shop",
icon = "fas fa-store",
action = function()
openShop(mechanicId, shopIndex)
end,
},
},
distance = 2.5,
})
elseif Config.Target == "ox_target" then
exports.ox_target:addLocalEntity(ped, {
{
name = "access_shop_" .. mechanicId .. "_" .. shopIndex,
label = "Access Shop",
icon = "fas fa-store",
onSelect = function()
openShop(mechanicId, shopIndex)
end,
},
})
end
else
local zoneData = {
coords = shop.coords,
size = vector3(shop.size, shop.size, 2.0),
rotation = shop.coords.w or 0,
debug = Config.Debug,
onEnter = function()
Framework.Client.ShowTextUI("Press [E] to access " .. shop.name)
end,
onExit = function()
Framework.Client.HideTextUI()
lib.hideContext()
end,
inside = function()
if IsControlJustReleased(0, 38) then
openShop(mechanicId, shopIndex)
end
end
}
local zone = lib.zones.box(zoneData)
shopZones[#shopZones+1] = zone
local point = drawCustomMarker(shop.coords, shop.marker, 10.0, mechanicId, shop.name, nil)
shopPoints[#shopPoints + 1] = point
end
::shop_continue::
end
::continue::
end
end
function createMechanicStashes()
for _, zone in pairs(stashZones) do
if zone and zone.remove then zone:remove() end
end
for _, ped in pairs(stashPeds) do
if ped then DeleteEntity(ped) end
end
for _, point in pairs(stashPoints) do
if point and point.remove then point:remove() end
end
stashZones, stashPeds, stashPoints = {}, {}, {}
for mechanicId, mechanicConfig in pairs(Config.MechanicLocations) do
local isMechanicEmployee = lib.callback.await("jg-mechanic:server:is-mechanic-employee", false, mechanicId)
if not isMechanicEmployee then goto continue end
if not mechanicConfig or not mechanicConfig.stashes then
debugPrint(("No stashes defined for '%s' in Config.MechanicLocations"):format(mechanicId), "warning")
goto continue
end
for stashIndex, stash in ipairs(mechanicConfig.stashes) do
if stash.type == "self-service" then
debugPrint(("Skipping self-service stash for '%s' (index: %d)"):format(mechanicId, stashIndex), "debug")
goto stash_continue
end
if not stash.coords or not stash.size then
debugPrint(("Invalid stash data for '%s' (index: %d) - missing coords or size"):format(mechanicId, stashIndex), "warning")
goto stash_continue
end
local stashId = mechanicId .. "_" .. stash.name:gsub(" ", "_"):lower() .. "_" .. stashIndex
if stash.usePed then
local ped = createPedForTarget(stash.pedModel or "s_m_m_lathandy_01", stash.coords.xyz)
stashPeds[#stashPeds + 1] = ped
-- If vec4, set heading
if stash.coords.w then
SetEntityHeading(ped, stash.coords.w or 0)
end
if Config.Target == "qb-target" then
exports["qb-target"]:AddTargetEntity(ped, {
options = {
{
label = "Access Stash",
icon = "fas fa-box",
action = function()
Framework.Client.OpenInventoryStash(stashId, stash.name)
end,
},
},
distance = 2.5,
})
elseif Config.Target == "ox_target" then
exports.ox_target:addLocalEntity(ped, {
{
name = "access_stash_" .. stashId,
label = "Access Stash",
icon = "fas fa-box",
onSelect = function()
Framework.Client.OpenInventoryStash(stashId, stash.name)
end,
},
})
end
else
local zoneData = {
coords = stash.coords,
size = vector3(stash.size, stash.size, 2.0),
rotation = stash.coords.w or 0,
debug = Config.Debug,
onEnter = function()
Framework.Client.ShowTextUI("Press [E] to access " .. stash.name)
end,
onExit = function()
Framework.Client.HideTextUI()
end,
inside = function()
if IsControlJustReleased(0, 38) then
Framework.Client.OpenInventoryStash(stashId, stash.name)
end
end
}
local zone = lib.zones.box(zoneData)
stashZones[#stashZones + 1] = zone
local point = drawCustomMarker(stash.coords, stash.marker, 10.0, mechanicId, nil, stash.name)
stashPoints[#stashPoints + 1] = point
end
::stash_continue::
end
::continue::
end
end
-- Remove peds on resource stop/restart
AddEventHandler("onResourceStop", function(resource)
if resource ~= GetCurrentResourceName() then return end
if shopPeds then
for _, ped in pairs(shopPeds) do
if DoesEntityExist(ped) then
DeleteEntity(ped)
end
end
shopPeds = {}
end
if stashPeds then
for _, ped in pairs(stashPeds) do
if DoesEntityExist(ped) then
DeleteEntity(ped)
end
end
stashPeds = {}
end
end)