RX Scripts Logo
Lumberjack

Configurables

All config & open sourced files included within this script.

Config Files

--[[
BY RX Scripts © rxscripts.xyz
--]]

Config = {}

Config.SaveInterval = 10 -- Minutes between automatic saves (Set to false to disable)
Config.Locale = 'en' -- Language (see locales/ folder)
Config.ImgDirectory = 'ox_inventory/web/images/' -- Inventory images directory

Config.LumberjackLicense = {
    enabled = true, -- Enable lumberjack license system
    buyable = true, -- Allow players to buy the license
    price = 1500, -- License cost
    moneyType = 'bank', -- Payment type: 'bank' or 'cash'
    restricts = {
        chopping = true, -- Require license to chop trees (alerts police if no license)
        shopNPC = true, -- Require license to access shop NPC
        sellNPC = true, -- Require license to access sell NPC
        lumberjackNPC = true, -- Require license to access lumberjack NPC
        vehicleRenting = true, -- Require license to rent vehicles
    },
}

Config.LumberjackNPC = { -- NPC to buy license and view routes/level
    enabled = true, -- Enable lumberjack NPC
    coords = vector3(-566.3479, 5324.9565, 72.5928), -- NPC coordinates
    heading = 343.3690, -- NPC heading
    model = 's_m_y_construct_01', -- NPC model
    blip = {
        enabled = true, -- Show blip on map
        sprite = 77, -- Blip icon
        color = 25, -- Blip color
        label = 'Paul The Lumberjack', -- Blip label
        display = 2, -- Blip display type
        scale = 0.7, -- Blip size
        shortrange = true, -- Only show when close
    },
}

Config.ShopNPC = { -- NPC to buy tools
    enabled = true, -- Enable shop NPC
    route = true, -- Show in lumberjack NPC routes menu
    label = 'Lumberjack Shop', -- Shop name
    moneyType = 'bank', -- Payment type: 'bank' or 'cash'
    model = 's_m_y_dockwork_01', -- NPC model
    coords = vector3(-469.0661, 5357.5054, 79.7761), -- NPC coordinates
    heading = 102.2222, -- NPC heading
    blip = {
        enabled = true,
        sprite = 77,
        color = 25,
        display = 2,
        scale = 0.7,
        shortrange = true,
    },
    categories = {
        ['Axes'] = { -- Category name
            { item = 'stone_axe',    amount = 1, price = 1000,  label = 'Stone Axe',    requiredLevel = 0, mystery = false }, -- mystery = hide until level reached
            { item = 'steel_axe',    amount = 1, price = 3500,  label = 'Steel Axe',    requiredLevel = 2, mystery = false },
            { item = 'titanium_axe', amount = 1, price = 7500, label = 'Titanium Axe', requiredLevel = 4, mystery = false },
            { item = 'diamond_axe',  amount = 1, price = 15000, label = 'Diamond Axe',  requiredLevel = 6, mystery = true },
        },
        ['Chainsaws'] = {
            { item = 'cordless_chainsaw', amount = 1, price = 25000,  label = 'Cordless Chainsaw', requiredLevel = 7, mystery = false },
            { item = 'petrol_chainsaw',   amount = 1, price = 45000, label = 'Petrol Chainsaw',   requiredLevel = 9, mystery = true },
        },
    },
}

