prp-shops
Player-Owned Shops v2.0 — configuration-first shop system with claim, buy, or faction ownership. GetShops() for prp-storerobbery.
Demo video coming soon (v2.0)
Highlights
Player-Owned Shops — Shops can be public (NPC), claim_hold (free claim, no rent), business_owner (buy and run), or faction_owned (job/gang).
Owner Panel — Manage stock, set prices, view finance, open stash. Employee roles: owner, manager, stocker, cashier with granular permissions.
Config & Go — Define shops in shops.lua; add owned = { shopId, mode, ... } for ownable shops. Override behavior in config/custom.lua (do not edit config/default.lua).
Inactivity Reclaim — Configurable days, warn days, and reclaim behavior (reset owner, keep/clear stock, liquidate).
Pricing Presets — standard, strict, loose (min/max multipliers). Optional demand tracking.
Bridges — Dispatch (ps, qs, cd, core), phone (gksphone, qb-phone, etc.), camera (rcore), notify, target. Auto-detect.
Robbery Ready — Exposes GetShops() for prp-storerobbery. Optional built-in robbery module (configurable).
Installation
- Run the SQL migration:
sql/001_owned_module.sql - Ensure dependencies in
server.cfg(order matters):ensure ox_lib ensure oxmysql ensure ox_inventory ensure ox_target ensure qbx_core # or qb-core / es_extended ensure prp-shops - (Optional) Copy
config/custom.example.luatoconfig/custom.luaand edit overrides. - Restart the server.
Ownership Modes
| Mode | Description |
|---|---|
public | Default NPC store. No ownership. Existing behavior. |
claim_hold | Free claim. Player holds the store. No rent, no passive profit. Must stay active or reclaim. |
business_owner | Player buys the store. Can stock, set prices, earn from sales. Optional tax/rent. |
faction_owned | Job/gang/org owns the store. Controlled by ranks and permissions. |
Adding Shops (including owned)
In shops.lua, add an entry to the Shops table. For ownable shops, add the owned field:
Shops["My Store"] = {
pedModel = "mp_m_shopkeep_01",
blipname = "My Store",
blipsprite = 52,
image = "img/mystore.png",
owned = {
shopId = "my_store_1", -- Unique ID (used in DB)
mode = "business_owner", -- public | claim_hold | business_owner | faction_owned
buyPrice = 50000, -- (business_owner)
factions = { "police" }, -- (faction_owned)
},
locations = { vector4(...) },
items = { ... },
}
Important: shopId must be unique across all shops.
Configuration
Main config: config.lua — Framework, Target, Inventory, PayMethod, InteractionDistance.
Owned module: Edit config/custom.lua only. Defaults live in config/default.lua (do not edit).
Owned Module (config/custom.lua)
Config.OwnedConfig = {
Owned = {
enabled = true,
modes = { public = true, claim_hold = true, business_owner = true, faction_owned = true },
defaultMode = 'public',
perShopOverrides = {},
claimHold = { maxShopsPerPlayer = 3 },
businessOwner = { maxShopsPerPlayer = 2, taxRate = 0.05 },
factionOwned = { taxRate = 0.03 },
unownedFallbackToPublic = true,
},
}
Inactivity Reclaim
Config.OwnedConfig.Inactivity = {
enabled = true,
defaultDays = 7,
warnDays = { 3, 1 },
checkIntervalMinutes = 30,
reclaimBehavior = 'reset_owner_keep_stock', -- or reset_owner_clear_stock, reset_owner_liquidate_to_bank
}
Pricing Presets
Config.OwnedConfig.Pricing = {
enabled = true,
defaultPreset = 'standard',
presets = {
standard = { minMult = 0.7, maxMult = 1.5 },
strict = { minMult = 0.9, maxMult = 1.2 },
loose = { minMult = 0.5, maxMult = 2.0 },
},
}
Admin Commands
Require prp-shops.admin or admin group.
/shopadmin create <shopId> <mode>— Create shop record in DB/shopadmin setmode <shopId> <mode>— Change ownership mode/shopadmin setowner <shopId> <identifier> [type]— Set owner manually/shopadmin clearowner <shopId>— Remove current owner/shopadmin reclaimnow <shopId>— Force reclaim immediately/shopadmin audit <shopId> [limit]— View transaction log/shopadmin info <shopId>— View shop details/shopadmin teleport <shopId>— Teleport to shop
API Exports (server)
exports['prp-shops']:GetShops() -- Returns shop data from shops.lua
exports['prp-shops']:GetShop(shopId) -- Returns owned shop data
exports['prp-shops']:SetOwner(shopId, { ownerType, ownerId, mode })
exports['prp-shops']:ClearOwner(shopId)
exports['prp-shops']:OpenShop(playerId, shopId)
exports['prp-shops']:OpenOwnerPanel(playerId, shopId)
Server Events
-- Purchase completed at owned shop
AddEventHandler('prp-shops:server:purchaseCompleted', function(shopId, playerId, items, total, paymentType) end)
-- Shop claimed or purchased
AddEventHandler('prp-shops:server:shopClaimed', function(shopId, ownerId) end)
-- Shop reclaimed (inactivity or admin)
AddEventHandler('prp-shops:server:shopReclaimed', function(shopId, previousOwnerId, reason) end)
Database Tables
prp_shops_owned— Shop ownership recordsprp_shops_employees— Employee roles per shopprp_shops_finance— Safe balance, lifetime statsprp_shops_transactions— Audit log (sales, withdrawals, etc.)prp_shops_prices— Custom owner-set prices per item
Included Presets (shops.lua)
Pre-configured chains: 24/7 Market, LTD Gasoline, Rob's Liquor, Rusty Browns, Digital Den, Mega Mall, You Tool, Mechanic Parts, and more. Shops without owned remain public.
Migration from v1.x
- Run
sql/001_owned_module.sql - Replace resource files
- Existing
shops.luastill works — shops withoutownedremain public - Add
oxmysqlto server.cfg - Create
config/custom.luaif you want to customize owned module
GetShops() provides locations. prp-storerobbery can also run without prp-shops using fallback from robberylocations.lua. Optional built-in robbery in prp-shops (Config.OwnedConfig.Robbery).