Wróć do bloga
Guide10 min czytania

System sądowy i prawny FiveM: oskryptuj realistyczne procesy

Dodaj działający system sądowy do swojego serwera FiveM. Narzędzia sędziowskie, role prawników, interfejsy dowodów i najlepsze skrypty systemu prawnego do głębokiego roleplayu.

Agency Scripts

Założyciel i główny deweloper w Agency Scripts

Architektura systemu prawnego

System sądowy i prawny wynosi serwer roleplay FiveM ponad zwykłą zabawę w policjantów i złodziei, tworząc zorganizowane społeczeństwo, w którym prawo ma znaczenie, a konsekwencje wynikają z procedur prawnych. System obejmuje nakazy używane przez policję do autoryzacji przeszukań i aresztowań, proces rozpraw sądowych z prezentacją spraw przed sędzią, role obrońców i oskarżycieli dla prawników, system zarządzania dowodami śledzący dowody fizyczne i cyfrowe oraz zasady wymierzania kar takich jak grzywny, więzienie i kary alternatywne. Architektura opiera się na bazie danych spraw, która rejestruje każde postępowanie od postawienia zarzutów, przez postawienie w stan oskarżenia, proces, aż po wyrok. Każda sprawa jest powiązana ze stronami, ich rolami, przedstawionymi dowodami i ostatecznym wynikiem. Dane te są trwale zapisywane, budując historię prawną serwera, do której gracze i urzędnicy mogą odwoływać się w przyszłych postępowaniach.

Schemat bazy danych dla kartotek prawnych

Twoja baza danych musi obsługiwać nakazy, sprawy sądowe, dowody i akta prawne. Schemat łączy śledztwa policyjne z postępowaniami sądowymi poprzez wspólny system dowodów, w którym przedmioty zebrane podczas dochodzenia stają się materiałem dowodowym na rozprawie. Zaprojektuj tabele tak, aby zachować pełną ścieżkę audytu każdego działania podjętego w postępowaniu prawnym:

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)
);

System nakazów

Nakazy są prawnym pomostem między śledztwem policyjnym a działaniem. Nakaz aresztowania upoważnia funkcjonariuszy do zatrzymania konkretnej osoby, nakaz przeszukania pozwala na przeszukanie posiadłości lub pojazdu, a nakaz doprowadzenia jest wydawany przez sędziego, gdy ktoś nie stawi się w sądzie. Funkcjonariusze policji tworzą wnioski o nakaz przez MDT, które trafiają do kolejki oczekujących na weryfikację sądową. Sędzia lub upoważniony urzędnik sprawdza wniosek, analizuje opis uzasadnionego podejrzenia i zatwierdza go lub odrzuca. Zatwierdzone nakazy stają się aktywne i pojawiają się w policyjnym MDT, gdy funkcjonariusze wchodzą w interakcję z daną osobą, informując ich o istnieniu nakazu. Zaimplementuj wygasanie nakazów, aby nie trwały wiecznie, z nakazami aresztowania trwającymi 7 rzeczywistych dni i nakazami przeszukania trwającymi 48 godzin od zatwierdzenia:

-- 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)

Przebieg rozprawy sądowej

Rozprawy sądowe opierają się na ustrukturyzowanym procesie, który prowadzi sprawę przez postawienie w stan oskarżenia, wnioski przedprocesowe, proces i wydanie wyroku. Gdy sprawa zostaje wniesiona, system generuje unikalny numer sprawy i przypisuje jej status filed. Sędzia przegląda sprawę i wyznacza termin posiedzenia wstępnego, na którym oskarżony składa oświadczenie o winie. Jeśli oskarżony nie przyznaje się do winy, sprawa przechodzi do etapu przedprocesowego, w którym prawnicy mogą składać wnioski i dowody, a następnie do procesu, gdzie obie strony przedstawiają swoje argumenty. Sędzia kontroluje przebieg rozprawy za pomocą komend, które zmieniają status sprawy i wywołują aktualizacje UI u wszystkich uczestników. Zaimplementuj NUI sali sądowej, które wyświetla informacje o sprawie, bieżącą fazę oraz udostępnia kontrolki specyficzne dla ról sędziego, prokuratora i obrońcy. Sędzia otrzymuje przyciski werdyktu oraz pola wymiaru kary, podczas gdy prawnicy otrzymują przyciski sprzeciwu i opcje prezentacji dowodów.

Rola prawnika i system obrony

Praca prawnika tworzy na serwerze całą ścieżkę kariery z odrębnymi mechanikami rozgrywki. Obrońcy mogą być zatrudniani przez oskarżonych za pośrednictwem katalogu prawników dostępnego z aresztu lub aplikacji w telefonie. Kiedy prawnik przyjmuje klienta, uzyskuje dostęp do akt sprawy w systemie prawnym, w tym do wszystkich dowodów przedstawionych przez prokuraturę. Prawnicy mogą składać wnioski o odrzucenie dowodów, wnioskować o odroczenie rozpraw, negocjować ugody z prokuratorem oraz przedstawiać własne dowody i zeznania świadków podczas procesu. Wdróż system egzaminu adwokackiego, w którym nowe postacie prawników muszą zdać test wiedzy przed otrzymaniem pracy prawnika, co zapewni minimalny poziom jakości roleplayu prawniczego. Śledź statystyki prawników, takie jak wygrane i przegrane sprawy oraz średnie skrócenie wyroku dla ich klientów, tworząc konkurencyjny rynek, na którym doświadczeni prawnicy mogą pobierać wyższe opłaty:

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)

System zarządzania dowodami

