Zurück zum Blog
Guide10 Min. Lesezeit

FiveM Gerichts- und Rechtssystem: Skript für realistische Verhandlungen

Füge deinem FiveM-Server ein Gerichtssystem hinzu. Mit Richterwerkzeugen, Anwaltrollen, Beweisoberflächen und Skripten für intensives Rollenspiel.

Agency Scripts

Gründer und leitender Entwickler bei Agency Scripts

Architektur des Rechtssystems

Ein Gerichts- und Rechtssystem hebt einen FiveM-Rollenspielserver von einfachem Räuber-und-Gendarm-Spiel zu einer strukturierten Gesellschaft, in der Gesetze Gewicht haben und Konsequenzen einem ordnungsgemäßen Verfahren folgen. Das System umfasst Haftbefehle, mit denen die Polizei Durchsuchungen und Festnahmen genehmigt, einen Ablauf für Gerichtsverhandlungen, in dem Fälle einem Richter vorgelegt werden, Verteidigungs- und Anklagerollen für Anwälte, ein Beweismittelverwaltungssystem zur Erfassung physischer und digitaler Beweise sowie einen Strafrahmen für Geldstrafen, Haft und alternative Strafen. Im Zentrum der Architektur steht eine Fallverwaltungsdatenbank, die jedes Verfahren von der ersten Anklage über die Anklageverlesung und den Prozess bis zum Urteil erfasst. Jeder Fall ist mit den beteiligten Parteien, ihren Rollen, den eingereichten Beweisen und dem endgültigen Ausgang verknüpft. Diese Daten bleiben dauerhaft gespeichert und bilden eine Rechtshistorie des Servers, auf die sich Spieler und Amtsträger bei künftigen Verfahren beziehen können.

Datenbankschema für Rechtsakten

Deine Datenbank muss Haftbefehle, Gerichtsverfahren, Beweismittel und Rechtsakten verwalten können. Das Schema verknüpft polizeiliche Ermittlungen über ein gemeinsames Beweismittelsystem mit Gerichtsverfahren. So werden bei einer Ermittlung gesammelte Gegenstände zu Beweisstücken, die im Prozess vorgelegt werden. Entwirf die Tabellen so, dass sie einen vollständigen Prüfpfad aller Handlungen in einem Rechtsverfahren sicherstellen:

CREATE TABLE IF NOT EXISTS warrants (
    id INT AUTO_INCREMENT PRIMARY KEY,
    type ENUM('arrest', 'search', 'bench') NOT NULL,
    target_citizenid VARCHAR(50) NOT NULL,
    target_name VARCHAR(100) NOT NULL,
    reason TEXT NOT NULL,
    issued_by VARCHAR(50) NOT NULL,
    approved_by VARCHAR(50) DEFAULT NULL,
    status ENUM('pending', 'active', 'executed', 'expired', 'revoked') DEFAULT 'pending',
    issued_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    expires_at TIMESTAMP NULL,
    executed_at TIMESTAMP NULL,
    INDEX idx_target (target_citizenid),
    INDEX idx_status (status)
);

CREATE TABLE IF NOT EXISTS court_cases (
    id INT AUTO_INCREMENT PRIMARY KEY,
    case_number VARCHAR(20) UNIQUE NOT NULL,
    defendant_citizenid VARCHAR(50) NOT NULL,
    defendant_name VARCHAR(100) NOT NULL,
    prosecutor_citizenid VARCHAR(50) DEFAULT NULL,
    defense_citizenid VARCHAR(50) DEFAULT NULL,
    judge_citizenid VARCHAR(50) DEFAULT NULL,
    charges TEXT NOT NULL,
    status ENUM('filed', 'arraignment', 'pretrial', 'trial', 'verdict', 'closed', 'dismissed') DEFAULT 'filed',
    plea ENUM('not_guilty', 'guilty', 'no_contest') DEFAULT NULL,
    verdict ENUM('guilty', 'not_guilty', 'mistrial', 'dismissed') DEFAULT NULL,
    sentence TEXT DEFAULT NULL,
    fine_amount INT DEFAULT 0,
    jail_minutes INT DEFAULT 0,
    filed_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    hearing_scheduled TIMESTAMP NULL,
    closed_at TIMESTAMP NULL,
    INDEX idx_defendant (defendant_citizenid),
    INDEX idx_status (status)
);

