[ESX] & [QBCORE] & [QBOX] Fruit Picker Job Script

Showcase
FRUIT PICKER JOB SCRIPT

Purchase
[QBCore & ESX & QBOX] - Fruit Picker Job Script

Shaking the tree
Extracting Ink

Six different fruit fields pre-configured: apple, orange, pear, lemon, peach, and plum.
Custom Minigame

Bottle/Jar Labelingr
Cutting Money Sheet

Mixing Jams
Cutting Money Sheet

Delivering Products
Cutting Money Sheet

Features

  • Interactive Fruit Picking System: Shake trees across different fields to gather fruits like apples, oranges, lemons, pears, peaches, and plums. Each tree has limited fruit for a more realistic feel.
  • Washing & Preparation Process: Wash dirty fruits, bottles, and jars before using them in production. Every step includes synced animations and detailed particle effects.
  • Juice & Jam Crafting: Use fresh fruit, sugar, and pectin to craft high-quality juices and jams. Recipes are defined in the config, allowing full control over ingredients and timing.
  • Jam Mixing System: Combine two types of jam to create unique flavors with higher profit potential. Mixing is done through an intuitive crafting menu.
  • Labeling & Filling Stations: Label your jars and bottles using the conveyor system, then fill them with your finished product to prepare for sale or delivery.
  • Flexible Selling Options: Instantly sell your goods for quick cash or package and deliver orders to customers for bigger rewards. Delivery prices scale with distance.
  • Dynamic Pricing System: All sales and delivery items support dynamic pricing, meaning item value changes based on in-game economy settings.
  • Built-In Exploit Protection: The script includes spawn checks, anti-cheat kick logic, and order validation to ensure fair gameplay.
  • Fully Customizable: Adjust fruit types, item labels, production times, prices, ingredients, and more via the config file.

Optimization
Full optimized.
0.00 ms

Code is accessible No
Subscription-based No
Lines (approximately) : ~5000
Requirements d3MBA-lib - Support most popular context menus (ox_lib, qb-menu, nh-context) - (ox_inputmenu, qb-input, nh-keyboard) (ox_target, qtarget, qb-target), PolyZone
Support Yes

Other Resources

Config

Config.DebugPolyZone = false -- [true/false] - If you want to see polyzone borders, set it to 'true' (Config.DebugPolyZone = true) 

Config.KickReason = "[d3MBA-fruitpickerjob] | Protection!" -- Kick reason if player try to cheat.

-- Config.JobRequired = "JOB_NAME" -- if you want to disable it just set it to 'false' (Config.JobRequired = false) 
Config.JobRequired = false -- Job name e.g. Config.JobRequired = "fruitpicker", make sure you have that job in the your framework(qbcore, esx, qbox...)

-- Particles synchronization   
Config.SyncParticlesWithAllPlayers = { -- If is false particles will see only the player who triggered it. 
    WashingDirtyItem = true, -- [true/false] - If you want to sync particles with all players, set it to 'true'
    MixingJams = true, -- [true/false] - If you want to sync particles with all players, set it to 'true'
    FillingItem = true, -- [true/false] - If you want to sync particles with all players, set it to 'true'
}

Config.Blip = { -- Main blip configuration
    -- https://docs.fivem.net/docs/game-references/blips/
    Pos = vector3(412.1158, 6481.666, 27.807),
    Use = true, 
    Sprite = 568,
    Scale = 1.1,
    Color = 17,         
    Label = "Fruit Picker Job", 
}

