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)