ब्लॉग पर वापस
Tutorial9 मिनट पढ़ें

FiveM वेंडिंग मशीन स्क्रिप्ट: भोजन, पेय और अधिक

अपने FiveM सर्वर में कार्यशील वेंडिंग मशीनें जोड़ें। स्नैक्स, ड्रिंक्स, कस्टम आइटम, प्रॉप प्लेसमेंट और मिनटों में इंस्टॉल करने के लिए शीर्ष वेंडिंग स्क्रिप्ट।

Agency Scripts

Agency Scripts के संस्थापक और प्रमुख डेवलपर

क्यों वेंडिंग मशीनें आपके सर्वर में गहराई जोड़ती हैं

वेंडिंग मशीनें और स्वचालित दुकान प्रणाली किसी भी रोलप्ले अर्थव्यवस्था में एक महत्वपूर्ण भूमिका निभाती हैं। वे भोजन, पानी, सिगरेट, और बुनियादी आपूर्ति जैसे आवश्यक वस्तुओं तक 24/7 पहुंच प्रदान करती हैं बिना किसी स्टोर क्लर्क के ऑनलाइन होने की आवश्यकता के। सुविधा से परे, वे प्राकृतिक सभा स्थल बनाती हैं जहां खिलाड़ी इकट्ठा होते हैं, जिससे गैस स्टेशन, अस्पताल, और कार्यालय भवनों में आकस्मिक रोलप्ले मुठभेड़ होती है। एक अच्छी तरह से लागू वेंडिंग मशीन प्रणाली एक सरल खरीद मेनू से कहीं अधिक है। इसमें यथार्थवादी खरीद एनिमेशन, स्टॉक प्रबंधन जो कमी पैदा करता है, आपूर्ति और मांग के अनुसार गतिशील मूल्य निर्धारण, विभिन्न मशीन प्रकार जो विभिन्न उत्पाद श्रेणियां बेचते हैं, आपराधिक रोलप्ले के लिए डकैती मैकेनिक, और पुनः स्टॉकिंग नौकरियां शामिल हैं जो खिलाड़ियों को सार्थक रोजगार देती हैं। यह ट्यूटोरियल प्रॉप डिटेक्शन से लेकर इन्वेंटरी एकीकरण और अर्थव्यवस्था प्रबंधन तक एक पूर्ण वेंडिंग और दुकान प्रणाली बनाने को कवर करता है।

वेंडिंग मशीन प्रॉप्स का पता लगाना और कॉन्फ़िगर करना

GTA V की दुनिया में वेंडिंग मशीन प्रॉप्स भरे हुए हैं जिन्हें आप इंटरैक्टिव ऑब्जेक्ट्स में बदल सकते हैं। मुख्य प्रॉप मॉडल्स में शामिल हैं prop_vend_soda_01 और prop_vend_soda_02 सोडा मशीनों के लिए, prop_vend_water_01 वाटर डिस्पेंसर्स के लिए, prop_vend_coffe_01 कॉफ़ी मशीनों के लिए, और prop_vend_snak_01 स्नैक मशीनों के लिए। मानचित्र पर हर मशीन स्थान पर मैन्युअल रूप से इंटरैक्शन पॉइंट्स रखने के बजाय, एक रेडियस-आधारित डिटेक्शन सिस्टम का उपयोग करें जो खिलाड़ी के पास इन प्रॉप मॉडल्स को स्कैन करता है। जब कोई खिलाड़ी इंटरैक्शन रेंज के भीतर किसी भी मेल खाने वाले प्रॉप के पास आता है, तो सिस्टम एक प्रॉम्प्ट या टारगेट ज़ोन सक्रिय करता है। यह तरीका पूरे मानचित्र में इन प्रॉप्स के हर उदाहरण के साथ बिना मैन्युअल कॉन्फ़िगरेशन के काम करता है, और यह कस्टम MLO इंटीरियर्स को भी पकड़ता है जिनमें ये मॉडल शामिल हैं। प्रत्येक प्रॉप प्रकार के लिए अलग-अलग उत्पाद कैटलॉग परिभाषित करें ताकि सोडा मशीनें केवल ड्रिंक बेचें, स्नैक मशीनें खाद्य आइटम बेचें, और कॉफी मशीनें कॉफी वेरिएंट बेचें।