Config.Instructions = { 
    SetPedInvisable = true, -- [true/false] - If you want to set ped invisable during instructions set it to 'true' (Config.Instructions.SetPedInvisable = true)
    SetRentPedBlockingOtherEvents = true, -- [true/false] - If you want to set rent ped blocking other events, set it to 'true' (Config.Instructions.SetRentPedBlockingOtherEvents = true) 

    -- Link for ped models - https://docs.fivem.net/docs/game-references/ped-models/
    Peds = {
        {Model = "s_m_m_trucker_01", Pos = vector4(2328.740, 4926.869, 40.909, 316.27)},
        {Model = "s_m_m_cntrybar_01", Pos = vector4(2284.929, 4974.396, 40.822, 317.4)},
        {Model = "s_m_m_cntrybar_01", Pos = vector4(2378.883, 5028.453, 44.894, 134.0)},
        {Model = "s_m_m_cntrybar_01", Pos = vector4(2304.925, 4758.785, 36.221, 258.81)},
        {Model = "s_m_m_cntrybar_01", Pos = vector4(2349.520, 4741.902, 33.525, 56.45)},
        {Model = "s_m_m_cntrybar_01", Pos = vector4(2446.739, 4659.842, 31.695, 52.03)},
        {Model = "s_m_m_cntrybar_01", Pos = vector4(2360.876, 4747.762, 33.503, 228.08)},
        {Model = "s_m_m_cntrybar_01", Pos = vector4(-1788.93, 2027.547, 125.21, 348.39)},
        {Model = "s_m_m_cntrybar_01", Pos = vector4(-1813.40, 1938.497, 133.54, 332.88)},
        {Model = "s_m_m_cntrybar_01", Pos = vector4(-1737.60, 2029.914, 112.68, 122.1)},
        {Model = "s_m_m_cntrybar_01", Pos = vector4(2334.753, 4944.350, 40.834, 125.81)},
        {Model = "s_m_m_cntrybar_01", Pos = vector4(292.2745, 6513.561, 29.008, 95.14)},
        {Model = "s_m_m_cntrybar_01", Pos = vector4(416.1566, 6520.784, 26.735, 266.76)},
        {Model = "s_m_m_cntrybar_01", Pos = vector4(408.2722, 6498.516, 26.767, 177.59)},
        {Model = "s_m_m_cntrybar_01", Pos = vector4(383.9749, 6524.742, 27.386, 106.75)},
        {Model = "s_m_m_cntrybar_01", Pos = vector4(353.8508, 6498.122, 27.618, 14.83)},
        {Model = "s_m_m_cntrybar_01", Pos = vector4(241.6500, 6493.268, 29.826, 5.45)},
        {Model = "s_m_m_cntrybar_01", Pos = vector4(-1855.59, 2015.269, 135.37, 275.82)},
        {Model = "s_m_m_cntrybar_01", Pos = vector4(-1768.80, 1990.883, 116.86, 114.54)},
        {Model = "s_m_m_cntrybar_01", Pos = vector4(433.6174, 6500.397, 27.860, 7.3)},
        {Model = "s_m_m_cntrybar_01", Pos = vector4(430.2473, 6472.247, 27.781, 144.36)},
        {Model = "s_m_m_cntrybar_01", Pos = vector4(442.5442, 6457.536, 34.864, 47.13)},
        {Model = "s_m_m_cntrybar_01", Pos = vector4(418.1120, 6470.866, 27.812, 51.21)},
        {Model = "s_m_m_cntrybar_01", Pos = vector4(418.1120, 6470.866, 27.812, 51.21)},
    },
}

Config.ChangeClothes = { 
    Use = true, -- [true/false] - If you want to use change clothes, set it to 'true' (Config.ChangeClothes.Use = true)
    CheckBeforeAnyInteraction = false,  -- [true/false] - If you want to check before any interaction, if player wearing job uniform set it to 'true' (Config.ChangeClothes.CheckBeforeAnyInteraction = true)
    
    -- This thing you should adjust to your server. Numbers for clothes you should find in your clothing shop!
    Uniforms = {
        Male = { 
            -- AJUST THIS FOR YOUR SERVER
            tshirt_1 = 15,  tshirt_2 = 0,
            torso_1 = 43,   torso_2 = 0,
            decals_1 = 0,   decals_2 = 0,
            arms = 70,
            pants_1 = 9,   pants_2 = 6,
            shoes_1 = 25,   shoes_2 = 0,
            chain_1 = 0,    chain_2 = 0,
            hat_1 = 20,     hat_2 = 0,
            ears_1 = -1,    ears_2 = 0,
            bproof_1 = 0,   bproof_2 = 0
        },  

        Female = {
            -- AJUST THIS FOR YOUR SERVER
            tshirt_1 = 23,  tshirt_2 = 0,
            torso_1 = 22,   torso_2 = 0,
            decals_1 = 0,   decals_2 = 0,
            arms = 85,
            pants_1 = 36,   pants_2 = 0,
            shoes_1 = 12,   shoes_2 = 3,
            chain_1 = 0,    chain_2 = 0,
            hat_1 = -1,     hat_2 = 0,
            ears_1 = -1,    ears_2 = 0,
            bproof_1 = 0,   bproof_2 = 0
        }
    },
}