Config.SellNPCS = { -- NPCs to sell lumberjack items
    { -- First sell NPC
        enabled = true, -- Enable this NPC
        route = true, -- Show in routes menu
        label = 'Planks Selling', -- NPC label
        moneyType = 'bank', -- Payment type received
        model = 'a_m_m_hillbilly_01', -- NPC model
        coords = vector3(-552.4118, 5348.6489, 73.7431), -- NPC coordinates
        heading = 69.7176, -- NPC heading
        blip = {
            enabled = true,
            sprite = 77,
            color = 25,
            display = 2,
            scale = 0.7,
            shortrange = true,
        },
        categories = { -- Price is per 1 item
            ['Planks'] = { -- Category name
                { item = 'pine_plank',     price = 50,  label = 'Pine Plank',     requiredLevel = 0, mystery = false },
                { item = 'oak_plank',       price = 85,  label = 'Oak Plank',       requiredLevel = 2, mystery = false },
                { item = 'maple_plank',     price = 120,  label = 'Maple Plank',     requiredLevel = 4, mystery = false },
                { item = 'birch_plank',       price = 145,  label = 'Birch Plank',       requiredLevel = 4, mystery = false },
                { item = 'cedar_plank',   price = 180,  label = 'Cedar Plank',   requiredLevel = 6, mystery = false },
                { item = 'mahogany_plank',   price = 240,  label = 'Mahogany Plank',   requiredLevel = 7, mystery = false },
                { item = 'redwood_plank',    price = 310, label = 'Redwood Plank',     requiredLevel = 7, mystery = true },
                { item = 'ancient_oak_plank', price = 420, label = 'Ancient Oak Plank', requiredLevel = 9, mystery = true },
            },
        },
    },
    { -- Second sell NPC
        enabled = true,
        route = true,
        label = 'Logs Selling',
        moneyType = 'bank',
        model = 'a_m_m_hillbilly_01',
        coords = vector3(-519.3457, 5308.3442, 79.2397),
        heading = 158.9465,
        blip = {
            enabled = true,
            sprite = 77,
            color = 25,
            display = 2,
            scale = 0.7,
            shortrange = true,
        },
        categories = {
            ['Logs'] = {
                { item = 'wood_scraps',       price = 5,  label = 'Wood Scraps',       requiredLevel = 0, mystery = false },
                { item = 'pine_log',     price = 8,  label = 'Pine Log',     requiredLevel = 0, mystery = false },
                { item = 'oak_log',       price = 12,  label = 'Oak Log',       requiredLevel = 2, mystery = false },
                { item = 'maple_log',     price = 18,  label = 'Maple Log',     requiredLevel = 4, mystery = false },
                { item = 'birch_log',       price = 22,  label = 'Birch Log',       requiredLevel = 4, mystery = false },
                { item = 'cedar_log',   price = 28,  label = 'Cedar Log',   requiredLevel = 6, mystery = false },
                { item = 'mahogany_log',   price = 38,  label = 'Mahogany Log',   requiredLevel = 7, mystery = false },
                { item = 'redwood_log',    price = 48, label = 'Redwood Log',     requiredLevel = 7, mystery = true },
                { item = 'ancient_oak_log', price = 65, label = 'Ancient Oak Log', requiredLevel = 9, mystery = true },
            },
        },
    }
}

Config.VehicleRentals = {
    ['Log Delivery Rental'] = { -- Rental location name
        model = 'a_m_m_hillbilly_01', -- NPC model
        locations = {
            { -- First rental location
                coords = vector3(-840.8017, 5401.6479, 33.6151), -- NPC coordinates
                heading = 343.1023, -- NPC heading
                spawnCoords = vector4(-842.8693, 5414.3418, 34.4844, 269.1899), -- Vehicle spawn location
                returnCoords = vector3(-808.8207, 5410.8232, 34.0360) -- Vehicle return location
            },
        },
        moneyType = 'bank', -- Payment type
        vehicles = {
            { model = 'forklift', label = 'Forklift', rentInterval = 1, intervalPrice = 25, deposit = 250, requiredLevel = 0, mystery = false }, -- rentInterval in minutes
            { model = 'hauler', trailer = 'trflat', label = 'Hauler', rentInterval = 3, intervalPrice = 75, deposit = 750, requiredLevel = 1, mystery = false },
            { model = 'hauler2', trailer = 'trflat', label = 'Heavy Hauler', rentInterval = 3, intervalPrice = 100, deposit = 1000, requiredLevel = 3, mystery = false },
            { model = 'phantom', trailer = 'trflat', label = 'Phantom', rentInterval = 4, intervalPrice = 125, deposit = 1500, requiredLevel = 5, mystery = false },
            { model = 'phantom2', trailer = 'trflat', label = 'Phantom Pro', rentInterval = 4, intervalPrice = 150, deposit = 2000, requiredLevel = 7, mystery = true },
            { model = 'phantom3', trailer = 'trflat', label = 'Phantom Elite', rentInterval = 5, intervalPrice = 175, deposit = 2500, requiredLevel = 8, mystery = true },
            { model = 'phantom4', trailer = 'trflat', label = 'Phantom Ultimate', rentInterval = 5, intervalPrice = 200, deposit = 3000, requiredLevel = 10, mystery = true },
        },
        blip = {
            enabled = true,
            sprite = 477,
            color = 25,
            display = 2,
            scale = 0.7,
            shortrange = true,
        },
    },
}

