qb-houserobbery
qb-houserobbery lets players lockpick a set of scripted houses, enter an interior shell, and search
furniture for items. It is an item source, not a money source. No cash or bank balance is granted at
any point.
Unlike qb-houses, it does not own property, ownership, or keys. The houses here are fixed robbery targets defined in its own config.
The manifest at the commit linked above declares version 1.5.0.
Dependencies and start order
The manifest declares dependencies { 'qb-minigames' } and loads @qb-core/shared/locale.lua.
Reading the implementation adds two more hard runtime dependencies that the manifest does not
declare:
| Resource | Used for | Declared in manifest |
|---|---|---|
qb-core | Core object, shared items, Lang:t | no, loaded via the locale shim |
| qb-minigames | Skillbar on the lockpick and on furniture | yes |
| qb-interior | CreateHouseRobbery and DespawnInterior | no |
| qb-inventory | AddItem, RemoveItem, item box | no |
Start order: qb-core, qb-inventory, qb-minigames, qb-interior, then qb-houserobbery.
qb-interior in particular is easy to miss. Without it, exports['qb-interior']:CreateHouseRobbery
fails and the player never gets inside.
Configuration
config.lua is a shared script.
| Key | Default | Meaning |
|---|---|---|
Config.PoliceOnDutyRequired | 0 | On-duty police required before a house can be robbed |
Config.LimitTime | true | Restrict robberies to an in-game clock window |
Config.MinimumTime | 6 | Window start hour, only used when LimitTime is true |
Config.MaximumTime | 22 | Window end hour |
Config.TimeToCloseDoors | 25 | Minutes after the first entry before the house resets |
Config.RequireScrewdriver | true | Require a screwdriver when not using an advanced lockpick |
Config.ChanceToBreakLockPick | 30 | Percent chance a normal lockpick breaks on failure |
Config.ChanceToBreakAdvancedLockPick | 15 | Same for the advanced lockpick |
Config.ChanceToAlertPolice | 20 | Percent chance the police are alerted during a robbery |
Config.MinZOffset | 45 | Also used as the server-side proximity radius, see below |
Config.Rewards | table | Tier to furniture type to item pool |
Config.Houses | table | House key to coords, tier, and furniture list |
Config.PoliceOnDutyRequired ships as 0. Raise it before going live.
Reward tiers
Config.Rewards is indexed by house tier, then by furniture type. At this commit only tier 1
exists, with the furniture types cabin, kitchen, chest, and livingroom. Each entry is
{ item, min, max }.
Searching one piece of furniture rolls math.random(0, 3) items, so an empty result is a normal
outcome and produces a notification rather than a reward. For each item drawn, if the shared item is
unique the amount is forced to 1, otherwise a random amount between min and max is granted.
Every item name in the reward pools must exist in your shared items list, and the server indexes
sharedItems[selectedItem.item].unique without a nil check, so a missing item name raises a Lua
error instead of failing quietly.
Server surface
| Handler | Kind | Arguments |
|---|---|---|
qb-houserobbery:server:GetHouseConfig | callback | none, returns Config.Houses |
qb-houserobbery:server:enterHouse | net event | house |
qb-houserobbery:server:searchFurniture | net event | cabin, house |
qb-houserobbery:server:SetBusyState | net event | cabin, house, bool |
qb-houserobbery:server:removeAdvancedLockpick | net event | none |
qb-houserobbery:server:removeLockpick | net event | none |
searchFurniture is the one that grants items, and at this commit it checks, in order:
- The house and the furniture index exist in
Config.Houses. - The house is currently
opened, so the player entered through the normal flow. - That furniture piece has not already been
searched. - The player’s server-side coordinates are within
Config.MinZOffsetof the house coordinates.
Note that step 4 reuses Config.MinZOffset, whose name and default of 45 suggest a vertical
offset rather than a proximity radius. It works as a coarse guard, but 45 units is wide. If you
tighten it for proximity reasons, re-test entering the shell, because the shell object sits at an
offset from the house coordinate.
SetBusyState performs no validation and indexes Config.Houses[house]['furniture'][cabin]
directly, so an unexpected argument raises a server-side Lua error.
Interaction with qb-interior
The client calls exports['qb-interior']:CreateHouseRobbery(coords) to spawn the shell, keeps the
returned handle array, and calls exports['qb-interior']:DespawnInterior(houseObj, cb) on exit. If
you replace qb-interior with another shell system, those are the two call sites to change. See
qb-interior for what those exports return.
Troubleshooting
| Symptom | Likely cause |
|---|---|
| Lockpick minigame never appears | qb-minigames is not started. It is the one declared dependency |
| Player picks the lock but never enters | qb-interior is not started, or CreateHouseRobbery requested a model your build does not stream |
| Server Lua error on searching furniture | A reward item name is missing from your shared items, so sharedItems[name].unique indexes nil |
| Nothing is ever found | math.random(0, 3) returned zero. Search other furniture before assuming a fault |
| Robberies refused at all hours | Config.LimitTime is true and your in-game clock is outside MinimumTime to MaximumTime |
| House never resets | The reset thread runs Config.TimeToCloseDoors minutes after the first entry. A resource restart resets state to the file defaults instead |
| Robbery starts with no police online | Config.PoliceOnDutyRequired still ships as 0 |
Proposed manual smoke test
Not yet executed. On staging:
- Confirm every item in
Config.Rewardsexists in your shared items before first run. - Lockpick one house, confirm the shell spawns and the exit works.
- Search each furniture type and confirm items and the empty-result notification.
- Confirm a searched piece cannot be searched twice.
- Wait out
Config.TimeToCloseDoorsand confirm the house and its furniture reset.