Farming Routes & Workstations - Economy Control

A script by alva98

No reviews yet.
Farming Routes & Workstations - Economy Control main image

Price

Unknown

Full Description

Hey everyone :wave:

Today I’m releasing as-routes — a complete, fully dynamic routes/workstations system that solves the classic problem of hardcoded farming/drug scripts: you can create, edit and balance full loops ingame (farm → process → sell) without constantly touching code.

It supports ESX + QBCore and is built to be lightweight + scalable.
The ressource also takes advantage of some high performance tricks to make it as close to 0.0ms resmon on the server as possible.

Features :computer:

  • Create full loops: Farming zones → Sell NPCs → Transform points / Workstations
  • Admin panel (creator/editor) + visual debug overlay, including a map to visually see all routes/ways to obtain farming items on your server
  • Farming Boost Command for Admins and additional Farm-boost-Items you could sell via tebex, fully customizable. The boost-Items are persistent and only go down while a player is online!
  • Police raid system: route blocking, per-route cooldowns, raid hour windows, min police online, notifications + markers
  • Optional workstations (storage + tick processing) or classic transform points
  • Optional ox_target interactions + ox_lib notifications/progress bar
  • Blip categories, theme colors + translations

:gear:Config file preview

Config (click to expand)
Config                          = Config or {}

-- General
Config.debug                    = true -- enable debug prints in F8 console
Config.logLevel                 = "debug" -- debug | info | warn | error
Config.locale                   = "en-US" -- language key (see config/translations.json)
Config.framework                = "auto" -- "auto" | "esx" | "qb"

-- Commands
Config.adminCommand             = "routeadmin" -- command to open admin panel
Config.enableColorpickerCommand = true    -- set false to disable the color picker command and UI
Config.colorPickerCommand       = "routecolors" -- command to open the color picker overlay
Config.debugCommand             = "routedebug" -- command to see visual debug of routes
Config.access                   = Config.access or {}

Config.access.admins            = {
    esxGroups     = { admin = true, superadmin = true },
    qbPermissions = { god = true, admin = true },
}

Config.access.identifiers       = { -- manual identifier overrides
    -- ["steam:123123123"] = true,
    -- ["license:abcbacbacbacbacb"] = true,
    -- ["discord:123123123123123"] = true,
}

-- ox_target Integration
Config.useOxTarget              = true -- set true to use ox_target eye interactions on sell/transform/workstation NPCs

Config.useBlipCategories        = true -- if true, all route blips will have their own category
Config.blipCategorys            = {
    farm = {
        categoryId = 22,
        name = "Farming",
    },
    sell = {
        categoryId = 23,
        name = "Selling",
    },
    transform = {
        name = "Transform",
        categoryId = 24,
    },
    workstation = {
        name = "Workstation",
        categoryId = 25,
    }
}

-- Colors (UI theming)
Config.colors                   = {
    primary   = "#3E8BC8",
    primary25 = "#3E8BC835",
    primary45 = "#3E8BC865",
}

-- ================================================================
-- Item Images  (same pattern as as-garage)
-- %s is replaced with the item spawn name; UI tries .webp > .png > .jpg
-- ox_inventory default:
-- ================================================================
Config.imagePattern     = "https://cfx-nui-ox_inventory/web/images/%s"
Config.placeholderImage = "https://cfx-nui-ox_inventory/web/images/none.png"


Config.drawMarkerColor = "3E0F97D6" -- color for farm/sell markers; can also be set per route, AARRGGBB


-- ================================================================
-- Police Raid System
-- ================================================================
Config.policeRaid              = {
    enabled                  = true,

    -- Route block: how many hours a route stays blocked after a successful raid.
    -- During this time, nobody can farm/sell/transform on this route.
    blockHours               = 24,

    -- Per-route cooldown: once a specific route has been raided, it cannot be
    -- raided again for this many hours (even after blockHours expires).
    -- Example: 168 = 1 week before the same route can be raided again.
    raidCooldownHours        = 168,

    -- Global raid limit: max number of raids police can complete within
    -- the last `blockHours` window across ALL routes. Prevents officers
    -- from chain-raiding every route back-to-back.
    -- Set to 0 or nil to disable the global limit.
    maxRaidsWithinBlockHours = 2,

    -- Minimum police officers online: raids can only be started when at least
    -- this many players with an allowedJob are online. Prevents solo raids.
    -- Set to 0 to disable this check.
    minPoliceOnlineForRaid   = 1,

    -- Raid time restrictions: raids can only be started during these hours
    -- (server real time, 24h format). Supports wrap-around (e.g. 18 to 0).
    -- Remove or set to nil to allow raids at any time of day.
    raidHours                = {        -- use 24h format: "HH:MM"
        start = "06:15",                -- raids allowed from (6:15 AM)
        stop  = "22:15",                -- until 22:15 (10:15 PM)
    },
    raidArea                 = 50.0,    -- if a player leaves the raid zone (is further away than 50.0 for example, the raid fails)
    raidDurationSeconds      = 60 * 15, -- how long the officer must survive at the raid point
    clearWorkstationOnRaid   = false,   -- wipe all workstation data for this route on successful raid
    notifyRadius             = 400.0,   -- meters — players within this range get the big on-screen warning
    markerAboveRaidersHead   = true,    -- show a marker above the raiders' heads during the raid
    allowedJobs              = {        -- job = minimum grade required, for qb, can also be a gang with minimum rank
        ["police"]  = 1,
        ["sheriff"] = 1,
    },
}

