203 lines
6.4 KiB
Lua
203 lines
6.4 KiB
Lua
ESX = exports['es_extended']:getSharedObject()
|
|
|
|
local spawnedPeds = {} -- location_id -> ped handle
|
|
local activeLocations = {} -- location_id -> location config
|
|
local isNuiOpen = false
|
|
|
|
-- =====================
|
|
-- NPC SPAWNING
|
|
-- =====================
|
|
function SpawnNPC(locationId, locationConfig)
|
|
if spawnedPeds[locationId] then return end
|
|
|
|
local coords = locationConfig.coords
|
|
local model = locationConfig.npcModel or Config.DefaultNpcModel
|
|
local scenario = locationConfig.npcScenario or Config.DefaultNpcScenario
|
|
local hash = GetHashKey(model)
|
|
|
|
RequestModel(hash)
|
|
while not HasModelLoaded(hash) do Citizen.Wait(10) end
|
|
|
|
local ped = CreatePed(4, hash, coords.x, coords.y, coords.z - 1.0, coords.w, false, true)
|
|
SetEntityHeading(ped, coords.w)
|
|
FreezeEntityPosition(ped, true)
|
|
SetEntityInvincible(ped, true)
|
|
SetBlockingOfNonTemporaryEvents(ped, true)
|
|
TaskStartScenarioInPlace(ped, scenario, 0, true)
|
|
SetModelAsNoLongerNeeded(hash)
|
|
|
|
spawnedPeds[locationId] = ped
|
|
end
|
|
|
|
function DespawnNPC(locationId)
|
|
if spawnedPeds[locationId] then
|
|
if DoesEntityExist(spawnedPeds[locationId]) then
|
|
DeleteEntity(spawnedPeds[locationId])
|
|
end
|
|
spawnedPeds[locationId] = nil
|
|
end
|
|
end
|
|
|
|
function SyncLocations(locations)
|
|
-- Despawn NPCs die nicht mehr aktiv sind
|
|
for id, _ in pairs(spawnedPeds) do
|
|
if not locations[id] then
|
|
DespawnNPC(id)
|
|
end
|
|
end
|
|
|
|
-- Spawn neue NPCs
|
|
for id, config in pairs(locations) do
|
|
if not spawnedPeds[id] then
|
|
SpawnNPC(id, config)
|
|
end
|
|
end
|
|
|
|
activeLocations = locations
|
|
end
|
|
|
|
-- =====================
|
|
-- LOCATION SYNC
|
|
-- =====================
|
|
RegisterNetEvent('mercyv-blackmarket:syncLocations')
|
|
AddEventHandler('mercyv-blackmarket:syncLocations', function(locations)
|
|
SyncLocations(locations)
|
|
end)
|
|
|
|
-- Cleanup on resource stop
|
|
AddEventHandler('onResourceStop', function(resourceName)
|
|
if resourceName ~= GetCurrentResourceName() then return end
|
|
for id, ped in pairs(spawnedPeds) do
|
|
if DoesEntityExist(ped) then DeleteEntity(ped) end
|
|
end
|
|
end)
|
|
|
|
-- Spawn NPCs und sync bei Start
|
|
Citizen.CreateThread(function()
|
|
Citizen.Wait(2000)
|
|
TriggerServerEvent('mercyv-blackmarket:requestSync')
|
|
end)
|
|
|
|
-- =====================
|
|
-- NPC INTERACTION
|
|
-- =====================
|
|
Citizen.CreateThread(function()
|
|
local nearLocation = false
|
|
local nearbyLocationId = nil
|
|
local COARSE_DIST = Config.CoarseDistance or 50.0
|
|
|
|
while true do
|
|
local sleep = 1000
|
|
local playerCoords = GetEntityCoords(PlayerPedId())
|
|
local foundNear = false
|
|
|
|
if not isNuiOpen then
|
|
-- Wenn bereits ein nahegelegener Standort bekannt ist
|
|
if nearbyLocationId then
|
|
local locConfig = activeLocations[nearbyLocationId]
|
|
if locConfig then
|
|
local dist = #(playerCoords - vector3(locConfig.coords.x, locConfig.coords.y, locConfig.coords.z))
|
|
|
|
if dist <= Config.InteractionDistance then
|
|
sleep = 0
|
|
foundNear = true
|
|
exports[Config.HelpNotify.export][Config.HelpNotify.showFunc](locConfig.label or 'Schwarzmarkt', 'E')
|
|
if IsControlJustReleased(0, 38) then
|
|
OpenBlackmarket(nearbyLocationId)
|
|
end
|
|
elseif dist > COARSE_DIST then
|
|
nearbyLocationId = nil
|
|
end
|
|
else
|
|
nearbyLocationId = nil
|
|
end
|
|
end
|
|
|
|
-- Suche nach nahegelegenen Standorten
|
|
if not nearbyLocationId and not foundNear then
|
|
for locId, locConfig in pairs(activeLocations) do
|
|
local dist = #(playerCoords - vector3(locConfig.coords.x, locConfig.coords.y, locConfig.coords.z))
|
|
if dist <= COARSE_DIST then
|
|
nearbyLocationId = locId
|
|
if dist <= Config.InteractionDistance then
|
|
sleep = 0
|
|
foundNear = true
|
|
exports[Config.HelpNotify.export][Config.HelpNotify.showFunc](locConfig.label or 'Schwarzmarkt', 'E')
|
|
if IsControlJustReleased(0, 38) then
|
|
OpenBlackmarket(locId)
|
|
end
|
|
end
|
|
break
|
|
end
|
|
end
|
|
end
|
|
|
|
if not foundNear and nearLocation then
|
|
exports[Config.HelpNotify.export][Config.HelpNotify.hideFunc]()
|
|
end
|
|
nearLocation = foundNear
|
|
end
|
|
|
|
Citizen.Wait(sleep)
|
|
end
|
|
end)
|
|
|
|
-- =====================
|
|
-- NUI MANAGEMENT
|
|
-- =====================
|
|
function OpenBlackmarket(locationId)
|
|
if isNuiOpen then return end
|
|
|
|
ESX.TriggerServerCallback('mercyv-blackmarket:getMarketData', function(data)
|
|
isNuiOpen = true
|
|
SetNuiFocus(true, true)
|
|
SendNUIMessage({
|
|
type = 'open',
|
|
locationId = locationId,
|
|
categories = data.categories,
|
|
theme = Config.Theme,
|
|
paymentMethod = Config.PaymentMethod,
|
|
})
|
|
end)
|
|
end
|
|
|
|
function CloseMenu()
|
|
if not isNuiOpen then return end
|
|
isNuiOpen = false
|
|
SetNuiFocus(false, false)
|
|
SendNUIMessage({ type = 'close' })
|
|
end
|
|
|
|
-- =====================
|
|
-- NUI CALLBACKS
|
|
-- =====================
|
|
RegisterNUICallback('close', function(_, cb)
|
|
CloseMenu()
|
|
cb('ok')
|
|
end)
|
|
|
|
RegisterNUICallback('buyItem', function(data, cb)
|
|
TriggerServerEvent('mercyv-blackmarket:buyItem', data.itemName, data.quantity)
|
|
cb('ok')
|
|
end)
|
|
|
|
-- =====================
|
|
-- SERVER EVENT HANDLERS
|
|
-- =====================
|
|
RegisterNetEvent('mercyv-blackmarket:notify')
|
|
AddEventHandler('mercyv-blackmarket:notify', function(message, nType)
|
|
TriggerEvent(Config.Notification.event, Config.Notification.title, message, nType or 'info', Config.Notification.duration)
|
|
end)
|
|
|
|
RegisterNetEvent('mercyv-blackmarket:buyResult')
|
|
AddEventHandler('mercyv-blackmarket:buyResult', function(success, updatedLimits)
|
|
if success then
|
|
SendNUIMessage({ type = 'updateLimits', limits = updatedLimits })
|
|
end
|
|
end)
|
|
|
|
RegisterNetEvent('mercyv-blackmarket:forceClose')
|
|
AddEventHandler('mercyv-blackmarket:forceClose', function()
|
|
CloseMenu()
|
|
end)
|