-- shared/config.lua
Config = {}

Config.InteractDistance = 1.5
Config.UseAnimation     = true
Config.AnimDuration     = 3000 -- ms

Config.Machines = {
    soda = {
        models = {
            `prop_vend_soda_01`,
            `prop_vend_soda_02`,
        },
        label = 'Soda Machine',
        items = {
            {name = 'cola',       label = 'Cola',        price = 5,  stock = 20},
            {name = 'sprunk',     label = 'Sprunk',      price = 5,  stock = 20},
            {name = 'ecola',      label = 'E-Cola',      price = 6,  stock = 15},
            {name = 'energydrink',label = 'Energy Drink', price = 8,  stock = 10},
        },
    },
    snack = {
        models = {`prop_vend_snak_01`},
        label = 'Snack Machine',
        items = {
            {name = 'chips',      label = 'Chips',       price = 4,  stock = 25},
            {name = 'candy',      label = 'Candy Bar',   price = 3,  stock = 30},
            {name = 'sandwich',   label = 'Sandwich',    price = 7,  stock = 15},
            {name = 'granola',    label = 'Granola Bar',  price = 5,  stock = 20},
        },
    },
    coffee = {
        models = {`prop_vend_coffe_01`},
        label = 'Coffee Machine',
        items = {
            {name = 'coffee',     label = 'Black Coffee', price = 4,  stock = 30},
            {name = 'latte',      label = 'Latte',       price = 6,  stock = 20},
            {name = 'espresso',   label = 'Espresso',    price = 5,  stock = 25},
        },
    },
    water = {
        models = {`prop_vend_water_01`},
        label = 'Water Cooler',
        items = {
            {name = 'water',      label = 'Water Bottle', price = 3,  stock = 40},
        },
    },
}

क्लाइंट-साइड इंटरैक्शन और एनीमेशन सिस्टम

जब कोई खिलाड़ी वेंडिंग मशीन के पास जाता है और इंटरैक्शन कुंजी दबाता है, तो एक इमर्सिव खरीद अनुभव बनाने के लिए कई चीजें क्रम में होती हैं। सबसे पहले, खिलाड़ी की गति को प्रतिबंधित किया जाता है ताकि वे एनिमेशन के बीच में दूर न चल सकें। फिर खिलाड़ी का पात्र मशीन की ओर मुड़ता है TaskTurnPedToFaceEntity. एक खरीदारी एनीमेशन चलती है जो उपयोग करती है MINI@SPRUNK सोडा मशीनों के लिए एनीमेशन डिक्शनरी या ANIM@AM_HOLD_UP@MALE सामान्य इंटरैक्शन के लिए। मशीन स्वयं एक ध्वनि प्रभाव चलाती है जिसका उपयोग PlaySoundFromEntity यांत्रिक डिस्पेंसिंग शोर का अनुकरण करने के लिए। एनिमेशन पूरा होने के बाद, क्लाइंट सर्वर को खरीद अनुरोध भेजता है, जो लेनदेन को सत्यापित करता है और आइटम को खिलाड़ी के इन्वेंटरी में जोड़ता है। यदि मशीन में कॉइन स्लॉट इंटरैक्शन है, तो एनिमेशन के दौरान खिलाड़ी के हाथ में एक छोटा प्रॉप संलग्न करने के लिए उपयोग करें AttachEntityToEntity अतिरिक्त दृश्य विश्वसनीयता के लिए। पूरी श्रृंखला को लगभग 3 सेकंड लेना चाहिए, जो यथार्थवादी महसूस करने के लिए पर्याप्त लंबा है लेकिन खिलाड़ियों को निराश न करने के लिए पर्याप्त छोटा है।

