This script will add the ability for players to rent and manage their very own stash houses, giving your players the ability to hide their supplies without having to buy another house.
This script is written to work withand
Requirements:andor
Features of Stash Houses:
Unlimited Stash Houses
Stash Houses can be created by either staff only or by set jobs (editable in config)
Stash House Interiors are created automatically using objects
Storable Cash (max amount editable within config)
Cash Objects depending on amount stored for added immersion.
Separate Storage Inventories for each object with a storage inventory.
Ability to furnish the stash house with a list of furniture (editable within config)
Ability for Police to Raid Stash Houses (Jobs editable within config)
Stash Management UI to manage rent and keys
This is compatible with the following inventory systems:
(QBCore)
(QBCore)
(ESX)
(ESX)
Editable functions file which means this can be converted to any framework.
Installation
Download the power_stashhouses from Keymaster
Run the .sql file in your database.
Add the files to your resources folder
Ensure that the resource file will start (either ensure your resource in the server.cfg or inside a folder which is started on server start)
Edit the config file to your needs
Restart your server
Configuration
Select the tab below for your framework to see the configuration options available.
--========================--
--== Framework Settings ==--
--========================--
-- Enable Support for QBCore
enableQBCore = true
QBCoreResourceName = 'qb-core'
-- QBCore will use qb-inventory or lj-inventory by default.
-- This system also supports ox_inventory
QBInventory = 'qb-inventory'
-- Enable QB-Target Support - (False = Using OX_Target, True = Using QB-Target)
enableQBTarget = true
-- Enable Support for ESX
enableESX = false
-- ESX Inventory
-- Compatible with 'ox_inventory' and 'chezza-inventory' and 'mf_inventory'
esxInventory = 'ox_inventory'
-- config to toggleProps for Renewed-Weaponscarry on enter and exit.
renewedWeapons = false
--======================--
--== Command Settings ==--
--======================--
-- The command that is used to create a new stash house.
addStashCommand = 'createstash'
-- This will allow only staff to create a new stash house, if this is disabled then it will use the job whitleist below.
addStashStaffOnly = true
-- The jobs required to use the addStashCommand, if the staff only setting is disabled.
addStashJobs = {
['realestate'] = {2, 3, 4}, -- This will only allow rel estate agents with grade 2, 3 or 4.
['realestateagent'] = {1, 2, 3},
}
-- Max cash that can be stored in a stash house.
maxStoredCash = 500000
In this section, you can edit the language if you need to translate to another language or edit the wording.
Lang = {
['stash_created'] = 'Stash Created',
['stash_rented'] = 'Stash Rented',
['stash_unrented'] = 'Stash Unrented',
['cash_withdrawn'] = 'Cash Withdrawn',
['cash_deposited'] = 'Cash Deposited',
['not_staff'] = 'You are not staff',
['not_job'] = 'You do not have the correct job to use this command',
['not_enough_money'] = 'You do not have enough money',
['max_cash'] = 'Stash is full',
['key_added'] = 'Key Added',
['key_removed'] = 'Key Removed',
['days_added'] = 'Days Added',
['furniture_deleted'] = 'Furniture Deleted',
['furniture_purchased'] = 'Furniture Purchased',
['not_staff'] = 'You are not staff',
['not_job'] = 'You do not have the correct job',
}
You can edit or add your own interiors here. Default settings are as follows:
-- This section can be used to add your own interiors, its important to set the right offsets for the enterance and management and money,
-- Money is the location where the player will go to deposit and withdraw money from the stash house, this will spawn a shelf with the money on it.
availableInteriors = {
['Default Stashhouse'] = {
ipl = 'power_stashhouse_shell',
enteranceOffset = vector3(-8.5, 0.25, -1.0),
managementOffset = vector3(-7.4, -1.8, -0.8),
moneyOffset = vector3(6.0, -3.65, -1.975),
},
}
You can edit the available furniture here, change the price and storage amount per piece, and add or remove furniture options. Default settings are as follows:
-- This section can be used to add your own furniture, you can add as many as you like, the name is the name of the furniture, the model is the model of the furniture, the price is the price of the furniture and the storageSize is the size of the storage that the furniture will have.
availableFurniture = {
{name = "Locker", model = "p_cs_locker_01_s", price = 200, storageSize = 50},
{name = "Locker 2", model = "p_cs_locker_02", price = 250, storageSize = 75},
{name = "Locker 3", model = "p_cs_locker_01", price = 200, storageSize = 50},
{name = "Lester Crate", model = "prop_cs_lester_crate", price = 300, storageSize = 100},
{name = "Crate 1", model = "prop_lev_crate_01", price = 350, storageSize = 150},
{name = "Side Unit", model = "v_res_fh_sidebrdlngb", price = 250, storageSize = 75},
{name = "Side Unit 2", model = "v_res_fh_sidebrddine", price = 200, storageSize = 50},
{name = "Side unit", model = "v_res_d_sideunit", price = 200, storageSize = 50},
{name = "Bed table", model = "v_res_mbbedtable", price = 200, storageSize = 50},
{name = "TV stand", model = "v_res_j_tvstand", price = 200, storageSize = 50},
{name = "Dresser", model = "v_res_mbdresser", price = 200, storageSize = 50},
{name = "Bottoman", model = "v_res_mbottoman", price = 200, storageSize = 50},
{name = "Console", model = "v_res_mconsolemod", price = 200, storageSize = 50},
{name = "Cupboard", model = "v_res_mcupboard", price = 200, storageSize = 50},
{name = "Chest", model = "v_res_mdchest", price = 200, storageSize = 50},
{name = "Cabinet 3", model = "v_res_msoncabinet", price = 200, storageSize = 50},
{name = "Cabinet 4", model = "prop_cabinet_02b", price = 200, storageSize = 50},
{name = "Cabinet 5", model = "prop_cabinet_01b", price = 200, storageSize = 50},
{name = "Sidetable", model = "v_res_m_sidetable", price = 200, storageSize = 50},
{name = "Bedsidetable", model = "v_res_tre_bedsidetable", price = 200, storageSize = 50},
{name = "Bookshelf", model = "v_res_tre_smallbookshelf", price = 200, storageSize = 50},
{name = "Storage box", model = "v_res_tre_storagebox", price = 200, storageSize = 250},
{name = "Storage unit", model = "v_res_tre_storageunit", price = 200, storageSize = 50},
{name = "Sidetable", model = "v_res_m_sidetable", price = 200, storageSize = 50},
{name = "Woodtable", model = "v_res_tre_wdunitscuz", price = 200, storageSize = 50},
{name = "Devin Box", model = "prop_devin_box_closed", price = 200, storageSize = 50},
{name = "Crate 3", model = "prop_mil_crate_01", price = 200, storageSize = 50},
{name = "Crate 4", model = "prop_mil_crate_02", price = 200, storageSize = 50},
{name = "Safe 1", model = "prop_ld_int_safe_01", price = 200, storageSize = 50},
{name = "Safe 2", model = "p_v_43_safe_s", price = 200, storageSize = 50},
{name = "Safe 3", model = "prop_ld_int_safe_01", price = 200, storageSize = 50},
{name = "Woodtable", model = "prop_mil_crate_02", price = 200, storageSize = 50},
{name = "Dressing table", model = "v_res_d_dressingtable", price = 200, storageSize = 50},
{name = "Cabinet", model = "prop_fbibombfile", price = 200, storageSize = 50},
{name = "Cabinet 2", model = "v_res_cabinet", price = 200, storageSize = 50},
{name = "Weapon Box", model = "p_secret_weapon_02", price = 200, storageSize = 50},
{name = "Gun Case", model = "prop_gun_case_02", price = 200, storageSize = 50},
{name = "Side Table 2", model = "v_res_mdbedtable", price = 200, storageSize = 50},
{name = "Used Bedside Table", model = "v_res_tre_bedsidetableb", price = 200, storageSize = 50},
{name = "Tool Chest", model = "ex_prop_ex_toolchest_01", price = 200, storageSize = 50},
{name = "Bedside Table 2", model = "mp_b_bed_table_dble_04", price = 200, storageSize = 50},
{name = "Office Shelf Grey", model = "v_corp_offshelf", price = 200, storageSize = 50},
{name = "Office Shelf Black", model = "v_corp_offshelfdark", price = 200, storageSize = 50},
{name = "Hanging Clothes", model = "ex_office_01c_dressing02", price = 200, storageSize = 50},
{name = "Wooden Box", model = "v_res_m_spanishbox", price = 200, storageSize = 50},
{name = "Shelf 1", model = "apa_mp_h_str_shelffloorm_02", price = 200, storageSize = 50},
{name = "Shelf 2", model = "apa_mp_h_str_shelffreel_01", price = 200, storageSize = 50},
{name = "Shelf 3", model = "apa_mp_h_str_shelfwallm_01", price = 200, storageSize = 50},
{name = "Shelf 4", model = "hei_int_heist_bed_unit", price = 200, storageSize = 50},
{name = "Console 9", model = "hei_int_heist_fh_sidebrdlngb", price = 200, storageSize = 50},
{name = "Coffin", model = "prop_coffin_02b", price = 200, storageSize = 50},
{name = "Bin 1", model = "prop_cs_bin_02", price = 200, storageSize = 50},
{name = "Bin 2", model = "prop_cs_bin_03", price = 200, storageSize = 50},
{name = "Bin 3", model = "prop_fbibombbin", price = 200, storageSize = 50},
{name = "Bin 4", model = "prop_rub_binbag_sd_01", price = 200, storageSize = 50},
{name = "Bin 5", model = "prop_rub_binbag_sd_01", price = 200, storageSize = 50},
{name = "Bin 6", model = "prop_bin_04a", price = 200, storageSize = 50},
{name = "Bin 7", model = "prop_bin_07a", price = 200, storageSize = 50},
{name = "Bin 8", model = "prop_bin_06a", price = 200, storageSize = 50},
{name = "Bin 9", model = "prop_bin_10b", price = 200, storageSize = 50},
{name = "Bin 10", model = "prop_bin_11b", price = 200, storageSize = 50},
{name = "Bin 11", model = "prop_bin_11a", price = 200, storageSize = 50},
{name = "Large bin", model = "prop_bin_13a", price = 200, storageSize = 50},
{name = "Bin bag", model = "prop_rub_binbag_sd_01", price = 200, storageSize = 50},
{name = "Sofa", model = "prop_t_sofa_02", price = 200},
{name = "Sofa 2", model = "prop_t_sofa", price = 200},
{name = "Sofa 3", model = "p_lev_sofa_s", price = 200},
{name = "Sofa 4", model = "p_res_sofa_l_s", price = 200},
{name = "Sofa 5", model = "p_v_med_p_sofa_s", price = 200},
{name = "Sofa 6", model = "p_yacht_sofa_01_s", price = 200},
{name = "Sofa 7", model = "v_ilev_m_sofa", price = 200},
}
Editable files
functions.lua
Inventory Compatibility
If you would like to edit the inventory functions, you can edit them in the functions.lua file. Default functions are as follows:
function openStorage(stashId, storageAmount)
if enableQBCore then
if QBInventory == 'ox_inventory' then
exports.ox_inventory:openInventory('stash', {id = stashId, owner = false})
else
TriggerServerEvent("inventory:server:OpenInventory", "stash", stashId, {maxweight = storageAmount})
TriggerEvent("inventory:client:SetCurrentStash", stashId)
end
end
if enableESX then
if esxInventory == 'mf-inventory' then
exports["mf-inventory"]:openOtherInventory(stashId)
end
if esxInventory == 'ox_inventory' then
exports.ox_inventory:openInventory('stash', {id = stashId, owner = false})
end
if esxInventory == 'chezza-inventory' then
TriggerEvent('inventory:openStorage', "Stash", stashId, storageAmount, 1000)
end
if esxInventory == 'quasar-inventory' then
local other = {}
other.maxweight = storageAmount
other.slots = 50
TriggerServerEvent("inventory:server:OpenInventory", "stash", stashId, other)
TriggerEvent("inventory:client:SetCurrentStash", stashId)
end
end
-- This is an example for if you would like to use your own framework
TriggerServerEvent('inventory:getStorageInventory', stashId, storageAmount)
end
Pulling character information
If you would like to edit how character information is pulled, you can edit them in the functions.lua file. Default functions are as follows:
function getCharacterId()
if enableQBCore then
local QBCore = exports['qb-core']:GetCoreObject()
return QBCore.Functions.GetPlayerData().citizenid
end
if enableESX then
local ESX = exports['es_extended']:getSharedObject()
local player = ESX.GetPlayerData()
return player.identifier
end
-- This is an example for if you would like to use your own framework
return LocalPlayer.state.characterId
end
Checking Police Job
If you would like to edit the check for police jobs functions, you can edit them in the functions.lua file. Default functions are as follows:
function isPolice()
if enableQBCore then
local QBCore = exports['qb-core']:GetCoreObject()
return QBCore.Functions.GetPlayerData().job.name == 'police'
end
if enableESX then
local ESX = exports['es_extended']:getSharedObject()
return ESX.PlayerData.job.name == 'police'
end
-- This is an example for if you would like to use your own framework
return LocalPlayer.state.jobId == 1
end
Custom Notifications
If you would like to edit the notifications to add your own custom notifications or to match them to your other server notifications, you can edit them in the functions.lua file. Default notifications are as follows:
If you need to change how player data is called, you can change this in the server_functions.lua. Default functions are as follows:
function getCharacterId(source)
if enableQBCore then
local QBCore = exports['qb-core']:GetCoreObject()
local Player = QBCore.Functions.GetPlayer(source)
return Player.PlayerData.citizenid
end
if enableESX then
local ESX = exports['es_extended']:getSharedObject()
local player = ESX.GetPlayerData(source)
return player.identifier
end
-- This is an example for if you would like to use your own framework
return Player(source).state.characterId
end
Money Functions
If you need to change how money functions are handled, you can change this in the server_functions.lua. Default functions are as follows:
function getMoney(source)
if enableQBCore then
local QBCore = exports['qb-core']:GetCoreObject()
local Player = QBCore.Functions.GetPlayer(source)
return Player.PlayerData.money['cash']
end
if enableESX then
local ESX = exports['es_extended']:getSharedObject()
local player = ESX.GetPlayerData(source)
return player.getMoney()
end
-- This is an example for if you would like to use your own framework
local source = tonumber(source)
local user = exports['dsrp_core']:getCharacterFromId(source)
return user.getMoney()
end
function removeMoney(source, amount)
if enableQBCore then
local QBCore = exports['qb-core']:GetCoreObject()
local Player = QBCore.Functions.GetPlayer(source)
Player.Functions.RemoveMoney('cash', amount)
return true
end
if enableESX then
local ESX = exports['es_extended']:getSharedObject()
local player = ESX.GetPlayerData(source)
player.removeMoney(amount)
return true
end
-- This is an example for if you would like to use your own framework
local source = tonumber(source)
local user = exports['dsrp_core']:getCharacterFromId(source)
user.removeMoney(amount)
return true
end
function addMoney(source, amount)
if enableQBCore then
local QBCore = exports['qb-core']:GetCoreObject()
local Player = QBCore.Functions.GetPlayer(source)
Player.Functions.AddMoney('cash', amount)
return true
end
if enableESX then
local ESX = exports['es_extended']:getSharedObject()
local player = ESX.GetPlayerData(source)
player.addMoney(amount)
return true
end
-- This is an example for if you would like to use your own framework
local source = tonumber(source)
local user = exports['dsrp_core']:getCharacterFromId(source)
user.addMoney(amount)
return true
end
Staff Checks
If you need to change how player staff permissions are handled, you can change this in the server_functions.lua. Default functions are as follows:
function isStaff(source)
if enableQBCore then
local QBCore = exports['qb-core']:GetCoreObject()
local Player = QBCore.Functions.GetPlayer(source)
if QBCore.Functions.HasPermission(source, 'admin') or IsPlayerAceAllowed(source, 'command') then
return true
end
end
if enableESX then
local ESX = exports['es_extended']:getSharedObject()
local player = ESX.GetPlayerData(source)
if player.getGroup() == 'admin' or player.getGroup() == 'superadmin' then
return true
end
end
-- This is an example for if you would like to use your own framework
return false
end
Job Checks
If you need to change how character job permissions are handled, you can change this in the server_functions.lua. Default functions are as follows:
function hasJob(source, jobs)
if enableQBCore then
local QBCore = exports['qb-core']:GetCoreObject()
local Player = QBCore.Functions.GetPlayer(source)
local job = Player.PlayerData.job.name
if jobs[job] then
return true
end
return false
end
if enableESX then
local ESX = exports['es_extended']:getSharedObject()
local player = ESX.GetPlayerData(source)
local job = player.job.name
if jobs[job] then
return true
end
return false
end
-- This is an example for if you would like to use your own framework
return false
end
HTML
HTML files can be edited as needed for additional language support or styling edits.
Additional language edits can be applied in index.html
Look for the following terms that can be translated: