276 lines
8.5 KiB
Lua
276 lines
8.5 KiB
Lua
ESX = exports['es_extended']:getSharedObject()
|
|
|
|
local spawnedPeds = {}
|
|
local isNuiOpen = false
|
|
local currentDealer = nil
|
|
|
|
-- =====================
|
|
-- DRAW TEXT 3D
|
|
-- =====================
|
|
|
|
function DrawText3D(x, y, z, text)
|
|
SetTextScale(0.35, 0.35)
|
|
SetTextFont(4)
|
|
SetTextProportional(1)
|
|
SetTextColour(255, 255, 255, 215)
|
|
SetTextEntry('STRING')
|
|
SetTextCentre(true)
|
|
AddTextComponentString(text)
|
|
SetDrawOrigin(x, y, z, 0)
|
|
DrawText(0.0, 0.0)
|
|
local factor = (string.len(text)) / 370
|
|
DrawRect(0.0, 0.0 + 0.0125, 0.017 + factor, 0.03, 0, 0, 0, 100)
|
|
ClearDrawOrigin()
|
|
end
|
|
|
|
-- =====================
|
|
-- NPC SPAWNING
|
|
-- =====================
|
|
|
|
Citizen.CreateThread(function()
|
|
for dealerId, dealer in pairs(Config.Dealers) do
|
|
local npc = dealer.npc
|
|
local hash = GetHashKey(npc.model)
|
|
|
|
RequestModel(hash)
|
|
while not HasModelLoaded(hash) do
|
|
Citizen.Wait(10)
|
|
end
|
|
|
|
local ped = CreatePed(4, hash, npc.coords.x, npc.coords.y, npc.coords.z - 1.0, npc.coords.w, false, true)
|
|
SetEntityHeading(ped, npc.coords.w)
|
|
FreezeEntityPosition(ped, true)
|
|
SetEntityInvincible(ped, true)
|
|
SetBlockingOfNonTemporaryEvents(ped, true)
|
|
|
|
if npc.scenario then
|
|
TaskStartScenarioInPlace(ped, npc.scenario, 0, true)
|
|
end
|
|
|
|
spawnedPeds[dealerId] = ped
|
|
SetModelAsNoLongerNeeded(hash)
|
|
end
|
|
end)
|
|
|
|
AddEventHandler('onResourceStop', function(resourceName)
|
|
if resourceName ~= GetCurrentResourceName() then return end
|
|
for _, ped in pairs(spawnedPeds) do
|
|
if DoesEntityExist(ped) then
|
|
DeleteEntity(ped)
|
|
end
|
|
end
|
|
end)
|
|
|
|
-- =====================
|
|
-- NPC INTERACTION
|
|
-- =====================
|
|
|
|
Citizen.CreateThread(function()
|
|
while true do
|
|
local sleep = 1000
|
|
local playerCoords = GetEntityCoords(PlayerPedId())
|
|
local closestDealer = nil
|
|
local closestDist = Config.InteractionDistance + 1
|
|
|
|
for dealerId, dealer in pairs(Config.Dealers) do
|
|
local dist = #(playerCoords - vector3(dealer.npc.coords.x, dealer.npc.coords.y, dealer.npc.coords.z))
|
|
if dist < closestDist then
|
|
closestDist = dist
|
|
closestDealer = dealerId
|
|
end
|
|
end
|
|
|
|
if closestDealer and closestDist <= Config.InteractionDistance then
|
|
sleep = 0
|
|
local dealer = Config.Dealers[closestDealer]
|
|
|
|
if not isNuiOpen then
|
|
local npcCoords = dealer.npc.coords
|
|
DrawText3D(npcCoords.x, npcCoords.y, npcCoords.z + 1.0, '[E] ' .. dealer.label)
|
|
|
|
if IsControlJustReleased(0, 38) then
|
|
OpenSellMenu(closestDealer)
|
|
end
|
|
end
|
|
end
|
|
|
|
Citizen.Wait(sleep)
|
|
end
|
|
end)
|
|
|
|
-- =====================
|
|
-- NUI MANAGEMENT
|
|
-- =====================
|
|
|
|
function OpenSellMenu(dealerId)
|
|
if isNuiOpen then return end
|
|
|
|
currentDealer = dealerId
|
|
local dealer = Config.Dealers[dealerId]
|
|
|
|
ESX.TriggerServerCallback('mercy-sell:getPlayerItems', function(playerItems)
|
|
ESX.TriggerServerCallback('mercy-sell:getDealerPrices', function(prices)
|
|
isNuiOpen = true
|
|
SetNuiFocus(true, true)
|
|
|
|
SendNUIMessage({
|
|
type = 'open',
|
|
dealerLabel = dealer.label,
|
|
dealerId = dealerId,
|
|
dealerImage = dealer.image or '',
|
|
dealerColor = dealer.color or '',
|
|
prices = prices,
|
|
playerItems = playerItems,
|
|
})
|
|
|
|
-- Check if there's an active sell or pending collect
|
|
ESX.TriggerServerCallback('mercy-sell:getSellStatus', function(sellData, collectData)
|
|
if sellData then
|
|
SendNUIMessage({
|
|
type = 'sellStatus',
|
|
itemName = sellData.itemName,
|
|
itemLabel = sellData.itemLabel,
|
|
amount = sellData.amount,
|
|
totalMoney = sellData.totalMoney,
|
|
totalDuration = sellData.totalDuration,
|
|
elapsed = sellData.elapsed,
|
|
isComplete = sellData.isComplete,
|
|
})
|
|
elseif collectData then
|
|
SendNUIMessage({
|
|
type = 'sellStatus',
|
|
itemName = collectData.itemName,
|
|
itemLabel = collectData.itemLabel,
|
|
amount = collectData.amount,
|
|
totalMoney = collectData.totalMoney,
|
|
totalDuration = 0,
|
|
elapsed = 0,
|
|
isComplete = true,
|
|
})
|
|
end
|
|
end)
|
|
end, dealerId)
|
|
end)
|
|
end
|
|
|
|
function CloseSellMenu()
|
|
if not isNuiOpen then return end
|
|
isNuiOpen = false
|
|
currentDealer = nil
|
|
SetNuiFocus(false, false)
|
|
SendNUIMessage({ type = 'close' })
|
|
end
|
|
|
|
-- =====================
|
|
-- NUI CALLBACKS
|
|
-- =====================
|
|
|
|
RegisterNUICallback('close', function(_, cb)
|
|
CloseSellMenu()
|
|
cb('ok')
|
|
end)
|
|
|
|
RegisterNUICallback('sellItems', function(data, cb)
|
|
if not currentDealer then
|
|
cb({ success = false })
|
|
return
|
|
end
|
|
|
|
TriggerServerEvent('mercy-sell:sellItems', data.itemName, data.amount, currentDealer)
|
|
cb('ok')
|
|
end)
|
|
|
|
RegisterNUICallback('collectMoney', function(_, cb)
|
|
TriggerServerEvent('mercy-sell:collectMoney')
|
|
cb('ok')
|
|
end)
|
|
|
|
-- =====================
|
|
-- SERVER EVENT HANDLERS
|
|
-- =====================
|
|
|
|
RegisterNetEvent('mercy-sell:sellResult')
|
|
AddEventHandler('mercy-sell:sellResult', function(success, message)
|
|
if success then
|
|
TriggerEvent('hex_4_hud:notify', 'Verkauf', message, 'success', 3000)
|
|
else
|
|
TriggerEvent('hex_4_hud:notify', 'Verkauf', message, 'error', 3000)
|
|
SendNUIMessage({ type = 'sellFailed', message = message })
|
|
end
|
|
end)
|
|
|
|
RegisterNetEvent('mercy-sell:sellStarted')
|
|
AddEventHandler('mercy-sell:sellStarted', function(data)
|
|
SendNUIMessage({
|
|
type = 'sellStarted',
|
|
itemName = data.itemName,
|
|
itemLabel = data.itemLabel,
|
|
amount = data.amount,
|
|
totalMoney = data.totalMoney,
|
|
totalDuration = data.totalDuration,
|
|
})
|
|
|
|
-- Refresh inventory and prices
|
|
if currentDealer then
|
|
ESX.TriggerServerCallback('mercy-sell:getPlayerItems', function(playerItems)
|
|
SendNUIMessage({ type = 'updateInventory', playerItems = playerItems })
|
|
end)
|
|
ESX.TriggerServerCallback('mercy-sell:getDealerPrices', function(prices)
|
|
SendNUIMessage({ type = 'updatePrices', prices = prices })
|
|
end, currentDealer)
|
|
end
|
|
end)
|
|
|
|
RegisterNetEvent('mercy-sell:sellReady')
|
|
AddEventHandler('mercy-sell:sellReady', function(data)
|
|
SendNUIMessage({
|
|
type = 'sellStatus',
|
|
itemName = data.itemName,
|
|
itemLabel = data.itemLabel,
|
|
amount = data.amount,
|
|
totalMoney = data.totalMoney,
|
|
totalDuration = 0,
|
|
elapsed = 0,
|
|
isComplete = true,
|
|
})
|
|
end)
|
|
|
|
RegisterNetEvent('mercy-sell:sellComplete')
|
|
AddEventHandler('mercy-sell:sellComplete', function(data)
|
|
TriggerEvent('hex_4_hud:notify', 'Verkauf',
|
|
'$' .. data.totalMoney .. ' abgeholt!',
|
|
'success', 5000)
|
|
SendNUIMessage({ type = 'sellComplete', totalMoney = data.totalMoney })
|
|
|
|
-- Refresh inventory
|
|
if currentDealer then
|
|
ESX.TriggerServerCallback('mercy-sell:getPlayerItems', function(playerItems)
|
|
SendNUIMessage({ type = 'updateInventory', playerItems = playerItems })
|
|
end)
|
|
end
|
|
end)
|
|
|
|
|
|
CreateThread(function()
|
|
for dealerID, data in pairs(Config.Dealers) do
|
|
-- Prüfen, ob für diesen Dealer ein Blip aktiviert ist
|
|
if data.blip and data.blip.enabled then
|
|
local coords = data.npc.coords
|
|
|
|
-- Blip erstellen
|
|
local blip = AddBlipForCoord(coords.x, coords.y, coords.z)
|
|
|
|
-- Blip optisch anpassen
|
|
SetBlipSprite(blip, data.blip.sprite or 1) -- Icon
|
|
SetBlipDisplay(blip, 4) -- Überall anzeigen
|
|
SetBlipScale(blip, data.blip.scale or 1.0) -- Größe
|
|
SetBlipColour(blip, data.blip.color or 1) -- Farbe
|
|
SetBlipAsShortRange(blip, true) -- Nur auf Minimap, wenn nah dran
|
|
|
|
-- Namen setzen
|
|
BeginTextCommandSetBlipName("STRING")
|
|
AddTextComponentString(data.label)
|
|
EndTextCommandSetBlipName(blip)
|
|
end
|
|
end
|
|
end) |