# Player Owned Offices

## Introduction

This script adds the ability for your players to purchase their very own office

{% hint style="danger" %}
**This script is written to work with** [**QBCore**](https://qbcore-framework.github.io/qb-docs/) **and** [**ESX Legacy**](https://github.com/zaphosting/esx_12)

**This resource requires** [**ox\_lib**](https://github.com/overextended/ox_lib)
{% endhint %}

#### Features of Player-Owned Offices:

* Ability to Change The Name of the Office.
* Ability to Change The Name Color.
* Ability to Change the Style of the Office. (Configurable to change cost)
* Ability to Add and Remove Props within the Office
* Ability to Deposit and Withdraw money into an Office Bank.
* Money Stacks will be displayed within the office depending on how much is stored within the office.
* Ability to Add and Manage Staff that can also manage the office
* Ability to Transfer the Office to Other Players (Configurable to disable)
* Ability for Office Staff to Lock the Office - Preventing anyone from entering until unlocked.
* Ability for Police Jobs to Access Storage Safes (Configurable Item Requirement too)
* 4 Separate Office Locations (Arcadius Business Centre, Lom Bank, Maze Bank Building, Maze Bank West)
* Each Office Location supports unlimited offices, each office location has a separate list.
* Each Office has access to the rooftop helipad (Good when you add a helicopter garage location to the rooftops)
* Each Office has the ability for the staff to access the outfit menus to change outfits
* Each Office is equipped with 2 separate storage safes (safes will physically open for the player to add to immersion)

{% hint style="info" %}
**This is compatible with the following inventory systems:**

* [qb-inventory](https://github.com/qbcore-framework/qb-inventory/)
* [lj-inventory](https://github.com/loljoshie/lj-inventory)
* [ox\_inventory](https://github.com/overextended/ox_inventory)
* [chezza-inventory](https://forum.cfx.re/t/paid-release-chezzas-inventory-esx/2040417)
  {% endhint %}

{% hint style="info" %}
**This is compatible with the following clothing systems:**

* [rcore\_clothes](https://store.rcore.cz/package/4337820)
* [illenium\_appearance](https://github.com/iLLeniumStudios/illenium-appearance)
* [qb-clothing](https://github.com/qbcore-framework/qb-clothing)
  {% endhint %}

***

## Installation

* Download the power\_offices 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.

{% tabs %}
{% tab title="Basic configuration options" %}

```lua
-- QBCore Support 
enableQBCore = true

-- ESX Support
enableESX = false

-- Resource Used for Inventories
-- Supported Resources: ox_inventory, qb-inventory, qs-inventory, chezza-inventory
inventoryResource = 'qb-inventory'

-- Max storage amount of each stash in the offices
storageAmount = 1000000

-- Max slots of each stash in the offices
storageSlots = 100 

-- Resource Used for Clothing
-- Supported Resources: rcore_clothes, illenium_appearance, qb-clothing
clothingResource = 'illenium_appearance'

-- Office Transfer  
-- This allows you to allow players to transfer their office to another player
enableOfficeTransfers = true

-- config to toggleProps for Renewed-Weaponscarry on enter and exit.
renewedWeapons = true

-- Police Raid Settings
-- This allows you to enable/disable police raids on offices
enablePoliceRaids = true

-- Police Raid Job
-- This allows you to set the jobs that is allowed to start a police raid
policeRaidJobs = {'police'}

-- Police Raid Item 
-- This allows you to set the item that is required to start a police raid
-- This item must already exist in your server
-- Set to false to disable item requirement
policeRaidItem = 'police_stormram'
```

{% endtab %}

{% tab title="Economy and Locations" %}
{% hint style="danger" %}
Be sure to adjust this section to fit in with your server's economy. You can also select which locations are active and rename the blips.
{% endhint %}

```lua
-- This is the amount of money that needs to be stored in a player office before it shows the desired cash stack
-- These can be edited to your economy values.
cashStacks = {
 [1] = 50000, -- if less than 50k is stored in office bank then this cash stack will be shown
 [2] = 100000, -- if more than 50k but less than 100k is stored then this cash stack is shown, etc, etc 
 [3] = 150000, 
 [4] = 200000,
 [5] = 250000,
 [6] = 500000,
 [7] = 750000,
 [8] = 1000000,
 [9] = 1500000,
 [10] = 2000000,
 [11] = 2500000,
 [12] = 3000000,
 [13] = 3500000,
 [14] = 4000000,
 [15] = 4500000,
 [16] = 5000000,
 [17] = 7500000,
 [18] = 10000000,
 [19] = 12500000,
 [20] = 15000000,
 [21] = 2000000,
 [22] = 25000000,
 [23] = 50000000,
 [24] = 100000000,
}

-- This allows you to set the cost of each office style
-- These can be edited to your economy values.
-- These are currently free.
officeStyleCosts = {
 ['Warm'] = 250000, 
 ['Classical'] = 250000,
 ['Vintage'] = 250000,
 ['Contrast'] = 250000,
 ['Rich'] = 250000,
 ['Cool'] = 250000,
 ['Ice'] = 250000,
 ['Conservative'] = 250000,
 ['Polished'] = 250000,
}

-- This allows you to set the cost of an office in each building
-- These can be edited to your economy values.
officePrices = { 
 [1] = 500000, -- Arcadius Business Centre
 [2] = 500000, -- Lom Bank
 [3] = 750000, -- Maze Bank Building
 [4] = 1000000, -- Maze Bank West
}

enabledOffices = {
 [1] = true, -- Arcadius Business Centre
 [2] = true, -- Lom Bank
 [3] = true, -- Maze Bank Building
 [4] = true, -- Maze Bank West
}

officeBlipNames = {
 [1] = 'Arcadius Business Centre',
 [2] = 'Lom Bank',
 [3] = 'Maze Bank Building',
 [4] = 'Maze Bank West',
}
```

{% hint style="warning" %}
**Logs**

You can hook into the following events to log to your own logging system / discord

These are server events and must be registered as such

`'offices:purchaseLog' - Sends source, office id and price`

`'offices:transferLog' - Sends source, target and office id`
{% endhint %}
{% endtab %}

{% tab title="Language" %}
In this section, you can edit the language if you need to translate to another language or edit the wording.

```lua
-- Language Settings
-- This allows you to change the language of aspects of the script
Lang = {
 ['Offices'] = 'Offices',

 -- Office Styles = Change This to your language
 ['Warm'] = 'Warm',
 ['Classical'] = 'Classical',
 ['Vintage'] = 'Vintage',
 ['Contrast'] = 'Contrast',
 ['Rich'] = 'Rich',
 ['Cool'] = 'Cool',
 ['Ice'] = 'Ice',
 ['Conservative'] = 'Conservative',
 ['Polished'] = 'Polished',
 -- Office Props 
 ['Booze and Cigarettes'] = 'Booze and Cigarettes',
 ['Counterfeit'] = 'Counterfeit',
 ['Drug Bags'] = 'Drug Bags',
 ['Drug Statues'] = 'Drug Statues',
 ['Electronics'] = 'Electronics',
 ['Fur Coats'] = 'Fur Coats',
 ['Gems'] = 'Gems',
 ['Guns'] = 'Guns',
 ['Ivory'] = 'Ivory',
 ['Jewels'] = 'Jewels',
 ['Meds'] = 'Meds',
 ['Painting'] = 'Painting',
 ['Pills'] = 'Pills',
 ['Silver'] = 'Silver',

 -- Menu Options
 ['Office Bank'] = 'Office Bank - $',
 ['Give Keys'] = 'Give Keys',
 ['Manage Keys'] = 'Manage Keys',
 ['Change Office Name'] = 'Change Office Name',
 ['Change Name Color'] = 'Change Name Color',
 ['Change Style'] = 'Change Style',
 ['Change Props'] = 'Change Props',

 ['Office Bank Description'] = 'Deposit or Withdraw money from your office bank',
 ['Give Keys Description'] = 'Give your office keys to another player',
 ['Manage Keys Description'] = 'Manage who has keys to your office',
 ['Toggle Office Locks'] = 'Toggle Office Locks',
 ['Toggle Office Locks Description'] = 'Toggle the locks on your office',
 ['Change Office Name Description'] = 'Change the name of your office',
 ['Change Name Color Description'] = 'Change the color of your office name',
 ['Update Style Description'] = 'Update the style of your office',
 ['Change Props Description'] = 'Change the props in your office',
 ['Change Style Description'] = 'Change the style of your office to %s for $%s',
 ['Transfer Office'] = 'Transfer Office',
 ['Transfer Office Description'] = 'Transfer your office to another player',

 ['Withdraw'] = 'Withdraw',
 ['Deposit'] = 'Deposit',

 ['Withdraw Description'] = 'Withdraw money from your office bank account',
 ['Deposit Description'] = 'Deposit money into your office bank account',
 ['Purchase'] = 'Purchase Office ($%s)',
 ['Purchase Description'] = "Purchase an office for $",

 ['Enter Office Description'] = 'Enter this office',

 -- Prompts
 ['Exit Office'] = 'Exit Office | E - Access Rooftop | H',
 ['Enter Office'] = 'Offices | E',
 ['Office Management'] = 'Office Management | E',
 ['Clothing'] = 'Clothing | E',
 ['Storage'] = 'Storage | E',

 -- Notifications 
 ['Office Purchased'] = 'You have purchased this office',
 ['Purchase Error'] = 'You do not have enough money to purchase this office/style',
 ['Office Locked'] = 'This office is currently locked, please come back later.',
 ['Office Locked But Staff'] = 'Reminder: This office is locked, but you are office staff.',
}
```

{% endtab %}
{% endtabs %}

***

## 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:

```lua
function accessStorageInventory(storageId)
 if enableQBCore then 
  local other = {
   maxweight = storageAmount,
   slots = storageSlots,
  }
  TriggerServerEvent("inventory:server:OpenInventory", "stash", 'p_offices_'..storageId, other)
  TriggerEvent("inventory:client:SetCurrentStash", 'p_offices_'..storageId)
 end 


 if enableESX then 
  if inventoryResource == 'ox_inventory' then 
   exports.ox_inventory:openInventory('stash', {id = 'p_offices_'..storageId, slots = tonumber(storageSlots), weight = tonumber(storageAmount)})
  end 

  if inventoryResource == 'mf-inventory' then 
   exports["mf-inventory"]:openOtherInventory('p_offices_'..storageId)
  end 

  if inventoryResource == 'chezza-inventory' then 
   TriggerEvent('inventory:openInventory', {type = "stash", id = 'p_offices_'..storageId, title = "Storage Locker", weight = tonumber(storageAmount), delay = 0, save = true})
  end 

  if inventoryResource == 'quasar-inventory' then 
   local other = {}
   other.maxweight = tonumber(storageAmount)
   other.slots = tonumber(storageSlots) 
   TriggerServerEvent("inventory:server:OpenInventory", "stash", 'p_offices_'..storageId, other)
   TriggerEvent("inventory:client:SetCurrentStash", 'p_offices_'..storageId)
  end 
 end 
end 
```

#### Clothing compatibility

If you would like to edit the clothing functions, you can edit them in the functions.lua file. Default functions are as follows:

```lua
function openClothingOutfits()
 if clothingResource == 'rcore_clothes' then
  TriggerEvent("rcore_clothes:openOutfits") 
 end

 if clothingResource == 'illenium_appearance' then
  TriggerEvent('illenium-appearance:client:openOutfitMenu')
 end

 if clothingResource == 'qb-clothing' then
  TriggerEvent('qb-clothing:client:openOutfitMenu')
 end
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:

```lua
RegisterNetEvent('offices:notification')
AddEventHandler('offices:notification', function(data)
 local timeout = 5000

 if data.timeout == nil then
  timeout = 5000
 else 
  timeout = data.timeout
 end

 lib.notify({title = data.title, description = data.text, type = data.type, position = 'top-right', duration = timeout})
end)
```

***


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.power-scripts.com/offices.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
