Zurück zum Blog
Guide9 Min. Lesezeit

FiveM-Gefängnissystem: Sinnvolle Haftzeit im Spiel

Baue ein Gefängnissystem, das Spieler wirklich einbindet. Mit Gefängnisjobs, Fluchtwegen, Wachen, Bewährung und den besten FiveM-Scripts für tiefes Roleplay.

Agency Scripts

Gründer und leitender Entwickler bei Agency Scripts

Architektur eines Gefängnissystems

Ein Gefängnissystem ist eines der wirkungsvollsten Features, die du deinem FiveM-Rollenspielserver hinzufügen kannst. Es schafft bedeutsame Konsequenzen für kriminelle Aktivitäten und bietet inhaftierten Spielern zugleich eine spannende Beschäftigung, statt sie dreißig Minuten lang auf eine Wand starren zu lassen. Die Architektur basiert auf einem Gefängnistimer, der in Echtzeit herunterzählt, einer Reihe von Gefängnisaktivitäten, mit denen Insassen ihre Strafe durch Arbeit verkürzen können, und einem Begrenzungssystem, das Spieler bis zum Ende ihrer Haftzeit auf das Gefängnisgelände beschränkt. Der Standort Bolingbroke Penitentiary in GTA V ist die gängige Wahl, da er über ein vollständig modelliertes Innenareal mit Zellentrakten, einem Hof und umliegenden Einrichtungen verfügt. Dein System benötigt drei zentrale Komponenten: die serverseitige Verurteilungslogik, die Haftstrafen festlegt und Waffen sowie Schmuggelware entfernt, die clientseitige Durchsetzung der Grenzen, die Spieler zurückteleportiert, wenn sie den Gefängnisbereich verlassen, und das Aktivitätssystem, das Insassen sinnvolle Aufgaben bietet, um sich die Zeit zu vertreiben.

Datenbankschema und Verurteilung

Die Datenbank speichert aktive Haftstrafen, den Strafverlauf für die Kriminalakte und den Fortschritt der Insassen bei Aktivitäten. Speichere das Strafende als absoluten Zeitstempel statt als verbleibende Dauer, damit die Zeit auch dann weiter herunterzählt, wenn der Spieler offline ist. So verhinderst du den Exploit, bei dem Spieler sich abmelden, um ihre Haftstrafe zu pausieren. Füge zur Dokumentation Felder für den verhaftenden Beamten, die Anklagepunkte und die ursprüngliche Strafdauer hinzu:

CREATE TABLE IF NOT EXISTS prison_sentences (
    id INT AUTO_INCREMENT PRIMARY KEY,
    citizenid VARCHAR(50) NOT NULL,
    sentence_minutes INT NOT NULL,
    time_served INT DEFAULT 0,
    reduction_earned INT DEFAULT 0,
    jailed_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    release_at TIMESTAMP NOT NULL,
    charges TEXT DEFAULT NULL,
    arresting_officer VARCHAR(50) DEFAULT NULL,
    status ENUM('active', 'released', 'escaped', 'pardoned') DEFAULT 'active',
    parole_eligible BOOLEAN DEFAULT FALSE,
    INDEX idx_citizen (citizenid),
    INDEX idx_status (status)
);

CREATE TABLE IF NOT EXISTS prison_activity_log (
    id BIGINT AUTO_INCREMENT PRIMARY KEY,
    citizenid VARCHAR(50) NOT NULL,
    sentence_id INT NOT NULL,
    activity_type ENUM('mining', 'gym', 'cleaning', 'library', 'yard') NOT NULL,
    reduction_minutes INT DEFAULT 0,
    completed_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY (sentence_id) REFERENCES prison_sentences(id)
);

Einen Spieler verurteilen