CREATE TABLE IF NOT EXISTS evidence (
    id INT AUTO_INCREMENT PRIMARY KEY,
    case_id INT DEFAULT NULL,
    type ENUM('physical', 'digital', 'testimony', 'document', 'photo') NOT NULL,
    label VARCHAR(200) NOT NULL,
    description TEXT DEFAULT NULL,
    collected_by VARCHAR(50) NOT NULL,
    collected_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    chain_of_custody TEXT DEFAULT NULL,
    is_admitted BOOLEAN DEFAULT FALSE,
    FOREIGN KEY (case_id) REFERENCES court_cases(id)
);

CREATE TABLE IF NOT EXISTS legal_records (
    id INT AUTO_INCREMENT PRIMARY KEY,
    citizenid VARCHAR(50) NOT NULL,
    record_type ENUM('conviction', 'acquittal', 'fine', 'warning', 'restraining_order') NOT NULL,
    description TEXT NOT NULL,
    case_id INT DEFAULT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    expunged BOOLEAN DEFAULT FALSE,
    INDEX idx_citizen (citizenid),
    FOREIGN KEY (case_id) REFERENCES court_cases(id)
);

Haftbefehlssystem

Haftbefehle bilden die rechtliche Grundlage für Maßnahmen der Polizei im Anschluss an Ermittlungen. Ein Haftbefehl ermächtigt Beamte, eine bestimmte Person festzunehmen, ein Durchsuchungsbeschluss erlaubt die Durchsuchung eines Grundstücks oder Fahrzeugs und ein Vorführungsbefehl wird von einem Richter ausgestellt, wenn jemand nicht vor Gericht erscheint. Polizeibeamte stellen Haftbefehlsanträge über das MDT, die dann zur gerichtlichen Prüfung in eine Warteschlange gelangen. Ein Richter oder eine autorisierte Amtsperson prüft den Antrag, begutachtet die Beschreibung des wahrscheinlichen Grundes und genehmigt oder lehnt ihn ab. Genehmigte Haftbefehle werden aktiv und erscheinen im Polizei-MDT, wenn Beamte mit der betroffenen Person interagieren. So werden sie darauf hingewiesen, dass ein Haftbefehl vorliegt. Sorge dafür, dass Haftbefehle ablaufen und nicht unbegrenzt gültig bleiben: Haftbefehle gelten 7 reale Tage, Durchsuchungsbeschlüsse 48 Stunden ab ihrer Genehmigung:

-- Warrant request by police
RegisterNetEvent('legal:server:requestWarrant', function(data)
    local src = source
    local Officer = QBCore.Functions.GetPlayer(src)
    if not Officer or Officer.PlayerData.job.name ~= 'police' then return end

    local warrant = {
        type = data.type,
        target_citizenid = data.targetCitizenid,
        target_name = data.targetName,
        reason = data.reason,
        issued_by = Officer.PlayerData.citizenid,
    }

    local id = MySQL.insert.await(
        'INSERT INTO warrants (type, target_citizenid, target_name, reason, issued_by) VALUES (?, ?, ?, ?, ?)',
        { warrant.type, warrant.target_citizenid, warrant.target_name, warrant.reason, warrant.issued_by }
    )

    -- Notify judges
    local players = QBCore.Functions.GetQBPlayers()
    for _, player in pairs(players) do
        if player.PlayerData.job.name == 'judge' then
            TriggerClientEvent('legal:client:warrantPending', player.PlayerData.source, {
                id = id,
                type = warrant.type,
                targetName = warrant.target_name,
                reason = warrant.reason,
                officerName = Officer.PlayerData.charinfo.firstname .. ' ' .. Officer.PlayerData.charinfo.lastname,
            })
        end
    end

    TriggerClientEvent('QBCore:Notify', src, 'Warrant request submitted for judicial review', 'success')
end)