Config.JobVehicle = {
    Ped = {
        Model = "s_m_m_cntrybar_01", -- https://docs.fivem.net/docs/game-references/ped-models/
        Pos = vector4(442.0668, 6510.069, 27.782, 96.88),
    },

    
    Model = "kalahari", 

    JobVehicleBlip = {
        Sprite = 477,
        Color = 2,
        Scale = 0.9,
        Label = "[Fruit Picker] - Job vehicle",
    },

    ReturnVehilclePos = vector3(436.0768, 6509.083, 28.448), -- return vehicle 

    ReturnVehicleMarker = { 
        Use = true, -- [true/false] - If you want to use marker, set it to 'true'
        Distance = 40.0, -- [float] - Distance to see marker 
        Type = 1, -- https://docs.fivem.net/docs/game-references/markers/
        Size = vector3(8.0, 8.0, 1.0),
        Color = {r = 255, g = 255, b = 255, a = 150},
    },

    ReturnVehicleBlip = {
        Sprite = 477,
        Color = 1,
        Scale = 0.9,
        Label = "[Fruit Picker] - Return vehicle",
    },
    

    SpawnPos = vector4(436.6591, 6510.906, 27.031, 93.5), -- vehicle spawn position

    SetPedIntoVehicle = true, -- if true, ped will be set into vehicle after spawning. 
    FullFuel = true, -- if true, vehicle will be spawned with full fuel. 

    Deposit = {
        Use = true, -- [true/false] - If you want to use deposit system, set it to 'true'
        Account = "cash", -- ("cash", "bank")
        Amount = 500, -- amount of money to deposit
    },

    SpawnPointCheck = { -- It will check spawn point. To prevent spawning vehicle on vehicle. 
        Use = true,
        Radius = 3.5 -- Default radius 3.5
    },  
}

Config.ShakeTree = {
    ShakingTime = 5, -- Time to shake tree (in seconds)

    SmoothPickup = true, -- [true/false] - If you want to use smooth pickup, (smooth attaching fruit to player) set it to true

}

Config.WashingDirtyItem = {
    WashingItemTime = 5, -- Time to wash dirty item (dirty bottle or dirty jar) (in seconds)
    WashingFruitTime = 2.5, -- Time to wash fruit (in seconds) multiplied by amount of fruits!
}

Config.ItemLabeling = {
    Time = 3,
    LabelingSpeed = 0.8,
 
}


Config.MixJams = { -- Mixing jam  
    Time = 15, -- Time to mix jams (in seconds)

    MixingMenu = {

        -- Apple pear jam
        [Config.Items.ApplePearJam] = {
            [Config.Items.AppleJam] = 1,
            [Config.Items.PearJam] = 1,
        },
                
        -- Peach plum jam
        [Config.Items.PeachPlumJam] = {
            [Config.Items.PeachJam] = 1,
            [Config.Items.PlumJam] = 1,
        },

        -- Lemon orange jam
        [Config.Items.LemonOrangeJam] = {
            [Config.Items.LemonJam] = 1,
            [Config.Items.OrangeJam] = 1,
        },

        -- Pear plum jam
        [Config.Items.PearPlumJam] = {
            [Config.Items.PearJam] = 1,
            [Config.Items.PlumJam] = 1,
        },

        -- Apple peach jam
        [Config.Items.ApplePeachJam] = {
            [Config.Items.AppleJam] = 1,
            [Config.Items.PeachJam] = 1,
        },

    }
}