Wenn die Polizei den Gefängnisbefehl verwendet, überprüft der Server die Berechtigungen des Beamten, berechnet die Haftstrafe anhand der Anklagepunkte, entfernt die Waffen und illegalen Gegenstände des Insassen und teleportiert ihn zu einem Spawnpunkt im Gefängnis. Die Haftstrafe muss sofort in der Datenbank gespeichert werden, damit sie Serverneustarts übersteht. Implementiere die Verurteilung als serverseitigen Befehl, den nur befugte Polizeibeamte ausführen können:

RegisterCommand('jail', function(source, args)
    local src = source
    local Officer = QBCore.Functions.GetPlayer(src)
    if not Officer then return end

    -- Check police job
    if Officer.PlayerData.job.name ~= 'police' then
        TriggerClientEvent('QBCore:Notify', src, 'Unauthorized', 'error')
        return
    end

    local targetId = tonumber(args[1])
    local minutes = tonumber(args[2])
    local charges = table.concat(args, ' ', 3)

    if not targetId or not minutes or minutes <= 0 then
        TriggerClientEvent('QBCore:Notify', src, 'Usage: /jail [id] [minutes] [charges]', 'error')
        return
    end

    local Target = QBCore.Functions.GetPlayer(targetId)
    if not Target then
        TriggerClientEvent('QBCore:Notify', src, 'Player not found', 'error')
        return
    end

    local citizenid = Target.PlayerData.citizenid
    local releaseAt = os.date('!%Y-%m-%d %H:%M:%S', os.time() + (minutes * 60))

    -- Insert sentence
    local sentenceId = MySQL.insert.await(
        'INSERT INTO prison_sentences (citizenid, sentence_minutes, release_at, charges, arresting_officer) VALUES (?, ?, ?, ?, ?)',
        { citizenid, minutes, releaseAt, charges, Officer.PlayerData.citizenid }
    )

    -- Strip weapons and contraband
    local contraband = {'weapon_pistol', 'weapon_smg', 'lockpick', 'thermite'}
    for _, item in ipairs(contraband) do
        local playerItem = Target.Functions.GetItemByName(item)
        if playerItem then
            Target.Functions.RemoveItem(item, playerItem.amount)
        end
    end

    -- Set jail metadata and teleport
    Target.Functions.SetMetaData('injail', sentenceId)
    TriggerClientEvent('prison:client:enter', targetId, sentenceId, minutes)
    TriggerClientEvent('QBCore:Notify', src, 'Jailed ' .. GetPlayerName(targetId) .. ' for ' .. minutes .. ' minutes', 'success')
end, false)

Gefängnisaktivitäten

Gefängnisaktivitäten bilden den zentralen Gameplay-Loop, der inhaftierte Spieler bei der Stange hält. Ohne sie ist die Haft eine Strafe, die Spieler zum Abmelden bewegt, was der Serverpopulation schadet. Gestalte Aktivitäten mit einem klaren Kompromiss: Wer arbeitet, verkürzt seine Haftstrafe und gibt Insassen damit Einfluss auf ihr Spielerlebnis. Jede Aktivität sollte eine Abklingzeit haben, um Spam zu verhindern, sowie eine maximale Strafminderung pro Aktivitätszyklus, damit eine 60-minütige Haftstrafe nicht in 5 Minuten abgebüßt werden kann. Zu den gängigsten Aktivitäten gehören der Abbau im Steinbruch, Training im Fitnessstudio, das Reinigen der Einrichtung und der Aufenthalt in der Gefängnisbibliothek. Jede Aktivität nutzt ein anderes Minispiel oder Interaktionsmuster, um Abwechslung zu bieten:

Config.PrisonActivities = {
    mining = {
        label = 'Quarry Mining',
        coords = vector3(1690.64, 2592.63, 45.56),
        radius = 15.0,
        reductionPerCycle = 2,   -- minutes reduced per completion
        cycleDuration = 45,       -- seconds per mining cycle
        cooldown = 30,            -- seconds between cycles
        maxReductionPerSession = 10,
        animation = { dict = 'amb@world_human_hammering@male@base', anim = 'base' },
        requiredProp = 'prop_tool_pickaxe',
    },
    gym = {
        label = 'Prison Gym',
        coords = vector3(1662.67, 2527.84, 45.56),
        radius = 10.0,
        reductionPerCycle = 1,
        cycleDuration = 30,
        cooldown = 60,
        maxReductionPerSession = 6,
        animation = { dict = 'amb@world_human_muscle_free_weights@male@barbell@base', anim = 'base' },
    },
    cleaning = {
        label = 'Facility Cleaning',
        coords = vector3(1653.18, 2499.26, 45.56),
        radius = 20.0,
        reductionPerCycle = 1,
        cycleDuration = 25,
        cooldown = 20,
        maxReductionPerSession = 8,
        animation = { dict = 'amb@world_human_janitor@male@base', anim = 'base' },
        requiredProp = 'prop_cs_broom',
    },
    library = {
        label = 'Prison Library',
        coords = vector3(1680.21, 2513.45, 45.56),
        radius = 8.0,
        reductionPerCycle = 1,
        cycleDuration = 60,
        cooldown = 45,
        maxReductionPerSession = 4,
        animation = { dict = 'amb@world_human_clipboard@male@base', anim = 'base' },
    },
}

-- Server-side activity completion handler
RegisterNetEvent('prison:server:completeActivity', function(activityType, sentenceId)
    local src = source
    local Player = QBCore.Functions.GetPlayer(src)
    if not Player then return end

    local citizenid = Player.PlayerData.citizenid
    local activity = Config.PrisonActivities[activityType]
    if not activity then return end

    -- Validate sentence is active
    local sentence = MySQL.single.await(
        'SELECT * FROM prison_sentences WHERE id = ? AND citizenid = ? AND status = "active"',
        { sentenceId, citizenid }
    )
    if not sentence then return end

    -- Check session reduction cap
    local sessionReduction = MySQL.scalar.await(
        'SELECT COALESCE(SUM(reduction_minutes), 0) FROM prison_activity_log WHERE sentence_id = ? AND activity_type = ? AND completed_at > DATE_SUB(NOW(), INTERVAL 1 HOUR)',
        { sentenceId, activityType }
    )
    if sessionReduction >= activity.maxReductionPerSession then
        TriggerClientEvent('QBCore:Notify', src, 'Maximum reduction reached for this activity', 'error')
        return
    end

    -- Apply reduction
    local reduction = activity.reductionPerCycle
    MySQL.update('UPDATE prison_sentences SET reduction_earned = reduction_earned + ?, release_at = DATE_SUB(release_at, INTERVAL ? MINUTE) WHERE id = ?',
        { reduction, reduction, sentenceId })

    MySQL.insert('INSERT INTO prison_activity_log (citizenid, sentence_id, activity_type, reduction_minutes) VALUES (?, ?, ?, ?)',
        { citizenid, sentenceId, activityType, reduction })

    TriggerClientEvent('QBCore:Notify', src, 'Sentence reduced by ' .. reduction .. ' minute(s)', 'success')
    TriggerClientEvent('prison:client:updateTimer', src, reduction)
end)

Bewährungssystem

Ein Bewährungssystem schafft eine Ebene für Rollenspiel zwischen Gefängnis und vollständiger Freiheit. Sobald ein Insasse einen konfigurierbaren Prozentsatz seiner Haftstrafe verbüßt hat, typischerweise 60-75%, kann er auf Bewährung entlassen werden. Ein Richter oder ranghoher Polizeibeamter kann die Bewährung per Befehl gewähren. Der Spieler wird dadurch vorzeitig entlassen, muss aber Auflagen erfüllen. Bewährte Spieler können eine Ausgangssperre haben, die sie verpflichtet, sich zwischen bestimmten Uhrzeiten auf ihrem Grundstück aufzuhalten. Außerdem können sie verpflichtet sein, sich regelmäßig bei einem Bewährungshelfer zu melden, und dürfen keine Waffen besitzen oder bestimmte Bereiche betreten. Verstößt ein Spieler auf Bewährung gegen eine Auflage, wird er automatisch mit der verbleibenden Haftstrafe zuzüglich einer zusätzlichen Strafe für den Verstoß ins Gefängnis zurückgebracht. Speichere den Bewährungsstatus in den Spielermetadaten und führe regelmäßige serverseitige Prüfungen durch, um die Einhaltung der Auflagen zu überprüfen.