-- Judge approval
RegisterNetEvent('legal:server:approveWarrant', function(warrantId)
    local src = source
    local Judge = QBCore.Functions.GetPlayer(src)
    if not Judge or Judge.PlayerData.job.name ~= 'judge' then return end

    local warrant = MySQL.single.await('SELECT * FROM warrants WHERE id = ? AND status = "pending"', { warrantId })
    if not warrant then return end

    local expiryHours = warrant.type == 'search' and 48 or 168
    local expiresAt = os.date('!%Y-%m-%d %H:%M:%S', os.time() + (expiryHours * 3600))

    MySQL.update('UPDATE warrants SET status = "active", approved_by = ?, expires_at = ? WHERE id = ?',
        { Judge.PlayerData.citizenid, expiresAt, warrantId })

    -- Notify requesting officer if online
    TriggerClientEvent('QBCore:Notify', src, 'Warrant #' .. warrantId .. ' approved', 'success')
end)

Ablauf einer Gerichtsverhandlung

Gerichtsverhandlungen folgen einem strukturierten Ablauf, der Fälle über Anklageverlesung, vorgerichtliche Anträge, Verhandlung und Urteilsverkündung führt. Wird ein Fall eingereicht, generiert das System eine eindeutige Fallnummer und weist ihm den Status „eingereicht“ zu. Ein Richter prüft den Fall und setzt eine Anklageverlesung an, bei der der Angeklagte sein Plädoyer abgibt. Plädiert der Angeklagte auf nicht schuldig, geht der Fall in die vorgerichtliche Phase über, in der Anwälte Anträge und Beweise einreichen können, und anschließend in die Verhandlung, in der beide Seiten ihre Argumente vorbringen. Der Richter steuert den Ablauf der Verhandlung über Befehle, die den Fallstatus aktualisieren und UI-Aktualisierungen für alle Beteiligten auslösen. Implementiere eine NUI für den Gerichtssaal, die Fallinformationen und die aktuelle Phase anzeigt und rollenspezifische Steuerelemente für Richter, Staatsanwalt und Verteidiger bereitstellt. Der Richter erhält Schaltflächen für den Urteilsspruch und Eingabefelder für das Strafmaß, während Anwälte Schaltflächen für Einsprüche und Steuerelemente zur Beweispräsentation erhalten.

Anwaltsrolle und Verteidigungssystem

Der Anwaltsjob schafft einen vollständigen Karriereweg auf dem Server mit eigenen Gameplay-Mechaniken. Angeklagte können Verteidiger über ein Anwaltsverzeichnis engagieren, das vom Gefängnis oder über die Telefon-App zugänglich ist. Nimmt ein Anwalt einen Mandanten an, erhält er im Rechtssystem Zugriff auf die Fallakte, einschließlich aller von der Staatsanwaltschaft eingereichten Beweise. Anwälte können Anträge auf Ausschluss von Beweisen stellen, eine Vertagung beantragen, um Verhandlungen aufzuschieben, mit dem Staatsanwalt Strafvereinbarungen aushandeln und während der Verhandlung eigene Beweise und Zeugenaussagen vorlegen. Implementiere ein Anwaltsexamensystem, bei dem neue Anwalt-Charaktere einen Wissenstest bestehen müssen, bevor sie den Anwaltsjob erhalten. So wird eine Mindestqualität beim juristischen Roleplay sichergestellt. Erfasse Anwaltstatistiken wie gewonnene und verlorene Fälle sowie die durchschnittliche Strafminderung für ihre Mandanten. Dadurch entsteht ein wettbewerbsfähiger Markt, auf dem etablierte Anwälte höhere Honorare verlangen können:

Config.LawyerSystem = {
    barExamQuestions = 15,
    passingScore = 11,       -- 73% to pass
    examCooldown = 86400,    -- 24 hours between attempts
    maxActiveClients = 5,
    consultationFee = 500,   -- base fee for initial consultation
    trialFeeRange = { min = 2000, max = 25000 },

    motionTypes = {
        { id = 'suppress_evidence', label = 'Motion to Suppress Evidence', description = 'Request exclusion of illegally obtained evidence' },
        { id = 'dismiss_charges', label = 'Motion to Dismiss', description = 'Request dismissal due to insufficient evidence' },
        { id = 'continuance', label = 'Motion for Continuance', description = 'Request to postpone the hearing' },
        { id = 'change_venue', label = 'Motion for Change of Venue', description = 'Request trial at different location' },
        { id = 'bail_reduction', label = 'Motion for Bail Reduction', description = 'Request lower bail amount' },
        { id = 'expungement', label = 'Motion for Expungement', description = 'Request to clear prior conviction' },
    },
}

-- Hire a lawyer from jail
RegisterNetEvent('legal:server:hireLawyer', function(lawyerCitizenid)
    local src = source
    local Player = QBCore.Functions.GetPlayer(src)
    if not Player then return end

    local citizenid = Player.PlayerData.citizenid

    -- Find active case for this player
    local activeCase = MySQL.single.await(
        'SELECT * FROM court_cases WHERE defendant_citizenid = ? AND status NOT IN ("closed", "dismissed") ORDER BY filed_at DESC LIMIT 1',
        { citizenid }
    )
    if not activeCase then
        TriggerClientEvent('QBCore:Notify', src, 'No active case found', 'error')
        return
    end

    -- Assign lawyer to case
    MySQL.update('UPDATE court_cases SET defense_citizenid = ? WHERE id = ?',
        { lawyerCitizenid, activeCase.id })

    -- Notify lawyer
    local lawyerPlayer = QBCore.Functions.GetPlayerByCitizenId(lawyerCitizenid)
    if lawyerPlayer then
        TriggerClientEvent('QBCore:Notify', lawyerPlayer.PlayerData.source,
            'New client: ' .. Player.PlayerData.charinfo.firstname .. ' ' .. Player.PlayerData.charinfo.lastname ..
            ' | Case #' .. activeCase.case_number, 'success')
    end

    TriggerClientEvent('QBCore:Notify', src, 'Attorney assigned to your case', 'success')
end)

Beweisverwaltungssystem

Das Beweissystem bildet eine lückenlose Beweismittelkette von der Tatortuntersuchung bis zur Präsentation vor Gericht ab. Sammelt die Polizei an einem Tatort mithilfe eines Beweismittel-Befehls Beweise, erstellt das System einen Beweismitteldatensatz mit der Identität des sammelnden Beamten sowie Zeitstempel und Fundort. Jedes Beweismittel erhält eine eindeutige Kennung, die während des gesamten juristischen Verfahrens erhalten bleibt. Zu den Beweisarten gehören physische Gegenstände wie Waffen, Drogen und Kleidung, digitale Beweise wie Telefonprotokolle und CCTV-Aufnahmen, als Texteingaben aufgezeichnete Zeugenaussagen sowie Dokumente wie Finanzunterlagen oder gefälschte Ausweise. Anwälte können die Zulässigkeit von Beweisen durch Anträge anfechten, die die Art der Sicherstellung oder die Beweismittelkette infrage stellen. Der Richter prüft diese Anträge und kann Beweise als unzulässig markieren, wodurch sie aus der Fallakte entfernt werden. Implementiere auf der Polizeiwache einen Beweismittelschrank, in dem physische Beweisstücke gelagert werden. Integriere dafür das Inventarsystem, um die bei Ermittlungen tatsächlich sichergestellten Gegenstände zu erfassen.

Straf- und Kautionsmechaniken

