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.