Bloga Geri Dön
Guide8 dk. okuma

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.

Başlamaya Hazır mısınız?

Scriptleri mağazamızdan edinin veya destek, güncellemeler ve gelecek yeniliklere göz atmak için Discord'a katılın.