-- ===================================================================== -- Aether HUD — Clientlogik -- Versorgt die Oberflaeche mit Status, Geld, Voice und Fahrzeugwerten. -- Es wird nur gesendet, wenn sich ein Wert tatsaechlich geaendert hat. -- ===================================================================== -- Ist der Spieler fertig geladen? (vorher kein HUD zeigen) local istGeladen = false -- Soll das HUD sichtbar sein? (z. B. bei offenen Menues ausblendbar) local istSichtbar = true -- Zuletzt gesendete Werte, um unnoetige Nachrichten zu vermeiden local letzterStatus = {} local letztesFahrzeug = {} local letzteVoice = {} -- --------------------------------------------------------------------- -- Hilfsfunktionen -- --------------------------------------------------------------------- --- Schickt eine Nachricht an die Oberflaeche --- @param nachricht table Zu sendende Daten local function SendeAnHud(nachricht) SendNuiMessage(json.encode(nachricht)) end --- Prueft, ob sich mindestens ein Feld gegenueber dem Zwischenspeicher geaendert hat --- @param neu table Neue Werte --- @param alt table Zwischenspeicher (wird aktualisiert) --- @return boolean true, wenn sich etwas geaendert hat local function HatSichGeaendert(neu, alt) local geaendert = false for schluessel, wert in pairs(neu) do if alt[schluessel] ~= wert then alt[schluessel] = wert geaendert = true end end return geaendert end --- Rechnet die Lebensenergie (100–200) in Prozent (0–100) um. --- GTA zaehlt Leben ab 100; darunter ist der Spieler tot. --- @param ped number Ped-Handle --- @return number Prozentwert 0–100 local function LebenInProzent(ped) local leben = GetEntityHealth(ped) if leben <= 100 then return 0 end return Aether.Begrenze((leben - 100) / 100 * 100, 0, 100) end -- --------------------------------------------------------------------- -- Ereignisse vom Core -- --------------------------------------------------------------------- --- Spieler ist im Spiel: HUD mit den Startwerten fuellen AddEventHandler('aether:client:bereit', function(daten) istGeladen = true SendeAnHud({ aktion = 'geld', bargeld = daten.bargeld, konto = daten.konto, schwarzgeld = daten.schwarzgeld, -- Schwarzgeld nur zeigen, wenn welches vorhanden ist schwarzgeldSichtbar = (daten.schwarzgeld or 0) > 0, }) SendeAnHud({ aktion = 'status', leben = LebenInProzent(PlayerPedId()), hunger = daten.hunger, durst = daten.durst, ausdauer = daten.ausdauer, }) SendeAnHud({ aktion = 'sichtbar', an = true }) end) --- Geld hat sich geaendert AddEventHandler('aether:client:geldGeaendert', function(geld) SendeAnHud({ aktion = 'geld', bargeld = geld.bargeld, konto = geld.konto, schwarzgeld = geld.schwarzgeld, schwarzgeldSichtbar = (geld.schwarzgeld or 0) > 0, }) end) --- Hunger/Durst/Ausdauer haben sich geaendert AddEventHandler('aether:client:zustandGeaendert', function(zustand) SendeAnHud({ aktion = 'status', hunger = zustand.hunger, durst = zustand.durst, ausdauer = zustand.ausdauer, }) end) -- --------------------------------------------------------------------- -- Laufende Erfassung: Leben und Ausdauer -- --------------------------------------------------------------------- CreateThread(function() while true do Wait(500) if istGeladen then local ped = PlayerPedId() -- Ausdauer aus dem Sprint-Vorrat ableiten (100 = ausgeruht) local ausdauer = 100.0 - GetPlayerSprintStaminaRemaining(PlayerId()) local neu = { leben = math.floor(LebenInProzent(ped)), ausdauer = math.floor(Aether.Begrenze(ausdauer, 0, 100)), } if HatSichGeaendert(neu, letzterStatus) then neu.aktion = 'status' SendeAnHud(neu) end end end end) -- --------------------------------------------------------------------- -- Laufende Erfassung: Voice -- --------------------------------------------------------------------- CreateThread(function() while true do Wait(200) if istGeladen then -- Sprechen erkennen (funktioniert mit dem eingebauten Mumble-Voice) local redet = NetworkIsPlayerTalking(PlayerId()) -- Reichweite aus der Mumble-Einstellung ableiten local reichweite = MumbleGetTalkerProximity() or 0.0 local stufe = 1 -- 0 = Fluestern, 1 = Normal, 2 = Rufen if reichweite <= 3.5 then stufe = 0 elseif reichweite >= 12.0 then stufe = 2 end local neu = { redet = redet, voiceStufe = stufe } if HatSichGeaendert(neu, letzteVoice) then neu.aktion = 'voice' SendeAnHud(neu) end end end end) -- --------------------------------------------------------------------- -- Laufende Erfassung: Fahrzeug -- Im Fahrzeug haeufiger abfragen, damit der Tacho fluessig laeuft. -- --------------------------------------------------------------------- CreateThread(function() while true do local pause = 500 if istGeladen then local daten = Fahrzeug.HoleDaten() if daten then pause = 100 -- fluessige Tachoanzeige if HatSichGeaendert(daten, letztesFahrzeug) then daten.aktion = 'fahrzeug' SendeAnHud(daten) end elseif letztesFahrzeug.imFahrzeug ~= false then -- Gerade ausgestiegen: Fahrzeuganzeige ausblenden letztesFahrzeug = { imFahrzeug = false } SendeAnHud({ aktion = 'fahrzeug', imFahrzeug = false, tempo = 0 }) end end Wait(pause) end end) -- ===================================================================== -- EXPORTS — andere Module koennen das HUD aus- und einblenden -- Beispiel: exports['aether-hud']:SetzeSichtbar(false) -- ===================================================================== --- Blendet das HUD ein oder aus --- @param an boolean true = sichtbar exports('SetzeSichtbar', function(an) istSichtbar = an and true or false SendeAnHud({ aktion = 'sichtbar', an = istSichtbar }) end) --- Ist das HUD gerade sichtbar? --- @return boolean exports('IstSichtbar', function() return istSichtbar end)