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

  1. Run the SQL migration:
    sql/001_owned_module.sql
  2. 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
  3. (Optional) Copy config/custom.example.lua to config/custom.lua and edit overrides.
  4. Restart the server.

Ownership Modes

ModeDescription
publicDefault NPC store. No ownership. Existing behavior.
claim_holdFree claim. Player holds the store. No rent, no passive profit. Must stay active or reclaim.
business_ownerPlayer buys the store. Can stock, set prices, earn from sales. Optional tax/rent.
faction_ownedJob/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.

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

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

  1. Run sql/001_owned_module.sql
  2. Replace resource files
  3. Existing shops.lua still works — shops without owned remain public
  4. Add oxmysql to server.cfg
  5. Create config/custom.lua if you want to customize owned module
Robbery: Use with prp-storerobberyGetShops() 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).