-- ===================================================================== -- Aether Death — Serverlogik -- Der Server fuehrt den Verblutungs-Countdown und entscheidet ueber -- Wiederbelebung, Aufgeben und Krankenhausaufenthalt. -- ===================================================================== local Core = exports['aether-core'] -- Verletzte Spieler: [quelle] = { seit, restBleed, sperre, emsGerufen, position } local verletzte = {} -- --------------------------------------------------------------------- -- Hilfsfunktionen -- --------------------------------------------------------------------- local function CharakterVon(quelle) return Core:HoleCharakterId(quelle) end --- Schickt den aktuellen Zustand an den verletzten Spieler --- @param quelle number Server-ID local function SendeZustand(quelle) local eintrag = verletzte[quelle] if not eintrag then return end TriggerClientEvent('aether:death:zustand', quelle, { restBleed = eintrag.restBleed, respawnSperre = eintrag.sperre, emsGerufen = eintrag.emsGerufen, bleedoutMax = Tod.BLEEDOUT, }) end --- Beendet den Verletzt-Zustand eines Spielers --- @param quelle number Server-ID local function BeendeVerletzung(quelle) verletzte[quelle] = nil local charakterId = CharakterVon(quelle) if charakterId then MySQL.update('UPDATE aether_characters SET is_dead = 0 WHERE id = ?', { charakterId }) end end -- --------------------------------------------------------------------- -- Spieler geht zu Boden -- --------------------------------------------------------------------- RegisterNetEvent('aether:death:gefallen', function() local quelle = source local charakterId = CharakterVon(quelle) if not charakterId then return end if verletzte[quelle] then return end -- schon verletzt local position = GetEntityCoords(GetPlayerPed(quelle)) verletzte[quelle] = { seit = os.time(), restBleed = Tod.BLEEDOUT, sperre = Tod.RESPAWN_SPERRE, emsGerufen = false, position = { x = position.x, y = position.y, z = position.z }, } MySQL.update('UPDATE aether_characters SET is_dead = 1 WHERE id = ?', { charakterId }) TriggerClientEvent('aether:death:zeige', quelle, { restBleed = Tod.BLEEDOUT, respawnSperre = Tod.RESPAWN_SPERRE, bleedoutMax = Tod.BLEEDOUT, }) -- Andere Module informieren (z. B. Job beenden, HUD anpassen) TriggerEvent('aether:death:spielerGefallen', quelle) end) -- --------------------------------------------------------------------- -- Rettungsdienst rufen -- --------------------------------------------------------------------- RegisterNetEvent('aether:death:emsRufen', function() local quelle = source local eintrag = verletzte[quelle] if not eintrag or eintrag.emsGerufen then return end eintrag.emsGerufen = true local person = Core:HoleSpielerInfo(quelle) local name = person and (person.vorname .. ' ' .. person.nachname) or 'Unbekannt' -- Notruf weiterreichen. Ein Rettungsdienst-Modul kann diesen Event -- abfangen und daraus einen Einsatz erzeugen. TriggerEvent('aether:death:notruf', quelle, { name = name, position = eintrag.position, }) SendeZustand(quelle) TriggerClientEvent('aether:death:hinweis', quelle, 'Notruf abgesetzt. Warte auf Hilfe.') end) -- --------------------------------------------------------------------- -- Aufgeben: im Krankenhaus aufwachen -- --------------------------------------------------------------------- RegisterNetEvent('aether:death:aufgeben', function() local quelle = source local eintrag = verletzte[quelle] if not eintrag then return end -- Sperrzeit pruefen: nicht sofort aufgeben koennen if eintrag.sperre > 0 then TriggerClientEvent('aether:death:hinweis', quelle, ('Noch %d Sekunden, bevor du aufgeben kannst.'):format(eintrag.sperre)) return end local klinik = Tod.NaechstesKrankenhaus( vector3(eintrag.position.x, eintrag.position.y, eintrag.position.z)) -- Behandlungskosten abbuchen (erst Bargeld, dann Konto) local bezahlt = Core:EntferneGeld(quelle, 'bargeld', Tod.KRANKENHAUS_KOSTEN, 'Behandlung Krankenhaus') if not bezahlt then bezahlt = Core:EntferneGeld(quelle, 'konto', Tod.KRANKENHAUS_KOSTEN, 'Behandlung Krankenhaus') end BeendeVerletzung(quelle) TriggerClientEvent('aether:death:krankenhaus', quelle, { klinik = klinik.name, position = { x = klinik.pos.x, y = klinik.pos.y, z = klinik.pos.z, w = klinik.pos.w }, leben = Tod.LEBEN_NACH_KLINIK, kosten = bezahlt and Tod.KRANKENHAUS_KOSTEN or 0, bezahlt = bezahlt, grund = 'aufgegeben', }) end) -- --------------------------------------------------------------------- -- Countdown: Verbluten und Sperrzeit -- --------------------------------------------------------------------- CreateThread(function() while true do Wait(1000) for quelle, eintrag in pairs(verletzte) do if eintrag.sperre > 0 then eintrag.sperre = eintrag.sperre - 1 end eintrag.restBleed = eintrag.restBleed - 1 -- Zeit abgelaufen: Der Spieler verblutet und wacht in der Klinik auf if eintrag.restBleed <= 0 then local klinik = Tod.NaechstesKrankenhaus( vector3(eintrag.position.x, eintrag.position.y, eintrag.position.z)) local bezahlt = Core:EntferneGeld(quelle, 'bargeld', Tod.KRANKENHAUS_KOSTEN, 'Behandlung Krankenhaus') if not bezahlt then bezahlt = Core:EntferneGeld(quelle, 'konto', Tod.KRANKENHAUS_KOSTEN, 'Behandlung Krankenhaus') end BeendeVerletzung(quelle) TriggerClientEvent('aether:death:krankenhaus', quelle, { klinik = klinik.name, position = { x = klinik.pos.x, y = klinik.pos.y, z = klinik.pos.z, w = klinik.pos.w }, leben = Tod.LEBEN_NACH_KLINIK, kosten = bezahlt and Tod.KRANKENHAUS_KOSTEN or 0, bezahlt = bezahlt, grund = 'verblutet', }) else SendeZustand(quelle) end end end end) -- --------------------------------------------------------------------- -- Position des Verletzten aktuell halten (er kann noch kriechen) -- --------------------------------------------------------------------- CreateThread(function() while true do Wait(5000) for quelle, eintrag in pairs(verletzte) do local ped = GetPlayerPed(quelle) if ped and ped ~= 0 then local position = GetEntityCoords(ped) eintrag.position = { x = position.x, y = position.y, z = position.z } end end end end) -- --------------------------------------------------------------------- -- Aufraeumen -- --------------------------------------------------------------------- AddEventHandler('playerDropped', function() verletzte[source] = nil end) -- ===================================================================== -- EXPORTS — fuer den Rettungsdienst -- ===================================================================== --- Belebt einen verletzten Spieler wieder. --- Wird vom EMS aufgerufen; prueft die Entfernung des Helfers. --- @param quelle number Server-ID des Verletzten --- @param helfer number|nil Server-ID des Sanitaeters (nil = ohne Pruefung) --- @return boolean Erfolg exports('Wiederbeleben', function(quelle, helfer) local eintrag = verletzte[quelle] if not eintrag then return false end -- Entfernungspruefung, wenn ein Helfer angegeben ist if helfer then local hier = GetEntityCoords(GetPlayerPed(helfer)) local dort = GetEntityCoords(GetPlayerPed(quelle)) if #(hier - dort) > Tod.WIEDERBELEBUNG_WEITE then return false end end BeendeVerletzung(quelle) TriggerClientEvent('aether:death:wiederbelebt', quelle, { leben = Tod.LEBEN_NACH_HILFE, }) return true end) --- Ist ein Spieler gerade verletzt am Boden? --- @param quelle number Server-ID --- @return boolean exports('IstVerletzt', function(quelle) return verletzte[quelle] ~= nil end) --- Liefert alle verletzten Spieler mit Position (fuer die EMS-Karte) --- @return table exports('HoleVerletzte', function() local liste = {} for quelle, eintrag in pairs(verletzte) do liste[#liste + 1] = { quelle = quelle, position = eintrag.position, emsGerufen = eintrag.emsGerufen, restBleed = eintrag.restBleed, } end return liste end)