FiveM-Raub- und Überfallsystem: Banken, Geschäfte und Tresore
Skripte lohnende Raubüberfälle in FiveM. Fleeca, Paleto, Juweliergeschäfte, Polizei und die besten Überfallskripte für raue Rollenspielserver.
Agency Scripts
Gründer und leitender Entwickler bei Agency Scripts
Architekturübersicht des Raubüberfallsystems
Raubüberfälle und Banküberfälle gehören zu den spannendsten Gameplay-Schleifen auf jedem FiveM-Rollenspielserver. Sie bringen Kriminelle zusammen, die eine ausgeklügelte Aktion planen, Polizisten, die mit taktischer Präzision reagieren, Geiselunterhändler, die angespannte Pattsituationen bewältigen, und Zivilisten, die ins Kreuzfeuer geraten. Ein gut entwickeltes Raubüberfallsystem geht weit über eine einfache Interaktionsaufforderung hinaus, die Spielern Geld gibt. Es erfordert eine mehrschichtige Architektur für die Verwaltung von Orten, die Prüfung von Voraussetzungen, fortschreitende Minigame-Phasen, die Verteilung der Beute, die Integration von Polizeialarmen, die Verwaltung von Cooldowns und Schutz vor Exploits. Das System sollte aus drei Kernschichten bestehen: einer Konfigurationsebene, die jeden Raubüberfallsort samt Voraussetzungen und Belohnungen definiert, einer serverseitigen Zustandsmaschine, die aktive Raubüberfälle verfolgt und alle Regeln durchsetzt, und einer clientseitigen Darstellungsebene für Minigames, Animationen und NUI-Oberflächen. Jede kritische Entscheidung muss serverseitig getroffen werden, da clientseitige Logik trivial ausnutzbar ist.
Raubüberfallsorte und Schwierigkeitsstufen konfigurieren
Dein Raubüberfallsystem sollte mehrere Ortstypen mit steigendem Schwierigkeitsgrad unterstützen. Tankstellen und kleine Läden bilden die Einstiegsklasse und erfordern nur eine geringe Polizeipräsenz und einfache Werkzeuge. Fleeca-Bankfilialen liegen in der mittleren Stufe und verfügen über moderate Sicherheitsvorkehrungen sowie höhere Anforderungen an die Polizeipräsenz. Der Tresor der Pacific Standard ist der Höhepunkt des Heists und erfordert ein vollständiges Team, fortschrittliche Ausrüstung und eine erhebliche Zahl anwesender Polizeikräfte. Für jeden Ort ist ein Konfigurationseintrag erforderlich, der die Koordinaten, benötigten Gegenstände, Mindestanzahl an Polizisten, Cooldown-Dauer, Belohnungsspanne und die Reihenfolge der zu überwindenden Sicherheitsebenen festlegt:
Config.Robberies = {
['store_1'] = {
label = 'LTD Gasoline - Davis',
type = 'store',
coords = vector3(-47.02, -1757.23, 29.42),
register = vector3(-43.43, -1748.60, 29.42),
tier = 1,
cooldown = 1800, -- 30 minutes
minPolice = 2,
requiredItems = {'weapon_pistol'},
reward = {min = 2500, max = 6000, type = 'cash'},
securityLayers = {
{type = 'intimidate', time = 30},
{type = 'grab_cash', time = 15},
},
},
['fleeca_legion'] = {
label = 'Fleeca Bank - Legion Square',
type = 'bank',
coords = vector3(149.73, -1042.65, 29.37),
vault = vector3(144.87, -1044.16, 29.37),
tier = 2,
cooldown = 7200, -- 2 hours
minPolice = 4,
requiredItems = {'electronickit', 'thermite'},
reward = {min = 45000, max = 90000, type = 'markedbills'},
securityLayers = {
{type = 'hack', difficulty = 'medium', time = 25},
{type = 'thermite', time = 10},
{type = 'drill', time = 40},
},
},
['pacific_standard'] = {
label = 'Pacific Standard Bank',
type = 'vault',
coords = vector3(255.85, 225.60, 101.88),
vault = vector3(262.20, 222.10, 101.68),
tier = 3,
cooldown = 14400, -- 4 hours
minPolice = 6,
requiredItems = {'electronickit', 'thermite', 'advancedlaptop', 'duffelbag'},
reward = {min = 250000, max = 500000, type = 'markedbills'},
securityLayers = {
{type = 'hack', difficulty = 'hard', time = 20},
{type = 'hack', difficulty = 'hard', time = 20},
{type = 'thermite', time = 8},
{type = 'drill', time = 60},
{type = 'hack', difficulty = 'expert', time = 15},
},
},
}
Jede Stufe sollte nicht nur die Belohnung, sondern auch Komplexität und Risiko steigern. Überfälle auf kleine Läden sind schnelle Aktionen, die weniger als zwei Minuten dauern, während der Pacific-Standard-Heist ein mehrphasiger Einsatz ist, dessen Abschluss fünfzehn Minuten oder länger dauern kann. So haben die Polizisten ausreichend Zeit, eine Absperrung einzurichten.
Serverseitige Zustandsmaschine
Die Zustandsmaschine für Raubüberfälle ist das Herzstück des Systems. Sie verfolgt für jeden Raubüberfallsort die Zustände seines Lebenszyklus: inaktiv, läuft, Cooldown und gesperrt. Wenn ein Spieler einen Raubüberfall startet, überprüft der Server alle Voraussetzungen, bevor der Ort von inaktiv zu läuft wechselt. Während der Zustand läuft aktiv ist, verfolgt der Server, an welcher Sicherheitsebene sich die Kriminellen gerade befinden, welche Spieler teilnehmen und wie viel Zeit vergangen ist. Wenn alle Spieler das Gebiet verlassen oder festgenommen werden, scheitert der Raubüberfall automatisch und es beginnt ein verkürzter Cooldown. Nach Abschluss wechselt der Ort für die konfigurierte Dauer in den Cooldown-Zustand, bevor er wieder verfügbar wird:
local RobberyState = {}
function InitializeRobbery(robberyId)
RobberyState[robberyId] = {
status = 'idle', -- idle | active | cooldown | locked
participants = {},
currentLayer = 0,
startedAt = 0,
cooldownUntil = 0,
}
end
RegisterNetEvent('robbery:server:startRobbery', function(robberyId)
local src = source
local Player = QBCore.Functions.GetPlayer(src)
if not Player then return end
local config = Config.Robberies[robberyId]
local state = RobberyState[robberyId]
if not config or not state then return end
-- Validate state
if state.status ~= 'idle' then
TriggerClientEvent('QBCore:Notify', src, 'This location is not available', 'error')
return
end
-- Check cooldown
if os.time() < state.cooldownUntil then
TriggerClientEvent('QBCore:Notify', src, 'Location on cooldown', 'error')
return
end
-- Check minimum police online
local policeCount = GetOnlinePolicCount()
if policeCount < config.minPolice then
TriggerClientEvent('QBCore:Notify', src, 'Not enough police online', 'error')
return
end
-- Check required items
for _, item in ipairs(config.requiredItems) do
if not Player.Functions.GetItemByName(item) then
TriggerClientEvent('QBCore:Notify', src, 'Missing required equipment', 'error')
return
end
end
-- Start robbery
state.status = 'active'
state.participants = {src}
state.currentLayer = 1
state.startedAt = os.time()
-- Alert police dispatch
TriggerEvent('dispatch:server:notify', {
type = 'robbery',
coords = config.coords,
message = 'Silent alarm triggered at ' .. config.label,
tier = config.tier,
})
-- Send first security layer to client
TriggerClientEvent('robbery:client:startLayer', src, robberyId, config.securityLayers[1])
end)
Die Zustandsmaschine sollte auch Sonderfälle wie Serverneustarts während laufender Raubüberfälle behandeln. Setze beim Serverstart alle Raubüberfallszustände auf inaktiv zurück und entferne alle aktiven Teilnehmer. Speichere Cooldown-Zeitstempel in einer persistenten Tabelle, damit sie Serverneustarts überstehen.
Minigame-Integration
Minigames machen aus passivem Warten bei Raubüberfällen eine aktive Geschicklichkeitsherausforderung. Jeder Sicherheitsebenentyp sollte einem anderen Minigame-Stil zugeordnet sein, der verschiedene Fähigkeiten der Spieler prüft. Hacking-Minigames können Memory-Puzzles, Herausforderungen zum Verbinden von Schaltkreisen oder schnelle Zahlenfolgen verwenden. Beim Platzieren von Thermit ist präzises Timing gefragt, damit die Ladungen angebracht werden, bevor sie verpuffen. Bohrmechaniken prüfen, ob Spieler die Maus ruhig führen können, während sie einen Bohrer durch einen Schließmechanismus steuern, ohne ihn zu überhitzen. Das zentrale Designprinzip: In höheren Stufen kommen komplexere Varianten dieser Minigames mit knapperen Zeitfenstern, mehr Elementen, die im Blick behalten werden müssen, oder höheren Geschwindigkeiten zum Einsatz:
-- Client-side minigame dispatcher
function StartMinigame(layerType, difficulty, callback)
if layerType == 'hack' then
local config = HackDifficulty[difficulty]
exports['ps-ui']:Circle(function(success)
callback(success)
end, config.circles, config.speed)
elseif layerType == 'thermite' then
exports['ps-ui']:Thermite(function(success)
callback(success)
end, 10, 5, 3)
elseif layerType == 'drill' then
exports['drilling']:StartDrill(function(success)
callback(success)
end)
elseif layerType == 'intimidate' then
-- Store clerk intimidation: aim weapon at NPC
StartClerkIntimidation(function(success)
callback(success)
end)
end
end
RegisterNetEvent('robbery:client:startLayer', function(robberyId, layer)
local ped = PlayerPedId()
-- Play appropriate animation
if layer.type == 'hack' then
PlayHackingAnimation(ped)
elseif layer.type == 'drill' then
PlayDrillingAnimation(ped)
end
StartMinigame(layer.type, layer.difficulty, function(success)
ClearPedTasks(ped)
TriggerServerEvent('robbery:server:layerResult', robberyId, success)
end)
end)
Fehlgeschlagene Minigame-Versuche sollten Konsequenzen haben. Ein misslungener Hack könnte zusätzliche Alarme auslösen, die verbleibende Zeit verkürzen oder den Spieler für kurze Zeit sperren. Bei Heists der höchsten Stufe könnte ein fehlgeschlagener letzter Hack den Tresor vollständig verriegeln, sodass das Team den Raubüberfall mit nur einem Teil der Beute abbrechen muss. Diese Fehlschlagsszenarien sorgen für Spannung und machen erfolgreiche Abschlüsse wirklich lohnend.
Integration von Polizeialarm und Einsatzreaktion
Ein Raubüberfallsystem ist ohne die Integration der Polizei nur zur Hälfte fertig. Sobald ein Raubüberfall beginnt, sollte das Alarmsystem je nach Stufe abgestufte Meldungen senden. Ein Überfall auf einen kleinen Laden löst eine einfache Benachrichtigung über einen stillen Alarm mit dem Standort des Ladens aus. Bei einer Fleeca-Filiale wird ein Bankalarm mit dem Namen der Filiale und einer empfohlenen Einsatzstufe ausgelöst. Der Pacific-Standard-Heist aktiviert einen umfassenden Notruf, der allen verfügbaren Einheiten empfiehlt, zum Einsatzort zu fahren. Stelle der Polizei im Verlauf des Raubüberfalls Echtzeit-Updates bereit: wenn Kriminelle eine neue Sicherheitsebene überwinden, im Gebäude Schüsse fallen oder die Kriminellen zu fliehen versuchen. Diese Updates helfen der Polizei, ihren Einsatz zu koordinieren, und schaffen dynamische Szenarien, in denen Beamte entscheiden können, ob sie sofort stürmen oder eine Absperrung einrichten und verhandeln. Implementiere eine Geiselmechanik, mit der Kriminelle NPC-Bankschaltermitarbeiter als Geiseln nehmen können. So bekommen polizeiliche Verhandler eine Rolle und die Kriminellen ein Druckmittel, um den Polizeieinsatz zu verzögern. Das Geiselsystem sollte verfolgen, wie viele Geiseln festgehalten werden, ob jemand verletzt wurde, und Verhandlungsaufforderungen über Telefonate zwischen den Kriminellen und den eintreffenden Beamten bereitstellen.
Beuteverteilung und Geldwäsche
Was Spieler bei einem Raubüberfall erhalten, ist genauso wichtig wie der Raubüberfall selbst. Statt sauberes Bargeld direkt auf Bankkonten einzuzahlen, belohnst du die Kriminellen mit markierten Geldscheinen oder gestohlenen Waren, die erst weitere Schritte erfordern, bevor sie sich in verwendbare Währung umwandeln lassen. So wird die kriminelle Gameplay-Schleife über den Heist hinaus verlängert und es entstehen miteinander verknüpfte Systeme. Markierte Geldscheine lassen sich an bestimmten Orten auf der Karte gegen eine Gebühr waschen. Dadurch entstehen Risiko-Nutzen-Entscheidungen darüber, wann und wo das Geld gewaschen wird. Gestohlenen Schmuck oder Elektronik müssen die Spieler über Hehler-NPCs verkaufen, die je nach Seltenheit des Gegenstands und aktueller Marktlage unterschiedliche Preise bieten. Implementiere ein Beutelsystem, bei dem die Spieler die Beute physisch tragen müssen. Das begrenzt ihre Bewegungsgeschwindigkeit und verhindert den Einsatz von Waffen, wodurch die Fluchtphase zusätzliche taktische Überlegungen erfordert:
RegisterNetEvent('robbery:server:distributeLoot', function(robberyId)
local src = source
local config = Config.Robberies[robberyId]
local state = RobberyState[robberyId]
if not config or not state then return end
if state.status ~= 'active' then return end
local rewardAmount = math.random(config.reward.min, config.reward.max)
local participants = state.participants
local perPlayer = math.floor(rewardAmount / #participants)
for _, playerId in ipairs(participants) do
local Player = QBCore.Functions.GetPlayer(playerId)
if Player then
if config.reward.type == 'markedbills' then
local billStacks = math.ceil(perPlayer / 5000)
for i = 1, billStacks do
local amount = math.min(5000, perPlayer - ((i - 1) * 5000))
Player.Functions.AddItem('markedbills', 1, nil, {
worth = amount,
source = config.label,
})
end
elseif config.reward.type == 'cash' then
Player.Functions.AddMoney('cash', perPlayer, 'robbery-' .. robberyId)
end
TriggerClientEvent('inventory:client:ItemBox', playerId, QBCore.Shared.Items['markedbills'], 'add')
end
end
-- Set cooldown
state.status = 'cooldown'
state.cooldownUntil = os.time() + config.cooldown
state.participants = {}
-- Log the robbery for admin review
LogRobbery(robberyId, participants, rewardAmount)
end)
Schutz vor Exploits und Cooldown-Verwaltung
Raubüberfallsysteme ziehen Exploit-Nutzer an, weil sie Geld generieren. Implementiere mehrere Schutzebenen gegen gängige Exploits. Serverseitige Distanzprüfungen stellen sicher, dass sich Spieler während jeder Phase am Raubüberfallsort aufhalten. Ratenbegrenzungen verhindern, dass Spieler Start-Events für Raubüberfälle spammen. Die Teilnehmerverfolgung stellt sicher, dass nur registrierte Teilnehmer Sicherheitsebenen durchlaufen oder Beute erhalten können. Globale Cooldowns verhindern das Spammen von Raubüberfällen auf dem gesamten Server, indem sie die Anzahl gleichzeitig aktiver Raubüberfälle begrenzen. Spielerbezogene Cooldowns verhindern, dass ein einzelner Spieler mehrere Orte direkt hintereinander ausraubt. Protokolliere jeden Raubüberfallsversuch mit Zeitstempeln, Teilnehmerkennungen, Erfolgs- oder Fehlschlagstatus und der ausgegebenen Belohnung, damit Admins verdächtige Muster untersuchen können. Überwache unmögliche Abschlusszeiten, bei denen ein Spieler alle Sicherheitsebenen schneller bewältigt, als es physisch möglich sein sollte. Implementiere ein Reputationssystem, bei dem häufige Raubüberfälle zu verstärkter Polizeiaufmerksamkeit und härteren Konsequenzen führen. So entsteht eine natürliche Begrenzung, die Spieler dazu anhält, ihre kriminellen Aktivitäten zeitlich zu verteilen.
Fluchtwege und dynamische Ereignisse
In der Fluchtphase werden Raubüberfälle wirklich unvorhersehbar. Sobald die Beute gesichert ist, müssen die Kriminellen das Gebiet mit schweren Seesäcken verlassen, die ihre Bewegung einschränken. Das System sollte mehrere Fluchtmöglichkeiten unterstützen: Bodenfahrzeuge, die draußen geparkt sind, Boote an nahegelegenen Anlegestellen bei Banken am Wasser oder Hubschrauber, die bei Heists der höchsten Stufe von Dächern aus abheben. Füge während der Fluchtphase dynamische Ereignisse hinzu, etwa Nagelstreifen, die Polizisten einsetzen können, Funkmeldungen mit einer Beschreibung des verdächtigen Fahrzeugs und zufällige Straßensperren an wichtigen Kreuzungen. Der Server sollte verfolgen, ob die Kriminellen die Raubüberfallszone verlassen haben. Sie wird über einen konfigurierbaren Radius um die Bank definiert. Erst dann gilt der Raubüberfall als vollständig abgeschlossen. Werden alle Teilnehmer getötet oder festgenommen, bevor sie die Zone verlassen, sollte die Polizei die Beute als Beweismittel sicherstellen können. Das schafft sinnvolles Gameplay nach dem Raubüberfall für beide Seiten und sorgt dafür, dass die Flucht genauso herausfordernd und lohnend ist wie der Heist selbst.