Config.JamAndJuiceProduction = {
    Ingredients = {
        Time = 2.5, -- Time to add ingredients (in seconds) multiplied by amount of ingredients!
    },

    Jam = {
        Time = 15, -- Time to produce jam (in seconds)
        Ingredients = {
            [Config.Items.Sugar] = 2,
            [Config.Items.FruitPectin] = 1,
        },
        FruitAmount = 7, -- Amount of fruits needed to produce jam
    },

    Juice = {
        Time = 10, -- Time to produce juice (in seconds)
        Ingredients = {
            [Config.Items.Sugar] = 2,
        },
        FruitAmount = 5, -- Amount of fruits needed to produce juice
    },

    StartingProductionTime = 3, -- Time to start production (in seconds) - this is the time when player can cancel production

    ProductionTime = { -- Random time to produce jam or juice IN SECONDS!
        Juice = { -- Random time to produce juice in range min and max seconds
            Min = 15, -- Minimum time to produce juice (in seconds) 
            Max = 25 -- Maximum time to produce juice (in seconds)
        }, 
        Jam = { -- Random time to produce jam in range min and max seconds
            Min = 20, -- Minimum time to produce jam (in seconds) 
            Max = 30 -- Maximum time to produce jam (in seconds)
        }
    },

    FillingTime = 7, -- Time to fill bottle or jar (in seconds)

}

Config.InstantSell = { 
    Use = true, -- [true/false] - If you want to use instant sell system, set it to 'true' 

    DisableQuickAllSell = false, -- [true/false] - If you want to disable "quick sell all items" button in the menu, set it to 'true' (Config.InstantSell.DisableQuickAllSell = true)

    Ped = {
        Model = "ig_sacha", -- https://docs.fivem.net/docs/game-references/ped-models/
        Pos = vector4(442.8260, 6457.162, 27.779, 53.11),
    }, 

    Blip = { -- https://docs.fivem.net/docs/game-references/blips/
        Use = true, -- [true/false] - If you want to use blip, set it to 'true'
        Sprite = 514,
        Color = 5,
        Scale = 0.9,
        Label = "[Fruit Picker] - Sell point",
    },

    DynamicPrices = {
        Use = true, -- [true/false] - If you want to use dynamic prices, set it to 'true'
        PriceMinMultiplier = 0.7, -- Min price multiplier, 70% of original price
        PriceMaxMultiplier = 1.5, -- Max price multiplier, 150% of original price
    }, 

    Account = "cash", -- ("cash", "bank")

    SellMenu = {
        -- Juices
        {ItemName = Config.Items.AppleJuice, Price = 45},
        {ItemName = Config.Items.OrangeJuice, Price = 50},
        {ItemName = Config.Items.LemonJuice, Price = 60},
        {ItemName = Config.Items.PearJuice, Price = 65},
        {ItemName = Config.Items.PeachJuice, Price = 80},
        {ItemName = Config.Items.PlumJuice, Price = 85},

        -- Jams
        {ItemName = Config.Items.AppleJam, Price = 50},
        {ItemName = Config.Items.OrangeJam, Price = 55},
        {ItemName = Config.Items.LemonJam, Price = 65},
        {ItemName = Config.Items.PearJam, Price = 70},
        {ItemName = Config.Items.PeachJam, Price = 90},
        {ItemName = Config.Items.PlumJam, Price = 95},

        -- Mixed Jams
        {ItemName = Config.Items.ApplePearJam, Price = 120},
        {ItemName = Config.Items.PeachPlumJam, Price = 250},
        {ItemName = Config.Items.LemonOrangeJam, Price = 130},
        {ItemName = Config.Items.PearPlumJam, Price = 170},
        {ItemName = Config.Items.ApplePeachJam, Price = 200},
        -- You can add more items here.
    }
}