-- client/interaction.lua
local isBuying = false

function PurchaseFromMachine(machineEntity, machineType, itemIndex)
    if isBuying then return end
    isBuying = true

    local ped = PlayerPedId()
    local machineCoords = GetEntityCoords(machineEntity)

    -- Face the machine
    TaskTurnPedToFaceEntity(ped, machineEntity, 1000)
    Wait(1000)

    -- Play animation
    if Config.UseAnimation then
        RequestAnimDict('mini@sprunk')
        while not HasAnimDictLoaded('mini@sprunk') do Wait(10) end

        TaskPlayAnim(ped, 'mini@sprunk', 'plyr_buy_drink_pt1',
            8.0, -8.0, 2000, 0, 0, false, false, false)
        Wait(1500)

        TaskPlayAnim(ped, 'mini@sprunk', 'plyr_buy_drink_pt2',
            8.0, -8.0, 1500, 0, 0, false, false, false)

        -- Machine sound effect
        PlaySoundFromEntity(-1, 'vending_machine_purchase',
            machineEntity, 'dlc_vw_table_games', false, 0)
        Wait(1500)
    end

    -- Request purchase from server
    TriggerServerEvent('vendingmachine:purchase', machineType, itemIndex)

    ClearPedTasks(ped)
    isBuying = false
end

सर्वर-साइड स्टॉक प्रबंधन और अर्थव्यवस्था

स्टॉक प्रबंधन वेंडिंग मशीनों को असीमित आइटम डिस्पेंसर से बदलकर गतिशील आर्थिक तत्व बनाता है। प्रत्येक मशीन स्थान अपनी इन्वेंटरी स्वतंत्र रूप से ट्रैक करता है। जब किसी मशीन में किसी विशेष आइटम का स्टॉक खत्म हो जाता है, तो खिलाड़ी खरीद मेनू में इसे बिक चुका के रूप में देखते हैं। स्टॉक स्तर डेटाबेस में सर्वर पुनः प्रारंभ के दौरान भी बना रहता है। एक रिस्टॉकिंग जॉब खिलाड़ियों को डिलीवरी ड्राइवर के रूप में काम करने की अनुमति देता है जो गोदाम से सप्लाई उठाकर शहर के खाली मशीनों तक ले जाते हैं। यह एक पूरा आर्थिक चक्र बनाता है: सप्लायर मशीनों को रिस्टॉक करते हैं, मशीनें उपभोक्ताओं को बेचती हैं, राजस्व मशीन मालिक को वापस जाता है, और डिलीवरी ड्राइवर मजदूरी कमाता है। डायनेमिक प्राइसिंग एक और स्तर जोड़ता है जहां लोकप्रिय आइटम धीरे-धीरे कीमत बढ़ाते हैं जैसे-जैसे स्टॉक कम होता है, और कीमतें मशीन के रिस्टॉक होने पर रीसेट हो जाती हैं। यह स्वाभाविक रूप से खपत पैटर्न को संतुलित करता है और जब मशीन में कोई वांछित आइटम कम होता है तो तत्कालता पैदा करता है।

-- server/stock.lua
local machineStock = {}

function GetMachineKey(machineType, coords)
    return machineType .. ':' ..
        math.floor(coords.x) .. ':' ..
        math.floor(coords.y) .. ':' ..
        math.floor(coords.z)
end

function GetStock(machineKey, itemIndex)
    if not machineStock[machineKey] then
        -- Load from database or initialize defaults
        machineStock[machineKey] = {}
    end
    return machineStock[machineKey][itemIndex] or
        Config.Machines[machineKey:match('^(%w+):')].items[itemIndex].stock
end