Gefängnisausbrüche

Gefängnisausbrüche sind serverweite Ereignisse, die spannendes Rollenspiel für Kriminelle und Strafverfolgungsbehörden schaffen. Für einen Ausbruch sollten umfangreiche Vorbereitungen und mehrere Beteiligte nötig sein. Außerdem müssen die Polizeikräfte ausreichend Zeit haben, um zu reagieren. Setze ihn als mehrphasiges Ereignis um: Zunächst muss ein Team außerhalb des Gefängnisses bestimmte Gegenstände wie einen Hubschrauber, Sprengstoff und Verkleidungen beschaffen. Anschließend muss es das Sicherheitssystem des Gefängnisses über ein anspruchsvolles Minispiel an einem externen Kontrollpult hacken. Sobald die Sicherheit deaktiviert ist, öffnen sich die Zellentüren für kurze Zeit. Die Insassen können dann über festgelegte Fluchtrouten zu entkommen versuchen, während Wach-NPCs und herbeigerufene Polizeikräfte sie aufhalten. Das System sollte Ausbrüche nur zulassen, wenn mindestens eine festgelegte Anzahl von Polizeibeamten online ist, damit eine faire Reaktion möglich ist:

Config.PrisonBreak = {
    minPoliceOnline = 5,
    cooldown = 28800, -- 8 hours between break attempts
    requiredItems = {
        { name = 'electronickit', amount = 2, label = 'Electronic Kit' },
        { name = 'thermite', amount = 3, label = 'Thermite Charge' },
    },
    phases = {
        {
            name = 'hack_security',
            label = 'Hack Security Grid',
            coords = vector3(1746.23, 2488.90, 45.80),
            duration = 60,
            minigame = { type = 'hack', difficulty = 'hard', attempts = 3 },
        },
        {
            name = 'breach_wall',
            label = 'Breach Perimeter Wall',
            coords = vector3(1651.78, 2569.33, 45.56),
            duration = 30,
            minigame = { type = 'thermite', time = 10 },
        },
        {
            name = 'disable_lockdown',
            label = 'Disable Lockdown Protocol',
            coords = vector3(1691.45, 2565.12, 45.56),
            duration = 45,
            minigame = { type = 'hack', difficulty = 'expert', attempts = 2 },
        },
    },
    escapeWindow = 300, -- 5 minutes to escape after all phases complete
    escapeRoutes = {
        { label = 'Main Gate', coords = vector3(1845.12, 2585.87, 45.67) },
        { label = 'Drainage Tunnel', coords = vector3(1617.34, 2523.90, 44.12) },
        { label = 'Helipad', coords = vector3(1700.89, 2565.34, 52.34) },
    },
}

Wach-NPC-System