Config.Delivery = {
    AutoDeleteOrder = 5, -- Time to auto delete order if is it unpackaged or not delivered (IN DAYS)

    PedModels = {
        "s_m_m_migrant_01", -- https://docs.fivem.net/docs/game-references/ped-models/
    },

    Account = "cash", -- ("cash", "bank")

    WaitingTime = { -- Time to find order (in seconds)  
        Min = 30, -- [Min] - Minimum time to find order (delivery point) (in seconds)
        Max = 60, -- [Max] - Maximum time to find order (delivery point) (in seconds)
    },

    Blip = {
        Use = true, -- [true/false] - If you want to use blip, set it to 'true'
        Sprite = 514,
        Color = 47,
        Scale = 1.0,
        Label = "[Fruit Picker] - Delivery point",
    },

    DeliveryPoints = { -- Delivery points
        vector4(2475.053, 4445.328, 35.397, 273.87),
        vector4(1088.094, 6509.520, 21.071, 198.03),            

        -- You can add more delivery points here.
    }, 

    NumberOfItems = { -- Number of items per order 
        Small = {
            Min = 2, -- [Min] - Minimum number of items per order
            Max = 4, -- [Max] - Maximum number of items per order
        },
        Large = { -- NUMBER IS LOWER THAN SMALL BECAUSE OF PRICE OF AMOUNT NEEDED FOR EACH ITEM
            Min = 4, -- [Min] - Minimum number of items per order
            Max = 6, -- [Max] - Maximum number of items per order
        },
    },

    DynamicPrices = {
        Use = true, -- [true/false] - If you want to use dynamic prices, set it to 'true'
        PriceMinMultiplier = 0.8, -- Min price multiplier, 80% of original price
        PriceMaxMultiplier = 1.7, -- Max price multiplier, 170% of original price
    }, 

    DistanceMultiplier = {
        Use = true, -- [true/false] - If you want to use distance multiplier, set it to 'true'
        PriceMultiplier = 0.1, -- Adittional earn for each meter - (distance between company and delivery point) default 0.1$ per meter
    },

    PackagingTime = 15, -- Time to pack items (in seconds) 

    DeliveryItems = { -- Items that can be delivered
        Small = { 

            -- Juices
            {ItemName = Config.Items.AppleJuice, Price = 65, Amount = {Min = 3, Max = 7}},
            {ItemName = Config.Items.OrangeJuice, Price = 70, Amount = {Min = 2, Max = 4}},
            {ItemName = Config.Items.LemonJuice, Price = 80, Amount = {Min = 1, Max = 3}},
            {ItemName = Config.Items.PearJuice, Price = 85, Amount = {Min = 1, Max = 3}},
            {ItemName = Config.Items.PeachJuice, Price = 100, Amount = {Min = 1, Max = 2}},
            {ItemName = Config.Items.PlumJuice, Price = 105, Amount = {Min = 1, Max = 3}},
            -- Jams
            {ItemName = Config.Items.AppleJam, Price = 70, Amount = {Min = 2, Max = 6}},
            {ItemName = Config.Items.OrangeJam, Price = 75, Amount = {Min = 2, Max = 5}},
            {ItemName = Config.Items.LemonJam, Price = 85, Amount = {Min = 1, Max = 2}},
            {ItemName = Config.Items.PearJam, Price = 90, Amount = {Min = 1, Max = 3}},
            {ItemName = Config.Items.PeachJam, Price = 110, Amount = {Min = 2, Max = 2}},
            {ItemName = Config.Items.PlumJam, Price = 115, Amount = {Min = 1, Max = 2}},
            -- Mixed Jams
            {ItemName = Config.Items.ApplePearJam, Price = 140, Amount = {Min = 1, Max = 2}},
            {ItemName = Config.Items.PeachPlumJam, Price = 270, Amount = {Min = 1, Max = 2}},
            {ItemName = Config.Items.LemonOrangeJam, Price = 150, Amount = {Min = 1, Max = 2}},
            {ItemName = Config.Items.PearPlumJam, Price = 190, Amount = {Min = 1, Max = 2}},
            {ItemName = Config.Items.ApplePeachJam, Price = 220, Amount = {Min = 1, Max = 2}},
        },
        Large = { -- LARGE ORDER
            -- Juices
            {ItemName = Config.Items.AppleJuice, Price = 65, Amount = {Min = 4, Max = 7}},
            {ItemName = Config.Items.OrangeJuice, Price = 70, Amount = {Min = 2, Max = 5}},
            {ItemName = Config.Items.LemonJuice, Price = 80, Amount = {Min = 1, Max = 4}},
            {ItemName = Config.Items.PearJuice, Price = 85, Amount = {Min = 2, Max = 3}},
            {ItemName = Config.Items.PeachJuice, Price = 100, Amount = {Min = 2, Max = 2}},
            {ItemName = Config.Items.PlumJuice, Price = 105, Amount = {Min = 1, Max = 2}},
            -- Jams
            {ItemName = Config.Items.AppleJam, Price = 70, Amount = {Min = 3, Max = 7}},
            {ItemName = Config.Items.OrangeJam, Price = 75, Amount = {Min = 1, Max = 4}},
            {ItemName = Config.Items.LemonJam, Price = 85, Amount = {Min = 1, Max = 3}},
            {ItemName = Config.Items.PearJam, Price = 90, Amount = {Min = 2, Max = 4}},
            {ItemName = Config.Items.PeachJam, Price = 110, Amount = {Min = 1, Max = 3}},
            {ItemName = Config.Items.PlumJam, Price = 115, Amount = {Min = 1, Max = 2}},
            -- Mixed Jams
            {ItemName = Config.Items.ApplePearJam, Price = 140, Amount = {Min = 1, Max = 2}},
            {ItemName = Config.Items.PeachPlumJam, Price = 270, Amount = {Min = 1, Max = 2}},
            {ItemName = Config.Items.LemonOrangeJam, Price = 150, Amount = {Min = 1, Max = 2}},
            {ItemName = Config.Items.PearPlumJam, Price = 190, Amount = {Min = 1, Max = 2}},
            {ItemName = Config.Items.ApplePeachJam, Price = 220, Amount = {Min = 1, Max = 2}},
        },
    }
}

