246 lines
8.0 KiB
Lua
246 lines
8.0 KiB
Lua
-- server/gang_shops.lua
|
|
print("^2[turfwar]^7 gang_shops.lua loaded (server)")
|
|
|
|
Config = Config or {}
|
|
Config.Shops = Config.Shops or {}
|
|
|
|
-- IMPORTANT:
|
|
-- This assumes you already have:
|
|
-- - player gang stored server-side somewhere, OR a callback/event to fetch it.
|
|
--
|
|
-- Below uses a simple server cache:
|
|
local playerGang = {} -- [src] = gangId
|
|
|
|
-- You likely already broadcast this elsewhere.
|
|
-- Hook into your existing gang set event if you have one.
|
|
RegisterNetEvent("turfwar:myGang:set", function(gangId)
|
|
local src = source
|
|
playerGang[src] = tonumber(gangId) or 0
|
|
end)
|
|
|
|
AddEventHandler("playerDropped", function()
|
|
local src = source
|
|
playerGang[src] = nil
|
|
end)
|
|
|
|
local function getGangId(src)
|
|
return tonumber(playerGang[src]) or 0
|
|
end
|
|
|
|
-- =========================
|
|
-- DB helpers (gang bank)
|
|
-- =========================
|
|
local function dbFetchBalance(gangId, cb)
|
|
exports.oxmysql:query("SELECT balance FROM turfwar_gang_accounts WHERE gang_id = ? LIMIT 1", { gangId }, function(rows)
|
|
local bal = 0
|
|
if rows and rows[1] and rows[1].balance then bal = tonumber(rows[1].balance) or 0 end
|
|
cb(bal)
|
|
end)
|
|
end
|
|
|
|
local function dbEnsureRow(gangId, cb)
|
|
exports.oxmysql:query("INSERT IGNORE INTO turfwar_gang_accounts (gang_id, balance) VALUES (?, 0)", { gangId }, function()
|
|
cb()
|
|
end)
|
|
end
|
|
|
|
local function dbDeduct(gangId, amount, cb)
|
|
amount = tonumber(amount) or 0
|
|
if amount <= 0 then cb(false, "bad_amount") return end
|
|
|
|
dbEnsureRow(gangId, function()
|
|
exports.oxmysql:query("UPDATE turfwar_gang_accounts SET balance = balance - ? WHERE gang_id = ? AND balance >= ?", {
|
|
amount, gangId, amount
|
|
}, function(result)
|
|
-- oxmysql UPDATE result varies by version; handle common cases:
|
|
local changed = 0
|
|
if type(result) == "table" and result.affectedRows then changed = result.affectedRows end
|
|
if type(result) == "number" then changed = result end
|
|
|
|
cb(changed and changed > 0, changed and changed > 0 and nil or "insufficient")
|
|
end)
|
|
end)
|
|
end
|
|
|
|
-- =========================
|
|
-- Lookup helpers
|
|
-- =========================
|
|
local function findWeaponItem(itemId)
|
|
if not Config.Shops or not Config.Shops.WeaponList then return nil end
|
|
for _, it in ipairs(Config.Shops.WeaponList) do
|
|
if it.id == itemId then return it end
|
|
end
|
|
return nil
|
|
end
|
|
|
|
local function findAmmoItem(itemId)
|
|
if not Config.Shops or not Config.Shops.AmmoList then return nil end
|
|
for _, it in ipairs(Config.Shops.AmmoList) do
|
|
if it.id == itemId then return it end
|
|
end
|
|
return nil
|
|
end
|
|
|
|
local function findVehicleItem(itemId)
|
|
if not Config.Shops or not Config.Shops.VehicleList then return nil end
|
|
for _, it in ipairs(Config.Shops.VehicleList) do
|
|
if it.id == itemId then return it end
|
|
end
|
|
return nil
|
|
end
|
|
|
|
-- =========================
|
|
-- Purchase: weapons
|
|
-- =========================
|
|
RegisterNetEvent("turfwar:shop:buyWeapon", function(itemId)
|
|
local src = source
|
|
local gangId = getGangId(src)
|
|
|
|
if not (Config.Shops.AllowedGang and Config.Shops.AllowedGang(gangId)) then
|
|
TriggerClientEvent("turfwar:shop:notify", src, "~r~You can't use the gang shop.")
|
|
return
|
|
end
|
|
|
|
local item = findWeaponItem(itemId)
|
|
if not item then
|
|
TriggerClientEvent("turfwar:shop:notify", src, "~r~Invalid item.")
|
|
return
|
|
end
|
|
|
|
local price = tonumber(item.price) or 0
|
|
if price < 0 then
|
|
TriggerClientEvent("turfwar:shop:notify", src, "~r~Bad price config.")
|
|
return
|
|
end
|
|
|
|
dbDeduct(gangId, price, function(ok, reason)
|
|
if not ok then
|
|
TriggerClientEvent("turfwar:shop:notify", src, "~r~Not enough gang cash.")
|
|
return
|
|
end
|
|
|
|
-- Grant on client (server-authoritative purchase)
|
|
TriggerClientEvent("turfwar:shop:grantWeapon", src, item, gangId)
|
|
TriggerClientEvent("turfwar:shop:notify", src, ("~g~Purchased: ~s~%s"):format(item.label or item.id))
|
|
TriggerClientEvent("turfwar:gangbank:requestRefresh", src) -- optional hook
|
|
end)
|
|
end)
|
|
|
|
RegisterNetEvent("turfwar:shop:buyAmmo", function(itemId)
|
|
local src = source
|
|
local gangId = getGangId(src)
|
|
|
|
if not (Config.Shops.AllowedGang and Config.Shops.AllowedGang(gangId)) then
|
|
TriggerClientEvent("turfwar:shop:notify", src, "~r~You can't use the gang shop.")
|
|
return
|
|
end
|
|
|
|
local item = findAmmoItem(itemId)
|
|
if not item then
|
|
TriggerClientEvent("turfwar:shop:notify", src, "~r~Invalid ammo item.")
|
|
return
|
|
end
|
|
|
|
local price = tonumber(item.price) or 0
|
|
if price <= 0 then
|
|
TriggerClientEvent("turfwar:shop:notify", src, "~r~Bad price config.")
|
|
return
|
|
end
|
|
|
|
dbDeduct(gangId, price, function(ok)
|
|
if not ok then
|
|
TriggerClientEvent("turfwar:shop:notify", src, "~r~Not enough gang cash.")
|
|
return
|
|
end
|
|
|
|
TriggerClientEvent("turfwar:shop:grantAmmo", src, item)
|
|
TriggerClientEvent("turfwar:shop:notify", src, ("~g~Purchased: ~s~%s"):format(item.label or item.id))
|
|
TriggerClientEvent("turfwar:gangbank:requestRefresh", src)
|
|
end)
|
|
end)
|
|
|
|
-- =========================
|
|
-- Purchase: vehicles
|
|
-- =========================
|
|
RegisterNetEvent("turfwar:shop:buyVehicle", function(itemId)
|
|
local src = source
|
|
local gangId = getGangId(src)
|
|
|
|
if not (Config.Shops.AllowedGang and Config.Shops.AllowedGang(gangId)) then
|
|
TriggerClientEvent("turfwar:shop:notify", src, "~r~You can't use the gang shop.")
|
|
return
|
|
end
|
|
|
|
local item = findVehicleItem(itemId)
|
|
if not item then
|
|
TriggerClientEvent("turfwar:shop:notify", src, "~r~Invalid vehicle.")
|
|
return
|
|
end
|
|
|
|
local price = tonumber(item.price)
|
|
if price == nil then price = 0 end
|
|
|
|
-- Allow FREE vehicles (price = 0). Only reject negative.
|
|
if price < 0 then
|
|
TriggerClientEvent("turfwar:shop:notify", src, "~r~Bad price config.")
|
|
return
|
|
end
|
|
|
|
local function afterPaid()
|
|
-- Use your existing spawn-pad system
|
|
if not VehicleSpawner or not VehicleSpawner.SpawnModelFor then
|
|
TriggerClientEvent("turfwar:shop:notify", src, "~r~VehicleSpawner not available.")
|
|
return
|
|
end
|
|
|
|
-- Support special model alias for "gang default"
|
|
local model = item.model
|
|
if model == "__GANG_DEFAULT__" then
|
|
model = (Config.Vehicles and Config.Vehicles.gangModels and Config.Vehicles.gangModels[gangId])
|
|
end
|
|
|
|
if type(model) ~= "string" or model == "" then
|
|
TriggerClientEvent("turfwar:shop:notify", src, "~r~No vehicle configured for your gang.")
|
|
return
|
|
end
|
|
|
|
local ok2, reason = VehicleSpawner.SpawnModelFor(src, model, { platePrefix = "G" })
|
|
if not ok2 then
|
|
TriggerClientEvent("turfwar:shop:notify", src, "~r~Vehicle spawn failed.")
|
|
return
|
|
end
|
|
|
|
TriggerClientEvent("turfwar:shop:notify", src, ("~g~Purchased: ~s~%s"):format(item.label or item.id))
|
|
TriggerClientEvent("turfwar:gangbank:requestRefresh", src)
|
|
end
|
|
|
|
-- If free, don't touch the gang bank
|
|
if price == 0 then
|
|
afterPaid()
|
|
return
|
|
end
|
|
|
|
-- Deduct first (server authority)
|
|
dbDeduct(gangId, price, function(ok)
|
|
if not ok then
|
|
TriggerClientEvent("turfwar:shop:notify", src, "~r~Not enough gang cash.")
|
|
return
|
|
end
|
|
afterPaid()
|
|
end)
|
|
end)
|
|
|
|
|
|
-- Optional: allow client to query gang balance (for UI)
|
|
RegisterNetEvent("turfwar:shop:getBalance", function()
|
|
local src = source
|
|
local gangId = getGangId(src)
|
|
if gangId <= 0 then
|
|
TriggerClientEvent("turfwar:shop:balance", src, 0)
|
|
return
|
|
end
|
|
dbFetchBalance(gangId, function(bal)
|
|
TriggerClientEvent("turfwar:shop:balance", src, bal)
|
|
end)
|
|
end)
|