Wach-NPCs sorgen für eine sichtbare Präsenz rund um das Gefängnis und verhindern, dass Insassen einfach hinausspazieren. Platziere Wachen an wichtigen Engpässen wie dem Haupttor, den Eingängen zu den Zellentrakten und entlang der Außenmauer. Jede Wache sollte eine Patrouillenroute mit Wegpunkten haben, die sie regelmäßig abläuft, sodass bestimmte Bereiche zeitweise unbewacht sind. Wachen erkennen Insassen, die autorisierte Bereiche verlassen, und reagieren zunächst mit einer mündlichen Warnung. Befolgt der Insasse diese nicht, verfolgen die Wachen ihn und greifen an. Implementiere die Erkennung über Näheprüfungen, die auch die Sichtlinie berücksichtigen, damit Insassen unbemerkt an Wachen vorbeischleichen können, wenn sie in Deckung bleiben. Spawne während eines Gefängnisausbruchs zusätzliche Wachen an wichtigen Positionen und erhöhe ihre Aggressivität. Verwende die nativen FiveM-Funktionen TaskPatrol und SetPedCombatAttributes um Wachen ein realistisches Patrouillenverhalten zu verleihen. Achte darauf, ihre Beziehungsgruppe so einzustellen, dass sie Insassen gegenüber feindselig, gegenüber Polizei und Besuchern aber neutral sind. So verhinderst du, dass es bei der Reaktion auf Gefängnisausbrüche zu versehentlichem Beschuss von Verbündeten kommt.

Durchsetzung der Grenzen und Entlassung

Das Begrenzungssystem hält Insassen innerhalb des Gefängnisgeländes, indem es eine Polygonzone verwendet, die das gesamte Gelände abdeckt. Verlässt ein Spieler mit aktiver Haftstrafe diese Zone, erhält er eine Warnmeldung und hat 10 Sekunden Zeit, zurückzukehren. Danach wird er als Strafe für den Fluchtversuch zum Gefängnis-Spawnpunkt zurückteleportiert und seine Haftstrafe wird verlängert. Führe clientseitig alle 2 Sekunden eine Prüfung durch, die die Position des Spielers mit dem Gefängnisgrenzpolygon vergleicht. Für die Entlassung führt der Server alle 30 Sekunden eine Timerschleife aus, die sämtliche aktiven Haftstrafen überprüft. Läuft eine Haftstrafe ab, aktualisiert das System den Datenbankstatus auf entlassen, löscht die Gefängnismetadaten des Spielers, stellt sein Inventar aus einem Backup vor der Inhaftierung wieder her, sofern du ein solches implementiert hast, teleportiert ihn mit einer Benachrichtigung über seine Freilassung zum Gefängnisausgang. Ist der Spieler zum Zeitpunkt des Haftendes offline, erfolgt die Entlassung bei seiner nächsten Anmeldung. Dafür werden beim Laden des Spielers aktive, bereits abgelaufene Haftstrafen überprüft. Füge einen Befehl hinzu, mit dem die Polizei Spieler in besonderen Fällen wie einer ungerechtfertigten Inhaftierung oder einem im Rollenspiel ausgehandelten Deal vorzeitig entlassen kann.

Integration mit Polizei- und Rechtssystemen

Dein Gefängnissystem sollte eng in das polizeiliche MDT und jedes Gerichtssystem auf dem Server integriert sein. Wird ein Spieler inhaftiert, sollte seine Kriminalakte im MDT automatisch um die Anklagepunkte, die Haftdauer und den verhaftenden Beamten ergänzt werden. Verfügt dein Server über ein Gerichtssystem, sollten von einem Richter verhängte Haftstrafen über dieselbe Inhaftierungsfunktion laufen, um ein einheitliches Vorgehen zu gewährleisten. Implementiere ein Berufungssystem, über das Insassen aus der Gefängnisbibliothek einen Antrag stellen können, der als Ticket für Richter angelegt wird. Das kann zu einer Strafminderung oder vorzeitigen Entlassung führen. Verfolge Rückfälligkeit, indem du zählst, wie oft jeder Bürger inhaftiert wurde, und nutze diese Daten über ein Multiplikatorsystem für härtere Strafen bei Wiederholungstätern. Stelle deine Inhaftierungsfunktion als Export bereit, damit andere Ressourcen wie das Gerichtssystem, die automatische Verbrechensdetektion oder Admin-Befehle Spieler über denselben geprüften Ablauf ins Gefängnis schicken 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.