RegisterNetEvent('vendingmachine:purchase', function(machineType, itemIndex)
    local src = source
    local config = Config.Machines[machineType]
    if not config or not config.items[itemIndex] then return end

    local item = config.items[itemIndex]
    local machineKey = machineType -- simplified; use coords in production

    -- Check stock
    local stock = GetStock(machineKey, itemIndex)
    if stock <= 0 then
        TriggerClientEvent('ox_lib:notify', src, {
            title = 'Sold Out',
            description = item.label .. ' is out of stock',
            type = 'error'
        })
        return
    end

    -- Calculate dynamic price
    local basePrice = item.price
    local stockRatio = stock / item.stock
    local dynamicPrice = math.ceil(basePrice * (1 + (1 - stockRatio) * 0.5))

    -- Deduct money
    local paid = exports['framework']:RemoveMoney(src, dynamicPrice, 'cash')
    if not paid then
        TriggerClientEvent('ox_lib:notify', src, {
            title = 'No Cash',
            description = 'You need $' .. dynamicPrice,
            type = 'error'
        })
        return
    end

    -- Add item to inventory
    local added = exports['ox_inventory']:AddItem(src, item.name, 1)
    if not added then
        exports['framework']:AddMoney(src, dynamicPrice, 'cash')
        return
    end

    -- Decrease stock
    machineStock[machineKey] = machineStock[machineKey] or {}
    machineStock[machineKey][itemIndex] = stock - 1

    TriggerClientEvent('ox_lib:notify', src, {
        title = 'Purchased',
        description = item.label .. ' - $' .. dynamicPrice,
        type = 'success'
    })
end)

क्रिमिनल रोलप्ले के लिए डकैती तंत्र

वेंडिंग मशीनें आपराधिक पात्रों के लिए एक प्राकृतिक डकैती लक्ष्य प्रस्तुत करती हैं। एक लॉकपिक या प्राई-बार मैकेनिक लागू करें जो अपराधियों को मशीनों में घुसपैठ करने और अंदर की नकदी चोरी करने की अनुमति देता है। डकैती में समय लगेगा, एक मिनीगेम जैसे लॉकपिकिंग पहेली की आवश्यकता होगी, शोर उत्पन्न होगा जो आसपास के खिलाड़ियों को सतर्क करेगा और संभवतः पुलिस डिस्पैच को ट्रिगर करेगा, और एक परिवर्तनीय इनाम देगा जो मशीन द्वारा उसके अंतिम पुनः स्टॉकिंग या डकैती के बाद की गई खरीदों की संख्या पर आधारित होगा। वास्तविक खिलाड़ी खरीदों के आधार पर प्रति मशीन नकदी संचय को ट्रैक करें ताकि डकैती इनाम यथार्थवादी हो और वास्तविक आर्थिक गतिविधि से जुड़ा हो। सफल डकैती के बाद, मशीन एक क्षतिग्रस्त स्थिति में प्रवेश करती है जहां इसे मैकेनिक द्वारा मरम्मत किए जाने तक या कूलडाउन अवधि के बाद स्वचालित रूप से खरीद प्रक्रिया नहीं कर सकती। यह आपराधिक गतिविधि के लिए परिणाम उत्पन्न करता है जो व्यापक समुदाय को प्रभावित करता है और मैकेनिक के लिए मरम्मत कार्य उत्पन्न करता है, जिससे आर्थिक पारिस्थितिकी तंत्र और समृद्ध होता है।

प्लेयर-स्वामित्व वाले दुकानें और कस्टम स्टोरफ्रंट्स

