-- ===================================================================== -- aether-medical / Modul: Fuhrpark -- -- Ein Fahrzeugbuch. Es fährt nichts, gibt nichts aus und ruft keine -- Werkstatt. -- -- Zwei Sorten von Angaben stehen hier nebeneinander, und sie werden -- streng auseinandergehalten: -- -- * GEMELDET — Tankstand, Zustand und Position kommen aus dem Spiel, -- während jemand fährt. Das sind Tatsachen, keine Entscheidungen. -- Sie werden nur festgeschrieben und mit ihrem Alter angezeigt. -- -- * EINGETRAGEN — Einsatzstatus, Wartungsstatus und Zuweisung setzt -- ausschliesslich ein Mensch. Kein gemeldeter Wert ändert sie je: -- ein leerer Tank stellt kein Fahrzeug ausser Dienst, und ein -- Schaden schickt keines in die Werkstatt. -- ===================================================================== Kern.RegistriereModul({ id = 'fahrzeug', name = 'Fuhrpark', icon = '🚐', reihenfolge = 12, recht = 'fahrzeug.sehen', beschreibung = 'Fahrzeuge, Status, Zuweisung und Wartung', }) -- --------------------------------------------------------------------- -- Grundbestand -- -- Damit sich überhaupt etwas zuweisen lässt. Die Pflege übernimmt -- danach die Fuhrparkverwaltung. -- --------------------------------------------------------------------- local GRUNDFAHRZEUGE = { -- kennzeichen, modell, bezeichnung, art, station, ausstattung { 'LSMC 001', 'ambulance', 'RTW 1', 'rtw', 'notaufnahme', 'Defibrillator, Beatmungsgerät, Notfallrucksack, Trage, Sauerstoff' }, { 'LSMC 002', 'ambulance', 'RTW 2', 'rtw', 'notaufnahme', 'Defibrillator, Notfallrucksack, Trage, Sauerstoff' }, { 'LSMC 010', 'ambulance', 'NEF 1', 'nef', 'notaufnahme', 'Notfallrucksack, Notfallmedikamente, Perfusor' }, { 'LSMC 020', 'ambulance', 'KTW 1', 'ktw', 'rettung', 'Trage, Sauerstoff' }, } CreateThread(function() Wait(2500) local vorhanden = tonumber(MySQL.scalar.await('SELECT COUNT(*) FROM medical_fahrzeug')) or 0 if vorhanden > 0 then return end for _, eintrag in ipairs(GRUNDFAHRZEUGE) do MySQL.insert.await([[ INSERT INTO medical_fahrzeug (kennzeichen, modell, bezeichnung, art, station, ausstattung) VALUES (?, ?, ?, ?, ?, ?) ]], { eintrag[1], eintrag[2], eintrag[3], eintrag[4], eintrag[5], eintrag[6] }) end Aether.Debug('Grundbestand an Fahrzeugen angelegt.') end) -- --------------------------------------------------------------------- -- Hilfsfunktionen -- --------------------------------------------------------------------- --- Begrenzt einen Text und liefert nil bei leerer Eingabe --- @param wert any Eingabe --- @param laenge number Maximale Zeichenzahl --- @return string|nil local function Text(wert, laenge) if type(wert) ~= 'string' then return nil end local sauber = wert:gsub('^%s+', ''):gsub('%s+$', '') if sauber == '' then return nil end return sauber:sub(1, laenge) end --- Name eines Charakters für die Anzeige --- @param charakterId number|nil Charakter --- @return string local function NameVon(charakterId) if not charakterId then return 'unbekannt' end local zeilen = MySQL.query.await( 'SELECT firstname, lastname FROM aether_characters WHERE id = ?', { charakterId }) if not zeilen or not zeilen[1] then return 'unbekannt' end return zeilen[1].firstname .. ' ' .. zeilen[1].lastname end --- Prüft eine Kennung gegen eine Konfigurationsliste --- @param liste table Liste aus Medizin.Config --- @param wert any Eingabe --- @return string|nil Gültige Kennung local function AusListe(liste, wert) local gesucht = tostring(wert or '') for _, eintrag in ipairs(liste) do if eintrag.id == gesucht then return eintrag.id end end return nil end --- Bringt ein Kennzeichen auf eine vergleichbare Schreibweise. --- Das Spiel liefert Kennzeichen mit Leerzeichen aufgefüllt. --- @param wert any Eingabe --- @return string|nil local function Kennzeichen(wert) local sauber = Text(wert, 12) if not sauber then return nil end return sauber:upper() end --- Anzeigename aus einer Konfigurationsliste --- @param liste table Liste aus Medizin.Config --- @param kennung string Kennung --- @return string local function NameAusListe(liste, kennung) for _, eintrag in ipairs(liste) do if eintrag.id == kennung then return eintrag.name end end return tostring(kennung) end --- Lädt ein Fahrzeug --- @param fahrzeugId number Fahrzeug --- @return table|nil local function LadeFahrzeug(fahrzeugId) local zeilen = MySQL.query.await([[ SELECT f.*, TIMESTAMPDIFF(MINUTE, f.gemeldet_am, NOW()) AS meldungAlter FROM medical_fahrzeug f WHERE f.id = ? ]], { fahrzeugId }) return zeilen and zeilen[1] or nil end --- Bereitet die gemeldeten Werte für die Anzeige auf. --- Wichtig ist dabei nicht der Wert allein, sondern sein Alter: eine --- alte Meldung sagt nichts über den jetzigen Zustand. --- @param eintrag table Fahrzeugzeile local function BereiteMeldung(eintrag) eintrag.tank = eintrag.tank and math.floor(tonumber(eintrag.tank) + 0.5) or nil eintrag.zustand = eintrag.zustand and math.floor(tonumber(eintrag.zustand) + 0.5) or nil eintrag.meldungAlter = eintrag.gemeldet_am and (tonumber(eintrag.meldungAlter) or 0) or nil eintrag.meldungVeraltet = eintrag.meldungAlter ~= nil and eintrag.meldungAlter > Medizin.Config.Erinnerungen.fahrzeugMeldungAltNach eintrag.letzterFahrer = eintrag.letzter_fahrer and NameVon(eintrag.letzter_fahrer) or nil eintrag.zugewiesenAn = eintrag.zugewiesen_an and NameVon(eintrag.zugewiesen_an) or nil eintrag.artName = NameAusListe(Medizin.Config.Fahrzeugarten, eintrag.art) eintrag.statusName = NameAusListe(Medizin.Config.Fahrzeugstatus, eintrag.status) eintrag.wartungName = NameAusListe(Medizin.Config.Wartungsstatus, eintrag.wartung) end -- ===================================================================== -- ÜBERSICHT -- ===================================================================== Kern.RegistriereAktion('fahrzeug', 'uebersicht', nil, function(quelle, mitarbeiter, daten) local ordner = tostring(daten.ordner or 'dienst') -- Welche Status gehören in diesen Ordner? local bedingung, werte = nil, {} if ordner == 'werkstatt' then bedingung = "f.status = 'werkstatt' OR f.wartung <> 'ok'" elseif ordner == 'ausser' then bedingung = "f.status = 'ausser_dienst'" else bedingung = "f.status IN ('verfuegbar', 'im_einsatz')" end if daten.art and daten.art ~= '' then bedingung = ('(%s) AND f.art = ?'):format(bedingung) werte[#werte + 1] = tostring(daten.art) end local liste = MySQL.query.await(([[ SELECT f.*, TIMESTAMPDIFF(MINUTE, f.gemeldet_am, NOW()) AS meldungAlter FROM medical_fahrzeug f WHERE %s ORDER BY f.art, f.bezeichnung LIMIT 200 ]]):format(bedingung), werte) or {} for _, eintrag in ipairs(liste) do BereiteMeldung(eintrag) -- Rohdaten der Position bleiben dem Client erspart, ausser als Wegpunkt eintrag.hatPosition = eintrag.pos_x ~= nil and eintrag.pos_y ~= nil end local function Zaehle(sql, parameter) return tonumber(MySQL.scalar.await(sql, parameter)) or 0 end local zaehler = { verfuegbar = Zaehle("SELECT COUNT(*) FROM medical_fahrzeug WHERE status = 'verfuegbar'"), imEinsatz = Zaehle("SELECT COUNT(*) FROM medical_fahrzeug WHERE status = 'im_einsatz'"), werkstatt = Zaehle([[ SELECT COUNT(*) FROM medical_fahrzeug WHERE status = 'werkstatt' OR wartung <> 'ok' ]]), ausserDienst = Zaehle( "SELECT COUNT(*) FROM medical_fahrzeug WHERE status = 'ausser_dienst'"), zugewiesen = Zaehle( 'SELECT COUNT(*) FROM medical_fahrzeug WHERE zugewiesen_an IS NOT NULL'), } return { ordner = ordner, liste = liste, zaehler = zaehler, arten = Medizin.Config.Fahrzeugarten, status = Medizin.Config.Fahrzeugstatus, wartungsstatus = Medizin.Config.Wartungsstatus, stationen = Medizin.Config.Stationen, ausstattung = Medizin.Config.Fahrzeugausstattung, grenzen = { tank = Medizin.Config.Erinnerungen.fahrzeugTankUnter, zustand = Medizin.Config.Erinnerungen.fahrzeugZustandUnter, meldung = Medizin.Config.Erinnerungen.fahrzeugMeldungAltNach, }, rechte = { zuweisen = Rechte.Hat(mitarbeiter, 'fahrzeug.zuweisen'), wartung = Rechte.Hat(mitarbeiter, 'fahrzeug.wartung'), pflegen = Rechte.Hat(mitarbeiter, 'fahrzeug.pflegen'), }, } end) -- ===================================================================== -- EINZELNES FAHRZEUG -- ===================================================================== Kern.RegistriereAktion('fahrzeug', 'oeffnen', nil, function(quelle, mitarbeiter, daten) local fahrzeugId = tonumber(daten.id) if not fahrzeugId then return nil, 'Ungültige Kennung.' end local eintrag = LadeFahrzeug(fahrzeugId) if not eintrag then return nil, 'Fahrzeug nicht gefunden.' end BereiteMeldung(eintrag) -- Der Weg des Fahrzeugs steht im Protokoll und wird nur gelesen local spur = Protokoll.Lies({ zielTyp = 'fahrzeug', zielId = fahrzeugId, limit = 40 }) for _, zeile in ipairs(spur) do zeile.autor = zeile.firstname and (zeile.firstname .. ' ' .. zeile.lastname) or 'System' zeile.firstname, zeile.lastname, zeile.details = nil, nil, nil end return { fahrzeug = { id = eintrag.id, kennzeichen = eintrag.kennzeichen, modell = eintrag.modell, bezeichnung = eintrag.bezeichnung, art = eintrag.art, artName = eintrag.artName, station = eintrag.station, status = eintrag.status, statusName = eintrag.statusName, wartung = eintrag.wartung, wartungName = eintrag.wartungName, ausstattung = eintrag.ausstattung, notiz = eintrag.notiz, tank = eintrag.tank, zustand = eintrag.zustand, gemeldetAm = eintrag.gemeldet_am, meldungAlter = eintrag.meldungAlter, meldungVeraltet = eintrag.meldungVeraltet, letzterFahrer = eintrag.letzterFahrer, zugewiesen = eintrag.zugewiesen_an, zugewiesenAn = eintrag.zugewiesenAn, position = (eintrag.pos_x and eintrag.pos_y) and { x = eintrag.pos_x, y = eintrag.pos_y, z = eintrag.pos_z } or nil, }, spur = spur, arten = Medizin.Config.Fahrzeugarten, status = Medizin.Config.Fahrzeugstatus, wartungsstatus = Medizin.Config.Wartungsstatus, stationen = Medizin.Config.Stationen, ausstattung = Medizin.Config.Fahrzeugausstattung, rechte = { zuweisen = Rechte.Hat(mitarbeiter, 'fahrzeug.zuweisen'), wartung = Rechte.Hat(mitarbeiter, 'fahrzeug.wartung'), pflegen = Rechte.Hat(mitarbeiter, 'fahrzeug.pflegen'), }, } end) -- ===================================================================== -- EINSATZSTATUS -- -- Wird immer eingetragen. Weder Telemetrie noch ein laufender Einsatz -- setzt ihn — auch ein Fahrzeug mit leerem Tank bleibt "verfügbar", -- bis jemand etwas anderes einträgt. -- ===================================================================== Kern.RegistriereAktion('fahrzeug', 'status', 'fahrzeug.zuweisen', function(quelle, mitarbeiter, daten) local fahrzeugId = tonumber(daten.id) if not fahrzeugId then return nil, 'Ungültige Kennung.' end local neu = AusListe(Medizin.Config.Fahrzeugstatus, daten.status) if not neu then return nil, 'Unbekannter Fahrzeugstatus.' end local eintrag = LadeFahrzeug(fahrzeugId) if not eintrag then return nil, 'Fahrzeug nicht gefunden.' end -- Ein Fahrzeug aus dem Dienst zu nehmen ist Sache der Wartung if (neu == 'werkstatt' or neu == 'ausser_dienst') and not Rechte.Hat(mitarbeiter, 'fahrzeug.wartung') then return nil, 'Fahrzeuge aus dem Dienst nehmen darf nur, wer die Wartung führt.' end local grund = Text(daten.grund, 255) if (neu == 'werkstatt' or neu == 'ausser_dienst') and not grund then return nil, 'Bitte angeben, warum das Fahrzeug nicht mehr fährt.' end MySQL.update.await('UPDATE medical_fahrzeug SET status = ? WHERE id = ?', { neu, fahrzeugId }) Protokoll.Schreibe(mitarbeiter, 'fahrzeug', 'Fahrzeugstatus gesetzt', { typ = 'fahrzeug', id = fahrzeugId }, { kennzeichen = eintrag.kennzeichen, bezeichnung = eintrag.bezeichnung, von = eintrag.status, nach = neu }, grund) -- Ein Fahrzeug, das jemandem zugewiesen war, geht nicht stillschweigend if (neu == 'werkstatt' or neu == 'ausser_dienst') and eintrag.zugewiesen_an then Hinweise.Erstelle({ charakterId = eintrag.zugewiesen_an }, { kategorie = 'system', prioritaet = 'normal', titel = 'Dein Fahrzeug wurde aus dem Dienst genommen', text = ('%s (%s) — %s.'):format(eintrag.bezeichnung, eintrag.kennzeichen, grund or 'ohne weitere Angabe'), zielTyp = 'fahrzeug', zielId = fahrzeugId, }) end Kern.Loese('fahrzeug.status', fahrzeugId, neu, mitarbeiter) return { ok = true } end) -- ===================================================================== -- ZUWEISUNG -- -- Ein Fahrzeug wird jemandem zugeteilt oder freigegeben. Das öffnet -- keine Tür, gibt keinen Schlüssel aus und spawnt nichts. -- ===================================================================== --- Wer ist gerade im Dienst? Kern.RegistriereAktion('fahrzeug', 'kollegen', 'fahrzeug.zuweisen', function(quelle, mitarbeiter, daten) local liste = {} for _, eintrag in pairs(Dienst.AlleImDienst()) do liste[#liste + 1] = { charakterId = eintrag.charakterId, name = eintrag.name, rolleName = eintrag.rolleName, personalnummer = eintrag.personalnummer, funktion = eintrag.funktion, status = eintrag.status, selbst = eintrag.charakterId == mitarbeiter.charakterId, } end table.sort(liste, function(a, b) return tostring(a.personalnummer) < tostring(b.personalnummer) end) return { liste = liste } end) Kern.RegistriereAktion('fahrzeug', 'zuweisen', 'fahrzeug.zuweisen', function(quelle, mitarbeiter, daten) local fahrzeugId = tonumber(daten.id) if not fahrzeugId then return nil, 'Ungültige Kennung.' end local eintrag = LadeFahrzeug(fahrzeugId) if not eintrag then return nil, 'Fahrzeug nicht gefunden.' end -- Ohne Ziel wird die Zuweisung aufgehoben local zielId = tonumber(daten.charakter) if zielId then if eintrag.status == 'werkstatt' or eintrag.status == 'ausser_dienst' then return nil, ('%s steht auf "%s" und lässt sich nicht zuweisen.') :format(eintrag.bezeichnung, eintrag.statusName or eintrag.status) end local zielQuelle = Dienst.QuelleVonCharakter(zielId) if not zielQuelle or not Dienst.Hole(zielQuelle) then return nil, 'Diese Person ist nicht im Dienst.' end -- Ein Fahrzeug gehört immer nur einer Person if eintrag.zugewiesen_an and eintrag.zugewiesen_an ~= zielId then local vorher = NameVon(eintrag.zugewiesen_an) if not Text(daten.grund, 255) then return nil, ('%s ist bereits %s zugewiesen — bitte einen Grund angeben.') :format(eintrag.bezeichnung, vorher) end end else local grund = Text(daten.grund, 255) if not grund then return nil, 'Bitte angeben, warum die Zuweisung entfällt.' end end MySQL.update.await('UPDATE medical_fahrzeug SET zugewiesen_an = ? WHERE id = ?', { zielId, fahrzeugId }) Protokoll.Schreibe(mitarbeiter, 'fahrzeug', zielId and 'Fahrzeug zugewiesen' or 'Zuweisung aufgehoben', { typ = 'fahrzeug', id = fahrzeugId }, { kennzeichen = eintrag.kennzeichen, bezeichnung = eintrag.bezeichnung, vorher = eintrag.zugewiesen_an, nachher = zielId }, Text(daten.grund, 255)) -- Die betroffene Person erfährt es unmittelbar if zielId and zielId ~= mitarbeiter.charakterId then Hinweise.Erstelle({ charakterId = zielId }, { kategorie = 'system', prioritaet = 'normal', titel = 'Dir wurde ein Fahrzeug zugewiesen', text = ('%s (%s) — von %s.'):format(eintrag.bezeichnung, eintrag.kennzeichen, mitarbeiter.name), zielTyp = 'fahrzeug', zielId = fahrzeugId, }) end -- Wer es vorher hatte, ebenfalls if eintrag.zugewiesen_an and eintrag.zugewiesen_an ~= zielId and eintrag.zugewiesen_an ~= mitarbeiter.charakterId then Hinweise.Erstelle({ charakterId = eintrag.zugewiesen_an }, { kategorie = 'system', prioritaet = 'normal', titel = 'Deine Fahrzeugzuweisung wurde geändert', text = ('%s (%s) ist dir nicht mehr zugewiesen.') :format(eintrag.bezeichnung, eintrag.kennzeichen), zielTyp = 'fahrzeug', zielId = fahrzeugId, }) end Kern.Loese('fahrzeug.zugewiesen', fahrzeugId, zielId, mitarbeiter) return { ok = true } end) -- ===================================================================== -- WARTUNG -- -- Der Wartungsstatus ist eine Beurteilung. Ein gemeldeter Schaden -- setzt ihn nicht — er erinnert nur daran, hinzusehen. -- ===================================================================== Kern.RegistriereAktion('fahrzeug', 'wartung', 'fahrzeug.wartung', function(quelle, mitarbeiter, daten) local fahrzeugId = tonumber(daten.id) if not fahrzeugId then return nil, 'Ungültige Kennung.' end local neu = AusListe(Medizin.Config.Wartungsstatus, daten.wartung) if not neu then return nil, 'Unbekannter Wartungsstatus.' end local eintrag = LadeFahrzeug(fahrzeugId) if not eintrag then return nil, 'Fahrzeug nicht gefunden.' end -- Ein leeres Feld löscht die Notiz, ein fehlendes lässt sie stehen local notiz = eintrag.notiz if daten.notiz ~= nil then notiz = Text(daten.notiz, 255) end MySQL.update.await('UPDATE medical_fahrzeug SET wartung = ?, notiz = ? WHERE id = ?', { neu, notiz, fahrzeugId }) Protokoll.Schreibe(mitarbeiter, 'fahrzeug', 'Wartungsstatus gesetzt', { typ = 'fahrzeug', id = fahrzeugId }, { kennzeichen = eintrag.kennzeichen, von = eintrag.wartung, nach = neu }, notiz) -- Fällige Wartung meldet das Haus, damit niemand ahnungslos losfährt if neu ~= 'ok' and eintrag.wartung == 'ok' then Hinweise.Erstelle(nil, { kategorie = 'system', prioritaet = 'normal', titel = ('Wartung eingetragen · %s'):format(eintrag.bezeichnung), text = ('%s (%s) — %s.'):format(eintrag.bezeichnung, eintrag.kennzeichen, NameAusListe(Medizin.Config.Wartungsstatus, neu)), zielTyp = 'fahrzeug', zielId = fahrzeugId, }) end Kern.Loese('fahrzeug.wartung', fahrzeugId, neu, mitarbeiter) return { ok = true } end) -- ===================================================================== -- FUHRPARK PFLEGEN -- ===================================================================== Kern.RegistriereAktion('fahrzeug', 'speichern', 'fahrzeug.pflegen', function(quelle, mitarbeiter, daten) local fahrzeugId = tonumber(daten.id) local kennzeichen = Kennzeichen(daten.kennzeichen) local modell = Text(daten.modell, 48) local bezeichnung = Text(daten.bezeichnung, 64) local art = AusListe(Medizin.Config.Fahrzeugarten, daten.art) if not kennzeichen then return nil, 'Bitte ein Kennzeichen angeben.' end if not modell then return nil, 'Bitte das Fahrzeugmodell angeben.' end if not bezeichnung then return nil, 'Bitte eine Bezeichnung angeben, z. B. RTW 1.' end if not art then return nil, 'Unbekannte Fahrzeugart.' end -- Kennzeichen müssen eindeutig bleiben: die Telemetrie findet das -- Fahrzeug ausschliesslich darüber wieder. local kollision = MySQL.scalar.await( 'SELECT id FROM medical_fahrzeug WHERE kennzeichen = ? AND id <> ?', { kennzeichen, fahrzeugId or 0 }) if kollision then return nil, ('Das Kennzeichen %s ist bereits vergeben.'):format(kennzeichen) end -- Eine Station ist freiwillig, muss aber eine bekannte sein local station = nil if Text(daten.station, 32) then station = AusListe(Medizin.Config.Stationen, daten.station) if not station then return nil, 'Unbekannte Station.' end end local ausstattung = Text(daten.ausstattung, 512) if fahrzeugId then local vorher = LadeFahrzeug(fahrzeugId) if not vorher then return nil, 'Fahrzeug nicht gefunden.' end MySQL.update.await([[ UPDATE medical_fahrzeug SET kennzeichen = ?, modell = ?, bezeichnung = ?, art = ?, station = ?, ausstattung = ? WHERE id = ? ]], { kennzeichen, modell, bezeichnung, art, station, ausstattung, fahrzeugId }) Protokoll.Schreibe(mitarbeiter, 'fahrzeug', 'Fahrzeug bearbeitet', { typ = 'fahrzeug', id = fahrzeugId }, { kennzeichen = kennzeichen, bezeichnung = bezeichnung, art = art, vorherigesKennzeichen = vorher.kennzeichen }) else fahrzeugId = MySQL.insert.await([[ INSERT INTO medical_fahrzeug (kennzeichen, modell, bezeichnung, art, station, ausstattung) VALUES (?, ?, ?, ?, ?, ?) ]], { kennzeichen, modell, bezeichnung, art, station, ausstattung }) Protokoll.Schreibe(mitarbeiter, 'fahrzeug', 'Fahrzeug aufgenommen', { typ = 'fahrzeug', id = fahrzeugId }, { kennzeichen = kennzeichen, bezeichnung = bezeichnung, art = art }) end Kern.Loese('fahrzeug.geaendert', fahrzeugId, mitarbeiter) return { id = fahrzeugId } end) --- Entfernt ein Fahrzeug endgültig. --- Möglich erst, wenn es ausser Dienst steht — ausmustern ist ein --- eigener Schritt und keine Nebenwirkung des Löschens. Kern.RegistriereAktion('fahrzeug', 'entfernen', 'fahrzeug.pflegen', function(quelle, mitarbeiter, daten) local fahrzeugId = tonumber(daten.id) if not fahrzeugId then return nil, 'Ungültige Kennung.' end local grund = Text(daten.grund, 255) if not grund then return nil, 'Bitte einen Grund angeben.' end local eintrag = LadeFahrzeug(fahrzeugId) if not eintrag then return nil, 'Fahrzeug nicht gefunden.' end if eintrag.status ~= 'ausser_dienst' then return nil, 'Nur ein Fahrzeug außer Dienst lässt sich aus dem Fuhrpark nehmen.' end MySQL.query.await('DELETE FROM medical_fahrzeug WHERE id = ?', { fahrzeugId }) Protokoll.Schreibe(mitarbeiter, 'fahrzeug', 'Fahrzeug aus dem Fuhrpark genommen', { typ = 'fahrzeug', id = fahrzeugId }, { kennzeichen = eintrag.kennzeichen, bezeichnung = eintrag.bezeichnung }, grund) Kern.Loese('fahrzeug.geaendert', fahrzeugId, mitarbeiter) return { ok = true } end) -- ===================================================================== -- TELEMETRIE -- -- Der Client meldet, was das Spiel hergibt, solange jemand fährt. -- Hier landen ausschliesslich Tatsachen — kein gemeldeter Wert ändert -- Status, Wartung oder Zuweisung. Wer daraus etwas ableitet, ist ein -- Mensch. -- ===================================================================== RegisterNetEvent('aether:medical:fahrzeugMelden', function(meldung) local quelle = source -- Nur wer im Dienst ist, meldet für den Fuhrpark local mitarbeiter = Dienst.Hole(quelle) if not mitarbeiter then return end if type(meldung) ~= 'table' then return end local kennzeichen = Kennzeichen(meldung.kennzeichen) if not kennzeichen then return end -- Fremde Fahrzeuge werden stillschweigend verworfen local fahrzeug = MySQL.query.await( 'SELECT id FROM medical_fahrzeug WHERE kennzeichen = ?', { kennzeichen }) if not fahrzeug or not fahrzeug[1] then return end --- Bringt einen gemeldeten Wert auf 0 bis 100 --- @param wert any Rohwert aus dem Spiel --- @param spanne number Wertebereich, den das Spiel liefert --- @return number|nil local function Prozent(wert, spanne) local zahl = tonumber(wert) if not zahl then return nil end local anteil = (zahl / spanne) * 100 return math.max(0, math.min(100, anteil)) end MySQL.update.await([[ UPDATE medical_fahrzeug SET tank = ?, zustand = ?, pos_x = ?, pos_y = ?, pos_z = ?, letzter_fahrer = ?, gemeldet_am = NOW() WHERE id = ? ]], { Prozent(meldung.tank, 100), -- Tankstand kommt bereits als Prozent Prozent(meldung.zustand, 1000), -- Karosseriezustand reicht von 0 bis 1000 tonumber(meldung.x), tonumber(meldung.y), tonumber(meldung.z), mitarbeiter.charakterId, fahrzeug[1].id, }) end) -- --------------------------------------------------------------------- -- Schnittstelle für andere Ressourcen -- --------------------------------------------------------------------- --- Liefert den Fuhrpark als Auskunft. --- Reine Anzeige — keine Ressource kann darüber ein Fahrzeug zuweisen, --- seinen Status setzen oder es in die Werkstatt schicken. --- @param nurVerfuegbar boolean|nil Nur einsatzbereite Fahrzeuge --- @return table Liste exports('HoleFuhrpark', function(nurVerfuegbar) local bedingung = nurVerfuegbar and "WHERE status = 'verfuegbar' AND wartung = 'ok'" or '' local zeilen = MySQL.query.await(([[ SELECT kennzeichen, bezeichnung, art, station, status, wartung, tank, zustand, gemeldet_am FROM medical_fahrzeug %s ORDER BY art, bezeichnung ]]):format(bedingung)) or {} return zeilen end)