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
--[[
BY RX Scripts © rxscripts.xyz
--]]
Config.Trees = {
['Pine Tree'] = { -- Tree name (must be unique)
models = { -- Tree prop models that will be registered for this tree type
'prop_tree_pine_01',
},
spawnChance = 50, -- Spawn chance (higher = more common, 0-100)
chopDuration = 5, -- Base seconds to chop (modified by tool multipliers)
chopHits = { min = 1, max = 1 }, -- Number of hits required to fell the tree
logsAmount = 2, -- Number of logs spawned when tree falls
logCutHits = { min = 2, max = 4 }, -- Hits required to cut each log
lootLoop = 2, -- Number of times loot table is rolled per hit
fellLoot = { -- Loot received when tree is felled (wood scraps)
{ item = 'wood_scraps', min = 2, max = 4, chance = 80 },
{ item = 'sawdust', min = 1, max = 2, chance = 20 },
},
cutLoot = { -- Loot received when cutting logs
{ item = 'pine_log', min = 1, max = 2, chance = 90 },
{ item = 'wood_scraps', min = 1, max = 1, chance = 10 },
},
xp = {
chopGain = 5, -- XP gained for felling tree
cutGain = 3, -- XP gained for cutting each log
},
tools = { -- Tools that can chop this tree type
'Petrol Chainsaw',
'Cordless Chainsaw',
'Diamond Axe',
'Titanium Axe',
'Steel Axe',
'Stone Axe',
},
},
['Oak Tree'] = {
models = {
'prop_tree_oak_01',
},
spawnChance = 45,
chopDuration = 7,
chopHits = { min = 1, max = 1 },
logsAmount = 2,
logCutHits = { min = 3, max = 5 },
lootLoop = 2,
fellLoot = {
{ item = 'wood_scraps', min = 2, max = 4, chance = 75 },
},
cutLoot = {
{ item = 'oak_log', min = 1, max = 2, chance = 85 },
{ item = 'wood_scraps', min = 1, max = 1, chance = 15 },
},
xp = {
chopGain = 7,
cutGain = 4,
},
tools = {
'Petrol Chainsaw',
'Cordless Chainsaw',
'Diamond Axe',
'Titanium Axe',
'Steel Axe',
},
},
['Maple Tree'] = {
models = {
'prop_tree_maple_02',
},
spawnChance = 40,
chopDuration = 10,
chopHits = { min = 3, max = 6 },
logsAmount = 3,
logCutHits = { min = 3, max = 5 },
lootLoop = 2,
fellLoot = {
{ item = 'wood_scraps', min = 1, max = 3, chance = 30 },
},
cutLoot = {
{ item = 'maple_log', min = 1, max = 2, chance = 85 },
{ item = 'wood_scraps', min = 1, max = 1, chance = 15 },
},
xp = {
chopGain = 10,
cutGain = 5,
},
tools = {
'Petrol Chainsaw',
'Cordless Chainsaw',
'Diamond Axe',
'Titanium Axe',
},
},
['Birch Tree'] = {
models = {
'prop_tree_birch_01',
},
spawnChance = 35,
chopDuration = 12,
chopHits = { min = 3, max = 5 },
logsAmount = 1,
logCutHits = { min = 2, max = 4 },
lootLoop = 2,
fellLoot = {
{ item = 'wood_scraps', min = 2, max = 3, chance = 75 },
},
cutLoot = {
{ item = 'birch_log', min = 1, max = 2, chance = 85 },
{ item = 'wood_scraps', min = 1, max = 1, chance = 15 },
},
xp = {
chopGain = 12,
cutGain = 6,
},
tools = {
'Petrol Chainsaw',
'Cordless Chainsaw',
'Diamond Axe',
'Titanium Axe',
},
},
['Cedar Tree'] = {
models = {
'prop_w_r_cedar_01',
'prop_tree_cedar_02',
'prop_tree_cedar_03',
'prop_tree_cedar_04',
'prop_tree_cedar_s_06',
'prop_tree_cedar_s_02',
'prop_tree_cedar_s_01',
'prop_tree_cedar_s_04',
'prop_tree_cedar_s_05',
'prop_w_r_cedar_dead',
'test_tree_cedar_trunk_001',
},
spawnChance = 30,
chopDuration = 15,
chopHits = { min = 4, max = 6 },
logsAmount = 2,
logCutHits = { min = 3, max = 5 },
lootLoop = 2,
fellLoot = {
{ item = 'wood_scraps', min = 3, max = 5, chance = 70 },
},
cutLoot = {
{ item = 'cedar_log', min = 1, max = 3, chance = 85 },
{ item = 'wood_scraps', min = 1, max = 1, chance = 15 },
},
xp = {
chopGain = 15,
cutGain = 8,
},
tools = {
'Petrol Chainsaw',
'Cordless Chainsaw',
'Diamond Axe',
},
},
['Mahogany Tree'] = {
models = {
'prop_tree_jacada_01',
},
spawnChance = 25,
chopDuration = 18,
chopHits = { min = 4, max = 7 },
logsAmount = 2,
logCutHits = { min = 3, max = 6 },
lootLoop = 2,
fellLoot = {
{ item = 'wood_scraps', min = 3, max = 5, chance = 65 },
},
cutLoot = {
{ item = 'mahogany_log', min = 2, max = 3, chance = 90 },
{ item = 'wood_scraps', min = 1, max = 1, chance = 10 },
},
xp = {
chopGain = 18,
cutGain = 10,
},
tools = {
'Petrol Chainsaw',
'Cordless Chainsaw',
},
},
['Redwood Tree'] = {
models = {
'prop_tree_jacada_02',
},
spawnChance = 20,
chopDuration = 20,
chopHits = { min = 5, max = 8 },
logsAmount = 3,
logCutHits = { min = 4, max = 7 },
lootLoop = 2,
fellLoot = {
{ item = 'wood_scraps', min = 4, max = 6, chance = 60 },
},
cutLoot = {
{ item = 'redwood_log', min = 2, max = 3, chance = 90 },
{ item = 'wood_scraps', min = 1, max = 2, chance = 10 },
},
xp = {
chopGain = 20,
cutGain = 12,
},
tools = {
'Petrol Chainsaw',
'Cordless Chainsaw',
},
},
['Ancient Oak'] = {
models = {
'prop_tree_oak_01',
},
spawnChance = 15,
chopDuration = 22,
chopHits = { min = 5, max = 9 },
logsAmount = 4,
logCutHits = { min = 4, max = 8 },
lootLoop = 2,
fellLoot = {
{ item = 'wood_scraps', min = 5, max = 7, chance = 55 },
},
cutLoot = {
{ item = 'ancient_oak_log', min = 2, max = 4, chance = 95 },
{ item = 'wood_scraps', min = 1, max = 2, chance = 5 },
},
xp = {
chopGain = 22,
cutGain = 15,
},
tools = {
'Petrol Chainsaw',
},
},
}
--[[
BY RX Scripts © rxscripts.xyz
--]]
Config.Tools = {
['Stone Axe'] = { -- Tool name (must be unique)
item = 'stone_axe', -- Item name in inventory
requiredLevel = 0, -- Minimum lumberjack level required to use this tool
multipliers = {
lootAmount = 1, -- Multiplier for loot amount (1.0 = normal, 2.0 = double)
chopDuration = 1.0, -- Multiplier for chop duration (1.0 = base time from trees.lua)
xpGain = 1.0, -- Multiplier for XP gained (1.0 = normal, 2.0 = double)
},
durability = 100, -- Number of uses before tool breaks
anim = { dict = 'melee@large_wpn@streamed_core', anim = 'ground_attack_on_spot' }, -- Animation played while chopping
prop = { bone = 57005, model = 'stone_axe', position = vec3(0.09, -0.65, -0.22), rotation = vec3(252.0, 180.0, 0.0) }, -- Tool prop attachment
type = 'axe', -- Tool type: 'axe' or 'chainsaw'
},
['Steel Axe'] = {
item = 'steel_axe',
requiredLevel = 2,
multipliers = {
lootAmount = 1.3,
chopDuration = 1.3,
xpGain = 1.3,
},
durability = 150,
anim = { dict = 'melee@large_wpn@streamed_core', anim = 'ground_attack_on_spot' },
prop = { bone = 57005, model = 'steel_axe', position = vec3(0.19, -0.65, -0.22), rotation = vec3(252.0, 180.0, 0.0) },
type = 'axe',
},
['Titanium Axe'] = {
item = 'titanium_axe',
requiredLevel = 4,
multipliers = {
lootAmount = 1.6,
chopDuration = 1.6,
xpGain = 1.6,
},
durability = 200,
anim = { dict = 'melee@large_wpn@streamed_core', anim = 'ground_attack_on_spot' },
prop = { bone = 57005, model = 'titanium_axe', position = vec3(0.09, -0.65, -0.22), rotation = vec3(252.0, 180.0, 0.0) },
type = 'axe',
},
['Diamond Axe'] = {
item = 'diamond_axe',
requiredLevel = 6,
multipliers = {
lootAmount = 2.0,
chopDuration = 2.0,
xpGain = 2.0,
},
durability = 250,
anim = { dict = 'melee@large_wpn@streamed_core', anim = 'ground_attack_on_spot' },
prop = { bone = 57005, model = 'diamond_axe', position = vec3(0.09, -0.65, -0.22), rotation = vec3(252.0, 180.0, 0.0) },
type = 'axe',
},
['Cordless Chainsaw'] = {
item = 'cordless_chainsaw',
requiredLevel = 7,
multipliers = {
lootAmount = 2.5,
chopDuration = 2.5,
xpGain = 2.5,
},
durability = 400,
anim = { dict = 'anim@heists@fleeca_bank@drilling', anim = 'drill_straight_fail' },
prop = { bone = 28422, model = 'cordless_chainsaw', position = vec3(0.0, -0.2, -0.6), rotation = vec3(0.0, 0.0, 90.0) },
type = 'chainsaw',
fuel = {
required = true, -- Does this tool require fuel?
item = 'chainsaw_battery', -- Fuel item name
maxCapacity = 100, -- Maximum fuel capacity (100 chops per full battery)
consumptionRate = 1, -- Fuel consumed per chop
refuelAmount = 100, -- Fuel added when refueling with one item
},
},
['Petrol Chainsaw'] = {
item = 'petrol_chainsaw',
requiredLevel = 9,
multipliers = {
lootAmount = 3.0,
chopDuration = 3.0,
xpGain = 3.0,
},
durability = 500,
anim = { dict = 'anim@heists@fleeca_bank@drilling', anim = 'drill_straight_fail' },
prop = { bone = 28422, model = 'petrol_chainsaw', position = vec3(0.0, -0.2, -0.6), rotation = vec3(0.0, 0.0, 90.0) },
type = 'chainsaw',
fuel = {
required = true,
item = 'fuel_can',
maxCapacity = 200,
consumptionRate = 1,
refuelAmount = 50,
},
},
}
--[[
BY RX Scripts © rxscripts.xyz
--]]
Config.Levels = { -- Levels must be incremental by 1, starting from 1
-- level 0 is the default starter level everyone has
[1] = 100, -- 100 xp needed to reach level 1
[2] = 250,
[3] = 500,
[4] = 750,
[5] = 1000,
[6] = 1500,
[7] = 2000,
[8] = 2750,
[9] = 3500,
[10] = 5000,
}
--[[
BY RX Scripts © rxscripts.xyz
--]]
Config.MaxMissions = 10 -- Max amount of missions that can be active at the same time (make sure it's 1 less than the amount of missions in the table below so it can rotate)
Config.Missions = {
-- Chop Missions
["Chop 50x Pine Trees"] = {
endTime = 12, -- Time in hours to complete the mission (after this a random other mission will start)
type = 'chopped', -- 'chopped'
amount = 50, -- Amount of trees required
tree = 'Pine Tree', -- Tree to chop
rewards = {
xp = 50, -- Set to 0 to disable
money = 1000, -- Set to 0 to disable
moneyType = 'bank',
items = {}, -- Empty table to disable
}
},
["Chop 40x Oak Trees"] = {
endTime = 10,
type = 'chopped',
amount = 40,
tree = 'Oak Tree',
rewards = {
xp = 70,
money = 1200,
moneyType = 'cash',
items = {},
}
},
["Chop 35x Maple Trees"] = {
endTime = 14,
type = 'chopped',
amount = 35,
tree = 'Maple Tree',
rewards = {
xp = 100,
money = 1500,
moneyType = 'bank',
items = {
-- { item = 'maple_syrup', amount = 5 }
}, -- Example reward item
}
},
["Chop 30x Birch Trees"] = {
endTime = 8,
type = 'chopped',
amount = 30,
tree = 'Birch Tree',
rewards = {
xp = 120,
money = 2000,
moneyType = 'bank',
items = {},
}
},
["Chop 20x Cedar Trees"] = {
endTime = 12,
type = 'chopped',
amount = 20,
tree = 'Cedar Tree',
rewards = {
xp = 150,
money = 3000,
moneyType = 'bank',
items = {
-- { item = 'cedar_oil', amount = 3 }
},
}
},
["Chop 15x Mahogany Trees"] = {
endTime = 16,
type = 'chopped',
amount = 15,
tree = 'Mahogany Tree',
rewards = {
xp = 200,
money = 5000,
moneyType = 'cash',
items = {
-- { item = 'mahogany_plank', amount = 2 }
},
}
},
["Chop 10x Redwood Trees"] = {
endTime = 18,
type = 'chopped',
amount = 10,
tree = 'Redwood Tree',
rewards = {
xp = 250,
money = 7500,
moneyType = 'bank',
items = {},
}
},
["Chop 8x Ancient Oaks"] = {
endTime = 20,
type = 'chopped',
amount = 8,
tree = 'Ancient Oak',
rewards = {
xp = 300,
money = 10000,
moneyType = 'bank',
items = {
-- { item = 'ancient_plank', amount = 1 }
},
}
},
["Chop 5x Ironwood Trees"] = {
endTime = 24,
type = 'chopped',
amount = 5,
tree = 'Ironwood Tree',
rewards = {
xp = 500,
money = 15000,
moneyType = 'bank',
items = {
-- { item = 'ironwood_plank', amount = 1 }
},
}
},
-- Log Cutting Missions
["Cut 100x Pine Logs"] = {
endTime = 10,
type = 'logs_cut',
amount = 100,
log = 'Pine Tree',
rewards = {
xp = 80,
money = 1500,
moneyType = 'bank',
items = {},
}
},
["Cut 80x Oak Logs"] = {
endTime = 12,
type = 'logs_cut',
amount = 80,
log = 'Oak Tree',
rewards = {
xp = 100,
money = 2000,
moneyType = 'cash',
items = {},
}
},
["Cut 60x Maple Logs"] = {
endTime = 14,
type = 'logs_cut',
amount = 60,
log = 'Maple Tree',
rewards = {
xp = 150,
money = 2500,
moneyType = 'bank',
items = {},
}
},
["Cut 40x Birch Logs"] = {
endTime = 10,
type = 'logs_cut',
amount = 40,
log = 'Birch Tree',
rewards = {
xp = 180,
money = 3000,
moneyType = 'bank',
items = {},
}
},
["Cut 30x Cedar Logs"] = {
endTime = 16,
type = 'logs_cut',
amount = 30,
log = 'Cedar Tree',
rewards = {
xp = 220,
money = 4000,
moneyType = 'cash',
items = {},
}
},
["Cut 25x Mahogany Logs"] = {
endTime = 18,
type = 'logs_cut',
amount = 25,
log = 'Mahogany Tree',
rewards = {
xp = 280,
money = 6000,
moneyType = 'bank',
items = {},
}
},
-- Sawmill Missions
["Saw 200x Pine Logs"] = {
endTime = 14,
type = 'logs_sawn',
amount = 200,
log = 'pine_log',
rewards = {
xp = 120,
money = 2500,
moneyType = 'bank',
items = {},
}
},
["Saw 150x Oak Logs"] = {
endTime = 16,
type = 'logs_sawn',
amount = 150,
log = 'oak_log',
rewards = {
xp = 160,
money = 3500,
moneyType = 'cash',
items = {},
}
},
["Saw 120x Maple Logs"] = {
endTime = 18,
type = 'logs_sawn',
amount = 120,
log = 'maple_log',
rewards = {
xp = 200,
money = 4000,
moneyType = 'bank',
items = {},
}
},
["Saw 80x Birch Logs"] = {
endTime = 16,
type = 'logs_sawn',
amount = 80,
log = 'birch_log',
rewards = {
xp = 250,
money = 5000,
moneyType = 'bank',
items = {},
}
},
["Saw 60x Cedar Logs"] = {
endTime = 20,
type = 'logs_sawn',
amount = 60,
log = 'cedar_log',
rewards = {
xp = 320,
money = 7000,
moneyType = 'cash',
items = {},
}
},
["Saw 40x Mahogany Logs"] = {
endTime = 24,
type = 'logs_sawn',
amount = 40,
log = 'mahogany_log',
rewards = {
xp = 400,
money = 10000,
moneyType = 'bank',
items = {},
}
},
-- Delivery Missions
["Deliver 50x Pine Logs"] = {
endTime = 24,
type = 'deliveries',
amount = 50,
tree = 'Pine Tree',
rewards = {
xp = 100,
money = 1500,
moneyType = 'bank',
items = {},
}
},
["Deliver 40x Oak Logs"] = {
endTime = 24,
type = 'deliveries',
amount = 40,
tree = 'Oak Tree',
rewards = {
xp = 150,
money = 2000,
moneyType = 'bank',
items = {},
}
},
["Deliver 35x Maple Logs"] = {
endTime = 24,
type = 'deliveries',
amount = 35,
tree = 'Maple Tree',
rewards = {
xp = 200,
money = 2500,
moneyType = 'bank',
items = {},
}
},
["Deliver 30x Birch Logs"] = {
endTime = 24,
type = 'deliveries',
amount = 30,
tree = 'Birch Tree',
rewards = {
xp = 250,
money = 3000,
moneyType = 'bank',
items = {},
}
},
["Deliver 25x Cedar Logs"] = {
endTime = 24,
type = 'deliveries',
amount = 25,
tree = 'Cedar Tree',
rewards = {
xp = 300,
money = 4000,
moneyType = 'bank',
items = {},
}
},
["Deliver 20x Mahogany Logs"] = {
endTime = 24,
type = 'deliveries',
amount = 20,
tree = 'Mahogany Tree',
rewards = {
xp = 400,
money = 5000,
moneyType = 'bank',
items = {},
}
},
}
--[[
BY RX Scripts © rxscripts.xyz
--]]
Config.LumberjackZones = {
['Cedar Forest'] = {
coords = vector3(-572.7, 5252.8, 70.5), -- Chiliad State Wilderness
distCheck = 250.0, -- From this distance, the trees will spawn
route = {
enabled = true,
coords = { x = -572.7, y = 5252.8 },
},
blip = {
enabled = true,
sprite = 361, -- Tree sprite
color = 2, -- Green
display = 2,
scale = 0.7,
shortrange = true,
},
radiusBlip = {
enabled = true,
radius = 250.0,
color = 2,
alpha = 80,
shortrange = true,
},
trees = {
types = { 'Cedar Tree', 'Pine Tree' },
--[[
If useNativeTreeModels is true, all trees, including default trees spawned by the server, in this zone are choppable.
Ofcourse, only if they match the models defined in 'types' above.
If false, only the trees spawned by our script, on the locations below will be choppable.
--]]
useNativeTreeModels = true,
respawnTime = 180, -- 3 minutes
locations = {
vector4(-627.6590, 5241.6289, 73.9307, 314.3531),
}
},
},
['Oak Grove'] = {
coords = vector3(-1535.4, 4703.2, 40.0), -- Paleto Forest
distCheck = 200.0,
route = {
enabled = true,
coords = { x = -1535.4, y = 4703.2 },
},
blip = {
enabled = true,
sprite = 361,
color = 25, -- Brown
display = 2,
scale = 0.7,
shortrange = true,
},
radiusBlip = {
enabled = true,
radius = 200.0,
color = 25,
alpha = 80,
shortrange = true,
},
trees = {
types = { 'Oak Tree', 'Maple Tree', 'Birch Tree' },
--[[
If useNativeTreeModels is true, all trees, including default trees spawned by the server, in this zone are choppable.
Ofcourse, only if they match the models defined in 'types' above.
If false, only the trees spawned by our script, on the locations below will be choppable.
--]]
useNativeTreeModels = true,
respawnTime = 180,
locations = {
vector4(-1550.3, 4720.5, 40.0, 0.0),
vector4(-1520.7, 4690.8, 40.0, 0.0),
vector4(-1545.6, 4685.2, 40.0, 0.0),
vector4(-1515.4, 4715.9, 40.0, 0.0),
vector4(-1530.1, 4735.3, 40.0, 0.0),
vector4(-1565.8, 4705.6, 40.0, 0.0),
vector4(-1505.2, 4680.4, 40.0, 0.0),
vector4(-1555.7, 4695.1, 40.0, 0.0),
vector4(-1525.9, 4725.7, 40.0, 0.0),
vector4(-1540.4, 4710.3, 40.0, 0.0),
}
},
},
['Redwood Forest'] = {
coords = vector3(-1133.9, 4631.7, 145.8), -- Raton Canyon
distCheck = 200.0,
route = {
enabled = true,
coords = { x = -1133.9, y = 4631.7 },
},
blip = {
enabled = true,
sprite = 361,
color = 1, -- Red
display = 2,
scale = 0.7,
shortrange = true,
},
radiusBlip = {
enabled = true,
radius = 200.0,
color = 1,
alpha = 80,
shortrange = true,
},
trees = {
types = { 'Redwood Tree', 'Mahogany Tree', 'Ancient Oak' },
--[[
If useNativeTreeModels is true, all trees, including default trees spawned by the server, in this zone are choppable.
Ofcourse, only if they match the models defined in 'types' above.
If false, only the trees spawned by our script, on the locations below will be choppable.
--]]
useNativeTreeModels = true,
respawnTime = 240, -- 4 minutes for rarer trees
locations = {
vector4(-1150.5, 4650.2, 145.8, 0.0),
vector4(-1120.3, 4620.7, 145.8, 0.0),
vector4(-1145.6, 4615.4, 145.8, 0.0),
vector4(-1115.9, 4645.1, 145.8, 0.0),
vector4(-1130.2, 4665.3, 145.8, 0.0),
vector4(-1165.7, 4635.6, 145.8, 0.0),
vector4(-1105.4, 4610.8, 145.8, 0.0),
vector4(-1155.1, 4625.9, 145.8, 0.0),
vector4(-1125.8, 4655.7, 145.8, 0.0),
vector4(-1140.6, 4640.4, 145.8, 0.0),
}
},
},
}
--[[
BY RX Scripts © rxscripts.xyz
--]]
Config.Sawmills = {
['Sawhorse'] = { -- Sawmill name (must be unique)
prop = 'prop_tool_sawhorse', -- Sawmill prop model
log = { -- Log prop configuration
prop = 'prop_log_01', -- Log prop model
offset = vector3(0.0, 0.0, 0.9), -- Offset from sawmill coords
rotation = vector3(0.0, 0.0, 90.0), -- Rotation (pitch, roll, yaw relative to sawmill heading)
scale = 0.5, -- Scale of the log (1.0 = normal, 0.5 = half size, 2.0 = double size)
},
requiredLevel = 0, -- Minimum lumberjack level required to use this sawmill
requiredItem = { -- Required tool to use this sawmill (optional)
item = 'consaw', -- Item name
durability = 100, -- Uses before tool breaks (tracked in sawUsage metadata)
},
anim = { -- Animation played during sawing
dict = 'weapons@heavy@minigun',
anim = 'idle_2_aim',
},
heldProp = { -- Prop held in hand during sawing (optional)
bone = 57005, -- Right hand bone
model = 'prop_tool_consaw', -- Prop model
position = vec3(0.13, 0.0, -0.01), -- Position offset from bone
rotation = vec3(0.0, 0.0, 90.0), -- Rotation offset
},
conversions = { -- Conversion recipes
{ input = { item = 'pine_log', amount = 6 }, output = { item = 'pine_plank', amount = 2 }, duration = 12 },
{ input = { item = 'oak_log', amount = 6 }, output = { item = 'oak_plank', amount = 2 }, duration = 13 },
},
locations = { -- Sawmill locations (vector4: x, y, z, heading)
vector4(-604.3439, 5293.8745, 70.3407, 275.5006),
},
},
['Cross Saw'] = {
prop = 'prop_crosssaw_01',
log = {
prop = 'prop_log_01',
offset = vector3(0.0, 0.0, 0.8),
rotation = vector3(0.0, 0.0, 90.0),
scale = 0.5,
},
requiredLevel = 4,
anim = {
dict = 'anim@amb@clubhouse@tutorial@bkr_tut_ig3@',
anim = 'machinic_loop_mechandplayer',
},
conversions = {
{ input = { item = 'pine_log', amount = 5 }, output = { item = 'pine_plank', amount = 2 }, duration = 10 },
{ input = { item = 'oak_log', amount = 5 }, output = { item = 'oak_plank', amount = 2 }, duration = 11 },
{ input = { item = 'maple_log', amount = 5 }, output = { item = 'maple_plank', amount = 2 }, duration = 10 },
{ input = { item = 'birch_log', amount = 5 }, output = { item = 'birch_plank', amount = 2 }, duration = 9 },
},
locations = {
vector4(-605.4741, 5301.4966, 70.2787, 90.8753),
},
},
['Band Saw'] = {
prop = 'prop_bandsaw_01',
log = {
prop = 'prop_log_01',
offset = vector3(0.0, -0.35, 0.9),
rotation = vector3(0.0, 0.0, 90.0),
scale = 0.6,
},
requiredLevel = 6,
anim = {
dict = 'anim@amb@clubhouse@tutorial@bkr_tut_ig3@',
anim = 'machinic_loop_mechandplayer',
},
conversions = {
{ input = { item = 'pine_log', amount = 4 }, output = { item = 'pine_plank', amount = 2 }, duration = 8 },
{ input = { item = 'oak_log', amount = 4 }, output = { item = 'oak_plank', amount = 2 }, duration = 9 },
{ input = { item = 'maple_log', amount = 4 }, output = { item = 'maple_plank', amount = 2 }, duration = 8 },
{ input = { item = 'birch_log', amount = 4 }, output = { item = 'birch_plank', amount = 2 }, duration = 7 },
{ input = { item = 'cedar_log', amount = 4 }, output = { item = 'cedar_plank', amount = 2 }, duration = 9 },
},
locations = {
vector4(-605.6862, 5309.1479, 70.4224, 75.8893),
},
},
['Table Saw'] = {
prop = 'prop_tablesaw_01',
log = {
prop = 'prop_log_01',
offset = vector3(-0.9, 0.0, 0.9),
rotation = vector3(0.0, 0.0, 90.0),
scale = 0.8,
},
requiredLevel = 9,
anim = {
dict = 'anim@amb@clubhouse@tutorial@bkr_tut_ig3@',
anim = 'machinic_loop_mechandplayer',
},
conversions = {
{ input = { item = 'pine_log', amount = 3 }, output = { item = 'pine_plank', amount = 2 }, duration = 6 },
{ input = { item = 'oak_log', amount = 3 }, output = { item = 'oak_plank', amount = 2 }, duration = 7 },
{ input = { item = 'maple_log', amount = 3 }, output = { item = 'maple_plank', amount = 2 }, duration = 6 },
{ input = { item = 'birch_log', amount = 3 }, output = { item = 'birch_plank', amount = 2 }, duration = 5 },
{ input = { item = 'cedar_log', amount = 3 }, output = { item = 'cedar_plank', amount = 2 }, duration = 7 },
{ input = { item = 'mahogany_log', amount = 3 }, output = { item = 'mahogany_plank', amount = 2 }, duration = 8 },
{ input = { item = 'redwood_log', amount = 3 }, output = { item = 'redwood_plank', amount = 2 }, duration = 9 },
{ input = { item = 'ancient_oak_log', amount = 3 }, output = { item = 'ancient_oak_plank', amount = 2 }, duration = 10 },
},
locations = {
vector4(-604.7268, 5317.8208, 70.4457, 83.2028),
},
},
}
--[[
BY RX Scripts © rxscripts.xyz
--]]
Config.Forklift = {
model = 'forklift', -- Forklift vehicle model
pickupDistance = 2.0, -- Distance from forks to log to pickup
dropDistance = 5.0, -- Distance from forks to trailer to drop log
attachmentBone = 'forks', -- Bone name on forklift to attach logs
attachmentOffset = vector3(0.0, 1.0, -0.2), -- Offset from bone
attachmentRotation = vector3(0.0, 0.0, 90.0), -- Rotation when attached
}
Config.DeliveryTrucks = {
['hauler'] = { -- Truck name (must match vehicle model)
trailer = 'trflat', -- Trailer model (optional, leave nil if truck has no trailer)
capacity = 15, -- Maximum logs this truck can carry (must match #storagePositions)
allowedLogs = { -- Tree types this truck can transport
'Pine Tree', 'Oak Tree', 'Maple Tree'
},
storagePositions = { -- Log attachment positions on trailer
[1] = { offset = vector3(-1.0, 3.9, 0.65), rotation = vector3(0.0, 0.0, 0.0) }, -- offset relative to trailer, rotation = pitch/roll/yaw
[2] = { offset = vector3(-0.5, 3.9, 0.65), rotation = vector3(0.0, 0.0, 0.0) },
[3] = { offset = vector3(0.0, 3.9, 0.65), rotation = vector3(0.0, 0.0, 0.0) },
[4] = { offset = vector3(0.5, 3.9, 0.65), rotation = vector3(0.0, 0.0, 0.0) },
[5] = { offset = vector3(1.0, 3.9, 0.65), rotation = vector3(0.0, 0.0, 0.0) },
[6] = { offset = vector3(-1.0, -0.2, 0.65), rotation = vector3(0.0, 0.0, 0.0) },
[7] = { offset = vector3(-0.5, -0.2, 0.65), rotation = vector3(0.0, 0.0, 0.0) },
[8] = { offset = vector3(0.0, -0.2, 0.65), rotation = vector3(0.0, 0.0, 0.0) },
[9] = { offset = vector3(0.5, -0.2, 0.65), rotation = vector3(0.0, 0.0, 0.0) },
[10] = { offset = vector3(1.0, -0.2, 0.65), rotation = vector3(0.0, 0.0, 0.0) },
[11] = { offset = vector3(-1.0, -4.3, 0.65), rotation = vector3(0.0, 0.0, 0.0) },
[12] = { offset = vector3(-0.5, -4.3, 0.65), rotation = vector3(0.0, 0.0, 0.0) },
[13] = { offset = vector3(0.0, -4.3, 0.65), rotation = vector3(0.0, 0.0, 0.0) },
[14] = { offset = vector3(0.5, -4.3, 0.65), rotation = vector3(0.0, 0.0, 0.0) },
[15] = { offset = vector3(1.0, -4.3, 0.65), rotation = vector3(0.0, 0.0, 0.0) },
},
},
['hauler2'] = {
trailer = 'trflat',
capacity = 15,
allowedLogs = {
'Pine Tree', 'Oak Tree', 'Maple Tree', 'Birch Tree'
},
storagePositions = {
[1] = { offset = vector3(-1.0, 3.9, 0.65), rotation = vector3(0.0, 0.0, 0.0) },
[2] = { offset = vector3(-0.5, 3.9, 0.65), rotation = vector3(0.0, 0.0, 0.0) },
[3] = { offset = vector3(0.0, 3.9, 0.65), rotation = vector3(0.0, 0.0, 0.0) },
[4] = { offset = vector3(0.5, 3.9, 0.65), rotation = vector3(0.0, 0.0, 0.0) },
[5] = { offset = vector3(1.0, 3.9, 0.65), rotation = vector3(0.0, 0.0, 0.0) },
[6] = { offset = vector3(-1.0, -0.2, 0.65), rotation = vector3(0.0, 0.0, 0.0) },
[7] = { offset = vector3(-0.5, -0.2, 0.65), rotation = vector3(0.0, 0.0, 0.0) },
[8] = { offset = vector3(0.0, -0.2, 0.65), rotation = vector3(0.0, 0.0, 0.0) },
[9] = { offset = vector3(0.5, -0.2, 0.65), rotation = vector3(0.0, 0.0, 0.0) },
[10] = { offset = vector3(1.0, -0.2, 0.65), rotation = vector3(0.0, 0.0, 0.0) },
[11] = { offset = vector3(-1.0, -4.3, 0.65), rotation = vector3(0.0, 0.0, 0.0) },
[12] = { offset = vector3(-0.5, -4.3, 0.65), rotation = vector3(0.0, 0.0, 0.0) },
[13] = { offset = vector3(0.0, -4.3, 0.65), rotation = vector3(0.0, 0.0, 0.0) },
[14] = { offset = vector3(0.5, -4.3, 0.65), rotation = vector3(0.0, 0.0, 0.0) },
[15] = { offset = vector3(1.0, -4.3, 0.65), rotation = vector3(0.0, 0.0, 0.0) },
},
},
['phantom'] = {
trailer = 'trflat',
capacity = 30,
allowedLogs = {
'Pine Tree', 'Oak Tree', 'Maple Tree', 'Birch Tree', 'Cedar Tree'
},
storagePositions = {
[1] = { offset = vector3(-1.0, 3.9, 0.65), rotation = vector3(0.0, 0.0, 0.0) },
[2] = { offset = vector3(-0.5, 3.9, 0.65), rotation = vector3(0.0, 0.0, 0.0) },
[3] = { offset = vector3(0.0, 3.9, 0.65), rotation = vector3(0.0, 0.0, 0.0) },
[4] = { offset = vector3(0.5, 3.9, 0.65), rotation = vector3(0.0, 0.0, 0.0) },
[5] = { offset = vector3(1.0, 3.9, 0.65), rotation = vector3(0.0, 0.0, 0.0) },
[6] = { offset = vector3(-1.0, -0.2, 0.65), rotation = vector3(0.0, 0.0, 0.0) },
[7] = { offset = vector3(-0.5, -0.2, 0.65), rotation = vector3(0.0, 0.0, 0.0) },
[8] = { offset = vector3(0.0, -0.2, 0.65), rotation = vector3(0.0, 0.0, 0.0) },
[9] = { offset = vector3(0.5, -0.2, 0.65), rotation = vector3(0.0, 0.0, 0.0) },
[10] = { offset = vector3(1.0, -0.2, 0.65), rotation = vector3(0.0, 0.0, 0.0) },
[11] = { offset = vector3(-1.0, -4.3, 0.65), rotation = vector3(0.0, 0.0, 0.0) },
[12] = { offset = vector3(-0.5, -4.3, 0.65), rotation = vector3(0.0, 0.0, 0.0) },
[13] = { offset = vector3(0.0, -4.3, 0.65), rotation = vector3(0.0, 0.0, 0.0) },
[14] = { offset = vector3(0.5, -4.3, 0.65), rotation = vector3(0.0, 0.0, 0.0) },
[15] = { offset = vector3(1.0, -4.3, 0.65), rotation = vector3(0.0, 0.0, 0.0) },
[16] = { offset = vector3(-1.0, 3.9, 1.20), rotation = vector3(0.0, 0.0, 0.0) },
[17] = { offset = vector3(-0.5, 3.9, 1.20), rotation = vector3(0.0, 0.0, 0.0) },
[18] = { offset = vector3(0.0, 3.9, 1.20), rotation = vector3(0.0, 0.0, 0.0) },
[19] = { offset = vector3(0.5, 3.9, 1.20), rotation = vector3(0.0, 0.0, 0.0) },
[20] = { offset = vector3(1.0, 3.9, 1.20), rotation = vector3(0.0, 0.0, 0.0) },
[21] = { offset = vector3(-1.0, -0.2, 1.20), rotation = vector3(0.0, 0.0, 0.0) },
[22] = { offset = vector3(-0.5, -0.2, 1.20), rotation = vector3(0.0, 0.0, 0.0) },
[23] = { offset = vector3(0.0, -0.2, 1.20), rotation = vector3(0.0, 0.0, 0.0) },
[24] = { offset = vector3(0.5, -0.2, 1.20), rotation = vector3(0.0, 0.0, 0.0) },
[25] = { offset = vector3(1.0, -0.2, 1.20), rotation = vector3(0.0, 0.0, 0.0) },
[26] = { offset = vector3(-1.0, -4.3, 1.20), rotation = vector3(0.0, 0.0, 0.0) },
[27] = { offset = vector3(-0.5, -4.3, 1.20), rotation = vector3(0.0, 0.0, 0.0) },
[28] = { offset = vector3(0.0, -4.3, 1.20), rotation = vector3(0.0, 0.0, 0.0) },
[29] = { offset = vector3(0.5, -4.3, 1.20), rotation = vector3(0.0, 0.0, 0.0) },
[30] = { offset = vector3(1.0, -4.3, 1.20), rotation = vector3(0.0, 0.0, 0.0) },
},
},
['phantom2'] = {
trailer = 'trflat',
capacity = 30,
allowedLogs = {
'Pine Tree', 'Oak Tree', 'Maple Tree', 'Birch Tree', 'Cedar Tree', 'Mahogany Tree'
},
storagePositions = {
[1] = { offset = vector3(-1.0, 3.9, 0.65), rotation = vector3(0.0, 0.0, 0.0) },
[2] = { offset = vector3(-0.5, 3.9, 0.65), rotation = vector3(0.0, 0.0, 0.0) },
[3] = { offset = vector3(0.0, 3.9, 0.65), rotation = vector3(0.0, 0.0, 0.0) },
[4] = { offset = vector3(0.5, 3.9, 0.65), rotation = vector3(0.0, 0.0, 0.0) },
[5] = { offset = vector3(1.0, 3.9, 0.65), rotation = vector3(0.0, 0.0, 0.0) },
[6] = { offset = vector3(-1.0, -0.2, 0.65), rotation = vector3(0.0, 0.0, 0.0) },
[7] = { offset = vector3(-0.5, -0.2, 0.65), rotation = vector3(0.0, 0.0, 0.0) },
[8] = { offset = vector3(0.0, -0.2, 0.65), rotation = vector3(0.0, 0.0, 0.0) },
[9] = { offset = vector3(0.5, -0.2, 0.65), rotation = vector3(0.0, 0.0, 0.0) },
[10] = { offset = vector3(1.0, -0.2, 0.65), rotation = vector3(0.0, 0.0, 0.0) },
[11] = { offset = vector3(-1.0, -4.3, 0.65), rotation = vector3(0.0, 0.0, 0.0) },
[12] = { offset = vector3(-0.5, -4.3, 0.65), rotation = vector3(0.0, 0.0, 0.0) },
[13] = { offset = vector3(0.0, -4.3, 0.65), rotation = vector3(0.0, 0.0, 0.0) },
[14] = { offset = vector3(0.5, -4.3, 0.65), rotation = vector3(0.0, 0.0, 0.0) },
[15] = { offset = vector3(1.0, -4.3, 0.65), rotation = vector3(0.0, 0.0, 0.0) },
[16] = { offset = vector3(-1.0, 3.9, 1.20), rotation = vector3(0.0, 0.0, 0.0) },
[17] = { offset = vector3(-0.5, 3.9, 1.20), rotation = vector3(0.0, 0.0, 0.0) },
[18] = { offset = vector3(0.0, 3.9, 1.20), rotation = vector3(0.0, 0.0, 0.0) },
[19] = { offset = vector3(0.5, 3.9, 1.20), rotation = vector3(0.0, 0.0, 0.0) },
[20] = { offset = vector3(1.0, 3.9, 1.20), rotation = vector3(0.0, 0.0, 0.0) },
[21] = { offset = vector3(-1.0, -0.2, 1.20), rotation = vector3(0.0, 0.0, 0.0) },
[22] = { offset = vector3(-0.5, -0.2, 1.20), rotation = vector3(0.0, 0.0, 0.0) },
[23] = { offset = vector3(0.0, -0.2, 1.20), rotation = vector3(0.0, 0.0, 0.0) },
[24] = { offset = vector3(0.5, -0.2, 1.20), rotation = vector3(0.0, 0.0, 0.0) },
[25] = { offset = vector3(1.0, -0.2, 1.20), rotation = vector3(0.0, 0.0, 0.0) },
[26] = { offset = vector3(-1.0, -4.3, 1.20), rotation = vector3(0.0, 0.0, 0.0) },
[27] = { offset = vector3(-0.5, -4.3, 1.20), rotation = vector3(0.0, 0.0, 0.0) },
[28] = { offset = vector3(0.0, -4.3, 1.20), rotation = vector3(0.0, 0.0, 0.0) },
[29] = { offset = vector3(0.5, -4.3, 1.20), rotation = vector3(0.0, 0.0, 0.0) },
[30] = { offset = vector3(1.0, -4.3, 1.20), rotation = vector3(0.0, 0.0, 0.0) },
},
},
['phantom3'] = {
trailer = 'trflat',
capacity = 45,
allowedLogs = {
'Pine Tree', 'Oak Tree', 'Maple Tree', 'Birch Tree', 'Cedar Tree', 'Mahogany Tree', 'Redwood Tree'
},
storagePositions = {
[1] = { offset = vector3(-1.0, 3.9, 0.65), rotation = vector3(0.0, 0.0, 0.0) },
[2] = { offset = vector3(-0.5, 3.9, 0.65), rotation = vector3(0.0, 0.0, 0.0) },
[3] = { offset = vector3(0.0, 3.9, 0.65), rotation = vector3(0.0, 0.0, 0.0) },
[4] = { offset = vector3(0.5, 3.9, 0.65), rotation = vector3(0.0, 0.0, 0.0) },
[5] = { offset = vector3(1.0, 3.9, 0.65), rotation = vector3(0.0, 0.0, 0.0) },
[6] = { offset = vector3(-1.0, -0.2, 0.65), rotation = vector3(0.0, 0.0, 0.0) },
[7] = { offset = vector3(-0.5, -0.2, 0.65), rotation = vector3(0.0, 0.0, 0.0) },
[8] = { offset = vector3(0.0, -0.2, 0.65), rotation = vector3(0.0, 0.0, 0.0) },
[9] = { offset = vector3(0.5, -0.2, 0.65), rotation = vector3(0.0, 0.0, 0.0) },
[10] = { offset = vector3(1.0, -0.2, 0.65), rotation = vector3(0.0, 0.0, 0.0) },
[11] = { offset = vector3(-1.0, -4.3, 0.65), rotation = vector3(0.0, 0.0, 0.0) },
[12] = { offset = vector3(-0.5, -4.3, 0.65), rotation = vector3(0.0, 0.0, 0.0) },
[13] = { offset = vector3(0.0, -4.3, 0.65), rotation = vector3(0.0, 0.0, 0.0) },
[14] = { offset = vector3(0.5, -4.3, 0.65), rotation = vector3(0.0, 0.0, 0.0) },
[15] = { offset = vector3(1.0, -4.3, 0.65), rotation = vector3(0.0, 0.0, 0.0) },
[16] = { offset = vector3(-1.0, 3.9, 1.20), rotation = vector3(0.0, 0.0, 0.0) },
[17] = { offset = vector3(-0.5, 3.9, 1.20), rotation = vector3(0.0, 0.0, 0.0) },
[18] = { offset = vector3(0.0, 3.9, 1.20), rotation = vector3(0.0, 0.0, 0.0) },
[19] = { offset = vector3(0.5, 3.9, 1.20), rotation = vector3(0.0, 0.0, 0.0) },
[20] = { offset = vector3(1.0, 3.9, 1.20), rotation = vector3(0.0, 0.0, 0.0) },
[21] = { offset = vector3(-1.0, -0.2, 1.20), rotation = vector3(0.0, 0.0, 0.0) },
[22] = { offset = vector3(-0.5, -0.2, 1.20), rotation = vector3(0.0, 0.0, 0.0) },
[23] = { offset = vector3(0.0, -0.2, 1.20), rotation = vector3(0.0, 0.0, 0.0) },
[24] = { offset = vector3(0.5, -0.2, 1.20), rotation = vector3(0.0, 0.0, 0.0) },
[25] = { offset = vector3(1.0, -0.2, 1.20), rotation = vector3(0.0, 0.0, 0.0) },
[26] = { offset = vector3(-1.0, -4.3, 1.20), rotation = vector3(0.0, 0.0, 0.0) },
[27] = { offset = vector3(-0.5, -4.3, 1.20), rotation = vector3(0.0, 0.0, 0.0) },
[28] = { offset = vector3(0.0, -4.3, 1.20), rotation = vector3(0.0, 0.0, 0.0) },
[29] = { offset = vector3(0.5, -4.3, 1.20), rotation = vector3(0.0, 0.0, 0.0) },
[30] = { offset = vector3(1.0, -4.3, 1.20), rotation = vector3(0.0, 0.0, 0.0) },
[31] = { offset = vector3(-1.0, 3.9, 1.75), rotation = vector3(0.0, 0.0, 0.0) },
[32] = { offset = vector3(-0.5, 3.9, 1.75), rotation = vector3(0.0, 0.0, 0.0) },
[33] = { offset = vector3(0.0, 3.9, 1.75), rotation = vector3(0.0, 0.0, 0.0) },
[34] = { offset = vector3(0.5, 3.9, 1.75), rotation = vector3(0.0, 0.0, 0.0) },
[35] = { offset = vector3(1.0, 3.9, 1.75), rotation = vector3(0.0, 0.0, 0.0) },
[36] = { offset = vector3(-1.0, -0.2, 1.75), rotation = vector3(0.0, 0.0, 0.0) },
[37] = { offset = vector3(-0.5, -0.2, 1.75), rotation = vector3(0.0, 0.0, 0.0) },
[38] = { offset = vector3(0.0, -0.2, 1.75), rotation = vector3(0.0, 0.0, 0.0) },
[39] = { offset = vector3(0.5, -0.2, 1.75), rotation = vector3(0.0, 0.0, 0.0) },
[40] = { offset = vector3(1.0, -0.2, 1.75), rotation = vector3(0.0, 0.0, 0.0) },
[41] = { offset = vector3(-1.0, -4.3, 1.75), rotation = vector3(0.0, 0.0, 0.0) },
[42] = { offset = vector3(-0.5, -4.3, 1.75), rotation = vector3(0.0, 0.0, 0.0) },
[43] = { offset = vector3(0.0, -4.3, 1.75), rotation = vector3(0.0, 0.0, 0.0) },
[44] = { offset = vector3(0.5, -4.3, 1.75), rotation = vector3(0.0, 0.0, 0.0) },
[45] = { offset = vector3(1.0, -4.3, 1.75), rotation = vector3(0.0, 0.0, 0.0) },
},
},
['phantom4'] = {
trailer = 'trflat',
capacity = 60,
allowedLogs = {
'Pine Tree', 'Oak Tree', 'Maple Tree', 'Birch Tree', 'Cedar Tree', 'Mahogany Tree', 'Redwood Tree', 'Ancient Oak'
},
storagePositions = {
[1] = { offset = vector3(-1.0, 3.9, 0.65), rotation = vector3(0.0, 0.0, 0.0) },
[2] = { offset = vector3(-0.5, 3.9, 0.65), rotation = vector3(0.0, 0.0, 0.0) },
[3] = { offset = vector3(0.0, 3.9, 0.65), rotation = vector3(0.0, 0.0, 0.0) },
[4] = { offset = vector3(0.5, 3.9, 0.65), rotation = vector3(0.0, 0.0, 0.0) },
[5] = { offset = vector3(1.0, 3.9, 0.65), rotation = vector3(0.0, 0.0, 0.0) },
[6] = { offset = vector3(-1.0, -0.2, 0.65), rotation = vector3(0.0, 0.0, 0.0) },
[7] = { offset = vector3(-0.5, -0.2, 0.65), rotation = vector3(0.0, 0.0, 0.0) },
[8] = { offset = vector3(0.0, -0.2, 0.65), rotation = vector3(0.0, 0.0, 0.0) },
[9] = { offset = vector3(0.5, -0.2, 0.65), rotation = vector3(0.0, 0.0, 0.0) },
[10] = { offset = vector3(1.0, -0.2, 0.65), rotation = vector3(0.0, 0.0, 0.0) },
[11] = { offset = vector3(-1.0, -4.3, 0.65), rotation = vector3(0.0, 0.0, 0.0) },
[12] = { offset = vector3(-0.5, -4.3, 0.65), rotation = vector3(0.0, 0.0, 0.0) },
[13] = { offset = vector3(0.0, -4.3, 0.65), rotation = vector3(0.0, 0.0, 0.0) },
[14] = { offset = vector3(0.5, -4.3, 0.65), rotation = vector3(0.0, 0.0, 0.0) },
[15] = { offset = vector3(1.0, -4.3, 0.65), rotation = vector3(0.0, 0.0, 0.0) },
[16] = { offset = vector3(-1.0, 3.9, 1.20), rotation = vector3(0.0, 0.0, 0.0) },
[17] = { offset = vector3(-0.5, 3.9, 1.20), rotation = vector3(0.0, 0.0, 0.0) },
[18] = { offset = vector3(0.0, 3.9, 1.20), rotation = vector3(0.0, 0.0, 0.0) },
[19] = { offset = vector3(0.5, 3.9, 1.20), rotation = vector3(0.0, 0.0, 0.0) },
[20] = { offset = vector3(1.0, 3.9, 1.20), rotation = vector3(0.0, 0.0, 0.0) },
[21] = { offset = vector3(-1.0, -0.2, 1.20), rotation = vector3(0.0, 0.0, 0.0) },
[22] = { offset = vector3(-0.5, -0.2, 1.20), rotation = vector3(0.0, 0.0, 0.0) },
[23] = { offset = vector3(0.0, -0.2, 1.20), rotation = vector3(0.0, 0.0, 0.0) },
[24] = { offset = vector3(0.5, -0.2, 1.20), rotation = vector3(0.0, 0.0, 0.0) },
[25] = { offset = vector3(1.0, -0.2, 1.20), rotation = vector3(0.0, 0.0, 0.0) },
[26] = { offset = vector3(-1.0, -4.3, 1.20), rotation = vector3(0.0, 0.0, 0.0) },
[27] = { offset = vector3(-0.5, -4.3, 1.20), rotation = vector3(0.0, 0.0, 0.0) },
[28] = { offset = vector3(0.0, -4.3, 1.20), rotation = vector3(0.0, 0.0, 0.0) },
[29] = { offset = vector3(0.5, -4.3, 1.20), rotation = vector3(0.0, 0.0, 0.0) },
[30] = { offset = vector3(1.0, -4.3, 1.20), rotation = vector3(0.0, 0.0, 0.0) },
[31] = { offset = vector3(-1.0, 3.9, 1.75), rotation = vector3(0.0, 0.0, 0.0) },
[32] = { offset = vector3(-0.5, 3.9, 1.75), rotation = vector3(0.0, 0.0, 0.0) },
[33] = { offset = vector3(0.0, 3.9, 1.75), rotation = vector3(0.0, 0.0, 0.0) },
[34] = { offset = vector3(0.5, 3.9, 1.75), rotation = vector3(0.0, 0.0, 0.0) },
[35] = { offset = vector3(1.0, 3.9, 1.75), rotation = vector3(0.0, 0.0, 0.0) },
[36] = { offset = vector3(-1.0, -0.2, 1.75), rotation = vector3(0.0, 0.0, 0.0) },
[37] = { offset = vector3(-0.5, -0.2, 1.75), rotation = vector3(0.0, 0.0, 0.0) },
[38] = { offset = vector3(0.0, -0.2, 1.75), rotation = vector3(0.0, 0.0, 0.0) },
[39] = { offset = vector3(0.5, -0.2, 1.75), rotation = vector3(0.0, 0.0, 0.0) },
[40] = { offset = vector3(1.0, -0.2, 1.75), rotation = vector3(0.0, 0.0, 0.0) },
[41] = { offset = vector3(-1.0, -4.3, 1.75), rotation = vector3(0.0, 0.0, 0.0) },
[42] = { offset = vector3(-0.5, -4.3, 1.75), rotation = vector3(0.0, 0.0, 0.0) },
[43] = { offset = vector3(0.0, -4.3, 1.75), rotation = vector3(0.0, 0.0, 0.0) },
[44] = { offset = vector3(0.5, -4.3, 1.75), rotation = vector3(0.0, 0.0, 0.0) },
[45] = { offset = vector3(1.0, -4.3, 1.75), rotation = vector3(0.0, 0.0, 0.0) },
[46] = { offset = vector3(-1.0, 3.9, 2.30), rotation = vector3(0.0, 0.0, 0.0) },
[47] = { offset = vector3(-0.5, 3.9, 2.30), rotation = vector3(0.0, 0.0, 0.0) },
[48] = { offset = vector3(0.0, 3.9, 2.30), rotation = vector3(0.0, 0.0, 0.0) },
[49] = { offset = vector3(0.5, 3.9, 2.30), rotation = vector3(0.0, 0.0, 0.0) },
[50] = { offset = vector3(1.0, 3.9, 2.30), rotation = vector3(0.0, 0.0, 0.0) },
[51] = { offset = vector3(-1.0, -0.2, 2.30), rotation = vector3(0.0, 0.0, 0.0) },
[52] = { offset = vector3(-0.5, -0.2, 2.30), rotation = vector3(0.0, 0.0, 0.0) },
[53] = { offset = vector3(0.0, -0.2, 2.30), rotation = vector3(0.0, 0.0, 0.0) },
[54] = { offset = vector3(0.5, -0.2, 2.30), rotation = vector3(0.0, 0.0, 0.0) },
[55] = { offset = vector3(1.0, -0.2, 2.30), rotation = vector3(0.0, 0.0, 0.0) },
[56] = { offset = vector3(-1.0, -4.3, 2.30), rotation = vector3(0.0, 0.0, 0.0) },
[57] = { offset = vector3(-0.5, -4.3, 2.30), rotation = vector3(0.0, 0.0, 0.0) },
[58] = { offset = vector3(0.0, -4.3, 2.30), rotation = vector3(0.0, 0.0, 0.0) },
[59] = { offset = vector3(0.5, -4.3, 2.30), rotation = vector3(0.0, 0.0, 0.0) },
[60] = { offset = vector3(1.0, -4.3, 2.30), rotation = vector3(0.0, 0.0, 0.0) },
},
},
}
Config.DeliveryLocations = {
{ -- First delivery location
label = 'Paleto Bay Lumber Mill', -- Location name
coords = vector3(293.8029, 2863.8818, 43.6424), -- Center coordinates of selling zone
distCheck = 50.0, -- Zone radius (players can sell within this distance)
route = { -- GPS route in lumberjack NPC menu
enabled = true, -- Show this location in routes
coords = { x = 293.8029, y = 2863.8818 }, -- GPS waypoint coordinates
},
blip = { -- Map blip at center
enabled = true, -- Show blip
sprite = 478, -- Blip icon
color = 5, -- Blip color
display = 2, -- Display type
scale = 0.8, -- Blip size
shortrange = true, -- Only show when close
},
radiusBlip = { -- Circle radius blip showing zone
enabled = true, -- Show radius blip
radius = 50.0, -- Radius size (matches distCheck)
color = 5, -- Blip color
alpha = 80, -- Transparency (0-255)
shortrange = true, -- Only show when close
},
selling = { -- Progressive selling configuration
progressiveSellingTime = 2000, -- Milliseconds between each log sale
logsPerBatch = 1, -- Number of logs sold per batch
keybind = 38, -- Keybind to start/cancel selling (E key)
},
moneyType = 'bank', -- Payment type: 'bank' or 'cash'
prices = { -- Price per log type (tree name from trees.lua)
['Pine Tree'] = 12,
['Oak Tree'] = 18,
['Maple Tree'] = 24,
['Birch Tree'] = 28,
['Cedar Tree'] = 35,
['Mahogany Tree'] = 48,
['Redwood Tree'] = 65,
['Ancient Oak'] = 90,
},
},
{
label = 'Grapeseed Wood Processing',
coords = vector3(1685.42, 4925.31, 42.08),
distCheck = 120.0,
route = {
enabled = true,
coords = { x = 1685.42, y = 4925.31 },
},
blip = {
enabled = true,
sprite = 478,
color = 5,
display = 2,
scale = 0.8,
shortrange = true,
},
radiusBlip = {
enabled = true,
radius = 120.0,
color = 5,
alpha = 80,
shortrange = true,
},
selling = {
progressiveSellingTime = 1500,
logsPerBatch = 2,
keybind = 38,
},
moneyType = 'cash',
prices = {
['Pine Tree'] = 15,
['Oak Tree'] = 22,
['Maple Tree'] = 28,
['Birch Tree'] = 32,
['Cedar Tree'] = 42,
['Mahogany Tree'] = 55,
['Redwood Tree'] = 75,
['Ancient Oak'] = 105,
},
},
}
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)
--[[
BY RX Scripts © rxscripts.xyz
--]]
function AddLumberjackNPCTarget(ped)
if OXTarget then
OXTarget:addLocalEntity(ped, {
{
label = 'Open Paul The Lumberjack',
name = 'openLumberjackNPC',
icon = 'fas fa-trowel',
distance = 2.5,
onSelect = function(data)
OpenLumberjackUI()
end,
}
})
elseif QBTarget then
QBTarget:AddTargetEntity(ped, {
options = {
{
label = 'Open Paul The Lumberjack',
icon = 'fas fa-trowel',
targeticon = 'fas fa-trowel',
action = function(entity)
OpenLumberjackUI()
end,
}
},
distance = 2.5,
})
end
end
function AddTreeTarget(zoneName, treeId)
local tree = SpawnedTrees[zoneName][treeId]
local label = 'Chop ' .. tree.name
local icon = 'fas fa-tree'
if OXTarget then
OXTarget:addLocalEntity(tree.obj, {
{
label = label,
name = 'chopTree',
icon = icon,
distance = 2.5,
canInteract = function()
return not IsChopping
end,
onSelect = function(data)
ChopTree(zoneName, treeId)
end,
}
})
elseif QBTarget then
QBTarget:AddTargetEntity(tree.obj, {
options = {
{
label = label,
icon = icon,
targeticon = icon,
canInteract = function()
return not IsChopping
end,
action = function(entity)
ChopTree(zoneName, treeId)
end,
}
},
distance = 2.5,
})
end
end
function AddGlobalTreeTargets()
for treeName, tree in pairs(Config.Trees) do
for _, model in pairs(tree.models) do
if OXTarget then
OXTarget:addModel(model, {
{
label = 'Chop ' .. treeName,
name = 'chopTreeGlobal_' .. treeName .. '_' .. model,
icon = 'fas fa-tree',
distance = 2.5,
canInteract = function(entity)
local zoneName = GetZoneInside()
if not zoneName or not Config.LumberjackZones[zoneName].trees.useNativeTreeModels then
return false
end
for _, treeData in pairs(SpawnedTrees[zoneName] or {}) do
if entity == treeData.obj then return false end
end
return not IsChopping and zoneName
end,
onSelect = function(data)
CreateAndChopScriptTree(data.entity, treeName)
end,
}
})
end
end
end
end
function AddLogTarget(zoneName, logId)
local log = SpawnedLogs[zoneName][logId]
if not log or not log.obj then return end
local label = 'Cut ' .. log.fromTree .. ' log'
if OXTarget then
OXTarget:addLocalEntity(log.obj, {
{
label = label,
name = 'cutLog',
icon = 'fas fa-cut',
distance = 2.5,
canInteract = function()
return not IsChopping
end,
onSelect = function(data)
CutLog(zoneName, logId)
end,
}
})
elseif QBTarget then
QBTarget:AddTargetEntity(log.obj, {
options = {
{
label = label,
icon = 'fas fa-cut',
targeticon = 'fas fa-cut',
canInteract = function()
return not IsChopping
end,
action = function(entity)
CutLog(zoneName, logId)
end,
}
},
distance = 2.5,
})
end
end
function RemoveLogTarget(logObj)
if OXTarget then
OXTarget:removeLocalEntity(logObj, 'cutLog')
elseif QBTarget then
QBTarget:RemoveTargetEntity(logObj)
end
end
function AddSawmillTarget(sawmillObj, sawmillType, sawmillIndex)
local sawmillCfg = Config.Sawmills[sawmillType]
if not sawmillCfg then return end
local label = 'Use ' .. sawmillType
local targetName = 'useSawmill_' .. sawmillType .. '_' .. sawmillIndex
if OXTarget then
OXTarget:addLocalEntity(sawmillObj, {
{
label = label,
name = targetName,
icon = 'fas fa-industry',
distance = 2.5,
canInteract = function()
return not IsUsingSawmill
end,
onSelect = function(data)
UseSawmill(sawmillType, sawmillIndex)
end,
}
})
elseif QBTarget then
QBTarget:AddTargetEntity(sawmillObj, {
options = {
{
label = label,
icon = 'fas fa-industry',
targeticon = 'fas fa-industry',
canInteract = function()
return not IsUsingSawmill
end,
action = function(entity)
UseSawmill(sawmillType, sawmillIndex)
end,
}
},
distance = 2.5,
})
end
end
function AddShopNPCTarget(npc)
if OXTarget then
OXTarget:addLocalEntity(npc, {
{
label = 'Open Lumberjack Shop',
name = 'openLumberjackShop',
icon = 'fas fa-shopping-cart',
distance = 2.5,
onSelect = function(data)
OpenShopNPC()
end,
}
})
elseif QBTarget then
QBTarget:AddTargetEntity(npc, {
options = {
{
label = 'Open Lumberjack Shop',
icon = 'fas fa-shopping-cart',
targeticon = 'fas fa-shopping-cart',
action = function(entity)
OpenShopNPC()
end,
}
},
distance = 2.5,
})
end
end
function AddSellNPCTarget(npc, sellId)
if OXTarget then
OXTarget:addLocalEntity(npc, {
{
label = 'Open Wood Selling',
name = 'openWoodSelling',
icon = 'fas fa-shopping-cart',
distance = 2.5,
onSelect = function(data)
OpenSellNPC(sellId)
end,
}
})
elseif QBTarget then
QBTarget:AddTargetEntity(npc, {
options = {
{
label = 'Open Wood Selling',
icon = 'fas fa-shopping-cart',
targeticon = 'fas fa-shopping-cart',
action = function(entity)
OpenSellNPC(sellId)
end,
}
},
distance = 2.5,
})
end
end
function AddVehicleRentalNPCTarget(npc, rentalName, locIndex)
if OXTarget then
OXTarget:addLocalEntity(npc, {
{
label = 'Open ' .. rentalName,
name = 'openVehicleRental',
icon = 'fas fa-truck',
distance = 2.5,
onSelect = function(data)
OpenVehicleRental(rentalName, locIndex)
end,
}
})
elseif QBTarget then
QBTarget:AddTargetEntity(npc, {
options = {
{
label = 'Open ' .. rentalName,
icon = 'fas fa-ship',
targeticon = 'fas fa-truck',
action = function(entity)
OpenVehicleRental(rentalName, locIndex)
end,
}
},
distance = 2.5,
})
end
end
function RemoveShopNPCTarget(ped)
if OXTarget then
OXTarget:removeLocalEntity(ped, 'openLumberjackShop')
elseif QBTarget then
QBTarget:RemoveTargetEntity(ped, 'Open Lumberjack Shop')
end
end
function RemoveSellNPCTarget(ped)
if OXTarget then
OXTarget:removeLocalEntity(ped, 'openWoodSelling')
elseif QBTarget then
QBTarget:RemoveTargetEntity(ped, 'Open Wood Selling')
end
end
function RemoveTarget(ent, name)
if OXTarget then
OXTarget:removeLocalEntity(ent, name)
elseif QBTarget then
QBTarget:RemoveTargetEntity(ent, name)
end
end
function GetItemsAmounts()
return FM.callback.sync('lumberjack:getItemsAmounts')
end
function ChopProgressBar(toolFound, duration)
local cfgTool = Config.Tools[toolFound]
return FM.progress.start({
label = 'Chopping',
time = duration,
anim = cfgTool.anim,
disable = {
move = true,
car = true,
combat = true,
},
prop = cfgTool.prop,
type = 'circle',
})
end
function SawmillProgressBar(sawmillCfg, duration, label)
local progressData = {
label = label or _L('sawing_logs') or 'Sawing logs...',
time = duration,
disable = {
move = true,
car = true,
combat = true,
},
type = 'circle',
}
-- Add animation if present
if sawmillCfg.anim then
progressData.anim = sawmillCfg.anim
end
-- Add held prop if present
if sawmillCfg.heldProp then
progressData.prop = sawmillCfg.heldProp
end
return FM.progress.start(progressData)
end
---@param type 'returnVehicle'
function ShowMarker(type, coords)
if type == 'returnVehicle' then
DrawMarker(39, coords, 0, 0, 0, 0, 0, 0, 3.0, 3.0, 3.0, 255, 100, 100, 100, false, true, 2, false, false, false,
false)
end
end
function ShowHelpNotification(msg, thisFrame, beep, duration)
AddTextEntry('helpNotification', msg)
if thisFrame then
DisplayHelpTextThisFrame('helpNotification', false)
else
if beep == nil then
beep = true
end
BeginTextCommandDisplayHelp('helpNotification')
EndTextCommandDisplayHelp(0, false, beep, duration or -1)
end
end
local function notifyPolice(coords, msg)
local blip = AddBlipForCoord(coords.x, coords.y, coords.z)
SetBlipSprite(blip, 161)
SetBlipScale(blip, 1.0)
SetBlipColour(blip, 1)
SetBlipAsShortRange(blip, false)
BeginTextCommandSetBlipName("STRING")
AddTextComponentString(_L('blip_suspicious_lumberjack_activity'))
EndTextCommandSetBlipName(blip)
FM.utils.notify(msg, 'error')
Wait(20000)
RemoveBlip(blip)
end
RegisterNetEvent('lumberjack:notifyPolice', function(coords, msg)
notifyPolice(coords, msg)
end)
FM.inventory.displayMetadata({
fuelLevel = 'Fuel Level',
chopUsage = 'Durability',
sawUsage = 'Durability',
})
function AddDeliveryZoneTargets()
for locationIndex, location in ipairs(Config.DeliveryLocations) do
if OXTarget then
OXTarget:addBoxZone({
coords = location.zone.coords,
size = location.zone.size,
rotation = location.zone.rotation,
options = {
{
label = _L('sell_logs'),
icon = 'fas fa-hand-holding-dollar',
distance = 3.0,
canInteract = function()
-- Always show the option, server will handle validation
return true
end,
onSelect = function()
SellTrailerLogs(locationIndex)
end,
}
}
})
elseif QBTarget then
QBTarget:AddBoxZone('lumberjack_delivery_' .. locationIndex, location.zone.coords, location.zone.size.x, location.zone.size.y, {
name = 'lumberjack_delivery_' .. locationIndex,
heading = location.zone.rotation,
debugPoly = false,
minZ = location.zone.coords.z - 1.0,
maxZ = location.zone.coords.z + 2.0,
}, {
options = {
{
label = _L('sell_logs'),
icon = 'fas fa-hand-holding-dollar',
canInteract = function()
-- Always show the option, server will handle validation
return true
end,
action = function()
SellTrailerLogs(locationIndex)
end,
}
},
distance = 3.0,
})
end
end
end
