config.lua
Copy
Config, Seconds, Minutes, Hours = {}, 1000, 60000, 3600000 -- Do not touch
-- Use only if needed, directed by support or know what you're doing
-- Notice: enabling debug features can significantly increase resmon
-- And should always be disabled in production unless otherwise needed
Config.Debug = false
-- Do you want to be notified via server console if an update is available?
-- True if yes, false if no
Config.VersionCheck = true
-- Select your context menu below
-- Available options are: 'lation_ui', 'ox_lib', 'esx' or 'qb'
Config.Menu = 'ox_lib'
-- Target system - options are: 'ox_target', 'qb-target', 'qtarget', 'custom' & 'none'
-- 'custom' needs to be added to client/functions.lua
-- If 'none' then TextUI is used instead of targeting
Config.Target = 'none'
-- Set your progress bar system below
-- Available options are: 'lation_ui', 'ox_lib', 'qbcore' & 'custom'
-- 'custom' needs to be added to client/functions.lua
-- Any custom progress bar must also support animations
Config.Progress = 'ox_lib'
-- Notification system - options are: 'lation_ui', 'ox_lib', 'esx', 'qb', 'okok', 'sd-notify', 'wasabi_notify' & 'custom'
-- 'custom' needs to be added to client/functions.lua
Config.Notify = 'ox_lib'
-- The below is only used if Config.Target = 'none'
-- This will be the key used for interactions if no target is set
-- More options here: https://docs.fivem.net/docs/game-references/controls/
Config.InteractKey = 38 -- E
-- How do you want to notify users their money is ready (when using the warehouse)?
-- You can set your phone system below or set to 'none' to use a default alert
-- Options: 'qb-phone', 'npwd', 'qs-smartphone', 'qs-smartphonepro', 'lb-phone', 'gksphone', 'yseries', 'custom' or 'none'
-- If 'custom' you will have to configure your event(s) via client & server functions.lua
-- If 'none' then it will use a default alert dialog from ox_lib
Config.Phone = 'none'
-- Customize how you want players to begin money laundering
Config.Start = {
-- If spawnPed = true, the main starting NPC will be spawned as normal
-- If false, there will be no starting NPC at all
-- This option exists for those who want to handle where
-- When and how to open the main menu via exports, etc
spawnPed = true,
-- If enabled, the NPC spawned from above will be spawned randomly
-- At only one of the locations listed. If false, the ped will spawn
-- Normally at all the locations listed below
randomizeSpawn = false,
-- The "require" option below is for requiring a specific item to
-- Interact with/begin the money laundering process with the starting ped
-- If you want to require an item, set require to true and set item below
require = false,
-- If require = true, then what item do you want to require?
-- If require = false, this can be ignored
-- If you want the item removed, set remove = true & if not, remove = false
item = { name = 'water', quantity = 1, remove = false },
-- Render is the distance a player must be within to the starting ped
-- In order for it to spawn, outside this radius and the ped is deleted
-- Until it is needed again
render = 75,
-- If we're spawning a ped (or peds), what model is the ped?
-- You can find more here: https://docs.fivem.net/docs/game-references/ped-models/
model = 'g_m_importexport_01',
-- Below is where the ped (or peds) will spawn
-- Be sure to use vector4 coordinates
locations = {
vec4(138.6853, 270.6841, 109.9740, 73.0269),
-- Add more spawns here if desired
}
}
-- Customize your police related settings below
Config.Police = {
-- List your police jobs below
jobs = { 'police', 'sheriff' },
-- Do you want to require police be online to start laundering?
-- If true, this only applies to ped contracts, not the warehouse
require = false,
-- If require = true above, how many must be online?
count = 3,
-- Do you want to allow players with the police job access to the
-- Warehouse, ignoring all requirements such as level, key, etc?
warehouseAccess = true,
-- Do you want to enable police dispatch alerts? Police will only be
-- Notified upon a player being rejected - so Config.Reject.enable must
-- Be true to use this feature
enableDispatch = false,
-- If enableDispatch = true, what dispatch system do you use? Available
-- Options are: 'linden_outlawalert', 'cd_dispatch', 'ps-dispatch', 'qs-dispatch',
-- 'core_dispatch', 'rcore_dispatch', 'aty_dispatch' & 'custom'
-- 'custom' must be manually added in client/functions.lua
dispatchSystem = 'none'
}
-- Customize item spawn names here if needed
Config.Items = {
key = 'warehouse_key',
uncountedMoney = 'uncounted_money'
}
-----------------------------------------------------------------
-- ⛔ QBCore Users: IMPORTANT - PLEASE READ CAREFULLY BELOW ⛔
-----------------------------------------------------------------
-- The options below are vitally important to ensure things work
-- The way you wish them to work. Read carefully and set your options
Config.QBCore = {
-- If your dirty money item (markedbills or similar) uses metadata
-- (metadata meaning a "worth" or "value" when you hover over the item)
-- Then ensure you have metadata set to true! If false, it will count
-- Your dirty money item as 1:1, so 1 markedbills item will equal $1
metadata = true,
-- If you use metadata, do you want to count (add) up the total value
-- Of all dirty money found in the inventory? If so, set to true
-- If false, it'll only consider the first dirty money item found
-- In the inventory and work one bag at a time (not add up total)
countTotal = true,
-- If you use metadata, do you want to simply clean the entire items
-- Value? For example, if a player has a markedbills value of $100
-- Or $10,000, it don't matter, it'll clean whatever the total value is
-- If countTotal = true then it'll clean everything found in inventory
takeAll = false,
-- If you don't use metadata, but want the laundering script to assign
-- Values itself to your dirty money item (or items), you can do so here
-- By setting hardValues = true and listing your items values below
-- This option will completely ignore any worth or values already existing
-- For example, if you want markedbills to always be worth $500 each
hardValues = false,
-- List your items below you want to hard-assign values too
-- Be sure to follow the format below
items = {
['markedbills'] = 500,
-- ['cashrolls'] = 250,
-- Add more items here following the same format above
}
}
-- Vehicle related options when starting a new contract mission
Config.Vehicle = {
-- When a player starts a new contract run, do you want
-- To spawn a vehicle for them to use?
spawn = true,
-- If spawning a vehicle, do you want to teleport (warp)
-- The player directly into the vehicle's driver seat?
teleport = true,
-- If spawning a vehicle, how much fuel should the vehicle
-- Be spawned with? Be sure to use a float value! That simply
-- Means to include a .0 on whatever number you set here
fuel = 85.0,
-- If spawning a vehicle, what model should be spawned?
models = { 'baller3', 'fugitive' },
-- If you add multiple models to the list above you can
-- Set random = true to randomly select a model from the list
random = true,
-- Do you want to require the player pay for the vehicle that
-- Is being supplied for them to use if spawn = true?
requireDeposit = true,
-- If requireDeposit is true, how much should it cost?
depositPrice = 500,
-- When a player ends their contracts runs, should we
-- Return their deposit? The vehicle must be returned
-- At the initial starting location in the main menu
returnDeposit = true,
-- If returnDeposit is true, how much should we give back?
depositReturn = 250,
-- If requireDeposit is true, what account do you want to use
-- To pay for the rental and return deposit? (cash or bank)
account = 'cash',
-- If spawning a vehicle, where should the vehicle spawn?
-- If you have multiple starting ped locations, ensure you
-- Have a location for the vehicle to spawn at each location
-- The script will automatically detect which location to spawn
-- The vehicle at based on the location of the player
locations = {
vec4(125.9180, 278.1013, 109.9004, 249.8953),
-- Add more locations here if necessary
}
}
-- Customize your rejection settings here
-- Rejection is the ability for a ped to reject a player during cleaning
-- You can customize the rejection chance per level below (Config.Levels)
Config.Reject = {
-- Do you want to enable rejections? If true, a player can be rejected
-- Based on the chance set in their respective level. If false a player
-- Will never be rejected (unless they don't have enough money, of course)
enable = true,
-- If rejections are enabled, do you want to allow missions to continue
-- As normal after a rejection? Set to true if so. If you want missions
-- To end after a rejection, set continue to false
continue = true
}
-- Customize all warehouse related options below
Config.Warehouse = {
-- Below is the level the player unlocks the use of the warehouse
unlockAt = 5,
-- By default, when a player reaches the level to unlock use of the
-- Warehouse then they are no longer able to run contracts like previous
-- Levels. However, if you wish to allow them the option of both, you
-- Can set allowContracts to true
allowContracts = false,
-- The option below allows you to customize who can and who cannot enter
-- and use the warehouse. If requireLvl is true, then it requires the player
-- Attempting to enter be the correct level (unlockAt). If set to false,
-- Anyone can enter (and use) as long as they have the key required to enter
requireLvl = true,
-- If you want to require the player to purchase the warehouse key
-- Ensure requirePurchase is set to true. If set to false, the key will
-- Be given to the player for free
requirePurchase = true,
-- If requirePurchase is set to true above, how much does the key cost?
-- If requirePurchase is false, this can be ignored
price = 2500,
-- If requirePurchase is set to true above, what account is used to
-- Purchase the key? Options are 'bank' and 'cash' - if requirePurchase
-- Is false, this can also be ignored
account = 'cash',
-- When a player unlocks use of the warehouse, do you want to create a
-- Blip showing the location to enter the warehouse?
showBlip = true,
-- Below is the location at which the players are able to enter the warehouse
-- This is also the same location the blip will be displayed if enabled
enterAt = vec4(1142.6859, -986.6674, 45.9059, 96.6889),
-- exitAt is the coords the player will be teleported too upon entering
-- It will also be the same point at which the player will exit the warehouse
-- And they will then be teleported back to enterAt
exitAt = vec4(1138.0872, -3199.1570, -39.6657, 181.2139),
-- Rotate is the amount of degrees to turn the player upon exit and entry
-- To ensure the player is facing the correct direction when teleported
rotate = 180,
-- If you are using a custom location and it is an MLO, be sure to set
-- isMLO to true, which will disable the usage of enter/exit points, etc
isMLO = false,
-- Duration is how long in hours, minutes + seconds it takes to complete a washing
-- Cycle for money before it is ready to be picked up and counted. This can be as
-- Long as you desire - the script will save the time remaining upon server
-- Restarts and player logout events and pick back up wherever they left off at
duration = 1 * Hours + 25 * Minutes + 30 * Seconds,
-- Below is the location of the washing machine at which players can use
-- To put dirty money in to begin the washing process
washer = {
coords = vec3(1122.4, -3193.5, -40.35), -- The location of the washing machine itself
size = vec3(1.7, 4.35, 2.1), -- The size of the zone around the washer (for TextUI only)
rotation = 0, -- The rotation of the zone (for TextUI only)
debug = false, -- Enable or disable zone debugging (visual display, for TextUI only)
},
-- Below is the configurations for each money counting machine
counters = {
[1] = {
coords = vec3(1116.0024, -3194.9362, -40.5910), -- The location of the counting machine itself
size = vec3(3.2, 1.0, 1.8), -- The size of the zone around the machine (for TextUI only)
rotation = 0, -- The rotation of the zone (for TextUI only)
radius = 0.35, -- The size of the radius around the machine (for targeting only)
offset = vec3(0.6327, 0.0385, -0.8101), -- The offset from the machine where chair spawns & player sits
heading = 88.88, -- The direction the player is facing when counting money
debug = false -- Enable or disable zone debugging (visual display, for TextUI only)
},
[2] = {
coords = vec3(1116.0164, -3196.2717, -40.5917),
size = vec3(3.2, 1.0, 1.8),
rotation = 0,
radius = 0.35,
offset = vec3(0.5997, 0.0329, -0.8074),
heading = 88.88,
debug = false
},
-- Add more here as needed or desired
-- Note: this does not spawn the money counter, just makes one that exists interactable
-- Be sure to follow the same format as above
},
-- Set your money washing & counting limits below
limits = {
washing = {
-- Minimum amount that can be washed in one cycle
min = 500,
-- Maximum amount that can be washed in one cycle
-- (To change mission/contract limits go to Config.Levels)
max = 25000
},
counting = {
-- Set the minimum amount of money a player can count in one sitting
min = 0,
-- Set the maximum amount of money a player can count in one sitting
max = 15000,
-- Interval is how much money equals one full animation to play
-- For example, if a player is counting $5,000 uncounted_money
-- And the interval is set to 2500, that means it will play 2 times
-- If counting $10,000 then it will play 4 times, so on and so forth
-- Because it will play once for every $2,500 in money being counted
interval = 2500
}
},
-- While a player is counting money, below are what keys/actions are disabled
-- During the animation. Find more here: https://docs.fivem.net/docs/game-references/controls/
-- You can also use empty functions StartedCounting & StoppedCounting
-- Found in client/functions.lua for further control/integration
disable = {
200, -- ESC / pause menu
36, -- Left CTRL / duck
-- Add or remove as you wish
},
-- ConvertTo below is what we are converting our uncounted_money too
-- When the user has completed the counting process. By default this is
-- Cash, but can be set to 'cash' or 'bank'
convertTo = 'cash'
}
-- Customize the leveling system below
Config.Levels = {
[1] = { -- Level 1
-- The dirty money item used at level 1
dirtyMoney = 'markedbills',
-- Tax rate is how much dirty money is lost during the cleaning process
-- For example, a 25% tax rate means the player will receive $750 clean
-- Cash for $1,000 dirty
taxRate = 25,
-- The clean options below are the minimum and maximum amounts each ped
-- Will clean in one contract. The ped will randomly select an amount
-- Between these two values and offer to clean that amount
clean = { min = 500, max = 1000 },
-- AddXP is how much experience is rewarded per cleaning contract
-- This is where you can adjust how fast or slow leveling is
addXP = 1000,
-- If negotiations are enabled, this is the percentage chance a
-- Players negotiation is accepted
negotiateChance = 60,
-- If negotiations are enabled and the ped successfully accepts
-- This is how much the cleaning amount offered is increased
-- This is a percentage, so 25 means 25% boost ($1000 offer becomes $1250)
multiplier = 25,
-- If Config.Reject.enable is true, RejectChance is the percentage
-- chance a player gets rejected during cleaning contracts at this level
rejectChance = 20
},
[2] = { -- Level 2
dirtyMoney = 'markedbills',
taxRate = 20,
clean = { min = 750, max = 1500 },
addXP = 500,
negotiateChance = 70,
multiplier = 50,
rejectChance = 15
},
[3] = { -- Level 3
dirtyMoney = 'markedbills',
taxRate = 15,
clean = { min = 1000, max = 2000 },
addXP = 250,
negotiateChance = 80,
multiplier = 75,
rejectChance = 10
},
[4] = { -- Level 4
dirtyMoney = 'markedbills',
taxRate = 10,
clean = { min = 1500, max = 3000 },
addXP = 125,
negotiateChance = 90,
multiplier = 100,
rejectChance = 5
},
[5] = { -- Level 5
dirtyMoney = 'markedbills',
taxRate = 5,
-- (To change warehouse washing limits go to Config.Warehouse.limits.washing)
clean = { min = 2000, max = 10000 },
-- When a player achieves the final level, no more XP is gained
-- No matter what is in addXP below
addXP = 1,
-- At the final level, by default level 5, the options below
-- negotiateChance, multiplier & rejectChance are only used
-- If allowContracts above is true, otherwise don't matter
negotiateChance = 95,
multiplier = 125,
rejectChance = 0
},
-- Add or remove levels with custom options however you wish!
-- Be sure to follow the correct format and increment numbers correctly
}
-- This is the amount of experience that must be earned between
-- Each level. For example, from level 1 to level 2 you must gain
-- 100,000 XP. Same goes for level 2 to level 3. To customize how
-- Fast or slow the leveling happens between levels, it's best
-- to simply adjust "addXP" above for each level, not this
Config.LevelUp = 100000
-- If you want to allow players the ability to negotiate with the ped
-- The amount of money they are offering to clean for a chance at a
-- Higher amount, set to true. If not, set to false. You can customize
-- The chances at which players are successful above in Config.Levels
Config.AllowNegotiations = true
-- Customize how you wants your blips to display
Config.Blips = {
start = { -- The ped location(s) to start cleaning money
enabled = true, -- Do you want blip(s) showing where to start money laundering?
sprite = 47, -- Sprite ID: https://docs.fivem.net/docs/game-references/blips/
color = 0, -- Color: https://docs.fivem.net/docs/game-references/blips/#blip-colors
scale = 0.8, -- Size of the blip on the map
label = 'Money Laundering' -- Blip name/label
},
contracts = { -- Blip used when washing money with various peds
sprite = 500,
color = 2,
scale = 0.8,
label = 'Money Contract'
},
warehouse = { -- Blip used for the warehouse location if enabled
sprite = 473,
color = 17,
scale = 0.8,
label = 'Warehouse'
}
}
-- Manage all animations used here
Config.Animations = {
accept = {
label = 'Making deal..',
duration = 5000,
position = 'bottom',
useWhileDead = false,
canCancel = true,
disable = { move = true, car = true, combat = true },
anim = { dict = 'missfam4', clip = 'base' },
prop = { model = `p_amb_clipboard_01`, bone = 36029, pos = vec3(0.160, 0.080, 0.100), rot = vec3(-130.00, -50.00, 0.00) }
},
negotiate = {
label = 'Negotiating..',
duration = 6000,
position = 'bottom',
useWhileDead = false,
canCancel = true,
disable = { move = true, car = true, combat = true },
anim = { dict = 'misscarsteal4@actor', clip = 'actor_berating_loop' },
prop = { }
},
wash = {
duration = 1500,
anim = { dict = 'missfbi_s4mop', clip = 'put_down_bucket' }
},
count = {
anim = { dict = 'anim@amb@business@cfm@cfm_counting_notes@', clip = 'note_counting_counter' },
props = {
chair = 'v_corp_cd_chair',
briefcase = 'prop_cash_case_02',
cash = 'bkr_prop_money_sorted_01',
cashWrapped = 'bkr_prop_money_wrapped_01'
}
}
}
-- Various locations at which NPCs will spawn during contracts
Config.Locations = {
vec4(130.2, -1274.99, 29.24, 0.0),
vec4(162.11, -1268.32, 29.24, 160.62),
vec4(161.79, -1286.42, 29.23, 110.34),
vec4(339.17, -1263.60, 31.96, 74.82),
vec4(306.83, -1246.18, 29.57, 08.58),
vec4(343.40, -1190.28, 29.31, 164.21),
vec4(109.19, -1804.54, 26.50, 179.38),
vec4(524.42, -1831.14, 28.28, 249.49),
vec4(959.98, -2373.81, 30.50, 0.0),
vec4(1062.27, -2408.46, 29.97, 92.5),
vec4(1140.85, -2332.80, 31.34, 166),
vec4(1126.36, -2096.35, 31.08, 278.05),
vec4(990.39, -1791.78, 31.63, 181.86),
vec4(1010.55, -1778.92, 31.42, 83.75),
vec4(977.90, -1708.98, 30.09, 87.52),
vec4(990.39, -1660.08, 29.44, 0.0),
vec4(980.86, -1383.56, 31.54, 29.47),
vec4(935.19, -1520.58, 31.06, 0.0),
vec4(998.07, -1489.55, 31.41, 278.1),
vec4(925.84, -1483.28, 30.11, 50.98),
vec4(886.78, -1516.57, 30.18, 223.01),
vec4(886.59, -1584.52, 30.95, 261.39),
vec4(536.46, -1650.18, 29.26, 259.47),
vec4(491.19, -1705.30, 29.35, 325.47),
vec4(353.25, -1850.11, 27.71, 217.45),
vec4(201.78, -2002.96, 18.86, 234),
vec4(-592.01, -1767.25, 23.18, 235.15),
vec4(-1110.98, -1046.5, 2.153, 214.28),
vec4(1064.63, -2407.89, 29.98, 106.59),
vec4(1078.87, -2443.25, 29.44, 89.69),
vec4(953.97, -2529.31, 28.30, 171.31),
vec4(402.26, -2188.63, 5.917, 243.06),
vec4(-353.99, -1490.89, 30.26, 142.04),
vec4(-312.45, -1342.49, 31.32, 42.24),
vec4(-342.67, -899.03, 31.07, 210.86),
vec4(-317.44, -772.25, 33.96, 28.59),
vec4(-241.84, -785.30, 30.45, 71.82),
vec4(-203.62, -758.88, 30.45, 196.89),
vec4(-222.69, -641.03, 33.39, 142),
vec4(66.48, -266.27, 48.18, 214.91),
vec4(117.78, -265.57, 46.33, 114.95),
vec4(133.96, -258.22, 46.33, 118.89),
vec4(169.79, -279.18, 50.27, 297.43),
vec4(475.16, -105.43, 63.15, 190.25),
vec4(741.29, 140.41, 80.76, 188.99),
vec4(777.54, 210.96, 83.64, 158.28),
vec4(955.28, -194.77, 73.20, 229.43),
vec4(960.85, -210.85, 73.21, 37.49),
vec4(974.39, -192.00, 73.20, 37.49),
vec4(966.46, -203.89, 76.25, 249.08),
vec4(955.76, -195.02, 79.29, 143.23),
vec4(791.53, -102.66, 82.03, 335.53),
vec4(820.06, -124.38, 80.22, 296.63),
vec4(501.94, -612.38, 24.75, 280.33),
vec4(460.75, -698.17, 27.42, 41.48),
vec4(367.92, -776.74, 29.26, 95.15),
vec4(378.51, -900.16, 29.41, 197.58),
vec4(-3.72, -1086.34, 26.67, 65.54),
vec4(-17.60, -1037.06, 28.90, 0.0),
vec4(45.53, -1011.18, 29.52, 109.67),
vec4(2.23, -1024.41, 28.96, 103.56),
vec4(-771.69, -1028.13, 14.13, 254.41),
vec4(-661.76, -710.01, 26.89, 193.05),
vec4(-617.15, -683.27, 32.23, 222.4),
vec4(-584.07, -698.28, 31.23, 176.97),
vec4(-577.70, -676.53, 36.28, 125.32),
vec4(-592.16, -751.90, 36.28, 4.41),
vec4(-594.46, -748.81, 29.48, 225.83),
vec4(-574.89, -800.02, 30.68, 40.03),
vec4(-590.54, -797.30, 26.04, 223.14),
vec4(-1000.58, -945.72, 2.15, 160.51),
vec4(-1055.29, -971.06, 2.00, 198.95),
vec4(-1072.79, -988.20, 2.15, 249.84),
vec4(-1044.78, -1168.74, 2.15, 302.46),
vec4(-1083.22, -1140.00, 2.15, 250.54),
vec4(-1122.34, -1237.42, 3.17, 295.03),
vec4(-1112.39, -1258.41, 6.65, 65.14)
}
-- Various NPC models that will be used as the contract NPCs
Config.Models = {
'a_m_m_afriamer_01',
'u_m_m_aldinapoli',
's_m_y_ammucity_01',
's_m_m_ammucountry',
'u_m_y_antonb',
'csb_anton',
'g_m_m_armboss_01',
'g_m_m_armgoon_01',
'g_m_y_armgoon_02',
'g_m_m_armlieut_01',
'ig_ashley',
'cs_ashley',
's_m_y_autopsy_01',
's_m_m_autoshop_01',
's_m_m_autoshop_02',
'ig_money',
'csb_money',
'g_m_y_azteca_01',
'u_m_y_babyd',
'g_m_y_ballaeast_01',
'g_m_y_ballaorig_01',
'g_f_y_ballas_01',
'ig_ballasog',
'csb_ballasog',
'g_m_y_ballasout_01',
's_m_y_barman_01',
's_f_y_bartender_01',
'u_m_y_baygor',
's_f_y_baywatch_01',
's_m_y_baywatch_01',
'a_f_m_beach_01',
'a_f_y_beach_01',
'a_m_m_beach_01',
'a_m_o_beach_01',
'a_m_y_beach_01',
'a_m_m_beach_02',
'a_m_y_beach_02',
'a_m_y_beach_03',
'a_m_y_beachvesp_01',
'a_m_y_beachvesp_02',
'ig_benny',
'ig_beverly',
'cs_beverly',
'a_f_m_bevhills_01',
'a_f_y_bevhills_01',
'a_m_m_bevhills_01',
'a_m_y_bevhills_01',
'a_f_m_bevhills_02',
'a_f_y_bevhills_02',
'a_m_m_bevhills_02',
'a_m_y_bevhills_02',
'a_f_y_bevhills_03',
'a_f_y_bevhills_04',
'u_m_m_bikehire_01',
'u_f_y_bikerchic',
'a_m_y_breakdance_01',
'u_m_y_burgerdrug_01',
'csb_burgerdrug',
's_m_y_busboy_01',
'u_m_m_rivalpap',
'a_m_y_roadcyc_01',
's_m_y_robber_01',
'ig_roccopelosi',
'csb_roccopelosi',
'a_f_y_runner_01',
'a_m_y_runner_01',
'a_m_y_runner_02',
'a_f_y_rurmeth_01',
'a_m_m_rurmeth_01',
'ig_russiandrunk',
'cs_russiandrunk',
'a_f_m_salton_01',
'a_f_o_salton_01',
'a_m_m_salton_01',
'a_m_o_salton_01',
'a_m_y_salton_01',
'a_m_m_salton_02',
'a_m_m_salton_03',
'a_m_m_salton_04',
'g_m_y_salvaboss_01',
'g_m_y_salvagoon_01',
'g_m_y_salvagoon_02',
'g_m_y_salvagoon_03',
'a_m_y_vinewood_04',
}
Copy
PlayerLoaded, PlayerData = nil, {}
-- Get framework
if GetResourceState('es_extended') == 'started' then
ESX = exports['es_extended']:getSharedObject()
Framework = 'esx'
RegisterNetEvent('esx:playerLoaded', function(xPlayer)
PlayerData = xPlayer
PlayerLoaded = true
TriggerEvent('lation_laundering:onPlayerLoaded')
end)
RegisterNetEvent('esx:onPlayerLogout', function()
table.wipe(PlayerData)
PlayerLoaded = false
end)
AddEventHandler('onResourceStart', function(resourceName)
if GetCurrentResourceName() ~= resourceName or not ESX.PlayerLoaded then return end
PlayerData = ESX.GetPlayerData()
PlayerLoaded = true
TriggerEvent('lation_laundering:onPlayerLoaded')
end)
elseif GetResourceState('qb-core') == 'started' then
QBCore = exports['qb-core']:GetCoreObject()
Framework = 'qb'
AddStateBagChangeHandler('isLoggedIn', '', function(_bagName, _key, value, _reserved, _replicated)
if value then
PlayerData = QBCore.Functions.GetPlayerData()
else
table.wipe(PlayerData)
end
PlayerLoaded = value
end)
RegisterNetEvent('QBCore:Client:OnPlayerLoaded', function()
TriggerEvent('lation_laundering:onPlayerLoaded')
end)
AddEventHandler('onResourceStart', function(resourceName)
if GetCurrentResourceName() ~= resourceName or not LocalPlayer.state.isLoggedIn then return end
PlayerData = QBCore.Functions.GetPlayerData()
PlayerLoaded = true
TriggerEvent('lation_laundering:onPlayerLoaded')
end)
else
-- Add support for a custom framework here
end
-- Function used to get latest player data
GetPlayerData = function()
if Framework == 'esx' then
return ESX.GetPlayerData()
elseif Framework == 'qb' then
return QBCore.Functions.GetPlayerData()
else
-- Add support for a custom framework here
end
end
Copy
local ox_inv = GetResourceState('ox_inventory') == 'started'
-- You can change the textUI script here
-- Options: 'lation_ui', 'ox_lib', 'jg-textui', 'okokTextUI', 'qbcore' & 'custom'
local textui = 'lation_ui'
-- Function to show a notification
--- @param message string
--- @param type string
ShowNotification = function(message, type)
if Config.Notify == 'lation_ui' then
exports.lation_ui:notify({ title = 'Money Laundering', message = message, type = type, icon = 'fas fa-money-bill-wave' })
elseif Config.Notify == 'ox_lib' then
lib.notify({ title = 'Money Laundering', description = message, type = type, position = 'top', icon = 'fas fa-money-bill-wave' })
elseif Config.Notify == 'esx' then
ESX.ShowNotification(message)
elseif Config.Notify == 'qb' then
QBCore.Functions.Notify(message, type)
elseif Config.Notify == 'okok' then
exports['okokNotify']:Alert('Money Laundering', message, 5000, type, false)
elseif Config.Notify == 'sd-notify' then
exports['sd-notify']:Notify('Money Laundering', message, type)
elseif Config.Notify == 'wasabi_notify' then
exports.wasabi_notify:notify('Money Laundering', message, 5000, type, false, 'fas fa-money-bill-wave')
elseif Config.Notify == 'custom' then
-- Add custom notification export/event here
end
end
-- Event used to display notifications from server
--- @param message string
--- @param type string
RegisterNetEvent('lation_laundering:Notify', function(message, type)
ShowNotification(message, type)
end)
-- Function used to set vehicle fuel
--- @param vehicle number
SetFuel = function(vehicle)
-- Check if LegacyFuel is running
if GetResourceState('LegacyFuel') == 'started' then
exports['LegacyFuel']:SetFuel(vehicle, Config.Vehicle.fuel)
end
-- Check if cdn-fuel is running
if GetResourceState('cdn-fuel') == 'started' then
exports['cdn-fuel']:SetFuel(vehicle, Config.Vehicle.fuel)
end
-- Check if ps-fuel is running
if GetResourceState('ps-fuel') == 'started' then
exports['ps-fuel']:SetFuel(vehicle, Config.Vehicle.fuel)
end
-- Check if lj-fuel is running
if GetResourceState('lj-fuel') == 'started' then
exports['lj-fuel']:SetFuel(vehicle, Config.Vehicle.fuel)
end
-- Check if okokGasStation is running
if GetResourceState('okokGasStation') == 'started' then
exports['okokGasStation']:SetFuel(vehicle, Config.Vehicle.fuel)
end
-- Check if nd_fuel is running
if GetResourceState('nd_fuel') == 'started' then
exports['nd_fuel']:SetFuel(vehicle, Config.Vehicle.fuel)
end
Entity(vehicle).state.fuel = Config.Vehicle.fuel
end
-- Function used to give keys to vehicle
--- @param vehicle number
GiveKeys = function(vehicle)
-- Get vehicle plate & model
local plate = GetVehicleNumberPlateText(vehicle)
local model = GetDisplayNameFromVehicleModel(GetEntityModel(vehicle))
-- Check if wasabi_carlock is running
if GetResourceState('wasabi_carlock') == 'started' then
exports.wasabi_carlock:GiveKey(plate)
end
-- Check if okokGarage is running
if GetResourceState('okokGarage') == 'started' then
TriggerServerEvent("okokGarage:GiveKeys", plate)
end
-- Check if qb-vehiclekeys is running
if GetResourceState('qb-vehiclekeys') == 'started' then
TriggerEvent('qb-vehiclekeys:client:AddKeys', plate)
end
-- Check if qs-vehiclekeys is running
if GetResourceState('qs-vehiclekeys') == 'started' then
exports['qs-vehiclekeys']:GiveKeys(plate, model, true)
end
-- Check if cd_garage is running
if GetResourceState('cd_garage') == 'started' then
TriggerEvent('cd_garage:AddKeys', plate)
end
-- Check if jaksam's vehicles_keys is running
if GetResourceState('vehicles_keys') == 'started' then
TriggerServerEvent('vehicles_keys:selfGiveVehicleKeys', plate)
end
-- Check if t1ger_keys is running
if GetResourceState('t1ger_keys') == 'started' then
TriggerServerEvent('t1ger_keys:updateOwnedKeys', plate, true)
end
-- Check if Renewed-Vehiclekeys is running
if GetResourceState('Renewed-Vehiclekeys') == 'started' then
exports['Renewed-Vehiclekeys']:addKey(plate)
end
end
-- Function that allows or rejects a player from opening main menu
CanOpenMenu = function()
-- Example implementation to show how this works
-- First, we're checking if the player is dead
local dead = IsPedDeadOrDying(cache.ped, false)
-- If the variable "dead" is true, it'll return false below
-- Which will not allow the menu to open
if dead then
-- Here is where you would display a notification providing
-- Some information to the player about why the menu won't open
return false
end
-- If "dead" is false, then the code proceeds to here
-- Which now returns "true", allowing the menu to open
return true
end
-- Function that allows or rejects a player from purchasing warehouse key
CanBuyKey = function()
-- This function works the same as the above CanOpenMenu
-- Except obviously for the purchasing of the warehouse key
-- We'll provide another example implementation below:
-- Let's say we wanted to restrict buying keys to gangs only
-- You would obviously replace "true" with your gang system export
-- That would check if a player was in a gang or not
local inGang = true
-- Next we add an if-then statement below, so if not inGang then..
if not inGang then
-- We return false! Thus not allowing the player to purchase
-- A warehouse key if they are not a gang member. We would also
-- Likely inform the player here with a notification like:
-- ShowNotification('You must be a gang member to purchase this', 'error')
return false
end
-- If the player IS a gang member, then we'll make it to this part of
-- The code and then simply return true, allowing them to purchase a key
return true
end
-- Function that runs to verify conditions before allowing warehouse entry
CanEnterWarehouse = function()
-- Initialize variables
local result, isPolice = true, false
-- Check if police exception exists
if Config.Police.warehouseAccess then
local player = GetPlayerData()
for _, job in pairs(Config.Police.jobs) do
if player.job.name == job then
isPolice = true
end
end
end
-- Check if player has the key
local hasKey = HasItem(Config.Items.key, 1)
if not hasKey and not isPolice then
ShowNotification(Strings.Notify.notAuthorized, 'error')
result = false
end
-- Check if we're enforcing level requirement
if Config.Warehouse.requireLvl then
local level = exports.lation_laundering:GetData('level')
if level < Config.Warehouse.unlockAt and not isPolice then
ShowNotification(Strings.Notify.notAuthorized, 'error')
result = false
end
end
-- If you want to add custom requirements to entering the warehouse
-- This is where you would make that happen
return result
end
-- Function that's triggered when started counting money
-- This function can be used for anything, but by default
-- It disables the ability to open your inventory during
-- The money counting process
StartedCounting = function()
-- Check if ox_inventory is running
if GetResourceState('ox_inventory') == 'started' then
LocalPlayer.state.invBusy = true
end
-- Check if qb-inventory is running
if GetResourceState('qb-inventory') == 'started' then
LocalPlayer.state.inv_busy = true
end
-- Check if qs-inventory is running
if GetResourceState('qs-inventory') == 'started' then
exports['qs-inventory']:setInventoryDisabled(true)
end
end
-- Function that's triggered when stopped counting money
-- As mentioned above, this function can be used for anything
-- After a player has completed counting money, it will
-- Re-enable access to their inventory
StoppedCounting = function()
-- Check if ox_inventory is running
if GetResourceState('ox_inventory') == 'started' then
LocalPlayer.state.invBusy = false
end
-- Check if qb-inventory is running
if GetResourceState('qb-inventory') == 'started' then
LocalPlayer.state.inv_busy = false
end
-- Check if qs-inventory is running
if GetResourceState('qs-inventory') == 'started' then
exports['qs-inventory']:setInventoryDisabled(false)
end
end
-- Function that's triggered when a player has entered the warehouse
EnteredWarehouse = function()
end
-- Function that's triggered when a player has exited the warehouse
ExitedWarehouse = function()
end
-- Function that's triggered when starting contracts
StartedLaundering = function()
end
-- Function that's triggered when stopping contracts
StoppedLaundering = function()
end
-- Function to handle dispatch notifications
--- @param dispatch table .coords, .street
PoliceDispatch = function(dispatch)
if Config.Police.dispatchSystem == 'linden_outlawalert' then
local d = {displayCode = '10-911', description = 'Suspicious Activity', isImportant = 0, recipientList = Config.Police.jobs, length = '10000', infoM = 'fa-info-circle', info = 'A citizen has reported suspicious activity on ' ..dispatch.street}
local dispatchData = { dispatchData = d, caller = 'Citizen', coords = dispatch.coords }
TriggerServerEvent('wf-alerts:svNotify', dispatchData)
elseif Config.Police.dispatchSystem == 'cd_dispatch' then
local data = exports['cd_dispatch']:GetPlayerInfo()
TriggerServerEvent('cd_dispatch:AddNotification', {
job_table = Config.Police.jobs,
coords = data.coords,
title = '10-911 - Suspicious Activity',
message = 'A citizen has reported suspicious activity on ' ..data.street,
flash = 0,
unique_id = data.unique_id,
sound = 1,
blip = {
sprite = 51,
scale = 1.0,
colour = 1,
flashes = false,
text = '10-911 | Suspicious Activity',
time = 5,
radius = 0,
}
})
elseif Config.Police.dispatchSystem == 'ps-dispatch' then
exports["ps-dispatch"]:CustomAlert({
coords = dispatch.coords,
message = "A citizen has reported suspicious activity on " ..dispatch.street,
dispatchCode = "10-911 | Suspicious Activity",
description = "Suspicious Activity",
radius = 0,
sprite = 64,
color = 2,
scale = 1.0,
length = 3,
})
elseif Config.Police.dispatchSystem == 'qs-dispatch' then
local playerData = exports['qs-dispatch']:GetPlayerInfo()
TriggerServerEvent('qs-dispatch:server:CreateDispatchCall', {
job = Config.Police.jobs,
callLocation = playerData.coords,
callCode = { code = '10-911', snippet = 'Suspicious Activity' },
message = 'A citizen has reported suspicious activity on ' ..playerData.street_1,
flashes = false,
image = nil,
blip = {
sprite = 488,
scale = 1.5,
colour = 1,
flashes = true,
text = 'Suspicious Activity',
time = (6 * 60 * 1000),
}
})
elseif Config.Police.dispatchSystem == 'core_dispatch' then
local gender = IsPedMale(cache.ped) and 'male' or 'female'
TriggerServerEvent("core_dispatch:addCall", "10-911", "Suspicious Activity",
{{icon = "fa-venus-mars", info = gender}},
{dispatch.coords.x, dispatch.coords.y, dispatch.coords.z},
'police', 30000, 156, 1, false)
elseif Config.Police.dispatchSystem == 'rcore_dispatch' then
local player_data = exports['rcore_dispatch']:GetPlayerData()
local data = {
code = '10-911 - Suspicious Activity',
default_priority = 'low',
coords = player_data.coords,
job = Config.Police.jobs,
text = 'A citizen has reported suspicious activity on ' ..player_data.street_1,
type = 'alerts',
blip = {
sprite = 54,
colour = 3,
scale = 0.7,
text = '10-911 - Suspicious Activity',
flashes = false,
radius = 0,
}
}
TriggerServerEvent('rcore_dispatch:server:sendAlert', data)
elseif Config.Police.dispatchSystem == 'aty_dispatch' then
TriggerEvent('aty_dispatch:SendDispatch', 'Suspicious Activity', '10-911', 54, Config.Police.jobs)
elseif Config.Police.dispatchSystem == 'custom' then
-- Add your custom dispatch system here
else
-- No dispatch system was found
if Config.Police.enableDispatch then
print('No dispatch system was identified - please update your Config.Police.dispatchSystem')
end
end
end
-- Function to handle sending a message to specific phone
SendPhoneMessage = function()
if Config.Phone == 'qb-phone' then
TriggerServerEvent('lation_laundering:phoneMessage', cache.serverId)
elseif Config.Phone == 'npwd' then
local number = exports.npwd:getPhoneNumber()
TriggerServerEvent('lation_laundering:phoneMessage', cache.serverId, number)
elseif Config.Phone == 'qs-smartphone' then
TriggerServerEvent('lation_laundering:phoneMessage', cache.serverId)
elseif Config.Phone == 'qs-smartphonepro' then
local data = { sender = Strings.Phone.sender, subject = Strings.Phone.subject, message = Strings.Phone.message }
TriggerServerEvent('phone:sendNewMail', data)
elseif Config.Phone == 'lb-phone' then
TriggerServerEvent('lation_laundering:phoneMessage', cache.serverId)
elseif Config.Phone == 'gksphone' then
local number = exports["gksphone"]:PhoneNumber()
TriggerServerEvent('gksphone:gksc:sendMessage', number, Strings.Phone.message)
elseif Config.Phone == 'yseries' then
TriggerServerEvent('lation_laundering:phoneMessage', cache.serverId)
elseif Config.Phone == 'custom' then
-- Configure 'custom' phone system here
end
end
-- Display a progress bar
--- @param data table
function ProgressBar(data)
if Config.Progress == 'lation_ui' then
if exports.lation_ui:progressBar({
label = data.label,
description = data.description or nil,
icon = data.icon or nil,
duration = data.duration,
useWhileDead = data.useWhileDead,
canCancel = data.canCancel,
steps = data.steps or nil,
disable = data.disable,
anim = {
dict = data.anim.dict or nil,
clip = data.anim.clip or nil,
flag = data.anim.flag or nil
},
prop = {
model = data.prop.model or nil,
bone = data.prop.bone or nil,
pos = data.prop.pos or nil,
rot = data.prop.rot or nil
}
}) then
return true
end
return false
elseif Config.Progress == 'ox_lib' then
-- Want to use ox_lib's progress circle instead of bar?
-- Change "progressBar" to "progressCircle" below & done!
if lib.progressBar({
label = data.label,
duration = data.duration,
position = data.position or 'bottom',
useWhileDead = data.useWhileDead,
canCancel = data.canCancel,
disable = data.disable,
anim = {
dict = data.anim.dict or nil,
clip = data.anim.clip or nil,
flag = data.anim.flag or nil
},
prop = {
model = data.prop.model or nil,
bone = data.prop.bone or nil,
pos = data.prop.pos or nil,
rot = data.prop.rot or nil
}
}) then
return true
end
return false
elseif Config.Progress == 'qbcore' then
local p = promise.new()
QBCore.Functions.Progressbar(data.label, data.label, data.duration, data.useWhileDead, data.canCancel, {
disableMovement = data.disable.move,
disableCarMovement = data.disable.car,
disableMouse = false,
disableCombat = data.disable.combat
}, {
animDict = data.anim.dict or nil,
anim = data.anim.clip or nil,
flags = data.anim.flag or nil
}, {
model = data.prop.model or nil,
bone = data.prop.bone or nil,
coords = data.prop.pos or nil,
rotation = data.prop.rot or nil
}, {},
function()
ClearPedTasks(cache.ped)
p:resolve(true)
end,
function()
ClearPedTasks(cache.ped)
p:resolve(false)
end)
return Citizen.Await(p)
else
-- Add 'custom' progress bar here
end
end
-- Function used to display TextUI
--- @param text string
--- @param icon string
ShowTextUI = function(text, icon)
if textui == 'lation_ui' then
local isOpen, _ = exports.lation_ui:isOpen()
if isOpen then return end
exports.lation_ui:showText({
description = text,
icon = icon
})
elseif textui == 'ox_lib' then
local isOpen, _ = lib.isTextUIOpen()
if isOpen then return end
lib.showTextUI(text, {
position = 'left-center',
icon = icon
})
elseif textui == 'jg-textui' then
exports['jg-textui']:DrawText(text)
elseif textui == 'okokTextUI' then
exports['okokTextUI']:Open(text, 'lightblue ', 'left', false)
elseif textui == 'qbcore' then
exports['qb-core']:DrawText(text, 'left')
else
-- Add custom textUI here
end
end
-- Function used to hide/remove TextUI
--- @param label string
HideTextUI = function(label)
if textui == 'lation_ui' then
local isOpen, text = exports.lation_ui:isOpen()
if isOpen and text == label then
exports.lation_ui:hideText()
end
elseif textui == 'ox_lib' then
local isOpen, text = lib.isTextUIOpen()
if isOpen and text == label then
lib.hideTextUI()
end
elseif textui == 'jg-textui' then
exports['jg-textui']:HideText()
elseif textui == 'okokTextUI' then
exports['okokTextUI']:Close()
elseif textui == 'qbcore' then
exports['qb-core']:HideText()
else
-- Add custom textUI here
end
end
-- Function to add circle target zones
--- @param data table
AddCircleZone = function(data)
if Config.Target == 'ox_target' then
exports.ox_target:addSphereZone(data)
elseif Config.Target == 'qb-target' then
exports['qb-target']:AddCircleZone(data.name, data.coords, data.radius, {
name = data.name,
debugPoly = Config.Debug}, {
options = data.options,
distance = 2,
})
elseif Config.Target == 'qtarget' then
exports.qtarget:AddCircleZone(data.name, data.coords, data.radius, {
name = data.name,
debugPoly = Config.Debug}, {
options = {data.options},
distance = 2,
})
elseif Config.Target == 'custom' then
-- Add support for a custom target system here
elseif Config.Target == 'none' then
-- TextUI is being used
else
print('No target system defined in the config file.')
end
end
-- Add target to entity
--- @param entity number Entity number
--- @param data table Options table
AddTargetEntity = function(entity, data)
if Config.Target == 'ox_target' then
exports.ox_target:addLocalEntity(entity, data)
elseif Config.Target == 'qb-target' then
exports['qb-target']:AddTargetEntity(entity, {options = data, distance = 2.0})
elseif Config.Target == 'qtarget' then
exports.qtarget:AddTargetEntity(entity, {options = data, distance = 2.0})
elseif Config.Target == 'custom' then
-- Add support for a custom target system here
else
print('No target system defined in the config file.')
end
end
-- Function to remove circle target zones
--- @param id number | string
RemoveCircleZone = function(id)
if Config.Target == 'ox_target' then
exports.ox_target:removeZone(id)
elseif Config.Target == 'qb-target' then
exports['qb-target']:RemoveZone(id)
elseif Config.Target == 'qtarget' then
exports.qtarget:RemoveZone(id)
elseif Config.Target == 'custom' then
-- Add support for a custom target system here
elseif Config.Target == 'none' then
-- TextUI is being used
else
print('No target system defined in the config file.')
end
end
-- Remove target from entity
--- @param entity number
--- @param data table|string|nil
RemoveTargetEntity = function(entity, data)
if Config.Target == 'ox_target' then
exports.ox_target:removeLocalEntity(entity, data)
elseif Config.Target == 'qb-target' then
exports['qb-target']:RemoveTargetEntity(entity, nil)
elseif Config.Target == 'qtarget' then
exports.qtarget:RemoveTargetEntity(entity, data)
elseif Config.Target == 'custom' then
-- Add support for a custom target system here
else
print('No target system defined in the config file.')
end
end
-- Function that returns true or false if player has item
--- @param item string
--- @param amount number
HasItem = function(item, amount)
if not item then return end
if ox_inv then
local count = exports.ox_inventory:Search('count', item)
if count >= amount then
return true
end
return false
end
if Framework == 'esx' then
if not ESX.GetPlayerData() or not ESX.GetPlayerData().inventory then
return false
end
local inventory = ESX.GetPlayerData().inventory
for _, itemData in pairs(inventory) do
if itemData.name == item then
local count = itemData.count or itemData.amount
if count >= amount then
return true
end
end
end
return false
elseif Framework == 'qb' then
local PlayerData = QBCore.Functions.GetPlayerData()
if not PlayerData or not PlayerData.items then
return false
end
for _, itemData in pairs(PlayerData.items) do
if itemData and itemData.name == item then
local count = itemData.amount or itemData.count
if count >= amount then
return true
end
end
end
return false
else
-- Add support for a custom framework here
end
end
-- Function that returns count of item in inventory
--- @param item string
ItemCount = function(item)
if not item then return end
if ox_inv then
local count = exports.ox_inventory:Search('count', item)
return count or 0
end
if Framework == 'esx' then
if not ESX.GetPlayerData() or not ESX.GetPlayerData().inventory then
return 0
end
local inventory = ESX.GetPlayerData().inventory
for _, itemData in pairs(inventory) do
if itemData.name == item then
local count = itemData.count or itemData.amount
return count or 0
end
end
return 0
elseif Framework == 'qb' then
local PlayerData = QBCore.Functions.GetPlayerData()
if not PlayerData or not PlayerData.items then
return 0
end
for _, itemData in pairs(PlayerData.items) do
if itemData and itemData.name == item then
local count = itemData.amount or itemData.count
return count or 0
end
end
return 0
else
-- Add support for a custom framework here
end
end
-- Function to spawn peds
--- @param model string
--- @param position vector4 | vector3
SpawnPed = function(model, position)
lib.requestModel(model, 1500)
while not HasModelLoaded(model) do Wait(0) end
local ped = CreatePed(0, model, position.x, position.y, position.z - 1.0, position.w, false, true)
FreezeEntityPosition(ped, true)
SetBlockingOfNonTemporaryEvents(ped, true)
SetEntityInvincible(ped, true)
return ped
end
-- Function used to spawn vehicles
--- @param model string
--- @param position vector4 | vector3
SpawnVehicle = function(model, position)
lib.requestModel(model, 1500)
while not HasModelLoaded(model) do Wait(0) end
local vehicle = CreateVehicle(model, position.x, position.y, position.z, position.w, true, true)
return vehicle
end
