639 lines
19 KiB
Lua
639 lines
19 KiB
Lua
-- client/shop.lua
|
|
print("^2[turfwar]^7 client/shop.lua loaded (gang+police shop NUI + markers + blips + shop vehicle ownership + debug)")
|
|
|
|
local currentGang = 0
|
|
local shopOpen = false
|
|
local lastOpenAttempt = 0
|
|
|
|
-- Debug toggles
|
|
local DEBUG_MARKERS = false -- /tw_shopdebug
|
|
|
|
-- Shop blips (map icons)
|
|
local ShopBlips = {}
|
|
|
|
-- Shop vehicle (1 per player) + blip
|
|
local myShopVeh = 0
|
|
local myShopVehBlip = 0
|
|
|
|
-- Server sync throttle
|
|
local lastSyncedGang = -1
|
|
local lastSyncAt = 0
|
|
|
|
-- =========================
|
|
-- Helpers
|
|
-- =========================
|
|
local function Notify(msg)
|
|
BeginTextCommandThefeedPost("STRING")
|
|
AddTextComponentSubstringPlayerName(msg)
|
|
EndTextCommandThefeedPostTicker(false, false)
|
|
end
|
|
|
|
local function v3(pos)
|
|
if not pos then return vector3(0.0, 0.0, 0.0) end
|
|
return vector3(pos.x + 0.0, pos.y + 0.0, pos.z + 0.0)
|
|
end
|
|
|
|
local function dist(a, b)
|
|
local dx = (a.x + 0.0) - (b.x + 0.0)
|
|
local dy = (a.y + 0.0) - (b.y + 0.0)
|
|
local dz = (a.z + 0.0) - (b.z + 0.0)
|
|
return math.sqrt(dx * dx + dy * dy + dz * dz)
|
|
end
|
|
|
|
local function iterList(t)
|
|
if type(t) ~= "table" then
|
|
return function() return nil end
|
|
end
|
|
|
|
local n = #t
|
|
if n > 0 then
|
|
local i = 0
|
|
return function()
|
|
i = i + 1
|
|
if i <= n then return i, t[i] end
|
|
end
|
|
end
|
|
|
|
return pairs(t)
|
|
end
|
|
|
|
local function getGangRGB(gangId)
|
|
local fallback = { r = 10, g = 10, b = 10 }
|
|
|
|
local gangs = (Config and Config.GANGS) or nil
|
|
if type(gangs) ~= "table" then return fallback end
|
|
|
|
local g = gangs[tonumber(gangId) or 0]
|
|
if type(g) ~= "table" then return fallback end
|
|
|
|
local rgb = g.rgb
|
|
if type(rgb) ~= "table" then return fallback end
|
|
|
|
local r = tonumber(rgb.r or rgb[1])
|
|
local gg = tonumber(rgb.g or rgb[2])
|
|
local b = tonumber(rgb.b or rgb[3])
|
|
|
|
if not r or not gg or not b then return fallback end
|
|
return { r = r, g = gg, b = b }
|
|
end
|
|
|
|
local function drawMarkerAt(posIn)
|
|
local shops = Config.Shops or {}
|
|
local m = shops.Marker or {}
|
|
|
|
local pos = v3(posIn)
|
|
local t = tonumber(m.type) or 1
|
|
|
|
local sc = m.scale
|
|
if sc == nil then
|
|
sc = vector3(1.2, 1.2, 0.9)
|
|
elseif type(sc) == "table" and sc.x == nil then
|
|
sc = vector3(
|
|
tonumber(sc[1]) or 1.2,
|
|
tonumber(sc[2]) or 1.2,
|
|
tonumber(sc[3]) or 0.9
|
|
)
|
|
end
|
|
|
|
local rgba = m.rgba or { 80, 160, 255, 140 }
|
|
|
|
local z = pos.z
|
|
local found, gz
|
|
for _, off in ipairs({ 300.0, 100.0, 30.0, 10.0 }) do
|
|
found, gz = GetGroundZFor_3dCoord(pos.x, pos.y, pos.z + off, true)
|
|
if found then
|
|
z = gz + 0.05
|
|
break
|
|
end
|
|
end
|
|
|
|
DrawMarker(
|
|
t,
|
|
pos.x, pos.y, z,
|
|
0.0, 0.0, 0.0,
|
|
0.0, 0.0, 0.0,
|
|
sc.x, sc.y, sc.z,
|
|
rgba[1] or 80,
|
|
rgba[2] or 160,
|
|
rgba[3] or 255,
|
|
rgba[4] or 140,
|
|
false, true, 2, false, nil, nil, false
|
|
)
|
|
end
|
|
|
|
-- =========================================================
|
|
-- NEW: Server->Client gang sync responder
|
|
-- =========================================================
|
|
RegisterNetEvent("turfwar:shop:syncGangRequest", function(nonce)
|
|
print(("[turfwar:shop] syncGangRequest nonce=%s -> reply gang=%d"):format(tostring(nonce), tonumber(currentGang) or 0))
|
|
TriggerServerEvent("turfwar:shop:syncGangResponse", nonce, currentGang or 0)
|
|
end)
|
|
|
|
-- =========================
|
|
-- Vehicle ownership (1 per player) + blip + gang colour
|
|
-- =========================
|
|
local function clearMyShopVehicle()
|
|
if myShopVehBlip ~= 0 and DoesBlipExist(myShopVehBlip) then
|
|
RemoveBlip(myShopVehBlip)
|
|
end
|
|
myShopVehBlip = 0
|
|
|
|
if myShopVeh ~= 0 and DoesEntityExist(myShopVeh) then
|
|
SetEntityAsMissionEntity(myShopVeh, true, true)
|
|
DeleteEntity(myShopVeh)
|
|
end
|
|
myShopVeh = 0
|
|
end
|
|
|
|
local function createMyShopVehBlip(veh)
|
|
if myShopVehBlip ~= 0 and DoesBlipExist(myShopVehBlip) then
|
|
RemoveBlip(myShopVehBlip)
|
|
end
|
|
|
|
local blip = AddBlipForEntity(veh)
|
|
SetBlipSprite(blip, 225)
|
|
SetBlipScale(blip, 0.85)
|
|
SetBlipAsShortRange(blip, false)
|
|
|
|
local g = Config and Config.GANGS and Config.GANGS[currentGang]
|
|
if g and g.blipColor then
|
|
SetBlipColour(blip, g.blipColor)
|
|
end
|
|
|
|
BeginTextCommandSetBlipName("STRING")
|
|
AddTextComponentString(currentGang == 3 and "Police Vehicle" or "My Vehicle")
|
|
EndTextCommandSetBlipName(blip)
|
|
|
|
myShopVehBlip = blip
|
|
end
|
|
|
|
local function applyGangColorsToVehicle(veh, gangId)
|
|
local rgb = getGangRGB(gangId)
|
|
SetVehicleModKit(veh, 0)
|
|
SetVehicleCustomPrimaryColour(veh, rgb.r, rgb.g, rgb.b)
|
|
SetVehicleCustomSecondaryColour(veh, rgb.r, rgb.g, rgb.b)
|
|
SetVehicleDirtLevel(veh, 0.0)
|
|
end
|
|
|
|
local function resolveVehicleModel(modelIn)
|
|
local model = tostring(modelIn or "")
|
|
if model ~= "" then return model end
|
|
|
|
if Config and Config.Shops and Config.Shops.GangVehicleModels and Config.Shops.GangVehicleModels[currentGang] then
|
|
return tostring(Config.Shops.GangVehicleModels[currentGang])
|
|
end
|
|
|
|
if Config and Config.Vehicles and Config.Vehicles.gangModels and Config.Vehicles.gangModels[currentGang] then
|
|
return tostring(Config.Vehicles.gangModels[currentGang])
|
|
end
|
|
|
|
return "sultan" -- fallback only
|
|
end
|
|
|
|
local function findBestVehicleSpawn()
|
|
local byGang = Config and Config.Shops and Config.Shops.LocationsByGang
|
|
local g = byGang and byGang[currentGang]
|
|
local pads = g and g.vehicles
|
|
|
|
local ped = PlayerPedId()
|
|
local p = GetEntityCoords(ped)
|
|
|
|
if type(pads) == "table" then
|
|
local best, bestD = nil, 999999.0
|
|
for _, v in pairs(pads) do
|
|
local pos = v3(v)
|
|
local d = dist(pos, p)
|
|
if d < bestD then
|
|
bestD = d
|
|
best = v
|
|
end
|
|
end
|
|
|
|
if best then
|
|
local pos = v3(best)
|
|
local heading = tonumber(best.w) or tonumber(best.h) or 0.0
|
|
return pos, heading
|
|
end
|
|
end
|
|
|
|
local fwd = GetEntityForwardVector(ped)
|
|
local pos = vector3(p.x + fwd.x * 6.0, p.y + fwd.y * 6.0, p.z)
|
|
return pos, GetEntityHeading(ped)
|
|
end
|
|
|
|
local function spawnVehicleClient(modelName)
|
|
clearMyShopVehicle()
|
|
|
|
local model = resolveVehicleModel(modelName)
|
|
local hash = GetHashKey(model)
|
|
|
|
if not IsModelInCdimage(hash) or not IsModelAVehicle(hash) then
|
|
Notify(("Invalid vehicle model: %s"):format(model))
|
|
return
|
|
end
|
|
|
|
RequestModel(hash)
|
|
local deadline = GetGameTimer() + 7000
|
|
while not HasModelLoaded(hash) do
|
|
Wait(0)
|
|
if GetGameTimer() > deadline then
|
|
Notify(("Failed to load model: %s"):format(model))
|
|
return
|
|
end
|
|
end
|
|
|
|
local pos, heading = findBestVehicleSpawn()
|
|
|
|
RequestCollisionAtCoord(pos.x, pos.y, pos.z)
|
|
for _ = 1, 20 do
|
|
local found, gz = GetGroundZFor_3dCoord(pos.x, pos.y, pos.z + 50.0, true)
|
|
if found then
|
|
pos = vector3(pos.x, pos.y, gz + 0.5)
|
|
break
|
|
end
|
|
Wait(0)
|
|
end
|
|
|
|
local veh = CreateVehicle(hash, pos.x, pos.y, pos.z, heading, true, false)
|
|
if veh == 0 then
|
|
Notify("Vehicle spawn failed.")
|
|
SetModelAsNoLongerNeeded(hash)
|
|
return
|
|
end
|
|
|
|
SetEntityAsMissionEntity(veh, true, true)
|
|
SetVehicleOnGroundProperly(veh)
|
|
SetVehicleEngineOn(veh, true, true, false)
|
|
SetVehRadioStation(veh, "OFF")
|
|
|
|
if tonumber(currentGang) == 3 then
|
|
local a = (Config and Config.Shops and Config.Shops.PoliceVehicleAppearance) or {}
|
|
if a.primary ~= nil and a.secondary ~= nil then
|
|
SetVehicleColours(veh, tonumber(a.primary) or 0, tonumber(a.secondary) or 0)
|
|
end
|
|
if a.pearlescent ~= nil or a.wheel ~= nil then
|
|
SetVehicleExtraColours(veh, tonumber(a.pearlescent) or 0, tonumber(a.wheel) or 0)
|
|
end
|
|
if a.livery ~= nil then
|
|
local liv = tonumber(a.livery)
|
|
if liv and liv >= 0 then SetVehicleLivery(veh, liv) end
|
|
end
|
|
if a.clean then
|
|
SetVehicleDirtLevel(veh, 0.0)
|
|
WashDecalsFromVehicle(veh, 1.0)
|
|
end
|
|
else
|
|
applyGangColorsToVehicle(veh, currentGang)
|
|
end
|
|
|
|
myShopVeh = veh
|
|
createMyShopVehBlip(veh)
|
|
TaskWarpPedIntoVehicle(PlayerPedId(), veh, -1)
|
|
|
|
SetModelAsNoLongerNeeded(hash)
|
|
Notify(("Spawned: %s"):format(model))
|
|
end
|
|
|
|
RegisterNetEvent("turfwar:shop:grantVehicle", function(model)
|
|
print(("[turfwar:shop] grantVehicle RECEIVED model=%s gang=%d"):format(tostring(model), tonumber(currentGang) or -1))
|
|
spawnVehicleClient(model)
|
|
end)
|
|
|
|
AddEventHandler("onResourceStop", function(res)
|
|
if res ~= GetCurrentResourceName() then return end
|
|
clearMyShopVehicle()
|
|
end)
|
|
|
|
-- =========================
|
|
-- Payload selector (Police vs Gang)
|
|
-- =========================
|
|
local function buildShopPayload()
|
|
local s = Config.Shops or {}
|
|
if currentGang == 3 then
|
|
return { weapons = s.PoliceWeapons or {}, ammo = s.PoliceAmmo or {}, vehicles = s.PoliceVehicles or {}, gangs = Config.GANGS or {} }
|
|
end
|
|
return { weapons = s.Weapons or {}, ammo = s.Ammo or {}, vehicles = s.Vehicles or {}, gangs = Config.GANGS or {} }
|
|
end
|
|
|
|
local function getGangShopLocations(gangId)
|
|
local s = Config.Shops or {}
|
|
local byGang = s.LocationsByGang or {}
|
|
local g = byGang[tonumber(gangId) or 0]
|
|
if type(g) ~= "table" then return nil end
|
|
return { shop = g.shop or {}, vehicles = g.vehicles or {} }
|
|
end
|
|
|
|
-- =========================
|
|
-- NUI Open/Close
|
|
-- =========================
|
|
local function openShop(tab, allowedTabs)
|
|
if shopOpen then return end
|
|
shopOpen = true
|
|
|
|
SetNuiFocus(true, true)
|
|
SetNuiFocusKeepInput(false)
|
|
|
|
SendNUIMessage({
|
|
type = "shop:open",
|
|
tab = tab or "weapons",
|
|
gangId = currentGang,
|
|
gangRGB = getGangRGB(currentGang),
|
|
payload = buildShopPayload(),
|
|
allowedTabs = allowedTabs or { "weapons", "ammo", "vehicles" },
|
|
})
|
|
|
|
TriggerServerEvent("turfwar:shop:requestBalance")
|
|
end
|
|
|
|
local function closeShop()
|
|
if not shopOpen then return end
|
|
shopOpen = false
|
|
SetNuiFocus(false, false)
|
|
SendNUIMessage({ type = "shop:close" })
|
|
end
|
|
|
|
-- =========================
|
|
-- Shop Blips
|
|
-- =========================
|
|
local function clearShopBlips()
|
|
for _, b in ipairs(ShopBlips) do
|
|
if DoesBlipExist(b) then RemoveBlip(b) end
|
|
end
|
|
ShopBlips = {}
|
|
end
|
|
|
|
local function addShopBlip(posIn, label)
|
|
local pos = v3(posIn)
|
|
local blip = AddBlipForCoord(pos.x, pos.y, pos.z)
|
|
|
|
SetBlipSprite(blip, 374)
|
|
SetBlipScale(blip, 0.75)
|
|
SetBlipAsShortRange(blip, true)
|
|
|
|
local g = Config.GANGS and Config.GANGS[currentGang]
|
|
SetBlipColour(blip, (g and g.blipColor) or 0)
|
|
|
|
BeginTextCommandSetBlipName("STRING")
|
|
AddTextComponentString(label)
|
|
EndTextCommandSetBlipName(blip)
|
|
|
|
ShopBlips[#ShopBlips + 1] = blip
|
|
end
|
|
|
|
local function buildShopBlips()
|
|
clearShopBlips()
|
|
|
|
if currentGang == 0 then
|
|
return
|
|
end
|
|
|
|
local gLocs = getGangShopLocations(currentGang)
|
|
if not gLocs then
|
|
print(("^1[turfwar]^7 No shop locations for gangId=%d. Check Config.Shops.LocationsByGang[%d] in shops.lua"):format(currentGang, currentGang))
|
|
return
|
|
end
|
|
|
|
local isPolice = (currentGang == 3)
|
|
|
|
for _, pos in iterList(gLocs.shop) do
|
|
addShopBlip(pos, isPolice and "Police Armory" or "Gang Shop")
|
|
end
|
|
|
|
for _, pos in iterList(gLocs.vehicles) do
|
|
addShopBlip(pos, isPolice and "Police Vehicles" or "Gang Vehicles")
|
|
end
|
|
end
|
|
|
|
-- =========================
|
|
-- Commands
|
|
-- =========================
|
|
RegisterCommand("tw_mygang", function()
|
|
Notify(("currentGang=%d"):format(currentGang or -1))
|
|
print(("^3[turfwar]^7 tw_mygang -> currentGang=%d"):format(currentGang or -1))
|
|
end, false)
|
|
|
|
RegisterCommand("tw_shopdebug", function()
|
|
DEBUG_MARKERS = not DEBUG_MARKERS
|
|
Notify(("Shop marker debug: %s"):format(DEBUG_MARKERS and "~g~ON~s~" or "~r~OFF~s~"))
|
|
print(("^3[turfwar]^7 DEBUG_MARKERS=%s"):format(tostring(DEBUG_MARKERS)))
|
|
end, false)
|
|
|
|
-- =========================
|
|
-- Server sync + gang setter
|
|
-- =========================
|
|
local function SyncGangToServer()
|
|
local now = GetGameTimer()
|
|
if currentGang == lastSyncedGang and (now - lastSyncAt) < 1000 then return end
|
|
lastSyncedGang = currentGang
|
|
lastSyncAt = now
|
|
TriggerServerEvent("turfwar:setFaction", currentGang)
|
|
end
|
|
|
|
local function setGang(newGang)
|
|
newGang = tonumber(newGang) or 0
|
|
if newGang == currentGang then
|
|
SyncGangToServer()
|
|
return
|
|
end
|
|
|
|
clearMyShopVehicle()
|
|
|
|
currentGang = newGang
|
|
SyncGangToServer()
|
|
|
|
if shopOpen then
|
|
SendNUIMessage({ type = "shop:gang", gangId = currentGang, gangRGB = getGangRGB(currentGang) })
|
|
TriggerServerEvent("turfwar:shop:requestBalance")
|
|
end
|
|
|
|
buildShopBlips()
|
|
end
|
|
|
|
-- =========================
|
|
-- Events from your gang system
|
|
-- =========================
|
|
RegisterNetEvent("turfwar:setMyGang", function(gangId)
|
|
setGang(gangId)
|
|
end)
|
|
|
|
RegisterNetEvent("turfwar:setFaction", function(gangId)
|
|
print(("^3[turfwar]^7 shop.lua got turfwar:setFaction -> %d"):format(tonumber(gangId) or 0))
|
|
setGang(gangId)
|
|
end)
|
|
|
|
RegisterNetEvent("turfwar:gangUpdate", function(gangId)
|
|
print(("^3[turfwar]^7 shop.lua got turfwar:gangUpdate -> %d"):format(tonumber(gangId) or 0))
|
|
setGang(gangId)
|
|
end)
|
|
|
|
-- =========================
|
|
-- Shop UI info events
|
|
-- =========================
|
|
RegisterNetEvent("turfwar:shop:balance", function(gangId, balance)
|
|
SendNUIMessage({
|
|
type = "shop:balance",
|
|
gangId = tonumber(gangId) or 0,
|
|
balance = tonumber(balance) or 0
|
|
})
|
|
end)
|
|
|
|
RegisterNetEvent("turfwar:shop:result", function(ok, message, newBalance)
|
|
if message and message ~= "" then Notify(message) end
|
|
if newBalance ~= nil then
|
|
SendNUIMessage({
|
|
type = "shop:balance",
|
|
gangId = currentGang,
|
|
balance = tonumber(newBalance) or 0
|
|
})
|
|
end
|
|
end)
|
|
|
|
RegisterNetEvent("turfwar:shop:grantWeapon", function(weaponName, ammo)
|
|
print(("[turfwar:shop] grantWeapon RECEIVED weapon=%s ammo=%s gang=%d"):format(
|
|
tostring(weaponName), tostring(ammo), tonumber(currentGang) or -1
|
|
))
|
|
|
|
local ped = PlayerPedId()
|
|
local wHash = GetHashKey(weaponName)
|
|
GiveWeaponToPed(ped, wHash, tonumber(ammo) or 0, false, true)
|
|
|
|
-- verify after a short delay (detects scripts stripping weapons)
|
|
CreateThread(function()
|
|
Wait(250)
|
|
local hasIt = HasPedGotWeapon(ped, wHash, false)
|
|
print(("[turfwar:shop] grantWeapon CHECK weapon=%s has=%s"):format(tostring(weaponName), tostring(hasIt)))
|
|
end)
|
|
end)
|
|
|
|
RegisterNetEvent("turfwar:shop:grantAmmo", function(weaponName, amount)
|
|
print(("[turfwar:shop] grantAmmo RECEIVED for=%s amount=%s gang=%d"):format(
|
|
tostring(weaponName), tostring(amount), tonumber(currentGang) or -1
|
|
))
|
|
|
|
local ped = PlayerPedId()
|
|
local wHash = GetHashKey(weaponName)
|
|
AddAmmoToPed(ped, wHash, tonumber(amount) or 0)
|
|
end)
|
|
|
|
RegisterNetEvent("turfwar:shop:debugOpen", function(tab)
|
|
openShop(tab or "weapons", { "weapons", "ammo", "vehicles" })
|
|
end)
|
|
|
|
-- =========================
|
|
-- NUI callbacks
|
|
-- =========================
|
|
RegisterNUICallback("shop:close", function(_, cb)
|
|
closeShop()
|
|
cb({ ok = true })
|
|
end)
|
|
|
|
RegisterNUICallback("shop:buyWeapon", function(data, cb)
|
|
TriggerServerEvent("turfwar:shop:buyWeapon", tostring(data.itemId or ""))
|
|
cb({ ok = true })
|
|
end)
|
|
|
|
RegisterNUICallback("shop:buyAmmo", function(data, cb)
|
|
TriggerServerEvent("turfwar:shop:buyAmmo", tostring(data.itemId or ""))
|
|
cb({ ok = true })
|
|
end)
|
|
|
|
RegisterNUICallback("shop:buyVehicle", function(data, cb)
|
|
TriggerServerEvent("turfwar:shop:buyVehicle", tostring(data.itemId or ""))
|
|
cb({ ok = true })
|
|
end)
|
|
|
|
-- =========================
|
|
-- Faction request (on join/spawn)
|
|
-- =========================
|
|
local function RequestFaction()
|
|
TriggerServerEvent("turfwar:requestFaction")
|
|
end
|
|
|
|
CreateThread(function()
|
|
Wait(1500)
|
|
RequestFaction()
|
|
end)
|
|
|
|
AddEventHandler("playerSpawned", function()
|
|
Wait(1500)
|
|
RequestFaction()
|
|
end)
|
|
|
|
-- =========================
|
|
-- Marker + Interact loop
|
|
-- =========================
|
|
CreateThread(function()
|
|
Wait(1000)
|
|
print("^3[turfwar]^7 shop.lua marker loop running")
|
|
|
|
buildShopBlips()
|
|
|
|
while true do
|
|
Wait(0)
|
|
|
|
local ped = PlayerPedId()
|
|
local p = GetEntityCoords(ped)
|
|
|
|
local shops = Config.Shops or {}
|
|
local md = tonumber(shops.MarkerDist) or 25.0
|
|
local id = tonumber(shops.InteractDist) or 2.0
|
|
local key = tonumber(shops.InteractKey) or 38
|
|
|
|
if DEBUG_MARKERS then
|
|
DrawMarker(1, p.x, p.y, p.z - 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
|
|
0.5, 0.5, 0.25, 255, 255, 255, 180, false, true, 2, false, nil, nil, false)
|
|
end
|
|
|
|
if currentGang ~= 0 then
|
|
local gLocs = getGangShopLocations(currentGang)
|
|
if gLocs then
|
|
local isPolice = (currentGang == 3)
|
|
|
|
local lists = {
|
|
{ tab = "weapons", locs = gLocs.shop, allowed = { "weapons", "ammo" } },
|
|
{ tab = "vehicles", locs = gLocs.vehicles, allowed = { "vehicles" } },
|
|
}
|
|
|
|
local canOpen = false
|
|
local openTab = nil
|
|
local openAllowed = nil
|
|
|
|
for _, entry in ipairs(lists) do
|
|
for _, posAny in iterList(entry.locs) do
|
|
local d = dist(v3(posAny), p)
|
|
if d <= md then
|
|
drawMarkerAt(posAny)
|
|
if d <= id then
|
|
canOpen = true
|
|
openTab = entry.tab
|
|
openAllowed = entry.allowed
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
if canOpen and not shopOpen then
|
|
BeginTextCommandDisplayHelp("STRING")
|
|
AddTextComponentSubstringPlayerName(
|
|
isPolice and "Press ~INPUT_CONTEXT~ to open Police Armory" or
|
|
"Press ~INPUT_CONTEXT~ to open Gang Shop"
|
|
)
|
|
EndTextCommandDisplayHelp(0, false, true, 0)
|
|
|
|
if IsControlJustPressed(0, key) then
|
|
local now = GetGameTimer()
|
|
if now - lastOpenAttempt > 400 then
|
|
lastOpenAttempt = now
|
|
openShop(openTab or "weapons", openAllowed)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
if shopOpen and IsControlJustPressed(0, 322) then
|
|
closeShop()
|
|
end
|
|
end
|
|
end)
|