-- Resource names (only change if you renamed the resources)
Resources = {
    FM = { name = 'fmLib', export = 'new' },
    OXTarget = { name = 'ox_target', export = 'all' },
    QBTarget = { name = 'qb-target', export = 'all' },
}
IgnoreScriptFoundLogs = false -- Show script loaded logs
ShowDebugPrints = true -- Show debug prints in console

Opensource Files

All script-related open source code is contained within these files. Third-party components, including frameworks, inventory systems, and other external code, are separately maintained & open sourced in our fmLib repository.
--[[
BY RX Scripts © rxscripts.xyz
--]]

Config.DiscordWebhook = ''

local function getPoliceSources()
    local players = FM.utils.getPlayers()
    local policeSources = {}

    for src, p in pairs(players) do
        if p.getJob().name == 'police' then
            policeSources[#policeSources+1] = src
        end
    end

    return policeSources
end

function NotifyPolice(coords, msg)
    local police = getPoliceSources()

    for _, src in pairs(police) do
        TriggerClientEvent('lumberjack:notifyPolice', src, coords, msg)
    end
end

function HasLumberjackLicense(src)
    local p = FM.player.get(src)
    if not p then return false end

    local identifier = p.getIdentifier()
    if not Lumberjacks[identifier] then return false end

    return Lumberjacks[identifier].license
end

--[[
    esx_licenses INTEGRATION FOR CHECKING LUMBERJACK LICENSE
    UNCOMMENT FUNCTION BELOW
    RENAME 'lumberjack_license_name_here' TO YOUR LUMBERJACK LICENSE NAME
    REMOVE/COMMENT THE FUNCTION ABOVE: function HasLumberjackLicense(src) ...... end
]]
-- function HasLumberjackLicense(src)
--     local hasLicense = promise.new()

--     TriggerEvent('esx_license:checkLicense', src, 'lumberjack_license_name_here', function(bool)
--         hasLicense:resolve(bool)
--     end)

--     return Citizen.Await(hasLicense)
-- end

FM.callback.register('lumberjack:getItemsAmounts', function(src)
    local p = FM.player.get(src)
    if not p then return end

    local items = p.getItems()
    local amounts = {}

    for _, item in pairs(items) do
        if amounts[item.name] then
            amounts[item.name] = amounts[item.name] + item.amount
        else
            amounts[item.name] = item.amount
        end
    end

    return amounts
end)

---@param src number Player server id
---@param xp number Amount of XP to add
---@return boolean success
function AddLumberjackXP(src, xp)
    local lumberjack = GetOrCreateLumberjack(src)
    if not lumberjack then return false end

    lumberjack:addXP(xp)
    return true
end

---@param src number Player server id
---@return number|false level
function GetLumberjackLevel(src)
    local p = FM.player.get(src)
    if not p then return false end

    local lumberjack = Lumberjacks[p.getIdentifier()]
    if not lumberjack then return false end

    return lumberjack.level
end

---@param src number Player server id
---@return number|false xp
function GetLumberjackXP(src)
    local p = FM.player.get(src)
    if not p then return false end

    local lumberjack = Lumberjacks[p.getIdentifier()]
    if not lumberjack then return false end

    return lumberjack.xp
end

--[[
    EVENTS
    You can listen to these events in other scripts to integrate with the lumberjack system
]]

---@param playerId number The server ID of the player
RegisterNetEvent('lumberjack:onLicenseBought', function(playerId)
    -- This event will be called whenever a player bought a lumberjack license
end)

---@param playerId number The server ID of the player
---@param itemData {item: string, label: string, amount: number, price: number, requiredLevel: number, mystery: boolean} The item data from config
---@param amount number The amount of items bought
---@param price number The price per item
RegisterNetEvent('lumberjack:onItemBought', function(playerId, itemData, amount, price)
    -- This event will be called whenever a player buys an item from the lumberjack shop
end)

---@param playerId number The server ID of the player
---@param itemData {item: string, label: string, price: number, requiredLevel: number, mystery: boolean} The item data from config
---@param amount number The amount of items sold
---@param totalPrice number The total price received (price * amount)
RegisterNetEvent('lumberjack:onItemSold', function(playerId, itemData, amount, totalPrice)
    -- This event will be called whenever a player sells an item at the lumberjack shop
end)

---@param playerId number The server ID of the player
---@param missionKey string The mission key/identifier
---@param rewards {xp: number, money: number, moneyType: string, items: {item: string, amount: number}[]} The rewards given
RegisterNetEvent('lumberjack:onMissionClaimed', function(playerId, missionKey, rewards)
    -- This event will be called whenever a player claims mission rewards
end)

---@param playerId number The server ID of the player
---@param rentalName string The name of the vehicle rental location
---@param vehicleData {model: string, label: string, rentInterval: number, intervalPrice: number, deposit: number, requiredLevel: number, mystery: boolean} The vehicle data from config
RegisterNetEvent('lumberjack:onVehicleRented', function(playerId, rentalName, vehicleData)
    -- This event will be called whenever a player rents a vehicle
end)

---@param playerId number The server ID of the player
---@param rentalName string The name of the vehicle rental location
---@param vehicleData {model: string, label: string, rentInterval: number, intervalPrice: number, deposit: number, requiredLevel: number, mystery: boolean} The vehicle data from config
RegisterNetEvent('lumberjack:onVehicleReturned', function(playerId, rentalName, vehicleData)
    -- This event will be called whenever a player returns a rented vehicle
end)

---@param playerId number The server ID of the player
---@param treeName string The name of the tree chopped
---@param lumberjack {id: number, identifier: string, license: boolean, level: number, xp: number, name: string, missions: table, chopped: table<string, number>} The lumberjack object
RegisterNetEvent('lumberjack:onTreeChopped', function(playerId, treeName, lumberjack)
    -- This event will be called whenever a player chopped a tree
end)

---@param playerId number The server ID of the player
---@param logName string The name/type of the log cut
---@param lumberjack {id: number, identifier: string, license: boolean, level: number, xp: number, name: string, missions: table, chopped: table<string, number>, logs_cut: table<string, number>} The lumberjack object
RegisterNetEvent('lumberjack:onLogCut', function(playerId, logName, lumberjack)
    -- This event will be called whenever a player cut a log
end)

---@param playerId number The server ID of the player
---@param logItem string The item name of the log sawn (e.g., 'pine_log')
---@param amount number The amount of logs sawn
---@param lumberjack {id: number, identifier: string, license: boolean, level: number, xp: number, name: string, missions: table, chopped: table<string, number>, logs_cut: table<string, number>, logs_sawn: table<string, number>} The lumberjack object
RegisterNetEvent('lumberjack:onLogSawn', function(playerId, logItem, amount, lumberjack)
    -- This event will be called whenever a player saws logs at a sawmill
end)

---@param playerId number The server ID of the player
---@param xpGained number The amount of XP gained
---@param newXP number The new total XP
---@param lumberjack {id: number, identifier: string, license: boolean, level: number, xp: number, name: string, missions: table, chopped: table<string, number>, logs_cut: table<string, number>, logs_sawn: table<string, number>} The lumberjack object
RegisterNetEvent('lumberjack:onXpGained', function(playerId, xpGained, newXP, lumberjack)
    -- This event will be called whenever a player gains XP
end)

---@param playerId number The server ID of the player
---@param newLevel number The new level
---@param lumberjack {id: number, identifier: string, license: boolean, level: number, xp: number, name: string, missions: table, chopped: table<string, number>} The lumberjack object
RegisterNetEvent('lumberjack:onLevelUp', function(playerId, newLevel, lumberjack)
    -- This event will be called whenever a player levels up
end)

---@param playerId number The server ID of the player
---@param locationLabel string The name of the delivery location
---@param logsSold table<string, number> Table of tree types and counts sold
---@param totalPayment number Total money received from the delivery
---@param totalLogs number Total number of logs delivered
---@param lumberjack {id: number, identifier: string, license: boolean, level: number, xp: number, name: string, missions: table, chopped: table<string, number>, logs_cut: table<string, number>, logs_sawn: table<string, number>, deliveries: table<string, number>} The lumberjack object
RegisterNetEvent('lumberjack:onDeliveryCompleted', function(playerId, locationLabel, logsSold, totalPayment, totalLogs, lumberjack)
    -- This event will be called whenever a player completes a log delivery
end)