-- 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)