FiveM Soygun ve Heist Sistemi: Bankalar, Marketler ve Kasalar
FiveM içinde soygunları ve baskınları ödüllendiren script. Gerçekçi roleplay sunucuları için Fleeca, Paleto, kuyumcular, polisler ve en iyi soygun scriptleri.
Agency Scripts
Agency Scripts Kurucusu ve Baş Geliştiricisi
Soygun Sistemi Mimarisine Genel Bakış
Soygunlar ve büyük soygunlar, her FiveM roleplay sunucusundaki en heyecan verici oynanış döngüleri arasındadır. Karmaşık bir operasyon planlayan suçluları, taktiksel hassasiyetle müdahale eden polisi, gergin pazarlıkları yöneten rehine arabulucularını ve çapraz ateşte kalan sivilleri bir araya getirir. İyi tasarlanmış bir soygun sistemi, oyunculara para veren basit bir etkileşim uyarısının çok ötesine geçer. Konum yönetimi, ön koşul kontrolleri, aşamalı minigame evreleri, ganimet dağıtımı, polis dispatch entegrasyonu, cooldown yönetimi ve anti-exploit korumalarını ele alan katmanlı bir mimari gerektirir. Sistem üç temel katmanla inşa edilmelidir: gereksinimleri ve ödülleriyle birlikte her soygun konumunu tanımlayan bir yapılandırma katmanı, aktif soygunları takip eden ve tüm kuralları uygulayan sunucu taraflı bir durum makinesi ve minigame'leri, animasyonları ve NUI arayüzlerini oluşturan istemci taraflı bir sunum katmanı. İstemci taraflı mantık kolayca suistimal edilebildiğinden, her kritik karar sunucu tarafında gerçekleşmelidir.
Soygun Konumlarını ve Kademelerini Yapılandırma
Soygun sisteminiz, artan zorluk seviyelerine sahip birden fazla konum türünü desteklemelidir. Marketler, minimum polis varlığı ve temel aletler gerektiren giriş seviyesini temsil eder. Fleeca banka şubeleri, orta düzey güvenlik katmanları ve daha yüksek polis gereksinimleriyle orta kademede yer alır. Pacific Standard kasası ise tam bir ekip, gelişmiş ekipmanlar ve çevrim içi önemli bir kolluk kuvveti varlığı gerektiren en üst düzey soygun olarak hizmet verir. Her konumun koordinatlarını, gerekli eşyalarını, minimum polis sayısını, bekleme süresini (cooldown), ödül aralığını ve aşılması gereken güvenlik katmanlarının sırasını tanımlayan bir yapılandırma girdisine ihtiyacı vardır:
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},
},
},
}
Her kademe yalnızca ödül açısından değil, karmaşıklık ve risk açısından da ölçeklenmelidir. Mağaza soygunları iki dakikadan kısa süren hızlı vur-kaç eylemleriyken, Pacific Standard soygunu polise çevre güvenliği sağlamak için bolca zaman tanıyan ve tamamlanması on beş dakika veya daha uzun sürebilen çok aşamalı bir operasyondur.
Sunucu Taraflı Durum Makinesi
Soygun state machine yapısı sistemin kalbidir. Her soygun konumunu yaşam döngüsü durumları üzerinden takip eder: idle, in-progress, cooldown ve locked. Bir oyuncu soygun başlattığında sunucu, konumu idle durumundan in-progress durumuna geçirmeden önce tüm ön koşulları doğrular. In-progress durumu sırasında sunucu, suçluların o anda hangi güvenlik katmanında olduğunu, hangi oyuncuların katıldığını ve ne kadar süre geçtiğini izler. Tüm oyuncular bölgeyi terk ederse veya tutuklanırsa, soygun otomatik olarak başarısız olur ve kısaltılmış bir cooldown sürecine girer. Tamamlandığında ise konum, tekrar kullanılabilir hale gelmeden önce yapılandırılan süre boyunca cooldown durumuna geçer:
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)
Durum makinesi, aktif soygunlar sırasındaki sunucu yeniden başlatmaları gibi sınır durumları da işlemelidir. Sunucu başladığında, tüm soygun durumlarını boşta (idle) durumuna sıfırlayın ve aktif katılımcıları temizleyin. Bekleme süresi zaman damgalarını kalıcı bir tabloda saklayın, böylece yeniden başlatmalardan etkilenmezler.
Mini Oyun Entegrasyonu
Mini oyunlar, soygunları pasif bir bekleme deneyiminden aktif bir beceri mücadelesine dönüştürür. Her güvenlik katmanı türü, farklı oyuncu yeteneklerini test eden farklı bir mini oyun tarzıyla eşleşmelidir. Hackleme mini oyunları: hafıza eşleştirme bulmacalarını, devre bağlama görevlerini veya hızlı sayı dizilerini kullanabilir. Termit yerleşimi, yüklerin sönmeden önce yerleştirilmesi için hassas bir zamanlama gerektirir. Delme mekanikleri, oyuncu matkap ucunu aşırı ısınmadan kilit mekanizması boyunca yönlendirirken sabit fare kontrolünü test eder. Temel tasarım ilkesi, daha zor kademelerin daha dar zaman aralıklarına, takip edilecek daha fazla ögeye veya daha yüksek hızlara sahip bu mini oyunların daha karmaşık varyantlarını kullanması gerektiğidir:
-- 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)
Başarısız minigame denemelerinin sonuçları olmalıdır. Başarısız bir hack ek alarmları tetikleyebilir, kalan süreyi azaltabilir veya oyuncuyu kısa bir ceza süresi boyunca kilitleyebilir. Üst düzey soygunlarda, son hack denemesinde başarısız olmak kasayı tamamen kilitleyebilir ve ekibi yalnızca kısmi ganimetle soygunu terk etmeye zorlayabilir. Bu başarısızlık durumları gerilim katar ve başarılı tamamlamaların gerçekten tatmin edici hissettirmesini sağlar.
Polis Dispatch ve Müdahale Entegrasyonu
Bir soygun sistemi, polis entegrasyonu olmadan yalnızca yarı yarıya tamamlanmış sayılır. Bir soygun başladığında dispatch sistemi, soygun kademesine bağlı olarak derecelendirilmiş bildirimler göndermelidir. Bir market soygunu, dükkan konumuyla birlikte basit bir sessiz alarm bildirimi oluşturur. Bir Fleeca şubesi, şube adı ve önerilen müdahale seviyesiyle bir banka alarmını tetikler. Pacific Standard soygunu ise mevcut tüm birimlerin müdahale etmesini öneren tam bir acil durum yayını başlatır. Soygun ilerledikçe polise gerçek zamanlı güncellemeler sağlayın: suçlular yeni bir güvenlik katmanını aştığında, bina içinde silah sesleri duyulduğunda veya suçlular kaçmaya çalıştığında. Bu güncellemeler polisin müdahalesini koordine etmesine yardımcı olur ve memurların hemen içeri girmek ile çevre güvenliği alıp müzakere etmek arasında karar verebileceği dinamik senaryolar yaratır. Suçluların NPC banka görevlilerini rehin alabileceği bir rehin alma mekanizması uygulayın; bu mekanizma polis müzakerecilerine bir rol verirken suçlulara da polisin müdahalesini geciktirmek için bir koz sağlar. Rehin alma sistemi kaç rehinenin tutulduğunu, herhangi birinin zarar görüp görmediğini takip etmeli ve suçlular ile müdahaleye gelen memurlar arasındaki telefon görüşmeleri aracılığıyla müzakere yönlendirmeleri sunmalıdır.
Ganimet Dağıtımı ve Para Aklama
Oyuncuların bir soygundan ne elde ettiği, soygunun kendisi kadar önemlidir. Temiz nakit parayı doğrudan banka hesaplarına yatırmak yerine, suçluları kullanılabilir para birimine dönüştürmek için ek adımlar gerektiren işaretli banknotlar veya çalıntı mallarla ödüllendirin. Bu tasarım, suç oynanış döngüsünü soygunun ötesine taşır ve birbirine bağlı sistemler oluşturur. İşaretli banknotlar, harita genelindeki belirli konumlarda yüzdelik bir komisyon karşılığında aklanabilir; bu da paranın ne zaman ve nerede aklanacağına dair risk ve kazanç kararları yaratır. Çalıntı mücevher veya elektronik eşyalar, eşya nadirliğine ve güncel piyasa koşullarına bağlı olarak değişken oranlar sunan NPC alıcıları aracılığıyla elden çıkarılmalıdır. Fiziksel ganimetin oyuncular tarafından taşınması gereken, hareket hızlarını sınırlayan ve silah kullanımını engelleyen bir ganimet çantası sistemi uygulayın; bu da kaçış aşamasına taktiksel faktörler ekler:
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)
Anti-Exploit ve Bekleme Süresi Yönetimi
Soygun sistemleri, zenginlik ürettikleri için istismarcıları çeker. Yaygın açıklara karşı birden fazla koruma katmanı uygulayın. Sunucu taraflı mesafe kontrolleri, oyuncuların her aşama boyunca soygun konumunda fiziksel olarak bulunmasını sağlar. Hız sınırlaması (rate limiting), oyuncuların soygun başlatma event'lerini spamlamasını önler. Katılımcı takibi, yalnızca kayıtlı katılımcıların güvenlik katmanlarında ilerleyebilmesini veya ganimet alabilmesini sağlar. Global cooldown'lar, aynı anda kaç soygunun aktif olabileceğini sınırlayarak sunucu genelindeki soygun spam'ini önler. Oyuncu başına cooldown'lar, tek bir oyuncunun art arda birden fazla konumu zincirleme soymasını engeller. Yöneticilerin şüpheli durumları inceleyebilmesi için her soygun girişimini zaman damgaları, katılımcı tanımlayıcıları, başarı veya başarısızlık durumu ve dağıtılan ödülle kaydedin. Bir oyuncunun tüm güvenlik katmanlarını fiziksel olarak mümkün olandan daha hızlı bitirdiği imkansız tamamlanma sürelerini izleyin. Aşırı soygun faaliyetinin daha fazla polis dikkatini ve daha ağır sonuçları çektiği, oyuncuları suç faaliyetlerini zamana yaymaya teşvik eden doğal bir sınırlama oluşturan bir itibar sistemi uygulayın.
Kaçış Rotaları ve Dinamik Etkinlikler
Kaçış aşaması, soygunların gerçekten öngörülemez hale geldiği yerdir. Ganimet güvenceye alındıktan sonra suçlular, hareketlerini kısıtlayan ağır spor çantaları taşırken bölgeden kaçmalıdır. Sistemi birden fazla kaçış yöntemini destekleyecek şekilde tasarlayın: dışarıya park edilmiş kara araçları, sahil kenarındaki bankalar için yakındaki iskelelerdeki tekneler veya üst düzey soygunlar için çatılardan helikopter tahliyeleri. Kaçış aşamasında polisin kullanabileceği lastik patlatan kapanlar, şüpheli araç tanımını ortaya çıkaran telsiz konuşması güncellemeleri ve kilit kavşaklardaki rastgele barikatlar gibi dinamik etkinlikler ekleyin. Sunucu, suçluların banka çevresinde yapılandırılabilir bir yarıçap olarak tanımlanan soygun bölgesinden başarıyla ayrılıp ayrılmadığını takip etmeli ve soygunu ancak o zaman tamamen tamamlandı olarak işaretlemelidir. Tüm katılımcılar bölgeden çıkmadan önce öldürülür veya tutuklanırsa ganimet polis tarafından delil olarak geri alınabilmelidir. Bu, her iki taraf için de soygun sonrası anlamlı bir oynanış yaratır ve kaçmanın da soygunun kendisi kadar zorlu ve tatmin edici olmasını sağlar.