System dowodów zapewnia łańcuch dowodowy łączący śledztwo na miejscu zbrodni z prezentacją na sali sądowej. Gdy policja zbiera dowody na miejscu zdarzenia za pomocą komendy zbierania dowodów, system tworzy wpis dowodowy z danymi funkcjonariusza, znacznikiem czasu i lokalizacją. Każdy dowód otrzymuje unikalny identyfikator, który zachowuje ważność przez cały proces prawny. Rodzaje dowodów obejmują przedmioty fizyczne, takie jak broń, narkotyki i odzież, dowody cyfrowe, takie jak bilingi telefoniczne i nagrania z monitoringu, zeznania świadków zapisane w formie tekstu oraz dokumenty, takie jak wyciągi finansowe czy podrobione dokumenty tożsamości. Prawnicy mogą podważać dopuszczalność dowodów poprzez wnioski kwestionujące sposób ich zebrania lub łańcuch dowodowy. Sędzia rozpatruje te wnioski i może uznać dowód za niedopuszczalny, usuwając go z akt sprawy. Wprowadź szafkę na dowody na komisariacie policji, w której przechowywane są dowody rzeczowe, korzystając z integracji z systemem ekwipunku do śledzenia faktycznych przedmiotów zabezpieczonych podczas śledztwa.

Mechanika mandatów i kaucji

Mandaty i kaucje niosą za sobą konsekwencje finansowe w systemie prawnym. Gdy oskarżony staje przed sądem, sędzia ustala kwotę kaucji na podstawie wagi zarzutów i historii kryminalnej oskarżonego. Oskarżony może wpłacić kaucję za pośrednictwem systemu sądowego, aby wyjść z aresztu w oczekiwaniu na proces, lub pozostać w areszcie do rozprawy. Płatność kaucji jest potrącana z konta bankowego gracza i zwracana po zakończeniu sprawy, jeśli oskarżony stawił się na wszystkich rozprawach. Jeśli oskarżony się nie stawi, kaucja przepada i wydawany jest nakaz aresztowania. Grzywny są nakładane w ramach wyroku i muszą zostać zapłacone w wyznaczonym terminie. Niezapłacone grzywny generują odsetki i mogą wywołać dodatkowe konsekwencje prawne, takie jak zawieszenie prawa jazdy lub zajęcie mienia. Wdróż system ratalnej spłaty wysokich grzywien, w którym oskarżony może płacić tygodniowe raty zamiast całej kwoty naraz, co tworzy stałe zobowiązanie finansowe i sprawia, że system prawny pozostaje istotną częścią codziennej rozgrywki na serwerze.

Komendy sędziego i wydawanie wyroków

Sędziowie potrzebują kompleksowego zestawu komend do prowadzenia postępowań sądowych i egzekwowania prawa. Podstawowe komendy obejmują /case aby przeglądać sprawy i nimi zarządzać, /warrant do zatwierdzania lub odrzucania wniosków o nakaz, /sentence aby nakładać wyroki więzienia i grzywny, /bail do ustalania kwot kaucji, /gag aby wyciszać przeszkadzających graczy podczas rozpraw oraz /contempt aby więzić graczy okazujących brak szacunku dla sądu. Komenda orzekania wyroku powinna odwoływać się do konfiguracji kodeksu karnego, która określa minimalne i maksymalne kary za każdy czyn, co zapewnia spójność między różnymi sędziami. Wdróż system wytycznych wymiaru kary, który sugeruje odpowiednie kary na podstawie zarzutów i kartoteki oskarżonego, jednocześnie dając sędziom swobodę odstępstwa w uzasadnionych przypadkach. Zapisuj wszystkie decyzje sądu w tabeli kartotek prawnych, aby serwer budował bazę precedensów, do której doświadczeni gracze mogą się odwoływać w przyszłych rozprawach. Dodaj procedurę rewizji sądowej, umożliwiającą odwołanie się od wyroku do sędziego wyższej rangi lub składu sędziowskiego, co stworzy dodatkowe poziomy roleplayu prawniczego dla zaangażowanych graczy.

Integracja z policją, więzieniem i MDT

System prawny musi bezproblemowo integrować się z istniejącymi resources policji, więzienia i MDT, tworząc spójny system wymiaru sprawiedliwości. Kiedy policja wnosi zarzuty za pośrednictwem MDT, system powinien automatycznie utworzyć sprawę sądową z odpowiednim numerem sprawy i podpiąć wszelkie dowody zebrane już podczas śledztwa. Gdy sędzia skazuje oskarżonego na karę więzienia, system powinien bezpośrednio wywołać funkcję exportu uwięzienia z resource więzienia, aby wyrok został wykonany automatycznie, bez konieczności ręcznego wpisywania komendy więzienia przez policjanta. Aktywne nakazy aresztowania powinny pojawiać się w MDT policji podczas wyszukiwania obywatela, z wyraźnymi wskaźnikami pokazującymi typ nakazu, organ wydający i datę ważności. Kartoteka kryminalna generowana na podstawie wyroków sądowych powinna być dostępna w MDT w profilu obywatela, pokazując jego pełną historię prawną, w tym wyroki skazujące, uniewinnienia, aktywne sprawy i zaległe grzywny. Wyeksportuj wszystkie funkcje systemu prawnego, aby inne resources mogły programowo sprawdzać status nakazów, weryfikować uprawnienia prawników, przeglądać kartotekę i wchodzić w interakcję z systemem sądowym.

Gotowy, aby zacząć?

Kup skrypty w naszym sklepie lub dołącz do Discorda, aby uzyskać wsparcie, aktualizacje i sprawdzić nadchodzące nowości.