|
| 1 | +local Framework, FW = nil, nil |
| 2 | + |
| 3 | +local function resolveFramework() |
| 4 | + local choice = Config.Framework |
| 5 | + if choice == 'esx' or (choice == 'auto' and GetResourceState('es_extended') == 'started') then |
| 6 | + Framework = 'esx' |
| 7 | + FW = exports['es_extended']:getSharedObject() |
| 8 | + elseif choice == 'qb' or (choice == 'auto' and GetResourceState('qb-core') == 'started') then |
| 9 | + Framework = 'qb' |
| 10 | + FW = exports['qb-core']:GetCoreObject() |
| 11 | + else |
| 12 | + Framework = 'standalone' |
| 13 | + end |
| 14 | +end |
| 15 | + |
| 16 | +local function notify(msg, kind) |
| 17 | + if Framework == 'esx' then |
| 18 | + FW.ShowNotification(msg) |
| 19 | + elseif Framework == 'qb' then |
| 20 | + FW.Functions.Notify(msg, kind or 'primary') |
| 21 | + else |
| 22 | + BeginTextCommandThefeedPost('STRING') |
| 23 | + AddTextComponentSubstringPlayerName(msg) |
| 24 | + EndTextCommandThefeedPostTicker(false, true) |
| 25 | + end |
| 26 | +end |
| 27 | + |
| 28 | +-- Returns the nearest pedestrian (non-player, alive) within Config.SellDistance. |
| 29 | +local function getNearestPed() |
| 30 | + local playerPed = PlayerPedId() |
| 31 | + local coords = GetEntityCoords(playerPed) |
| 32 | + local handle, ped = FindFirstPed() |
| 33 | + local success, nearest, nearestDist = true, nil, Config.SellDistance |
| 34 | + |
| 35 | + repeat |
| 36 | + if DoesEntityExist(ped) |
| 37 | + and not IsPedAPlayer(ped) |
| 38 | + and not IsPedDeadOrDying(ped, true) |
| 39 | + and not IsEntityDead(ped) then |
| 40 | + local dist = #(coords - GetEntityCoords(ped)) |
| 41 | + if dist < nearestDist then |
| 42 | + nearest = ped |
| 43 | + nearestDist = dist |
| 44 | + end |
| 45 | + end |
| 46 | + success, ped = FindNextPed(handle) |
| 47 | + until not success |
| 48 | + |
| 49 | + EndFindPed(handle) |
| 50 | + return nearest |
| 51 | +end |
| 52 | + |
| 53 | +-- Pick a random drug the player can attempt to sell. The server re-validates inventory. |
| 54 | +local function pickDrug() |
| 55 | + return Config.Drugs[math.random(1, #Config.Drugs)] |
| 56 | +end |
| 57 | + |
| 58 | +local lastSale = 0 |
| 59 | + |
| 60 | +local function attemptSale() |
| 61 | + if Config.RequireOnFoot and IsPedInAnyVehicle(PlayerPedId(), false) then |
| 62 | + return |
| 63 | + end |
| 64 | + |
| 65 | + local now = GetGameTimer() |
| 66 | + if now - lastSale < Config.Cooldown * 1000 then |
| 67 | + notify('You need to lay low for a moment.', 'error') |
| 68 | + return |
| 69 | + end |
| 70 | + |
| 71 | + local ped = getNearestPed() |
| 72 | + if not ped then |
| 73 | + notify('No one nearby to sell to.', 'error') |
| 74 | + return |
| 75 | + end |
| 76 | + |
| 77 | + lastSale = now |
| 78 | + |
| 79 | + local drug = pickDrug() |
| 80 | + local roll = math.random() |
| 81 | + local pedNet = PedToNet(ped) |
| 82 | + |
| 83 | + if roll <= Config.Chances.accept then |
| 84 | + notify(('Selling %s...'):format(drug.label), 'primary') |
| 85 | + TaskTurnPedToFaceEntity(ped, PlayerPedId(), 1500) |
| 86 | + Wait(1200) |
| 87 | + TriggerServerEvent('drug-sell:server:sell', drug.item) |
| 88 | + elseif roll <= Config.Chances.accept + Config.Chances.decline then |
| 89 | + notify('They waved you off.', 'error') |
| 90 | + TaskSmartFleePed(ped, PlayerPedId(), 60.0, -1, false, false) |
| 91 | + SetPedKeepTask(ped, true) |
| 92 | + else |
| 93 | + notify('Wrong customer. They are calling the cops!', 'error') |
| 94 | + TaskSmartFleePed(ped, PlayerPedId(), 100.0, -1, false, false) |
| 95 | + SetPedKeepTask(ped, true) |
| 96 | + local coords = GetEntityCoords(PlayerPedId()) |
| 97 | + TriggerServerEvent(Config.PoliceAlertEvent, { x = coords.x, y = coords.y, z = coords.z }) |
| 98 | + end |
| 99 | +end |
| 100 | + |
| 101 | +CreateThread(function() |
| 102 | + resolveFramework() |
| 103 | + while true do |
| 104 | + Wait(0) |
| 105 | + if IsControlJustReleased(0, Config.SellKey) then |
| 106 | + attemptSale() |
| 107 | + end |
| 108 | + end |
| 109 | +end) |
| 110 | + |
| 111 | +RegisterNetEvent('drug-sell:client:saleResult', function(ok, label, amount) |
| 112 | + if ok then |
| 113 | + notify(('Sold for $%d.'):format(amount), 'success') |
| 114 | + else |
| 115 | + notify(('You have no %s to sell.'):format(label or 'drugs'), 'error') |
| 116 | + end |
| 117 | +end) |
0 commit comments