Strafen und Kautionen schaffen wirtschaftliche Konsequenzen innerhalb des Rechtssystems. Bei der Anklageverlesung setzt der Richter die Kautionssumme anhand der Schwere der Vorwürfe und der kriminellen Vorgeschichte des Angeklagten fest. Der Angeklagte kann die Kaution über das Gerichtssystem zahlen und bis zur Verhandlung aus der Haft entlassen werden oder bis zur Anhörung im Gefängnis bleiben. Bei der Kautionszahlung wird der Betrag vom Bankkonto des Spielers abgebucht und nach Abschluss des Falls zurückerstattet, wenn der Angeklagte an allen Anhörungen teilgenommen hat. Erscheint der Angeklagte nicht, verfällt die Kaution und es wird ein Haftbefehl erlassen. Geldstrafen werden im Rahmen des Strafmaßes verhängt und müssen innerhalb einer festgelegten Frist bezahlt werden. Auf unbezahlte Geldstrafen fallen Zinsen an. Sie können außerdem weitere rechtliche Konsequenzen nach sich ziehen, etwa den Entzug des Führerscheins oder eine Pfändung von Eigentum. Implementiere für hohe Geldstrafen ein Ratenzahlungssystem, über das der Angeklagte wöchentliche Teilzahlungen leisten kann, statt den gesamten Betrag auf einmal zu zahlen. Dadurch entsteht eine dauerhafte finanzielle Verpflichtung, die das Rechtssystem im Alltag der Spieler auf dem Server relevant hält.

Richterbefehle und Strafmaß

Richter benötigen ein umfassendes Befehlssystem, um Gerichtsverfahren zu leiten und das Rechtssystem durchzusetzen. Zu den grundlegenden Befehlen gehören /case zum Anzeigen und Verwalten von Fällen, /warrant zum Genehmigen oder Ablehnen von Haftbefehlsanträgen, /sentence zum Verhängen von Haftstrafen und Geldstrafen, /bail zum Festlegen von Kautionssummen, /gag zum Stummschalten störender Spieler während Verhandlungen und /contempt zum Inhaftieren von Spielern, die das Gericht missachten. Der Befehl für das Strafmaß sollte auf eine Strafgesetzbuch-Konfiguration zugreifen, die für jede Anklage Mindest- und Höchststrafen festlegt und so für einheitliche Entscheidungen verschiedener Richter sorgt. Implementiere ein System für Strafzumessungsrichtlinien, das anhand der Anklagen und der kriminellen Vorgeschichte des Angeklagten angemessene Strafen vorschlägt, Richtern aber weiterhin erlaubt, begründet davon abzuweichen. Speichere alle gerichtlichen Entscheidungen in der Tabelle für Rechtsakten, damit auf dem Server ein Präzedenzbestand entsteht, auf den erfahrene Spieler in künftigen Verfahren zurückgreifen können. Füge ein Verfahren zur Überprüfung von Urteilen hinzu, bei dem Strafen bei einem höherrangigen Richter oder einem Gremium angefochten werden können. So entstehen weitere Ebenen des juristischen Roleplays für engagierte Spieler.

Integration mit Polizei, Gefängnis und MDT

Das Rechtssystem muss nahtlos in bestehende Polizei-, Gefängnis- und MDT-Ressourcen integriert werden, damit ein durchgängiger Ablauf der Strafverfolgung entsteht. Reicht die Polizei über das MDT Anklage ein, sollte das System automatisch einen Gerichtsfall mit der passenden Fallnummer erstellen und alle bereits während der Ermittlungen gesammelten Beweise verknüpfen. Verurteilt ein Richter einen Angeklagten zu einer Haftstrafe, sollte das System direkt die Export-Funktion zum Inhaftieren der Gefängnis-Ressource aufrufen, damit die Strafe automatisch umgesetzt wird und kein Polizeibeamter manuell einen Haftbefehl ausführen muss. Aktive Haftbefehle sollten im MDT der Polizei erscheinen, wenn Beamte nach einem Bürger suchen. Dabei müssen Haftbefehlstyp, ausstellende Behörde und Ablaufdatum klar angezeigt werden. Strafregistereinträge aus Gerichtsurteilen sollten im MDT im Profil des Bürgers abrufbar sein und dessen vollständige Rechtsgeschichte mit Verurteilungen, Freisprüchen, laufenden Fällen und offenen Geldstrafen anzeigen. Exportiere alle Funktionen des Rechtssystems, damit andere Ressourcen den Status von Haftbefehlen abfragen, Anwaltszulassungen überprüfen, Strafregister einsehen und programmgesteuert mit dem Gerichtssystem interagieren können.

Bereit loszulegen?

Hol dir die Scripts in unserem Shop, oder komm auf den Discord für Support, Updates und einen Blick auf das, was kommt.