Items

Config.Items = {
    -- Dirty Fruits
    DirtyApple = "fruitpicker_dirty_apple",
    DirtyOrange = "fruitpicker_dirty_orange",
    DirtyLemon = "fruitpicker_dirty_lemon",
    DirtyPear = "fruitpicker_dirty_pear",
    DirtyPeach = "fruitpicker_dirty_peach",
    DirtyPlum = "fruitpicker_dirty_plum",
    
    -- Fruits
    Apple = "fruitpicker_apple",
    Orange = "fruitpicker_orange",
    Lemon = "fruitpicker_lemon",
    Pear = "fruitpicker_pear",
    Peach = "fruitpicker_peach",
    Plum = "fruitpicker_plum",

    -- Ingredients
    Sugar = "fruitpicker_sugar",
    FruitPectin = "fruitpicker_fruit_pectin",

    -- Juice items
    DirtyBottle = "fruitpicker_dirty_bottle",
    Bottle = "fruitpicker_bottle",
    LabeledBottle = "fruitpicker_labeled_bottle",
 
    -- Jar items
    DirtyJar = "fruitpicker_dirty_jar",
    Jar = "fruitpicker_jar",
    LabeledJar = "fruitpicker_labeled_jar",

    -- Juices
    AppleJuice = "fruitpicker_apple_juice",
    OrangeJuice = "fruitpicker_orange_juice",
    LemonJuice = "fruitpicker_lemon_juice",
    PearJuice = "fruitpicker_pear_juice",
    PeachJuice = "fruitpicker_peach_juice",
    PlumJuice = "fruitpicker_plum_juice",

    -- Jams
    AppleJam = "fruitpicker_apple_jam",
    OrangeJam = "fruitpicker_orange_jam",
    LemonJam = "fruitpicker_lemon_jam",
    PearJam = "fruitpicker_pear_jam",
    PeachJam = "fruitpicker_peach_jam",
    PlumJam = "fruitpicker_plum_jam",

    -- Mixed jams
    ApplePearJam = "fruitpicker_applepear_jam",
    PeachPlumJam = "fruitpicker_peachplum_jam",
    LemonOrangeJam = "fruitpicker_lemonorange_jam",
    PearPlumJam = "fruitpicker_pearplum_jam",
    ApplePeachJam = "fruitpicker_applepeach_jam",

    -- Order
    Order = "fruitpicker_order",
} 

Hey, Buddy! It looks great again.

Its possible also without PolyZone and to use just ox lib Zones?