वेंडिंग मशीन फ्रेमवर्क को खिलाड़ी-स्वामित्व वाले व्यवसायों के लिए पूर्ण प्वाइंट-ऑफ-सेल सिस्टम में विस्तारित करें। व्यवसाय मालिक अपनी संपत्तियों पर कस्टम दुकान काउंटर रख सकते हैं, वे कौन से आइटम बेचते हैं, अपनी कीमतें सेट कर सकते हैं, और प्रबंधन NUI के माध्यम से अपनी सूची प्रबंधित कर सकते हैं। दुकान प्रणाली वेंडिंग मशीनों के समान खरीद और स्टॉक मैकेनिक्स का उपयोग करती है लेकिन मालिक परत जोड़ती है जिसमें राजस्व ट्रैकिंग, खर्च प्रबंधन, कर्मचारी अनुमतियां, और लाभ रिपोर्ट शामिल हैं। व्यवसाय में क्लॉक इन कर्मचारी बिक्री को मैन्युअल रूप से प्रोसेस करने के लिए रजिस्टर तक पहुंच सकते हैं, जबकि स्वचालित प्रणाली तब बिक्री संभालती है जब कोई कर्मचारी उपस्थित नहीं होता। स्वचालित बिक्री से राजस्व व्यवसाय बैंक खाते में जाता है, जिसमें से एक विन्यास योग्य कर प्रतिशत सर्वर की सरकारी कोषागार में जाता है। यह एक पूर्ण खुदरा अर्थव्यवस्था बनाता है जहां खिलाड़ी वस्तुओं का निर्माण या स्रोत करते हैं, अपनी दुकानों को स्टॉक करते हैं, अन्य व्यवसायों के खिलाफ प्रतिस्पर्धात्मक मूल्य निर्धारण करते हैं, और अपने निवेश से निष्क्रिय आय कमाते हैं।

प्रदर्शन अनुकूलन और लक्ष्य एकीकरण

प्रॉप मॉडल्स के लिए हर फ्रेम स्कैन करना सर्वर प्रदर्शन को नष्ट कर देगा। इसके बजाय, एक स्तरित डिटेक्शन दृष्टिकोण का उपयोग करें। हर 2 सेकंड में 15-मीटर की त्रिज्या में व्यापक स्कैन चलाएं ताकि निकटवर्ती वेंडिंग मशीन प्रॉप्स मिल सकें। खोजे गए मशीन स्थानों को कैश करें और बाद के फ्रेम्स में केवल कैश के खिलाफ सटीक दूरी जांच करें। जब खिलाड़ी किसी भी कैश की गई मशीन से 20 मीटर से अधिक दूर जाता है, तो कैश साफ़ करें और एक नया स्कैन ट्रिगर करें। ox_target या qb-target जैसे टारगेट सिस्टम का उपयोग करने वाले सर्वरों के लिए, निकाले गए प्रॉप्स पर टारगेट ज़ोन पंजीकृत करें बजाय निकटता प्रॉम्प्ट के। टारगेट ज़ोन अधिक प्रदर्शनक्षम हैं क्योंकि वे केवल तब सक्रिय होते हैं जब खिलाड़ी वस्तु की ओर लक्ष्य करता है, जिससे निरंतर दूरी जांच की आवश्यकता पूरी तरह समाप्त हो जाती है। टारगेट दृष्टिकोण एक साफ UI अनुभव भी प्रदान करता है जिसमें संदर्भ-संवेदनशील इंटरैक्शन विकल्प सीधे मशीन मॉडल पर दिखाई देते हैं बजाय फ्लोटिंग टेक्स्ट प्रॉम्प्ट के।

-- client/target.lua (ox_target integration)
local registeredMachines = {}

CreateThread(function()
    for machineType, config in pairs(Config.Machines) do
        for _, model in ipairs(config.models) do
            exports.ox_target:addModel(model, {
                {
                    name     = 'vending_' .. machineType,
                    icon     = 'fas fa-shopping-cart',
                    label    = 'Use ' .. config.label,
                    onSelect = function(data)
                        OpenMachineMenu(machineType, data.entity)
                    end,
                    distance = Config.InteractDistance,
                },
            })
        end
    end
end)

शुरू करने के लिए तैयार?

हमारी शॉप से स्क्रिप्ट लें, या सपोर्ट, अपडेट और आगे आने वाली चीज़ों की झलक के लिए Discord से जुड़ें।