System więzienia FiveM: Skryptuj wartościowy czas odsiadki
Stwórz system więziennictwa, w który gracze naprawdę się zaangażują. Prace więzienne, drogi ucieczki, strażnicy, zwolnienia warunkowe i najlepsze skrypty więzienia FiveM do głębokiego roleplayu.
Agency Scripts
Założyciel i główny deweloper w Agency Scripts
Architektura systemu więziennictwa
System więzienia to jedna z najważniejszych funkcji, jakie możesz dodać do serwera roleplay FiveM, ponieważ tworzy realne konsekwencje działalności przestępczej, dając jednocześnie osadzonym graczom angażujące zajęcia zamiast wpatrywania się w ścianę przez trzydzieści minut. Architektura opiera się na timerze odsiadki odliczanym w czasie rzeczywistym, zestawie aktywności więziennych pozwalających skrócić wyrok poprzez pracę oraz systemie granic ograniczającym graczy do terenu więzienia do momentu odbycia kary. Więzienie Bolingbroke Penitentiary w GTA V to standardowy wybór, ponieważ posiada w pełni wymodelowane wnętrze z blokami cel, spacerniakiem i otaczającymi obiektami. Twój system potrzebuje trzech głównych komponentów: logiki wyroków po stronie serwera przydzielającej czas odsiadki i odbierającej broń oraz kontrabandę, egzekwowania granic po stronie klienta teleportującego graczy z powrotem przy próbie opuszczenia terenu więzienia oraz frameworku aktywności zapewniającego więźniom produktywne zadania na zabicie czasu.
Schemat bazy danych i wyroki
Baza danych śledzi aktywne wyroki, historię wyroków do kartoteki karnej oraz postępy więźnia w pracach. Zapisuj czas zakończenia wyroku jako bezwzględny znacznik czasu, a nie pozostały czas trwania, dzięki czemu czas upływa nawet wtedy, gdy gracz jest offline, co zapobiega exploitowi wylogowywania się w celu wstrzymania kary. Na potrzeby ewidencji uwzględnij pola dla aresztującego funkcjonariusza, zarzutów oraz pierwotnej długości wyroku:
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)
);
Wydawanie wyroku na gracza
Gdy policja używa komendy jail, serwer sprawdza uprawnienia funkcjonariusza, oblicza wyrok na podstawie zarzutów, odbiera więźniowi broń oraz nielegalne przedmioty i teleportuje go do punktu spawnu w więzieniu. Wyrok musi zostać natychmiast zapisany w bazie danych, aby przetrwał restarty serwera. Zaimplementuj wydawanie wyroku jako komendę po stronie serwera, którą mogą wykonywać tylko uprawnieni policjanci:
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)
Aktywności więzienne
Aktywności więzienne to główna pętla rozgrywki, która angażuje uwięzionych graczy. Bez nich odsiadka jest karą skłaniającą graczy do wyjścia z serwera, co źle wpływa na liczbę graczy. Zaprojektuj aktywności oferujące kompromis: praca skraca wyrok, dając więźniom kontrolę nad ich losem. Każda aktywność powinna mieć czas odnowienia zapobiegający spamowaniu oraz maksymalny limit skrócenia kary na cykl, aby 60-minutowego wyroku nie dało się zbić w 5 minut. Najczęstsze aktywności to wydobycie w kamieniołomie, trening na siłowni, sprzątanie obiektu i spędzanie czasu w bibliotece więziennej. Każda aktywność wykorzystuje inną minigrę lub schemat interakcji, aby zapewnić różnorodność:
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)
System zwolnień warunkowych
System zwolnień warunkowych wprowadza warstwę roleplayu pomiędzy więzieniem a pełną wolnością. Gdy więzień odbędzie konfigurowalny procent wyroku, zazwyczaj 60-75%, zyskuje prawo do ubiegania się o zwolnienie warunkowe. Zwolnienie warunkowe może zostać przyznane przez sędziego lub wyższego rangą funkcjonariusza policji za pomocą komendy, co zwalnia gracza wcześniej, ale nakłada na niego ograniczenia. Gracze objęci dozorem mogą mieć godzinę policyjną wymagającą przebywania na terenie swojej posiadłości w określonych godzinach, obowiązek regularnego meldowania się u kuratora oraz zakaz posiadania broni lub wstępu do określonych stref. Jeśli zwolniony warunkowo gracz złamie którykolwiek z warunków, automatycznie wraca do więzienia, aby odsiedzieć pozostałą część wyroku powiększoną o dodatkowy czas za naruszenie zasad. Śledź status zwolnienia warunkowego w metadanych gracza i przeprowadzaj okresowe kontrole na serwerze, aby weryfikować przestrzeganie warunków.
Wydarzenia ucieczki z więzienia
Ucieczki z więzienia to wydarzenia obejmujące cały serwer, które tworzą roleplay o wysoką stawkę zarówno dla przestępców, jak i służb porządkowych. Ucieczka z więzienia powinna wymagać sporego przygotowania, wielu uczestników oraz dać policji wystarczająco wcześnie sygnał do podjęcia działań. Zaimplementuj ją jako wydarzenie wielofazowe: ekipa z zewnątrz musi najpierw zdobyć określone przedmioty, takie jak helikopter, ładunki wybuchowe i przebrania. Następnie musi zhakować system bezpieczeństwa więzienia w trudnej minigrze przy zewnętrznym panelu sterowania. Po wyłączeniu zabezpieczeń drzwi cel otwierają się na określony czas, a więźniowie mogą próbować ucieczki wyznaczonymi trasami, podczas gdy strażnicy NPC i reagująca policja próbują ich powstrzymać. System powinien zezwalać na ucieczki z więzienia tylko wtedy, gdy online jest minimalna liczba policjantów, aby zapewnić sprawiedliwą reakcję:
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) },
},
}
System strażników NPC
Strażnicy NPC zapewniają ochronę wokół więzienia i uniemożliwiają więźniom swobodne wyjście. Rozmieść strażników w kluczowych punktach, takich jak brama główna, wejścia do bloków więziennych oraz wzdłuż muru obwodowego. Każdy strażnik powinien mieć trasę patrolową z punktami trasy, po których cyklicznie się porusza, tworząc okna czasowe, w których określone obszary pozostają niestrzeżone. Strażnicy wykrywają więźniów opuszczających dozwolone strefy i reagują ostrzeżeniem słownym, a w przypadku braku reakcji więźnia, pościgiem i atakiem. Zaimplementuj wykrywanie strażników za pomocą testów odległości uwzględniających linię wzroku, aby więźniowie mogli przekradać się obok strażników, kryjąc się za osłonami. Podczas ucieczki z więzienia zespawnuj dodatkowych strażników na kluczowych pozycjach i zwiększ ich poziom agresji. Użyj funkcji natywnych FiveM TaskPatrol i SetPedCombatAttributes aby nadać strażnikom realistyczne zachowanie podczas patrolu. Pamiętaj, aby ustawić ich grupę relacji jako wrogą wobec więźniów, a jednocześnie neutralną wobec policji i odwiedzających, co zapobiegnie incydentom friendly fire podczas interwencji przy ucieczce z więzienia.
Egzekwowanie granic i zwolnienie
System granic utrzymuje więźniów na terenie więzienia za pomocą strefy wielokąta obejmującej cały obiekt. Gdy gracz z aktywnym wyrokiem wyjdzie poza tę strefę, otrzymuje powiadomienie z ostrzeżeniem i ma 10 sekund na powrót, zanim zostanie przeteleportowany z powrotem do punktu odradzania w więzieniu z dodatkowym czasem doliczonym do wyroku jako kara za próbę ucieczki. Po stronie klienta wykonuj cykliczne sprawdzanie co 2 sekundy, porównując pozycję gracza z wielokątem granic więzienia. W przypadku zwolnienia serwer uruchamia pętlę timera sprawdzającą wszystkie aktywne wyroki co 30 sekund. Gdy wyrok wygaśnie, system aktualizuje status w bazie danych na zwolniony, czyści metadane więzienne gracza, przywraca jego ekwipunek z kopii zapasowej sprzed odsiadki (jeśli została wdrożona) i teleportuje go do wyjścia z więzienia z powiadomieniem o odzyskaniu wolności. Jeśli gracz jest offline w momencie wygaśnięcia wyroku, zwolnienie jest przetwarzane przy jego kolejnym logowaniu poprzez sprawdzenie wygasłych aktywnych wyroków w zdarzeniu ładowania gracza. Dołącz komendę dla policji do ręcznego, wcześniejszego zwalniania graczy w sytuacjach takich jak niesłuszne uwięzienie lub ugody wynegocjowane w ramach roleplay.
Integracja z policją i systemem prawnym
Twój system więzienia powinien ściśle integrować się z policyjnym MDT i każdym systemem sądownictwa na serwerze. Gdy gracz trafia do więzienia, jego kartoteka w MDT powinna automatycznie aktualizować się o zarzuty, długość wyroku i aresztującego funkcjonariusza. Jeśli twój serwer posiada system sądownictwa, wyroki wydawane przez sędziego powinny przechodzić przez tę samą funkcję więzienia, aby zapewnić spójność. Wdróż system apelacji od wyroku, w którym więźniowie mogą składać apelację z biblioteki więziennej, co tworzy zgłoszenie do rozpatrzenia przez sędziów, potencjalnie prowadząc do skrócenia wyroku lub wcześniejszego zwolnienia. Śledź recydywę, licząc, ile razy każdy obywatel był w więzieniu, i wykorzystaj te dane do wprowadzenia surowszych wyroków dla recydywistów za pomocą systemu mnożników. Wyeksportuj funkcję więzienia, aby inne zasoby, takie jak system sądownictwa, automatyczne wykrywanie przestępstw czy komendy administratora, mogły wysyłać graczy do więzienia tą samą sprawdzoną ścieżką.