2026-04-15 22:20:01 +02:00

410 lines
14 KiB
Lua

local ESX = exports['es_extended']:getSharedObject()
-- ============================================================
-- STATE TRACKING
-- ============================================================
local PlayerDeathStates = {} -- [serverId] = 'UNCONSCIOUS' | 'BLEEDING_OUT' | 'DEAD'
-- Broadcastet die Liste aller bewusstlosen Spieler an alle Clients (für ox_target)
local function BroadcastDownedPlayers()
local downedList = {}
for playerId, _ in pairs(PlayerDeathStates) do
downedList[playerId] = true
end
TriggerClientEvent('mercyv-deathscreen:client:syncDownedPlayers', -1, downedList)
end
-- ============================================================
-- STATE UPDATE
-- ============================================================
RegisterNetEvent('mercyv-deathscreen:server:updateState')
AddEventHandler('mercyv-deathscreen:server:updateState', function(state)
local src = source
if state == 'ALIVE' then
PlayerDeathStates[src] = nil
else
PlayerDeathStates[src] = state
end
BroadcastDownedPlayers()
end)
-- ============================================================
-- RESPAWN (Server-authoritative Verluste)
-- ============================================================
RegisterNetEvent('mercyv-deathscreen:server:respawn')
AddEventHandler('mercyv-deathscreen:server:respawn', function()
local src = source
-- Validieren dass Spieler bewusstlos/verblutend ist
if not PlayerDeathStates[src] then return end
local xPlayer = ESX.GetPlayerFromId(src)
if not xPlayer then return end
-- Geld entfernen
if Config.LoseMoney then
if Config.MoneyLossType == 'money' or Config.MoneyLossType == 'both' then
local cash = xPlayer.getMoney()
local loss = math.floor(cash * (Config.MoneyLossPercent / 100))
if loss > 0 then
xPlayer.removeMoney(loss)
end
end
if Config.MoneyLossType == 'black_money' or Config.MoneyLossType == 'both' then
local blackMoney = xPlayer.getAccount('black_money')
if blackMoney then
local loss = math.floor(blackMoney.money * (Config.MoneyLossPercent / 100))
if loss > 0 then
xPlayer.removeAccountMoney('black_money', loss)
end
end
end
end
-- Items entfernen (codem-inventory)
if Config.LoseItems then
local identifier = xPlayer.getIdentifier()
local inventory = exports['codem-inventory']:GetInventory(identifier, src)
if inventory then
if #Config.ItemsToLose == 0 then
-- Alle Items entfernen
for _, item in pairs(inventory) do
if item.name and item.amount and item.amount > 0 then
exports['codem-inventory']:RemoveItem(src, item.name, item.amount)
end
end
else
-- Nur bestimmte Items entfernen
for _, item in pairs(inventory) do
if item.name and item.amount and item.amount > 0 then
for _, loseName in ipairs(Config.ItemsToLose) do
if item.name == loseName then
exports['codem-inventory']:RemoveItem(src, item.name, item.amount)
break
end
end
end
end
end
end
end
-- Waffen entfernen
if Config.LoseWeapons then
local loadout = xPlayer.getLoadout()
local weaponsToRemove = {}
for _, weapon in ipairs(loadout) do
local keep = false
for _, keepWeapon in ipairs(Config.WeaponsToKeep) do
if weapon.name == keepWeapon then
keep = true
break
end
end
if not keep then
weaponsToRemove[#weaponsToRemove + 1] = weapon.name
end
end
for _, weaponName in ipairs(weaponsToRemove) do
xPlayer.removeWeapon(weaponName)
end
end
-- Hunger & Durst auf voll setzen
TriggerClientEvent('esx_status:set', src, 'hunger', 1000000)
TriggerClientEvent('esx_status:set', src, 'thirst', 1000000)
-- State aufräumen und Client zum Respawn schicken
PlayerDeathStates[src] = nil
BroadcastDownedPlayers()
TriggerClientEvent('mercyv-deathscreen:client:doRespawn', src)
end)
-- ============================================================
-- REVIVE SYSTEM
-- ============================================================
local function RevivePlayer(targetId)
targetId = tonumber(targetId)
if not targetId then return false end
if not PlayerDeathStates[targetId] then return false end
-- Hunger & Durst auf voll setzen
TriggerClientEvent('esx_status:set', targetId, 'hunger', 1000000)
TriggerClientEvent('esx_status:set', targetId, 'thirst', 1000000)
PlayerDeathStates[targetId] = nil
BroadcastDownedPlayers()
TriggerClientEvent('mercyv-deathscreen:client:revived', targetId)
return true
end
-- EMS / Zivilist belebt jemanden wieder
RegisterNetEvent('mercyv-deathscreen:server:revivePlayer')
AddEventHandler('mercyv-deathscreen:server:revivePlayer', function(targetId)
local src = source
local xPlayer = ESX.GetPlayerFromId(src)
if not xPlayer then return end
if not PlayerDeathStates[targetId] then return end
-- Prüfen ob Spieler EMS ist
local isEMS = false
for _, jobName in ipairs(Config.EMSJobNames) do
if xPlayer.job.name == jobName then
isEMS = true
break
end
end
if isEMS then
RevivePlayer(targetId)
return
end
-- Zivilist: Nur wenn CitizenRevive aktiviert ist und Item vorhanden
if Config.CitizenRevive then
local item = xPlayer.getInventoryItem(Config.CitizenReviveItem)
if item and item.count > 0 then
xPlayer.removeInventoryItem(Config.CitizenReviveItem, 1)
RevivePlayer(targetId)
TriggerClientEvent('esx:showNotification', src, Config.Locale.reviveItemUsed or (Config.CitizenReviveItem .. ' benutzt'))
else
TriggerClientEvent('esx:showNotification', src, Config.Locale.reviveNoItem or ('Du brauchst ein ' .. Config.CitizenReviveItem))
end
end
end)
-- Admin-Command: /revive [id]
RegisterCommand('revive', function(source, args)
local src = source
if src == 0 then
local targetId = tonumber(args[1])
if targetId then
RevivePlayer(targetId)
print('[mercyv-deathscreen] Spieler ' .. targetId .. ' wiederbelebt')
else
print('[mercyv-deathscreen] Benutzung: /revive [spieler-id]')
end
return
end
local xPlayer = ESX.GetPlayerFromId(src)
if not xPlayer then return end
if xPlayer.getGroup() ~= 'admin' and xPlayer.getGroup() ~= 'superadmin' then
TriggerClientEvent('esx:showNotification', src, 'Keine Berechtigung!')
return
end
local targetId = tonumber(args[1])
if not targetId then
targetId = src
end
if RevivePlayer(targetId) then
TriggerClientEvent('esx:showNotification', src, 'Spieler ' .. targetId .. ' wiederbelebt!')
else
TriggerClientEvent('esx:showNotification', src, 'Spieler ist nicht bewusstlos/tot!')
end
end, false)
exports('RevivePlayer', RevivePlayer)
-- ============================================================
-- WUNDENBEHANDLUNG (auf lebende Spieler)
-- ============================================================
RegisterNetEvent('mercyv-deathscreen:server:healPlayer')
AddEventHandler('mercyv-deathscreen:server:healPlayer', function(targetId, healType)
local src = source
local xPlayer = ESX.GetPlayerFromId(src)
if not xPlayer then return end
-- Nur EMS darf heilen
local isEMS = false
for _, jobName in ipairs(Config.EMSJobNames) do
if xPlayer.job.name == jobName then
isEMS = true
break
end
end
if not isEMS then return end
-- Ziel-Spieler muss existieren und lebendig sein
local targetPed = GetPlayerPed(targetId)
if not targetPed or targetPed <= 0 then return end
if PlayerDeathStates[targetId] then return end -- Bewusstlose nicht heilen, dafür gibts Revive
local currentHealth = GetEntityHealth(targetPed)
local maxHealth = GetEntityMaxHealth(targetPed)
local newHealth = currentHealth
if healType == 'big' then
-- Große Wunden: Heilt auf X% der max HP
newHealth = math.floor(maxHealth * (Config.HealBigPercent or 1.0))
elseif healType == 'small' then
-- Kleine Wunden: Heilt um X HP
newHealth = currentHealth + (Config.HealSmallAmount or 50)
end
-- HP nicht über max
if newHealth > maxHealth then newHealth = maxHealth end
TriggerClientEvent('mercyv-deathscreen:client:healed', targetId, newHealth, healType)
-- Notification an den Medic
if healType == 'big' then
TriggerClientEvent('esx:showNotification', src, Config.Locale.healBigDone or 'Große Wunden behandelt')
else
TriggerClientEvent('esx:showNotification', src, Config.Locale.healSmallDone or 'Kleine Wunden behandelt')
end
end)
-- ============================================================
-- SELBSTHEILUNG (Bandage)
-- ============================================================
if Config.SelfHeal then
ESX.RegisterUsableItem(Config.SelfHealItem or 'bandage', function(playerId)
-- Nicht wenn bewusstlos/tot
if PlayerDeathStates[playerId] then return end
local xPlayer = ESX.GetPlayerFromId(playerId)
if not xPlayer then return end
xPlayer.removeInventoryItem(Config.SelfHealItem or 'bandage', 1)
TriggerClientEvent('mercyv-deathscreen:client:selfHeal', playerId)
end)
end
-- ============================================================
-- EMS BENACHRICHTIGUNG
-- ============================================================
RegisterNetEvent('mercyv-deathscreen:server:callEMS')
AddEventHandler('mercyv-deathscreen:server:callEMS', function(coords, streetName)
local src = source
if not PlayerDeathStates[src] then return end
local xPlayers = ESX.GetPlayers()
for _, playerId in ipairs(xPlayers) do
local xTarget = ESX.GetPlayerFromId(playerId)
if xTarget then
for _, jobName in ipairs(Config.EMSJobNames) do
if xTarget.job.name == jobName then
TriggerClientEvent('mercyv-deathscreen:client:emsDispatch', playerId, {
coords = coords,
street = streetName or 'Unbekannt'
})
break
end
end
end
end
end)
-- ============================================================
-- CLEANUP
-- ============================================================
AddEventHandler('playerDropped', function()
PlayerDeathStates[source] = nil
BroadcastDownedPlayers()
end)
AddEventHandler('onResourceStop', function(resourceName)
if resourceName ~= GetCurrentResourceName() then return end
PlayerDeathStates = {}
end)
-- ============================================================
-- NPC MEDICAL SERVER LOGIC
-- ============================================================
-- Preise für den NPC-Arzt einstellen
local NPCCosts = {
Heal = 1000, -- Kosten für "Sich selbst heilen"
Revive = 1500 -- Kosten für "Andere Person wiederbeleben"
}
-- Hilfsfunktion: Prüft ob EMS im Dienst ist
local function IsEMSOnDuty()
local xPlayers = ESX.GetExtendedPlayers('job', 'ambulance') -- Ersetze 'ambulance' falls dein Job anders heißt
return #xPlayers > 0
end
-- NPC Selbstheilung
RegisterNetEvent('mercyv-deathscreen:server:npcHealSelf')
AddEventHandler('mercyv-deathscreen:server:npcHealSelf', function()
local src = source
if IsEMSOnDuty() then
TriggerClientEvent('esx:showNotification', src, 'Es sind Sanitäter im Dienst! Bitte rufe den Notruf.')
return
end
local xPlayer = ESX.GetPlayerFromId(src)
if xPlayer then
local cost = NPCCosts.Heal
-- Bezahl-Logik (zuerst Bargeld, dann Bank)
if xPlayer.getMoney() >= cost then
xPlayer.removeMoney(cost)
elseif xPlayer.getAccount('bank').money >= cost then
xPlayer.removeAccountMoney('bank', cost)
else
TriggerClientEvent('esx:showNotification', src, 'Du hast nicht genug Geld! (Kosten: $' .. cost .. ')')
return -- Bricht hier ab, wenn kein Geld da ist
end
TriggerClientEvent('mercyv-deathscreen:client:healed', src, 200, 'big')
TriggerClientEvent('esx:showNotification', src, 'Der Arzt hat deine Wunden für $' .. cost .. ' versorgt.')
end
end)
-- NPC Wiederbelebung für andere
RegisterNetEvent('mercyv-deathscreen:server:npcReviveOther')
AddEventHandler('mercyv-deathscreen:server:npcReviveOther', function(targetId)
local src = source
if IsEMSOnDuty() then
TriggerClientEvent('esx:showNotification', src, 'Es sind Sanitäter im Dienst! Bitte rufe den Notruf.')
return
end
local xPlayer = ESX.GetPlayerFromId(src)
if xPlayer then
local cost = NPCCosts.Revive
-- Bezahl-Logik (zuerst Bargeld, dann Bank)
if xPlayer.getMoney() >= cost then
xPlayer.removeMoney(cost)
elseif xPlayer.getAccount('bank').money >= cost then
xPlayer.removeAccountMoney('bank', cost)
else
TriggerClientEvent('esx:showNotification', src, 'Du hast nicht genug Geld! (Kosten: $' .. cost .. ')')
return -- Bricht hier ab, wenn kein Geld da ist
end
if RevivePlayer(targetId) then
TriggerClientEvent('esx:showNotification', src, 'Du hast die Person für $' .. cost .. ' wiederbelebt.')
TriggerClientEvent('esx:showNotification', targetId, 'Du wurdest von jemandem beim NPC-Arzt gerettet.')
else
-- Falls die Wiederbelebung fehlschlägt, geben wir das Geld zurück
xPlayer.addMoney(cost)
TriggerClientEvent('esx:showNotification', src, 'Fehler bei der Wiederbelebung. Geld wurde erstattet.')
end
end
end)