Config.raidMarkerType          = 31   -- wolf head
Config.raidMarkerDrawDistance  = 20.0 -- distance to draw the raid marker

-- ================================================================
-- Farming / Selling / Workstation Defaults
-- ================================================================
Config.defaults                = {
    farmTime            = 5000,          -- ms per farm tick (overrideable per route)
    sellTime            = 1000,          -- ms per sell tick (overrideable per route)
    farmAmount          = 2,             -- items given per farm tick
    circleRadius        = 5.0,           -- default farm zone radius
    moneyType           = "money",       -- "money" | "bank" | "black_money" / "dirty"  (normal routes)
    drugMoneyType       = "black_money", -- money type for drug routes
    npcSpawnDistance    = 200.0,         -- distance to spawn sell NPCs
    npcDespawnDistance  = 220.0,         -- distance to despawn sell NPCs
    interactionDistance = 3.0,           -- distance to interact with sell NPC
    defaultNPCModel     = "s_m_m_cntrybar_01",
    defaultNPCScenario  = "WORLD_HUMAN_SMOKING",
    markerType          = 1,
    farmAnimation       = { -- animation played each farm tick
        dict = "pickup_object",
        clip = "pickup_low",
    },
}

-- ================================================================
-- Workstation Defaults
-- ================================================================
Config.workstation             = {
    enabled             = true, -- global toggle; if false, transform points are used instead
    defaultInput        = 5,    -- items consumed per tick
    defaultOutput       = 1,    -- items produced per tick
    defaultMaxInput     = 3000, -- max items storable
    defaultMaxOutput    = 300,  -- max converted items storable
    tickIntervalSeconds = 60,   -- how often a workstation tick processes (seconds)
    defaultPedModel     = "s_m_m_cntrybar_01",
    defaultPedAnim      = "WORLD_HUMAN_CLIPBOARD",
}

Config.sellAllItemsAtOnce      = false -- set to true to sell all items within the cooldown u set, if this is set to false
-- and the cooldown is 10s and it takes 5 items and you have 25, it will take 10 seconds *5 items = 50 seconds. Otherwise you sell all
-- 25 in 5 seconds.
Config.transformAllItemsAtOnce = false -- same as above but for transform points.
Config.transformPoint          = {
    useOxProgress       = true,        -- use ox_lib progressBar; set false to use custom, see client/open.lua doProgressBar()
    defaultDuration     = 5000,        -- ms for the progress bar
    defaultInputAmount  = 10,          -- items consumed
    defaultOutputAmount = 1,           -- items produced
    animation           = {
        dict = "mp_common",
        clip = "givetake1_a",
    },
}

-- ================================================================
-- Admin Panel Slider Limits
-- These control the min/max ranges for sliders in the admin UI.
-- Adjust to match your server's economy and gameplay balance.
-- ================================================================
Config.adminLimits             = {
    minPrice           = 0,
    maxPrice           = 2000,  -- maximum sell price per item
    minFarmTime        = 1000,  -- minimum farm time (ms) — at least 1 second
    maxFarmTime        = 60000, -- maximum farm time (ms)
    minSellTime        = 500,   -- minimum sell time (ms)
    maxSellTime        = 30000, -- maximum sell time (ms)
    minFarmAmount      = 1,     -- minimum items per farm tick
    maxFarmAmount      = 50,    -- maximum items per farm tick
    minRadius          = 1,     -- minimum farm circle radius
    maxRadius          = 30,    -- maximum farm circle radius
    minBlipScale       = 0.3,   -- minimum blip scale
    maxBlipScale       = 1.5,   -- maximum blip scale
    minTransformInput  = 1,     -- minimum transform input amount
    maxTransformInput  = 100,   -- maximum transform input amount
    minTransformOutput = 1,     -- minimum transform output amount
    maxTransformOutput = 100,   -- maximum transform output amount
    minTransformTime   = 1000,  -- minimum transform duration (ms)
    maxTransformTime   = 60000, -- maximum transform duration (ms)
    -- Workstation limits
    minInputPerTick    = 1,
    maxInputPerTick    = 50,
    minOutputPerTick   = 1,
    maxOutputPerTick   = 50,
    minMaxInput        = 1,
    maxMaxInput        = 3000,
    minMaxOutput       = 10,
    maxMaxOutput       = 500,
    minTickSeconds     = 1,   -- minimum workstation tick interval (seconds)
    maxTickSeconds     = 600, -- 10 minutes per tick
}

Config.restartBlock            = {
    enabled            = true,
    secondsBeforeBlock = 60, -- 1 minute before restart
}

-- ================================================================
-- Farm Boost System
-- ================================================================
Config.farmBoost               = {
    -- Admin command: /farmboost <percent>  (e.g. 10 = +10% items)
    -- Set to 0 to disable. Only admins can use this command.
    command        = "farmboost", -- command name
    defaultPercent = 0,           -- default boost % on resource start (0 = none)

    -- Booster items: items in the player's inventory that grant a temporary
    -- farm boost when used. The item is consumed on use and the boost lasts
    -- for `durationMinutes`. Multiple booster items stack additively.
    boosterItems   = {
        -- { item = "farm_booster_small",  boostPercent = 10, durationMinutes = 15, label = "Small Farm Booster"  },
        { item = "farm_booster_large", boostPercent = 50, durationMinutes = 30, label = "Large Farm Booster" },
    },
}

-- ================================================================
-- Dynamic Pricing (optional and highly experimental!)
-- If enabled, route prices will fluctuate based on supply/demand:
--  - Each sale lowers the price multiplier by `decayPerSale`
--  - The multiplier recovers over time at `recoveryPerTick`
--  - Multiplier is clamped between `minMultiplier` and `maxMultiplier`
Config.dynamicPrices           = {
    enabled           = false, -- set true to enable supply/demand pricing
    checkIntervalMins = 30,    -- how often to recalculate multipliers
    minMultiplier     = 0.5,   -- lowest price multiplier
    maxMultiplier     = 2.0,   -- highest price multiplier
    decayPerSale      = 0.002, -- how much each sale lowers the multiplier
    recoveryPerTick   = 0.01,  -- how much the multiplier recovers per interval
}

-- ================================================================
-- Notification Helper  (works on both server and client)
-- Server:  Config.Notify(src, msg, title, ntype)
-- Client:  Config.Notify(msg, title, ntype)   (no src needed)
-- ================================================================
local isServer                 = IsDuplicityVersion()
Config.Notify                  = function(srcOrMsg, msgOrTitle, titleOrType, ntype)
    if isServer then
        -- Server: (src, msg, title, ntype)
        local src   = srcOrMsg
        local msg   = tostring(msgOrTitle or "")
        local title = tostring(titleOrType or "Drug Routes")
        local t     = ntype or "inform"

        if GetResourceState("ox_lib") == "started" then
            TriggerClientEvent("ox_lib:notify", src, {
                title       = title,
                description = msg,
                type        = t,
                position    = "bottom-right",
            })
        else
            TriggerClientEvent("chat:addMessage", src, {
                args = { ("^3%s^7"):format(title), msg }
            })
        end
    else
        -- Client: (msg, title, ntype)  — no src
        local msg   = tostring(srcOrMsg or "")
        local title = tostring(msgOrTitle or "Drug Routes")
        local t     = titleOrType or "inform"

        if GetResourceState("ox_lib") == "started" then
            exports.ox_lib:notify({
                title       = title,
                description = msg,
                type        = t,
                position    = "bottom-right",
            })
        else
            TriggerEvent("chat:addMessage", {
                args = { ("^3%s^7"):format(title), msg }
            })
        end
    end
end

:movie_camera: Video Preview

https://www.youtube.com/watch?v=1TkSSjR_0v4

:framed_picture: Images of the Product





:shopping_cart: Purchase

https://alva-scripts.com/scripts/7317153 (alva-scripts.com)


:speech_balloon: Support / Updates

Support + lifetime updates are available via my Discord.
(Linked on the store page) (alva-scripts.com)

The first 5 people to create a ticket on my discord will receive this product completly for free!

:computer: Other Products you might enjoy


Code is accessible No (Protected with FiveM Asset Escrow), only Configs are
Subscription-based No
Lines of Code ~5000
Framework ESX / QBCore (auto-detect)
Requirements MySQL (oxmysql)
Optional ox_target, ox_lib
Support Yes

Config Merger
Have you tried Config Merger? Merge your configs easily