# T1GER Scripts Documentation

Learn more about T1GER scripts, follow installation guides or troubleshoot a script.

<figure><img src="https://2167335559-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MiDWIMbFBeXle-trOlk%2Fuploads%2FjkPRV69YtGVU0uiOMMoD%2Fdiscord_channel_title.png?alt=media&amp;token=6c550568-78c4-49df-89e5-071856b6e25c" alt=""><figcaption></figcaption></figure>

## ABOUT US

We provide an extensive array of premium-quality resources for FiveM, catering to both legal and illicit requirements. We are committed to developing unique assets that elevate the role-playing experience in a truly immersive way.

[**Store**](https://t1ger.net/) | [**Discord**](https://discord.gg/t1ger) | [**YouTube**](https://www.youtube.com/@T1GER) | [**CFX Forum**](https://forum.cfx.re/u/T1GER_Scripts/)

We are proud to say that we have established a well-known name and a positive reputation within the FiveM Community. We have existed for a few years now and have 8.000+ members and thousands of satisfied customers with hundreds of positive reviews.&#x20;

## TERMS OF SERVICE

{% hint style="danger" %}
**Read very carefully. Do not promote or engage in unauthorized use/distribution. We have a zero-tolerance on this.**
{% endhint %}

Unauthorized use or distribution ("leaking") of T1GER Scripts, paid and free scripts, is strictly prohibited.

**If you or your server is engaging in unauthorized use or distribution of our resources, the following will happen:**

* Your account/email will be banned from T1GER Scripts website.&#x20;
* Your Discord will be banned from T1GER Scripts Discord.
* No refunds for revoked assets will be issued under any circumstances .

To sum up, leaking is basically stealing. We put lots of hours to provide unique resources for the FiveM Community. Instead of spending time on people engaging in unauthorized use/distribution, we'd love to spend time creating new resources and/or providing support.

## SUPPORT

To be eligible for support, you must meet one of the following criteria:

* T1GER Scripts Customer & authorized on our discord with roles.
* Confirmed developer of a customer (customer must confirm the developer)

{% hint style="warning" %}
We reserve the right to not offer support if the (non)-customer is not following our guidelines and/or not behaving properly towards community or staff members.
{% endhint %}

This is what our support can offer you:

* **Documentation**
  * We provide you a detailed documentation for every resource, including an installation-guide.
  * Use our documentation as reference for installation, issues/errors and information-seeking.
* **Remote Services**
  * Due to numerous liability issues, we do not offer support using remote services (TeamViewer, AnyDesk etc.).&#x20;
* **Installation**
  * We do not install resources for you - our documentation and installation-guide should help you through it.
  * If you are struggling to install a resource with the provided documentation & installation-guide, our support may guide you through the installation.
* **Resource Issues & Errors**
  * If your encountered error/issue is not addressed in the documentation, then please open an appropriate ticket on our discord and our support will assist you.&#x20;
  * Please note; some errors/bugs/issues may require bigger updates, therefore instant-fixes will not always be possible.&#x20;
* **Customization**
  * We provide the resource as-is. If you customize it, please do not expect us to provide support with it.
  * We do not offer custom edits/features. If you want to customize it, you can suggest is as a feature on our discord, hire a developer or do it yourself.
* **Other content**
  * We do not offer support for resources which is not related to our resources.
  * We cannot modify/access other paid resources.
* **Communication**
  * All communication in terms of support is done in English.&#x20;

**All support is handled on our official** [**Discord**](https://discord.gg/t1ger)**. Before contacting our support:**

* Please go through the documentation and installation-guide.&#x20;
* Keep in mind that our resources are running on lots of servers. The most likely issues are resource installation or configuration and not an actual bug/error.&#x20;
* Our support-team is here to to attempt to resolve your issues, so please refrain from arguing with them and behave yourself.&#x20;
* Try to google your issue. FiveM has a large community where people tend to help out each other.&#x20;


# FiveM Asset Escrow

Guide to use resources utilizing FiveM Asset Escrow and getting roles on discord.

## RESOURCE DOWNLOAD&#x20;

You can find all your granted assets on [Cfx.re Portal](https://portal.cfx.re/assets/granted-assets)

## RESOURCE USAGE

Your packages are instantly authorized upon purchase automatically. No further action is required.

This is of course assuming you understand how the Cfx.re Asset Escrow works. Please read here for more information: [#faq](#faq "mention")

## DISCORD ROLES

When purchasing a package from our Tebex Store you should automatically receive discord roles for the respective package.

If you are not a member of our [Discord](https://discord.gg/t1ger), then make sure to join and then head to #commands channel and type /claim to receive your package roles. If this doesn't work, then please open an authentication ticket on our discord and read the introductory message. You need to provide:

* CFX Username
* Email
* Tebex Transaction ID

{% hint style="info" %}
If you are an existing customer and haven't purchased through Tebex, then please open a ticket on our discord and provide same details, but instead of Tebex Transaction ID, send us an image of your order including order# and purchased resource(s).
{% endhint %}

## FAQ

Are you having issues with Cfx.re Asset Escrow? Maybe your purchased resource is not there? Or maybe your console spits an error? Don't worry, FiveM got you covered with frequently asked questions that most likely will resolve your issue:&#x20;

<https://forum.cfx.re/t/introducing-asset-escrow-for-your-resources/4777151#faq-3>


# T1GER Mechanic

The most immersive and realistic mechanic script for FiveM

<figure><img src="https://2167335559-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MiDWIMbFBeXle-trOlk%2Fuploads%2FsQx6wVKMCq5dlmTrgN7M%2Ft1ger_mechanic.png?alt=media&amp;token=8d07a72f-51e9-4b8e-aab9-21b851909f99" alt=""><figcaption></figcaption></figure>

This mechanic script is designed to elevate roleplay for both casual players and dedicated mechanics. Open and manage your own mechanic business, carry out in-depth vehicle diagnostics, perform realistic repairs and services, and interact with a highly detailed system using custom props, animations, and authentic tools. Every aspect—from inspections to part replacements—is crafted to simulate real-world automotive work, making this the go-to solution for servers seeking top-tier mechanic gameplay.

## Purchase

<https://t1ger.net/product/5719711>

## Showcase

{% embed url="<https://youtu.be/zhuVV_jqyPI>" %}

## Features

### **Dynamic Shop Management**

Admins can create, configure, and manage mechanic shops entirely in-game—no restarts required. Through a built-in interface, they can assign a boss, edit or delete markers, list shops for sale, or remove shops entirely. Each shop becomes fully functional as soon as it’s placed.

### **Ownable Mechanic Shops**

Players can run their own fully interactive mechanic businesses. Shops include built-in markers for core job functions like toggling duty, storing or retrieving vehicles, accessing storage, crafting items, and ordering parts. Bosses can use a dedicated marker to manage employees and shop finances. All marker locations and functions are fully customizable by admins, allowing each shop to be tailored to its layout and workflow.

### **Realistic Component Structure**

Each vehicle is built from two layers of parts: **Service Parts** (e.g., oil, filters, fluids) and **Core Parts** (e.g., brakes, radiator, alternator). Service parts follow mileage-based intervals and degrade over time as the vehicle is driven. If not replaced on schedule, they begin to damage their associated core parts. Core parts otherwise only degrade from collisions.

### 1:1 Real-World Mileage Tracking

Mileage is tracked with near-perfect real-time accuracy and drives all degradation logic. Service parts wear down based on distance driven, even on ambient NPC vehicles. Maintenance demands vary by vehicle class — with some classes requiring more frequent servicing than others. Electric vehicles have fewer components and minimal upkeep.

### Mechanical Servicing

Mechanics inspect vehicles using a diagnostic tool, then select components to replace from a menu. Starting the repair opens a workflow UI that displays the selected parts. Repairs require specific items and are enhanced with **custom-made props**, animations, and visual effects. For quick fixes, items can also be used directly. Replaced parts return salvage materials for crafting or reuse.

### Core Part Malfunctions

Core parts have four health states: **Optimal**, **Worn**, **Critical**, and **Failed**. As condition worsens, real-time malfunction effects begin to appear while driving. A fully failed part disables the engine entirely. A patch kit can be used for emergency roadside recovery.

### Service History

All part replacements and mileage are logged for owned vehicles. Players can access the full service history using a service book item or command — ideal for inspections, diagnostics, and resale checks.

### Body Repair System

Mechanics can inspect vehicles for body damage using a diagnostic tool, generating a visual damage report displayed in the workflow UI. Damaged parts like doors, windows, hoods, trunks, and wheels are repaired using specific items. Repairs feature immersive props, animations, and particle effects. For quick jobs, mechanics can also replace individual parts directly without inspection.

### Repair Kits

Repair kits provide quick, configurable vehicle fixes without needing full maintenance. Basic kits can be used by anyone to restore engine health to a set value, with optional body repair. Advanced kits fully restore engine and body health and can be restricted to mechanics and specific whitelisted jobs.

### Car Lifts & Jacks

Enhance mechanic roleplay with immersive vehicle lifting tools. Custom car lift props can be placed in shops and used to raise vehicles for inspections or servicing. The portable car jack, using a native GTA prop, allows mechanics to realistically lift any of the four wheels by positioning the jack at the appropriate spot. It plays synced animations and adjusts vehicle height at the contact point. While not required for maintenance or repairs, both systems add realism and visual feedback to every job.

### Repair Stations

Repair stations are configurable, map-placed points where players can quickly fix their vehicles without needing a mechanic. Each station can repair engine, body, service parts, and core parts individually or all at once, with configurable prices, durations, and effects. Stations can be restricted by job, mechanic availability, or set to free use. Perfect for police depots, EMS garages, or public pay-per-use locations, with fully customizable blips, icons, and marker styles.

### Player Mechanic Menu

Mechanics can access a custom in-game menu to perform essential job functions. The menu provides quick access to NPC missions, vehicle interactions (push, flip, impound, unlock), billing, and towing tools. Menu options are fully configurable.

### NPC Missions

Give mechanics something to do between customer jobs with immersive NPC missions. They can tow broken-down vehicles, perform roadside repairs like refueling or jump-starting, or scrap abandoned cars for materials. Each mission includes randomized NPCs, vehicles, and locations for variety. A simple menu lets mechanics choose their job type and get paid or rewarded with crafting materials — perfect for earning extra income when business is slow.

### Flatbed Towing

Mechanics can attach vehicles to supported flatbed trucks using a simple keybind or command. Each flatbed model is individually configurable with attach offsets for precise placement. The system supports clean attach/detach logic, optional action menu integration, and marker feedback. Ideal for recovery jobs, NPC missions, or impound work.

### Prop Emotes

Mechanics can place, interact with, and push props like toolboxes, cones, signs, and barriers to enhance roleplay scenes. Each prop is tied to an item and supports immersive animations like pushing or picking up. Props can be attached to the player, dropped, or removed, allowing for realistic roadside setups, garage details, or job site control.

### Utility Vehicle Actions

Mechanics can push stuck vehicles, flip overturned ones, unlock locked cars, or impound vehicles through configurable job actions. These functions are accessible via the mechanic menu or custom commands and include realistic animations and usage conditions for immersion.

### Billing System

A detailed, itemized billing system allows mechanics to create transparent invoices with notes for each service. Customers must review and confirm the bill before payment, ensuring clear communication and consent. All bills are logged for shop owners to track transactions, completed jobs, and overall shop income — ideal for maintaining records and accountability in a busy workshop.

### Crafting Workbenches

Mechanics can craft repair kits, tools, and components using materials at shop-assigned workbenches. Recipes are fully configurable. Crafting integrates seamlessly with salvaged materials returned from part replacements, supporting a full resource loop and encouraging in-house production. You can easily integrate and use your own crafting system.

### Supplier System

Mechanic shops can order parts and repair items directly from a built-in supplier interface. Items can be delivered either to the shop’s storage or directly to the player’s inventory. All items and prices are configurable. The supplier system offers an alternative to crafting, giving mechanics flexibility in how they stock parts and operate their shop.


# Installation

This page covers the installation guide for T1GER Mechanic

{% stepper %}
{% step %}

### Ensure Dependencies

{% hint style="warning" %}
Verify that you have the latest version of the listed mandatory resources installed and ensured in correct [start order](https://docs.t1ger.net/resources/t1ger-mechanic/installation#start-order).
{% endhint %}

<table data-full-width="false"><thead><tr><th>Type</th><th width="462.60009765625">Resource(s)</th><th data-type="checkbox">Mandatory</th></tr></thead><tbody><tr><td>Database</td><td><a href="https://github.com/overextended/oxmysql/releases/latest">oxmysql</a></td><td>true</td></tr><tr><td>Library</td><td><a href="https://github.com/overextended/ox_lib/releases/latest">ox_lib</a></td><td>true</td></tr><tr><td>Framework</td><td><a href="https://github.com/esx-framework/esx_core/tree/main/%5Bcore%5D/es_extended">es_extended</a>, <a href="https://github.com/Qbox-project/qbx_core/releases/latest">qbx_core</a> or <a href="https://github.com/qbcore-framework/qb-core">qb-core</a></td><td>true</td></tr><tr><td>Target</td><td><a href="https://github.com/overextended/ox_target">ox_target</a> or <a href="https://github.com/qbcore-framework/qb-target">qb-target</a></td><td>true</td></tr><tr><td>Inventory</td><td><a href="https://github.com/overextended/ox_inventory">ox_inventory</a>, <a href="https://github.com/qbcore-framework/qb-inventory">qb-inventory</a>, qs-inventory, core_inventory, codem-inventory, origen_inventory or ak47_inventory</td><td>true</td></tr></tbody></table>
{% endstep %}

{% step %}

### Download

{% hint style="info" %}
Download the listed assets from [Cfx.re Portal](https://portal.cfx.re/assets/granted-assets):

* `t1ger_mechanic`
* `t1ger_carlift`
* `t1ger_mechanicprops`

Unzip the downloaded assets (`t1ger_mechanic`, `t1ger_carlift` and `t1ger_mechanicprops`) and drag them into a new folder named `[t1ger]` inside your server's `resources` folder.
{% endhint %}
{% endstep %}

{% step %}

### Start Order

{% hint style="warning" %}
It's **very important** to ensure the resources in correct order to prevent any errors due to missing dependencies!
{% endhint %}

```lua
ensure oxmysql
ensure ox_lib
ensure es_extended -- or qbx_core / qb-core
ensure ox_target -- or qb-target
ensure ox_inventory -- or whatever compatible inventory
ensure [t1ger]
```

{% hint style="info" %}
*There can be resources ensure in between the listed resources - this **solely clarifies** the correct start order.*
{% endhint %}
{% endstep %}

{% step %}

### Run SQL

{% hint style="info" %}
Open the `t1ger_mechanic/install/main.sql` file and run the queries in your database.

Alternatively you can the import file directly into your database.
{% endhint %}
{% endstep %}

{% step %}

### Add Items

{% hint style="danger" %}
If you rename the items or wish to use your own items, make sure to update inside t1ger\_mechanic/shared/\*.lua files!
{% endhint %}

{% tabs %}
{% tab title="ox\_inventory" %}
Open `t1ger_mechanic/install/items/ox_inventory.lua` file and copy/paste into `ox_inventory/data/items.lua` file.
{% endtab %}

{% tab title="qb-inventory" %}
Open `t1ger_mechanic/install/items/qb-inventory.lua` file and copy/paste into `qb-core/shared/items.lua` file.
{% endtab %}

{% tab title="es\_extended" %}
Open `t1ger_mechanic/install/items/items.sql` file and run the query in your database. You can also import the file directly into your database.

If using `ox_inventory`, it will automatically pull items from your database. Otherwise, you can open the `t1ger_mechanic/install/items/ox_inventory.lua` file and copy/paste into `ox_inventory/data/items.lua` file.
{% endtab %}
{% endtabs %}

{% hint style="info" %}
Inventory icons are located in `t1ger_mechanic/install/items/icons/` folder.
{% endhint %}
{% endstep %}

{% step %}

### Configuration

{% hint style="info" %}
Configure the resource to your liking. Read the end-text comments carefully. If you do not understand, please refer to our documentation or contact us through the relevant support channels on .

Refer to [Configuration](/resources/t1ger-mechanic/configuration)
{% endhint %}
{% endstep %}

{% step %}

### Complete

{% hint style="success" %}
You have successfully installed our T1GER Mechanic resource. Restart your server and enjoy!
{% endhint %}
{% endstep %}
{% endstepper %}


# Job Account

Instructions on how to setup job accounts to allow for runtime creation of accounts for jobs

## **Supported Banking Systems**

This module supports the following job account systems:

1. **ESX:** Uses `esx_addonaccount`
2. **QBCore:** Supports both `qb-banking` and `qb-management`
3. **QBox:** Uses `Renewed-Banking`
4. **Custom Implementations:** You can add support for a different system by modifying the `_API` functions, see [API](/resources/t1ger-mechanic/installation/job-account/api).

## **Configuration (`bridge/config.lua`):**

To set up the job account system, modify the `JobAccount` value:

```lua
JobAccount = "auto", -- "esx_addonaccount", "qb-banking", "qb-management", "Renewed-Banking", "tgg-banking" or "auto" (auto-detect)
```

* **If `auto` is selected**, the system will automatically choose the best option based on the framework.
* **If manually set**, it will enforce that specific system.
* **If using custom**, edit `InitializeJobAccount()` function inside `bridge/init.lua`.

## Setup

Instructions on how to prepare for runtime creation of shared accounts

{% content-ref url="/pages/Bu34dHW8wLldot88XPJz" %}
[Setup](/resources/t1ger-mechanic/installation/job-account/setup)
{% endcontent-ref %}

## Functions

Useful functions for Job Accounts. Also these you want to modify to integrate/compatibility for a custom job banking resource

{% content-ref url="/pages/C0ZQwMUaQ9P7Hpi8nhdu" %}
[API](/resources/t1ger-mechanic/installation/job-account/api)
{% endcontent-ref %}


# Setup

Instructions on how to setup your job/society integrations with your framework to create shared accounts for jobs in runtime!

## ESX

Download and ensure the latest `esx_addonaccount` from here: <https://github.com/esx-framework/esx_addonaccount>.

## QBCore

Instructions on how to setup job/society accounts with QBCore framework compatibility.

### `qb-banking`

If you are using `qb-banking`, all you need to do is download and ensure the latest version of `qb-banking` from here: <https://github.com/qbcore-framework/qb-banking>.

### `qb-management`

If you are using qb-management (old method), then follow these instructions.&#x20;

{% hint style="warning" %}
Latest `qb-management` does not manage job/society accounts. This is now handled by `qb-banking`. If you are using old qb-management, it's highly recommended to update to latest and utilize `qb-banking` instead.&#x20;
{% endhint %}

{% stepper %}
{% step %}

### Find the file to modify

Navigate to `qb-management/server/sv_boss.lua`.&#x20;
{% endstep %}

{% step %}

### Check for functions

Do `Ctrl + F` (search) for `GetAccount` or `AddMoney` or `RemoveMoney`. If they do not exist, then do not proceed further! Instead, ensure that you have latest [`qb-banking`](https://github.com/qbcore-framework/qb-banking) installed, as this resource now handles job/society accounts.&#x20;
{% endstep %}

{% step %}

### Insert new function

Scroll down all the way to the bottom and insert the following code:

```lua
--- Creates a management account for a job in qb-management.
---@param job_name string The name of the job to create the management account for.
---@param amount number|nil The initial balance of the account (defaults to 0 if not provided).
---@return boolean success Returns `true` if the account was created successfully, `false` otherwise.
function CreateManagementAccount(job_name, amount)
    -- Ensure a valid job name is provided
    if type(job_name) ~= "string" or job_name == "" then
        error("Invalid job_name provided")
    end

    amount = amount or 0 -- Default to 0 if no amount is provided

    -- Check if account already exists in cache
    if Accounts[job_name] then
        return Accounts[job_name] -- Account already exists, no need to create it again
    end

    -- Insert the new account into the database
    local insertSuccess = MySQL.insert.await('INSERT INTO management_funds (job_name, amount, type) VALUES (@job_name, @amount, @type)', {
        ['@job_name'] = job_name,
        ['@amount'] = amount,
        ['@type'] = 'boss'
    })

    if not insertSuccess then
        error("Database error: Failed to insert management account")
    end

    -- Store in local cache
    Accounts[job_name] = amount

    return Accounts[job_name]
end
exports("CreateManagementAccount", CreateManagementAccount)
```

{% endstep %}

{% step %}

### Complete

Restart your server and you'll now be able to create management account in runtime!&#x20;
{% endstep %}
{% endstepper %}

## Qbox

Download and ensure the latest version of `Renewed-Banking` from here: <https://github.com/Renewed-Scripts/Renewed-Banking/releases>.

If you are using another banking/management for job/shared accounts, then refer to [API](/resources/t1ger-mechanic/installation/job-account/api) for custom integrations on your own.&#x20;

If using `qb-management` (old version) with backwards compatibility, then see [#qb-management](#qb-management "mention").


# API

Functions for Job Account. Modify them inside bridge/jobaccount/server.lua for custom changes.

## **Get a Job Account**

**`_API.JobAccount.Get(jobName)`**

Retrieves the shared job account for a given job.

* **Parameters:**
  * `jobName` *(string)* – The name of the job whose account is being retrieved.
* **Returns:**
  * `JobAccount` *(table)* – The job account object if found.
  * `nil` – If no account is found.
* **Example Usage:**

  ```lua
  local account = _API.JobAccount.Get("mechanic")
  if account then
      print("Account found:", account)
  else
      print("No job account exists for mechanic.")
  end
  ```

***

## **Get Job Account Balance**

**`_API.JobAccount.GetBalance(jobName)`**

Retrieves the balance of a shared job account.

* **Parameters:**
  * `jobName` *(string)* – The name of the job whose balance is being retrieved.
* **Returns:**
  * `balance` *(number)* – The current balance of the job account, or `0` if unavailable.
* **Example Usage:**

  ```lua
  local balance = _API.JobAccount.GetBalance("mechanic")
  print("Current balance:", balance)
  ```

***

## **Add Money to a Job Account**

**`_API.JobAccount.AddMoney(jobName, amount)`**

Adds money to a shared job account.

* **Parameters:**
  * `jobName` *(string)* – The name of the job whose account will receive money.
  * `amount` *(number)* – The amount of money to add.
* **Example Usage:**

  ```lua
  _API.JobAccount.AddMoney("mechanic", 5000)
  print("Added 5000 to mechanic account")
  ```

***

## **Remove Money from a Job Account**

**`_API.JobAccount.RemoveMoney(jobName, amount)`**

Removes money from a shared job account.

* **Parameters:**
  * `jobName` *(string)* – The name of the job whose account will be debited.
  * `amount` *(number)* – The amount of money to remove.
* **Example Usage:**

  ```lua
  _API.JobAccount.RemoveMoney("mechanic", 2000)
  print("Removed 2000 from mechanic account")
  ```

***

## **Set a Job Account Balance**

**`_API.JobAccount.SetMoney(jobName, amount)`**

Sets a specific balance for a shared job account.

* **Parameters:**
  * `jobName` *(string)* – The name of the job whose account balance will be set.
  * `amount` *(number)* – The new balance to be set for the job account.
* **Example Usage:**

  ```lua
  _API.JobAccount.SetMoney("mechanic", 10000)
  print("Set mechanic account balance to 10000")
  ```

***

## **Create a New Job Account**

**`_API.JobAccount.Create(jobName, startBalance)`**

Creates a new shared job account with a starting balance.

* **Parameters:**
  * `jobName` *(string)* – The name of the job/society for which the account will be created.
  * `startBalance` *(number)* – The initial balance of the newly created job account.
* **Returns:**
  * `true` – If the account was created successfully.
  * `false` – If the account could not be created.
* **Example Usage:**

  ```lua
  local success = _API.JobAccount.Create("mechanic", 5000)
  if success then
      print("Mechanic job account created successfully!")
  else
      print("Failed to create mechanic job account.")
  end
  ```


# Configuration

This page covers all configurable aspects of T1GER Mechanic

Configuration files are located in the `t1ger_mechanic/shared/` folder and control various systems like shops, parts, missions, crafting, and suppliers.

{% content-ref url="/pages/zFh6Vahh6MTUvvn7DriZ" %}
[Config](/resources/t1ger-mechanic/configuration/config)
{% endcontent-ref %}

{% content-ref url="/pages/y4754b9bi2frSRcr4gEo" %}
[Shop](/resources/t1ger-mechanic/configuration/shop)
{% endcontent-ref %}

{% content-ref url="/pages/qWuOSizXHs5EQDAEdJTH" %}
[Parts](/resources/t1ger-mechanic/configuration/parts)
{% endcontent-ref %}


# Config

t1ger\_mechanic/shared/config.lua

```lua
Config = {}

Config.Debug = true

Config.Currency = "$" -- currency used for pricing

Config.ServerSideProps = true -- create objects/props on server or client?

--- Mechanic Action Menu
Config.ActionMenu = {
	Enable = true, -- set to false to disable mechanic action menu
	Command = {enable = true, name = "mechanic"}, -- enable/disable command, set command string.
	Keybind = {enable = true, defaultMapping = "F7", description = "Open Mechanic Action Menu"} -- enable/disable keybind, set default mapping (players edit button in-game inside GTA Settings)
}

--- Car Lifts settings
Config.CarLift = {
    Model = {
        base = `t1ger_carlift_base`, -- model for carlift base
        arm = `t1ger_carlift_arms`, -- model for carlift arm
    },
	Command = "createlift", -- command to create a carlift
	Icons = { -- icons for target options on carlift
		["up"] = "fa-sharp fa-solid fa-arrow-up",
		["down"] = "fa-sharp fa-solid fa-arrow-down",
		["stop"] = "fa-regular fa-circle-stop",
		["delete"] = "fa-solid fa-ban"
	}
}

--- Car Jack
Config.CarJack = {
	Item = "t1ger_carjack",
	Marker = {type = 27, scale = vector3{0.35, 0.35, 0.35}, color = {r = 200, g = 100, b = 200, a = 100}},
    Prop = {model = "imp_prop_car_jack_01a", pos = vector3(-0.40, -1.4, -0.8), rot = vector3(5.0, 0.0, -180.0), boneId = 28422},
	Keybind = 38, -- Default [E] | Attaches carjack prop to vehicle
	Icons = {
		target = { -- target icons
			remove = "fa-solid fa-trash",
			handle = "fa-solid fa-gamepad"
		},
		menu = {
			raise = "arrow-up",
			lower = "arrow-down"
		}
	},
	AllowEveryone = false, -- allow everyone with carjack to use on a vehicle?
}

--- Default random values when generating data for unowned vehicles (e.g. NPC vehicles, rental cars, etc.)
Config.RandomVehicleDefaults = {
    MileageRange = {5000, 200000},      -- Min and max total vehicle mileage (in km or mi)
    ServicePartRange = {0.0, 0.9},		-- Min and max percentage of the part's service interval used. Example: 0.9 = 90% of interval used. Values over 1.0 are allowed (e.g., 1.1 = 10% overdue).
    CorePartHealthRange = {65, 100},    -- Min and max health (0–100%) of core parts. Values outside 0-100 will be clamped safely.
}

--- Mileage settings
Config.Mileage = {-- 1:1 Real-World Mileage Tracking! There could be a maximum of 5% difference.
	Metric = true, -- true is kilometers and false is miles
	Unit = 'KM', -- or 'KM' or 'Mi' or whatever
	Command = {enable = true, name = "mileage"}, -- enable command to view vehicle mileage?
}

--- Associated wear on core parts for service parts that are overdue 
Config.AssociatedWear = { -- This simulates real-world mechanical wear caused by neglected maintenance on service parts.
    Enabled = true,       -- Enable or disable associated core part degradation
    Rate = 0.5            -- % of health lost per second (1000 ms) for each affected core part
}

--- Malfunction Effects Settings
Config.MalfunctionEffects = {
	Enabled = true, -- Enable or disable malfunction effects caused by degraded core parts.
	Interval = 10, -- Delay between each malfunction effect in thread ticks (1 tick = 1 second). For example, 30 means one malfunction effect every 30 seconds (if any degraded core parts exist).
	Notify = true, -- notify with part label and condition when malfunction effects plays?
}

--- Multiplier for service intervals by vehicle class. Lower = more frequent maintenance, higher = less frequent.
--- Applied to Config.ServiceParts[<partName>].interval based on the vehicle's class.
Config.ServiceIntervalMultipliers = {
    [0]  = 1.4,  -- Compacts: lightweight, low-stress vehicles
    [1]  = 1.2,  -- Sedans: everyday use, moderate wear
    [2]  = 1.0,  -- SUVs: heavier, average wear
    [3]  = 1.1,  -- Coupes: generally better maintained, moderate wear
    [4]  = 0.8,  -- Muscle: powerful engines, driven hard = faster wear
    [5]  = 0.7,  -- Sports Classics: older tech, higher maintenance needs
    [6]  = 0.85, -- Sports: performance use, more wear than average
    [7]  = 0.75, -- Super: high-performance, demanding servicing
    [8]  = 1.3,  -- Motorcycles: light use but exposed components
    [9]  = 0.6,  -- Off-road: harsh terrain = rapid degradation
    [10] = 0.5,  -- Industrial: heavy loads, constant strain
    [11] = 0.6,  -- Utility: work vehicles, rugged use
    [12] = 0.9,  -- Vans: often used commercially, moderate wear
    [17] = 0.6,  -- Service: fleet use, high uptime
    [18] = 0.5,  -- Emergency: aggressive use, high stress
    [19] = 0.4,  -- Military: off-road, rugged, heavy-duty
    [20] = 0.5,  -- Commercial: delivery/freight, long hours
    [22] = 0.3   -- Open Wheel: race use, extreme servicing needs
}

--- Blacklist certain vehicle models from being tracked regarding degradation of parts on overdue and collisions
Config.BlacklistTracking = {
	"mesa3",
	"nightshark"
}

--- Disable Automatic Engine Start
Config.DisableAutoEngineStart = true -- If true, disables GTA's automatic engine start behavior when entering a vehicle.

--- Part Conditions
Config.PartConditions = {
    -- Condition percent for service parts (based on used mileage compared with interval)
    service_parts = {
        {percent = 16, label = locale("menu_title.service_ok")},               -- The part has 16% or more of its service interval remaining.
        {percent = 0, label = locale("menu_title.service_due")},               -- The part has between 0% and 15% of its service interval remaining. A service is recommended soon.
        {percent = -math.huge, label = locale("menu_title.service_overdue")}   -- The part has exceeded its service interval (negative remaining mileage), posing a risk of core part damage.
    },

    -- Condition percent for core parts (based on health)
    core_parts = {
        {percent = 51, label = locale("menu_title.part_optimal")},	-- No malfunctions. The part is in good condition, and the vehicle operates normally.
        {percent = 21, label = locale("menu_title.part_worn")},		-- Minor malfunctions occur occasionally. Players will begin noticing small issues.
        {percent = 1, label = locale("menu_title.part_critical")},	-- Frequent and sustained malfunctions. Players will experience major performance issues.
        {percent = 0, label = locale("menu_title.part_failed")}		-- The part has failed completely, causing constant effects or rendering the vehicle undriveable.
    }
}

--- Vehicle Collision Settings
Config.VehicleCollision = {
    Enable = true,       	-- Enable or disable collision-based part degradation
    MinImpactSpeed = 40, 	-- Minimum vehicle speed (in KMH or MPH based on Config.Mileage) required for collision to cause degradation
    CooldownTime = 5000,	-- Cooldown (in milliseconds) between consecutive degradable collisions to avoid rapid triggering
    PartCount = 2,          -- How many core parts to degrade per collision
    MinPercent = 5,         -- Minimum % degradation per part
    MaxPercent = 15         -- Maximum % degradation per part
}

--- Define Electric Vehicles
Config.ElectricVehicles = { -- if using gamebuild 3258+ then script will auto detect electric vehicles a using native
	"surge",
	"buffalo5",
	"caddy",
	"caddy2",
	"caddy3",
	"cyclone",
	"dilettante",
	"dilettante2",
	"iwagen",
	"imorgen",
	"khamelion",
	"neon",
	"omnisegt",
	"raiden",
	"tezeract",
	"voltic",
	"voltic2",
	"virtue"
}

--- Admin Vehicle Reapir
Config.AdminRepair = {
	Enable = true, -- set to false to disable this command
	Command = "fix", -- command name to quick fix a vehicle
	Parts = true, -- repair core_parts and service_parts?
	Refuel = true -- set to fuel to 100.0?
}

--- Repair Kits
Config.RepairKits = {
	Skillcheck = {enable = true, difficulty = {"easy", "easy", "easy"}, inputs = {"w", "a", "s", "d"}}, -- skillcheck settings
	Duration = 3000,

	Types = {
		-- basic repair kit
		basic = {
			item = "t1ger_repairkit",
			engineHealth = 600.0, -- minimum health after repair (clamped 250.0–1000.0)
			repairBody = false, -- repair body health?
		},
	
		-- advanced repair kit
		advanced = {
			item = "t1ger_repairkit_adv",
			engineHealth = 1000.0, -- value to set the engine health to?
			repairBody = true, -- repair body health?
			mechanicOnly = false, -- only allow mechanics to use?
			whitelitedJobs = {"police", "ems", "police2"}, -- always allow these jobs to use this kit. Set to nil or {} to ignore.
		}
	}
}

--- Patch Kit Configuration
Config.PatchKit = {
    Item = "t1ger_patchkit", -- Item name required to use a patch kit
    CorePartHealth = 5.0, -- Sets all failed core parts' health to this value. (Clamped between 1% and 100%)
	ServicePartRemainingMileage = 10.0, -- if overdue, it reset the mileage to 10.0 km/mi before overdue
	Skillcheck = {enable = true, difficulty = {"easy", "easy", "easy"}, inputs = {"w", "a", "s", "d"}}, -- skillcheck settings
	Duration = 4000, -- Repair duration in miliseconds (MS)
}

--- Components (Service- and Core-Parts) related interactions
Config.Components = {
	Repair = {
		targetIcon = "fa-solid fa-hammer", -- icon for target when installing parts
		skillcheck = {enable = true, difficulty = {"easy", "easy", "easy"}, inputs = {"w", "a", "s", "d"}}, -- enable skillcheck before installing part?
		duration = 3000, -- Repair/replace duration in miliseconds (MS)
		cancelCommand = {enable = true, name = "component:cancel"},

		-- setting to return salvaged materials on part replacement
		materialReturn = {
			enable = true, -- Enable or disable material return
			scaleWithCondition = true, -- If true: scale based on condition, if false: random between min/max
			minAmount = 0, -- Random minimum (only if scaleWithCondition = false)
			maxAmount = 5, -- Random maximum (but clamped to recipe material count requirement)
			notify = true, -- Send notification of salvaged/returned materials?
		}
	},

	Diagnostic = {
		item = "t1ger_diagnostictool",
		duration = 4000, -- duration to diagnose in miliseconds (MS)
		icons = { -- menu icons for system overview, core parts and service parts
			system_overview = "fa-tachometer-alt",
			core_parts = "https://i.postimg.cc/X7GXytsj/t1ger-brakes.png",
			service_parts = "https://i.postimg.cc/bNBb7QBJ/t1ger-oilfilter.png",
			start_workflow = "fa-screwdriver-wrench",
		},
		command = {enable = true, name = "diagnose"},
		systemOverview = {
			engineHealth = {enable = true, label = locale("menu_metadata.diagnostic_engine_health"), icon = "kit-medical", symbol = "%"},
			bodyHealth = {enable = true, label = locale("menu_metadata.diagnostic_body_health"), icon = "car", symbol = "%"},
			tankHealth = {enable = true, label = locale("menu_metadata.diagnostic_tank_health"), icon = "gas-pump", symbol = "%"},
			fuelLevel = {enable = true, label = locale("menu_metadata.diagnostic_fuel_level"), icon = "gauge", symbol = "%"},
			dirtLevel = {enable = true, label = locale("menu_metadata.diagnostic_dirt_level"), icon = "shower", symbol = "%"},
			oilLevel = {enable = true, label = locale("menu_metadata.diagnostic_oil_level"), icon = "oil-can", symbol = "L"},
			engineTemp = {enable = true, label = locale("menu_metadata.diagnostic_engine_temp"), icon = "temperature-high", symbol = "°C"},
			mileage = {enable = true, label = locale("menu_metadata.diagnostic_mileage"), icon = "road", symbol = " "..Config.Mileage.Unit},
			plate = {enable = true, label = locale("menu_metadata.diagnostic_plate"), icon = "id-card", symbol = ""}
		}
	},

    WorkflowTitle = "Workflow - %s", -- workflow title followed by plate
    WorkflowName = "<strong>%s</strong>" -- work flow (body part label)
}

--- Service History
Config.ServiceHistory = {
	Item = "t1ger_servicebook",
	Command = {enable = true, name = "servicebook"}
}

--- Body Repair and Inspection
Config.BodyRepair = {
	TargetIcon = "fa-solid fa-car", -- icon for target when installing parts
	Skillcheck = {enable = true, difficulty = {"easy", "easy", "easy"}, inputs = {"w", "a", "s", "d"}}, -- enable skillcheck before installing part?
	Duration = 3000, -- Repair/replace duration in miliseconds (MS)

	AllowEveryoneForWheelRepair = false, -- allow everyone to use wheel to fix damaged wheels?
	FixEngineHealth = true, -- sets engine health to 1000.0 once body repair is completed?

	Inspect = { -- Inspect vehicle to get damage report and trigger workflow UI
		diagnosticTool = true, -- allow inspection by using diagnostic tool when not inside or at engine?
		command = {enable = true, name = "inspect:start"}, -- command to trigger inspection of body? command name
		target = {enable = true, icon = "fa-solid fa-car"}, -- target to trigger inspection of body?  icon for target option

        marker = {type = 20, scale = {x = 0.35, y = 0.35, z = 0.35}, color = {r = 217, g = 164, b = 61, a = 100}}, -- marker settings
		textUI = {
			icon = "magnifying-glass", -- textUI icon
			position = "right-center", -- textUI position
			style = {borderRadius = 0, backgroundColor = "#d9a43dcc", color = "white"} -- textUI style/css
		},
        keybind = 38, -- [E]
        duration = 2000, -- duration in MS for each inspection point
		cancel = {command = "inspect:cancel"}
	},

	CancelCommand = "body:cancel", -- command to cancel body part installation

    WorkflowTitle = "Workflow - %s", -- workflow title followed by plate
    WorkflowName = "<strong>%s</strong>" -- work flow (body part label)
}

--- Workflow UI
Config.WorkflowUI = {
	Commands = {
		open = "workflow:open",
		close = "workflow:close",
		cursor = "workflow:cursor",
		clear = "workflow:clear"
	},
	CursorKeybind = {
		description = "Toggle Workflow UI Cursor",
		defaultKey = "J"
	},
	DefaultTitle = "Workflow UI", -- default workflow UI title (if u open with no data set)
}

--- Static / NPC repair stations
Config.RepairStations = {
	Blip = {name = "Repair Station", sprite = 402, color = 7, scale = 1.0}, -- blip settings
	Marker = {type = 20, scale = {x = 0.35, y = 0.35, z = 0.35}, color = {r = 162, g = 31, b = 224, a = 100}}, -- draw marker settings
	Keybind = 38, -- Default [E] keybind

	TextUi = {
		icon = "wrench", -- textUi icon
		position = "right-center", -- textUi position
		style = {borderRadius = 0, backgroundColor = "#a21fe080", color = "white"} -- textUi style/css
	},

	Repairs = { -- allowed repairs
		engine = {enable = true, value = 1000.0, duration = 2000, price = 1500, icon = "gauge-high"}, -- allow engine repair? Fixed engine health value?
		body = {enable = true, value = 1000.0, duration = 3000, price = 1000, icon = "car-side"}, -- allow body repair? Fixed body health value?
		core_parts = {enable = true, value = 100.0, duration = 4000, price = 2500, icon = "tools"}, -- allow core_parts repair? Fixed parts value (min = 0.0, max = 100.0)
		service_parts = {enable = true, value = 0, duration = 5000, price = 3000, icon = "wrench"} -- allow service_parts mileage set? Reset mileage on service parts to value greater than 0.
	},

	Mode = "individual", -- "full" or "individual". Individual, select repair types in menu. Full repairs all enabled repair types above.
	FullRepairIcon = "wrench", -- icon in menu for full repair
	FullRepairDuration = 10000, -- repair duration if mode is set to "full"
	FullRepairPrice = 8000, -- repair price if mode is set to "full"

	RestrictWithOnlineMechanics = true, -- if true players cannot use repair station if mechanics are online
	AllowIfMechanicCountBelow = 3, -- allow repair station usage if fewer than 3 mechanics online
	RestrictOnWhitelistedStations = false, -- if false ignore online mechanics on repair stations with jobs defined. If true it checks for online count.

	Locations = { -- repair locations. Coords for the point. Set jobs = nil to allow everyone. Enable/disable blip. Add free = true to allow free repairs.
		[1] = {coords = vector3(433.62, -1018.28, 28.84), jobs = {"police", "police2"}, blip = true, free = true},
		[2] = {coords = vector3(344.39, -553.79, 28.74), jobs = {"ambulance", "ems"}, blip = true, free = true},
		[3] = {coords = vector3(548.18, -206.17, 54.15), jobs = nil, blip = true},
	}
}

--- Flatbed Towing
Config.FlatbedTowing = {
	Enable = true, -- set to false to disable
	Command = "tow", -- command to use tow feature
	ActionMenu = {enable = true, icon = "anchor"}, -- enable from action menu? icon for menu option
	Trucks = { -- supported trucks index by modelname.
		["flatbed"] = {offset = vector3(0.0, -2.0, 0.8), boneName = "bodyshell"},
		-- add more
	},
	Blacklisted = {"flatbed", "towtruck", "cargobob"}, -- vehicles that cannot be attached to flatbed
	Marker = {type = 20, scale = {x = 0.50, y = 0.50, z = 0.50}, color = {r = 240, g = 52, b = 52, a = 100}},
	Keybind = 47, -- default G | Attach or detach vehicle from flatbed/towtruck
}

--- Push Vehicle
Config.PushVehicle = {
	Enable = true, -- set to false to disable
	Command = {enable = true, name = "pushvehicle"}, -- enable command to push vehicle?
	ActionMenu = {enable = true, icon = "hand"}, -- enable from action menu? icon for menu option
	AllowEveryone = false, -- if false only mechanics can push, else everyone can push
	DrawDist = 4.0, -- istance to draw 3d text
	PushKey = 21, --  DEFAULT KEY: [LEFT SHIFT]
	StopKey = 177, --  DEFAULT KEY: [BACKSPACE]
	LeftKey = 34, --  DEFAULT KEY: [A]
	RightKey = 35, --  DEFAULT KEY: [D]
}

--- Flip Vehicle
Config.FlipVehicle = {
	Enable = true, -- set to false to disable
	Command = {enable = true, name = "flipvehicle"}, -- enable command to unlock vehicle?
	ActionMenu = {enable = true, icon = "turn-up"}, -- enable from action menu? icon for menu option
	DrawDist = 4.0, -- istance to draw 3d text
	Keybind = 38, -- DEFAULT KEY: [E]
	Scenario = "CODE_HUMAN_MEDIC_TEND_TO_DEAD",
	Duration = 3000 -- progbar duration
}

--- Unlock Vehicle
Config.UnlockVehicle = {
	Enable = true, -- set to false to disable
	Command = {enable = true, name = "unlockvehicle"}, -- enable command to unlock vehicle?
	ActionMenu = {enable = true, icon = "unlock"}, -- enable from action menu? icon for menu option
	DrawDist = 4.0, -- istance to draw 3d text
	Keybind = 38, -- DEFAULT KEY: [E]
	Anim = {dict = "anim@amb@clubhouse@tutorial@bkr_tut_ig3@", clip = "machinic_loop_mechandplayer", blendIn = 3.0, blendOut = 3.0, flag = 31},
	Duration = 3000 -- progbar duration
}

--- Impound Vehicle
Config.ImpoundVehicle = {
	Enable = true, -- set to false to disable
	Command = {enable = true, str = "impoundvehicle"}, -- enable command to unlock vehicle?
	ActionMenu = {enable = true, icon = "square-parking"}, -- enable from action menu? icon for menu option
	DrawDist = 4.0, -- istance to draw 3d text
	Keybind = 38, -- DEFAULT KEY: [E]
	Scenario = "CODE_HUMAN_MEDIC_TEND_TO_DEAD",
	Duration = 3000 -- progbar duration
}

--- Prop Emotes
Config.Emotes = {
	Keybind = 38, -- keybind to place prop,
	Distance = 2.0, -- distance to interact with prop
	Icons = { -- icons for taget
		remove = "fa-solid fa-trash", -- remove icon
		attach = "fa-solid fa-hand" -- attach (carry/push) icon
	},
	Anim = {
		['push'] = {dict = 'anim@heists@box_carry@', clip = 'idle', blendIn = 4.0, blendOut = 1.0, duration = -1, flags = 49},
		['pickup'] = {dict = 'random@domestic', clip = 'pickup_low', blendIn = 5.0, blendOut = 3.0, duration = -1, flags = 48}
	},
	Props = {
		['-1036807324'] = {label = 'Road Cone', item = "t1ger_roadcone", model = 'prop_roadcone02a', bone = 28422, pos = {0.6,-0.15,-0.1}, rot = {315.0,288.0,0.0}},
		['-1776497660'] = {label = 'Tools Trolley', item = "t1ger_toolstrolley", model = 'prop_cs_trolley_01', push = true, bone = 28422, pos = {-0.1,-0.6,-0.85}, rot = {-180.0,-165.0,90.0}},
		['-1972842851'] = {label = 'Tool Box', item = "t1ger_toolbox", model = 'prop_tool_box_04', bone = 28422, pos = {0.4,-0.1,-0.1}, rot = {315.0,288.0,0.0}},
		['-2146714905'] = {label = 'Con Sign', item = "t1ger_consign", model = 'prop_consign_02a', push = true, bone = 28422, pos = {0.0,0.2,-1.05}, rot = {-195.0,-180.0,180.0}},
		['-205311355'] = {label = 'Road Barrier', item = "t1ger_roadbarrier", model = 'prop_mp_barrier_02b', push = true, bone = 28422, pos = {0.0,0.2,-1.05}, rot = {-195.0,-180.0,180.0}}
	}
}

--- Mechanic NPC Missions / Jobs
Config.Missions = {
	Enable = true, -- set to false to disable built in mechanic missions/jobs
	Command = {enable = true, name = 'missions'}, -- enable command to open missions menu?
	ActionMenu = {enable = true, icon = 'comment-dots'}, -- enable from action menu? icon for menu option
	CancelIcon = 'ban', -- icon menu to cancel job?

	Types = {
		breakdown = {
			enable = true, -- enable mission type
			icon = "truck-pickup", -- icon in menu
			travelDistance = 1000.0, -- minimum travel distance from players coords to the "fetched" mission location.
			blip = {label = 'Breakdown Mission', sprite = 1, color = 5, scale = 0.7, route = {enable = true, color = 5}}, -- blip settings
		},
		roadsiderepair = {
			enable = true, -- enable mission type
			icon = "screwdriver-wrench", -- icon in menu
			travelDistance = 1000.0, -- minimum travel distance from players coords to the "fetched" mission location.
			blip = {label = 'Roadside Repair Mission', sprite = 1, color = 5, scale = 0.7, route = {enable = true, color = 5}}, -- blip settings
			types = {
				fuel = {enable = true, subtitle = "Out of Fuel", item = "t1ger_fuelcan"}, -- enable/disable fuel repair type, subtitle for notify and set required item
				battery = {enable = true, subtitle = "Battery Failure", item = "t1ger_jumpstarter"},  -- enable/disable battery repair type subtitle for notify and set required item
				tire = {enable = true, subtitle = "Flat Tire", item = "t1ger_repairkit_tire"} -- enable/disable tyre repair type subtitle for notify and set required item
			},
			duration = 5000, -- time in ms for anim duration
		},
		carscrapping = {
			enable = true, -- enable mission type
			icon = "recycle", -- icon in menu
			travelDistance = 1000.0, -- minimum travel distance from players coords to the "fetched" mission location.
			blip = {label = 'Car Scrapping Mission', sprite = 1, color = 5, scale = 0.7, route = {enable = true, color = 5}}, -- blip settings
			scrapyard = {
				ped = {
					model = 's_m_y_xmech_02_mp', -- scrapyard ped model
					coords = vector4(-465.77,-1707.58,18.8,252.19), -- scrapyard ped coords
				},
				dropoff = vector3(-457.29,-1713.84,18.64), -- vehicle drop off coords
				inspect = vector4(-459.98,-1712.81,18.67,240.04), -- inspect pos and heading
				scenarios = {
					idle = 'WORLD_HUMAN_AA_SMOKE', -- ped idle scenario
					inspect = 'WORLD_HUMAN_CLIPBOARD' -- ped inspect scenario
				}
			},
			reward = {
				count = 4, -- how many types of random materials to receive, like alu, steel etc.
				amount = {min = 1, max = 5} -- of selected material, how many to receive randomly from min-max
			}
		}
	},

	NotifyIcon = "CHAR_MP_MECHANIC", -- advanced notification icon
	
	RandomPeds = {"s_m_y_dealer_01", "a_m_m_indian_01", "a_m_m_polynesian_01", "a_m_m_prolhost_01", "a_m_m_socenlat_01"}, -- randomized ped models used for the NPC missions
	
	RandomVehicles = {"sultan", "blista", "glendale", "exemplar"}, -- randomized vehicle models used for the NPC missions

	Locations = require("shared/missions") -- Load locations from the shared/missions.lua file index by mission type. DO NOT TOUCH!
}
```


# Missions

t1ger\_mechanic/shared/missions

```lua
local locations = {}

locations["breakdown"] = {
    [1] = {
        pos = vector4(932.04, -62.5, 78.76, 85.98), -- npc vehicle spawn coords
        inUse = false, -- do not touch
        pedCoords = vector4(931.58, -59.92, 78.76, 135.83), -- npc ped spawn coords and model
        dropoff = vector3(-366.25, -124.89, 38.7), -- vehicle dropoff location
        payout = { min = 250,  max = 400 } -- payout cash minimum amount and maximum amount
    },
    [2] = {
        pos = vector4(99.43, 247.17, 108.19, 66.33), -- npc vehicle spawn coords
        inUse = false, -- do not touch
        pedCoords = vector4(97.83, 250.58, 108.38, 177.98), -- npc ped spawn coords and model
        dropoff = vector3(-218.37,-1296.19,31.3), -- vehicle dropoff location
        payout = { min = 250,  max = 400 } -- payout cash minimum amount and maximum amount
    },
    [3] = {
        pos = vector4(167.33, -1460.1, 29.14, 138.45), -- npc vehicle spawn coords
        inUse = false, -- do not touch
        pedCoords = vector4(171.92, -1458.62, 29.24, 126.2), -- npc ped spawn coords and model
        dropoff = vector3(716.32, -1080.13, 22.28), -- vehicle dropoff location
        payout = { min = 250,  max = 400 } -- payout cash minimum amount and maximum amount
    },
    -- add more locations
}

locations["roadsiderepair"] = {
    [1] = {pos = vector4(880.16, -34.66, 78.75, 240.94), inUse = false, payout = {min = 250, max = 400}},
    [2] = {pos = vector4(1492.09, 758.45, 77.45, 288.26), inUse = false, payout = {min = 250, max = 400}},
    [3] = {pos = vector4(387.67, -767.56, 29.29, 358.94), inUse = false, payout = {min = 250, max = 400}},
    [4] = {pos = vector4(-583.75, -239.55, 36.08, 33.14), inUse = false, payout = {min = 250, max = 400}},
    [5] = {pos = vector4(350.12, 345.60, 105.15, 73.70), inUse = false, payout = {min = 250, max = 400}},
    [6] = {pos = vector4(106.11, 317.55, 112.13, 340.15), inUse = false, payout = {min = 250, max = 400}},
    [7] = {pos = vector4(-250.24, 292.83, 91.79, 85.03), inUse = false, payout = {min = 250, max = 400}},
    [8] = {pos = vector4(-1325.35, 275.32, 63.41, 215.43), inUse = false, payout = {min = 250, max = 400}},
    [9] = {pos = vector4(-1622.20, -237.69, 53.93, 158.74), inUse = false, payout = {min = 250, max = 400}},
    [10] = {pos = vector4(-1273.45, -1010.42, 9.34, 195.59), inUse = false, payout = {min = 250, max = 400}},
}

locations["carscrapping"] = {
    [1] = {pos = vector4(-367.42, -1521.98, 26.72, 174.32), inUse = false},
    [2] = {pos = vector4(-12.45, -1799.43, 26.4, 317.32), inUse = false},
    [3] = {pos = vector4(587.51, -1791.45, 21.08, 172.84), inUse = false},
    [4] = {pos = vector4(1043.62, -2130.04, 31.74, 262.95), inUse = false},
    [5] = {pos = vector4(1160.78, -1651.02, 35.92, 203.69), inUse = false},
    [6] = {pos = vector4(1118.26, -975.1, 45.49, 8.07), inUse = false},
    [7] = {pos = vector4(1100.01, -332.12, 66.21, 124.12), inUse = false},
    [8] = {pos = vector4(700.74, 254.74, 92.31, 237.35), inUse = false},
    [9] = {pos = vector4(177.77, 380.25, 108.03, 356.36), inUse = false},
    [10] = {pos = vector4(-1155.14, -228.36, 36.9, 314.13), inUse = false},
    [11] = {pos = vector4(320.33, -2034.69, 20.17, -38.61), inUse = false},
    [12] = {pos = vector4(-520.84, 574.89, 120.56, -78.21), inUse = false},
    [13] = {pos = vector4(-1452.84, -51.61, 52.75, 73.59), inUse = false},
    [14] = {pos = vector4(361.42, -2474.03, 5.90, -91.64), inUse = false},
    [15] = {pos = vector4(815.73, -2144.15, 28.81, -172.18), inUse = false},
    [16] = {pos = vector4(1300.98, -1736.43, 53.38, -159.24), inUse = false},
    [17] = {pos = vector4(1260.82, -1739.77, 49.13, 116.28), inUse = false},
    [18] = {pos = vector4(1228.02, -1606.06, 51.18, 35.05), inUse = false},
    [19] = {pos = vector4(1201.94, -1387.29, 34.72, 19.94), inUse = false},
    [20] = {pos = vector4(-1106.47, 791.78, 164.17, 13.24), inUse = false},
    [21] = {pos = vector4(-683.99, 602.62, 143.10, -31.46), inUse = false},
    [22] = {pos = vector4(318.58, 495.42, 152.24, -72.93), inUse = false},
    [23] = {pos = vector4(-2165.52, -277.60, 12.22, 157.83), inUse = false},
    [24] = {pos = vector4(-1539.14, -1004.59, 12.51, -104.60), inUse = false},
    [25] = {pos = vector4(-996.22, -1262.95, 5.27, -61.32), inUse = false},
    [26] = {pos = vector4(-135.45, -1971.81, 22.30, -61.32), inUse = false},
    [27] = {pos = vector4(-177.49, -2022.95, 27.12, -106.34), inUse = false},
    [28] = {pos = vector4(-3044.68, 112.43, 11.21, 138.63), inUse = false},
    [29] = {pos = vector4(1364.97, -2065.10, 51.49, 117.16), inUse = false},
    [30] = {pos = vector4(-1104.28, -1953.91, 12.65, 132.38), inUse = false}
}

return locations
```


# Shop

t1ger\_mechanic/shared/shop.lua

```lua
Config.Shop = {}

Config.Shop.Job = { -- Job Settings
    defaultGrades = {
        [0] = {grade = 0, name = "recruit", label = "Recruit", salary = 50},
        [1] = {grade = 1, name = "employee", label = "Employee", salary = 75},
        [2] = {grade = 2, name = "boss", label = "Boss", salary = 100},
        -- make sure boss grade is the very last one (higest grade)
    },
    defaultDuty = true, -- only qbcore/qbox
    offDutyPay = false, -- only qbcore/qbox
}

Config.Shop.JobAccount = true -- true = Use JobAccount system for society/shared account | false = Use our integrated account system

Config.Shop.Sale = true -- allow buy shops? And admins to list shop for_sale or cancel sale?

Config.Shop.Admin = {
    menu = { 
		enable = true, -- enable/disable admin mechanic menu?
		command = {enable = true, str = "mechanic:admin"}, -- enable/disable command
		keybind = {enable = true, default = "F10", description = "Mechanic Admin Menu"} -- enable/disable keybind
	},
}

Config.Shop.Creation = {
    command = {enable = true, str = "mechanic:create"}, -- enable/disable command to directly open creator interface?
    blip = { -- blip settings for shop blips
		input = true, -- allow admins to modify sprite & color in shop creator interface?
		sprite = 446, -- default sprite
		color = 5, -- default color
		display = 4, -- default display
		scale = 0.75 -- default scale 
	},
}

Config.Shop.Management = {
    command = {enable = true, str = "mechanic:manage"}, -- enable/disable command for admins to directly open management interface?
    markerEdit = true, -- set to false to disable option in admin management menu to edit marker. 
    markerTeleport = true, -- set to false to disable option in admin management menu to TP to marker.
}

Config.Shop.Storage = {
    slots = 50, -- default slots for created storage/stash
    weight = 100000, -- default weight for created storage/stash
    maxSlots = 500, -- max slots for editing storage/stash
    maxWeight = 999999 -- max weight for editing storage/stash
}

Config.Shop.MarkerSettings = {
    keybind = 38, -- Keybind for interacting with the marker. 
    distance = 5.0, -- distance to load/draw marker
    textUi = { -- UI settings for prompts.
        position = 'right-center',
        style = {borderRadius = 0, backgroundColor = '#48BB78', color = 'white'}
    },
}

Config.Shop.Markers = {
    duty = {
        title = "Duty",
        enable = true, -- Toggle this marker class on/off.
        icon = 'briefcase', -- Icon used for text UI and/or menu.
        blip = {sprite = 280, display = 4, scale = 0.65, color = 0} -- Blip settings.
    },

    boss = {
        title = "Boss",
        enable = true,
        icon = 'user-tie',
        blip = {sprite = 164, display = 4, scale = 0.65, color = 0}
    },

    garage = {
        title = "Garage",
        enable = true,
        icon = 'square-parking',
        blip = {sprite = 357, display = 4, scale = 0.65, color = 0}
    },

    storage = {
        title = "Storage",
        enable = true,
        icon = 'warehouse',
        blip = {sprite = 587, display = 4, scale = 0.65, color = 0}
    },

    workbench = {
        title = "Workbench",
        enable = true,
        icon = 'tools',
        blip = {sprite = 566, display = 4, scale = 0.65, color = 0}
    },

    supplier = {
        title = "Supplier",
        enable = true,
        icon = 'shopping-cart',
        blip = {sprite = 521, display = 4, scale = 0.65, color = 0}
    }
}

Config.Shop.Workbench = {
	enable = true, -- set to false to disable and add your own crafting export/event
	duration = 2500, -- duration in ms for crafting
	anim = {dict = 'mini@repair', clip = 'fixing_a_player', blendIn = 8.0, blendOut = -8.0, flag = 49},
	skillcheck = {enable = true, difficulty = {'easy', 'easy'}, inputs = {'w', 'a', 's', 'd'}},
    maxCraftAmount = 20, -- max allowed amount to craft of selected item.
    categories = require("shared/workbench") -- Load categories from the shared/workbench.lua file
}

Config.Shop.Supplier = {
    receiveInStash = true, -- `true` ordered items delivered to stash. `false` otherwise in player inventory
    playerPay = false, -- `true` player/mechanic pays for items. `false` shop account pays for items
    maxQuantity = 30, -- max quantity of an item that can be ordered.
    catalogue = require("shared/supplier") -- Load catalogue from the shared/supplier.lua file
}

Config.Shop.Billing = {
	enable = true, -- set to false to disable built in billing entirely
	command = {enable = true, name = 'billing'}, -- enable command to open billing interface
	actionMenu = {enable = true, icon = 'file-invoice-dollar'}, -- enable from action menu? icon for menu option
}
```


# Workbench

t1ger\_mechanic/shared/workbench.lua

## Crafting Categories

Our built in crafting system has a category system to easily craft the required items.

Each category will have:

* `label` (string) — the title of the category
* `description`(string) — the description of the category
* `icon` (string) — an icon for the category
* `recipe` (table) — the items to craft as index and recipe as the value.

## Recipes

The setup of a recipe is indexed by the item name you want to craft:

```lua
["t1ger_vehicledoor"] = { -- output item name
                icon = "https://i.postimg.cc/hvHDrP2S/t1ger-vehicledoor.png", -- output item icon
                materials = { -- materials to craft one piece
                    ["steel"] = 5, -- item name and required amount
                    ["plastic"] = 2, -- item name and required amount
                    ["rubber"] = 2, -- item name and required amount
                }
            },
```

* `icon` (string) — the icon of the item to craft
* `materials` (table) — the materials required to craft the item
  * `index` is the item name
  * `number` is the required amount of materials

You can add whatever items you like and require whatever materials and amount that fits your server.

```lua
return {
    { -- BODY PARTS
        label = "Body Parts",
        description = "Body Parts are used by mechanics to repair visuals of the vehicle.",
        icon = "https://i.postimg.cc/hvHDrP2S/t1ger-vehicledoor.png",
        recipe = {
            ["t1ger_vehicledoor"] = { -- output item name
                icon = "https://i.postimg.cc/hvHDrP2S/t1ger-vehicledoor.png", -- output item icon
                materials = { -- materials to craft one piece
                    ["steel"] = 5, -- item name and required amount
                    ["plastic"] = 2, -- item name and required amount
                    ["rubber"] = 2, -- item name and required amount
                }
            },
            ["t1ger_vehiclehood"] = {
                icon = "https://i.postimg.cc/5yH9LFq7/t1ger-vehiclehood.png",
                materials = {
                    ["steel"] = 6,
                    ["aluminium"] = 3,
                    ["rubber"] = 1,
                }
            },
            ["t1ger_vehicletrunk"] = {
                icon = "https://i.postimg.cc/WpK1jXTQ/t1ger-vehicletrunk.png",
                materials = {
                    ["steel"] = 5,
                    ["aluminium"] = 2,
                    ["plastic"] = 2,
                    ["rubber"] = 1,
                }
            },
            ["t1ger_vehiclewheel"] = {
                icon = "https://i.postimg.cc/15q5zwz4/t1ger-vehiclewheel.png",
                materials = {
                    ["steel"] = 4,
                    ["rubber"] = 5,
                    ["carbon_fiber"] = 2,
                    ["brass"] = 1,
                }
            },
            ["t1ger_vehiclewindow"] = {
                icon = "https://i.postimg.cc/pLMV5r9C/t1ger-vehiclewindow.png",
                materials = {
                    ["glass"] = 4,
                }
            },
        }
    },
    { -- CORE PARTS
        label = "Core Parts",
        description = "These parts are used by mechanics to repair worn, critical or failured parts.",
        icon = "https://i.postimg.cc/XY9JsdMt/t1ger-powersteeringpump.png",
        recipe = {
            ["t1ger_alternator"] = {
                icon = "https://i.postimg.cc/CM6z5wHr/t1ger-alternator.png",
                materials = {
                    ["steel"] = 5,
                    ["copper"] = 4,
                    ["electric_scrap"] = 3,
                }
            },
            ["t1ger_brakes"] = {
                icon = "https://i.postimg.cc/X7GXytsj/t1ger-brakes.png",
                materials = {
                    ["steel"] = 5,
                    ["rubber"] = 3,
                    ["brass"] = 2,
                }
            },
            ["t1ger_electricmotor"] = {
                icon = "https://i.postimg.cc/J0gn2QzC/t1ger-electricmotor.png",
                materials = {
                    ["steel"] = 8,
                    ["copper"] = 7,
                    ["electric_scrap"] = 6,
                    ["carbon_fiber"] = 4,
                }
            },
            ["t1ger_evbattery"] = {
                icon = "https://i.postimg.cc/ZKGnPjQr/t1ger-evbattery.png",
                materials = {
                    ["aluminium"] = 6,
                    ["copper"] = 5,
                    ["electric_scrap"] = 7,
                    ["acid"] = 5,
                }
            },
            ["t1ger_fuelinjector"] = {
                icon = "https://i.postimg.cc/Pqhq9JTJ/t1ger-fuelinjector.png",
                materials = {
                    ["steel"] = 4,
                    ["aluminium"] = 3,
                    ["plastic"] = 2,
                    ["electric_scrap"] = 2,
                }
            },
            ["t1ger_powersteeringpump"] = {
                icon = "https://i.postimg.cc/XY9JsdMt/t1ger-powersteeringpump.png",
                materials = {
                    ["steel"] = 8,
                    ["aluminium"] = 6,
                    ["synthetic_oil"] = 2,
                    ["electric_scrap"] = 3,
                }
            },
            ["t1ger_radiator"] = {
                icon = "https://i.postimg.cc/0NfNsvyf/t1ger-radiator.png",
                materials = {
                    ["steel"] = 6,
                    ["aluminium"] = 5,
                    ["plastic"] = 3,
                    ["synthetic_oil"] = 1,
                }
            },
            ["t1ger_transmission"] = {
                icon = "https://i.postimg.cc/bJwwY5Gj/t1ger-transmission.png",
                materials = {
                    ["steel"] = 10,
                    ["aluminium"] = 6,
                    ["synthetic_oil"] = 3,
                    ["brass"] = 2,
                }
            },
        }
    },
    { -- SERVICE PARTS
        label = "Service Parts",
        description = "These parts are used by mechanics to do service on vehicles.",
        icon = "https://i.postimg.cc/Y02YH874/t1ger-coolant.png",
        recipe = {
            ["t1ger_airfilter"] = {
                icon = "https://i.postimg.cc/hj1T66kW/t1ger-airfilter.png",
                materials = {
                    ["plastic"] = 2,
                    ["rubber"] = 1,
                }
            },
            ["t1ger_batterycoolant"] = {
                icon = "https://i.postimg.cc/26DnHrX7/t1ger-batterycoolant.png",
                materials = {
                    ["acid"] = 2,
                    ["plastic"] = 1,
                }
            },
            ["t1ger_brakefluid"] = {
                icon = "https://i.postimg.cc/jjNzQLvj/t1ger-brakefluid.png",
                materials = {
                    ["acid"] = 2,
                    ["synthetic_oil"] = 1,
                }
            },
            ["t1ger_brakepad"] = {
                icon = "https://i.postimg.cc/jSBH7zH9/t1ger-brakepad.png",
                materials = {
                    ["steel"] = 3,
                    ["rubber"] = 2,
                }
            },
            ["t1ger_coolant"] = {
                icon = "https://i.postimg.cc/Y02YH874/t1ger-coolant.png",
                materials = {
                    ["acid"] = 2,
                    ["plastic"] = 1,
                }
            },
            ["t1ger_drivebelt"] = {
                icon = "https://i.postimg.cc/bYL1TX01/t1ger-drivebelt.png",
                materials = {
                    ["rubber"] = 3,
                    ["steel"] = 2,
                }
            },
            ["t1ger_fuelfilter"] = {
                icon = "https://i.postimg.cc/3NLpJprt/t1ger-fuelfilter.png",
                materials = {
                    ["steel"] = 2,
                    ["plastic"] = 2,
                    ["rubber"] = 1,
                }
            },
            ["t1ger_hvwiring"] = {
                icon = "https://i.postimg.cc/g09hJGdb/t1ger-hvwiring.png",
                materials = {
                    ["copper"] = 5,
                    ["electric_scrap"] = 4,
                    ["carbon_fiber"] = 1,
                }
            },
            ["t1ger_oilfilter"] = {
                icon = "https://i.postimg.cc/bNBb7QBJ/t1ger-oilfilter.png",
                materials = {
                    ["steel"] = 2,
                    ["synthetic_oil"] = 1,
                    ["rubber"] = 1,
                }
            },
            ["t1ger_sparkplugs"] = {
                icon = "https://i.postimg.cc/NfMmCNbS/t1ger-sparkplugs.png",
                materials = {
                    ["steel"] = 2,
                    ["copper"] = 2,
                    ["electric_scrap"] = 1,
                }
            },
            ["t1ger_steeringfluid"] = {
                icon = "https://i.postimg.cc/rwRWMKB9/t1ger-steeringfluid.png",
                materials = {
                    ["synthetic_oil"] = 2,
                    ["acid"] = 1,
                }
            },
            ["t1ger_tires"] = {
                icon = "https://i.postimg.cc/BvxKPRQL/t1ger-tires.png",
                materials = {
                    ["rubber"] = 5,
                    ["steel"] = 2,
                }
            },
            ["t1ger_transmissionfluid"] = {
                icon = "https://i.postimg.cc/4dsh6wm8/t1ger-transmissionfluid.png",
                materials = {
                    ["synthetic_oil"] = 3,
                    ["acid"] = 1,
                }
            },
        }
    },
    { -- KITS
        label = "Kits",
        description = "Kits are used by mechanics for different stuff.",
        icon = "https://i.postimg.cc/W4jRTJDR/t1ger-carjack.png",
        recipe = {
            ["t1ger_repairkit"] = {
                icon = "https://i.postimg.cc/Tw7BV7tG/t1ger-repairkit.png",
                materials = {
                    ["steel"] = 3,
                    ["rubber"] = 2,
                    ["plastic"] = 2,
                    ["electric_scrap"] = 1,
                }
            },
            ["t1ger_repairkit_adv"] = {
                icon = "https://i.postimg.cc/9Xkvzk4Y/t1ger-repairkit-adv.png",
                materials = {
                    ["steel"] = 5,
                    ["rubber"] = 3,
                    ["plastic"] = 3,
                    ["electric_scrap"] = 2,
                    ["carbon_fiber"] = 1,
                }
            },
            ["t1ger_carjack"] = {
                icon = "https://i.postimg.cc/W4jRTJDR/t1ger-carjack.png",
                materials = {
                    ["steel"] = 8,
                    ["rubber"] = 4,
                    ["aluminium"] = 2,
                }
            },
            ["t1ger_patchkit"] = {
                icon = "https://i.postimg.cc/NFKSp6nX/t1ger-patchkit.png",
                materials = {
                    ["rubber"] = 5,
                    ["plastic"] = 2,
                    ["synthetic_oil"] = 1,
                }
            },
            ["t1ger_fuelcan"] = {
                icon = "https://i.postimg.cc/528chm2q/t1ger-fuelcan.png",
                materials = {
                    ["steel"] = 3,
                    ["plastic"] = 2,
                }
            },
            ["t1ger_jumpstarter"] = {
                icon = "https://i.postimg.cc/QtxRWGk0/t1ger-jumpstarter.png",
                materials = {
                    ["steel"] = 2,
                    ["electric_scrap"] = 3,
                    ["plastic"] = 2,
                    ["copper"] = 1,
                }
            },
            ["t1ger_repairkit_tire"] = {
                icon = "https://i.postimg.cc/6qFSS7sm/t1ger-repairkit-tire.png",
                materials = {
                    ["rubber"] = 4,
                    ["steel"] = 2,
                    ["synthetic_oil"] = 1,
                }
            },
            ["t1ger_diagnostictool"] = {
                icon = "https://i.postimg.cc/P5zPyYYN/t1ger-diagnostictool.png",
                materials = {
                    ["plastic"] = 5,
                    ["electric_scrap"] = 6,
                    ["copper"] = 4,
                    ["glass"] = 2,
                    ["carbon_fiber"] = 1,
                }
            },
            ["t1ger_servicebook"] = {
                icon = "https://i.postimg.cc/wxFCGD6f/t1ger-servicebook.png", -- placeholder image, replace if needed
                materials = {
                    ["plastic"] = 3,        -- for binding or cover
                    ["electric_scrap"] = 2, -- simulates digital storage or RFID
                    ["glass"] = 1,          -- maybe for display panel or screen
                    ["scrap_metal"] = 2     -- for casing or internal structure
                }
            }
        }
    },
    { -- PROPS
        label = "Props",
        description = "Props are used by mechanics to do different prop emotes.",
        icon = "https://i.postimg.cc/xdksrf5r/t1ger-roadbarrier.png",
        recipe = {
            ["t1ger_roadcone"] = {
                icon = "https://i.postimg.cc/8zzKHBrz/t1ger-roadcone.png",
                materials = {
                    ["plastic"] = 3,
                    ["rubber"] = 1,
                }
            },
            ["t1ger_toolstrolley"] = {
                icon = "https://i.postimg.cc/pTzqTs3q/t1ger-toolstrolley.png",
                materials = {
                    ["steel"] = 6,
                    ["rubber"] = 2,
                    ["plastic"] = 3,
                }
            },
            ["t1ger_toolbox"] = {
                icon = "https://i.postimg.cc/Jh9pMfYs/t1ger-toolbox.png",
                materials = {
                    ["steel"] = 4,
                    ["plastic"] = 2,
                }
            },
            ["t1ger_consign"] = {
                icon = "https://i.postimg.cc/kgYjh6xF/t1ger-consign.png",
                materials = {
                    ["steel"] = 3,
                    ["plastic"] = 2,
                }
            },
            ["t1ger_roadbarrier"] = {
                icon = "https://i.postimg.cc/xdksrf5r/t1ger-roadbarrier.png",
                materials = {
                    ["steel"] = 5,
                    ["plastic"] = 3,
                    ["rubber"] = 1,
                }
            },
        }
    },
}
```

## How to integrate my own crafting script?

To integrate your own crafting resource follow these steps.

{% stepper %}
{% step %}

### Disable the built-in crafting

Navigate to `t1ger_mechanic/shared/shop.lua` and find the option called `Config.Shop.Workbench` and set the `enable` value to `false`.
{% endstep %}

{% step %}

### Find function to modify

Navigate to `t1ger_mechanic/client/shop/markers/workbench.lua` and find the function called `WorkbenchMain`.
{% endstep %}

{% step %}

### Add your export or event

You will see this section:

```lua
    if not Config.Shop.Workbench.enable then
        -- add export/event to open your own crafting stuff 
    else
```

Inside the if statement, you can add your own export/event.
{% endstep %}
{% endstepper %}


# Supplier

t1ger\_mechanic/shared/supplier.lua

Our built in supplier system has categories to easily acquire the required items.

Each category will have:

* `title` (string) — the title of the category
* `icon` (string) — an icon for the category
* `items` (table) — the items to be listed in the category. Item name is the index of each entry and:
  * `price` (number) — the price of the item
  * `icon` (string) — the icon of the item

```lua
return {
    {
        title = "Body Parts", 
        icon = "https://i.postimg.cc/hvHDrP2S/t1ger-vehicledoor.png", 
        items = {
            ["t1ger_vehicledoor"] = {price = 200, icon = "https://i.postimg.cc/hvHDrP2S/t1ger-vehicledoor.png"},
            ["t1ger_vehiclehood"] = {price = 500, icon = "https://i.postimg.cc/5yH9LFq7/t1ger-vehiclehood.png"},
            ["t1ger_vehicletrunk"] = {price = 400, icon = "https://i.postimg.cc/WpK1jXTQ/t1ger-vehicletrunk.png"},
            ["t1ger_vehiclewindow"] = {price = 100, icon = "https://i.postimg.cc/pLMV5r9C/t1ger-vehiclewindow.png"},
            ["t1ger_vehiclewheel"] = {price = 300, icon = "https://i.postimg.cc/15q5zwz4/t1ger-vehiclewheel.png"}
        }
    },
    {
        title = "Core Parts",
        icon = "https://i.postimg.cc/CM6z5wHr/t1ger-alternator.png",
        items = {
            ["t1ger_alternator"] = {price = 600, icon = "https://i.postimg.cc/CM6z5wHr/t1ger-alternator.png"},
            ["t1ger_brakes"] = {price = 400, icon = "https://i.postimg.cc/X7GXytsj/t1ger-brakes.png"},
            ["t1ger_electricmotor"] = {price = 1200, icon = "https://i.postimg.cc/J0gn2QzC/t1ger-electricmotor.png"},
            ["t1ger_evbattery"] = {price = 1800, icon = "https://i.postimg.cc/ZKGnPjQr/t1ger-evbattery.png"},
            ["t1ger_fuelinjector"] = {price = 750, icon = "https://i.postimg.cc/Pqhq9JTJ/t1ger-fuelinjector.png"},
            ["t1ger_powersteeringpump"] = {price = 900, icon = "https://i.postimg.cc/XY9JsdMt/t1ger-powersteeringpump.png"},
            ["t1ger_radiator"] = {price = 500, icon = "https://i.postimg.cc/0NfNsvyf/t1ger-radiator.png"},
            ["t1ger_transmission"] = {price = 1600, icon = "https://i.postimg.cc/bJwwY5Gj/t1ger-transmission.png"},
        }
    },
    {
        title = "Service Parts",
        icon = "https://i.postimg.cc/Y02YH874/t1ger-coolant.png",
        items = {
            ["t1ger_airfilter"] = {price = 150, icon = "https://i.postimg.cc/hj1T66kW/t1ger-airfilter.png"},
            ["t1ger_batterycoolant"] = {price = 70, icon = "https://i.postimg.cc/26DnHrX7/t1ger-batterycoolant.png"},
            ["t1ger_brakefluid"] = {price = 60, icon = "https://i.postimg.cc/jjNzQLvj/t1ger-brakefluid.png"},
            ["t1ger_brakepad"] = {price = 140, icon = "https://i.postimg.cc/jSBH7zH9/t1ger-brakepad.png"},
            ["t1ger_coolant"] = {price = 40, icon = "https://i.postimg.cc/Y02YH874/t1ger-coolant.png"},
            ["t1ger_drivebelt"] = {price = 200, icon = "https://i.postimg.cc/bYL1TX01/t1ger-drivebelt.png"},
            ["t1ger_fuelfilter"] = {price = 250, icon = "https://i.postimg.cc/3NLpJprt/t1ger-fuelfilter.png"},
            ["t1ger_hvwiring"] = {price = 420, icon = "https://i.postimg.cc/g09hJGdb/t1ger-hvwiring.png"},
            ["t1ger_oilfilter"] = {price = 200, icon = "https://i.postimg.cc/bNBb7QBJ/t1ger-oilfilter.png"},
            ["t1ger_sparkplugs"] = {price = 350, icon = "https://i.postimg.cc/NfMmCNbS/t1ger-sparkplugs.png"},
            ["t1ger_steeringfluid"] = {price = 80, icon = "https://i.postimg.cc/rwRWMKB9/t1ger-steeringfluid.png"},
            ["t1ger_tires"] = {price = 100, icon = "https://i.postimg.cc/BvxKPRQL/t1ger-tires.png"},
            ["t1ger_transmissionfluid"] = {price = 90, icon = "https://i.postimg.cc/4dsh6wm8/t1ger-transmissionfluid.png"}
        }
    },
    {
        title = "Kits",
        icon = "https://i.postimg.cc/W4jRTJDR/t1ger-carjack.png",
        items = {
            ["t1ger_repairkit"] = {price = 1500, icon = "https://i.postimg.cc/Tw7BV7tG/t1ger-repairkit.png"},
            ["t1ger_repairkit_adv"] = {price = 3000, icon = "https://i.postimg.cc/9Xkvzk4Y/t1ger-repairkit-adv.png"},
            ["t1ger_carjack"] = {price = 2500, icon = "https://i.postimg.cc/W4jRTJDR/t1ger-carjack.png"},
            ["t1ger_patchkit"] = {price = 2000, icon = "https://i.postimg.cc/NFKSp6nX/t1ger-patchkit.png"},
            ["t1ger_fuelcan"] = {price = 300, icon = "https://i.postimg.cc/528chm2q/t1ger-fuelcan.png"},
            ["t1ger_jumpstarter"] = {price = 400, icon = "https://i.postimg.cc/QtxRWGk0/t1ger-jumpstarter.png"},
            ["t1ger_repairkit_tire"] = {price = 500, icon = "https://i.postimg.cc/6qFSS7sm/t1ger-repairkit-tire.png"},
            ["t1ger_diagnostictool"] = {price = 1000, icon = "https://i.postimg.cc/P5zPyYYN/t1ger-diagnostictool.png"},
            ["t1ger_servicebook"] = {price = 100, icon = "https://i.postimg.cc/wxFCGD6f/t1ger-servicebook.png"}
        }
    },
    {
        title = "Props",
        icon = "https://i.postimg.cc/xdksrf5r/t1ger-roadbarrier.png",
        items = {
            ["t1ger_roadcone"] = {price = 50, icon = "https://i.postimg.cc/8zzKHBrz/t1ger-roadcone.png"},
            ["t1ger_toolstrolley"] = {price = 200, icon = "https://i.postimg.cc/pTzqTs3q/t1ger-toolstrolley.png"},
            ["t1ger_toolbox"] = {price = 100, icon = "https://i.postimg.cc/Jh9pMfYs/t1ger-toolbox.png"},
            ["t1ger_consign"] = {price = 150, icon = "https://i.postimg.cc/kgYjh6xF/t1ger-consign.png"},
            ["t1ger_roadbarrier"] = {price = 600, icon = "https://i.postimg.cc/xdksrf5r/t1ger-roadbarrier.png"}
        }
    }
}
```


# Parts

t1ger\_mechanic/shared/parts.lua

## Body Parts

{% hint style="info" %}
These parts are used to replace/repair parts on vehicles during body repairs.
{% endhint %}

```lua
Config.BodyParts = {
    door = {
        item = "t1ger_vehicledoor",
        label = "Vehicle Door",
        icon = "https://i.postimg.cc/hvHDrP2S/t1ger-vehicledoor.png",
        prop = {model = "imp_prop_impexp_car_door_04a", pos = vector3(-0.7, -0.2, 0.0), rot = vector3(0.0, -10.0, 90.0), boneId = 28422},
        anim = {dict = "anim@amb@clubhouse@tutorial@bkr_tut_ig3@", clip = "machinic_loop_mechandplayer", duration = -1, blendIn = 2.0, blendOut = 2.0, flag = 1}
    },
    hood = {
        item = "t1ger_vehiclehood",
        label = "Vehicle Hood",
        icon = "https://i.postimg.cc/5yH9LFq7/t1ger-vehiclehood.png",
        prop = {model = "imp_prop_impexp_bonnet_04a", pos = vector3(0.0, 0.20, 0.12), rot = vector3(-20.0, 0.0, 180.0), boneId = 28422},
        anim = {dict = "mini@repair", clip = "fixing_a_player", duration = -1, blendIn = 2.0, blendOut = 2.0, flag = 1}
    },
    trunk = {
        item = "t1ger_vehicletrunk",
        label = "Vehicle Trunk",
        icon = "https://i.postimg.cc/WpK1jXTQ/t1ger-vehicletrunk.png",
        prop = {model = "imp_prop_impexp_trunk_01a", pos = vector3(0.0, 0.15, 0.1), rot = vector3(30.0, 0.0, 0.0), boneId = 28422},
        anim = {dict = "mini@repair", clip = "fixing_a_player", duration = -1, blendIn = 2.0, blendOut = 2.0, flag = 1}
    },
    wheel = {
        item = "t1ger_vehiclewheel",
        label = "Vehicle Wheel",
        icon = "https://i.postimg.cc/15q5zwz4/t1ger-vehiclewheel.png",
        prop = {model = "imp_prop_impexp_tyre_01c", pos = vector3(0.0, -0.1, 0.2), rot = vector3(0.0, 0.0, 0.0), boneId = 28422},
        anim = {dict = "anim@amb@clubhouse@tutorial@bkr_tut_ig3@", clip = "machinic_loop_mechandplayer", duration = -1, blendIn = 2.0, blendOut = 2.0, flag = 1}
    },
    window = {
        item = "t1ger_vehiclewindow",
        label = "Vehicle Window",
        icon = "https://i.postimg.cc/pLMV5r9C/t1ger-vehiclewindow.png",
        prop = {model = "h4_prop_yacht_glass_04", pos = vector3(0.0, -0.1, 0.3), rot = vector3(0.0, 0.0, 0.0), boneId = 28422},
        anim = {dict = "missmechanic", clip = "work_in", duration = -1, blendIn = 2.0, blendOut = 2.0, flag = 1}
    },
}
```

* `item` (string) — the item name for the body part
* `label` (string) — the label of the body part
* `icon` (string) — the icon for the body part
* `prop` (table) — the prop settings for the body part, used during replacements/repairs
  * `model` (string) — the prop model
  * `pos` (vector3) — the position offset on the player when attached
  * `rot` (vector3) — the rotation offset on the player when attached
  * `boneId` (number) — the boneId on the player to attach the prop
* `anim` (table) — the animations settings for the body part, used during replacements/repairs.
  * `dict` (string) — the animation dictonary
  * `clip` (string) — the animation clip/name
  * `duration` (number) — the duration of the anim. Must be `-1`
  * `blendIn` (number) — the blend in speed of the animation
  * `blendOut` (number) — the blend out speed of the animation
  * `flag` (integer) — the flag for the animation. Recommended to use `1`

## Service Parts

{% hint style="info" %}
These parts needs to be maintained within their service interval, otherwise they affect associated core parts.
{% endhint %}

```lua
Config.ServiceParts = {
    air_filter = {
        item = "t1ger_airfilter",
        label = "Air Filter",
        icon = "https://i.postimg.cc/hj1T66kW/t1ger-airfilter.png",
        interval = 8000,
        associated = {"fuel_injector"},
        type = "gas",
        prop = {model = "t1ger_airfilter", pos = vector3(0.0, 0.0, 0.0), rot = vector3(0.0, 120.0, 0.0), boneId = 60309},
    },
    battery_coolant = {
        item = "t1ger_batterycoolant",
        label = "Battery Coolant",
        icon = "https://i.postimg.cc/26DnHrX7/t1ger-batterycoolant.png",
        interval = 20000,
        associated = {"ev_battery"},
        type = "electric",
        prop = {model = "t1ger_batterycoolant", pos = vector3(0.0, 0.0, -0.1), rot = vector3(0.0, 0.0, 25.0), boneId = 28422, small = true},
    },
    brake_fluid = {
        item = "t1ger_brakefluid",
        label = "Brake Fluid",
        icon = "https://i.postimg.cc/jjNzQLvj/t1ger-brakefluid.png",
        interval = 15000,
        associated = {"brakes"},
        type = "shared",
        prop = {model = "t1ger_brakefluid", pos = vector3(-0.03, 0.03, 0.0), rot = vector3(-90.0, -40.0, -150.0), boneId = 60309},
    },
    brake_pad = {
        item = "t1ger_brakepad",
        label = "Brake Pads",
        icon = "https://i.postimg.cc/jSBH7zH9/t1ger-brakepad.png",
        interval = 10000,
        associated = {"brakes"},
        type = "gas",
        prop = {model = "t1ger_brakepad", pos = vector3(0.0, 0.0, 0.0), rot = vector3(-40.0, 0.0, 0.0), boneId = 60309},
    },
    coolant = {
        item = "t1ger_coolant",
        label = "Coolant",
        icon = "https://i.postimg.cc/Y02YH874/t1ger-coolant.png",
        interval = 15000,
        associated = {"radiator"},
        type = "gas",
        prop = {model = "t1ger_coolant", pos = vector3(0.0, 0.0, -0.1), rot = vector3(0.0, 0.0, 25.0), boneId = 28422, small = true},
    },
    drive_belt = {
        item = "t1ger_drivebelt",
        label = "Drive Belt",
        icon = "https://i.postimg.cc/bYL1TX01/t1ger-drivebelt.png",
        interval = 20000,
        associated = {"alternator", "radiator"},
        type = "gas",
        prop = {model = "t1ger_drivebelt", pos = vector3(0.0, 0.0, 0.0), rot = vector3(0.0, 0.0, 0.0), boneId = 60309},
    },
    fuel_filter = {
        item = "t1ger_fuelfilter",
        label = "Fuel Filter",
        icon = "https://i.postimg.cc/3NLpJprt/t1ger-fuelfilter.png",
        interval = 12000,
        associated = {"fuel_injector"},
        type = "gas",
        prop = {model = "t1ger_fuelfilter", pos = vector3(0.0, 0.0, 0.0), rot = vector3(0.0, 120.0, 0.0), boneId = 60309},
    },
    hv_wiring = {
        item = "t1ger_hvwiring",
        label = "High-Voltage Wiring",
        icon = "https://i.postimg.cc/g09hJGdb/t1ger-hvwiring.png",
        interval = 25000,
        associated = {"electric_motor"},
        type = "electric",
        prop = {model = "t1ger_hvwiring", pos = vector3(0.0, 0.0, 0.0), rot = vector3(90.0, 0.0, 0.0), boneId = 60309},
    },
    oil_filter = {
        item = "t1ger_oilfilter",
        label = "Oil + Filter",
        icon = "https://i.postimg.cc/bNBb7QBJ/t1ger-oilfilter.png",
        interval = 5000,
        associated = {"fuel_injector", "transmission"},
        type = "gas",
        prop = {model = "t1ger_oilfilter", pos = vector3(0.0, 0.0, 0.0), rot = vector3(90.0, 0.0, 0.0), boneId = 60309},
    },
    spark_plugs = {
        item = "t1ger_sparkplugs",
        label = "Spark Plugs",
        icon = "https://i.postimg.cc/NfMmCNbS/t1ger-sparkplugs.png",
        interval = 15000,
        associated = {"fuel_injector"},
        type = "gas",
        prop = {model = "t1ger_sparkplugs", pos = vector3(-0.03, 0.0, 0.0), rot = vector3(0.0, 120.0, 0.0), boneId = 60309},
    },
    steering_fluid = {
        item = "t1ger_steeringfluid",
        label = "Power Steering Fluid",
        icon = "https://i.postimg.cc/rwRWMKB9/t1ger-steeringfluid.png",
        interval = 20000,
        associated = {"power_steering_pump"},
        type = "gas",
        prop = {model = "t1ger_steeringfluid", pos = vector3(-0.03, 0.03, 0.0), rot = vector3(-90.0, -40.0, -150.0), boneId = 60309},
    },
    tires = {
        item = "t1ger_tires",
        label = "Tires",
        icon = "https://i.postimg.cc/BvxKPRQL/t1ger-tires.png",
        interval = 50000,
        associated = {},
        type = "shared",
        prop = {model = "t1ger_tires", pos = vector3(0.0, -0.05, 0.0), rot = vector3(0.0, -90.0, -90.0), boneId = 28422},
    },
    transmission_fluid = {
        item = "t1ger_transmissionfluid",
        label = "Transmission Fluid",
        icon = "https://i.postimg.cc/4dsh6wm8/t1ger-transmissionfluid.png",
        interval = 25000,
        associated = {"transmission"},
        type = "gas",
        prop = {model = "t1ger_transmissionfluid", pos = vector3(-0.03, 0.03, 0.0), rot = vector3(-90.0, -40.0, -150.0), boneId = 60309},
    },
}
```

Each service part has the following:

* `item` (string) — the item name for the service part
* `label` (string) — the label of the service part
* `icon` (string) — the icon for the service part
* `interval` (string) — the service interval before requiring replacement
* `associated` (array) — the list of associated core parts that are affected on neglected maintenance
* `type` (string) — select between `"gas"`, `"electric"` or `"shared"`. Defines which type of vehicle this part is tracked on.
* `prop` (table) — the prop settings for the service part, used during replacements/repairs
  * `model` (string) — the prop model
  * `pos` (vector3) — the position offset on the player when attached
  * `rot` (vector3) — the rotation offset on the player when attached
  * `boneId` (number) — the boneId on the player to attach the prop

## Core Parts

{% hint style="info" %}
These parts are vital components of the vehicle. If worn, critical or failed they affect the vehicle performance or entirely disable the vehicle.
{% endhint %}

```lua
Config.CoreParts = {
    alternator = {
        item = "t1ger_alternator",
        label = "Alternator",
        icon = "https://i.postimg.cc/CM6z5wHr/t1ger-alternator.png",
        associated = {"drive_belt"},
        type = "gas",
        prop = {model = "t1ger_alternator", pos = vector3(0.0, 0.0, 0.0), rot = vector3(90.0, 120.0, 0.0), boneId = 60309},
    },
    brakes = {
        item = "t1ger_brakes",
        label = "Brakes",
        icon = "https://i.postimg.cc/X7GXytsj/t1ger-brakes.png",
        associated = {"brake_fluid", "brake_pads"},
        type = "shared",
        prop = {model = "t1ger_brakes", pos = vector3(0.0, 0.0, 0.0), rot = vector3(0.0, 0.0, -90.0), boneId = 60309},
    },
    electric_motor = {
        item = "t1ger_electricmotor",
        label = "Electric Motor",
        icon = "https://i.postimg.cc/J0gn2QzC/t1ger-electricmotor.png",
        associated = {"hv_wiring"},
        type = "electric",
        prop = {model = "t1ger_electricmotor", pos = vector3(0.0, 0.0, -0.1), rot = vector3(90.0, 0.0, 0.0), boneId = 60309},
    },
    ev_battery = {
        item = "t1ger_evbattery",
        label = "EV Battery",
        icon = "https://i.postimg.cc/ZKGnPjQr/t1ger-evbattery.png",
        associated = {"battery_coolant"},
        type = "electric",
        prop = {model = "t1ger_evbattery", pos = vector3(-0.01, -0.1, -0.13), rot = vector3(0.0, -2.0, 0.0), boneId = 28422},  -- texture fix
    },
    fuel_injector = {
        item = "t1ger_fuelinjector",
        label = "Fuel Injector",
        icon = "https://i.postimg.cc/Pqhq9JTJ/t1ger-fuelinjector.png",
        associated = {"oil_filter", "air_filter", "fuel_filter", "spark_plugs"},
        type = "gas",
        prop = {model = "t1ger_fuelinjector", pos = vector3(0.0, 0.0, 0.0), rot = vector3(0.0, -90.0, 0.0), boneId = 60309},
    },
    power_steering_pump = {
        item = "t1ger_powersteeringpump",
        label = "Power Steering Pump",
        icon = "https://i.postimg.cc/XY9JsdMt/t1ger-powersteeringpump.png",
        associated = {"steering_fluid"},
        type = "gas",
        prop = {model = "t1ger_powersteeringpump", pos = vector3(0.0, -0.12, 0.10), rot = vector3(120.0, 0.0, 0.0), boneId = 60309},
    },
    radiator = {
        item = "t1ger_radiator",
        label = "Radiator",
        icon = "https://i.postimg.cc/0NfNsvyf/t1ger-radiator.png",
        associated = {"coolant", "drive_belt"},
        type = "gas",
        prop = {model = "t1ger_radiator", pos = vector3(0.0, -0.1, 0.1), rot = vector3(0.0, 0.0, 0.0), boneId = 28422},
    },
    transmission = {
        item = "t1ger_transmission",
        label = "Transmission",
        icon = "https://i.postimg.cc/bJwwY5Gj/t1ger-transmission.png",
        associated = {"oil_filter", "transmission_fluid"},
        type = "gas",
        prop = {model = "t1ger_transmission", pos = vector3(-0.1, -0.1, -0.03), rot = vector3(0.0, -10.0, -90.0), boneId = 28422},
    }
}
```

Each core part has the following:

* `item` (string) — the item name for the service part
* `label` (string) — the label of the service part
* `icon` (string) — the icon for the service part
* `associated` (array) — the list of associated service parts that will affect this part on neglected maintenance
* `type` (string) — select between `"gas"`, `"electric"` or `"shared"`. Defines which type of vehicle this part is tracked on.
* `prop` (table) — the prop settings for the service part, used during replacements/repairs
  * `model` (string) — the prop model
  * `pos` (vector3) — the position offset on the player when attached
  * `rot` (vector3) — the rotation offset on the player when attached
  * `boneId` (number) — the boneId on the player to attach the prop

## Materials

{% hint style="info" %}
These are the defined materials used throughout the script. You can add, edit or remove as you please. Make sure to update accordingly in the [Workbench](/resources/t1ger-mechanic/configuration/shop/workbench) if using our built-in crafting system.
{% endhint %}

```lua
Config.Materials = { -- index is item name and value is item label.
    scrap_metal = "Scrap Metal",
    steel = "Steel",
    aluminium = "Aluminium",
    plastic = "Plastic",
    rubber = "Rubber",
    electric_scrap = "Electric Scrap",
    glass = "Glass",
    copper = "Copper",
    carbon_fiber = "Carbon Fiber",
    brass = "Brass",
    synthetic_oil = "Synthetic Oil",
    acid = "Acid"
}
```

Index is the item name and value is the item label.


# Exports

In this section you'll find various exports & events to be used/integrated with other 3rd party resources.

{% content-ref url="/pages/Dqen0MPYOmke2f3sPdTh" %}
[Server](/resources/t1ger-mechanic/exports/server)
{% endcontent-ref %}

{% content-ref url="/pages/gwK1m2YywjH23Ou1NvOz" %}
[Client](/resources/t1ger-mechanic/exports/client)
{% endcontent-ref %}


# Server

Server-sided exports

## **TrimPlate**

Trims a given plate.&#x20;

```lua
exports["t1ger_mechanic"]:TrimPlate(plate)
```

#### **Parameters**

* **`plate`***(string)* – The vehicle number plate.

#### **Returns**

* `string` – The trimmed plate.

***

## **IsPlayerEmployee**

Checks if player is an employee of a specific shop or any shop.

```lua
exports["t1ger_mechanic"]:IsPlayerEmployee(src, shopId)
```

#### **Parameters**

* **`src`***(number)* – The player source.
* **`shopId?`***(number)* – The ID of the shop you check for. If shopId is nil, it checks all shops.

#### **Returns**

* `boolean` – `true` if employee, otherwise `false`.
* `number|nil`– If employee, then Shop ID is also returne, otherwise `nil`.

***

## IsPlayerMechanicBoss

Checks whether a player is a boss-grade mechanic in a specific mechanic shop or any shop.

```lua
exports["t1ger_mechanic"]:IsPlayerMechanicBoss(src, shopId)
```

**Parameters**

* `src` (`number`) – The player's source ID.
* `shopId` (`number|nil`) – *(Optional)* Specific shop ID to check. If omitted, all shops are checked.

**Returns**

* `boolean` – `true` if the player is a boss-grade mechanic, otherwise `false`.
* `number|nil` – Shop ID where the player is a boss, or `nil` if not applicable.

***

## IsPlayerShopOwner

Checks whether a player is the owner of a specific mechanic shop or any shop.

```lua
exports["t1ger_mechanic"]:IsPlayerShopOwner(src, shopId)
```

**Parameters**

* `src` (`number`) – The player's source ID.
* `shopId` (`number|nil`) – *(Optional)* Specific shop ID to check. If omitted, all shops are checked.

**Returns**

* `boolean` – `true` if the player is the owner of a shop, otherwise `false`.
* `number|nil` – Shop ID the player owns, or `nil` if not applicable.

***

## **RegisterVehicleData**

Registers mileage, core- and service-parts data to database in t1ger\_vehicledata table for a given plate. This can be used when purchasing a car from vehicleshop or using command to turn a vehicle into an owned one.

```lua
exports["t1ger_mechanic"]:RegisterVehicleData(plate)
```

#### **Parameters**

* **`plate`***(string)* – The plate of the vehicle.

***

## **SaveVehicleData**

Saves the vehicle's vehicle-data for given vehicle entity in `t1ger_vehicledata` table in database. Useful if u want to force save a vehicle's vehicle-data.

```lua
exports["t1ger_mechanic"]:SaveVehicleData(vehicle)
```

#### **Parameters**

* **`vehicle`***(integer)* – The vehicle entity handle

#### **Returns**

* `boolean` – `true` if saved succesfully, otherwise `false`.

***

## **UpdateVehicleDataPlate**

Updates a given plate in the `t1ger_vehicledata` table to a new plate. Usefull if using fake plates or plate changer scripts and so on.

```lua
exports["t1ger_mechanic"]:UpdateVehicleDataPlate(currentPlate, newPlate)
```

#### **Parameters**

* **`currentPlate`***(string)* – The current plate to be replaced by `newPlate`
* **`newPlate`***(string)* – The new plate to replace with the `currentPlate`

#### **Returns**

* `boolean` – `true` if updated succesfully, otherwise `false`.

***

## AddServiceHistory

Adds a new service history entry to the `t1ger_servicehistory` table in the database for a given vehicle plate.\
This should be used whenever a mechanic performs service on a part and you want to log the action along with mileage, mechanic, and shop data.

```lua
exports["t1ger_mechanic"]:AddServiceHistory(plate, part, mileage, mechanic, shop)
```

**Parameters**

* `plate` (`string`) – The plate of the vehicle.
* `part` (`string`) – The label of the part that was serviced.
* `mileage` (`number`) – The vehicle's mileage at the time of service.
* `mechanic` (`string`) – Identifier of the mechanic who performed the service.
* `shop` (`string`) – Label of the shop or job where the service took place.

**Returns**

* `boolean` – `true` if the history entry was successfully inserted, otherwise `false`.

{% hint style="info" %}

* Only works on vehicles that are already registered (owned).
* Automatically adds the current date (`YYYY-MM-DD`) to the entry.
  {% endhint %}

***

## GetVehicleServiceHistory

Retrieves all recorded service history entries for a specific vehicle plate from the `t1ger_servicehistory` table.\
Only works on owned vehicles and returns entries in reverse chronological order.

```lua
exports["t1ger_mechanic"]:GetVehicleServiceHistory(plate)
```

**Parameters**

* `plate` (`string`) – The plate of the vehicle.

**Returns**

* `table|nil` – A table of service history entries if found, otherwise `nil`.

Each entry contains:

```lua
{
    id = number,
    part = string,
    mileage = number,
    mechanic = string,
    shop = string,
    date = string -- format: YYYY-MM-DD
}
```

***


# Client

Client-sided exports

## **IsVehicleOnCarJack**

Returns whether a given vehicle entity is on a car jack or not.

```lua
exports["t1ger_mechanic"]:IsVehicleOnCarJack(vehicle)
```

#### **Parameters**

* **`vehicle`***(number)* – The vehicle entity handle.

#### **Returns**

* `boolean` – `true` if vehicle is on car jack, otherwise `false`.

***

## IsWorkflowActive

Returns whether the mechanic workflow UI is currently active and open.

```lua
exports["t1ger_mechanic"]:IsWorkflowActive()
```

**Returns**

* `boolean` – `true` if the workflow UI is open, otherwise `false`.

***

## CreateCarLift

Spawns a car lift at the player's current position and rotation, then triggers the server to create and sync it for all clients.

```lua
exports["t1ger_mechanic"]:CreateCarLift()
```

***

## IsCarryingBodyPart

Checks whether the player is currently carrying a body part prop (e.g., door, hood, etc.).

```lua
exports["t1ger_mechanic"]:IsCarryingBodyPart()
```

**Returns**

* `boolean` – `true` if the player is carrying a body part, otherwise `false`.

***

## IsCarryingComponent

Checks whether the player is currently carrying a component prop (core or service part).

```lua
exports["t1ger_mechanic"]:IsCarryingComponent()
```

**Returns**

* `boolean` – `true` if the player is carrying a component, otherwise `false`.

***

## IsPlayerInspectingVehicle

Returns whether the local player is currently inspecting a vehicle body.

```lua
exports["t1ger_mechanic"]:IsPlayerInspectingVehicle()
```

**Returns**

* `boolean` – Returns `true` if the player is currently in a body inspection, `false` otherwise.

**Example**

```lua
if exports["t1ger_mechanic"]:IsPlayerInspectingVehicle() then
    -- block other actions during inspection
end
```

***

## CancelBodyPartInstallation

Cancels an ongoing body part installation.\
Clears the player's animation and deletes any carried body part prop.

```lua
exports["t1ger_mechanic"]:CancelBodyPartInstallation()
```

***

## CancelComponentRepair

Cancels an in-progress component repair by removing any carried props and clearing the player's tasks.

```lua
exports["t1ger_mechanic"]:CancelComponentRepair()
```

***

## CancelInspection

Cancels an ongoing vehicle body inspection by setting the internal inspection flag.

```lua
exports["t1ger_mechanic"]:CancelInspection()
```

***

## QuickRepair

Fully repairs the vehicle the player is currently inside, including body, engine, and optionally fuel and part states based on config settings.

```lua
exports["t1ger_mechanic"]:QuickRepair()
```

***

## CreateShop

Opens the admin-only shop creation interface to create a new mechanic shop at the player’s current location.

```lua
exports["t1ger_mechanic"]:CreateShop(returnMenu)
```

**Parameters**

* `returnMenu` (`string`, optional) – The `ox_lib` context menu ID to return to if the dialog is canceled.

{% hint style="warning" %}
Only works for players with admin permissions (`_API.Player.isAdmin` must return `true`).
{% endhint %}

***

## ViewShops

Displays a list of all mechanic shops in a context menu using `ox_lib`.

```lua
exports["t1ger_mechanic"]:ViewShops(returnMenu)
```

**Parameters**

* `returnMenu` (`string`) – Menu ID to return to if no shops exist or the list is exited.

***

## BillingMain

Opens the mechanic shop billing interface for viewing and/or creating invoices.\
Only available to mechanic players if billing is enabled in the config.

```lua
exports["t1ger_mechanic"]:BillingMain(returnMenu)
```

**Parameters**

* `returnMenu` (`string`, optional) – Menu ID to return to if the billing interface is exited.

***

## IsPlayerEmployee

Checks whether the local player is employed at a specific mechanic shop or any shop.

```lua
exports["t1ger_mechanic"]:IsPlayerEmployee(shopId)
```

**Parameters**

* `shopId` (`number|nil`) – *(Optional)* Shop ID to check. If omitted, all shops are checked.

**Returns**

* `boolean` – `true` if the player is an employee, otherwise `false`.
* `number|nil` – The ID of the shop the player is employed at, or `nil` if not found.

***

## IsPlayerMechanic

Checks whether the local player has a mechanic job assigned to any registered shop.

```lua
exports["t1ger_mechanic"]:IsPlayerMechanic(shopId)
```

**Parameters**

* `shopId` (`number|nil`) – *(Optional)* Shop ID to check. If omitted, all shops are checked.

**Returns**

* `boolean` – `true` if the player has a mechanic job, otherwise `false`.
* `number|nil` – The ID of the matching shop, or `nil` if not found.

***

## IsPlayerMechanicBoss

Checks whether the local player holds a boss-grade mechanic job in a specific shop or any shop.

```lua
exports["t1ger_mechanic"]:IsPlayerMechanicBoss(shopId)
```

**Parameters**

* `shopId` (`number|nil`) – *(Optional)* Shop ID to check. If omitted, all shops are checked.

**Returns**

* `boolean` – `true` if the player is a boss-grade mechanic, otherwise `false`.
* `number|nil` – The ID of the shop where the player is a boss, or `nil` if not found.

***

## IsPlayerShopOwner

Checks whether the local player is the owner of a specific mechanic shop or any shop.

```lua
exports["t1ger_mechanic"]:IsPlayerShopOwner(shopId)
```

**Parameters**

* `shopId` (`number|nil`) – *(Optional)* Shop ID to check. If omitted, all shops are checked.

**Returns**

* `boolean` – `true` if the player is the owner of a shop, otherwise `false`.
* `number|nil` – The ID of the shop the player owns, or `nil` if not found.

***

## **IsPlayerDiagnosing**

Returns whether the player is currently diagnosing or inspecting a vehicle.

```lua
exports["t1ger_mechanic"]:IsPlayerDiagnosing()
```

#### **Returns**

* `boolean`

***

## GetVehicleData

Retrieves stored mechanic data for a given vehicle from its statebag.

```lua
exports["t1ger_mechanic"]:GetVehicleData(vehicle)
```

**Parameters**

* `vehicle` (`integer`) – The vehicle entity handle.

**Returns**

* `table|nil` – Returns a table containing vehicle data if found, otherwise `nil`.
* Returned structure:

  ```
  {
      mileage = number, -- total mileage in km
      service_parts = {
          [partName] = number, -- mileage since last replacement
          ...
      },
      core_parts = {
          [partName] = number, -- health (0–100)
          ...
      }
  }
  ```

***

## SetVehicleData

Sets or updates mechanic data for a vehicle using the statebag. Validates the structure before applying.

```lua
exports["t1ger_mechanic"]:SetVehicleData(vehicle, data, replicate)
```

**Parameters**

* `vehicle` (`integer`) – The vehicle entity handle.
* `data` (`table`) – Vehicle data to apply (must include `mileage`, `service_parts`, and `core_parts`).
* `replicate` (`boolean`) – *(Optional)* Whether to replicate the state to clients. Defaults to `true`.

**Returns**

* `boolean` – `true` if the data was set successfully, otherwise throws an error.
* Expected `data` structure:

  ```lua
  {
      mileage = number,
      service_parts = {
          [partName] = number
      },
      core_parts = {
          [partName] = number
      }
  }
  ```

***

## **IsVehicleDataReady**

Returns whether a vehicle's data statebag has been populated and is ready to use. Call this before using `SetVehicleMileage`, `SetCorePartHealth`, `SetServicePartMileage` or any other statebag-dependent export to avoid silent failures.

```lua
exports["t1ger_mechanic"]:IsVehicleDataReady(vehicle)
```

**Parameters**

* `vehicle` ( `integer` ) – The vehicle entity handle.

**Returns**

* `boolean` – Returns `true` if the vehicle's data statebag is populated and ready, `false` otherwise.

**Example**

```lua
if exports["t1ger_mechanic"]:IsVehicleDataReady(vehicle) then
    exports["t1ger_mechanic"]:SetVehicleMileage(vehicle, 1000)
end
```

***

## SaveVehicleData

Saves vehicle data client-side and sends it to the server for persistence.

```lua
exports["t1ger_mechanic"]:SaveVehicleData(vehicle)
```

#### Parameters

* `vehicle` *(number)* – The vehicle entity handle (must be valid and exist).

{% hint style="info" %}
Intended for use in garage scripts that delete the vehicle before the server can catch it (e.g., `entityRemoved` not triggered in time).
{% endhint %}

***

## **GetVehicleMileage**

Returns the current mileage of a given vehicle entity.

```lua
exports["t1ger_mechanic"]:GetVehicleMileage(vehicle)
```

#### **Parameters**

* **`vehicle`***(number)* – The vehicle entity handle.

#### **Returns**

* `number`– The vehicle mileage

***

## SetVehicleMileage

Sets the mileage value for a vehicle safely and updates it in the statebag.

```lua
luaKopiérRedigerexports["t1ger_mechanic"]:SetVehicleMileage(vehicle, mileage)
```

**Parameters**

* `vehicle` (`integer`) – The vehicle entity handle.
* `mileage` (`number`) – New mileage value to set. Must be a non-negative number.

**Returns**

* `boolean` – `true` if mileage was set successfully, otherwise `false`.

***

## GetCorePartHealth

Returns the current health value of a specific core part on a given vehicle.

```lua
exports["t1ger_mechanic"]:GetCorePartHealth(vehicle, part)
```

**Parameters**

* `vehicle` (`integer`) – The vehicle entity handle.
* `part` (`string`) – The name of the core part (e.g., `"radiator"`, `"brakes"`).

**Returns**

* `number` – Health value of the part (`0–100`), or `-1` if not found.

***

## SetCorePartHealth

Sets the health value for a specific core part on a given vehicle. The value is clamped between `0` and `100`.

```lua
exports["t1ger_mechanic"]:SetCorePartHealth(vehicle, part, health)
```

**Parameters**

* `vehicle` (`integer`) – The vehicle entity handle.
* `part` (`string`) – The name of the core part.
* `health` (`number`) – New health value (clamped between 0 and 100).

**Returns**

* `boolean` – `true` if the part was updated successfully, otherwise `false`.

***

## SetAllCorePartsHealth

Sets all core parts of the given vehicle to a specified health value — but only if their current health is lower than the new value.

```lua
exports["t1ger_mechanic"]:SetAllCorePartsHealth(vehicle, value)
```

**Parameters**

* `vehicle` (`integer`) – The vehicle entity handle.
* `value` (`number`) – New health value to apply. Clamped between `0.0` and `100.0`.

**Returns**

* `boolean` – `true` if updated successfully, otherwise `false`.

***

## GetServicePartMileage

Returns the current mileage driven since installation of a specific service part on a vehicle.

```lua
exports["t1ger_mechanic"]:GetServicePartMileage(vehicle, part)
```

**Parameters**

* `vehicle` (`integer`) – The vehicle entity handle.
* `part` (`string`) – The name of the service part (e.g., `"oil_filter"`, `"brake_fluid"`).

**Returns**

* `number` – Mileage driven for the part, or `-1` if the part is not found.

***

## SetServicePartMileage

Sets the mileage value for a specific service part on a vehicle.

```lua
exports["t1ger_mechanic"]:SetServicePartMileage(vehicle, part, mileage)
```

**Parameters**

* `vehicle` (`integer`) – The vehicle entity handle.
* `part` (`string`) – The name of the service part.
* `mileage` (`number`) – New mileage value. Negative values are clamped to `0`.

**Returns**

* `boolean` – `true` if updated successfully, otherwise `false`.

***

## SetAllServicePartsMileage

Sets all service parts to a specified mileage — only affects parts currently above that value.

```lua
exports["t1ger_mechanic"]:SetAllServicePartsMileage(vehicle, value)
```

**Parameters**

* `vehicle` (`integer`) – The vehicle entity handle.
* `value` (`number`) – New mileage value to apply (must be ≥ `0`).

**Returns**

* `boolean` – `true` if updated successfully, otherwise `false`.

***

## GetComponentType

Returns the part category type (`"core_parts"` or `"service_parts"`) for a given part name.

```lua
exports["t1ger_mechanic"]:GetComponentType(part)
```

**Parameters**

* `part` (`string`) – The name of the part (e.g., `"radiator"`, `"oil_filter"`).

**Returns**

* `string|nil` – Returns `"core_parts"` or `"service_parts"` if found, otherwise `nil`.

***

## SetComponentFixed

Fully restores a specified vehicle component by automatically determining its type (`core` or `service`).

{% hint style="info" %}

* **Core parts**: health is set to `100.0` via `SetCorePartHealth`.
* **Service parts**: mileage is reset to `0.0` via `SetServicePartMileage`.
* Adds a service history entry and updates the workflow task if applicable.
  {% endhint %}

```lua
exports["t1ger_mechanic"]:SetComponentFixed(vehicle, partName, partType)
```

**Parameters**

* `vehicle` (`number`) – The vehicle entity handle.
* `partName` (`string`) – The name of the part to restore (e.g., `"radiator"`, `"oil_filter"`).
* `partType` (`string`, optional) – `"core_parts"` or `"service_parts"`. If omitted, the function auto-detects using `GetComponentType`.

***

## IsVehicleElectric

Determines whether a given vehicle is electric.\
Uses native `GetIsVehicleElectric` on game builds `3258+`, otherwise checks the config-defined list.

```lua
exports["t1ger_mechanic"]:IsVehicleElectric(vehicle)
```

**Parameters**

* `vehicle` (`integer`) – The vehicle entity handle.

**Returns**

* `boolean` – `true` if the vehicle is electric, otherwise `false`.

***

## GetMechanicVehicleType

Returns the mechanic-specific vehicle type for the given vehicle: `"electric"` or `"gas"`.

```lua
exports["t1ger_mechanic"]:GetMechanicVehicleType(vehicle)
```

**Parameters**

* `vehicle` (`integer`) – The vehicle entity handle.

**Returns**

* `string` – `"electric"` if the vehicle is electric, otherwise `"gas"`.

***

## IsTrackableVehicle

Checks whether the given vehicle should be tracked for mileage, degradation, and service.\
Excludes blacklisted models and non-trackable vehicle classes (e.g., boats, aircraft, trailers, bicycles).

```lua
exports["t1ger_mechanic"]:IsTrackableVehicle(vehicle)
```

**Parameters**

* `vehicle` (`integer`) – The vehicle entity handle.

**Returns**

* `boolean` – `true` if the vehicle is trackable, otherwise `false`.

***

## DoesVehicleHaveFailuredParts

Checks whether the vehicle has at least one core part in a **failed** condition (`isFailured = true`) based on type compatibility.

```lua
exports["t1ger_mechanic"]:DoesVehicleHaveFailuredParts(vehicle)
```

**Parameters**

* `vehicle` (`integer`) – The vehicle entity handle.

**Returns**

* `boolean` – `true` if one or more core parts are in failure state, otherwise `false`.

***

## ApplyCollisionDegradation

Applies random degradation to core parts of a vehicle as a result of collision, based on compatibility and configuration values. Can be used as integration into existing vehicle-failure-damage scripts

```lua
exports["t1ger_mechanic"]:ApplyCollisionDegradation(vehicle)
```

**Parameters**

* `vehicle` (`entity`) – The vehicle entity handle.

{% hint style="info" %}

* Only applies if:
  * The vehicle is trackable (`IsTrackableVehicle` returns `true`).
  * The local player is the driver.
  * `currentVehicleData` is valid.
* Selects a random number of compatible core parts (gas/electric/shared) and reduces their health by a random percentage within the configured range (`MinPercent`–`MaxPercent`).
* Uses `Config.VehicleCollision.PartCount` to determine how many parts are affected.
  {% endhint %}

***


# Troubleshoot

Your guide to quickly troubleshoot and resolve your issues

{% stepper %}
{% step %}

### Frequently Asked Questions

Verify that your issue is not already addressed in our [FAQ](/resources/t1ger-mechanic/troubleshoot/faq).
{% endstep %}

{% step %}

### Reinstall

If your issue is not addressed in our [FAQ](/resources/t1ger-mechanic/troubleshoot/faq) and you are still experiencing issues, please conduct a reinstall of the resource and follow our [Installation](/resources/t1ger-mechanic/installation) guide properly.&#x20;
{% endstep %}

{% step %}

### Contact us

If you've tried steps 1 and 2 - and still encountering issues, please open a ticket on our official Discord.
{% endstep %}
{% endstepper %}


# FAQ

Frequently Asked Questions

{% hint style="success" %}

## Could not find dependency `t1ger_mechanicprops` for resource `t1ger_mechanic`

The props asset is new and has been added to the [Granted Assets](https://portal.cfx.re/assets/granted-assets) in Cfx.re Portal of the account that originally purchased the mechanic script.

If you can’t find it:

* You likely had the script transferred from someone else. Ask them to also transfer the props asset.
* If the script was gifted via the webstore (we can check) and the props didn’t show up, open a ticket on our [Discord](https://discord.gg/t1ger) — we can manually resend it.
* If you **don’t have access to the original purchasing account**, we cannot help. The asset can only be resent to the account that made the original purchase.
* We **do not send or sell the props separately**. Buying from resellers or third parties is not supported - nor our issue to take care of.
  {% endhint %}

***

{% hint style="success" %}

## `sv_enforceGameBuild` needs to be at least 3258

Build 3258 is required to use a native that detects electric vehicles. If you prefer using a lower build:

1. Open `fxmanifest.lua` and lower or comment out the `gameBuild` dependency.
2. Manually configure your electric vehicles in `Config.ElectricVehicles`.
   {% endhint %}

***

{% hint style="success" %}

## Failed to insert job

This is an error you are likely to see on `es_extended` when creating shops/jobs in runtime. All you have to do is:

1. Open `createJob.lua` located inside `es_extended/server/modules`. If you do not have a `createJob.lua` file or modules folder, then open `functions.lua` inside `es_extended/server`.
2. Locate the function named: `ESX.CreateJob`.
3. Replace the entire function with the following code:

```lua
--- Create Job at Runtime
--- @param name string
--- @param label string
--- @param grades table
function ESX.CreateJob(name, label, grades)
  local currentResourceName = GetInvokingResource()
  local success = false

  if not name or name == '' then
      print("ERROR",currentResourceName, 'Missing argument `name`')
      return success
  end

  if not label or label == '' then
      print("ERROR",currentResourceName, 'Missing argument `label`')
      return success
  end

  if type(grades) ~= "table" or not next(grades) then
      print("ERROR",currentResourceName, 'Missing argument `grades`')
      return success
  end

  if ESX.DoesJobExist(name, 0) then
      print("ERROR",currentResourceName, 'Job already exists: `%s`', name)
      return success
  end

  local queries = {
      { query = 'INSERT INTO jobs (name, label) VALUES (?, ?)', values = { name, label } }
  }

  for _, grade in pairs(grades) do
      queries[#queries + 1] = {
          query = 'INSERT INTO job_grades (job_name, grade, name, label, salary, skin_male, skin_female) VALUES (?, ?, ?, ?, ?, ?, ?)',
          values = { name, grade.grade, grade.name, grade.label, grade.salary, type(grade.skin_male) == "table" and json.encode(grade.skin_male) or '{}', type(grade.skin_female) == "table" and json.encode(grade.skin_female) or '{}' }
      }
  end

  success = exports.oxmysql:transaction_async(queries)

  if not success then
      print("ERROR", currentResourceName, 'Failed to insert one or more grades for job: `%s`', name)
      return success
  end

  local job = { name = name, label = label, grades = {} }
  for _, v in pairs(grades) do
      job.grades[tostring(v.grade)] = { job_name = name, grade = v.grade, name = v.name, label = v.label, salary = v.salary, skin_male = v.skin_male or '{}', skin_female = v.skin_female or '{}' }
  end

  ESX.Jobs[name] = job

  print("SUCCESS", currentResourceName, 'Job created successfully: `%s`', name)

  TriggerEvent('esx:jobCreated', name, ESX.Jobs[name])

  return success
end
```

4. Restart your server
   {% endhint %}

***


# T1GER Tuning

The most immersive and realistic tuning script for FiveM

<figure><img src="https://2167335559-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MiDWIMbFBeXle-trOlk%2Fuploads%2FwohAJaCiImqZxZhgYPX8%2Ft1ger_tuning.png?alt=media&amp;token=c55cd1d8-5b74-4503-b8fe-3823c871c675" alt=""><figcaption></figcaption></figure>

Take your server's car culture to the next level with a full-featured tuning script built for real automotive passion. Own and run a tuning shop, hire employees, and handle everything from performance upgrades to visual customization. Perform authentic engine swaps with a hoist-based install system, fit nitrous kits with a genuine purge/burst risk mechanic, and fine-tune torque, power, and braking on the dyno. Manage customer mod orders through the tuner tablet, take on realistic side jobs when business is slow, and give every tuner on your server a deep, believable way to build their reputation.

## Purchase

<https://t1ger.net/product/6044615>

## Showcase

{% embed url="<https://youtu.be/fQfBW-U81FI>" %}

## Features

### Dynamic Shop Management

Admins can create, configure, and manage tuning shops entirely in-game—no restarts required. Through a built-in interface, they can assign a boss, edit or delete markers, list shops for sale, or remove shops entirely. Each shop becomes fully functional as soon as it's placed.

### Ownable Tuning Shops

Players can run their own fully interactive tuning businesses, complete with duty, boss, garage, storage, workbench, supplier, customs, and tuning bay markers. Bosses can manage employees, shop finances, delivery points, and set a price markup through a dedicated boss menu. Combine it with our mechanic script to run unified shops offering both mechanic and tuning services—including a shared supplier—from a single location.

### Full Vehicle Customization

A complete mods menu lets tuners install performance and cosmetic upgrades across every configurable vehicle part, with real-time preview, custom RGB paint and neon coloring, and door-open previews for accurate part placement. Customers can check out directly at a discount-free rate or through incentivized pricing that rewards visiting a tuner in person, with an optional quick-repair option available right from the menu.

### Public Mod Stations

Place standalone, job-restricted or public modification points anywhere on the map—independent of a full tuning shop—for quick, limited-category customization on the go.

### Immersive Mod Order Workflow

Customers place detailed mod orders that tuners fulfill through a realistic, bone-accurate installation system—parts get installed exactly where they belong on the vehicle, with doors and hoods opening automatically for interior or engine work. A visual workflow UI tracks each order's progress in real time, letting tuners manage installs with a dedicated cursor mode.

### Engine Swap System

Tuners can perform full engine swaps using a hands-on hoist system. The process involves opening the engine bay, carrying and positioning a hoist, extracting the old engine, and installing the new one—complete with custom animations, precision alignment markers, and realistic engine sound swapping.

### Nitrous System

Install nitrous kits and burst upgrade kits to unlock a genuine purge/burst risk-and-reward mechanic. Purging before a burst builds efficiency for a stronger boost, while bursting without purging risks engine damage. Bottles can be refilled at map-placed stations, and purge dye lets players customize their effect color.

### Dyno Fine-Tuning

Tuners can fine-tune a vehicle's torque, power, and braking through the dyno menu, with the option to view current modifiers or hard reset back to the vehicle's stock defaults. Changes apply instantly and persist across sessions.

### Tuner Tablet

A single, all-in-one device for managing shop operations—view vehicle diagnostics, examine installed performance parts, check nitrous and dyno status, manage mod orders, and handle billing, all from one interface.

### Billing System

A detailed, itemized billing system lets tuners create transparent invoices with notes for each service. Customers must review and confirm the bill before payment, ensuring clear communication and consent.

### Supplier & Restocking

Tuners can order parts, tools, and materials from a fully configurable supplier catalogue, paid either by the shop account or the player, with deliveries sent straight to shop storage or personal inventory.

### Crafting Workbenches

Tuners can craft mod parts, tools, nitrous components, and even custom tire types using materials at shop-assigned workbenches. Recipes are fully configurable, and crafting integrates with materials earned through NPC jobs, supporting a complete in-house production loop.

### NPC Jobs

Give tuners something to do between customer orders with immersive NPC jobs. Salvage junk cars for crafting materials and rare mod parts, or take on mobile tuning callouts where customers need specific on-site installations—perfect for earning extra income when the shop is quiet.


# Installation

This page covers the installation guide for T1GER Tuning

{% stepper %}
{% step %}

### Ensure Dependencies

{% hint style="warning" %}
Verify that you have the latest version of the listed mandatory resources installed and ensured in correct [start order](#start-order).
{% endhint %}

<table data-full-width="false"><thead><tr><th>Type</th><th width="462.60009765625">Resource(s)</th><th data-type="checkbox">Mandatory</th></tr></thead><tbody><tr><td>Database</td><td><a href="https://github.com/overextended/oxmysql/releases/latest">oxmysql</a></td><td>true</td></tr><tr><td>Library</td><td><a href="https://github.com/overextended/ox_lib/releases/latest">ox_lib</a></td><td>true</td></tr><tr><td>Framework</td><td><a href="https://github.com/esx-framework/esx_core/tree/main/%5Bcore%5D/es_extended">es_extended</a>, <a href="https://github.com/Qbox-project/qbx_core/releases/latest">qbx_core</a> or <a href="https://github.com/qbcore-framework/qb-core">qb-core</a></td><td>true</td></tr><tr><td>Target</td><td><a href="https://github.com/overextended/ox_target">ox_target</a> or <a href="https://github.com/qbcore-framework/qb-target">qb-target</a></td><td>true</td></tr><tr><td>Inventory</td><td><a href="https://github.com/overextended/ox_inventory">ox_inventory</a>, <a href="https://github.com/qbcore-framework/qb-inventory">qb-inventory</a>, qs-inventory, core_inventory, codem-inventory, origen_inventory or ak47_inventory</td><td>true</td></tr></tbody></table>
{% endstep %}

{% step %}

### Download

{% hint style="info" %}
Download the listed asset from [Cfx.re Portal](https://portal.cfx.re/assets/granted-assets):

* `t1ger_tuning`

Unzip the downloaded asset and drag it into a new (or existing) folder named `[t1ger]` inside your server's `resources` folder.
{% endhint %}
{% endstep %}

{% step %}

### Start Order

{% hint style="warning" %}
It's **very important** to ensure the resources in correct order to prevent any errors due to missing dependencies!
{% endhint %}

```lua
ensure oxmysql
ensure ox_lib
ensure es_extended -- or qbx_core / qb-core
ensure ox_target -- or qb-target
ensure ox_inventory -- or whatever compatible inventory
ensure [t1ger]
```

{% hint style="info" %}
*There can be resources ensure in between the listed resources - this **solely clarifies** the correct start order.*
{% endhint %}
{% endstep %}

{% step %}

### Run SQL

{% hint style="info" %}
Open the `t1ger_tuning/install/main.sql` file and run the queries in your database.

Alternatively you can the import file directly into your database.
{% endhint %}
{% endstep %}

{% step %}

### Add Items

{% hint style="danger" %}
If you rename the items or wish to use your own items, make sure to update inside t1ger\_mechanic/shared/\*.lua files!
{% endhint %}

{% tabs %}
{% tab title="ox\_inventory" %}
Open `t1ger_tuning/install/items/ox_inventory.lua` file and copy/paste into `ox_inventory/data/items.lua` file.
{% endtab %}

{% tab title="qb-inventory" %}
Open `t1ger_tuning/install/items/qb-inventory.lua` file and copy/paste into `qb-core/shared/items.lua` file.
{% endtab %}

{% tab title="es\_extended" %}
Open `t1ger_tuning/install/items/items.sql` file and run the query in your database. You can also import the file directly into your database.

If using `ox_inventory`, it will automatically pull items from your database. Otherwise, you can open the `t1ger_tuning/install/items/ox_inventory.lua` file and copy/paste into `ox_inventory/data/items.lua` file.
{% endtab %}
{% endtabs %}

{% hint style="info" %}
Inventory icons are located in `t1ger_tuning/install/items/icons/` folder.
{% endhint %}
{% endstep %}

{% step %}

### Configuration

{% hint style="info" %}
Configure the resource to your liking. Read the end-text comments carefully. If you do not understand, please refer to our documentation or contact us through the relevant support channels on .

Refer to [Configuration](/resources/t1ger-tuning/configuration)
{% endhint %}
{% endstep %}

{% step %}

### Complete

{% hint style="success" %}
You have successfully installed our T1GER Tuning resource. Restart your server and enjoy!
{% endhint %}
{% endstep %}
{% endstepper %}


# Job Account

Instructions on how to setup job accounts to allow for runtime creation of accounts for jobs

## **Supported Banking Systems**

This module supports the following job account systems:

1. **ESX:** Uses `esx_addonaccount`
2. **QBCore:** Supports both `qb-banking` and `qb-management`
3. **QBox:** Uses `Renewed-Banking`
4. **Custom Implementations:** You can add support for a different system by modifying the `_API` functions, see [API](/resources/t1ger-mechanic/installation/job-account/api).

## **Configuration (`bridge/config.lua`):**

To set up the job account system, modify the `JobAccount` value:

```lua
JobAccount = "auto", -- "esx_addonaccount", "qb-banking", "qb-management", "Renewed-Banking", "tgg-banking" or "auto" (auto-detect)
```

* **If `auto` is selected**, the system will automatically choose the best option based on the framework.
* **If manually set**, it will enforce that specific system.
* **If using custom**, edit `InitializeJobAccount()` function inside `bridge/init.lua`.

## Setup

Instructions on how to prepare for runtime creation of shared accounts

{% content-ref url="/pages/69eCq2EKQtID2z2uay0K" %}
[Setup](/resources/t1ger-tuning/installation/job-account/setup)
{% endcontent-ref %}

## Functions

Useful functions for Job Accounts. Also these you want to modify to integrate/compatibility for a custom job banking resource

{% content-ref url="/pages/3g2Ihp493qVMSaYnSZGe" %}
[API](/resources/t1ger-tuning/installation/job-account/api)
{% endcontent-ref %}


# Setup

Instructions on how to setup your job/society integrations with your framework to create shared accounts for jobs in runtime!

## ESX

Download and ensure the latest `esx_addonaccount` from here: <https://github.com/esx-framework/esx_addonaccount>.

## QBCore

Instructions on how to setup job/society accounts with QBCore framework compatibility.

### `qb-banking`

If you are using `qb-banking`, all you need to do is download and ensure the latest version of `qb-banking` from here: <https://github.com/qbcore-framework/qb-banking>.

### `qb-management`

If you are using qb-management (old method), then follow these instructions.&#x20;

{% hint style="warning" %}
Latest `qb-management` does not manage job/society accounts. This is now handled by `qb-banking`. If you are using old qb-management, it's highly recommended to update to latest and utilize `qb-banking` instead.&#x20;
{% endhint %}

{% stepper %}
{% step %}

### Find the file to modify

Navigate to `qb-management/server/sv_boss.lua`.&#x20;
{% endstep %}

{% step %}

### Check for functions

Do `Ctrl + F` (search) for `GetAccount` or `AddMoney` or `RemoveMoney`. If they do not exist, then do not proceed further! Instead, ensure that you have latest [`qb-banking`](https://github.com/qbcore-framework/qb-banking) installed, as this resource now handles job/society accounts.&#x20;
{% endstep %}

{% step %}

### Insert new function

Scroll down all the way to the bottom and insert the following code:

```lua
--- Creates a management account for a job in qb-management.
---@param job_name string The name of the job to create the management account for.
---@param amount number|nil The initial balance of the account (defaults to 0 if not provided).
---@return boolean success Returns `true` if the account was created successfully, `false` otherwise.
function CreateManagementAccount(job_name, amount)
    -- Ensure a valid job name is provided
    if type(job_name) ~= "string" or job_name == "" then
        error("Invalid job_name provided")
    end

    amount = amount or 0 -- Default to 0 if no amount is provided

    -- Check if account already exists in cache
    if Accounts[job_name] then
        return Accounts[job_name] -- Account already exists, no need to create it again
    end

    -- Insert the new account into the database
    local insertSuccess = MySQL.insert.await('INSERT INTO management_funds (job_name, amount, type) VALUES (@job_name, @amount, @type)', {
        ['@job_name'] = job_name,
        ['@amount'] = amount,
        ['@type'] = 'boss'
    })

    if not insertSuccess then
        error("Database error: Failed to insert management account")
    end

    -- Store in local cache
    Accounts[job_name] = amount

    return Accounts[job_name]
end
exports("CreateManagementAccount", CreateManagementAccount)
```

{% endstep %}

{% step %}

### Complete

Restart your server and you'll now be able to create management account in runtime!&#x20;
{% endstep %}
{% endstepper %}

## Qbox

Download and ensure the latest version of `Renewed-Banking` from here: <https://github.com/Renewed-Scripts/Renewed-Banking/releases>.

If you are using another banking/management for job/shared accounts, then refer to [API](/resources/t1ger-mechanic/installation/job-account/api) for custom integrations on your own.&#x20;

If using `qb-management` (old version) with backwards compatibility, then see [#qb-management](#qb-management "mention").


# API

Functions for Job Account. Modify them inside bridge/jobaccount/server.lua for custom changes.

## **Get a Job Account**

**`_API.JobAccount.Get(jobName)`**

Retrieves the shared job account for a given job.

* **Parameters:**
  * `jobName` *(string)* – The name of the job whose account is being retrieved.
* **Returns:**
  * `JobAccount` *(table)* – The job account object if found.
  * `nil` – If no account is found.
* **Example Usage:**

  ```lua
  local account = _API.JobAccount.Get("tuner")
  if account then
      print("Account found:", account)
  else
      print("No job account exists for tuner.")
  end
  ```

***

## **Get Job Account Balance**

**`_API.JobAccount.GetBalance(jobName)`**

Retrieves the balance of a shared job account.

* **Parameters:**
  * `jobName` *(string)* – The name of the job whose balance is being retrieved.
* **Returns:**
  * `balance` *(number)* – The current balance of the job account, or `0` if unavailable.
* **Example Usage:**

  ```lua
  local balance = _API.JobAccount.GetBalance("tuner")
  print("Current balance:", balance)
  ```

***

## **Add Money to a Job Account**

**`_API.JobAccount.AddMoney(jobName, amount)`**

Adds money to a shared job account.

* **Parameters:**
  * `jobName` *(string)* – The name of the job whose account will receive money.
  * `amount` *(number)* – The amount of money to add.
* **Example Usage:**

  ```lua
  _API.JobAccount.AddMoney("tuner", 5000)
  print("Added 5000 to tuner account")
  ```

***

## **Remove Money from a Job Account**

**`_API.JobAccount.RemoveMoney(jobName, amount)`**

Removes money from a shared job account.

* **Parameters:**
  * `jobName` *(string)* – The name of the job whose account will be debited.
  * `amount` *(number)* – The amount of money to remove.
* **Example Usage:**

  ```lua
  _API.JobAccount.RemoveMoney("tuner", 2000)
  print("Removed 2000 from tuner account")
  ```

***

## **Set a Job Account Balance**

**`_API.JobAccount.SetMoney(jobName, amount)`**

Sets a specific balance for a shared job account.

* **Parameters:**
  * `jobName` *(string)* – The name of the job whose account balance will be set.
  * `amount` *(number)* – The new balance to be set for the job account.
* **Example Usage:**

  ```lua
  _API.JobAccount.SetMoney("tuner", 10000)
  print("Set tuner account balance to 10000")
  ```

***

## **Create a New Job Account**

**`_API.JobAccount.Create(jobName, startBalance)`**

Creates a new shared job account with a starting balance.

* **Parameters:**
  * `jobName` *(string)* – The name of the job/society for which the account will be created.
  * `startBalance` *(number)* – The initial balance of the newly created job account.
* **Returns:**
  * `true` – If the account was created successfully.
  * `false` – If the account could not be created.
* **Example Usage:**

  ```lua
  local success = _API.JobAccount.Create("tuner", 5000)
  if success then
      print("Tuner job account created successfully!")
  else
      print("Failed to create tuner job account.")
  end
  ```


# Configuration

This page covers all configurable aspects of T1GER Tuning

Configuration files are located in the `t1ger_tuning/shared/` folder and control various systems like shops, parts, missions, crafting, and suppliers.

{% content-ref url="/pages/onsE6mXMxyMHrwIL5EFu" %}
[Config](/resources/t1ger-tuning/configuration/config)
{% endcontent-ref %}

{% content-ref url="/pages/Ncd0ewObGYU2xYd36Xa9" %}
[Shop](/resources/t1ger-tuning/configuration/shop)
{% endcontent-ref %}

{% content-ref url="/pages/AEfXuValj3JoZC7P41no" %}
[Parts](/resources/t1ger-tuning/configuration/parts)
{% endcontent-ref %}


# Config

t1ger\_tuning/shared/config.lua

```lua
Config = {}

Config.Debug = true

Config.Currency = "$" -- currency used for pricing

Config.ServerSideProps = true -- create objects/props on server or client?

Config.UseCharacterNames = true -- if true, shows character (first+last) names instead of game/Rockstar names in player lists.

Config.ModCategories = { -- All mods from Config.ModTypes are sorted in these categories. You are only allowed to change title, position and icon (also supports fontawesome icons). Changing anything else will break the script functionality.
    ["styling"]     = { title = "Styling",     position = "top-left", icon = "https://i.postimg.cc/YG4Jj5mR/mod-bodywork.png" },
    ["performance"] = { title = "Performance", position = "top-left", icon = "https://i.postimg.cc/G8Z6DXk7/mod-engine.png" },
    ["wheels"]      = { title = "Wheels",      position = "top-left", icon = "https://i.postimg.cc/yWZMKzK6/mod-wheels.png" },
    ["respray"]     = { title = "Respray",     position = "top-left", icon = "https://i.postimg.cc/4HVqQpPK/mod-respray.png" },
    ["lights"]      = { title = "Lights",      position = "top-left", icon = "https://i.postimg.cc/dkzgC52w/mod-headlights.png" },
    ["extras"]      = { title = "Extras",      position = "top-left", icon = "https://i.postimg.cc/62DFZMrs/mod-extras.png" },
}

Config.ModTypes = require("shared/modtypes") -- all mod types, prices etc. defined inside shared/modtypes.lya
Config.Paints = require("shared/paints")

--Not all servers prefer the players being able to install special mods, such as weapons, proximity mines and so on. The resource have disabled some of the most common mods that are seen in-game. You can alter this array by finding the config option inside the mods.lua file.
Config.DisableMods = { -- Add specific mods in here you want to disable. If you find more in-game, you can add them in here. By default, weapon mods are disabled
    'Primary Weapons', 'Proximity Mine', 'Armor Plating', 'Ram Weapons', 'Imani Tech', 'Blades', 'Spikes', 'Secondary Weapons'
}

Config.ModSlotNames = {
    CMOD_ROOF_ACC = "Roof Accessories",
    -- Add more slot name overrides here if needed
}

Config.ModsMenu = {
	Menu = {title = 'Mods Menu', position = 'top-left'}, -- mods main menu title and position

	UseGameModLabels = true, -- true = GTA native labels (language dependent), false = Config.ModTypes labels

	Repair = {
		allow = true, -- allow quick repair for $Repair.price (below) in mod menu marker. Set to false to force customers to go to a mechanic first.
		price = 1000, -- 1000$ to repair vehicle, before installing mods.
	},

	IncentivizedPricing = {
		enable = true, -- set to true to enable incentivized pricing. Only applies if purchasing and applying mods directly through the mods menu. This incentivized price is ignored if a mod order is created.
		percent = 25 -- percentage to increase the price of mods in the mod menu, to kinda force players to RP with tuners.
	},

	DisableCheckout = false -- set to true to disable direct checkout, forcing players to place mod orders with tuners instead
}

Config.ModStations = {
    enable   = true,
    distance = 2.0,
    keybind = 38, -- Default keybind: [E]

    -- Global blip settings for all stations
    blip = {
        sprite = 72, color = 0, scale = 0.65, display = 4, label = "Mod Station",
    },

    -- Global marker settings for all stations
    marker = {
        enable = true, type = 20, size = vector3(0.35, 0.35, 0.35), color = { r = 100, g = 200, b = 255, a = 100 }, bobUpAndDown = true,
    },

    -- Global text UI settings for all stations
    textUi = {
        label = "[E] Open Mod Station", position = "right-center", icon = "spray-can", style = {borderRadius = 0, backgroundColor = 'FF488DBB', color = 'white'},
    },

    locations = require("shared/modstations"),
}

--- Workflow UI
Config.WorkflowUI = {
    Commands = {
        open   = "tuning:workflow:open",
        close  = "tuning:workflow:close",
        cursor = "tuning:workflow:cursor",
        clear  = "tuning:workflow:clear"
    },
    CursorKeybind = {
        description = "Toggle Tuning Workflow Cursor",
        defaultKey  = "J"
    },
    DefaultTitle = "Mod Order",
    ShowItemName    = true,  -- show item name in brackets e.g. (mod_engine)
    ShowModLabel    = true,  -- show mod type label prefix e.g. "Engine — "
}

Config.ModOrder = {
    InstallDuration = 5000,
    ConsumeOnUse    = true,
    OpenHoodForEngineBay = true,
    NotifyCustomer  = true,

    CancelInstall = {
        button = 252,
        label  = "[X] Cancel Install",
    },

    SkillCheck = {
        enable     = true,
        difficulty = { "easy", "easy", "easy" },
        inputs     = { "w", "a", "s", "d" },
    },

    Target = {
        label = "Install Mod",
        icon  = "fa-solid fa-wrench",
        distance  = 2.0,
    },

    InstallZones = {
        front = {
            bones    = { "bumper_f", "bonnet", "headlight_l", "headlight_r", "wing_lf", "wing_rf", "indicator_lf", "indicator_rf" },
            fallback = vec3(0.0, 2.5, 0.5),
            openHood = false, openDoor = false,
        },
        rear = {
            bones    = { "bumper_r", "boot", "spoiler", "taillight_l", "taillight_r", "indicator_lr", "indicator_rr" },
            fallback = vec3(0.0, -2.5, 0.5),
            openHood = false, openDoor = false,
        },
        wheel = {
            bones    = { "wheel_lf", "wheel_rf", "wheel_lr", "wheel_rr", "wheel_lm1", "wheel_rm1", "suspension_lf", "suspension_rf", "hub_lf", "hub_rf" },
            fallback = vec3(-1.2, 0.0, 0.3),
            openHood = false, openDoor = false,
        },
        engine = {
            bones    = { "engine", "bonnet", "engineblock", "petroltank", "transmission_f", "transmission_m" },
            fallback = vec3(0.0, 1.0, 0.5),
            openHood = true, openDoor = false,
        },
        interior = {
            bones    = { "seat_dside_f", "seat_pside_f", "seat_dside_r", "seat_pside_r", "door_dside_f", "door_pside_f", "steering", "dials", "interiorlight", "dashglow" },
            fallback = vec3(0.0, 0.0, 0.3),
            openHood = false, openDoor = true,
        },
        vehicle = {
            bones    = { "chassis", "bodyshell", "roof", "roof2", "exhaust", "exhaust_2", "numberplate", "petrolcap", "struts" },
            fallback = vec3(0.0, 0.0, 0.0),
            openHood = false, openDoor = false,
        },
    },

    -- Approximate RGB values for predefined paint colors used in spray particles.
    -- String matched against the color label — add more as needed.
    SprayColors = {
        white   = { 255, 255, 255 },
        red     = { 246, 75,  60  },
        pink    = { 253, 226, 226 },
        blue    = { 0,   168, 204 },
        yellow  = { 245, 252, 193 },
        green   = { 99,  154, 103 },
        orange  = { 255, 164, 27  },
        brown   = { 156, 85,  24  },
        purple  = { 190, 121, 223 },
        grey    = { 50,  50,  50  },
        gray    = { 50,  50,  50  },
        black   = { 0,   0,   0   },
        gold    = { 255, 215, 0   },
        silver  = { 192, 192, 192 },
        bronze  = { 205, 127, 50  },
    },
}

Config.TunerTablet = {
    -- Enable/disable individual tablet sections
    Enable = {
        VehicleInfo         = true,
        ExaminePerformance  = true,
        Dyno                = true,
        Billing             = true,
        NpcJobs             = true,
        ModOrders           = true,
        Nitrous             = true,
    },

    -- Icons used throughout the tablet menu (FontAwesome classes)
    Icons = {
        VehicleInfo        = "circle-info",
        ExaminePerformance = "magnifying-glass",
        Dyno               = "chart-line",
        Billing            = "file-invoice-dollar",
        NpcJobs            = "comment-dots",
        ModOrders          = "cart-shopping",
        Refund             = "rotate-left",
        Abandon            = "trash",
        Locked             = "lock",
        Nitrous            = "fire-flame-simple",
    },
}

Config.RepairKit = {
    Enable          = true,
    RequireTunerJob = true,
    Duration        = 3000,
}

Config.EngineSwaps = {

    Enable = true, -- enable/disable the engine swap feature entirely

    Engines = require("shared/engine_swap"), -- configure engines for each class in shared/engine_swap.lua

    -- Command used to cancel an active engine swap task (refunds the shop)
    CancelCommand = "cancelengineswap",

    -- Default icon shown for engines with no custom icon set
    DefaultIcon = "gear",

    -- Keybind used to place/detach the hoist while carrying
    HoistKeybind = 47, -- G

    -- Play the hook engage sound when lifting/lowering an engine
    HoistPlaySound = true,

    -- Text UI shown while carrying the hoist
    HoistTextUi = {
        string   = "[G] - Detach Hoist",
        icon     = "location-crosshairs",
        position = "right-center",
    },

    -- Icons/labels only — internal target names are fixed in code
    VehicleTarget = {
        access   = { icon = "fa-solid fa-screwdriver", label = "Access Engine Bay" },
        complete = { icon = "fa-solid fa-screwdriver", label = "Complete Engine Swap" },
    },

    ExtractTarget = {
        icon  = "fa-solid fa-trash-can",
        label = "Dump Engine",
    },

    HoistTarget = {
        carry   = { icon = "fa-solid fa-up-down-left-right", label = "Carry Hoist" },
        extract = { icon = "fa-solid fa-arrow-up-long",      label = "Extract Engine" },
        attach  = { icon = "fa-solid fa-link",               label = "Attach Engine" },
        detach  = { icon = "fa-solid fa-link-slash",         label = "Detach Engine" },
        remove  = { icon = "fa-solid fa-hand",                label = "Collect Hoist" },
    },

    -- Marker colors only — type/scale are fixed in code
    VehiclePointColor = {
        default = vector4(194, 80, 80, 200),  -- red — target marker
        success = vector4(63, 195, 128, 200), -- green — aligned
        hoist   = vector4(20, 20, 20, 200),   -- black — hoist hook marker
    },

    EnginePointColor = {
        default = vector4(194, 80, 80, 200),  -- red — target marker
        success = vector4(63, 195, 128, 200), -- green — aligned
        hoist   = vector4(20, 20, 20, 200),   -- black — hoist hook marker
    },
}

Config.Nitrous = require("shared/nitrous")
Config.Dyno = require("shared/dyno")
Config.NpcJobs = require("shared/npc_jobs")

Config.CustomTires = {
    Enable            = true, -- master enable/disable for the whole feature
    RequireCarJack    = true, -- if t1ger_mechanic is detected, require the vehicle to be raised on a car jack
    RequireTunerJob   = false, -- if true, only employed tuners can use these items
    DriftTires        = true, -- enable/disable the drift tires item specifically
    BulletproofTires  = true, -- enable/disable the bulletproof tires item specifically
}

T1GER_Mechanic = false
CreateThread(function()
	Wait(3000)
	if GetResourceState("t1ger_mechanic") == "started" then
		T1GER_Mechanic = true
		print("DETECTED: T1GER Mechanic")
	end
end)
```


# Shop

t1ger\_tuning/shared/shop.lua

```lua
Config.Shop = {}

Config.Shop.Job = { -- Job Settings
    defaultGrades = {
        [0] = {grade = 0, name = "recruit", label = "Recruit", salary = 50},
        [1] = {grade = 1, name = "employee", label = "Employee", salary = 75},
        [2] = {grade = 2, name = "boss", label = "Boss", salary = 100},
        -- make sure boss grade is the very last one (higest grade)
    },
    defaultDuty = true, -- only qbcore/qbox
    offDutyPay = false, -- only qbcore/qbox
}

Config.Shop.JobAccount = true -- true = Use JobAccount system for society/shared account | false = Use our integrated account system

Config.Shop.Sale = true -- allow buy shops? And admins to list shop for_sale or cancel sale?

Config.Shop.Admin = {
    menu = { 
		enable = true, -- enable/disable admin tuning menu?
		command = {enable = true, str = "tuning:admin"}, -- enable/disable command
		keybind = {enable = true, default = "F9", description = "Tuning Admin Menu"} -- enable/disable keybind
	},
}

Config.Shop.Creation = {
    command = {enable = true, str = "tuning:create"}, -- enable/disable command to directly open creator interface?
    blip = { -- blip settings for shop blips
		input = true, -- allow admins to modify sprite & color in shop creator interface?
		sprite = 446, -- default sprite
		color = 5, -- default color
		display = 4, -- default display
		scale = 0.75 -- default scale 
	},
}

Config.Shop.Management = {
    command = {enable = true, str = "tuning:manage"}, -- enable/disable command for admins to directly open management interface?
    markerEdit = true, -- set to false to disable option in admin management menu to edit marker. 
    markerTeleport = true, -- set to false to disable option in admin management menu to TP to marker.
}

Config.Shop.Storage = {
    slots = 50, -- default slots for created storage/stash
    weight = 100000, -- default weight for created storage/stash
    maxSlots = 500, -- max slots for editing storage/stash
    maxWeight = 999999 -- max weight for editing storage/stash
}

Config.Shop.MarkerSettings = {
    keybind = 38, -- Keybind for interacting with the marker. 
    distance = 5.0, -- distance to load/draw marker
    textUi = { -- UI settings for prompts.
        position = 'right-center',
        style = {borderRadius = 0, backgroundColor = '#48BB78', color = 'white'}
    },
}

Config.Shop.Markers = {
    duty = {
        title = "Duty",
        enable = true, -- Toggle this marker class on/off.
        icon = "briefcase", -- Icon used for text UI and/or menu.
        blip = {sprite = 280, display = 4, scale = 0.65, color = 0} -- Blip settings.
    },

    boss = {
        title = "Boss",
        enable = true,
        icon = "user-tie",
        blip = {sprite = 164, display = 4, scale = 0.65, color = 0}
    },

    garage = {
        title = "Garage",
        enable = true,
        icon = "square-parking",
        blip = {sprite = 357, display = 4, scale = 0.65, color = 0}
    },

    storage = {
        title = "Storage",
        enable = true,
        icon = "box",
        blip = {sprite = 587, display = 4, scale = 0.65, color = 0}
    },

    workbench = {
        title = "Workbench",
        enable = true,
        icon = "tools",
        blip = {sprite = 566, display = 4, scale = 0.65, color = 0}
    },

    supplier = {
        title = "Supplier",
        enable = true,
        icon = "shopping-cart",
        blip = {sprite = 521, display = 4, scale = 0.65, color = 0}
    },

    customs = {
        title = "Vehicle Customs",
        enable = true,
        icon = "spray-can",
        blip = {sprite = 72, display = 4, scale = 0.65, color = 0}
    },

    tuningbay = {
        title = "Tuning Bay",
        enable = true,
        icon = "wrench",
        blip = {sprite = 402, display = 4, scale = 0.65, color = 0}
    },
}

Config.Shop.Workbench = {
	enable = true, -- set to false to disable and add your own crafting export/event
	duration = 2500, -- duration in ms for crafting
	anim = {dict = 'mini@repair', clip = 'fixing_a_player', blendIn = 8.0, blendOut = -8.0, flag = 49},
	skillcheck = {enable = true, difficulty = {'easy', 'easy'}, inputs = {'w', 'a', 's', 'd'}},
    maxCraftAmount = 20, -- max allowed amount to craft of selected item.
    categories = require("shared/workbench") -- Load categories from the shared/workbench.lua file
}

Config.Shop.Supplier = {
    receiveInStash = true, -- `true` ordered items delivered to stash. `false` otherwise in player inventory
    playerPay = false, -- `true` player/tuner pays for items. `false` shop account pays for items
    maxQuantity = 30, -- max quantity of an item that can be ordered.
    catalogue = require("shared/supplier") -- Load catalogue from the shared/supplier.lua file
}

Config.Shop.Billing = {
	enable = true, -- set to false to disable built in billing entirely
	command = {enable = true, name = 'billing'}, -- enable command to open billing interface
	actionMenu = {enable = true, icon = 'file-invoice-dollar'}, -- enable from action menu? icon for menu option
}

Config.Shop.Markup = {
	enable = true, -- enable/disable adding markup % on top of the total price (realistic feature)
	default = 10, -- default markup %, else it uses the defined price by the boss
	max = 100 -- max value for markup % able to be set by boss in the boss menu (max 100!)
}

Config.Shop.Customs = {
    AllowEmployeesOnly = false, -- set to true to only allow employees of the shop to use it.
    
	RepairMoneyToAccount = true, -- if true, paid repair fees goes to the shop's account, else the money just disappears.

    -- Defines where the checkout payment goes when inside a customs marker in tuner shop.
    Checkout = "full_amount",
    -- "full_amount"  — shop account receives the full checkout total (parts + service fee)
	-- "service_fee"  — shop account receives only the shop's markup portion
}
```


# Workbench

t1ger\_tuning/shared/workbench.lua

## Crafting Categories

Our built in crafting system has a category system to easily craft the required items.

Each category will have:

* `label` (string) — the title of the category
* `description`(string) — the description of the category
* `icon` (string) — an icon for the category
* `recipe` (table) — the items to craft as index and recipe as the value.

## Recipes

The setup of a recipe is indexed by the item name you want to craft:

```lua
["mod_bodywork"] = { -- output item name
                icon = "https://i.postimg.cc/YG4Jj5mR/mod-bodywork.png", -- output item icon
                materials = { -- materials to craft one piece
                    ["steel"]        = 5, -- item name and required amount
                    ["aluminium"]    = 3, -- item name and required amount
                    ["carbon_fiber"] = 2, -- item name and required amount
                    ["plastic"]      = 2, -- item name and required amount
                }
            },
```

* `icon` (string) — the icon of the item to craft
* `materials` (table) — the materials required to craft the item
  * `index` is the item name
  * `number` is the required amount of materials

You can add whatever items you like and require whatever materials and amount that fits your server.

```lua
return {
    { -- PERFORMANCE
        label = "Performance",
        description = "Performance mods are used to upgrade vehicle's performance.",
        icon = "https://i.postimg.cc/VrS35xb4/mod-brakes.png",
        recipe = {
            ["mod_engine"] = {
                icon = "https://i.postimg.cc/G8Z6DXk7/mod-engine.png",
                materials = {
                    ["aluminium"]     = 6,
                    ["steel"]         = 4,
                    ["copper"]        = 3,
                    ["carbon_fiber"]  = 2,
                    ["electric_scrap"]= 2,
                }
            },
            ["mod_brakes"] = {
                icon = "https://i.postimg.cc/VrS35xb4/mod-brakes.png",
                materials = {
                    ["steel"]        = 3,
                    ["rubber"]       = 2,
                    ["copper"]       = 1,
                    ["carbon_fiber"] = 1,
                }
            },
            ["mod_transmission"] = {
                icon = "https://i.postimg.cc/SYC3fcdZ/mod-transmission.png",
                materials = {
                    ["steel"]         = 4,
                    ["aluminium"]     = 2,
                    ["copper"]        = 3,
                    ["synthetic_oil"] = 1,
                    ["plastic"]       = 2,
                }
            },
            ["mod_suspension"] = {
                icon = "https://i.postimg.cc/RJKyLwdT/mod-suspension.png",
                materials = {
                    ["steel"]        = 3,
                    ["rubber"]       = 2,
                    ["aluminium"]    = 2,
                    ["carbon_fiber"] = 1,
                }
            },
            ["mod_armor"] = {
                icon = "https://i.postimg.cc/627DTkG0/mod-armor.png",
                materials = {
                    ["steel"]        = 6,
                    ["carbon_fiber"] = 3,
                    ["rubber"]       = 2,
                    ["brass"]        = 1,
                    ["aluminium"]    = 4,
                }
            },
            ["mod_turbo"] = {
                icon = "https://i.postimg.cc/nMDyxtxx/mod-turbo.png",
                materials = {
                    ["steel"]         = 2,
                    ["copper"]        = 2,
                    ["aluminium"]     = 1,
                    ["plastic"]       = 1,
                    ["electric_scrap"]= 1,
                }
            },
        }
    },

    { -- COSMETICS
        label = "Cosmetics",
        description = "Cosmetic mods are used to customize the vehicle's appearance.",
        icon = "https://i.postimg.cc/4HVqQpPK/mod-respray.png",
        recipe = {
            ["mod_extras"] = {
                icon = "https://i.postimg.cc/62DFZMrs/mod-extras.png",
                materials = {
                    ["plastic"]       = 3,
                    ["aluminium"]     = 1,
                    ["electric_scrap"]= 1,
                }
            },
            ["mod_exterior"] = {
                icon = "https://i.postimg.cc/MMhgB9yC/mod-exterior.png",
                materials = {
                    ["aluminium"] = 4,
                    ["plastic"]   = 3,
                    ["glass"]     = 1,
                }
            },
            ["mod_interior"] = {
                icon = "https://i.postimg.cc/hzHNm2Lv/mod-interior.png",
                materials = {
                    ["plastic"]       = 4,
                    ["rubber"]        = 2,
                    ["synthetic_oil"] = 1,
                }
            },
            ["mod_horn"] = {
                icon = "https://i.postimg.cc/Q9Rv7fQ8/mod-horn.png",
                materials = {
                    ["copper"]        = 2,
                    ["plastic"]       = 2,
                    ["electric_scrap"]= 1,
                }
            },
            ["mod_headlights"] = {
                icon = "https://i.postimg.cc/dkzgC52w/mod-headlights.png",
                materials = {
                    ["glass"]         = 2,
                    ["plastic"]       = 2,
                    ["electric_scrap"]= 2,
                }
            },
            ["mod_livery"] = {
                icon = "https://i.postimg.cc/wySnNwX7/mod-livery.png",
                materials = {
                    ["plastic"]       = 3,
                    ["synthetic_oil"] = 2,
                    ["acid"]          = 1,
                }
            },
            ["mod_neon"] = {
                icon = "https://i.postimg.cc/TLZBbtVy/mod-neon.png",
                materials = {
                    ["plastic"]       = 3,
                    ["glass"]         = 2,
                    ["electric_scrap"]= 2,
                }
            },
            ["mod_plate"] = {
                icon = "https://i.postimg.cc/BPHkB2pv/mod-plate.png",
                materials = {
                    ["aluminium"] = 2,
                    ["plastic"]   = 2,
                    ["steel"]     = 1,
                }
            },
            ["mod_respray"] = {
                icon = "https://i.postimg.cc/4HVqQpPK/mod-respray.png",
                materials = {
                    ["synthetic_oil"] = 2,
                    ["acid"]          = 2,
                    ["plastic"]       = 1,
                }
            },
            ["mod_tyresmoke"] = {
                icon = "https://i.postimg.cc/kDb0CdCq/mod-tyresmoke.png",
                materials = {
                    ["synthetic_oil"] = 2,
                    ["rubber"]        = 2,
                    ["acid"]          = 1,
                }
            },
            ["mod_windowtint"] = {
                icon = "https://i.postimg.cc/9z762j2f/mod-windowtint.png",
                materials = {
                    ["plastic"]       = 2,
                    ["synthetic_oil"] = 1,
                    ["acid"]          = 1,
                }
            },
            ["mod_wheels"] = {
                icon = "https://i.postimg.cc/yWZMKzK6/mod-wheels.png",
                materials = {
                    ["aluminium"] = 4,
                    ["steel"]     = 2,
                    ["rubber"]    = 2,
                }
            },
            ["mod_bodywork"] = {
                icon = "https://i.postimg.cc/YG4Jj5mR/mod-bodywork.png",
                materials = {
                    ["steel"]        = 5,
                    ["aluminium"]    = 3,
                    ["carbon_fiber"] = 2,
                    ["plastic"]      = 2,
                }
            },
            ["mod_enginebay"] = {
                icon = "https://i.postimg.cc/7GpjzKgW/mod-enginebay.png",
                materials = {
                    ["aluminium"]      = 4,
                    ["copper"]         = 3,
                    ["plastic"]        = 2,
                    ["electric_scrap"] = 2,
                }
            },
        }
    },

    { -- KITS AND TOOLS
        label = "Kits & Tools",
        description = "Kits are used by tuners for different stuff.",
        icon = "https://i.postimg.cc/gxCk6rqd/tuner-tablet.png",
        recipe = {
            ["tuner_tablet"] = {
                icon = "https://i.postimg.cc/gxCk6rqd/tuner-tablet.png",
                materials = {
                    ["plastic"]       = 3,
                    ["electric_scrap"]= 4,
                    ["glass"]         = 2,
                    ["copper"]        = 2,
                    ["aluminium"]     = 1,
                }
            },
            ["tuner_repairkit"] = {
                icon = "https://i.postimg.cc/LJc6ZhBS/tuner-repairkit.png",
                materials = {
                    ["steel"]         = 2,
                    ["plastic"]       = 2,
                    ["rubber"]        = 1,
                    ["synthetic_oil"] = 1,
                    ["electric_scrap"]= 1,
                }
            },
            ["tuner_enghoist"] = {
                icon = "https://i.postimg.cc/QF2xWVg2/tuner-enghoist.png",
                materials = {
                    ["steel"]         = 5,
                    ["scrap_metal"]   = 3,
                    ["rubber"]        = 2,
                    ["carbon_fiber"]  = 1,
                    ["synthetic_oil"] = 1,
                    ["brass"]         = 1,
                }
            },
            ["nos_empty_bottle"] = {
                icon = "https://i.postimg.cc/LJc6ZhBF/nos-empty-bottle.png",
                materials = {
                    ["steel"]         = 3,
                    ["aluminium"]     = 2,
                    ["carbon_fiber"]  = 1,
                    ["synthetic_oil"] = 1,
                    ["rubber"]        = 1,
                    ["acid"]          = 1,
                }
            },
            ["nos_purge_dye"] = {
                icon = "https://i.postimg.cc/ZWGKy0Ft/nos-purge-dye.png",
                materials = {
                    ["synthetic_oil"] = 6,
                    ["acid"]          = 8,
                    ["plastic"]       = 1,
                    ["copper"]        = 1,
                    ["glass"]         = 2,
                }
            },
        }
    },

    { -- CUSTOM
        label = "Custom",
        description = "Custom items can be crafted here.",
        icon = "https://i.ibb.co/vQXJgJd/mod-bullettires.png",
        recipe = {
            ["mod_bullettires"] = {
                icon = "https://i.ibb.co/vQXJgJd/mod-bullettires.png",
                materials = {
                    ["rubber"]        = 5,
                    ["steel"]         = 4,
                    ["carbon_fiber"]  = 3,
                    ["synthetic_oil"] = 2,
                }
            },
            ["mod_drifttires"] = {
                icon = "https://i.ibb.co/pRx0whN/mod-drifttires.png",
                materials = {
                    ["rubber"]        = 6,
                    ["steel"]         = 2,
                    ["synthetic_oil"] = 2,
                    ["plastic"]       = 1,
                }
            },
            ["mod_stocktires"] = {
                icon = "https://i.ibb.co/mHVgnsz/mod-stocktires.png",
                materials = {
                    ["rubber"]        = 4,
                    ["steel"]         = 1,
                    ["synthetic_oil"] = 1,
                }
            },
        }
    },

}
```

## How to integrate my own crafting script?

To integrate your own crafting resource follow these steps.

{% stepper %}
{% step %}

### Disable the built-in crafting

Navigate to `t1ger_tuning/shared/shop.lua` and find the option called `Config.Shop.Workbench` and set the `enable` value to `false`.
{% endstep %}

{% step %}

### Find function to modify

Navigate to `t1ger_tuning/client/shop/markers/workbench.lua` and find the function called `WorkbenchMain`.
{% endstep %}

{% step %}

### Add your export or event

You will see this section:

```lua
    if not Config.Shop.Workbench.enable then
        -- add export/event to open your own crafting stuff 
    else
```

Inside the if statement, you can add your own export/event.
{% endstep %}
{% endstepper %}


# Supplier

t1ger\_tuning/shared/supplier.lua

Our built in supplier system has categories to easily acquire the required items.

Each category will have:

* `title` (string) — the title of the category
* `icon` (string) — an icon for the category
* `items` (table) — the items to be listed in the category. Item name is the index of each entry and:
  * `price` (number) — the price of the item
  * `icon` (string) — the icon of the item

```lua
return {
    {
        title = "Kits & Tools",
        icon = "https://i.postimg.cc/gxCk6rqd/tuner-tablet.png",
        items = {
            ["tuner_tablet"] = {price = 1500, icon = "https://i.postimg.cc/gxCk6rqd/tuner-tablet.png"},
            ["tuner_repairkit"] = {price = 300, icon = "https://i.postimg.cc/LJc6ZhBS/tuner-repairkit.png"},
            ["tuner_enghoist"] = {price = 800, icon = "https://i.postimg.cc/QF2xWVg2/tuner-enghoist.png"},
            ["nos_shots_bottle"] = {price = 7500, icon = "https://i.postimg.cc/nXycQMY8/nos-shots-bottle.png"},
            ["nos_empty_bottle"] = {price = 2000, icon = "https://i.postimg.cc/LJc6ZhBF/nos-empty-bottle.png"},
            ["nos_purge_dye"] = {price = 12500, icon = "https://i.postimg.cc/ZWGKy0Ft/nos-purge-dye.png"}
        }
    },

    {
        title = "Performance",
        icon  = "https://i.postimg.cc/VrS35xb4/mod-brakes.png",
        items = {
            ["mod_engine"]       = { price = 3000, icon = "https://i.postimg.cc/G8Z6DXk7/mod-engine.png" },
            ["mod_brakes"]       = { price = 2000, icon = "https://i.postimg.cc/VrS35xb4/mod-brakes.png" },
            ["mod_transmission"] = { price = 2500, icon = "https://i.postimg.cc/SYC3fcdZ/mod-transmission.png" },
            ["mod_suspension"]   = { price = 1500, icon = "https://i.postimg.cc/RJKyLwdT/mod-suspension.png" },
            ["mod_armor"]        = { price = 7500, icon = "https://i.postimg.cc/627DTkG0/mod-armor.png" },
            ["mod_turbo"]        = { price = 1000, icon = "https://i.postimg.cc/nMDyxtxx/mod-turbo.png" },
        }
    },

    {
        title = "Cosmetics",
        icon  = "https://i.postimg.cc/4HVqQpPK/mod-respray.png",
        items = {
            ["mod_wheels"]       = { price = 350,  icon = "https://i.postimg.cc/yWZMKzK6/mod-wheels.png" },
            ["mod_tyresmoke"]    = { price = 175,  icon = "https://i.postimg.cc/kDb0CdCq/mod-tyresmoke.png" },
            ["mod_headlights"]    = { price = 250,  icon = "https://i.postimg.cc/dkzgC52w/mod-headlights.png" },
            ["mod_neon"]         = { price = 900,  icon = "https://i.postimg.cc/TLZBbtVy/mod-neon.png" },
            ["mod_respray"]      = { price = 200,  icon = "https://i.postimg.cc/4HVqQpPK/mod-respray.png" },
            ["mod_livery"]       = { price = 2000, icon = "https://i.postimg.cc/wySnNwX7/mod-livery.png" },
            ["mod_windowtint"]   = { price = 75,   icon = "https://i.postimg.cc/9z762j2f/mod-windowtint.png" },
            ["mod_plate"]        = { price = 450,  icon = "https://i.postimg.cc/BPHkB2pv/mod-plate.png" },
            ["mod_horn"]         = { price = 50,   icon = "https://i.postimg.cc/Q9Rv7fQ8/mod-horn.png" },
            ["mod_extras"]       = { price = 250,  icon = "https://i.postimg.cc/62DFZMrs/mod-extras.png" },
            ["mod_bodywork"]     = { price = 650,  icon = "https://i.postimg.cc/YG4Jj5mR/mod-bodywork.png" },
            ["mod_enginebay"]    = { price = 800,  icon = "https://i.postimg.cc/7GpjzKgW/mod-enginebay.png" },
            ["mod_exterior"]     = { price = 400,  icon = "https://i.postimg.cc/MMhgB9yC/mod-exterior.png" },
            ["mod_interior"]     = { price = 300,  icon = "https://i.postimg.cc/hzHNm2Lv/mod-interior.png" },
        }
    },

    {
        title = "Custom",
        icon = "https://i.postimg.cc/phg9WkG1/mod-drifttires.png",
        items = {
            ["mod_bullettires"] = {price = 8000, icon = "https://i.postimg.cc/G8ZBLz77/mod-bullettires.png"},
            ["mod_drifttires"] = {price = 5000, icon = "https://i.postimg.cc/phg9WkG1/mod-drifttires.png"},
            ["mod_stocktires"] = {price = 100, icon = "https://i.postimg.cc/w3myf8M2/mod-stocktires.png"},
        }
    },
}
```


# Parts

t1ger\_tuning/shared/parts.lua

```lua
Config.TuningParts = {
    mod_engine       = { label = "Vehicle Engine", image = "https://i.postimg.cc/G8Z6DXk7/mod-engine.png" },
    mod_brakes       = { label = "Vehicle Brakes", image = "https://i.postimg.cc/VrS35xb4/mod-brakes.png" },
    mod_transmission = { label = "Vehicle Transmission", image = "https://i.postimg.cc/SYC3fcdZ/mod-transmission.png" },
    mod_suspension   = { label = "Vehicle Suspension", image = "https://i.postimg.cc/RJKyLwdT/mod-suspension.png" },
    mod_armor        = { label = "Vehicle Armor", image = "https://i.postimg.cc/627DTkG0/mod-armor.png" },
    mod_turbo        = { label = "Vehicle Turbo", image = "https://i.postimg.cc/nMDyxtxx/mod-turbo.png" },
    mod_wheels       = { label = "Vehicle Wheels", image = "https://i.postimg.cc/yWZMKzK6/mod-wheels.png" },
    mod_tyresmoke    = { label = "Vehicle Tyre Smoke", image = "https://i.postimg.cc/kDb0CdCq/mod-tyresmoke.png" },
    mod_headlights   = { label = "Vehicle Headlights", image = "https://i.postimg.cc/dkzgC52w/mod-headlights.png" },
    mod_neon         = { label = "Vehicle Neon", image = "https://i.postimg.cc/TLZBbtVy/mod-neon.png" },
    mod_respray      = { label = "Vehicle Respray", image = "https://i.postimg.cc/4HVqQpPK/mod-respray.png" },
    mod_livery       = { label = "Vehicle Livery", image = "https://i.postimg.cc/wySnNwX7/mod-livery.png" },
    mod_windowtint   = { label = "Vehicle Window Tint", image = "https://i.postimg.cc/9z762j2f/mod-windowtint.png" },
    mod_plate        = { label = "Vehicle Plate", image = "https://i.postimg.cc/BPHkB2pv/mod-plate.png" },
    mod_horn         = { label = "Vehicle Horn", image = "https://i.postimg.cc/Q9Rv7fQ8/mod-horn.png" },
    mod_extras       = { label = "Vehicle Extras", image = "https://i.postimg.cc/62DFZMrs/mod-extras.png" },
    mod_bodywork     = { label = "Vehicle Bodywork", image = "https://i.postimg.cc/YG4Jj5mR/mod-bodywork.png" },
    mod_enginebay    = { label = "Vehicle Engine Bay", image = "https://i.postimg.cc/7GpjzKgW/mod-enginebay.png" },
    mod_exterior     = { label = "Vehicle Exterior", image = "https://i.postimg.cc/MMhgB9yC/mod-exterior.png" },
    mod_interior     = { label = "Vehicle Interior", image = "https://i.postimg.cc/hzHNm2Lv/mod-interior.png" },
}

Config.Kits = {
    tuner_tablet     = { label = "Tuner Tablet",           image = "https://i.postimg.cc/gxCk6rqd/tuner-tablet.png" },
    tuner_repairkit  = { label = "Tuner Repair Kit",       image = "https://i.postimg.cc/LJc6ZhBS/tuner-repairkit.png" },
    tuner_enghoist   = { label = "Tuner Engine Hoist",     image = "https://i.postimg.cc/QF2xWVg2/tuner-enghoist.png" },
    nos_shots_bottle = { label = "NOS 10-Shots (1lb)",     image = "https://i.postimg.cc/nXycQMY8/nos-shots-bottle.png" },
    nos_empty_bottle = { label = "NOS Empty (1lb)",        image = "https://i.postimg.cc/LJc6ZhBF/nos-empty-bottle.png" },
    nos_purge_dye    = { label = "NOS Purge Dye",          image = "https://i.postimg.cc/ZWGKy0Ft/nos-purge-dye.png" },
}

Config.Tires = {
    mod_bullettires  = { label = "Stock Tires",            image = "https://i.postimg.cc/G8ZBLz77/mod-bullettires.png" },
    mod_drifttires   = { label = "Drift Tires",            image = "https://i.postimg.cc/phg9WkG1/mod-drifttires.png" },
    mod_stocktires   = { label = "Bulletproof Tires",      image = "https://i.postimg.cc/w3myf8M2/mod-stocktires.png" },
}

Config.Materials = { -- index is item name and value is item label.
    scrap_metal = "Scrap Metal",
    steel = "Steel",
    aluminium = "Aluminium",
    plastic = "Plastic",
    rubber = "Rubber",
    electric_scrap = "Electric Scrap",
    glass = "Glass",
    copper = "Copper",
    carbon_fiber = "Carbon Fiber",
    brass = "Brass",
    synthetic_oil = "Synthetic Oil",
    acid = "Acid"
}
```

* `label` (string) — the label of the tuning part
* `image`(string) — the icon for the tuning part


# Mod Types

t1ger\_tuning/shared/modtypes.lua

```lua
-- shared/modtypes.lua
-- Defines all mod types available in the tuning menu.
--
-- Fields per mod:
--   label      — display name shown in menus
--   modType    — GTA native mod slot number (or string key for special mods)
--   item       — item name from Config.TuningParts used for mod order installation
--   price      — base price (used if no variants defined)
--   escalation — if true, price increases progressively per variant
--   category   — menu category ("performance", "styling", "wheels", "lights", "respray")
--   icon       — URL to icon image
--   prop       — prop carried by tuner during installation { model, pos, rot }
--   anim       — animations during installation { idle = {...}, install = {...} }
--   variants   — optional fixed variant list (if not set, uses native GTA mod count)

return {

    -- ── Bodywork ──────────────────────────────────────────────────────────

    modSpoilers = {
        label = "Spoiler", modType = 0, item = "mod_bodywork", price = 700, escalation = true, category = "styling", installPoint = "rear",
        icon  = "https://i.postimg.cc/Zvp2x6Hr/mod-spoiler.png",
        prop  = { model = "imp_prop_impexp_spoiler_01a",     pos = { x = 0.0,   y = -0.2,  z = -0.2  }, rot = { x = 0.0,   y = 0.0,  z = -180.0 } },
        anim  = { idle = { dict = "anim@heists@box_carry@", name = "idle",                blendIn = 4.0, blendOut = 1.0, duration = -1, flag = 49 },
                  install = { dict = "mini@repair",          name = "fixing_a_player",     blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1  } },
    },

    modFrontBumper = {
        label = "Front Bumper", modType = 1, item = "mod_bodywork", price = 2100, escalation = true, category = "styling", installPoint = "front",
        icon  = "https://i.postimg.cc/Vr32tKqw/mod-frontbumper.png",
        prop  = { model = "imp_prop_impexp_front_bumper_01a", pos = { x = 0.0,   y = -0.25, z = -0.15 }, rot = { x = 0.0,   y = 0.0,  z = -180.0 } },
        anim  = { idle = { dict = "anim@heists@box_carry@",  name = "idle",                blendIn = 4.0, blendOut = 1.0, duration = -1, flag = 49 },
                  install = { dict = "anim@amb@clubhouse@tutorial@bkr_tut_ig3@", name = "machinic_loop_mechandplayer", blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1 } },
    },

    modRearBumper = {
        label = "Rear Bumper", modType = 2, item = "mod_bodywork", price = 1800, escalation = true, category = "styling", installPoint = "rear",
        icon  = "https://i.postimg.cc/Zvp2x6HW/mod-rearbumper.png",
        prop  = { model = "imp_prop_impexp_rear_bumper_03a", pos = { x = 0.0,   y = -0.25, z = -0.15 }, rot = { x = -20.0, y = 0.0,  z = -180.0 } },
        anim  = { idle = { dict = "anim@heists@box_carry@",  name = "idle",                blendIn = 4.0, blendOut = 1.0, duration = -1, flag = 49 },
                  install = { dict = "anim@amb@clubhouse@tutorial@bkr_tut_ig3@", name = "machinic_loop_mechandplayer", blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1 } },
    },

    modSideSkirt = {
        label = "Skirt", modType = 3, item = "mod_bodywork", price = 800, escalation = true, category = "styling", installPoint = "vehicle",
        icon  = "https://i.postimg.cc/MfVNm15B/mod-sideskirt.png",
        prop  = { model = "imp_prop_impexp_rear_bumper_01a", pos = { x = 0.0,   y = -0.25, z = -0.15 }, rot = { x = -20.0, y = 0.0,  z = -180.0 } },
        anim  = { idle = { dict = "anim@heists@box_carry@",  name = "idle",                blendIn = 4.0, blendOut = 1.0, duration = -1, flag = 49 },
                  install = { dict = "anim@amb@clubhouse@tutorial@bkr_tut_ig3@", name = "machinic_loop_mechandplayer", blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1 } },
    },

    modExhaust = {
        label = "Exhaust", modType = 4, item = "mod_exterior", price = 1000, escalation = true, category = "styling", installPoint = "rear",
        icon  = "https://i.postimg.cc/YGJTFd1T/mod-exhaust.png",
        prop  = { model = "imp_prop_impexp_exhaust_01",       pos = { x = -0.1,  y = -0.20, z = -0.20 }, rot = { x = 20.0,  y = 10.0, z = 90.0   } },
        anim  = { idle = { dict = "anim@heists@box_carry@",  name = "idle",                blendIn = 4.0, blendOut = 1.0, duration = -1, flag = 49 },
                  install = { dict = "anim@amb@clubhouse@tutorial@bkr_tut_ig3@", name = "machinic_loop_mechandplayer", blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1 } },
    },

    modFrame = {
        label = "Roll Cage", modType = 5, item = "mod_bodywork", price = 2300, escalation = true, category = "styling", installPoint = "interior",
        icon  = "https://i.postimg.cc/pykkFGRs/mod-Frame.png",
        prop  = { model = "imp_prop_impexp_rear_bars_01b",    pos = { x = 0.0,   y = 0.60,  z = -0.26 }, rot = { x = -30.0, y = 0.0,  z = -180.0 } },
        anim  = { idle = { dict = "anim@heists@box_carry@",  name = "idle",                blendIn = 4.0, blendOut = 1.0, duration = -1, flag = 49 },
                  install = { dict = "mini@repair",          name = "fixing_a_player",     blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1  } },
    },

    modGrille = {
        label = "Grill", modType = 6, item = "mod_bodywork", price = 900, escalation = true, category = "styling", installPoint = "front",
        icon  = "https://i.postimg.cc/phg3jsfx/mod-grille.png",
        prop  = { model = "imp_prop_impexp_radiator_01",      pos = { x = 0.0,   y = -0.28, z = -0.23 }, rot = { x = 0.0,   y = 0.0,  z = 0.0    } },
        anim  = { idle = { dict = "anim@heists@box_carry@",  name = "idle",                blendIn = 4.0, blendOut = 1.0, duration = -1, flag = 49 },
                  install = { dict = "anim@amb@clubhouse@tutorial@bkr_tut_ig3@", name = "machinic_loop_mechandplayer", blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1 } },
    },

    modHood = {
        label = "Hood", modType = 7, item = "mod_bodywork", price = 1900, escalation = true, category = "styling", installPoint = "front",
        icon  = "https://i.postimg.cc/CBW98cGw/mod-hood.png",
        prop  = { model = "imp_prop_impexp_bonnet_04a",       pos = { x = 0.0,   y = 0.20,  z = 0.12  }, rot = { x = -20.0, y = 0.0,  z = 180.0  } },
        anim  = { idle = { dict = "anim@heists@box_carry@",  name = "idle",                blendIn = 4.0, blendOut = 1.0, duration = -1, flag = 49 },
                  install = { dict = "mini@repair",          name = "fixing_a_player",     blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1  } },
    },

    modFender = {
        label = "Left Fender", modType = 8, item = "mod_bodywork", price = 1200, escalation = true, category = "styling", installPoint = "vehicle",
        icon  = "https://i.postimg.cc/Fd2wSTyX/mod-fender.png",
        prop  = { model = "imp_prop_impexp_car_panel_01a",    pos = { x = -0.15, y = -0.18, z = -0.16 }, rot = { x = 5.0,   y = 0.0,  z = -90.0  } },
        anim  = { idle = { dict = "anim@heists@box_carry@",  name = "idle",                blendIn = 4.0, blendOut = 1.0, duration = -1, flag = 49 },
                  install = { dict = "anim@amb@clubhouse@tutorial@bkr_tut_ig3@", name = "machinic_loop_mechandplayer", blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1 } },
    },

    modRightFender = {
        label = "Right Fender", modType = 9, item = "mod_bodywork", price = 1200, escalation = true, category = "styling", installPoint = "vehicle",
        icon  = "https://i.postimg.cc/bSkW91gD/mod-rightfender.png",
        prop  = { model = "imp_prop_impexp_car_panel_01a",    pos = { x = 0.0,   y = -0.0,  z = -0.4  }, rot = { x = 0.0,   y = 0.0,  z = 90.0   } },
        anim  = { idle = { dict = "anim@heists@box_carry@",  name = "idle",                blendIn = 4.0, blendOut = 1.0, duration = -1, flag = 49 },
                  install = { dict = "anim@amb@clubhouse@tutorial@bkr_tut_ig3@", name = "machinic_loop_mechandplayer", blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1 } },
    },

    modRoof = {
        label = "Roof", modType = 10, item = "mod_bodywork", price = 1100, escalation = true, category = "styling", installPoint = "vehicle",
        icon  = "https://i.postimg.cc/2LhM7nGB/mod-roof.png",
        prop  = { model = "prop_cs_cardbox_01",               pos = { x = 0.0,   y = -0.2,  z = -0.1  }, rot = { x = 40.0,  y = 0.0,  z = 0.0    } },
        anim  = { idle = { dict = "anim@heists@box_carry@",  name = "idle",                blendIn = 4.0, blendOut = 1.0, duration = -1, flag = 49 },
                  install = { dict = "mini@repair",          name = "fixing_a_player",     blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1  } },
    },

    -- ── Performance ───────────────────────────────────────────────────────

    modEngine = {
        label = "Engine", modType = 11, item = "mod_engine", category = "performance", installPoint = "engine",
        icon  = "https://i.postimg.cc/G8Z6DXk7/mod-engine.png",
        prop  = { model = "imp_prop_impexp_engine_part_01a",  pos = { x = 0.0,   y = -0.1,  z = -0.20 }, rot = { x = 40.0,  y = 0.0,  z = 0.0    } },
        anim  = { idle = { dict = "anim@heists@box_carry@",  name = "idle",                blendIn = 4.0, blendOut = 1.0, duration = -1, flag = 49 },
                  install = { dict = "mini@repair",          name = "fixing_a_player",     blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1  } },
        variants = {
            ["-1"] = { label = "Stock Engine", index = -1, price = 3000 },
            ["0"] = { label = "EMS Upg. Level 1", index = 0, price = 5000 },
            ["1"] = { label = "EMS Upg. Level 2", index = 1, price = 7000 },
            ["2"] = { label = "EMS Upg. Level 3", index = 2, price = 9000 },
            ["3"] = { label = "EMS Upg. Level 4", index = 3, price = 12000 },
            ["4"] = { label = "Custom Engine Tune", index = 4, price = 15000 }
        }
    },

    modBrakes = {
        label = "Brakes", modType = 12, item = "mod_brakes", category = "performance", installPoint = "wheel",
        icon  = "https://i.postimg.cc/VrS35xb4/mod-brakes.png",
        prop  = { model = "imp_prop_impexp_brake_caliper_01a", pos = { x = 0.0,  y = -0.1,  z = -0.2  }, rot = { x = 0.0,   y = 90.0, z = 0.0    } },
        anim  = { idle = { dict = "anim@heists@box_carry@",  name = "idle",                blendIn = 4.0, blendOut = 1.0, duration = -1, flag = 49 },
                  install = { dict = "anim@amb@clubhouse@tutorial@bkr_tut_ig3@", name = "machinic_loop_mechandplayer", blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1 } },
        variants = {
            ["-1"] = { label = "Stock Brakes", index = -1, price = 1500 },
            ["0"] = { label = "Street Brakes", index = 0, price = 2500 },
            ["1"] = { label = "Sports Brakes", index = 1, price = 3500 },
            ["2"] = { label = "Race Brakes", index = 2, price = 4500 },
            ["3"] = { label = "Custom Brakes", index = 3, price = 5500 }
        }
    },

    modTransmission = {
        label = "Transmission", modType = 13, item = "mod_transmission", category = "performance", installPoint = "engine",
        icon  = "https://i.postimg.cc/SYC3fcdZ/mod-transmission.png",
        prop  = { model = "imp_prop_impexp_gearbox_01",       pos = { x = 0.0,   y = -0.1,  z = -0.2  }, rot = { x = 0.0,   y = 0.0,  z = 90.0   } },
        anim  = { idle = { dict = "anim@heists@box_carry@",  name = "idle",                blendIn = 4.0, blendOut = 1.0, duration = -1, flag = 49 },
                  install = { dict = "mini@repair",          name = "fixing_a_player",     blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1  } },
        variants = {
            ["-1"] = { label = "Stock Transmission", index = -1, price = 2000 },
            ["0"] = { label = "Street Transmission", index = 0, price = 3500 },
            ["1"] = { label = "Sports Transmission", index = 1, price = 5000 },
            ["2"] = { label = "Race Transmission", index = 2, price = 6500 },
            ["3"] = { label = "Custom Transmission", index = 3, price = 7000 }
        }
    },

    modSuspension = {
        label = "Suspension", modType = 15, item = "mod_suspension", category = "performance", installPoint = "wheel",
        icon  = "https://i.postimg.cc/jnqX1N4s/mod-Suspension.png",
        prop  = { model = "prop_cs_cardbox_01",               pos = { x = 0.0,   y = -0.2,  z = -0.1  }, rot = { x = 135.0, y = 0.0,  z = 0.0    } },
        anim  = { idle = { dict = "anim@heists@box_carry@",  name = "idle",                blendIn = 4.0, blendOut = 1.0, duration = -1, flag = 49 },
                  install = { dict = "anim@amb@clubhouse@tutorial@bkr_tut_ig3@", name = "machinic_loop_mechandplayer", blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1 } },
        variants = {
            ["-1"] = { label = "Stock Suspension", index = -1, price = 1000 },
            ["0"] = { label = "Lowered Suspension", index = 0, price = 2000 },
            ["1"] = { label = "Street Suspension", index = 1, price = 3000 },
            ["2"] = { label = "Sports Suspension", index = 2, price = 4000 },
            ["3"] = { label = "Competition Suspension", index = 3, price = 5000 },
            ["4"] = { label = "Custom Suspension", index = 4, price = 7500 }
        }
    },

    modArmor = {
        label = "Armor", modType = 16, item = "mod_armor", category = "performance", installPoint = "vehicle",
        icon  = "https://i.postimg.cc/YL23PgzM/mod-Armor.png",
        prop  = { model = "prop_cs_cardbox_01",               pos = { x = 0.0,   y = -0.2,  z = -0.1  }, rot = { x = 135.0, y = 0.0,  z = 0.0    } },
        anim  = { idle = { dict = "anim@heists@box_carry@",  name = "idle",                blendIn = 4.0, blendOut = 1.0, duration = -1, flag = 49 },
                  install = { dict = "mini@repair",          name = "fixing_a_player",     blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1  } },
        variants = {
            ["-1"] = { label = "Stock Armor", index = -1, price = 2500 },
            ["0"] = { label = "20% Armor", index = 0, price = 5000 },
            ["1"] = { label = "40% Armor", index = 1, price = 10000 },
            ["2"] = { label = "60% Armor", index = 2, price = 15000 },
            ["3"] = { label = "80% Armor", index = 3, price = 20000 },
            ["4"] = { label = "100% Armor", index = 4, price = 25000 }
        }
    },

    modTurbo = {
        label = "Turbo Upgrade", modType = 18, item = "mod_turbo", category = "performance", installPoint = "engine",
        icon  = "https://i.postimg.cc/JtRPtVVj/mod-Turbo.png",
        prop  = { model = "prop_cs_cardbox_01",               pos = { x = 0.0,   y = -0.2,  z = -0.1  }, rot = { x = 135.0, y = 0.0,  z = 0.0    } },
        anim  = { idle = { dict = "anim@heists@box_carry@",  name = "idle",                blendIn = 4.0, blendOut = 1.0, duration = -1, flag = 49 },
                  install = { dict = "mini@repair",          name = "fixing_a_player",     blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1  } },
        variants = {
            ["0"] = { label = "Stock Turbo", index = 0, price = 500 },
            ["1"] = { label = "Upgraded Turbo", index = 1, price = 7000 }
        }
    },

    -- ── Wheels ────────────────────────────────────────────────────────────

    tyreSmokeColor = {
        label = "Tyre Smoke", modType = 20, item = "mod_tyresmoke", category = "wheels", installPoint = "wheel",
        icon  = "https://i.postimg.cc/kDb0CdCq/mod-tyresmoke.png",
        prop  = { model = "imp_prop_impexp_tyre_01a",         pos = { x = 0.0,   y = -0.10, z = 0.15  }, rot = { x = 0.0,   y = 0.0,  z = 0.0    } },
        anim  = { idle = { dict = "anim@heists@box_carry@",  name = "idle",                blendIn = 4.0, blendOut = 1.0, duration = -1, flag = 49 },
                  install = { dict = "anim@amb@clubhouse@tutorial@bkr_tut_ig3@", name = "machinic_loop_mechandplayer", blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1 } },
        variants = {
            ["0"] = { label = "White", rgb = { 254, 254, 254 }, price = 150 },
            ["1"] = { label = "Black", rgb = { 1, 1, 1 }, price = 150 },
            ["2"] = { label = "Blue", rgb = { 0, 150, 255 }, price = 150 },
            ["3"] = { label = "Yellow", rgb = { 255, 255, 50 }, price = 150 },
            ["4"] = { label = "Orange", rgb = { 255, 153, 51 }, price = 150 },
            ["5"] = { label = "Red", rgb = { 255, 10, 10 }, price = 150 },
            ["6"] = { label = "Green", rgb = { 10, 255, 10 }, price = 150 },
            ["7"] = { label = "Purple", rgb = { 153, 10, 153 }, price = 150 },
            ["8"] = { label = "Pink", rgb = { 255, 102, 178 }, price = 150 },
            ["9"] = { label = "Gray", rgb = { 128, 128, 128 }, price = 150 }
        }
    },

    modFrontWheels = {
        label = "Wheels", modType = 23, item = "mod_wheels", category = "wheels", installPoint = "wheel",
        icon  = "https://i.postimg.cc/SjmDjFFW/mod-Front-Wheels.png",
        prop  = { model = "imp_prop_impexp_wheel_05a",                  pos = { x = 0.0,   y = -0.1,  z = 0.2 }, rot = { x = 0.0,  y = 0.0,  z = 0.0    } },
        anim  = { idle = { dict = "anim@heists@box_carry@",  name = "idle",                blendIn = 4.0, blendOut = 1.0, duration = -1, flag = 49 },
                  install = { dict = "anim@amb@clubhouse@tutorial@bkr_tut_ig3@", name = "machinic_loop_mechandplayer", blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1 } },
        variants = {
            ["0"] = { label = "Sport", index = 0, price = 1200 },
            ["1"] = { label = "Muscle", index = 1, price = 1000 },
            ["2"] = { label = "Lowrider", index = 2, price = 1100 },
            ["3"] = { label = "SUV", index = 3, price = 1400 },
            ["4"] = { label = "Offroad", index = 4, price = 900 },
            ["5"] = { label = "Tuner", index = 5, price = 1600 },
            ["6"] = { label = "Bike Front", index = 6, price = 700 },
            ["7"] = { label = "High End", index = 7, price = 1800 },
            ["8"] = { label = "Benny's Original", index = 8, price = 1700 },
            ["9"] = { label = "Benny's Bespoke", index = 9, price = 2000 },
            ["10"] = { label = "Open Wheel", index = 10, price = 2200 },
            ["11"] = { label = "Street", index = 11, price = 2500 },
            ["12"] = { label = "Track", index = 12, price = 3200 }
        }
    },

    modBackWheels = {
        label = "Bike Rear", modType = 24, item = "mod_wheels", category = "wheels", installPoint = "wheel",
        icon  = "https://i.postimg.cc/SjmDjFFW/mod-Front-Wheels.png",
        prop  = { model = "imp_prop_impexp_wheel_05a",                  pos = { x = 0.0,   y = -0.1,  z = 0.2 }, rot = { x = 0.0,  y = 0.0,  z = 0.0    } },
        anim  = { idle = { dict = "anim@heists@box_carry@",  name = "idle",                blendIn = 4.0, blendOut = 1.0, duration = -1, flag = 49 },
                  install = { dict = "anim@amb@clubhouse@tutorial@bkr_tut_ig3@", name = "machinic_loop_mechandplayer", blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1 } },
    },

    customTires = {
        label = "Custom Tires", modType = "customTires", item = "mod_wheels", category = "wheels", installPoint = "wheel",
        icon  = "https://i.postimg.cc/1ngL4kNv/mod-customtires.png",
        prop  = { model = "imp_prop_impexp_tyre_03a",                  pos = { x = 0.0,   y = -0.1,  z = -0.20 }, rot = { x = 40.0,  y = 0.0,  z = 0.0    } },
        anim  = { idle = { dict = "anim@heists@box_carry@",  name = "idle",                blendIn = 4.0, blendOut = 1.0, duration = -1, flag = 49 },
                  install = { dict = "anim@amb@clubhouse@tutorial@bkr_tut_ig3@", name = "machinic_loop_mechandplayer", blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1 } },
        variants  = {
            ["0"] = { label = "Stock Sidewall",  index = 0, price = 0 },
            ["1"] = { label = "Custom Sidewall", index = 1, price = 500 },
        }
    },

    driftTyres = {
        label = "Drift Tyres", modType = "driftTyres", item = "mod_drifttires", category = "wheels", installPoint = "wheel",
        icon  = "https://i.postimg.cc/WFDQtBkR/mod-drifttires.png",
        prop  = { model = "imp_prop_impexp_tyre_03a",                  pos = { x = 0.0,   y = -0.1,  z = -0.20 }, rot = { x = 40.0,  y = 0.0,  z = 0.0    } },
        anim  = { idle = { dict = "anim@heists@box_carry@",  name = "idle",                blendIn = 4.0, blendOut = 1.0, duration = -1, flag = 49 },
                  install = { dict = "anim@amb@clubhouse@tutorial@bkr_tut_ig3@", name = "machinic_loop_mechandplayer", blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1 } },
    },

    bulletProofTyres = {
        label = "Bulletproof Tyres", modType = "bulletProofTyres", item = "mod_bullettires", category = "wheels", installPoint = "wheel",
        icon  = "https://i.postimg.cc/Fdf21MJD/mod-bulletprooftires.png",
        prop  = { model = "imp_prop_impexp_tyre_03a",                  pos = { x = 0.0,   y = -0.1,  z = -0.20 }, rot = { x = 40.0,  y = 0.0,  z = 0.0    } },
        anim  = { idle = { dict = "anim@heists@box_carry@",  name = "idle",                blendIn = 4.0, blendOut = 1.0, duration = -1, flag = 49 },
                  install = { dict = "anim@amb@clubhouse@tutorial@bkr_tut_ig3@", name = "machinic_loop_mechandplayer", blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1 } },
    },

    -- ── Lights ────────────────────────────────────────────────────────────

    modXenon = {
        label = "Headlights", modType = 22, item = "mod_headlights", category = "lights", installPoint = "front",
        icon  = "https://i.postimg.cc/dkzgC52w/mod-headlights.png",
        prop  = { model = "prop_cs_package_01",               pos = { x = 0.0,   y = -0.05, z = -0.1  }, rot = { x = 100.0, y = 0.0,  z = 0.0    } },
        anim  = { idle = { dict = "anim@heists@box_carry@",  name = "idle",                blendIn = 4.0, blendOut = 1.0, duration = -1, flag = 49 },
                  install = { dict = "mini@repair",          name = "fixing_a_player",     blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1  } },
        variants = {
            ["0"] = { label = "Stock", index = 0, price = 200 },
            ["1"] = { label = "Xenon", index = 1, price = 2000 },
        }
    },

    xenonColor = {
        label = "Xenon Colors", modType = "xenonColor", item = "mod_headlights", category = "lights", installPoint = "front",
        icon  = "https://i.postimg.cc/dkzgC52w/mod-headlights.png",
        prop  = { model = "prop_cs_package_01",               pos = { x = 0.0,   y = -0.05, z = -0.1  }, rot = { x = 100.0, y = 0.0,  z = 0.0    } },
        anim  = { idle = { dict = "anim@heists@box_carry@",  name = "idle",                blendIn = 4.0, blendOut = 1.0, duration = -1, flag = 49 },
                  install = { dict = "mini@repair",          name = "fixing_a_player",     blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1  } },
        variants = {
            ["-1"] = { label = "Default", index = -1, price = 100 },
            ["0"] = { label = "White", index = 0, price = 200 },
            ["1"] = { label = "Blue", index = 1, price = 250 },
            ["2"] = { label = "Electric Blue", index = 2, price = 250 },
            ["3"] = { label = "Mint Green", index = 3, price = 250 },
            ["4"] = { label = "Lime Green", index = 4, price = 250 },
            ["5"] = { label = "Yellow", index = 5, price = 250 },
            ["6"] = { label = "Golden Shower", index = 6, price = 250 },
            ["7"] = { label = "Orange", index = 7, price = 250 },
            ["8"] = { label = "Red", index = 8, price = 250 },
            ["9"] = { label = "Pony Pink", index = 9, price = 250 },
            ["10"] = { label = "Hot Pink", index = 10, price = 250 },
            ["11"] = { label = "Purple", index = 11, price = 250 },
            ["12"] = { label = "Blacklight", index = 12, price = 250 },
        }
    },

    customXenon = {
        label = "Xenon RGB", modType = "customXenon", item = "mod_headlights", category = "lights", installPoint = "front",
        icon  = "https://i.postimg.cc/dkzgC52w/mod-headlights.png",
        prop  = { model = "prop_cs_package_01",               pos = { x = 0.0,   y = -0.05, z = -0.1  }, rot = { x = 100.0, y = 0.0,  z = 0.0    } },
        anim  = { idle = { dict = "anim@heists@box_carry@",  name = "idle",                blendIn = 4.0, blendOut = 1.0, duration = -1, flag = 49 },
                  install = { dict = "mini@repair",          name = "fixing_a_player",     blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1  } },
    },

    modLightbar = {
        label = "Lightbar", modType = 49, item = "mod_exterior", price = 900, escalation = true, category = "styling", installPoint = "vehicle",
        icon  = "https://i.postimg.cc/gXf1hgVJ/mod-lightbar.png",
        prop  = { model = "prop_cs_cardbox_01",               pos = { x = 0.0,   y = -0.2,  z = -0.1  }, rot = { x = 135.0, y = 0.0,  z = 0.0    } },
        anim  = { idle = { dict = "anim@heists@box_carry@",  name = "idle",                blendIn = 4.0, blendOut = 1.0, duration = -1, flag = 49 },
                  install = { dict = "mini@repair",          name = "fixing_a_player",     blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1  } },
    },

    neonEnabled = {
        label = "Neon Lights", modType = "neonEnabled", item = "mod_neon", price = 1000, category = "lights", installPoint = "vehicle",
        icon  = "https://i.postimg.cc/TLZBbtVy/mod-neon.png",
        prop  = { model = "prop_cs_package_01",               pos = { x = 0.0,   y = -0.05, z = -0.1  }, rot = { x = 100.0, y = 0.0,  z = 0.0    } },
        anim  = { idle = { dict = "anim@heists@box_carry@",  name = "idle",                blendIn = 4.0, blendOut = 1.0, duration = -1, flag = 49 },
                  install = { dict = "mini@repair",          name = "fixing_a_player",     blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1  } },
        variants = {
            ["0"] = { label = "Left", index = 0, price = 1000 },
            ["1"] = { label = "Right", index = 1, price = 1000 },
            ["2"] = { label = "Front", index = 2, price = 1000 },
            ["3"] = { label = "Rear", index = 3, price = 1000 },
        }
    },

    neonColor = {
        label = "Neon Colors", modType = "neonColor", item = "mod_neon", category = "lights", installPoint = "vehicle",
        icon  = "https://i.postimg.cc/TLZBbtVy/mod-neon.png",
        prop  = { model = "prop_cs_package_01",               pos = { x = 0.0,   y = -0.05, z = -0.1  }, rot = { x = 100.0, y = 0.0,  z = 0.0    } },
        anim  = { idle = { dict = "anim@heists@box_carry@",  name = "idle",                blendIn = 4.0, blendOut = 1.0, duration = -1, flag = 49 },
                  install = { dict = "mini@repair",          name = "fixing_a_player",     blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1  } },
        variants = {
            ["0"] = { label = "White", rgb = { 222, 222, 255 }, price = 200 },
            ["1"] = { label = "Blue", rgb = { 2, 21, 255 }, price = 200 },
            ["2"] = { label = "Electric Blue", rgb = { 3, 83, 255 }, price = 200 },
            ["3"] = { label = "Mint Green", rgb = { 0, 255, 140 }, price = 200 },
            ["4"] = { label = "Lime Green", rgb = { 94, 222, 1 }, price = 200 },
            ["5"] = { label = "Yellow", rgb = { 255, 255, 0 }, price = 200 },
            ["6"] = { label = "Golden Shower", rgb = { 255, 150, 0 }, price = 200 },
            ["7"] = { label = "Orange", rgb = { 255, 62, 0 }, price = 200 },
            ["8"] = { label = "Red", rgb = { 255, 1, 1 }, price = 200 },
            ["9"] = { label = "Pony Pink", rgb = { 255, 50, 100 }, price = 200 },
            ["10"] = { label = "Hot Pink", rgb = { 255, 5, 190 }, price = 200 },
            ["11"] = { label = "Purple", rgb = { 35, 1, 255 }, price = 200 },
            ["12"] = { label = "Blacklight", rgb = { 15, 3, 255 }, price = 200 }
        }
    },

    windowTint = {
        label = "Window Tints", modType = "windowTint", item = "mod_windowtint", category = "styling", installPoint = "vehicle",
        icon  = "https://i.postimg.cc/9z762j2f/mod-windowtint.png",
        prop  = { model = "h4_prop_yacht_glass_04",           pos = { x = 0.0,   y = -0.1,  z = 0.3   }, rot = { x = 0.0,   y = 0.0,  z = 0.0    } },
        anim  = { idle = { dict = "anim@heists@box_carry@",  name = "idle",                blendIn = 4.0, blendOut = 1.0, duration = -1, flag = 49 },
                  install = { dict = "mini@repair",          name = "fixing_a_player",     blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1  } },
        variants = {
            ["0"] = { label = "None", index = 0, price = 300 },
            ["1"] = { label = "Pure black", index = 1, price = 2500 },
            ["2"] = { label = "Dark Smoke", index = 2, price = 1800 },
            ["3"] = { label = "Light Smoke", index = 3, price = 1200 },
            ["4"] = { label = "Stock", index = 4, price = 300 },
            ["5"] = { label = "Green", index = 5, price = 2200 }
        }
    },

    plateIndex = {
        label = "License Plates", modType = "plateIndex", item = "mod_plate", category = "styling", installPoint = "rear",
        icon  = "https://i.postimg.cc/BPHkB2pv/mod-plate.png",
        prop  = { model = "p_num_plate_01",                   pos = { x = 0.01,  y = -0.1,  z = -0.18 }, rot = { x = -60.0, y = 0.0,  z = 0.0    } },
        anim  = { idle = { dict = "anim@heists@box_carry@",  name = "idle",                blendIn = 4.0, blendOut = 1.0, duration = -1, flag = 49 },
                  install = { dict = "anim@amb@clubhouse@tutorial@bkr_tut_ig3@", name = "machinic_loop_mechandplayer", blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1 } },
        variants = {
            ["0"] = { label = "Blue on White 1", index = 0, price = 300 },
            ["1"] = { label = "Yellow on Black", index = 1, price = 400 },
            ["2"] = { label = "Yellow on Blue", index = 2, price = 500 },
            ["3"] = { label = "Blue on White 2", index = 3, price = 600 },
            ["4"] = { label = "Blue on White 3", index = 4, price = 700 },
            ["5"] = { label = "Yankton", index = 5, price = 800 },
            -- These requires gamebuild 3095:
            ["6"] = { label = "eCola", index = 6, price = 900 },
            ["7"] = { label = "Las Venturas", index = 7, price = 1000 },
            ["8"] = { label = "Liberty City", index = 8, price = 1100 },
            ["9"] = { label = "Los Santos Car Meet", index = 9, price = 1200 },
            ["10"] = { label = "Los Santos Panic", index = 10, price = 1300 },
            ["11"] = { label = "Los Santos Pounders", index = 11, price = 1400 },
            ["12"] = { label = "Sprunk", index = 12, price = 1500 },
        }
    },

    -- ── Respray ───────────────────────────────────────────────────────────

    color1 = {
        label = 'Primary Color', modType = 'color1', item = 'mod_respray', price = 300, escalation = false, category = 'respray', installPoint = 'vehicle',
        icon  = 'https://i.postimg.cc/4HVqQpPK/mod-respray.png',
        prop  = { model = 'ng_proc_spraycan01b',              pos = { x = 0.072, y = 0.041, z = -0.06 }, rot = { x = 33.0,  y = 38.0, z = 0.0    } },
        anim  = { idle = { dict = nil,                       name = nil,                   blendIn = 4.0, blendOut = 1.0, duration = -1, flag = 49 },
                  install = { dict = "anim@amb@business@weed@weed_inspecting_lo_med_hi@", name = "weed_spraybottle_crouch_spraying_03_inspector", blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1 } },
    },

    color2 = {
        label = 'Secondary Color', modType = 'color2', item = 'mod_respray', price = 200, escalation = false, category = 'respray', installPoint = 'vehicle',
        icon  = 'https://i.postimg.cc/4HVqQpPK/mod-respray.png',
        prop  = { model = 'ng_proc_spraycan01b',              pos = { x = 0.072, y = 0.041, z = -0.06 }, rot = { x = 33.0,  y = 38.0, z = 0.0    } },
        anim  = { idle = { dict = nil,                       name = nil,                   blendIn = 4.0, blendOut = 1.0, duration = -1, flag = 49 },
                  install = { dict = "anim@amb@business@weed@weed_inspecting_lo_med_hi@", name = "weed_spraybottle_crouch_spraying_03_inspector", blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1 } },
    },

    pearlescentColor = {
        label = 'Pearlescent Color', modType = 'pearlescentColor', item = 'mod_respray', price = 100, escalation = false, category = 'respray', installPoint = 'vehicle',
        icon  = 'https://i.postimg.cc/4HVqQpPK/mod-respray.png',
        prop  = { model = 'ng_proc_spraycan01b',              pos = { x = 0.072, y = 0.041, z = -0.06 }, rot = { x = 33.0,  y = 38.0, z = 0.0    } },
        anim  = { idle = { dict = nil,                       name = nil,                   blendIn = 4.0, blendOut = 1.0, duration = -1, flag = 49 },
                  install = { dict = "anim@amb@business@weed@weed_inspecting_lo_med_hi@", name = "weed_spraybottle_crouch_spraying_03_inspector", blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1 } },
    },

    wheelColor = {
        label = 'Wheel Color', modType = 'wheelColor', item = 'mod_respray', price = 100, escalation = false, category = 'respray', installPoint = 'wheel',
        icon  = 'https://i.postimg.cc/4HVqQpPK/mod-respray.png',
        prop  = { model = 'ng_proc_spraycan01b',              pos = { x = 0.072, y = 0.041, z = -0.06 }, rot = { x = 33.0,  y = 38.0, z = 0.0    } },
        anim  = { idle = { dict = nil,                       name = nil,                   blendIn = 4.0, blendOut = 1.0, duration = -1, flag = 49 },
                  install = { dict = "anim@amb@business@weed@weed_inspecting_lo_med_hi@", name = "weed_spraybottle_crouch_spraying_03_inspector", blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1 } },
    },

    dashboardColor = {
        label = 'Dashboard Color', modType = 'dashboardColor', item = 'mod_respray', price = 100, escalation = false, category = 'respray', installPoint = 'interior',
        icon  = 'https://i.postimg.cc/4HVqQpPK/mod-respray.png',
        prop  = { model = 'ng_proc_spraycan01b',              pos = { x = 0.072, y = 0.041, z = -0.06 }, rot = { x = 33.0,  y = 38.0, z = 0.0    } },
        anim  = { idle = { dict = nil,                       name = nil,                   blendIn = 4.0, blendOut = 1.0, duration = -1, flag = 49 },
                  install = { dict = "anim@amb@business@weed@weed_inspecting_lo_med_hi@", name = "weed_spraybottle_crouch_spraying_03_inspector", blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1 } },
    },

    interiorColor = {
        label = 'Interior Color', modType = 'interiorColor', item = 'mod_respray', price = 100, escalation = false, category = 'respray', installPoint = 'interior',
        icon  = 'https://i.postimg.cc/4HVqQpPK/mod-respray.png',
        prop  = { model = 'ng_proc_spraycan01b',              pos = { x = 0.072, y = 0.041, z = -0.06 }, rot = { x = 33.0,  y = 38.0, z = 0.0    } },
        anim  = { idle = { dict = nil,                       name = nil,                   blendIn = 4.0, blendOut = 1.0, duration = -1, flag = 49 },
                  install = { dict = "anim@amb@business@weed@weed_inspecting_lo_med_hi@", name = "weed_spraybottle_crouch_spraying_03_inspector", blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1 } },
    },

    modLivery = {
        label = "Livery", modType = 48, item = "mod_livery", price = 1500, escalation = false, category = "respray", installPoint = "vehicle",
        icon  = "https://i.postimg.cc/wySnNwX7/mod-livery.png",
        prop  = { model = "v_ind_cfwrap",                     pos = { x = 0.0,   y = -0.10, z = -0.15 }, rot = { x = 0.0,   y = 0.0,  z = 0.0    } },
        anim  = { idle = { dict = "anim@heists@box_carry@",  name = "idle",                blendIn = 4.0, blendOut = 1.0, duration = -1, flag = 49 },
                  install = { dict = "anim@amb@business@weed@weed_inspecting_lo_med_hi@", name = "weed_spraybottle_crouch_spraying_03_inspector", blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1 } },
    },

    modRoofLivery = {
        label = "Roof Livery", modType = "modRoofLivery", item = "mod_livery", price = 250, escalation = false, category = "respray", installPoint = "vehicle",
        icon  = "https://i.postimg.cc/wySnNwX7/mod-livery.png",
        prop  = { model = "v_ind_cfwrap",                     pos = { x = 0.0,   y = -0.10, z = -0.15 }, rot = { x = 0.0,   y = 0.0,  z = 0.0    } },
        anim  = { idle = { dict = "anim@heists@box_carry@",  name = "idle",                blendIn = 4.0, blendOut = 1.0, duration = -1, flag = 49 },
                  install = { dict = "anim@amb@business@weed@weed_inspecting_lo_med_hi@", name = "weed_spraybottle_crouch_spraying_03_inspector", blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1 } },
    },

    -- ── Styling — Interior ────────────────────────────────────────────────

    modHorns = {
        label = "Horn", modType = 14, item = "mod_horn", escalation = false, category = "styling", installPoint = "interior",
        icon  = "https://i.postimg.cc/Q9Rv7fQ8/mod-horn.png",
        prop  = { model = "prop_cs_cardbox_01",               pos = { x = 0.0,   y = -0.2,  z = -0.1  }, rot = { x = 135.0, y = 0.0,  z = 0.0    } },
        anim  = { idle = { dict = "anim@heists@box_carry@",  name = "idle",                blendIn = 4.0, blendOut = 1.0, duration = -1, flag = 49 },
                  install = { dict = "mini@repair",          name = "fixing_a_player",     blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1  } },
        variants = {
            ['-1'] = { label = 'Stock', index = -1 },
            ['0'] = { label = 'Truck Horn', index = 0 },
            ['1'] = { label = 'Cop Horn', index = 1 },
            ['2'] = { label = 'Clown Horn', index = 2 },
            ['3'] = { label = 'Musical Horn 1', index = 3 },
            ['4'] = { label = 'Musical Horn 2', index = 4 },
            ['5'] = { label = 'Musical Horn 3', index = 5 },
            ['6'] = { label = 'Musical Horn 4', index = 6 },
            ['7'] = { label = 'Musical Horn 5', index = 7 },
            ['8'] = { label = 'Sad Trombone', index = 8 },
            ['9'] = { label = 'Classical Horn 1', index = 9 },
            ['10'] = { label = 'Classical Horn 2', index = 10 },
            ['11'] = { label = 'Classical Horn 3', index = 11 },
            ['12'] = { label = 'Classical Horn 4', index = 12 },
            ['13'] = { label = 'Classical Horn 5', index = 13 },
            ['14'] = { label = 'Classical Horn 6', index = 14 },
            ['15'] = { label = 'Classical Horn 7', index = 15 },
            ['16'] = { label = 'Scale - Do', index = 16 },
            ['17'] = { label = 'Scale - Re', index = 17 },
            ['18'] = { label = 'Scale - Mi', index = 18 },
            ['19'] = { label = 'Scale - Fa', index = 19 },
            ['20'] = { label = 'Scale - Sol', index = 20 },
            ['21'] = { label = 'Scale - La', index = 21 },
            ['22'] = { label = 'Scale - Ti', index = 22 },
            ['23'] = { label = 'Scale - Do (High)', index = 23 },
            ['24'] = { label = 'Jazz Horn 1', index = 24 },
            ['25'] = { label = 'Jazz Horn 2', index = 25 },
            ['26'] = { label = 'Jazz Horn 3', index = 26 },
            ['27'] = { label = 'Jazz Horn Loop', index = 27 },
            ['28'] = { label = 'Star Spangled Banner 1', index = 28 },
            ['29'] = { label = 'Star Spangled Banner 2', index = 29 },
            ['30'] = { label = 'Star Spangled Banner 3', index = 30 },
            ['31'] = { label = 'Star Spangled Banner 4', index = 31 },
            ['32'] = { label = 'Classical Horn 8 Loop', index = 32 },
            ['33'] = { label = 'Classical Horn 9 Loop', index = 33 },
            ['34'] = { label = 'Classical Horn 10 Loop', index = 34 },
            ['35'] = { label = 'Classical Horn 8', index = 35 },
            ['36'] = { label = 'Classical Horn 9', index = 36 },
            ['37'] = { label = 'Classical Horn 10', index = 37 },
            ['38'] = { label = 'Funeral Loop', index = 38 },
            ['39'] = { label = 'Funeral', index = 39 },
            ['40'] = { label = 'Spooky Loop', index = 40 },
            ['41'] = { label = 'Spooky', index = 41 },
            ['42'] = { label = 'San Andreas Loop', index = 42 },
            ['43'] = { label = 'San Andreas', index = 43 },
            ['44'] = { label = 'Liberty City Loop', index = 44 },
            ['45'] = { label = 'Liberty City', index = 45 },
            ['46'] = { label = 'Festive 1 Loop', index = 46 },
            ['47'] = { label = 'Festive 1', index = 47 },
            ['48'] = { label = 'Festive 2 Loop', index = 48 },
            ['49'] = { label = 'Festive 2', index = 49 },
            ['50'] = { label = 'Festive 3 Loop', index = 50 },
            ['51'] = { label = 'Festive 3', index = 51 },
            ['52'] = { label = 'Air Horn Low Loop', index = 52 },
            ['53'] = { label = 'Air Horn Low', index = 53 },
            ['54'] = { label = 'Air Horn Medium Loop', index = 54 },
            ['55'] = { label = 'Air Horn Medium', index = 55 },
            ['56'] = { label = 'Air Horn High Loop', index = 56 },
            ['57'] = { label = 'Air Horn High', index = 57 }
        }
    },

    modPlateHolder = {
        label = "Plate Holder", modType = 25, item = "mod_interior", price = 500, escalation = true, category = "styling", installPoint = "interior",
        icon  = "https://i.postimg.cc/hQT61Vsj/mod-plateholder.png",
        prop  = { model = "prop_cs_cardbox_01",               pos = { x = 0.0,   y = -0.2,  z = -0.1  }, rot = { x = 135.0, y = 0.0,  z = 0.0    } },
        anim  = { idle = { dict = "anim@heists@box_carry@",  name = "idle",                blendIn = 4.0, blendOut = 1.0, duration = -1, flag = 49 },
                  install = { dict = "anim@amb@clubhouse@tutorial@bkr_tut_ig3@", name = "machinic_loop_mechandplayer", blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1 } },
    },

    modVanityPlate = {
        label = "Vanity Plates", modType = 26, item = "mod_interior", price = 700, escalation = true, category = "styling", installPoint = "interior",
        icon  = "https://i.postimg.cc/vDVJydyG/mod-vanityplate.png",
        prop  = { model = "prop_cs_cardbox_01",               pos = { x = 0.0,   y = -0.2,  z = -0.1  }, rot = { x = 135.0, y = 0.0,  z = 0.0    } },
        anim  = { idle = { dict = "anim@heists@box_carry@",  name = "idle",                blendIn = 4.0, blendOut = 1.0, duration = -1, flag = 49 },
                  install = { dict = "anim@amb@clubhouse@tutorial@bkr_tut_ig3@", name = "machinic_loop_mechandplayer", blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1 } },
    },

    modTrimA = {
        label = "Trim A", modType = 27, item = "mod_interior", price = 400, escalation = true, category = "styling", installPoint = "interior",
        icon  = "https://i.postimg.cc/zHK6FT7x/mod-trim-A.png",
        prop  = { model = "prop_cs_cardbox_01",               pos = { x = 0.0,   y = -0.2,  z = -0.1  }, rot = { x = 135.0, y = 0.0,  z = 0.0    } },
        anim  = { idle = { dict = "anim@heists@box_carry@",  name = "idle",                blendIn = 4.0, blendOut = 1.0, duration = -1, flag = 49 },
                  install = { dict = "anim@amb@clubhouse@tutorial@bkr_tut_ig3@", name = "machinic_loop_mechandplayer", blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1 } },
    },

    modOrnaments = {
        label = "Ornaments", modType = 28, item = "mod_interior", price = 250, escalation = true, category = "styling", installPoint = "interior",
        icon  = "https://i.postimg.cc/tnWwNFkC/mod-ornaments.png",
        prop  = { model = "prop_cs_cardbox_01",               pos = { x = 0.0,   y = -0.2,  z = -0.1  }, rot = { x = 135.0, y = 0.0,  z = 0.0    } },
        anim  = { idle = { dict = "anim@heists@box_carry@",  name = "idle",                blendIn = 4.0, blendOut = 1.0, duration = -1, flag = 49 },
                  install = { dict = "anim@amb@clubhouse@tutorial@bkr_tut_ig3@", name = "machinic_loop_mechandplayer", blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1 } },
    },

    modDashboard = {
        label = "Dashboard", modType = 29, item = "mod_interior", price = 400, escalation = true, category = "styling", installPoint = "interior",
        icon  = "https://i.postimg.cc/47KrnDh2/mod-dashboard.png",
        prop  = { model = "prop_cs_cardbox_01",               pos = { x = 0.0,   y = -0.2,  z = -0.1  }, rot = { x = 135.0, y = 0.0,  z = 0.0    } },
        anim  = { idle = { dict = "anim@heists@box_carry@",  name = "idle",                blendIn = 4.0, blendOut = 1.0, duration = -1, flag = 49 },
                  install = { dict = "anim@amb@clubhouse@tutorial@bkr_tut_ig3@", name = "machinic_loop_mechandplayer", blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1 } },
    },

    modDial = {
        label = "Gauges", modType = 30, item = "mod_interior", price = 350, escalation = true, category = "styling", installPoint = "interior",
        icon  = "https://i.postimg.cc/BL8dtr1V/mod-dial.png",
        prop  = { model = "prop_cs_cardbox_01",               pos = { x = 0.0,   y = -0.2,  z = -0.1  }, rot = { x = 135.0, y = 0.0,  z = 0.0    } },
        anim  = { idle = { dict = "anim@heists@box_carry@",  name = "idle",                blendIn = 4.0, blendOut = 1.0, duration = -1, flag = 49 },
                  install = { dict = "anim@amb@clubhouse@tutorial@bkr_tut_ig3@", name = "machinic_loop_mechandplayer", blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1 } },
    },

    modDoorSpeaker = {
        label = "Door Speaker", modType = 31, item = "mod_interior", price = 650, escalation = true, category = "styling", installPoint = "interior",
        icon  = "https://i.postimg.cc/BL8dtr1k/mod-doorspeaker.png",
        prop  = { model = "prop_cs_cardbox_01",               pos = { x = 0.0,   y = -0.2,  z = -0.1  }, rot = { x = 135.0, y = 0.0,  z = 0.0    } },
        anim  = { idle = { dict = "anim@heists@box_carry@",  name = "idle",                blendIn = 4.0, blendOut = 1.0, duration = -1, flag = 49 },
                  install = { dict = "anim@amb@clubhouse@tutorial@bkr_tut_ig3@", name = "machinic_loop_mechandplayer", blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1 } },
    },

    modSeats = {
        label = "Seats", modType = 32, item = "mod_interior", price = 1400, escalation = true, category = "styling", installPoint = "interior",
        icon  = "https://i.postimg.cc/CnkXsb7q/mod-seats.png",
        prop  = { model = "prop_cs_cardbox_01",               pos = { x = 0.0,   y = -0.2,  z = -0.1  }, rot = { x = 135.0, y = 0.0,  z = 0.0    } },
        anim  = { idle = { dict = "anim@heists@box_carry@",  name = "idle",                blendIn = 4.0, blendOut = 1.0, duration = -1, flag = 49 },
                  install = { dict = "anim@amb@clubhouse@tutorial@bkr_tut_ig3@", name = "machinic_loop_mechandplayer", blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1 } },
    },

    modSteeringWheel = {
        label = "Steering Wheel", modType = 33, item = "mod_interior", price = 950, escalation = true, category = "styling", installPoint = "interior",
        icon  = "https://i.postimg.cc/q6BLFnXY/mod-Steering-Wheel.png",
        prop  = { model = "prop_cs_cardbox_01",               pos = { x = 0.0,   y = -0.2,  z = -0.1  }, rot = { x = 135.0, y = 0.0,  z = 0.0    } },
        anim  = { idle = { dict = "anim@heists@box_carry@",  name = "idle",                blendIn = 4.0, blendOut = 1.0, duration = -1, flag = 49 },
                  install = { dict = "anim@amb@clubhouse@tutorial@bkr_tut_ig3@", name = "machinic_loop_mechandplayer", blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1 } },
    },

    modShifterLeavers = {
        label = "Shifter Leaver", modType = 34, item = "mod_interior", price = 450, escalation = true, category = "styling", installPoint = "interior",
        icon  = "https://i.postimg.cc/8fkHYWBZ/mod-Shifter-Leavers.png",
        prop  = { model = "prop_cs_cardbox_01",               pos = { x = 0.0,   y = -0.2,  z = -0.1  }, rot = { x = 135.0, y = 0.0,  z = 0.0    } },
        anim  = { idle = { dict = "anim@heists@box_carry@",  name = "idle",                blendIn = 4.0, blendOut = 1.0, duration = -1, flag = 49 },
                  install = { dict = "anim@amb@clubhouse@tutorial@bkr_tut_ig3@", name = "machinic_loop_mechandplayer", blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1 } },
    },

    modAPlate = {
        label = "Plaque", modType = 35, item = "mod_interior", price = 800, escalation = true, category = "styling", installPoint = "interior",
        icon  = "https://i.postimg.cc/DJWtm9bs/mod-aplate.png",
        prop  = { model = "prop_cs_cardbox_01",               pos = { x = 0.0,   y = -0.2,  z = -0.1  }, rot = { x = 135.0, y = 0.0,  z = 0.0    } },
        anim  = { idle = { dict = "anim@heists@box_carry@",  name = "idle",                blendIn = 4.0, blendOut = 1.0, duration = -1, flag = 49 },
                  install = { dict = "anim@amb@clubhouse@tutorial@bkr_tut_ig3@", name = "machinic_loop_mechandplayer", blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1 } },
    },

    modSpeakers = {
        label = "Speaker", modType = 36, item = "mod_interior", price = 1200, escalation = true, category = "styling", installPoint = "interior",
        icon  = "https://i.postimg.cc/YGzR88gD/mod-Speakers.png",
        prop  = { model = "sm_prop_smug_speaker",             pos = { x = 0.0,   y = -0.1,  z = -0.2  }, rot = { x = -15.0, y = 0.0,  z = 0.0    } },
        anim  = { idle = { dict = "anim@heists@box_carry@",  name = "idle",                blendIn = 4.0, blendOut = 1.0, duration = -1, flag = 49 },
                  install = { dict = "anim@amb@clubhouse@tutorial@bkr_tut_ig3@", name = "machinic_loop_mechandplayer", blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1 } },
    },

    modTrunk = {
        label = "Trunk", modType = 37, item = "mod_interior", price = 2300, escalation = true, category = "styling", installPoint = "interior",
        icon  = "https://i.postimg.cc/hhdknqnq/mod-trunk.png",
        prop  = { model = "imp_prop_impexp_trunk_01a",        pos = { x = 0.0,   y = 0.15,  z = 0.1   }, rot = { x = 30.0,  y = 0.0,  z = 0.0    } },
        anim  = { idle = { dict = "anim@heists@box_carry@",  name = "idle",                blendIn = 4.0, blendOut = 1.0, duration = -1, flag = 49 },
                  install = { dict = "mini@repair",          name = "fixing_a_player",     blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1  } },
    },

    modHydrolic = {
        label = "Hydraulics", modType = 38, item = "mod_interior", price = 5400, escalation = true, category = "styling", installPoint = "interior",
        icon  = "https://i.postimg.cc/DJtRGxry/mod-hydrolic.png",
        prop  = { model = "prop_cs_cardbox_01",               pos = { x = 0.0,   y = -0.2,  z = -0.1  }, rot = { x = 135.0, y = 0.0,  z = 0.0    } },
        anim  = { idle = { dict = "anim@heists@box_carry@",  name = "idle",                blendIn = 4.0, blendOut = 1.0, duration = -1, flag = 49 },
                  install = { dict = "anim@amb@clubhouse@tutorial@bkr_tut_ig3@", name = "machinic_loop_mechandplayer", blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1 } },
    },

    -- ── Styling — Engine Bay ──────────────────────────────────────────────

    modEngineBlock = {
        label = "Engine Block", modType = 39, item = "mod_enginebay", price = 1600, escalation = true, category = "styling", installPoint = "engine",
        icon  = "https://i.postimg.cc/Fd2wSTjq/mod-engineblock.png",
        prop  = { model = "prop_cs_cardbox_01",               pos = { x = 0.0,   y = -0.2,  z = -0.1  }, rot = { x = 135.0, y = 0.0,  z = 0.0    } },
        anim  = { idle = { dict = "anim@heists@box_carry@",  name = "idle",                blendIn = 4.0, blendOut = 1.0, duration = -1, flag = 49 },
                  install = { dict = "mini@repair",          name = "fixing_a_player",     blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1  } },
    },

    modAirFilter = {
        label = "Air Filters", modType = 40, item = "mod_enginebay", price = 1300, escalation = true, category = "styling", installPoint = "engine",
        icon  = "https://i.postimg.cc/BL8dtr1x/mod-air-Filter.png",
        prop  = { model = "prop_cs_cardbox_01",               pos = { x = 0.0,   y = -0.2,  z = -0.1  }, rot = { x = 135.0, y = 0.0,  z = 0.0    } },
        anim  = { idle = { dict = "anim@heists@box_carry@",  name = "idle",                blendIn = 4.0, blendOut = 1.0, duration = -1, flag = 49 },
                  install = { dict = "mini@repair",          name = "fixing_a_player",     blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1  } },
    },

    modStruts = {
        label = "Strut Brace", modType = 41, item = "mod_enginebay", price = 1400, escalation = true, category = "styling", installPoint = "engine",
        icon  = "https://i.postimg.cc/4HVqQpPb/mod-struts.png",
        prop  = { model = "prop_cs_cardbox_01",               pos = { x = 0.0,   y = -0.2,  z = -0.1  }, rot = { x = 135.0, y = 0.0,  z = 0.0    } },
        anim  = { idle = { dict = "anim@heists@box_carry@",  name = "idle",                blendIn = 4.0, blendOut = 1.0, duration = -1, flag = 49 },
                  install = { dict = "mini@repair",          name = "fixing_a_player",     blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1  } },
    },

    -- ── Styling — Exterior ────────────────────────────────────────────────

    modArchCover = {
        label = "Arch Cover", modType = 42, item = "mod_exterior", price = 900, escalation = true, category = "styling", installPoint = "vehicle",
        icon  = "https://i.postimg.cc/bDGKd72k/mod-archcover.png",
        prop  = { model = "prop_cs_cardbox_01",               pos = { x = 0.0,   y = -0.2,  z = -0.1  }, rot = { x = 135.0, y = 0.0,  z = 0.0    } },
        anim  = { idle = { dict = "anim@heists@box_carry@",  name = "idle",                blendIn = 4.0, blendOut = 1.0, duration = -1, flag = 49 },
                  install = { dict = "anim@amb@clubhouse@tutorial@bkr_tut_ig3@", name = "machinic_loop_mechandplayer", blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1 } },
    },

    modAerials = {
        label = "Aerials", modType = 43, item = "mod_exterior", price = 600, escalation = true, category = "styling", installPoint = "vehicle",
        icon  = "https://i.postimg.cc/ygJwWMS0/mod-aerials.png",
        prop  = { model = "prop_cs_cardbox_01",               pos = { x = 0.0,   y = -0.2,  z = -0.1  }, rot = { x = 135.0, y = 0.0,  z = 0.0    } },
        anim  = { idle = { dict = "anim@heists@box_carry@",  name = "idle",                blendIn = 4.0, blendOut = 1.0, duration = -1, flag = 49 },
                  install = { dict = "anim@amb@clubhouse@tutorial@bkr_tut_ig3@", name = "machinic_loop_mechandplayer", blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1 } },
    },

    modTrimB = {
        label = "Trim B", modType = 44, item = "mod_exterior", price = 1100, escalation = true, category = "styling", installPoint = "interior",
        icon  = "https://i.postimg.cc/s1hkzRrk/mod-trim-B.png",
        prop  = { model = "prop_cs_cardbox_01",               pos = { x = 0.0,   y = -0.2,  z = -0.1  }, rot = { x = 135.0, y = 0.0,  z = 0.0    } },
        anim  = { idle = { dict = "anim@heists@box_carry@",  name = "idle",                blendIn = 4.0, blendOut = 1.0, duration = -1, flag = 49 },
                  install = { dict = "anim@amb@clubhouse@tutorial@bkr_tut_ig3@", name = "machinic_loop_mechandplayer", blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1 } },
    },

    modTank = {
        label = "Fuel Tank", modType = 45, item = "mod_exterior", price = 1900, escalation = true, category = "styling", installPoint = "vehicle",
        icon  = "https://i.postimg.cc/PvY9Q1yK/mod-tank.png",
        prop  = { model = "prop_cs_cardbox_01",               pos = { x = 0.0,   y = -0.2,  z = -0.1  }, rot = { x = 135.0, y = 0.0,  z = 0.0    } },
        anim  = { idle = { dict = "anim@heists@box_carry@",  name = "idle",                blendIn = 4.0, blendOut = 1.0, duration = -1, flag = 49 },
                  install = { dict = "anim@amb@clubhouse@tutorial@bkr_tut_ig3@", name = "machinic_loop_mechandplayer", blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1 } },
    },

    modWindows = {
        label = "Left Door", modType = 46, item = "mod_exterior", price = 1700, escalation = true, category = "styling", installPoint = "interior",
        icon  = "https://i.postimg.cc/jC7pTrTd/mod-windows.png",
        prop  = { model = "imp_prop_impexp_car_door_04a",     pos = { x = -0.7,  y = -0.2,  z = 0.0   }, rot = { x = 0.0,   y = -10.0,z = 90.0   } },
        anim  = { idle = { dict = "anim@heists@box_carry@",  name = "idle",                blendIn = 4.0, blendOut = 1.0, duration = -1, flag = 49 },
                  install = { dict = "anim@amb@clubhouse@tutorial@bkr_tut_ig3@", name = "machinic_loop_mechandplayer", blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1 } },
    },

    modDoorR = {
        label = "Right Door", modType = 47, item = "mod_exterior", price = 1700, escalation = true, category = "styling", installPoint = "interior",
        icon  = "https://i.postimg.cc/Q9BRV2Wz/mod-door-R.png",
        prop  = { model = "imp_prop_impexp_car_door_04a",     pos = { x = -0.7,  y = -0.2,  z = 0.0   }, rot = { x = 0.0,   y = -10.0,z = 90.0   } },
        anim  = { idle = { dict = "anim@heists@box_carry@",  name = "idle",                blendIn = 4.0, blendOut = 1.0, duration = -1, flag = 49 },
                  install = { dict = "anim@amb@clubhouse@tutorial@bkr_tut_ig3@", name = "machinic_loop_mechandplayer", blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1 } },
    },

    -- ── Extras ────────────────────────────────────────────────────────────

    extras = {
        label = "Extras", modType = "extras", item = "mod_extras", category = "styling", installPoint = "vehicle",
        icon  = "https://i.postimg.cc/62DFZMrs/mod-extras.png",
        prop  = { model = "prop_cs_package_01",               pos = { x = 0.0,   y = -0.05, z = -0.1  }, rot = { x = 100.0, y = 0.0,  z = 0.0    } },
        anim  = { idle = { dict = "anim@heists@box_carry@",  name = "idle",                blendIn = 4.0, blendOut = 1.0, duration = -1, flag = 49 },
                  install = { dict = "mini@repair",          name = "fixing_a_player",     blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1  } },
    },
}
```


# Prices

t1ger\_tuning/shared/prices.lua

```lua
Config.PriceEscalationPercent = 5 -- Integer | value in percent between 0-100 where setting to 0 will disable price escalation, otherwise mod variant prices increase progressively. Making each higher option cost more.

Config.PartAcquisitionCost = true -- boolean | if true, item price from Config.Items['mods'] will be added to the calculated mod price price, else skipped. Ideally this would cover the cost to acquire parts if enabled.

Config.DefaultVehiclePrice = 50000 -- integer | Default vehicle price to be used if the script cannot retrieve the vehicle value from a database table or shared lua file.

Config.TieredPricing = true -- boolean | if true then tier-based multipliers for mod pricing, to disable set to false. This option uses Config.PriceTiers.

Config.PriceTiers = { -- A list of tiers where each tier specifies an upper limit and a corresponding multiplier. Config.TieredPricing must be enabled.
    { upperLimit = 10000, multiplier = 0.05 }, -- Tier 1: For vehicle prices up to $10,000, apply a multiplier of 5%.
    { upperLimit = 50000, multiplier = 0.03 }, -- Tier 2: For vehicle prices between $10,000 and $50,000, apply a multiplier of 3%.
    { upperLimit = 100000, multiplier = 0.02 }, -- Tier 3: For vehicle prices between $50,000 and $100,000, apply a multiplier of 2%.
    { upperLimit = 500000, multiplier = 0.01 }, -- Tier 4: For vehicle prices between $100,000 and $500,000, apply a multiplier of 1%.
    { upperLimit = math.huge, multiplier = 0.005 }, -- Tier 5: For vehicle prices above $500,000, apply a multiplier of 0.5%.
    -- u can easily add more tiers, edit the current ones but make sure that math.huge is used to represent infinity for the highest tier.
}

Config.Prices = {

    -- mod base prices can be modified inside shared/modtypes.lua

    paints = {
        metallic = 250,
        matte = 350,
        metals = 500,
        util = 700,
        worn = 750,
        chameleon = 1000,
    },

    rgb = 1000
}

```


# Paints

t1ger\_tuning/shared/paints.lua

```lua
return {

    Categories = {
        { id = "metallic",      label = "Metallic",     paintType = 1,     price = 250 },
        { id = "matte",         label = "Matte",        paintType = 3,     price = 350 },
        { id = "metals",        label = "Metals",       paintType = 4,     price = 500 },
        { id = "util",          label = "Util",         paintType = 1,     price = 700 },
        { id = "worn",          label = "Worn",         paintType = 1,     price = 750 },
        { id = "chameleon",     label = "Chameleon",    paintType = 6,     price = 1000 }
    },

    Colors = {
        ["metallic"] = {
            { label = "Black",               index = 0 },
            { label = "Graphite Black",      index = 1 },
            { label = "Black Steel",         index = 2 },
            { label = "Dark Silver",         index = 3 },
            { label = "Silver",              index = 4 },
            { label = "Blue Silver",         index = 5 },
            { label = "Steel Grey",          index = 6 },
            { label = "Shadow Silver",       index = 7 },
            { label = "Stone Silver",        index = 8 },
            { label = "Midnight Silver",     index = 9 },
            { label = "Gun Metal",           index = 10 },
            { label = "Anthracite Grey",     index = 11 },
            { label = "Red",                 index = 27 },
            { label = "Torino Red",          index = 28 },
            { label = "Formula Red",         index = 29 },
            { label = "Blaze Red",           index = 30 },
            { label = "Graceful Red",        index = 31 },
            { label = "Garnet Red",          index = 32 },
            { label = "Desert Red",          index = 33 },
            { label = "Cabernet Red",        index = 34 },
            { label = "Candy Red",           index = 35 },
            { label = "Sunrise Orange",      index = 36 },
            { label = "Classic Gold",        index = 37 },
            { label = "Orange",              index = 38 },
            { label = "Dark Green",          index = 49 },
            { label = "Racing Green",        index = 50 },
            { label = "Sea Green",           index = 51 },
            { label = "Olive Green",         index = 52 },
            { label = "Green",               index = 53 },
            { label = "Gasoline Blue Green", index = 54 },
            { label = "Midnight Blue",       index = 61 },
            { label = "Dark Blue",           index = 62 },
            { label = "Saxony Blue",         index = 63 },
            { label = "Blue",                index = 64 },
            { label = "Mariner Blue",        index = 65 },
            { label = "Harbor Blue",         index = 66 },
            { label = "Diamond Blue",        index = 67 },
            { label = "Surf Blue",           index = 68 },
            { label = "Nautical Blue",       index = 69 },
            { label = "Bright Blue",         index = 70 },
            { label = "Purple Blue",         index = 71 },
            { label = "Spinnaker Blue",      index = 72 },
            { label = "Ultra Blue",          index = 73 },
            { label = "Light Blue",          index = 74 },
            { label = "Taxi Yellow",         index = 88 },
            { label = "Race Yellow",         index = 89 },
            { label = "Bronze",              index = 90 },
            { label = "Yellow Bird",         index = 91 },
            { label = "Lime",                index = 92 },
            { label = "Champagne",           index = 93 },
            { label = "Pueblo Beige",        index = 94 },
            { label = "Dark Ivory",          index = 95 },
            { label = "Choco Brown",         index = 96 },
            { label = "Golden Brown",        index = 97 },
            { label = "Light Brown",         index = 98 },
            { label = "Straw Beige",         index = 99 },
            { label = "Moss Brown",          index = 100 },
            { label = "Biston Brown",        index = 101 },
            { label = "Beechwood",           index = 102 },
            { label = "Dark Beechwood",      index = 103 },
            { label = "Choco Orange",        index = 104 },
            { label = "Beach Sand",          index = 105 },
            { label = "Sun Bleeched Sand",   index = 106 },
            { label = "Cream",               index = 107 },
            { label = "White",               index = 111 },
            { label = "Frost White",         index = 112 },
            { label = "Securicor Green",     index = 125 },
            { label = "Pure White",          index = 134 },
            { label = "Hot Pink",            index = 135 },
            { label = "Salmon pink",         index = 136 },
            { label = "Vermillion Pink",     index = 137 },
            { label = "Bright Orange",       index = 138 },
            { label = "Bright Green",        index = 139 },
            { label = "Bright Blue",         index = 140 },
            { label = "Black Blue",          index = 141 },
            { label = "Black Purple",        index = 142 },
            { label = "Black Red",           index = 143 },
            { label = "Purple",              index = 145 },
            { label = "V Dark Blue",         index = 146 },
            { label = "Carbon Black",        index = 147 },
            { label = "Lava Red",            index = 150 }
        },
        ["matte"] = {
            { label = "Black",         index = 12 },
            { label = "Gray",          index = 13 },
            { label = "Light Grey",    index = 14 },
            { label = "Red",           index = 39 },
            { label = "Dark Red",      index = 40 },
            { label = "Orange",        index = 41 },
            { label = "Yellow",        index = 42 },
            { label = "Lime Green",    index = 55 },
            { label = "Dark Blue",     index = 82 },
            { label = "Blue",          index = 83 },
            { label = "Midnight Blue", index = 84 },
            { label = "Green",         index = 128 },
            { label = "Brown",         index = 129 },
            { label = "White",         index = 131 },
            { label = "Purple",        index = 148 },
            { label = "Dark Purple",   index = 149 },
            { label = "Forest Green",  index = 151 },
            { label = "Olive Drab",    index = 152 },
            { label = "Desert Brown",  index = 153 },
            { label = "Desert Tan",    index = 154 },
            { label = "Foliage Green", index = 155 }
        },
        ["metals"] = {
            { label = "Brushed Steel",       index = 117 },
            { label = "Brushed Black Steel", index = 118 },
            { label = "Brushed Aluminum",    index = 119 },
            { label = "Chrome",              index = 120 },
            { label = "Alloy",               index = 156 },
            { label = "Epsilon Blue",        index = 157 },
            { label = "Pure Gold",           index = 158 },
            { label = "Brushed Gold",        index = 159 }
        },
        ["util"] = {
            { label = "Black",          index = 15 },
            { label = "Black Poly",     index = 16 },
            { label = "Dark silver",    index = 17 },
            { label = "Silver",         index = 18 },
            { label = "Gun Metal",      index = 19 },
            { label = "Shadow Silver",  index = 20 },
            { label = "Red",            index = 43 },
            { label = "Bright Red",     index = 44 },
            { label = "Garnet Red",     index = 45 },
            { label = "Dark Green",     index = 56 },
            { label = "Green",          index = 57 },
            { label = "Dark Blue",      index = 75 },
            { label = "Midnight Blue",  index = 76 },
            { label = "Blue",           index = 77 },
            { label = "Sea Foam Blue",  index = 78 },
            { label = "Lightning blue", index = 79 },
            { label = "Maui Blue Poly", index = 80 },
            { label = "Bright Blue",    index = 81 },
            { label = "Brown",          index = 108 },
            { label = "Medium Brown",   index = 109 },
            { label = "Light Brown",    index = 110 },
            { label = "Off White",      index = 122 }
        },
        ["worn"] = {
            { label = "Black",            index = 21 },
            { label = "Graphite",         index = 22 },
            { label = "Silver Grey",      index = 23 },
            { label = "Silver",           index = 24 },
            { label = "Blue Silver",      index = 25 },
            { label = "Shadow Silver",    index = 26 },
            { label = "Red",              index = 46 },
            { label = "Golden Red",       index = 47 },
            { label = "Dark Red",         index = 48 },
            { label = "Dark Green",       index = 58 },
            { label = "Green",            index = 59 },
            { label = "Sea Wash",         index = 60 },
            { label = "Dark Blue",        index = 85 },
            { label = "Blue",             index = 86 },
            { label = "Light Blue",       index = 87 },
            { label = "Honey Beige",      index = 113 },
            { label = "Brown",            index = 114 },
            { label = "Dark Brown",       index = 115 },
            { label = "Straw Beige",      index = 116 },
            { label = "Off White",        index = 121 },
            { label = "Orange",           index = 123 },
            { label = "Light Orange",     index = 124 },
            { label = "Taxi Yellow",      index = 126 },
            { label = "Orange 2",         index = 130 },
            { label = "White",            index = 132 },
            { label = "Olive Army Green", index = 133 }
        },
        ["chameleon"] = {
            { label = "Anodized Red Pearl",                   index = 161 },
            { label = "Anodized Wine Pearl",                  index = 162 },
            { label = "Anodized Purple Pearl",                index = 163 },
            { label = "Anodized Blue Pearl",                  index = 164 },
            { label = "Anodized Green Pearl",                 index = 165 },
            { label = "Anodized Lime Pearl",                  index = 166 },
            { label = "Anodized Copper Pearl",                index = 167 },
            { label = "Anodized Bronze Pearl",                index = 168 },
            { label = "Anodized Champagne Pearl",             index = 169 },
            { label = "Anodized Gold Pearl",                  index = 170 },
            { label = "Green/Blue Flip",                      index = 171 },
            { label = "Green/Red Flip",                       index = 172 },
            { label = "Green/Brown Flip",                     index = 173 },
            { label = "Green/Turquoise Flip",                 index = 174 },
            { label = "Green/Purple Flip",                    index = 175 },
            { label = "Teal/Purple Flip",                     index = 176 },
            { label = "Turquoise/Red Flip",                   index = 177 },
            { label = "Turquoise/Purple Flip",                index = 178 },
            { label = "Cyan/Purple Flip",                     index = 179 },
            { label = "Blue/Pink Flip",                       index = 180 },
            { label = "Blue/Green Flip",                      index = 181 },
            { label = "Purple/Red Flip",                      index = 182 },
            { label = "Purple/Green Flip",                    index = 183 },
            { label = "Magenta/Green Flip",                   index = 184 },
            { label = "Magenta/Yellow Flip",                  index = 185 },
            { label = "Burgundy/Green Flip",                  index = 186 },
            { label = "Magenta/Cyan Flip",                    index = 187 },
            { label = "Copper/Purple Flip",                   index = 188 },
            { label = "Magenta/Orange Flip",                  index = 189 },
            { label = "Red/Orange Flip",                      index = 190 },
            { label = "Orange/Purple Flip",                   index = 191 },
            { label = "Orange/Blue Flip",                     index = 192 },
            { label = "White/Purple Flip",                    index = 193 },
            { label = "Red/Rainbow Flip",                     index = 194 },
            { label = "Blue/Rainbow Flip",                    index = 195 },
            { label = "Dark Green Pearl",                     index = 196 },
            { label = "Dark Teal Pearl",                      index = 197 },
            { label = "Dark Blue Pearl",                      index = 198 },
            { label = "Dark Purple Pearl",                    index = 199 },
            { label = "Oil Slick Pearl",                      index = 200 },
            { label = "Light Green Pearl",                    index = 201 },
            { label = "Light Blue Pearl",                     index = 202 },
            { label = "Light Purple Pearl",                   index = 203 },
            { label = "Light Pink Pearl",                     index = 204 },
            { label = "Off White Pearl",                      index = 205 },
            { label = "Cute Pink Pearl",                      index = 206 },
            { label = "Baby Yellow Pearl",                    index = 207 },
            { label = "Baby Green Pearl",                     index = 208 },
            { label = "Baby Blue Pearl",                      index = 209 },
            { label = "Cream Pearl",                          index = 210 },
            { label = "White Prismatic Pearl",                index = 211 },
            { label = "Graphite Prismatic Pearl",             index = 212 },
            { label = "Blue Prismatic Pearl",                 index = 213 },
            { label = "Purple Prismatic Pearl",               index = 214 },
            { label = "Hot Pink Prismatic Pearl",             index = 215 },
            { label = "Red Prismatic Pearl",                  index = 216 },
            { label = "Green Prismatic Pearl",                index = 217 },
            { label = "Black Prismatic Pearl",                index = 218 },
            { label = "Oil Spill Prismatic Pearl",            index = 219 },
            { label = "Rainbow Prismatic Pearl",              index = 220 },
            { label = "Black Holographic Pearl",              index = 221 },
            { label = "White Holographic Pearl",              index = 222 },
            { label = "Fubuki-jo Specials: Monochrome",       index = 223 },
            { label = "Fubuki-jo Specials: Night & Day",      index = 224 },
            { label = "Fubuki-jo Specials: The Verlierer",    index = 225 },
            { label = "Fubuki-jo Specials: Sprunk Extreme",   index = 226 },
            { label = "Fubuki-jo Specials: Vice City",        index = 227 },
            { label = "Fubuki-jo Specials: Synthwave Night",  index = 228 },
            { label = "Fubuki-jo Specials: Four Seasons",     index = 229 },
            { label = "Fubuki-jo Specials: M9 Throwback",     index = 230 },
            { label = "Fubuki-jo Specials: Bubblegum",        index = 231 },
            { label = "Fubuki-jo Specials: Full Rainbow",     index = 232 },
            { label = "Fubuki-jo Specials: Sunset",           index = 233 },
            { label = "Fubuki-jo Specials: The Seven",        index = 234 },
            { label = "Fubuki-jo Specials: Kamen Rider",      index = 235 },
            { label = "Fubuki-jo Specials: Chromatic",        index = 236 },
            { label = "Fubuki-jo Specials: It\"s Christmas!", index = 237 },
            { label = "Fubuki-jo Specials: Temperature",      index = 238 },
            { label = "Fubuki-jo Specials: HSW Badge",        index = 239 },
            { label = "Fubuki-jo Specials: Anod. Lightning",  index = 240 },
            { label = "Fubuki-jo Specials: Emeralds",         index = 241 },
            { label = "Fubuki-jo Specials: Fubuki Castle",    index = 242 }
        }
    },

    Types = {
        {value = 0, label = "Normal"},
        {value = 1, label = "Metallic"},
        {value = 2, label = "Pearl"},
        {value = 3, label = "Matte"},
        {value = 4, label = "Metal"},
        {value = 5, label = "Chrome"}
    }
}

```


# Mod Stations

t1ger\_tuning/shared/modstations.lua

```lua
-- shared/modstations.lua
-- Each location requires coords.
-- All other fields are optional and fall back to global Config.ModStations defaults.

return {
    {
        coords     = vector3(478.68, -1022.33, 28.01), -- position of the station
        blip       = true,                           -- override global blip.enable for this station
        isFree     = false,                          -- whether mods are free at this station
        jobs       = {"police", "lspd"},                            -- restrict to specific jobs, nil = everyone. Example: { "mechanic", "police" }
        categories = {"extras"},                            -- restrict to specific mod categories, nil = all. Example: { "performance", "wheels" }
        mods       = nil,                            -- restrict to specific mod types, nil = all. Example: { "modEngine", "modBrakes" }
    },

    -- Compact examples:
    { coords = vector3(344.53, -554.79, 28.74), blip = true, isFree = true, jobs = nil, categories = nil, mods = nil},
}
```


# NPC Jobs

t1ger\_tuning/shared/npc\_jobs.lua

```lua
return {

    Cooldown = 5, -- minutes, shared across both job types below

    -- ── Salvage Car ──────────────────────────────────────────────────────
    -- Strip a junk car for crafting materials, with a small chance at
    -- rare mod items.
    Salvage = {
        Enable = true,

        Menu = {
            title       = "Salvage Car",
            icon        = "car-burst",
            description = "Salvage a junk car to retrieve materials — and maybe a chance at some valuable parts.",
        },

        JunkCars = { "sultan", "asterope", "club", "exemplar", "felon", "fugitive" },

        Blip = { label = "Junk Car", sprite = 380, color = 51, scale = 0.65, route = { enable = true, color = 51 } },

        SkillCheck = { enable = true, difficulty = { "easy", "easy", "easy" }, inputs = { "w", "a", "s", "d" } },

        Target = { label = "Salvage %s", icon = "fa-solid fa-hammer" },

        -- Reward tables, rolled independently per part salvaged. chance is
        -- a % out of 100, min/max is the quantity awarded on a hit.
        Reward = {
            wheel = {
                ["rubber"]        = { chance = 100, min = 1, max = 5 },
                ["aluminium"]     = { chance = 100, min = 1, max = 5 },
                ["steel"]         = { chance = 80,  min = 1, max = 4 },
                ["mod_tyresmoke"] = { chance = 10,  min = 1, max = 1 },
            },
            door = {
                ["plastic"]      = { chance = 100, min = 3, max = 6 },
                ["scrap_metal"]  = { chance = 40,  min = 1, max = 3 },
                ["copper"]       = { chance = 70,  min = 2, max = 4 },
                ["mod_bodywork"] = { chance = 12,  min = 1, max = 1 },
                ["mod_exterior"] = { chance = 12,  min = 1, max = 1 },
            },
        },

        Locations = {
            vector4(-451.14, -1723.09, 18.66, 348.66),
            vector4(-450.36, -1691.61, 18.95, 155.90),
            vector4(-468.30, -1675.68, 19.05, 178.58),
            vector4(-425.61, -1687.68, 19.01, 158.74),
            vector4(-496.40, -1753.30, 18.31, 266.45),
            vector4(-551.26, -1703.73, 19.00, 212.59),
            vector4(-581.59, -1696.18, 19.06, 354.33),
        },
    },

    -- ── Mobile Tuning ────────────────────────────────────────────────────
    -- A roadside customer needs a specific cosmetic mod installed. Only
    -- realistic bolt-on/quick-fit mods are eligible — no engine work.
    MobileTuning = {
        Enable = true,

        Menu = {
            title       = "Mobile Tuning",
            icon        = "spray-can",
            description = "A customer needs on-site cosmetic tuning work done.",
        },

        Cars = { "euros", "zr350", "sultan3", "rt3000", "previon", "jester3" },
        Peds = { "a_m_m_bevhills_02", "a_m_m_socenlat_01", "a_m_y_bevhills_01" },

        Blip = { label = "Mobile Tuning Job", sprite = 643, color = 51, scale = 0.65, route = { enable = true, color = 51 } },

        TalkTarget = { label = "Talk with NPC", icon = "fa-solid fa-comments" },
        InstallTarget = { label = "Install Mod", icon = "fa-solid fa-wrench" },

        SkillCheck = { enable = true, difficulty = { "easy", "easy" }, inputs = { "w", "a", "s", "d" } },

        Reward = { min = 500, max = 5000 }, -- paid to the tuner's personal wallet

        -- Whitelist, not blacklist — only these Config.ModTypes keys are
        -- eligible for a mobile tuning request. Any variant satisfies the
        -- job, so no specific target value is picked or checked.
        AllowedMods = {
            "modSpoilers", "modFrontBumper", "modRearBumper", "modSideSkirt", "modGrille", "modHood", 
            "modExhaust", "xenonColor", "windowTint", "plateIndex", "modFrontWheels", 
            "modHorns", "tyreSmokeColor",
        },

        Locations = {
            vector4(-237.94, -2077.31, 27.61, 31.18),
            vector4(-47.36, -2103.38, 16.69, 198.42),
            vector4(-315.57, -2736.34, 5.99, 130.39),
            vector4(256.57, -3314.43, 5.77, 184.25),
            vector4(1125.61, -3138.51, 5.89, 0.0),
            vector4(1000.90, -1955.57, 30.88, 175.74),
            vector4(-1679.27, -924.27, 7.81, 323.14),
            vector4(1131.25, 255.89, 80.84, 56.69),
            vector4(853.26, -895.72, 25.30, 266.45),
            vector4(22.66, -1068.55, 38.14, 73.70),
            vector4(-725.80, -405.12, 34.99, 87.87),
            vector4(-2314.77, 449.45, 174.45, 170.07),
        },
    },
}
```


# Nitrous

t1ger\_tuning/shared/nitrous.lua

```lua
return {

    Enable = true, -- enable/disable the nitrous feature entirely

    RequireTurbo = false, -- if true, vehicle needs turbo installed to install a nitrous kit

    MaxSize = 12, -- max lb size of a nitrous kit, 1 lb = 10 shots. Min size is always 1lb
    UnitPrice = 1500, -- price per lb — e.g. a 4lb kit costs 4 x UnitPrice
    DefaultThreshold = 5, -- seconds — how long burst/purge can be held before any burst kit is installed
    DefaultPurgeColor = {r = 1.0, g = 1.0, b = 1.0}, -- default purge color.
    Weight = "lb", -- unit string used in menus

    -- keybind settings for NOS purge and burst
    Keybinds = {
        purge = {
            description = "Use NOS Purge",
            defaultKey  = "RCONTROL",
        },
        burst = {
            description = "Use NOS Burst",
            defaultKey  = "LSHIFT",
        },
    },

    -- icons used across nitrous menus
    MenuIcons = {
        unitPrice     = "dollar-sign",
        selectSize    = "bottle-droplet",
        currentNosKit = "fire-flame-simple",
        nitrousKit    = "bottle-droplet",
        burstKit      = "gauge-high",
    },

    -- nitrous kit and burst kit installation settings
    Install = {
        NitrousKit = {
            prop   = "v_ind_cs_gascanister",
            anim   = { dict = "anim@heists@box_carry@", name = "idle", blendIn = 4.0, blendOut = 1.0, duration = -1, flags = 49, boneId = 28422 },
            offset = { pos = vector3(0.1, -0.1, -0.05), rot = vector3(-45.0, 90.0, 0.0) },
            target = { icon = "fa-solid fa-screwdriver", label = "Install Nitrous Kit", distance = 5.0 },
            resetShots = true, -- installing a new kit resets shots to 0, forcing a refill
        },
        BurstKit = {
            prop   = "imp_prop_impexp_differential_01a",
            anim   = { dict = "anim@heists@humane_labs@finale@keycards", name = "ped_a_enter_loop", blendIn = 4.0, blendOut = 1.0, duration = -1, flags = 49, boneId = 60309 },
            offset = { pos = vector3(0.0, 0.0, 0.0), rot = vector3(0.0, -90.0, 0.0) },
            target = { icon = "fa-solid fa-screwdriver", label = "Install Burst Kit", distance = 5.0 },
        },
    },

    -- default burst kit, always shown first, uses DefaultThreshold seconds
    DefaultBurst = {
        label       = "Stock Burst Kit",
        icon        = "gauge-simple",
        price       = 1000, -- free when installing the nitrous kit for the first time
        description = "Stock Threshold of 5 seconds",
    },

    -- burst upgrade kits — raise the threshold seconds for burst/purge
    BurstKits = {
        [1] = { label = "Street Burst Kit", icon = "gauge", threshold = 7,  price = 6500,  description = "Threshold upgrade to 7 seconds" },
        [2] = { label = "Sports Burst Kit", icon = "gauge", threshold = 10, price = 12500, description = "Threshold upgrade to 10 seconds" },
        [3] = { label = "Race Burst Kit",   icon = "gauge", threshold = 13, price = 27500, description = "Threshold upgrade to 13 seconds" },
    },

    -- nitrous refill via bottle item
    Bottle = {
        skillcheck = { enable = true, difficulty = { "easy", "easy" }, inputs = { "w", "a", "s", "d" } },
        duration   = 3000, -- ms to load nitrous from bottle into kit
        label      = "Filling Nitrous",
        anim       = { dict = "mini@repair", name = "fixing_a_player", blendIn = 8.0, blendOut = -8.0, flag = 49 },
    },

    -- purge dye injection settings
    DyeInstall = {
        target   = { icon = "fa-solid fa-syringe", label = "Inject Purge Dye", distance = 5.0 },
        duration = 3000, -- ms to install the dye
    },

    -- efficiency percentages for burst, based on purge behavior
    Efficiency = {
        noPurge      = 30, -- % efficiency if burst is used without purging
        windowExpiry = 50, -- % efficiency once the efficiency window expires
        purge = {
            min = 70,  -- % at 1-second purge
            max = 100, -- % at full purge (up to burst kit threshold)
        },
    },

    -- purge mechanics and notifications
    Purge = {
        ptfx_size = 0.35, -- size of purge particle effects
        window    = 2,    -- minutes the efficiency window lasts for burst
        cooldown  = 1,    -- minutes after window expires before a new one can start

        gasLeak = {
            duration = 1000, -- ms the leak ptfx plays
            chance   = 50,   -- % chance of a leak occurring during cooldown purge
            remove   = { min = 1, max = 50 }, -- % of shots lost on leak
        },

        notify = {
            showHeldDuration = true, -- notify every second while purge is held
            showConsumption  = true, -- notify shots consumed on release
            showEfficiency   = true, -- notify efficiency % gained on release
        },
    },

    -- burst mechanics and notifications
    Burst = {
        cooldown = true, -- cooldown equal to how long burst was held

        baseTorqueMultiplier = 1.8, -- multiplied with (maxSpeed / currentSpeed) — never go below 1.0
        requiredEngineHealth = 500.0, -- 0.0-1000.0, minimum engine health to activate burst
        screenShakeIntensity = 0.40, -- camera shake amplitude while bursting

        engineDamage = {
            noPurge      = { chance = 70, engineHealth = 199.9 }, -- bursting without purging
            windowExpiry = { chance = 25, engineHealth = 199.9 }, -- bursting after window expired
            threshold    = { chance = 90, engineHealth = 199.9 }, -- held past burst kit threshold
        },

        notify = {
            showHeldDuration   = true, -- notify every second while burst is held
            showRemainingShots = true, -- notify remaining shots after use
        },
    },

    -- points where tuners can refill empty bottles into 10-shot bottles, finite stock resets on restart
    Refill = {
        distance = 2.0,
        blip     = { name = "NOS Refill", sprite = 436, display = 4, scale = 0.65, color = 38 },
        skillcheck = { enable = false, difficulty = { "easy", "easy" }, inputs = { "w", "a", "s", "d" } },
        duration = 3000, -- ms to transform empty bottle into a nos bottle
        label    = "Refilling NOS Bottle",
        anim     = { dict = "mini@repair", name = "fixing_a_player", blendIn = 8.0, blendOut = -8.0, flag = 49 },

        points = {
            [1] = { pos = vector3(1697.86, -1696.32, 112.46), blip = true, size = 20 },
            [2] = { pos = vector3(251.15, -2932.52, 5.75),    blip = true, size = 20 },
            [3] = { pos = vector3(1014.79, -2529.23, 28.30),  blip = true, size = 20 },
            [4] = { pos = vector3(1119.73, -1625.65, 34.87),  blip = true, size = 20 },
            [5] = { pos = vector3(-104.67, -2686.20, 5.99),   blip = true, size = 20 },
            [6] = { pos = vector3(-424.44, -2265.67, 7.59),   blip = true, size = 20 },
        },
    },
}
```


# Engine Swap

t1ger\_tuning/shared/engine\_swap.lua

```lua
-- the index number represent the vehicle class!
return { -- set icon to nil to use defaualt, else set your own icon.
    ['0'] = { -- Compacts Class
        {label = 'Stock Engine', stock = true, price = 1000, icon = nil}, -- requires 'gameName' in vehicles.meta to be specified!
        {label = 'Kanjo Engine', soundName = 'kanjo', price = 2500, icon = nil}, -- Dinka Kanjo
        {label = 'Club Engine', soundName = 'club', price = 3500, icon = nil}, -- BF Club
        {label = 'Issi Engine', soundName = 'issi3', price = 4500, icon = nil}, -- Weeny Issy Classic
    },
    ['1'] = { -- Sedans Class
        {label = 'Stock Engine', stock = true, price = 1000, icon = nil}, -- requires 'gameName' in vehicles.meta to be specified!
        {label = 'Fugitive Engine', soundName = 'fugitive', price = 4500, icon = nil}, -- Cheval Fugitive
        {label = 'Tailgater S Engine', soundName = 'tailgater2', price = 6000, icon = nil}, -- Obey Tailgater S
        {label = 'Schafter V12 Engine', soundName = 'schafter5', price = 7500, icon = nil}, -- Benefactor Schafter V12 (Armored)
    },
    ['2'] = { -- SUVs Class
        {label = 'Stock Engine', stock = true, price = 1000, icon = nil}, -- requires 'gameName' in vehicles.meta to be specified!
        {label = 'Baller ST-D Engine', soundName = 'baller8', price = 6000, icon = nil}, -- Gallivanter Baller ST-D
        {label = 'Contender Engine', soundName = 'contender', price = 7000, icon = nil}, -- Vapid Contender
        {label = 'Toros Engine', soundName = 'toros', price = 8000, icon = nil}, -- Pegassi Toros
        {label = 'Rebla GTS Engine', soundName = 'rebla', price = 10000, icon = nil}, -- Ubermacht Rebla GTS
    },
    ['3'] = { -- Coupes Class
        {label = 'Stock Engine', stock = true, price = 1000, icon = nil}, -- requires 'gameName' in vehicles.meta to be specified!
        {label = 'Sentinel XS Engine', soundName = 'sentinel', price = 4000, icon = nil}, -- Ubermacht Sentinel XS
        {label = 'Cognoscenti Engine', soundName = 'cogcabrio', price = 5000, icon = nil}, -- Cognoscenti Cabrio
        {label = 'Previon Engine', soundName = 'previon', price = 6000, icon = nil}, -- Karin Previon
    },
    ['4'] = { -- Muscle Class
        {label = 'Stock Engine', stock = true, price = 1000, icon = nil}, -- requires 'gameName' in vehicles.meta to be specified!
        {label = 'Blade Engine', soundName = 'blade', price = 4000, icon = nil}, -- Vapid Blade 
        {label = 'Yosemite Engine', soundName = 'yosemite', price = 5000, icon = nil}, -- Declasse Yosemite
        {label = 'Gauntlet Hellfire Engine', soundName = 'gauntlet4', price = 6000, icon = nil}, -- Bravado Gauntlet Hellfire
        {label = 'Dominator GT Engine', soundName = 'dominator9', price = 7000, icon = nil}, -- Vapid Dominator GT
        {label = 'BlackFin Engine', soundName = 'coquette3', price = 10000, icon = nil}, -- Invetero Coquette BlackFin
    },
    ['5'] = { -- Sports Classics Class
        {label = 'Stock Engine', stock = true, price = 1000, icon = nil}, -- requires 'gameName' in vehicles.meta to be specified!
        {label = 'Stirling GT Engine', soundName = 'feltzer3', price = 10000, icon = nil}, -- Benefactor Stirling GT
        {label = 'Casco Engine', soundName = 'casco', price = 8000, icon = nil}, -- Lampadatti Casco
        {label = 'Ardent Engine', soundName = 'ardent', price = 6000, icon = nil}, -- Ocelot Ardent
        
    },
    ['6'] = { -- Sports Class
        {label = 'Stock Engine', stock = true, price = 1000, icon = nil}, -- requires 'gameName' in vehicles.meta to be specified!
        {label = 'Drafter Engine', soundName = 'drafter', price = 6000, icon = nil}, -- Obey 8F Drafter
        {label = 'Comet S2 Engine', soundName = 'comet7', price = 7000, icon = nil}, -- Pfister Comet S2 Cabrio
        {label = 'Slagen GT Engine', soundName = 'schlagen', price = 8500, icon = nil}, -- Benefactor Schalgen GT
        {label = 'Schafter V12 Engine', soundName = 'schafter3', price = 9500, icon = nil}, -- Benefactor Schafter V12
    },
    ['7'] = { -- Super Class
        {label = 'Stock Engine', stock = true, price = 1000, icon = nil}, -- requires 'gameName' in vehicles.meta to be specified!
        {label = 'Turismo R Engine', soundName = 'turismor', price = 12500, icon = nil}, -- Grotti Turismo R
        {label = 'Zorrusso Engine', soundName = 'zorrusso', price = 15000, icon = nil}, -- Pegassi Zorrusso
        {label = 'XA-21 Engine', soundName = 'xa21', price = 18000, icon = nil}, -- Ocelat XA-21
    },
    ['8'] = { -- Motorcycles Class
        {label = 'Stock Engine', stock = true, price = 1000, icon = nil}, -- requires 'gameName' in vehicles.meta to be specified!
        {label = 'Sanctus Engine', soundName = 'sanctus', price = 4500, icon = nil}, -- LCC Sanctus
        {label = 'Gargoyle Engine', soundName = 'gargoyle', price = 6000, icon = nil}, -- Western Gargoyle
        {label = 'FCR 1000 Engine', soundName = 'fcr', price = 7500, icon = nil}, -- Pegassi FCR 1000
        {label = 'Shinobi Engine', soundName = 'shinobi', price = 8500, icon = nil}, -- Nagasaki Shinobi 
    },
    ['9'] = { -- Off Roads
        {label = 'Stock Engine', stock = true, price = 1000, icon = nil}, -- requires 'gameName' in vehicles.meta to be specified!
    },
    ['12'] = { -- Vans
        {label = 'Stock Engine', stock = true, price = 1000, icon = nil}, -- requires 'gameName' in vehicles.meta to be specified!
    },
}
```


# Dyno Fine-Tuning

t1ger\_tuning/shared/dyno.lua

```lua
return {

    Enable = true, -- enable/disable the dyno feature entirely

    -- torque modifier — drive force at the wheels. 1.0 is the vehicle's default.
    -- <1.0 = less drive force, >1.0 = more drive force
    Torque = {
        label       = "Torque Modifier",
        description = "Specifies the drive force of the car at the wheels.",
        icon        = "gears",
        slider = {
            min  = 1.0, -- not recommended below 1.0 — this is the vehicle's default
            max  = 3.0, -- not recommended above 2.0 — torque becomes overpowered
            step = 0.1,
        },
    },

    -- power modifier — how fast the engine revs / affects top speed
    Power = {
        label       = "Power Modifier",
        description = "Describes how fast an engine will rev.",
        icon        = "gauge-high",
        slider = {
            min  = 0.00,
            max  = 2.0,
            step = 0.05,
        },
    },

    -- brakes modifier — multiplies deceleration, bigger number = harder braking
    Brakes = {
        label       = "Brakes Modifier",
        description = "Multiplies the game's calculation of deceleration. Bigger number = harder braking.",
        icon        = "shoe-prints",
        slider = {
            min  = 0.01, -- almost no brakes
            max  = 2.0,  -- hard brakes — 1.0 seems to be the max on most vehicles
            step = 0.1,
        },
    },

    -- "View Modifiers" menu option
    ViewModifiers = {
        icon        = "magnifying-glass",
        description = "View current dyno handling modifiers",
    },

    -- "Fine Tuning" menu option — the slider input + hard reset + save progressbar
    FineTuning = {
        icon        = "sliders",
        description = "Fine tune the vehicle's torque, power and brakes",
        reset       = { label = "Hard Reset" },
        progressBar = {
            enable   = true,
            duration = 3000,
            label    = "Saving Dyno Profile...",
        },
    },
}
```


# Exports

In this section you'll find various exports & events to be used/integrated with other 3rd party resources.

{% content-ref url="/pages/Dqen0MPYOmke2f3sPdTh" %}
[Server](/resources/t1ger-mechanic/exports/server)
{% endcontent-ref %}

{% content-ref url="/pages/gwK1m2YywjH23Ou1NvOz" %}
[Client](/resources/t1ger-mechanic/exports/client)
{% endcontent-ref %}


# Server

Server-sided exports

## TrimPlate

Trims leading and trailing spaces from a plate string. Ensures plate numbers are formatted correctly to prevent inconsistencies in database lookups.

```lua
exports["t1ger_tuning"]:TrimPlate(plate)
```

**Parameters**

* **plate** *(string)* – The plate string to be trimmed.

**Returns**

* **string** – The trimmed plate.

***

## GetVehicleEngineSwap

Returns cached engine swap data for a plate, loading from the database on first access. Acts as a fallback for entries not yet preloaded (e.g. created after the last resource start).

```lua
exports["t1ger_tuning"]:GetVehicleEngineSwap(plate)
```

**Parameters**

* **plate** *(string)* – The vehicle plate.

**Returns**

* **table|nil** – `{ vehicle, engine }`, or `nil` if no engine swap data exists for this plate.

***

## SetVehicleEngineSwap

Saves engine swap data for a plate — updates cache, database and vehicle statebag. Only persists to the database if the vehicle is actually owned, to avoid orphaned rows for test/NPC vehicles. Still applies visually/in-memory regardless.

```lua
exports["t1ger_tuning"]:SetVehicleEngineSwap(netId, plate, data)
```

**Parameters**

* **netId** *(number)* – Network ID of the vehicle.
* **plate** *(string)* – The vehicle plate.
* **data** *(table)* – `{ vehicle = modelName, engine = soundName }`.

***

## GetModOrders

Returns all currently tracked mod orders.

```lua
exports["t1ger_tuning"]:GetModOrders()
```

**Returns**

* **table** – All mod orders, keyed by plate.

***

## GetModOrder

Returns the mod order for a specific plate.

```lua
exports["t1ger_tuning"]:GetModOrder(plate)
```

**Parameters**

* **plate** *(string)* – The vehicle plate.

**Returns**

* **table|nil** – The mod order data, or `nil` if no active order exists for this plate.

***

## GetCombinedShops

Returns the slim shop data cache used for combined (mechanic + tuning) shops, so other resources can read it without listening for events.

```lua
exports["t1ger_tuning"]:GetCombinedShops()
```

**Returns**

* **table** – All combined shops, keyed by shop ID.

***

## SetCombinedOwner

Sets or clears the owner of a combined shop in the slim cache.

```lua
exports["t1ger_tuning"]:SetCombinedOwner(target, shopId, newOwner)
```

**Parameters**

* **target** *(integer)* – Player ID, or `-1` to broadcast to everyone.
* **shopId** *(integer)* – The shop ID.
* **newOwner** *(string|nil)* – The new owner's identifier, or `nil` to clear the owner.

***

## AddCombinedEmployee

Adds an employee to a combined shop's slim cache.

```lua
exports["t1ger_tuning"]:AddCombinedEmployee(target, shopId, employee)
```

**Parameters**

* **target** *(integer)* – Player ID, or `-1` to broadcast to everyone.
* **shopId** *(integer)* – The shop ID.
* **employee** *(table)* – Employee data `{ identifier, grade, label? }`.

***

## UpdateCombinedEmployee

Updates an employee's data in the slim cache.

```lua
exports["t1ger_tuning"]:UpdateCombinedEmployee(target, shopId, employee)
```

**Parameters**

* **target** *(integer)* – Player ID, or `-1` to broadcast to everyone.
* **shopId** *(integer)* – The shop ID.
* **employee** *(table)* – The updated employee data.

***

## RemoveCombinedEmployee

Removes an employee by identifier from the slim cache.

```lua
exports["t1ger_tuning"]:RemoveCombinedEmployee(target, shopId, identifier)
```

**Parameters**

* **target** *(integer)* – Player ID, or `-1` to broadcast to everyone.
* **shopId** *(integer)* – The shop ID.
* **identifier** *(string)* – The employee identifier to remove.

***

## IsPlayerEmployee

Checks if a player is an employee of a specific shop, or any shop.

```lua
exports["t1ger_tuning"]:IsPlayerEmployee(src, shopId)
```

**Parameters**

* **src** *(number)* – The player's server ID.
* **shopId** *(number, optional)* – The shop ID to check. If omitted, checks all shops.

**Returns**

* **boolean** – `true` if the player is an employee, otherwise `false`.
* **number|nil** – The ID of the shop the player is employed at, or `nil` if not found.

***

## IsPlayerTunerBoss

Checks if a player's job is boss-grade at a specific tuner shop, or any shop.

```lua
exports["t1ger_tuning"]:IsPlayerTunerBoss(src, shopId)
```

**Parameters**

* **src** *(number)* – The player's server ID.
* **shopId** *(number, optional)* – The shop ID to check. If omitted, checks all shops.

**Returns**

* **boolean** – `true` if the player is a boss-grade tuner, otherwise `false`.
* **number|nil** – The ID of the shop where the player is boss, or `nil` if not found.

***

## IsPlayerShopOwner

Checks if a player is the owner of a specific shop, or any shop.

```lua
exports["t1ger_tuning"]:IsPlayerShopOwner(src, shopId)
```

**Parameters**

* **src** *(number)* – The player's server ID.
* **shopId** *(number, optional)* – The shop ID to check. If omitted, checks all shops.

**Returns**

* **boolean** – `true` if the player owns the shop, otherwise `false`.
* **number|nil** – The ID of the owned shop, or `nil` if not found.

***

## AddEmployee

Adds an employee to a shop.

```lua
exports["t1ger_tuning"]:AddEmployee(shopId, jobGrade, setJob, srcOrIdentifier)
```

**Parameters**

* **shopId** *(number)* – The shop ID.
* **jobGrade** *(number)* – The job grade to assign.
* **setJob** *(boolean|nil)* – Whether to set the player's job.
* **srcOrIdentifier** *(number|string)* – Player source or identifier.

**Returns**

* **boolean** – `true` on success.

***

## RemoveEmployee

Removes an employee from a shop.

```lua
exports["t1ger_tuning"]:RemoveEmployee(shopId, setJob, srcOrIdentifier)
```

**Parameters**

* **shopId** *(number)* – The shop ID.
* **setJob** *(boolean|nil)* – Whether to reset the player's job.
* **srcOrIdentifier** *(number|string)* – Player source or identifier.

**Returns**

* **boolean** – `true` on success.

***

## UpdateEmployee

Updates an employee's job grade in a shop.

```lua
exports["t1ger_tuning"]:UpdateEmployee(shopId, jobGrade, setJob, srcOrIdentifier)
```

**Parameters**

* **shopId** *(number)* – The shop ID.
* **jobGrade** *(number)* – The new job grade.
* **setJob** *(boolean|nil)* – Whether to set the player's job.
* **srcOrIdentifier** *(number|string)* – Player source or identifier.

**Returns**

* **boolean** – `true` on success.

***

## GetVehicleNitrous

Returns cached nitrous data for a plate. Purely an in-memory lookup — the cache is fully populated at startup and kept up to date on every install, so there's nothing left to fall back to a database query for.

```lua
exports["t1ger_tuning"]:GetVehicleNitrous(plate)
```

**Parameters**

* **plate** *(string)* – The vehicle plate.

**Returns**

* **table|nil** – `{ size, shots, burst, color }`, or `nil` if no nitrous data exists for this plate.

***

## TrySaveVehicleNitrous

Saves a vehicle's current nitrous data, read live from its statebag. Stateless — most vehicles never have nitrous data at all, so this bails out on a single free table read for the vast majority of calls.

```lua
exports["t1ger_tuning"]:TrySaveVehicleNitrous(vehicle)
```

**Parameters**

* **vehicle** *(number)* – The vehicle entity handle.

***

## GetVehicleDyno

Returns cached dyno data for a plate. Purely an in-memory lookup — the cache is fully populated at startup and kept up to date on every save, so there's nothing left to fall back to a database query for.

```lua
exports["t1ger_tuning"]:GetVehicleDyno(plate)
```

**Parameters**

* **plate** *(string)* – The vehicle plate.

**Returns**

* **table|nil** – `{ torque, power, brakes }`, or `nil` if no dyno data exists for this plate.

***

## SetVehicleDyno

Saves dyno data for a plate — updates cache, database and vehicle statebag. Values are clamped to the configured slider ranges regardless of what's sent, since this feature has no payment gate to naturally limit abuse.

```lua
exports["t1ger_tuning"]:SetVehicleDyno(netId, plate, data)
```

**Parameters**

* **netId** *(number)* – Network ID of the vehicle.
* **plate** *(string)* – The vehicle plate.
* **data** *(table)* – `{ torque, power, brakes }`.

**Returns**

* **boolean** – `true` on success.


# Client

Client-sided exports

## OpenModsMainMenu

Opens the mods menu for a vehicle. Blocks entry if the vehicle needs repair and `Repair.allow` is false. Snapshots all current mods before opening so the vehicle can be restored if the menu is closed without checkout.

```lua
exports["t1ger_tuning"]:OpenModsMainMenu(vehicle, accessType, shopId, allowedCategories, allowedMods, isFree)
```

**Parameters**

* **vehicle** *(integer)* – The vehicle entity handle.
* **accessType** *(string)* – `"customs"` or `"modstation"`.
* **shopId** *(integer, optional)* – The shop ID. Customs access only.
* **allowedCategories** *(table, optional)* – Restricts the menu to specific categories. `nil` means all categories allowed.
* **allowedMods** *(table, optional)* – Restricts the menu to specific mod types. Modstation access only; `nil` means all mods allowed.
* **isFree** *(boolean, optional)* – Whether mods are free at this access point. Modstation access only.

***

## GetModsMenuState

Returns the current in-memory state of the mods menu session (active vehicle, access type, basket alterations, etc).

```lua
exports["t1ger_tuning"]:GetModsMenuState()
```

**Returns**

* **table** – The `ModsMenu` state table.

***

## OpenEngineSwapMenu

Opens the engine swap menu for a vehicle at a tuner shop.

```lua
exports["t1ger_tuning"]:OpenEngineSwapMenu(vehicle, shopId)
```

**Parameters**

* **vehicle** *(integer)* – The vehicle entity handle.
* **shopId** *(number)* – The shop ID.

***

## OpenDynoMenu

Opens the dyno main menu — view current modifiers or fine tune torque, power and brakes.

```lua
exports["t1ger_tuning"]:OpenDynoMenu(vehicle, knownStats)
```

**Parameters**

* **vehicle** *(integer)* – The vehicle entity handle.
* **knownStats** *(table, optional)* – Pass the just-applied `{ torque, power, brakes }` values directly to avoid a stale display right after saving.

***

## GetVehicleDyno

Returns the vehicle's current dyno data from its statebag.

```lua
exports["t1ger_tuning"]:GetVehicleDyno(vehicle)
```

**Parameters**

* **vehicle** *(integer)* – The vehicle entity handle.

**Returns**

* **table|nil** – `{ torque, power, brakes }`, or `nil` if the vehicle has never been dyno tuned.

***

## SetVehicleDyno

Sets the vehicle's dyno data. Server-authoritative — values are clamped server-side to the configured slider ranges regardless of what's sent here.

```lua
exports["t1ger_tuning"]:SetVehicleDyno(vehicle, data)
```

**Parameters**

* **vehicle** *(integer)* – The vehicle entity handle.
* **data** *(table)* – `{ torque, power, brakes }`.

***

## OpenNitrousMenu

Opens the nitrous menu for a vehicle — install a fresh kit, upgrade an existing one, or manage the burst kit.

```lua
exports["t1ger_tuning"]:OpenNitrousMenu(vehicle, shopId)
```

**Parameters**

* **vehicle** *(integer)* – The vehicle entity handle.
* **shopId** *(number)* – The shop ID.

***

## GetVehicleNitrous

Returns the vehicle's current nitrous data from its statebag.

```lua
exports["t1ger_tuning"]:GetVehicleNitrous(vehicle)
```

**Parameters**

* **vehicle** *(integer)* – The vehicle entity handle.

**Returns**

* **table|nil** – `{ size, shots, burst, color }`, or `nil` if no nitrous kit is installed.

***

## SetVehicleNitrous

Merges the given fields into the vehicle's nitrous data and updates the statebag, syncing to all clients. Pass only the fields you want to change — e.g. `{ shots = 12 }` — existing fields are preserved.

```lua
exports["t1ger_tuning"]:SetVehicleNitrous(vehicle, data)
```

**Parameters**

* **vehicle** *(integer)* – The vehicle entity handle.
* **data** *(table)* – Partial or full `{ size, shots, burst, color }`.

***

## GetVehicleNitrousShots

Returns the vehicle's current nitrous shots count.

```lua
exports["t1ger_tuning"]:GetVehicleNitrousShots(vehicle)
```

**Parameters**

* **vehicle** *(integer)* – The vehicle entity handle.

**Returns**

* **number** – The current shot count. `0` if no kit is installed.

***

## SetVehicleNitrousShots

Sets the vehicle's nitrous shots count, clamped between 0 and the kit's max capacity (size × 10).

```lua
exports["t1ger_tuning"]:SetVehicleNitrousShots(vehicle, shots)
```

**Parameters**

* **vehicle** *(integer)* – The vehicle entity handle.
* **shots** *(number)* – The desired shot count.

***

## SaveVehicleNitrous

Sends the vehicle's current nitrous data to the server for persistence. Intended for use in garage scripts that delete the vehicle before the server's own removal handler can catch it.

```lua
exports["t1ger_tuning"]:SaveVehicleNitrous(vehicle)
```

**Parameters**

* **vehicle** *(integer)* – The vehicle entity handle.

***

## BillingMain

Opens the main billing menu for the local player's tuner shop.

```lua
exports["t1ger_tuning"]:BillingMain(returnMenu)
```

**Parameters**

* **returnMenu** *(string, optional)* – ox\_lib context menu ID to return to when this menu is closed.

***

## CreateShop

Opens the interface for creating a new tuner shop. Admin use.

```lua
exports["t1ger_tuning"]:CreateShop(returnMenu)
```

**Parameters**

* **returnMenu** *(string, optional)* – ox\_lib context menu ID to return to when this menu is closed.

***

## ViewShops

Displays the list of tuner shops in a menu. Admin use.

```lua
exports["t1ger_tuning"]:ViewShops(returnMenu)
```

**Parameters**

* **returnMenu** *(string, optional)* – Menu ID to return to if entered from a menu.

***

## IsPlayerEmployee

Checks if the local player is an employee of a specific shop, or any shop.

```lua
exports["t1ger_tuning"]:IsPlayerEmployee(shopId)
```

**Parameters**

* **shopId** *(number, optional)* – The shop ID to check. If omitted, checks all shops.

**Returns**

* **boolean** – `true` if the player is an employee, otherwise `false`.
* **number|nil** – The ID of the shop the player is employed at, or `nil` if not found.

***

## IsPlayerTuner

Checks if the local player's job matches any tuner shop's job.

```lua
exports["t1ger_tuning"]:IsPlayerTuner(shopId)
```

**Parameters**

* **shopId** *(number, optional)* – The shop ID to check. If omitted, checks all shops.

**Returns**

* **boolean** – `true` if the player has a matching tuner job, otherwise `false`.
* **number|nil** – The ID of the matching shop, or `nil` if not found.

***

## IsPlayerTunerBoss

Checks if the local player's job is boss-grade at a specific tuner shop, or any shop.

```lua
exports["t1ger_tuning"]:IsPlayerTunerBoss(shopId)
```

**Parameters**

* **shopId** *(number, optional)* – The shop ID to check. If omitted, checks all shops.

**Returns**

* **boolean** – `true` if the player is a boss-grade tuner, otherwise `false`.
* **number|nil** – The ID of the shop where the player is boss, or `nil` if not found.

***

## IsPlayerShopOwner

Checks if the local player is the owner of a specific shop, or any shop.

```lua
exports["t1ger_tuning"]:IsPlayerShopOwner(shopId)
```

**Parameters**

* **shopId** *(number, optional)* – The shop ID to check. If omitted, checks all shops.

**Returns**

* **boolean** – `true` if the player owns the shop, otherwise `false`.
* **number|nil** – The ID of the owned shop, or `nil` if not found.

***

## OpenModOrderMenu

Opens the mod order context menu for the tuner. Shows order details, start/stop work options and the full task list.

```lua
exports["t1ger_tuning"]:OpenModOrderMenu(vehicle, shopId, plate, order)
```

**Parameters**

* **vehicle** *(integer)* – The vehicle entity handle.
* **shopId** *(number)* – The shop ID.
* **plate** *(string)* – The vehicle's plate.
* **order** *(table)* – The mod order data.

***

## OpenNpcJobsMenu

Opens the NPC jobs menu from the tuner tablet — Salvage Car and Mobile Tuning.

```lua
exports["t1ger_tuning"]:OpenNpcJobsMenu()
```

***

## IsWorkflowActive

Returns whether the mod order workflow UI is currently active and open.

```lua
exports["t1ger_tuning"]:IsWorkflowActive()
```

**Returns**

* **boolean** – `true` if the workflow UI is open, otherwise `false`.


# Guides

Step-by-step guides covering how each of t1ger\_tuning's systems actually works in-game

{% content-ref url="/pages/x7OWn6Mz7qwiakwgRhGs" %}
[Nitrous](/resources/t1ger-tuning/guides/nitrous)
{% endcontent-ref %}

{% content-ref url="/pages/c4XgYDIuW5FQYWYNgXgU" %}
[Engine Swap](/resources/t1ger-tuning/guides/engine-swap)
{% endcontent-ref %}

{% content-ref url="/pages/rDuS6dCQirnP4ichmyCH" %}
[Pricing](/resources/t1ger-tuning/guides/pricing)
{% endcontent-ref %}


# Tuner Shops

Tuner shops are the backbone of the whole tuning system — every mod install, engine swap, nitrous kit, and NPC job ultimately runs through one. This guide covers creating a shop as an admin, and running one day-to-day as a boss or employee.

#### Creating a Shop (Admin)

Shops are created through the admin interface — open it with the configured command (`/tuning:create` by default) or via the admin tuning menu (`F9` by default). Creating a shop places all of its markers in the world at once, and it becomes fully functional immediately — no server restart required.

Each shop gets its own set of markers, and every marker type can be individually enabled or disabled per shop:

| Marker         | Purpose                                       |
| -------------- | --------------------------------------------- |
| **Duty**       | Toggle on/off duty as an employee             |
| **Boss**       | Manage employees, shop account, markup        |
| **Garage**     | Store/retrieve owned vehicles                 |
| **Storage**    | Access the shop's shared stash                |
| **Workbench**  | Craft mod parts, tools and nitrous components |
| **Supplier**   | Order parts and materials from the catalogue  |
| **Customs**    | Public/customer-facing mods menu access       |
| **Tuning Bay** | Engine swaps, nitrous, dyno                   |

Marker positions, blip sprites, and colors are all fully customizable per shop through the admin management interface (`/tuning:manage`), which also lets you edit or delete markers, list a shop for sale, or remove it entirely.

#### Assigning a Boss

Every shop needs an assigned boss — done through the admin management interface when the shop is created or later. The boss is the player responsible for running that shop's day-to-day operations.

#### Running a Shop (Boss)

The **Boss** marker opens a dedicated menu with everything needed to manage the shop:

**Account** — view the shop's current balance, and deposit or withdraw funds. The shop account is what pays for engine swap parts, nitrous kits, and supplier orders — it needs a healthy balance to keep operating.

**Employees** — recruit nearby players directly (sends them a recruitment offer they can accept or decline), view the current roster, and manage individual employees: adjust their job grade or remove them from the shop. The shop owner can't be fired or demoted through this menu.

**Markup** — set the shop's price markup percentage, applied on top of mod order and customs pricing (see the **Pricing** guide for how this fits into the full price calculation). This lets each shop position itself differently — a premium shop might run a higher markup, while a budget shop keeps it low to attract more customers.

#### Delivery Point

Each shop has its own delivery point — where new engines arrive during an engine swap. This is set up through the boss menu, either teleporting to update an existing point or placing one for the first time. Only one engine swap can use a shop's delivery point at a time, so busy shops may want tuners coordinating rather than starting swaps simultaneously.

#### Job Grades & Duty

Shops use a standard job grade system — recruit, employee, boss by default, though grades are fully configurable. Employees can toggle on/off duty at the Duty marker; being off duty typically means no salary and no access to shop functions, depending on your server's configuration.

#### Combined Shops (with t1ger\_mechanic)

If `t1ger_mechanic` is installed alongside this resource, a single shop location can offer **both** mechanic and tuning services — one set of markers, one employee roster, one shared account, all in the same spot. This is set up the same way as a standalone tuning shop; the combined behavior is detected and applied automatically when both resources are present.

#### Buying & Selling Shops

If enabled (`Config.Shop.Sale`), shops can be listed for sale by an admin and purchased by players — giving ownership a real in-game economy instead of being purely admin-assigned.


# Mod Orders

Mod orders are the formal, tuner-fulfilled alternative to buying and installing mods yourself through the mods menu. A customer places an order for the parts they want, and a tuner physically installs each one — a real roleplay interaction instead of a self-service purchase.

#### Placing an Order

Orders are created from inside the mods menu. Instead of checking out directly, a customer builds their basket as normal — browsing categories, previewing mods live on their vehicle — then places an order instead of paying immediately. The order records exactly what was selected: each part, its price, and the total.

If `Config.ModsMenu.DisableCheckout` is enabled on your server, direct self-checkout is removed entirely, and placing an order becomes the *only* way to buy mods — forcing every customer to go through a tuner.

#### Pricing

An order's total is the sum of each selected part's price (calculated the same way as any mods menu purchase — see the **Pricing** guide for the full breakdown), plus the shop's configured markup on top. Unlike checking out directly through the mods menu, orders are never affected by incentivized pricing — that markup only applies to self-service purchases.

#### Fulfilling an Order

Once an order exists, any tuner at that shop can start working it. The order opens in a workflow UI that tracks progress in real time — every item on the order is listed as a task, showing what's done and what's left.

Installing each part is a genuine physical process, not a menu click:

1. **Target the correct install point** — each mod type has its own zone on the vehicle (front, rear, wheel, engine bay, interior). Walking up to the wrong spot won't let you install it.
2. **Hood or doors open automatically** if the part requires it (engine bay work opens the hood, interior work opens a door).
3. **Install the part** — using the matching item plays an installation animation and a skill check. Succeeding applies the mod; failing lets you try again.

Only one tuner can actively work a given order's install at a time, and a **Cancel Install** option is available if you need to stop partway through a specific part.

#### Tracking Orders

The tuner tablet's **Mod Orders** section lists every order for your shop — pending ones (not yet started) and in-progress ones (someone's already working them). Selecting an order shows its full breakdown: customer name, parts total, service fee, and the task list.

* **Pending orders** can be refunded outright, returning the customer's money and cancelling the order.
* **In-progress orders** can be abandoned by whoever's working them, or by a shop boss/owner — this stops the install and notifies the customer.

Boss and shop owner roles get elevated visibility across *all* orders at the shop, not just the ones they personally started.

#### Order Completion

Once every part on the order has been successfully installed, the order closes automatically — no separate "finish" step needed. The customer's vehicle reflects every mod exactly as ordered.


# Pricing

Mod pricing in t1ger\_tuning is built from several independent layers that stack together. Understanding each layer — and where it's calculated — makes it much easier to tune the economy to fit your server, whether you want mods to feel cheap and accessible or expensive and prestige-driven.

## The Core Formula

Every mod variant's price is calculated in this order:

### **1. Base Price**

Each mod type has a base price set in `shared/modtypes.lua` (`modData.price`). Some mods also define **per-variant prices** directly (`modData.variants[index].price`) — when a variant has its own explicit price, that's used exactly as-is, and none of the calculation below applies to it. This is useful for mods where certain options are genuinely worth more than a formula could capture (e.g. a rare paint style, a premium wheel design).

### **2. Escalation** (only for mods without a variant-level price)

If a mod has `escalation = true` set in `shared/modtypes.lua`, each successive variant costs progressively more than the last, controlled by:

lua

```lua
Config.PriceEscalationPercent = 5 -- % increase per variant index
```

At 5%, variant 0 costs base price × 1.05, variant 1 costs base price × 1.10, variant 2 costs × 1.15, and so on. This makes "the highest tier is the most expensive" happen automatically without needing to hand-price every single option — useful for mods with a long list of similar variants (like most performance upgrades).

### **3. Vehicle Value Tiering**

On top of the base/escalated price, a portion of the *vehicle's own market value* gets added — so modding an expensive supercar costs more than modding a beater, even for the exact same part:

lua

```lua
Config.TieredPricing = true -- master toggle for this whole layer

Config.PriceTiers = {
    { upperLimit = 10000,    multiplier = 0.05 },  -- cars up to $10k:   +5% of vehicle value
    { upperLimit = 50000,    multiplier = 0.03 },  -- cars up to $50k:   +3%
    { upperLimit = 100000,   multiplier = 0.02 },  -- cars up to $100k:  +2%
    { upperLimit = 500000,   multiplier = 0.01 },  -- cars up to $500k:  +1%
    { upperLimit = math.huge, multiplier = 0.005 }, -- everything above: +0.5%
}
```

The vehicle's price is matched against the **first tier whose `upperLimit` it fits under**, and that tier's multiplier is applied to the vehicle's value and added to the base price. If a vehicle's real market value can't be determined, `Config.DefaultVehiclePrice` is used instead — worth setting this to something reasonable for your server's average vehicle price if you use tiered pricing.

**One important exception:** if a mod's base price is exactly `0`, tiered pricing is skipped entirely and the mod stays completely free — this is how you make specific mods (or specific "remove/stock" variants) genuinely free regardless of what car it's on.

## The Two Extra Layers (Applied at Checkout, Not in the Base Formula)

These are separate from everything above — they're markups added on top, depending on *how* the player is buying:

**Incentivized Pricing** — a markup applied only when a player checks out **directly through the mods menu** themselves, without involving a tuner:

lua

```lua
Config.ModsMenu.IncentivizedPricing = {
    enable  = true,
    percent = 25, -- self-service costs 25% more than going through a tuner
}
```

This is a soft nudge, not a hard requirement — you can force real tuner interaction entirely instead by setting `Config.ModsMenu.DisableCheckout = true`, which removes direct checkout altogether and requires every customer to place a mod order.

**Shop Markup** — the tuner shop boss's own configurable markup percentage, applied when a mod order or customs checkout goes through their shop. This is set per-shop by the boss (up to `Config.Shop.Markup.max`), letting individual shops price themselves higher or lower than competitors — a genuine player-driven economy lever, not something you configure globally.

## Worked Example

A tuner installs an engine upgrade (base price $3,000, no escalation) on a $30,000 car, with default tiered pricing:

1. Base price: $3,000
2. $30,000 falls into the "up to $50,000" tier → 3% multiplier
3. Tier addition: $30,000 × 0.03 = $900
4. Calculated price: $3,000 + $900 = **$3,900**
5. If bought directly through the mods menu (no tuner): $3,900 × 1.25 = **$4,875**
6. If bought through a tuner shop with a 10% shop markup instead: $3,900 × 1.10 = **$4,290**

## Configuring for Your Server's Economy

* **Want mods to feel cheap and accessible?** Lower or disable `PriceEscalationPercent`, disable `TieredPricing` entirely, and keep base prices in `modtypes.lua` low.
* **Want expensive cars to be a genuine status symbol to mod?** Keep tiered pricing on and make sure `Config.DefaultVehiclePrice` and your vehicle price source are accurate — this is what makes supercars cost dramatically more to tune than a beater.
* **Want to push players toward roleplay with tuners instead of self-service?** Raise `IncentivizedPricing.percent`, or go further and set `DisableCheckout = true` to remove self-service entirely.
* **Want certain mods to always be free** (e.g. a starter/basic option)? Set that specific mod or variant's price to `0` in `modtypes.lua` — remember this also skips the vehicle-value tier addition automatically.

## Reference

| Config                                | Location              | Purpose                                                                   |
| ------------------------------------- | --------------------- | ------------------------------------------------------------------------- |
| `Config.PriceEscalationPercent`       | `config.lua`          | % cost increase per variant index, for mods with `escalation = true`      |
| `Config.DefaultVehiclePrice`          | `config.lua`          | Fallback vehicle value when the real one can't be determined              |
| `Config.TieredPricing`                | `config.lua`          | Master toggle for vehicle-value-based pricing                             |
| `Config.PriceTiers`                   | `config.lua`          | The tier table itself — fully editable, more tiers can be added           |
| `Config.PartAcquisitionCost`          | `config.lua`          | Whether the item's own value is factored into the part's acquisition cost |
| `Config.Prices`                       | `config.lua`          | Base prices for paints and RGB custom colors specifically                 |
| `modData.price`                       | `shared/modtypes.lua` | Base price per mod type                                                   |
| `modData.variants[i].price`           | `shared/modtypes.lua` | Explicit per-variant price override, skips escalation                     |
| `modData.escalation`                  | `shared/modtypes.lua` | Enables per-variant price escalation for that mod                         |
| `Config.ModsMenu.IncentivizedPricing` | `config.lua`          | Self-checkout markup                                                      |
| `Config.Shop.Markup`                  | `config.lua`          | Per-shop boss-configurable markup                                         |


# Nitrous

Nitrous gives your vehicle a powerful, risky speed boost — but getting the most out of it means mastering the purge/burst system, not just holding a button.

## Installing a Nitrous Kit

Nitrous kits are installed through the tuner shop's **Tuning Bay** menu. Select a kit size from 1lb to 12lb — larger kits hold more shots (10 shots per lb) but cost more. Upgrading an existing kit to a larger size only charges the difference in price.

Once purchased, a short installation sequence plays at the vehicle — the hood opens, the kit is carried and fitted, and the kit becomes active once complete. A freshly installed kit starts empty and needs to be filled with NOS bottles before it can be used.

## Burst Kits

Every nitrous kit comes with a stock burst kit that allows up to 5 seconds of purge or burst before extra risk kicks in. Burst kits can be upgraded through the same Tuning Bay menu, raising that threshold to 7, 10, or 13 seconds — giving more room to build efficiency and hold a longer burst.

## Refilling Shots

Nitrous kits run on shots (10 per lb). There are two ways to keep a kit topped up:

* **Full bottles** (`NOS 10-Shots`) — use the item while seated as the driver, stationary, to add shots directly to the kit.
* **Empty bottles** (`NOS Empty`) — can't be used directly. Bring them to a NOS refill station (marked on the map for tuners) and exchange them for full bottles.

Both bottle types can be crafted at a tuner shop's workbench, or purchased through the shop supplier.

## Using Nitrous — Purge & Burst

Nitrous isn't just "hold a button and go fast." It's built around a risk/reward loop:

**Purge** (default key: `Right Ctrl`) — while stationary, hold purge to build up efficiency. The longer you hold it (up to your burst kit's threshold), the more efficiency you earn, up to 100%. Releasing purge opens an efficiency window — your burst will draw on whatever efficiency you built, for a limited time.

**Burst** (default key: `Left Shift`) — while driving, hold burst to apply a torque boost. The strength of the boost scales with your current efficiency:

* **Purged first, used within the window** — strongest, safest boost
* **Burst with no purge at all** — weak boost, and a high chance of engine damage
* **Burst after your efficiency window has expired** — reduced efficiency, moderate damage risk
* **Held past your burst kit's threshold** — very high chance of engine damage, regardless of efficiency

Each second of burst held consumes one shot. After releasing, a cooldown begins equal to how long you held it — so you can't just spam burst repeatedly.

## Gas Leaks

If you purge again during the post-window cooldown before a new efficiency cycle can start, you're gambling — there's a chance of a gas leak, which vents a portion of your shots and produces a visible steam effect. Wait out the cooldown to purge safely again.

## Purge Dye

Want your purge smoke a different color than the default white? Use a `NOS Purge Dye` item at the vehicle's engine bay to permanently recolor the purge effect for that vehicle.

## Engine Health

Nitrous requires a minimum engine health to activate at all — a badly damaged engine won't let you burst or purge until it's repaired.


# Engine Swap

Engine swaps let tuners physically replace a vehicle's engine — complete with a real hoist mechanic, not just a menu selection.

## Starting a Swap

Engine swap is available through the tuner shop's **Tuning Bay** menu. Available engines depend on the vehicle's class, each with its own price and a distinct engine sound once installed. Selecting an engine charges the shop account and begins the physical install task at the vehicle.

## The Physical Install

Engine swapping is a genuine multi-step process, not an instant menu action:

1. **Access the engine bay** — the hood opens and the bay is prepared for work.
2. **Bring the hoist** — a tuner engine hoist item is required. Use it to spawn a hoist near the vehicle.
3. **Extract the old engine** — attach the hoist to the vehicle's engine and lift it out. The extracted engine is discarded.
4. **Collect the new engine** — the new engine is delivered to your shop's delivery point (visible on the map). Use the hoist to pick it up and carry it back.
5. **Install the new engine** — attach the hoist to the vehicle again and lower the new engine into place.
6. **Complete the swap** — once installed, the hood closes and the vehicle's engine sound updates to match the new engine.

Throughout the process, precision markers guide you to the correct alignment points for the hoist, both when extracting and when installing.

## Delivery Points

Each tuner shop has its own delivery point where new engines are dropped off — this can be set up by the shop boss. Only one engine swap can use a shop's delivery point at a time; if another tuner is already mid-swap, you'll need to wait until it's free.

## Cancelling a Swap

If you need to stop partway through, use the cancel command (default: `/cancelengineswap`). This safely returns the vehicle to its normal state and refunds the shop for the swap.


# Tuner Tablet

The tuner tablet is the all-in-one device tuners carry for managing shop operations, checking vehicle info, and accessing features that don't need a physical marker — including Dyno and NPC Jobs, both covered in full here.

#### Opening the Tablet

Using the tuner tablet item opens the main menu. What's available depends on whether you're currently inside a vehicle — some sections only make sense with a vehicle present (Vehicle Info, Examine Performance, Dyno), while others are always accessible (Billing, NPC Jobs, Mod Orders).

Every section can be individually enabled or disabled server-side, so a given server's tablet might look slightly different depending on which features are active.

#### Vehicle Info

A quick read-only snapshot of whatever vehicle you're currently in — engine health, body health, fuel level, and plate. Useful for a fast diagnostic check without opening any other menu.

#### Examine Performance

Lists every performance mod currently installed on the vehicle — engine, transmission, suspension, armor, brakes, turbo — read-only. A fast way to see what's already been done to a car before quoting a customer or starting new work.

#### Dyno

The dyno lets a tuner fine-tune three core handling values on any vehicle: **torque** (drive force at the wheels), **power** (how fast the engine revs, tied to top speed), and **brakes** (deceleration strength). It's completely free to use — no payment involved.

**View Modifiers** shows the vehicle's current values read-only — either its saved dyno settings if it's been tuned before, or its live native values if it hasn't.

**Fine Tuning** opens sliders for all three values, plus a **Hard Reset** checkbox. Adjusting the sliders and confirming applies those exact values immediately — torque and brakes take effect instantly, and changes persist across sessions. Checking Hard Reset instead ignores the sliders and restores the vehicle to its true stock defaults, calculated fresh for that specific model rather than a generic fallback.

Torque above the default (`1.0`) also feeds into nitrous burst strength — a dyno-tuned vehicle bursts noticeably harder than a stock one at the same efficiency, on top of whatever nitrous itself provides. See the **Nitrous** guide for how burst strength is calculated.

#### Nitrous Status

A read-only summary of the vehicle's current nitrous kit — size, remaining shots, burst threshold, and purge color — if one's installed. For the full purge/burst gameplay loop, installation, and refilling, see the **Nitrous** guide.

#### Mod Orders

Lists every mod order at your shop, pending and in-progress, with refund/abandon options depending on the order's state and your role. Covered in full in the **Mod Orders** guide.

#### NPC Jobs

When there's nothing going on at the shop, NPC jobs give tuners paid work to take on solo. Two job types are available, each with their own shared cooldown so you can't chain them back-to-back endlessly.

**Salvage Car** sends you to a random scrapyard location with a junk car waiting. Every door, the hood, the trunk, and all four wheels can individually be broken off and salvaged — each one requires standing right at that specific part, not just being near the car. Salvaging rewards crafting materials, with a small chance at rare mod items too. Wander too far from the vehicle mid-job and it gets cancelled automatically.

**Mobile Tuning** sends you to a roadside customer who needs a specific cosmetic mod installed — the tablet tells you what type of part to bring (headlights, neon, a bumper, etc.) so you can craft or acquire it before heading out. On arrival, talk to the customer for a quick interaction, then find and use the correct item at the vehicle's install point to fit the part. Once installed, talk to the customer again to collect a cash payment straight to your personal wallet — no formal order or shop involvement needed.

Both jobs use random locations pulled from a shared pool, so two tuners will never be sent to the exact same spot at the same time.

#### Billing

Tuners can create itemized bills for customers directly from the tablet — the customer reviews and confirms before any money changes hands, keeping every transaction transparent and consensual.


# Troubleshoot

Your guide to quickly troubleshoot and resolve your issues

{% stepper %}
{% step %}

### Frequently Asked Questions

Verify that your issue is not already addressed in our [FAQ](/resources/t1ger-tuning/troubleshoot/faq).
{% endstep %}

{% step %}

### Reinstall

If your issue is not addressed in our [FAQ](/resources/t1ger-tuning/troubleshoot/faq) and you are still experiencing issues, please conduct a reinstall of the resource and follow our [Installation](/resources/t1ger-tuning/installation) guide properly.&#x20;
{% endstep %}

{% step %}

### Contact us

If you've tried steps 1 and 2 - and still encountering issues, please open a ticket on our official Discord.
{% endstep %}
{% endstepper %}


# FAQ

Frequently Asked Questions

{% hint style="success" %}

## Error: 150 “Foreign key constraint is incorrectly formed”

This is an error you are likely to see on if you only have t1ger\_tuning script and is trying to run the database query for t1ger\_tunershops.

1. Open `main.sql` located inside `t1ger_tuning/install`.&#x20;
2. Run this SQL in your database

```lua
-- ONLY RUN THIS IF YOU DO NOT HAVE t1ger_mechanic TABLE ALREADY!!
CREATE TABLE IF NOT EXISTS `t1ger_mechanic` (
    `id` INT(11) NOT NULL AUTO_INCREMENT,
    `name` VARCHAR(100) NOT NULL,
    `job` LONGTEXT NOT NULL DEFAULT ('[]'),
    `blip` LONGTEXT NOT NULL DEFAULT ('[]'),
    `owner` VARCHAR(100) DEFAULT NULL,
    `account` INT(11) NOT NULL DEFAULT 0,
    `employees` LONGTEXT NOT NULL DEFAULT ('[]'),
    `markers` LONGTEXT NOT NULL DEFAULT ('[]'),
    `billing` LONGTEXT NOT NULL DEFAULT ('[]'),
    `for_sale` TINYINT(1) NOT NULL DEFAULT 0,
    `sale_price` INT(11) DEFAULT NULL,
    `type` ENUM('mechanic', 'tuner', 'combined') NOT NULL DEFAULT 'mechanic',
    PRIMARY KEY (`id`)
);
```

3. Refresh the database
4. Then run this SQL in your database:

```sql
DROP TABLE IF EXISTS `t1ger_tunershops`;
CREATE TABLE `t1ger_tunershops` (
    `shop_id` INT(11) NOT NULL, -- FK to t1ger_mechanic.id
    `markup` INT(11) NOT NULL DEFAULT 0, -- % markup for upgrades
    `categories` LONGTEXT NOT NULL DEFAULT ('[]'), -- Available upgrade categories
    `delivery` LONGTEXT DEFAULT NULL, -- Delivery settings as JSON
    `is_combined` TINYINT(1) NOT NULL DEFAULT 0, -- 1 = combined with mechanic
    PRIMARY KEY (`shop_id`),
    FOREIGN KEY (`shop_id`) REFERENCES `t1ger_mechanic`(`id`) ON DELETE CASCADE
);
```

5. Restart your server and you'll be fine.
   {% endhint %}

{% hint style="success" %}

## Failed to insert job

This is an error you are likely to see on `es_extended` when creating shops/jobs in runtime. All you have to do is:

1. Open `createJob.lua` located inside `es_extended/server/modules`. If you do not have a `createJob.lua` file or modules folder, then open `functions.lua` inside `es_extended/server`.
2. Locate the function named: `ESX.CreateJob`.
3. Replace the entire function with the following code:

```lua
--- Create Job at Runtime
--- @param name string
--- @param label string
--- @param grades table
function ESX.CreateJob(name, label, grades)
  local currentResourceName = GetInvokingResource()
  local success = false

  if not name or name == '' then
      print("ERROR",currentResourceName, 'Missing argument `name`')
      return success
  end

  if not label or label == '' then
      print("ERROR",currentResourceName, 'Missing argument `label`')
      return success
  end

  if type(grades) ~= "table" or not next(grades) then
      print("ERROR",currentResourceName, 'Missing argument `grades`')
      return success
  end

  if ESX.DoesJobExist(name, 0) then
      print("ERROR",currentResourceName, 'Job already exists: `%s`', name)
      return success
  end

  local queries = {
      { query = 'INSERT INTO jobs (name, label) VALUES (?, ?)', values = { name, label } }
  }

  for _, grade in pairs(grades) do
      queries[#queries + 1] = {
          query = 'INSERT INTO job_grades (job_name, grade, name, label, salary, skin_male, skin_female) VALUES (?, ?, ?, ?, ?, ?, ?)',
          values = { name, grade.grade, grade.name, grade.label, grade.salary, type(grade.skin_male) == "table" and json.encode(grade.skin_male) or '{}', type(grade.skin_female) == "table" and json.encode(grade.skin_female) or '{}' }
      }
  end

  success = exports.oxmysql:transaction_async(queries)

  if not success then
      print("ERROR", currentResourceName, 'Failed to insert one or more grades for job: `%s`', name)
      return success
  end

  local job = { name = name, label = label, grades = {} }
  for _, v in pairs(grades) do
      job.grades[tostring(v.grade)] = { job_name = name, grade = v.grade, name = v.name, label = v.label, salary = v.salary, skin_male = v.skin_male or '{}', skin_female = v.skin_female or '{}' }
  end

  ESX.Jobs[name] = job

  print("SUCCESS", currentResourceName, 'Job created successfully: `%s`', name)

  TriggerEvent('esx:jobCreated', name, ESX.Jobs[name])

  return success
end
```

4. Restart your server
   {% endhint %}

***


# T1GER Chop Shop

The most immersive and realistic chop shop script for FiveM

<figure><img src="https://2167335559-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MiDWIMbFBeXle-trOlk%2Fuploads%2F36eS4iwsiUihKKlEmJk8%2Ft1ger_chopshop.png?alt=media&amp;token=e86197b5-a6a3-40fe-b5b0-692f2e807c9f" alt=""><figcaption></figcaption></figure>

This immersive chop shop script offers two distinct criminal paths: structured contracts that scale with your reputation, sending you on high-stakes vehicle retrieval missions — and an open-world system where players strip cars for parts, materials, and black market profit. With dynamic tool progression, reputation-based unlocks, detailed part interactions, and a player-driven bounty system, it delivers the ultimate vehicle crime experience for serious roleplay servers.

## Purchase

<https://t1ger.net/product/6879483>

## Showcase

{% embed url="<https://youtu.be/36Sx3XuB3zc?feature=shared>" %}

## Features

### Fixer NPC

The Fixer is the central hub for all chop shop features, including the chop list, black market, tool shop, bounties, contracts, and reputation tracking. This NPC is fully configurable with custom model, coordinates, scenario, map blip, and target icon. Players access all core systems through an immersive and intuitive menu tied to the Fixer.

### Chop List

A rotating list of target vehicles that refreshes at set intervals, defining which models can be chopped. Supports quotas per model, list size limits, and manual or automatic refresh. Players can view the list via command or through the Fixer NPC, with optional expiry timer display. Fully configurable vehicle pool and zone-restricted access ensure immersive gameplay balance.

### Chop Zones

Designated locations where players can dismantle vehicles from the chop list. Each zone is defined using custom box zones with adjustable size, rotation, and coordinates. Configurable map blips make zones easy to locate, and multiple zones can be placed across the map to encourage open-world activity. Only inside these zones can vehicles be stripped for parts and materials.

### Vehicle Dismantling

Players can freely dismantle vehicle parts in any order, including wheels, doors, hood, trunk, engine components, or scrap the frame entirely. Chopped body parts yield usable components, engine bay salvaging rewards select engine items, and frame scrapping provides raw materials like scrap metal and rubber. All actions require the correct tool, are performed within chop zones, and can include optional progress bars and skillchecks.

### Tool System

Tools are predefined and assigned to specific part types — socket and impact wrenches for wheels, cutting torches and angle grinders for doors, hoods, and trunks. Advanced tools chop faster but require more reputation to use. Each tool has configurable animation duration, progress bar, and skillcheck difficulty. Visual effects and sound are synced for each tool, adding realism and immersion to every action.

### Hardcore Chopping Mode

This optional system allows player-owned vehicles to be chopped — with the ability to permanently delete them from the database when the frame is scrapped. A built-in blacklist filters out restricted models and plates to prevent abuse. This high-risk, high-control feature is ideal for serious servers looking to push immersion and economy balance to the next level.

### Engine Bay Salvage

Players with enough reputation can salvage the engine bay to extract valuable components like alternators, radiators, and fuel injectors. This process uses a separate tool interaction, duration, and skillcheck, with item drops based on individual chance values. A great way to reward experienced players with rare mechanical parts.

### Frame Scrapping

Once a vehicle is stripped, players can scrap the frame at any time to collect raw materials such as scrap metal, steel, rubber, and copper. The process is time-based and does not require a tool, offering a final reward before the vehicle is deleted or despawned. Materials and their drop ranges are fully configurable.

### Vehicle Radar

A tool that scans the map for valid chop list vehicles and reveals their general locations as blip zones. The system clusters nearby vehicles to avoid spam and creates temporary blips with configurable radius, color, alpha, and duration. Ideal for players who want to quickly locate high-value targets without randomly searching the city.

### Vehicle Lockpicking

Built-in lockpicking allows players to break into locked vehicles using a skillcheck-based minigame. Servers can configure difficulty, control whether the lockpick item is consumed, and enable alarm triggers with randomized chance and duration. A default raycast targets nearby vehicles, and the system can be replaced with a custom minigame for deeper integration.

### Reputation System

Players earn reputation points by chopping vehicles and completing contracts, unlocking access to better tools, engine salvaging, and high-value missions. Reputation is fully configurable, with fictional rank titles, color-coded progress display, and admin commands for manual adjustments. This system rewards consistent activity and provides long-term progression for criminal careers. Reputation checks can also be disabled entirely for servers that prefer open access.

### Contract System

Structured missions offered by the Fixer that task players with retrieving specific vehicles for high rewards. Two contracts are included by default — each with unique requirements, reputation thresholds, and payout structures. Contracts support cooldowns, drop-off locations, and are fully expandable for future mission types.

* **Boosting Contracts** – Send players to steal specific vehicles from predefined locations and deliver them to a drop-off point for cash, materials, and reputation. Fully customizable with randomized rewards. No reputation required, making it ideal as an entry-level mission.
* **Repossession Contracts** – Higher-risk missions where players recover guarded vehicles from hostile NPCs. Random peds, weapons, and scenarios create unpredictable encounters. Requires higher reputation but offers greater rewards.

### Bounty System

Players can place bounties on specific vehicle models or license plates, creating open targets for others to locate, steal, and deliver. Bounties can be tracked through the Fixer, and drop-offs are handled at a secure warehouse. Ideal for repossession jobs, gang-related car thefts, or high-stakes vehicle hunts, the system adds a player-driven layer of economy and roleplay. Reward ranges, commission fees, and refund rules are fully configurable to fit your server’s balance.

### Tool Shop

Players can purchase tools directly from the Fixer, each with a unique function and reputation requirement. Basic tools like the socket wrench and lockpick are immediately accessible, while faster or specialized tools such as the angle grinder, spanner set, and vehicle radar unlock with higher reputation. Prices, descriptions, and point requirements are fully configurable, making the shop a natural extension of the player’s criminal progression.

### Black Market

The black market gives players two options: sell salvaged parts for quick cash or exchange them for valuable crafting materials. Each part has a defined price and conversion recipe, encouraging players to choose between profit and utility. Accessible through the Fixer, this system ties seamlessly into your server’s black market economy or crafting systems. All prices, materials, and exchange values are fully configurable.

### Statistics & Leaderboards

Players can view their personal progress through the Fixer, including total reputation, parts chopped, frames scrapped, and contracts completed. A built-in leaderboard ranks top players across multiple categories, such as points, parts, and bounties. All options are toggleable and fully configurable, making it easy to highlight player activity and reward dedication.


# Installation

This page covers the installation guide for T1GER Chop Shop

{% stepper %}
{% step %}

### Ensure Dependencies

{% hint style="warning" %}
Verify that you have the latest version of the listed mandatory resources installed and ensured in correct [start order](https://docs.t1ger.net/resources/t1ger-chop-shop/installation#start-order).
{% endhint %}

<table data-full-width="false"><thead><tr><th>Type</th><th width="462.60009765625">Resource(s)</th><th data-type="checkbox">Mandatory</th></tr></thead><tbody><tr><td>Database</td><td><a href="https://github.com/overextended/oxmysql/releases/latest">oxmysql</a></td><td>true</td></tr><tr><td>Library</td><td><a href="https://github.com/overextended/ox_lib/releases/latest">ox_lib</a></td><td>true</td></tr><tr><td>Framework</td><td><a href="https://github.com/esx-framework/esx_core/tree/main/%5Bcore%5D/es_extended">es_extended</a>, <a href="https://github.com/Qbox-project/qbx_core/releases/latest">qbx_core</a> or <a href="https://github.com/qbcore-framework/qb-core">qb-core</a></td><td>true</td></tr><tr><td>Target</td><td><a href="https://github.com/overextended/ox_target">ox_target</a> or <a href="https://github.com/qbcore-framework/qb-target">qb-target</a></td><td>true</td></tr><tr><td>Inventory</td><td><a href="https://github.com/overextended/ox_inventory">ox_inventory</a>, <a href="https://github.com/qbcore-framework/qb-inventory">qb-inventory</a>, qs-inventory, core_inventory, codem-inventory, origen_inventory or ak47_inventory</td><td>true</td></tr></tbody></table>
{% endstep %}

{% step %}

### Download

{% hint style="info" %}
Download the `t1ger_chopshop` asset from [Cfx.re Portal](https://portal.cfx.re/assets/granted-assets). Unzip the downloaded assets and drag it into a new(or existing) folder named `[t1ger]` inside your server's `resources` folder.
{% endhint %}
{% endstep %}

{% step %}

### Start Order

{% hint style="warning" %}
It's **very important** to ensure the resources in correct order to prevent any errors due to missing dependencies!
{% endhint %}

```lua
ensure oxmysql
ensure ox_lib
ensure es_extended -- or qbx_core / qb-core
ensure ox_target -- or qb-target
ensure ox_inventory -- or whatever compatible inventory
ensure [t1ger]
```

{% hint style="info" %}
*There can be resources ensure in between the listed resources - this **solely clarifies** the correct start order.*
{% endhint %}
{% endstep %}

{% step %}

### Run SQL

{% hint style="info" %}
Open the `t1ger_chopshop/install/main.sql` file and run the queries in your database.

Alternatively you can the import file directly into your database.
{% endhint %}
{% endstep %}

{% step %}

### Add Items

{% hint style="danger" %}
If you rename the items or wish to use your own items, make sure to update inside t1ger\_chopshop/shared/\*.lua files!
{% endhint %}

{% tabs %}
{% tab title="ox\_inventory" %}
Open `t1ger_chopshop/install/items/ox_inventory.lua` file and copy/paste into `ox_inventory/data/items.lua` file.
{% endtab %}

{% tab title="qb-inventory" %}
Open `t1ger_chopshop/install/items/qb-inventory.lua` file and copy/paste into `qb-core/shared/items.lua` file.
{% endtab %}

{% tab title="es\_extended" %}
Open `t1ger_chopshop/install/items/items.sql` file and run the query in your database. You can also import the file directly into your database.

If using `ox_inventory`, it will automatically pull items from your database. Otherwise, you can open the `t1ger_chopshop/install/items/ox_inventory.lua` file and copy/paste into `ox_inventory/data/items.lua` file.
{% endtab %}
{% endtabs %}

{% hint style="info" %}
Inventory icons are located in `t1ger_chopshop/install/items/icons/` folder.
{% endhint %}
{% endstep %}

{% step %}

### Configuration

{% hint style="info" %}
Configure the resource to your liking. Read the end-text comments carefully. If you do not understand, please refer to our documentation or contact us through the relevant support channels on .

Refer to [Configuration](/resources/t1ger-mechanic/configuration)
{% endhint %}
{% endstep %}

{% step %}

### Complete

{% hint style="success" %}
You have successfully installed our T1GER Chop Shop resource. Restart your server and enjoy!
{% endhint %}
{% endstep %}
{% endstepper %}


# Configuration

This page covers all configurable aspects of T1GER Chop Shop


# config

t1ger\_chopshop/shared/config.lua

All configurable options

```lua
Config = {}

Config.Debug = true

Config.Currency = "$" -- Currency used for pricing

Config.ServerSideProps = true -- Create objects/props on server or client?

Config.Items = require("shared/items") -- Loads items and data from shared/items.lua

Config.PoliceJobs = {"police", "lspd"} -- Define your police jobs in here

Config.PoliceAlert = { -- Police Alert
    Enable = true, -- enable/disable our built in police alert?
    Blip = { -- blip settings for police blip?
        enable = true, -- enable blip?
        duration = 20,
        radius = 50,
        alpha = 250,
        color = 3
    }
}

Config.FixerNPC = { -- The Fixer NPC
    Model = "s_m_m_autoshop_02", -- model of the fixer the npc
    Coords = vec4(-68.26, 191.96, 87.39, 170.07), -- coords for the npc
    Scenario = "WORLD_HUMAN_STAND_MOBILE", -- scenario to play
    Blip = {enable = true, name = "The Fixer", sprite = 792, display = 4, color = 81, scale = 0.8}, -- blip settings
    TargetIcon = "fa-solid fa-comment", -- icon shown when targetting the npc
}

Config.ChopZones = require("shared/chopzones") -- Loads chop zones from the shared/chopzones.lua file.

--- Chop List
Config.ChopList = {
    Enable = true, -- Set to false to disable chop list feature thus allowing to chop any vehicles in the chop zones

    Commands = { -- Command to view chop list vehicles
        view = {
            name = "choplist:view", -- Command name
            restrict = true, -- Set to false to be able to use command anywhere and not only in chop zones
        },
        refresh = {
            name = "choplist:refresh", -- Command name
            allowAdmins = true, -- Set to false to only allow refresh from server-console
        }
    },

    FixerMenu = {
        show = true, -- Show view chop list option in fixer menu?
        icon = "fa-list", -- Icon to show for chop list option in fixer menu
    },

    ShowExpiryTime = true, -- Show minutes left for current car list in menu?
    ExpiryMenuIcon = "clock", -- Menu icon for expiry timer

    RefreshInterval = 60, -- Minutes between list refresh

    MaxVehicles = 10, -- Number of vehicles in each list refresh
    ModelMenuIcon = "car", -- Icon for each vehicle model in the chop list menu

    ModelQuota = {
        enable = true, -- Enable per-model chop limits during each list cycle
        min = 2,       -- Minimum number of times each selected model can be chopped
        max = 5        -- Maximum number of times each selected model can be chopped
    },

    ModelPool = { -- List vehicle models in here to scramble in the chop list
        "sultan", "exemplar", "felon", "f620", "panto", "baller2", "baller", "buffalo", "manana", "emperor", "minivan", "fugitive", "intruder", "premier", "washington",
        "asterope", "fusilade", "penumbra", "prairie", "futo", "ingot", "stanier", "dilettante", "regina", "rhapsody", "granger", "rocoto", "landstalker", "seminole",
        "zion", "oracle", "tailgater", "glendale", "asea", "sentinel", "jackal", "cavalcade", "issi2"
    },
}

--- Chopping settings
Config.Chopping = {
    OwnedVehicles = false, -- Enable/disable chopping owned vehicles?
    DeleteOwnedVehicles = false, -- delete owned vehicle from database if frame scrapped? Only works if `Config.Chopping.OwnedVehicles` is enabled
    ChopListOnly = true, -- Only allow chopping vehicles from chop list? Or allow all vehicles?

    Blacklist = { -- Blacklist certain vehicles from being chopped?
        models = {"police3", "police4"}, -- Cannot chop these models. Add/remove models as you like
        plateMatch = {"JOB", "COP"}, -- Cannot chop vehicles with plate prefix starting with these
    },

    CancelCommand = {enable = true, name = "chop:cancel"}, -- Command to clear the tool prop and cancel anim

    TargetIcon = { -- Icons for target options
        start = "fa-solid fa-recycle", -- When u start the chopping session
        chop = "fa-solid fa-hammer", -- When u want to chop a given part
        scrap = "fa-solid fa-trash-can", -- When u want to scrap the vehicle frame
        salvage = "fa-solid fa-gears", -- When u want to salvage engine components
    },

    PointRewards = {
        door = 1, -- amount of points to add when door is chopped
        hood = 1, -- amount of points to add when hood is chopped
        trunk = 1, -- amount of points to add when trunk is chopped
        wheel = 1, -- amount of points to add when wheel is chopped
        engine_components = 1, -- amount of points to add when engine components are salvaged
        scrap = 5, -- amount of points to add when vehicle frame is scrapped
    },

    Tools = { -- tools used for chopping vehicles. Specify duration and enable/disable skillcheck and set difficulty
        socket_wrench = {
            requiredPoints = 0, -- required points to use item?
            duration = 6000, -- duration in MS for animation
            progressbar = true, -- enable / disable progress bar?
            skillcheck = {enable = true, difficulty = {"easy", "easy", "easy", "easy"}, inputs = {"w", "a", "s", "d"}}
        },
        impact_wrench = {
            requiredPoints = 500, -- required points to use item?
            duration = 3000, -- duration in MS for animation
            progressbar = true, -- enable / disable progress bar?
            skillcheck = {enable = true, difficulty = {"easy", "easy"},inputs = {"w", "a", "s", "d"}}
        },
        cutting_torch = {
            requiredPoints = 0, -- required points to use item?
            duration = 6000, -- duration in MS for animation
            progressbar = true, -- enable / disable progress bar?
            skillcheck = {enable = true, difficulty = {"easy", "easy", "easy", "easy"}, inputs = {"w", "a", "s", "d"}}
        },
        angle_grinder = {
            requiredPoints = 1500, -- required points to use item?
            duration = 3000, -- duration in MS for animation
            progressbar = true, -- enable / disable progress bar?
            skillcheck = {enable = true, difficulty = {"easy", "easy"}, inputs = {"w", "a", "s", "d"}}
        },
    },

    EngineBayComponents = {
        enable = true, -- allow to salvage engine bay for components?
        requiredPoints = 1000, -- required reputation points to salvage engine bay area?
        duration = 8000, -- duration in MS for animation
        progressbar = true, -- enable / disable progress bar?
        skillcheck = {enable = true, difficulty = {"easy", "easy", "easy", "easy"}, inputs = {"w", "a", "s", "d"}},
        items = { -- list of items that player has chance of receiving when done with engine salvaging
            {name = "t1ger_alternator", chance = 80},
            {name = "t1ger_radiator", chance = 100},
            {name = "t1ger_fuelinjector", chance = 50},
            {name = "t1ger_powersteeringpump", chance = 75},
            {name = "t1ger_transmission", chance = 40},
        }
    },

    ScrapFrame = {
        duration = 10000, -- duration in MS
        progressbar = true, -- enable/disable progressbar?
        reward = { -- When scrapping the frame, add items to receive. Use min = 0 to make it random to even receive that type of material
            {item = "scrap_metal", amount = {min = 2, max = 6}},
            {item = "steel", amount = {min = 1, max = 4}},
            {item = "aluminium", amount = {min = 0, max = 3}},
            {item = "plastic", amount = {min = 1, max = 2}},
            {item = "glass", amount = {min = 1, max = 2}},
            {item = "rubber", amount = {min = 0, max = 2}},
            {item = "electric_scrap", amount = {min = 0, max = 2}}, -- random chance
            {item = "copper", amount = {min = 0, max = 2}},
            -- add or remove lines/items
        }
    }
}

--- Vehicle Radar Tool
Config.VehicleRadar = {
    Enable = true, -- enable vehicle radar usage?
    Blip = { -- blip settings
        color = 76, -- blip color
        alpha = 120, -- blip alpha
        radius = 100.0, -- blip radius
        duration = 20, -- duration in seconds
    },
}

--- Vehicle Lockpicking
Config.VehicleLockpick = {
    Enable = true,  -- enable our built-in lockpicking?
    Skillcheck = {difficulty = {"easy", "easy", "easy", "easy", "easy"}, inputs = {"w", "a", "s", "d"}}, -- skillcheck settings (use custom minigame inside client/customize.lua)
    RemoveItem = true, -- remove lockpick item on usage?
    Alarm = {
        enable = true, -- enable vehicle alarm sound & effects upon lockpicking
        chance = 50, -- chance between 1-100 
        duration = 10000, -- alarm sound duration in MS
    },
}

--- Repuration system
Config.Reputation = {
    Enable = true, -- set to false to disable reputation system entirely
    MenuIcon = "fa-star", -- icon in the Fixer NPC menu
    AutosaveInterval = 5, -- auto save all reputation data for players every x minutes

    Commands = { -- commands to set, add and remove reputation points
        set = {enable = true, name = "reputation:set"}, -- enable for admins? False only useable by server-console
        add = {enable = true, name = "reputation:add"}, -- enable for admins? False only useable by server-console
        remove = {enable = true, name = "reputation:remove"}, -- enable for admins? False only useable by server-console
    },
    CommandSuggestion = "Usage: /%s <playerId> <amount>", -- command suggestion/helper. %s is automatically calling `set`, `add` or `remove`

    Levels = { -- the script ONLY checks for reputation points. All the rank/titles are fictional
        [0] = "Street Scav",
        [250] = "Tool Runner",
        [500] = "Parts Hustler",
        [800] = "Grease Monkey",
        [1200] = "Chop Apprentice",
        [1500] = "Engine Surgeon",
        [2000] = "Frame Butcher",
        [2500] = "Auto Dissector",
        [3000] = "Ghost Mechanic",
        [4000] = "Industrial Ripper",
        [5500] = "Machine Surgeon",
        [7000] = "Vehicle Anarchist",
        [9000] = "Urban Legend",
        [12000] = "Master Reclaimer",
        -- add or remove ranks as you like
    },

    ProgressColors = { -- Set up colors for progression in reputation menu option
        { threshold = 0, color = "#dc2626" },   -- Red
        { threshold = 20, color = "#f97316" },  -- Orange
        { threshold = 40, color = "#facc15" },  -- Yellow
        { threshold = 60, color = "#84cc16" },  -- Lime
        { threshold = 80, color = "#22c55e" },  -- Bright Green
        { threshold = 100, color = "#16a34a" }, -- Deep Green
    }   
}

--- Settings for statistics at the Fixer NPC
Config.Statistics = {
    Enable = true,
    MenuIcon = "fa-chart-simple",

    Options = {
        title = {enable = true, icon = "id-card"}, -- enable/disable option and set icon
        points = {enable = true, icon = "chart-line"}, -- enable/disable option and set icon
        parts = {enable = true, icon = "hammer"}, -- enable/disable option and set icon
        scraps = {enable = true, icon = "car-burst"}, -- enable/disable option and set icon
        contracts = {enable = true, icon = "file-contract"}, -- enable/disable option and set icon
        bounties = {enable = true, icon = "bullseye"}, -- enable/disable option and set icon
        leaderboards = {enable = true, icon = "ranking-star"} -- enable/disable option and set icon
    },

    Leaderboards = {
        topCount = 10, -- by default shows top 10. You can lower or raise to show more/less.
        options = {
            points = {enable = true, icon = "chart-line"}, -- enable/disable option and set icon
            parts = {enable = true, icon = "hammer"}, -- enable/disable option and set icon
            scraps = {enable = true, icon = "car-burst"}, -- enable/disable option and set icon
            contracts = {enable = true, icon = "file-contract"}, -- enable/disable option and set icon
            bounties = {enable = true, icon = "bullseye"} -- enable/disable option and set icon
        }
    }
}

--- Settings for the tool shop provided by the Fixer NPC
Config.ToolShop = {
    Enable = true, -- set to false to disable tools acquisiton in the fixer menu
    MenuIcon = "fa-tools", -- icon in the Fixer NPC menu
    MaxPurchaseQty = 20, -- max amount of an item to purchase at once
    BankPay = false, -- set to true to use bank money, otherwise uses cash/money in inventory/purse
    Items = require("shared/toolshop"), -- loads items in shop from shared/toolshop.lua
}

--- The fixer's black-market to sell salvaged parts or exchange them for materials
Config.BlackMarket = {
    Enable = true, -- set to false to disable black market (sell or exchange salvaged parts)
    MenuIcon = "fa-exchange-alt", -- icon in the Fixer NPC menu

    Sell = {
        enable = true, -- enable/disable sell system?
        menuIcon = "fa-coins", -- menu icon
        options = require("shared/bm_sell"), -- loads sell options from the shared/bm_sell.lua file.
    },

    Exchange = {
        enable = true, -- enable/disable exchange system?
        menuIcon = "fa-recycle", -- menu icon
        options = require("shared/bm_exchange") -- loads exchange options from the shared/bm_exchange.lua file.
    }
}

-- Structured missions provided by the Fixer NPC to source specific types of vehicles for higher rewards
Config.Contracts = {
    Enable = true, -- set to false to disable vehicle contracts
    MenuIcon = "file-contract", -- menu icon

    Cooldown = {enable = true, duration = 5}, -- enable/disable cooldown and set duration in minutes

    Dropoff = { -- vehicle dropoff location and settings
        coords = vector3(-71.81, 185.67, 87.42), 
        blip = {sprite = 162, scale = 0.7, color = 2, route = true, text = "Vehicle Dropoff"},
        marker = {type = 20, scale = {0.35, 0.35, 0.35}, rgba = {32, 173, 63, 100}},
        keybind = 38, -- keybind to dropoff vehicle
    },

    Boosting = { -- vehicle boosting contract
        enable = true, -- enable this contract?
        title = locale("menu_title.contracts_boosting"), -- menu title
        icon = "fa-car-side", -- menu icon
        description = locale("menu_description.contracts_boosting"), -- menu description
        requiredPoints = 0, -- required points to start contract
        data = require("shared/boosting") --
    },

    Repossession = { -- vehicle repossession contract
        enable = true, -- enable this contract?
        title = locale("menu_title.contracts_repossession"), -- menu title
        icon = "fa-handcuffs", -- menu icon
        description = locale("menu_description.contracts_repossession"), -- menu description
        requiredPoints = 2000, -- required points to start contract
        data = require("shared/repossession") --
    },
}

-- Place or claim bounties on specific vehicles by model or plate; deliver them to the fixer for rewards
Config.Bounty = {
    Enable = true, -- set to false to disable vehicle contracts
    MenuIcon = "fa-bullseye", -- menu icon

    Commission = 15, -- % fee deducted when bounty is completed or removed (if partial refund is enabled)
    AllowRemoval = true, -- Can players remove bounties after placing them?
    RefundOnRemoval = "partial", -- Options: "none" (gets nothing back), "full" (gets everything back), "partial" (gets bounty - commission back)

    Reward = {
        min = 2000, -- minimum reward
        max = 25000 -- maximum reward
    },

    ReputationReward = 50, -- add reputation points on delivery? Set to 0 to disable.

    Warehouse = { -- bounty vehicle delivery and retrieval
        coords = vector4(1087.68, -2289.63, 30.17, 266.45), -- coords
        blip = {enable = true, name = "Fixer Warehouse", sprite = 524, display = 4, color = 81, scale = 0.8}, -- blip settings
        marker = {type = 20, scale = {0.35, 0.35, 0.35}, rgba = {245, 175, 39, 100}}, -- marker settings
        keybind = 38, -- Default keybind [E]
    }
}

--- Define materials
Config.Materials = { -- index is item name and value is item label.
    scrap_metal = "Scrap Metal",
    steel = "Steel",
    aluminium = "Aluminium",
    plastic = "Plastic",
    rubber = "Rubber",
    electric_scrap = "Electric Scrap",
    glass = "Glass",
    copper = "Copper",
    carbon_fiber = "Carbon Fiber",
    brass = "Brass",
    synthetic_oil = "Synthetic Oil",
    acid = "Acid"
}
```


# items

t1ger\_chopshop/shared/items.lua

Types and list of items used throughout the script. Make sure to add items in here if you are adding custom items to toolshop or blackmarket. You can set prop to nil for custom items.

```lua
---@class ItemProp
---@field model string
---@field pos vector3
---@field rot vector3
---@field boneId number

---@class ScriptItem
---@field item string         -- The actual item name used in inventory
---@field label string        -- Display label
---@field icon string         -- Icon URL or asset
---@field prop ItemProp       -- Prop to attach when item is equipped/used

---@type table<string, ScriptItem>
return {
    -- salvageable parts
    door = {
        item = "t1ger_vehicledoor",
        label = "Vehicle Door",
        icon = "https://i.postimg.cc/m211T9R9/t1ger-vehicledoor.png",
        prop = {model = "imp_prop_impexp_car_door_04a", pos = vector3(-0.7, -0.2, 0.0), rot = vector3(0.0, -10.0, 90.0), boneId = 28422}
    },
    hood = {
        item = "t1ger_vehiclehood",
        label = "Vehicle Hood",
        icon = "https://i.postimg.cc/gJML2qnV/t1ger-vehiclehood.png",
        prop = {model = "imp_prop_impexp_bonnet_04a", pos = vector3(0.0, 0.20, 0.12), rot = vector3(-20.0, 0.0, 180.0), boneId = 28422}
    },
    trunk = {
        item = "t1ger_vehicletrunk",
        label = "Vehicle Trunk",
        icon = "https://i.postimg.cc/Jn7B8d47/t1ger-vehicletrunk.png",
        prop = {model = "imp_prop_impexp_trunk_01a", pos = vector3(0.0, 0.15, 0.1), rot = vector3(30.0, 0.0, 0.0), boneId = 28422}
    },
    wheel = {
        item = "t1ger_vehiclewheel",
        label = "Vehicle Wheel",
        icon = "https://i.postimg.cc/9Xnq3b3V/t1ger-vehiclewheel.png",
        prop = {model = "imp_prop_impexp_tyre_01c", pos = vector3(0.0, -0.1, 0.2), rot = vector3(0.0, 0.0, 0.0), boneId = 28422}
    },
    
    -- chopping tools
    socket_wrench = { -- Slow tool for loosening wheel bolts.
        item = "t1ger_socketwrench",
        label = "Socket Wrench",
        icon = "https://i.postimg.cc/3R6gHT6m/t1ger-socketwrench.png",
        prop = {model = "imp_prop_torque_wrench_01a", pos = vector3(0.08, -0.07, -0.07), rot = vector3(-55.0, 30.0, 0.0), boneId = 57005}
    },
    impact_wrench = {
        item = "t1ger_impactwrench",
        label = "Impact Wrench",
        icon = "https://i.postimg.cc/MKhLLmk5/t1ger-impactwrench.png",
        prop = {model = "imp_prop_impact_driver_01a", pos = vector3(0.12, -0.09, -0.09), rot = vector3(-90.0, 90.0, 40.0), boneId = 57005}
    },
    cutting_torch = {
        item = "t1ger_cuttingtorch",
        label = "Cutting Torch",
        icon = "https://i.postimg.cc/6pTWJKhH/t1ger-cuttingtorch.png",
        prop = {model = "prop_tool_blowtorch", pos = vector3(0.12, -0.12, -0.11), rot = vector3(-60.0, 0.0, 0.0), boneId = 57005}
    },
    angle_grinder = {
        item = "t1ger_anglegrinder",
        label = "Angle Grinder",
        icon = "https://i.postimg.cc/fRs6YnLw/t1ger-anglegrinder.png",
        prop = {model = "imp_prop_grinder_01a", pos = vector3(0.06, 0.10, -0.04), rot = vector3(140.0, 180.0, 0.0), boneId = 57005}
    },
    spanner_set = {
        item = "t1ger_spannerset",
        label = "Spanner Set",
        icon = "https://i.postimg.cc/2ynbWd9r/t1ger-spannerset.png"
    },
    -- other tools:
    lockpick = {
        item = "t1ger_lockpick",
        label = "Lockpick",
        icon = "https://i.postimg.cc/MGQzHYNV/t1ger-lockpickset.png",
        prop = {model = "", pos = vector3(0.0, 0.0, 0.0), rot = vector3(0.0, 0.0, 0.0), boneId = 28422}
    },
    vehicle_radar = {
        item = "t1ger_vehicleradar",
        label = "Vehicle Radar",
        icon = "https://i.postimg.cc/MpjL09wG/t1ger-vehicleradar.png",
        prop = {model = "", pos = vector3(0.0, 0.0, 0.0), rot = vector3(0.0, 0.0, 0.0), boneId = 28422}
    },
}
```


# toolshop

t1ger\_chopshop/shared/toolshop.lua

Types and list of items available in the toolshop menu.&#x20;

{% hint style="success" %}
You can add or remove items in here. Just define them inside `t1ger_chopshop/shared/items.lua` and follow the same setup as below.
{% endhint %}

```lua
---@class ToolShopItem
---@field name string
---@field label string
---@field icon string
---@field description string?
---@field price number
---@field requiredPoints number

---@type ToolShopItem[]
return {
    -- socket wrench:
    {
        name = Config.Items["socket_wrench"].item, -- item name
        label = Config.Items["socket_wrench"].label, -- item label
        icon = Config.Items["socket_wrench"].icon, -- item icon
        description = "Slow tool for loosening wheel bolts.", -- item/menu description. Set to nil to disable.
        price = 250, -- item price
        requiredPoints = 0, -- required reputation points?
    },
    -- impact wrench:
    {
        name = Config.Items["impact_wrench"].item,
        label = Config.Items["impact_wrench"].label,
        icon = Config.Items["impact_wrench"].icon,
        description = "Fast tool for loosening wheel bolts.",
        price = 950,
        requiredPoints = 500,
    },
    -- cutting torch:
    {
        name = Config.Items["cutting_torch"].item,
        label = Config.Items["cutting_torch"].label,
        icon = Config.Items["cutting_torch"].icon,
        description = "Burns slowly through bolts and hinges.",
        price = 1200,
        requiredPoints = 0,
    },
    -- angle grinder:
    {
        name = Config.Items["angle_grinder"].item,
        label = Config.Items["angle_grinder"].label,
        icon = Config.Items["angle_grinder"].icon,
        description = "Cuts through panels, bolts and hinges fast.",
        price = 2200,
        requiredPoints = 1500,
    },
    -- spanner set:
    {
        name = Config.Items["spanner_set"].item,
        label = Config.Items["spanner_set"].label,
        icon = Config.Items["spanner_set"].icon,
        description = "Used to salvage components from engine bay area.",
        price = 1600,
        requiredPoints = 2000,
    },
    -- vehicle radar:
    {
        name = Config.Items["vehicle_radar"].item,
        label = Config.Items["vehicle_radar"].label,
        icon = Config.Items["vehicle_radar"].icon,
        description = "Scans tracked vehicles on the chop list",
        price = 5000,
        requiredPoints = 3000,
    },
    -- lockpick:
    {
        name = Config.Items["lockpick"].item,
        label = Config.Items["lockpick"].label,
        icon = Config.Items["lockpick"].icon,
        description = "Unlocks vehicle doors.",
        price = 600,
        requiredPoints = 0,
    },
}
```


# chopzones

t1ger\_chopshop/shared/chopzones.lua

Types and settings for the chopzones. You can set up as many as you like around the map using ox\_lib box zones.

```lua
---@class ChopZoneBlip
---@field enable boolean
---@field name string
---@field sprite number
---@field display number
---@field color number
---@field scale number

---@class ChopZone
---@field coords vector3
---@field size vector3
---@field rotation number
---@field blip ChopZoneBlip

---@type ChopZone[]
return {
    {
        coords = vec3(2383.5, 3054.0, 48.0), -- box zone coords
        size = vec3(103.0, 54.0, 8.0), -- box zone size
        rotation = 0.0, -- box zone rotation
        blip = {enable = true, name = "Thomson Scrapyard", sprite = 867, display = 4, color = 35, scale = 0.8}, -- blip settings
    },
    {
        coords = vec3(-184.5, 6276.0, 31.0), -- box zone coords
        size = vec3(74.0, 54.0, 9.0), -- box zone size
        rotation = 315.0, -- box zone rotation
        blip = {enable = true, name = "Paleto Scrapyard", sprite = 867, display = 4, color = 35, scale = 0.8}, -- blip settings
    },
    {
        coords = vec3(-492.0, -1692.0, 19.0), -- box zone coords
        size = vec3(143.0, 95.0, 24.0), -- box zone size
        rotation = 340.0, -- box zone rotation
        blip = {enable = true, name = "La Puerta Scrapyard", sprite = 867, display = 4, color = 35, scale = 0.8}, -- blip settings
    },
    {
        coords = vec3(1527.25, -2120.0, 77.5), -- box zone coords
        size = vec3(71.0, 73.25, 9.0), -- box zone size
        rotation = 1.5, -- box zone rotation
        blip = {enable = true, name = "El Burro Heights Scrapyard", sprite = 867, display = 4, color = 35, scale = 0.8}, -- blip settings
    },
    -- add more
}
```


# bm\_exchange

t1ger\_chopshop/shared/bm\_exchange

Types and settings for the blackmarket exchange option

{% hint style="success" %}
You can add or remove items in here. Just define them inside `t1ger_chopshop/shared/items.lua` and follow the same setup as below.
{% endhint %}

```lua
---@class ExchangeMaterial
---@field item string
---@field amount number

---@class ExchangeGive
---@field item string
---@field icon string

---@class BlackmarketExchange
---@field give ExchangeGive
---@field receive ExchangeMaterial[]

---@type BlackmarketExchange[]
return {
    {
        give = {item = Config.Items["door"].item, icon = Config.Items["door"].icon}, -- item (name and icon) to give
        receive = { -- items (materials) to receive
            {item = "scrap_metal", amount = 3}, -- item name and amount
            {item = "steel", amount = 5}, -- item name and amount
            {item = "plastic", amount = 2}, -- item name and amount
            {item = "rubber", amount = 2} -- item name and amount
        }
    },
    {
        give = {item = Config.Items["hood"].item, icon = Config.Items["hood"].icon},
        receive = {
            {item = "scrap_metal", amount = 3},
            {item = "steel", amount = 6},
            {item = "aluminium", amount = 3},
            {item = "rubber", amount = 1}
        }
    },
    {
        give = {item = Config.Items["trunk"].item, icon = Config.Items["trunk"].icon},
        receive = {
            {item = "scrap_metal", amount = 4},
            {item = "steel", amount = 5},
            {item = "aluminium", amount = 2},
            {item = "plastic", amount = 2},
            {item = "rubber", amount = 1}
        }
    },
    {
        give = {item = Config.Items["wheel"].item, icon = Config.Items["wheel"].icon},
        receive = {
            {item = "scrap_metal", amount = 2},
            {item = "steel", amount = 4},
            {item = "rubber", amount = 5},
            {item = "carbon_fiber", amount = 2},
            {item = "brass", amount = 1}
        }
    },
}
```


# bm\_sell

t1ger\_chopshop/shared/bm\_sell.lua

Types and settings for the blackmarket sell option

{% hint style="success" %}
You can add or remove items in here. Just define them inside `t1ger_chopshop/shared/items.lua` and follow the same setup as below.
{% endhint %}

```lua
---@class BlackmarketSellOption
---@field name string
---@field icon string
---@field price number

---@type BlackmarketSellOption[]
return {
    {
        name = Config.Items["door"].item, -- item name
        icon = Config.Items["door"].icon, -- item icon
        price = 200 -- item sell price
    },
    {
        name = Config.Items["hood"].item,
        icon = Config.Items["hood"].icon,
        price = 200
    },
    {
        name = Config.Items["trunk"].item,
        icon = Config.Items["trunk"].icon,
        price = 200
    },
    {
        name = Config.Items["wheel"].item,
        icon = Config.Items["wheel"].icon,
        price = 200
    },
}
```


# boosting

t1ger\_chopshop/shared/boosting.lua

Types and mission/job settings for the boosting contract

```lua
---@class BoostingRewardItem
---@field item string
---@field amount { min: number, max: number }

---@class BoostingReward
---@field cash { min: number, max: number }
---@field items BoostingRewardItem[]
---@field reputationPoints number?

---@class BoostingLocation
---@field coords vector4

---@class BoostingData
---@field blip { sprite: number, scale: number, color: number, text: string }
---@field vehicles string[]
---@field reward BoostingReward
---@field locations BoostingLocation[]

---@type BoostingData
return {
    blip = {sprite = 326, scale = 0.7, color = 1, route = true, text = "Boosting Contract"},

    vehicles = {
        "sultan", "sentinel", "felon", "buffalo", "dominator", "zion", "tailgater", "premier", "fugitive", "intruder", "jackal", "gauntlet",
    },

    reward = {
        cash = {min = 100, max = 1000},
        items = {
            {item = "scrap_metal", amount = {min = 2, max = 6}},
            {item = "steel", amount = {min = 1, max = 4}},
            {item = "aluminium", amount = {min = 0, max = 3}},
            {item = "plastic", amount = {min = 1, max = 2}},
            {item = "glass", amount = {min = 1, max = 2}},
            {item = "rubber", amount = {min = 0, max = 2}},
            {item = "electric_scrap", amount = {min = 0, max = 2}}, -- random chance
            {item = "copper", amount = {min = 0, max = 2}},
        },
        reputationPoints = 5, -- reputation points? set to nil or 0 to disable
    },

    locations = {
        {coords = vector4(-310.11, -756.56, 53.24, 155.90)},
        {coords = vector4(-336.26, -976.79, 31.06, 337.32)},
        {coords = vector4(-412.65, 1231.89, 325.63, 235.27)},
        {coords = vector4(-1691.69, 54.92, 64.49, 158.74)},
        {coords = vector4(-1124.71, -1611.83, 4.39, 300.47)},
        {coords = vector4(-1353.99, -890.83, 13.86, 39.68)},
        {coords = vector4(-691.68, -744.71, 37.99, 0.0)},
        {coords = vector4(-740.08, -75.07, 41.73, 25.51)},
        {coords = vector4(-336.68, -1495.00, 30.61, 357.16)},
        {coords = vector4(54.03, -1417.72, 29.34, 42.51)},
        {coords = vector4(153.61, -1645.43, 29.27, 300.47)},
        {coords = vector4(368.38, -1116.26, 29.39, 0.0)},
        {coords = vector4(10.39, -620.33, 35.71, 68.03)},
        {coords = vector4(-924.73, -2643.67, 39.03, 56.69)},
        {coords = vector4(-503.53, -2168.22, 8.31, 226.77)},
        {coords = vector4(-680.08, -1403.89, 4.99, 82.20)},
        {coords = vector4(-645.07, -1170.52, 9.66, 39.68)},
        {coords = vector4(1182.10, -1554.55, 39.38, 172.91)},
        {coords = vector4(1130.07, -485.31, 65.60, 252.28)},
        {coords = vector4(1274.29, -357.37, 69.06, 110.55)},
        {coords = vector4(878.72, -37.63, 78.75, 238.11)},
        {coords = vector4(635.39, 161.56, 95.68, 249.44)},
        {coords = vector4(-2351.97, 291.27, 169.45, 291.96)},
        {coords = vector4(-3053.53, 128.96, 11.55, 266.45)},
        {coords = vector4(-3135.41, 1102.41, 20.61, 76.53)},
        {coords = vector4(1101.69, 2662.86, 37.95, 357.16)},
        {coords = vector4(2547.23, 2612.94, 37.94, 11.33)},
        {coords = vector4(2732.50, 1354.73, 24.51, 0.0)},
        {coords = vector4(2567.51, 327.32, 108.44, 357.16)},
        {coords = vector4(2575.70, -377.05, 92.98, 85.03)},
        {coords = vector4(22.18, -1071.38, 38.14, 68.03)},
    }
}
```


# repossession

t1ger\_chopshop/shared/repossession.lua

Types and mission/job settings for the repossession contract

```lua
---@class RepossessionRewardItem
---@field item string
---@field amount { min: number, max: number }

---@class RepossessionReward
---@field cash { min: number, max: number }
---@field items RepossessionRewardItem[]
---@field reputationPoints number?

---@class RepossessionLocation
---@field coords vector4
---@field ped vector4

---@class RepossessionData
---@field blip { sprite: number, scale: number, color: number, text: string }
---@field vehicles string[]
---@field peds string[]
---@field scenarios string[]
---@field weapons string[]
---@field reward RepossessionReward
---@field locations RepossessionLocation[]

---@type RepossessionData
return {
    blip = {sprite = 326, scale = 0.7, color = 1, route = true, text = "Repossession Contract"},

    vehicles = {
        "sultan", "sentinel", "felon", "buffalo", "dominator", "zion", "tailgater", "premier", "fugitive", "intruder", "jackal", "gauntlet",
    },

    peds = {
        "a_m_m_bevhills_02", "a_m_m_eastsa_01", "a_m_m_fatlatin_01", "a_m_m_indian_01", "a_m_m_malibu_01", "a_m_m_og_boss_01", "a_m_m_salton_03", "a_m_m_stlat_02"
    },

    scenarios = {
        "WORLD_HUMAN_SMOKING", "WORLD_HUMAN_STAND_MOBILE", "WORLD_HUMAN_STAND_IMPATIENT", "WORLD_HUMAN_MUSCLE_FLEX"
    },

    weapons = {
        "WEAPON_UNARMED", "WEAPON_BAT", "WEAPON_GOLFCLUB", "WEAPON_KNIFE", "WEAPON_SWITCHBLADE", "WEAPON_MACHETE", "WEAPON_PISTOL"
    },

    reward = {
        cash = {min = 500, max = 3000},
        items = {
            {item = "scrap_metal", amount = {min = 2, max = 6}},
            {item = "steel", amount = {min = 1, max = 4}},
            {item = "aluminium", amount = {min = 0, max = 3}},
            {item = "plastic", amount = {min = 1, max = 2}},
            {item = "glass", amount = {min = 1, max = 2}},
            {item = "rubber", amount = {min = 0, max = 2}},
            {item = "electric_scrap", amount = {min = 0, max = 2}}, -- random chance
            {item = "copper", amount = {min = 0, max = 2}},
        },
        reputationPoints = 10, -- reputation points? set to nil or 0 to disable
    },

    locations = {
        {coords = vector4(957.83, -551.69, 59.30, 209.76), ped = vector4(960.73, -550.41, 59.39, 206.92)},
        {coords = vector4(1261.52, -714.44, 64.51, 235.27), ped = vector4(1264.57, -712.61, 64.78, 144.56)},
        {coords = vector4(1373.01, -1521.99, 57.13, 204.09), ped = vector4(1377.95, -1520.09, 57.50, 121.88)},
        {coords = vector4(470.04, -1741.83, 28.94, 249.44), ped = vector4(475.01, -1740.47, 28.82, 153.07)},
        {coords = vector4(166.57, -1859.80, 24.15, 150.23), ped = vector4(168.22, -1864.41, 24.07, 68.03)},
        {coords = vector4(-954.09, -1083.70, 2.13, 209.76), ped = vector4(-951.70, -1079.94, 2.13, 175.74)},
        {coords = vector4(-1183.46, -934.32, 2.82, 209.76), ped = vector4(-1182.11, -930.88, 2.79, 127.55)},
        {coords = vector4(-1578.17, -86.23, 54.13, 274.96), ped = vector4(-1576.91, -89.59, 54.31, 357.16)},
        {coords = vector4(-1942.52, 385.34, 96.49, 90.70), ped = vector4(-1945.93, 387.95, 96.49, 198.42)},
        {coords = vector4(-1974.98, 623.67, 122.52, 246.61), ped = vector4(-1974.19, 627.38, 122.52, 198.42)},
        {coords = vector4(-1550.66, 427.13, 109.41, 274.96), ped = vector4(-1548.60, 424.00, 109.61, 348.66)},
        {coords = vector4(-1344.46, 611.74, 133.78, 102.04), ped = vector4(-1344.88, 606.52, 133.69, 31.18)},
        {coords = vector4(-1021.74, 811.62, 172.04, 204.09), ped = vector4(-1016.74, 811.85, 172.13, 127.55)},
        {coords = vector4(-341.43, 632.18, 172.35, 45.35), ped = vector4(-345.58, 631.68, 172.25, 39.68)},
        {coords = vector4(174.31, 482.92, 142.32, 354.33), ped = vector4(169.55, 483.96, 142.51, 289.13)}, 
    }
}
```


# Exports

In this section you'll find various exports & events to be used/integrated with other 3rd party resources.

{% content-ref url="/pages/z73t2VimK3AuBFyu9MZ1" %}
[Server](/resources/t1ger-chop-shop/exports/server)
{% endcontent-ref %}

{% content-ref url="/pages/kNufGD69C3QFwXSsOzft" %}
[Client](/resources/t1ger-chop-shop/exports/client)
{% endcontent-ref %}


# Server

Server-sided exports

## GetReputationData

Returns basic reputation stats as a plain table.

```lua
exports["t1ger_chopshop"]:GetPlayerReputation(src)
```

**Parameters**

* `src` *(number)* – The player's server ID.

**Returns**

* `table|nil` – A table with:
  * `points` *(integer)* – Reputation points
  * `parts` *(integer)* – Total parts chopped
  * `scraps` *(integer)* – Total full vehicles scrapped

***

## AddReputationPoints

Adds reputation points to a player and syncs it to their statebag.

```lua
exports["t1ger_chopshop"]:AddReputationPoints(src, amount)
```

**Parameters**

* `src` *(number)* – The player's server ID.
* `amount` *(number)* – The amount of XP to add.

**Returns**

* `boolean` – `true` if successful, `false` otherwise.

***

## RemoveReputationPoints

Removes reputation points from a player (min 0), and syncs to statebag.

```lua
exports["t1ger_chopshop"]:RemoveReputationPoints(src, amount)
```

**Parameters**

* `src` *(number)* – The player's server ID.
* `amount` *(number)* – The amount of XP to remove.

**Returns**

* `boolean` – `true` if successful, `false` otherwise.

***

## SetReputationPoints

Sets a player’s reputation points directly and syncs to statebag.

```lua
exports["t1ger_chopshop"]:SetReputationPoints(src, amount)
```

**Parameters**

* `src` *(number)* – The player's server ID.
* `amount` *(number)* – The amount of XP to remove.

**Returns**

* `boolean` – `true` if successful, `false` otherwise.

***

## GetChopList

Returns the current active Chop List entries.

```lua
exports["t1ger_chopshop"]:GetChopList()
```

**Returns**

* `ChopListEntry[]` – An array of chop list entries with model, hash, quota, and remaining fields.

***

## GetChopListRefreshTime

Returns the remaining time (in seconds) until the next Chop List refresh.

```lua
exports["t1ger_chopshop"]:GetChopListRefreshTime()
```

**Returns**

* `integer` – Seconds remaining until the next chop list update.

{% hint style="info" %}
💡 Divide by 60 and round down if you want minutes.
{% endhint %}

***

## RefreshChopList

Force-refreshes the Chop List immediately. Useful for admin tools, debugging, or manual triggers.

```lua
exports["t1ger_chopshop"]:RefreshChopList()
```

**Returns**

* `void`

***

## CreateBounty

Creates a bounty entry in the database and deducts the reward from the player's cash.\
Only valid, existing vehicles (if a plate is provided) and players with sufficient funds can place a bounty.

```lua
exports["t1ger_chopshop"]:CreateBounty(src, model, plate, reward)
```

**Parameters**

* `src` (`number`) – The server ID of the player placing the bounty.
* `model` (`string`) – The vehicle model name (e.g., `"sultan"`).
* `plate` (`string | nil`) – *(Optional)* Specific license plate to target. If `nil`, any vehicle of the model is valid.
* `reward` (`number`) – The cash reward the player is offering for the bounty.

**Returns**

* `boolean` – `true` if the bounty was created successfully, `false` if validation failed (e.g., invalid model, unowned plate, insufficient funds).

***

## RemoveBounty

Removes an active bounty from the database and optionally refunds the player based on configuration.\
Only valid, unclaimed bounties placed by the requesting player can be removed.

```lua
exports["t1ger_chopshop"]:RemoveBounty(src, bountyId)
```

#### Parameters

* `src` (`number`) – The server ID of the player attempting to remove the bounty.
* `bountyId` (`number`) – The database ID of the bounty to be removed.

#### Returns

* `boolean` – `true` if the bounty was removed successfully, `false` if validation failed (e.g., bounty not found, not owned by player, already completed).

{% hint style="info" %}
Refund amount depends on config:

* `Config.Bounty.RefundOnRemoval = "full"` → full reward refunded.
* `Config.Bounty.RefundOnRemoval = "partial"` → commission deducted (`Config.Bounty.Commission`%).
* `Config.Bounty.RefundOnRemoval = "none"` → no refund.

Only active bounties (`state = 0`) can be removed.
{% endhint %}

***


# Client

Client-sided exports

## IsLockpickingVehicle

Returns whether the player is currently lockpicking a vehicle or not.

```lua
exports["t1ger_chopshop"]:IsLockpickingVehicle()
```

**Returns**

* `boolean` – `true` if the player is currently lockpicking, `false` otherwise.

***

## GetPlayerReputationPoints

Returns the player's current reputation points.

```lua
exports["t1ger_chopshop"]:GetPlayerReputationPoints()
```

**Returns**

* `integer` – The player's reputation points (returns `0` if none are set).

***

## GetPlayerReputation

Returns the player's reputation points and corresponding level title.

```lua
exports["t1ger_chopshop"]:GetPlayerReputation()
```

**Returns**

* `table` – A table with:
  * `points` (`integer`) – The player's reputation points.
  * `level` (`string`) – The player's current level title based on their reputation.

***

## IsCarryingChoppingTool

Returns whether the player is currently carrying a chopping tool prop.

```lua
exports["t1ger_chopshop"]:IsCarryingChoppingTool()
```

**Returns**

* `boolean` – `true` if the player is carrying a chopping tool, `false` otherwise.

***

## HasActiveContract

Checks if the player currently has an active contract.

```lua
exports["t1ger_chopshop"]:HasActiveContract()
```

**Returns**

* `boolean` – `true` if a contract is currently active, `false` otherwise.

***

***

## StartBoostingContract

Starts a boosting contract for the player, performing necessary checks such as active contract status and cooldown, and retrieves contract data from the server.

```lua
exports["t1ger_chopshop"]:StartBoostingContract()
```

***

## StartRepossessionContract

Starts a repossession contract for the player, performing necessary checks such as active contract status and cooldown, and retrieves contract data from the server.

```lua
exports["t1ger_chopshop"]:StartRepossessionContract()
```

***


# Troubleshoot

Your guide to quickly troubleshoot and resolve your issues

{% stepper %}
{% step %}

### Frequently Asked Questions

Verify that your issue is not already addressed in our [FAQ](/resources/t1ger-chop-shop/troubleshoot/faq).
{% endstep %}

{% step %}

### Reinstall

If your issue is not addressed in our [FAQ](/resources/t1ger-chop-shop/troubleshoot/faq) and you are still experiencing issues, please conduct a reinstall of the resource and follow our [Installation](/resources/t1ger-chop-shop/installation) guide properly.&#x20;
{% endstep %}

{% step %}

### Contact us

If you've tried steps 1 and 2 - and still encountering issues, please open a ticket on our official Discord.
{% endstep %}
{% endstepper %}


# FAQ

Frequently Asked Questions

***

***

***


# T1GER Library

Documentation, troubleshooting and support for T1GER Library

## Note

This resource will be used in all T1GER resources as a dependency. The main purpose of the library is to add configurable support between frameworks, inventories, target systems and etc. for the gameplay resources. All options must be set in `config.lua`.

{% hint style="danger" %}
Do not edit/customize functions if you have no knowledge of LUA and FiveM Coding!
{% endhint %}

## Get Player/Owned Vehicles

This is a function to retrieve all owned vehicles for a player. This function will be used throughout T1GER resources. According to what columns you have in your owned\_vehicles or player\_vehicles table, you might need to update something inside the function.&#x20;

1. Navigate to `t1ger_lib/server/framework.lua`.
2. Find the function named: `GetAllVehicles`.
3. You should see a `table.insert()` function containing the keys and values below:

```lua
table.insert(vehicles, {
    plate = results[i].plate,
    props = results[i].vehicle or results[i].mods,
    type = results[i].type or nil,
    job = results[i].job or nil,
    stored = results[i].stored or results[i].state or nil,
    garage = results[i].garage or results[i].parking or nil,
    impound = results[i].impound or results[i].pound or nil,
    seized = results[i].seized or nil,
    model = results[i].model or nil,
    name = results[i].name or nil,
    category = results[i].category or nil,
    fuel = results[i].fuel or nil,
    engine = results[i].engine or nil,
    body = results[i].body or nil,
})
```

{% hint style="warning" %}
Do not alter the key name, as these key names are used throughout the resources and may break them!
{% endhint %}

4. You can alter the values starting with results\[i] if your table columns are named something else. Look below for examples.

**Example #1: garage column is named `t1ger_garage`.**

```lua
garage = results[i].t1ger_garage
```

**Example #2: stored column is named `parked`.**

```lua
stored = results[i].parked
```

## Update Owned Vehicle

This is a function to update owned vehicle, when the respective vehicle is either spawned or stored from/in a garage. According to what columns you have in your `owned_vehicles` or `player_vehicles` table, you might need to update something inside the function.&#x20;

1. Navigate to `t1ger_lib/server/framework.lua`.
2. Find the function named: `UpdateOwnedVehicle`.

   ```lua
   UpdateOwnedVehicle = function(src, stored, garage, props)
   -- stored (boolean) true/false
   -- garage (string)
   -- props (table)
   ```
3. Do not edit the `'@'` but only the value before the `"="`, as it's the exact column-name from your database table.&#x20;
4. Please read the end-line comments for brief information on the edits you are about to do.
5. Start with updating the SQL string to your server's preferences:
   * is it the correct table?&#x20;
   * is your stored state called: `'stored'`, `'state'`, `'parked'` or something else?
   * do you even have a `'garage'` or `'parked'` column, if not delete it from the SQL string. If you have it, then make sure to name it the same as your table column.&#x20;
   * are you using `'vehicle'`, `'mods'` or something else for vehicle properties? If so, update it!&#x20;
6. After updating the SQL, make sure to update the keys & values inside the MySQL call. Only do this if you've added/removed keys from the SQL string.&#x20;
7. That's it - you are now all set.&#x20;
   * Please note; if your database column for stored uses other value than boolean, then you need to re-code the true/false to return INT or whatever it may be.&#x20;

## Notifications

* You should see a `table.insert()` function containing the keys and values below:

Set the config option `UseFrameworkNotification` to either `true` or `false`. If true, the system will use default ESX or QB notifications. If false, by default it will use ox notifications. Inside utils, you can easily customize/change to your own notification system.

Throughout the gameplay resources, all notification messages will be sent as a table with title, message and type. Integration of your own notifcation system won't get any easier.&#x20;

If you want to parse more data through the notification, then you'd have to find the specific notification in the gameplay resource and add your extra values.

## Create Vehicle Meta

You can use this server sided export to create vehicle meta on spawned vehicles in run-time.

{% hint style="danger" %}
The vehicle must be added to the database as an owned vehicle, when using this. &#x20;
{% endhint %}

```lua
exports['t1ger_lib']:CreateVehicleMeta(plate, src)
```

Parameters:

* plate(string): the plate string of the vehicle to create metadata for.
* src(int): the player handle (player server id)

{% hint style="info" %}
**EXAMPLE #1**&#x20;

This example will make sure that when `/admincar` command is used in `qb-core`, the vehicle in question will have metadata created and synced.&#x20;

```lua
RegisterNetEvent('qb-admin:server:SaveCar', function(mods, vehicle, _, plate)
    local src = source
    if QBCore.Functions.HasPermission(src, 'admin') or IsPlayerAceAllowed(src, 'command') then
        local Player = QBCore.Functions.GetPlayer(src)
        local result = MySQL.query.await('SELECT plate FROM player_vehicles WHERE plate = ?', { plate })
        if result[1] == nil then
            MySQL.insert('INSERT INTO player_vehicles (license, citizenid, vehicle, hash, mods, plate, state) VALUES (?, ?, ?, ?, ?, ?, ?)', {
                Player.PlayerData.license,
                Player.PlayerData.citizenid,
                vehicle.model,
                vehicle.hash,
                json.encode(mods),
                plate,
                0
            })
            exports['t1ger_lib']:CreateVehicleMeta(plate, src)
            TriggerClientEvent('QBCore:Notify', src, Lang:t("success.success_vehicle_owner"), 'success', 5000)
        else
            TriggerClientEvent('QBCore:Notify', src, Lang:t("error.failed_vehicle_owner"), 'error', 3000)
        end
    else
        BanPlayer(src)
    end
end)
```

{% endhint %}

## Utils

Inside the utils.lua you'll find various functions. Feel free to use these in your resources as you please.


# Installation

Instruction and guide to install and setup t1ger\_lib dependency resource for all T1GER resources.

## 1. Ensure Dependencies

The very first step of the installation is to have the dependencies installed and make sure they are ensure before the `t1ger_lib` resource.&#x20;

{% hint style="info" %}
Make sure to download the latest .zip files and not the source-code!
{% endhint %}

### [**oxmysql**](https://github.com/overextended/oxmysql/releases)

*FiveM resource to communicate with a MySQL database using* [*node-mysql2*](https://github.com/sidorares/node-mysql2)*. (You might already be running this as it's becoming a very standard SQL wrapper to use).*

**Download:** <https://github.com/overextended/oxmysql/releases>

### [**ox\_lib**](https://github.com/overextended/ox_lib/releases)

*A FiveM library and resource implementing reusable modules, methods, and UI elements.*

**Download:** <https://github.com/overextended/ox_lib/releases>

## 2 - Get T1GER Library

* Get the `t1ger_lib` resource from: <https://store.t1ger.net/package/5579988> (FREE)&#x20;
* Download from: [FiveM's Keymaster](https://keymaster.fivem.net/login?return_url=/asset-grants).

## 3 - Ensure T1GER Library

Unzip `t1ger_lib.zip` folder and place it into your `resource` folder.

{% hint style="warning" %}
To avoid any startup issues, we highly recommend to place it inside the root resource folder and not in any sub-folder!
{% endhint %}

Add `ensure t1ger_lib` to your server start config.&#x20;

{% hint style="danger" %}
Make sure to ensure `t1ger_lib` after your framework (`es_extended`/`qb-core`), target (`ox_target`/`qb-target`) and inventory (`ox_inventory`/`qb-inventory`) resources!
{% endhint %}

<div align="left"><figure><img src="https://2167335559-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MiDWIMbFBeXle-trOlk%2Fuploads%2F5vJguEpzLyI3xhBQu79T%2Fimage.png?alt=media&amp;token=ba155e8c-6a54-44e9-ae60-d68e505133c1" alt=""><figcaption><p>Example of my server.cfg startup order</p></figcaption></figure></div>

## 4 - Configuration

The config options can be found inside `t1ger_lib/config.lua` and you must go through every option. Refer to [Configuration](/resources/t1ger-library/configuration) for in-depth explanations of the configurable options.

{% hint style="success" %}
Use the end-text comments which explains every option!
{% endhint %}

{% hint style="danger" %}
Important to configure [`Inventory`](/resources/t1ger-library/installation/inventory), `TargetSystem`, `Garage and` [`SocietyAccount`](/resources/t1ger-library/installation/society-account) options!
{% endhint %}

### 4.1 - Inventory

Please refer to [Inventory](/resources/t1ger-library/installation/inventory) on guide/instructions on how to setup inventory.&#x20;

### 4.2 - Society Account

Please refer to [Society Account](/resources/t1ger-library/installation/society-account) on guide/instructions on how to setup society account and integrate required functions.&#x20;

## 5 - Ready

Congratulations, you've successfully installed the `t1ger_lib` resource. Restart the server and you will be all set.&#x20;


# Inventory

Instruction and guide on how to setup your inventory for T1GER resources

## Introduction

T1GER Resources supports compatibility with popular custom inventories. We plan on adding "out-the-box" compatibility with more inventories as they are being proposed to us.&#x20;

{% hint style="success" %}
You can also use the 'custom' option and integrate your own exports/function for whatever custom inventory you may have.
{% endhint %}

### Config.Inventory

```lua
Config.Inventory = 'ox-inventory' -- Set the inventory system
```

Specifies the custom inventory system in use. Update this based on your selected inventory system.

* **Type**: `string`
* **Options**:
  * `'ox-inventory'` - [Ox Inventory](https://github.com/overextended/ox_inventory)
  * `'qb-inventory'` - [QB Inventory](https://docs.qbcore.org/qbcore-documentation/qbcore-resources/qb-inventory)
  * `'mf-inventory'` - ModFreakz Inventory (paid)
  * `'qs-inventory'` - Quasar Inventory (paid)
  * `'core-inventory'` - Core Inventory (paid)
  * `'codem-inventory'` - CodeM Inventory (paid)
  * `'custom'` - If none of these are being used or if you want to integrate your own!

## Setup

All you need to do is basically set your inventory system in `Config.Inventory` and you are all set.

{% hint style="danger" %}
If you are not using any of the preconfigured inventories, set the option to **`'custom'`**.

* Please note that you have to integrate exports/functions yourself! It's not our job to support for 3rd party paid inventory.
* We strongly recommend to reach out to your inventory creator to ask them to help you integrate their resource.&#x20;
* You can suggest compatibility on our discord and we might reach out to the creator of said inventory to possibly add preconfigured support.
  {% endhint %}

## Functions

These are the functions used in our T1GER resources.

{% hint style="info" %}
These are also the functions you want to modify in case you want to integrate your custom inventory resource. Simply use `'custom'` in `Config.Inventory` and integrate your export/functions in the if/else statements for `'custom'`.
{% endhint %}

### OpenStash

```
t1ger_lib/client/framework.lua
```

Used when player in-game opens a shared/stash inventory. Usually in my resources, owner is nil.

```lua
OpenStash(id, label, slots, weight, owner)
-- parameters: id(string), label(string), slots(int), weight(int), owner(string)
-- void: client-function to open the stash/inventory. Commonly used parameters are parsed as u can see.
```

### CreateStash

```
t1ger_lib/server/framework.lua
```

Used when creating a stash first time (example when creating a storage marker). Not all inventories require this function to be ran.

```lua
CreateStash(id, label, slots, weight, owner)
-- parameters: id(string), label(string), slots(int), weight(int), owner(string)
-- void: server-function to create/register stash first time when creating for example a marker.
```

### RegisterStash

```
t1ger_lib/server/framework.lua
```

Used when restarting resource or starting up server. Some inventories requires stashes/storages to be registered/created manually.&#x20;

```lua
RegisterStash(id, label, slots, weight, owner)
-- parameters: id(string), label(string), slots(int), weight(int), owner(string)
-- void: server-function to register stash on resource startup
```

### StashAddItem

```
t1ger_lib/server/framework.lua
```

Used when need to add an item directly into a stash/storage. The stash/storage identifier string is also parsed as an argument in this function.

```lua
StashAddItem(storageId, item, amount)
-- parameters: storageId(string), item(string), amount(int)
-- void: adds x amount of item into stash/storage with given id/identifier for the stash
```

## QB Inventory Not Opening

By default, t1ger\_lib will support latest qb-inventory. If you may for whatever reason, still be using the old qb-inventory, then follow these instructions:

#### `t1ger_lib/client/framework.lua`

Find the function called `OpenStash` and you should see the following code:

<figure><img src="https://2167335559-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MiDWIMbFBeXle-trOlk%2Fuploads%2FRkVQ1xhmaqSorJ1d1Z3W%2Fimage.png?alt=media&amp;token=25ed3601-fcc7-49d2-8e94-f458696d48a7" alt=""><figcaption></figcaption></figure>

Now, all u need to do is simply commenting out the TriggerServerEvent and enabling the other code that has already been commented out.&#x20;

You can also replace your whole OpenStash function with this snippet, where I have made the changes for you:&#x20;

```lua
    OpenStash = function(id, label, slots, weight, owner)
        if Config.Inventory == 'ox-inventory' then
            exports.ox_inventory:openInventory('stash', {id = id})
        elseif Config.Inventory == 'qb-inventory' then
            --TriggerServerEvent('t1ger_lib:server:openInventory', id, label, slots, weight, owner)
            TriggerServerEvent('inventory:server:OpenInventory', 'stash', id, {
                maxweight = weight,
                slots = slots
            })
            TriggerEvent('inventory:client:SetCurrentStash', id)
        elseif Config.Inventory == 'mf-inventory' then
            exports['mf-inventory']:openOtherInventory(id)
        elseif Config.Inventory == 'qs-inventory' then
            local other = {}
            other.maxweight = weight 
            other.slots = slots 
            TriggerServerEvent('inventory:server:OpenInventory', 'stash', 'Stash_'..id, other)
            TriggerEvent('inventory:client:SetCurrentStash', 'Stash_'..id)
        elseif Config.Inventory == 'core-inventory' then
            TriggerServerEvent('core_inventory:server:openInventory', 'stash-'..id:gsub('/',''):gsub(':',''):gsub('#',''), 'stash', nil, nil)
        elseif Config.Inventory == 'custom' then
            -- export/event to open stash/storage inventory
        end
    end,
```


# Target

Instruction and guide on how to setup 3rd-eye target for T1GER resources

## Introduction

T1GER Resources supports compatibility with popular 3rd-eye target systems. We plan on adding "out-the-box" compatibility with more target systems as they are being proposed to us.&#x20;

{% hint style="success" %}
You can also use the 'custom' option and integrate your own exports/function for whatever custom target you may have.
{% endhint %}

### Config.TargetSystem

```lua
Config.TargetSystem = 'ox-target' -- Set the target system
```

Specifies the target system in use. Update this based on your selected target system.

* **Type**: `string`
* **Options**:
  * `'ox-target'` - [Ox Target](https://github.com/overextended/ox_target) (free)
  * `'qb-target'` - [QB Target](https://github.com/qbcore-framework/qb-target) (free)
  * `'meta-target'` - [Meta Target](https://github.com/meta-hub/meta_target) (free)
  * `'custom'` - Custom | integrate your own functions/exports!

## Setup

All you need to do is basically set your target system in `Config.TargetSystem` and you are all set.

{% hint style="danger" %}
If you are not using any of the preconfigured target system, set the option to **`'custom'`**.

* Please note that you have to integrate exports/functions yourself! It's not our job to support for 3rd party target systems.
* We strongly recommend to reach out to your target creator to ask them to help you integrate their resource.&#x20;
* You can suggest compatibility on our discord and we might reach out to the creator of said target system to possibly add preconfigured support.
  {% endhint %}

## Functions

These are the functions used in our T1GER resources.

*...To Be Continued. W\.I.P.*


# Garage

Instruction and guide on how to setup garage for T1GER resources

## Introduction

T1GER Resources supports compatibility with popular garage systems. We plan on adding "out-the-box" compatibility with more garage systems as they are being proposed to us.&#x20;

{% hint style="success" %}
You can also use the 'custom' option and integrate your own exports/function for whatever custom garage you may have.
{% endhint %}

### Config.Garage

```lua
Config.Garage = 'default' -- Set the garage system
```

Specifies the garage system in use. Update this based on your selected garage system.

* **Type**: `string`
* **Options**:
  * `'default'` - Default ESX or QB garages
  * `'t1ger-garage'` - [T1GER Garage](https://youtu.be/7qgiFW0Qi2Q)
  * `'cd-garage'` - [Codesign Garage](https://docs.codesign.pro/paid-scripts/garage)
  * `'renzu-garage'` - [Renzu Garage](https://github.com/renzuzu/renzu_garage)
  * `'jg-advancedgarages'` - [JG Advanced Garages](https://docs.jgscripts.com/advanced-garages/)
  * `'rcore-garage'` - [rCore Garage](https://documentation.rcore.cz/paid-resources/rcore_garage)
  * `'okok-garage'` - [OkOk Garage](https://docs.okokscripts.io/scripts/okokgarage)
  * `'codeM-garage'` - [CodeM mGarage](https://codem.gitbook.io/codem-documentation/m-series/mgarage)
  * `'qs-advancedgarages'` - [Quasar Advanced Garages](https://docs.quasar-store.com/assets-and-guides/advanced-garages)
  * `'custom'` - Custom | integrate exports/functions yourself

## Setup

All you need to do is basically set your garage system in `Config.Garage` and you are all set.

{% hint style="danger" %}
If you are not using any of the preconfigured garage system, set the option to **`'custom'`**.

* Please note that you have to integrate exports/functions yourself! It's not our job to support for 3rd party garage systems.
* We strongly recommend to reach out to your garage creator to ask them to help you integrate their resource.&#x20;
* You can suggest compatibility on our discord and we might reach out to the creator of said garage system to possibly add preconfigured support.
  {% endhint %}

## Functions

These are the functions used in our T1GER resources.

*...To Be Continued. W\.I.P.*


# Society Account

Instruction and guide on how to setup your society account for T1GER resources

## Introduction

T1GER Resources supports compatibility with society accounts handled by `esx_addonaccount`, `qb-banking` or `qb-management`.

{% hint style="success" %}
You can also use a custom society-/shared account resource, however you need to implement the functionality yourself.
{% endhint %}

### Config.SocietyAccount

```lua
Config.SocietyAccount = 'esx_addonaccount' -- Set the society account system
```

Specifies the society account system in use. Update this based on your selected society system.

* **Type**: `string`
* **Options**:
  * `'esx_addonaccount'` - [ESX addon Account](https://github.com/esx-framework/esx_addonaccount)
  * `'qb-banking'` - [QB Banking](https://docs.qbcore.org/qbcore-documentation/qbcore-resources/qb-banking)
  * `'qb-management'` - [QB Management](https://docs.qbcore.org/qbcore-documentation/qbcore-resources/qb-management)
  * `'`renewed-banking`'` - [Renewed Banking](https://github.com/Renewed-Scripts/Renewed-Banking)
  * `'custom'` - You need to make your own integrations!

## Setup

This guide will help you setup society account functionality with T1GER Resources.

<details>

<summary>ESX</summary>

## `esx_addonaccount`

Setting up functionality to create shared account in runtime is very simple; all you need to is download and install latest `esx_addonaccount` from here: <https://github.com/esx-framework/esx_addonaccount>.&#x20;

*<mark style="color:red;">**Only do the following if you CANNOT download and install latest version and you are required/force to do the changes manually!!**</mark>*

If you prefer to keep your current `esx_addonaccount` resource for some weird reason, you can also manually implement the functionality.&#x20;

1. Navigate to `esx_addonaccount/server/main.lua`
2. Find this function:&#x20;

{% code fullWidth="false" %}

```lua
function GetSharedAccount(name)
```

{% endcode %}

3. Add this export code below the function

```lua
exports("GetSharedAccount", GetSharedAccount)
```

If done correct, it will look like this:\
![](https://2167335559-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MiDWIMbFBeXle-trOlk%2Fuploads%2FgbYL2Hl0vYm0Bf3GEFNI%2Fimage.png?alt=media\&token=e769b565-cc6e-4056-8c2d-3ab6ea88a1e5)

5. Now in the same file, find this function:

```lua
function AddSharedAccount(society, amount)
```

6. If the function exists, replace the whole function, if it doesn't exist, the insert - in both cases it's the same code:&#x20;

```lua
function AddSharedAccount(society, amount)
    -- society.name = job_name/society_name
    -- society.label = label for the job/account
    -- amount = if the shared account should start with x amount
    if type(society) ~= 'table' or not society?.name or not society?.label then return end

    -- check if account already exist?
    if SharedAccounts[society.name] ~= nil then return SharedAccounts[society.name] end

    -- addon account:
    local account = MySQL.insert.await('INSERT INTO `addon_account` (name, label, shared) VALUES (?, ?, ?)', {
        society.name, society.label, 1
    })
    if not account then return end

    -- if addon account inserted, insert addon account data:
    local account_data = MySQL.insert.await('INSERT INTO `addon_account_data` (account_name, money) VALUES (?, ?)', {
        society.name, (amount or 0)
    })
    if not account_data then return end
	
    -- if all data inserted successfully to sql:
    SharedAccounts[society.name] = CreateAddonAccount(society.name, nil, (amount or 0))
	return SharedAccounts[society.name]
end
exports("AddSharedAccount", AddSharedAccount)
```

6. You have succesfully set up `esx_addonaccount` to allow for automatic society account creation in runtime. All you need to do is restart the server!

</details>

<details>

<summary>QB Core</summary>

## `qb-banking`

Setting up functionality to create shared account in runtime is very simple; all you need to is download and install latest `qb-banking` from here: <https://github.com/qbcore-framework/qb-banking>.&#x20;

## `qb-management`

*<mark style="color:red;">**Only do the following if you are using**</mark><mark style="color:red;">**&#x20;**</mark><mark style="color:red;">**`qb-management`**</mark><mark style="color:red;">**:**</mark>*

1. Navigate to `qb-management/server/sv_boss.lua`
2. Scroll down all the way to the bottom and insert the following code:

```lua
-- ## T1GER Integrations:
function CreateManagementAccount(job_name, amount)
	local findRow = MySQL.query.await('SELECT * FROM management_funds WHERE type = @type AND job_name = @job_name', {
		['@job_name'] = job_name,
		['@type'] = 'boss'
	})
	if not findRow[1] then 
		MySQL.insert('INSERT INTO management_funds (job_name, amount, type) VALUES (@job_name, @amount, @type)', {
			['@job_name'] = job_name,
			['@amount'] = amount or 0,
			['@type'] = 'boss'
		})
		Accounts[job_name] = amount or 0
	end
end
exports("CreateManagementAccount", CreateManagementAccount)
```

3. Restart your server and you will now be able to create society accounts in runtime!

</details>

<details>

<summary>Qbox</summary>

## Renewed Banking

Setting up functionality to create shared account in runtime is very simple; all you need to is download and install latest `Renwed-Banking` from here: <https://github.com/Renewed-Scripts/Renewed-Banking/releases>.

1. Navigate to `Renewed-Banking/server/main.lua`
2. Go all the way to bottom of the file.
3. Paste the follow coding there: <br>

   ```lua
   local function CreateJobAccount(job, initialBalance)
       -- job(table): name(string), label(string) - job name and job label
       -- initialBalance(int): (optional) amount for account to start with
       if not job.name or not job.label then return end

       -- check if account already exist?
       if cachedAccounts[job.name] then return cachedAccounts[job.name] end

       cachedAccounts[job.name] = {
           id = job.name,
           type = locale('org'),
           name = job.label,
           frozen = 0,
           amount = initialBalance or 0,
           transactions = {},
           auth = {},
           creator = nil
       }

       MySQL.insert("INSERT INTO bank_accounts_new (id, amount, transactions, auth, isFrozen, creator) VALUES (?, ?, ?, ?, ?, NULL) ",{
           job.name, cachedAccounts[job.name].amount, json.encode(cachedAccounts[job.name].transactions), json.encode({}), cachedAccounts[job.name].frozen
       })

       return cachedAccounts[job.name]
   end
   exports('CreateJobAccount', CreateJobAccount)
   ```
4. You have succesfully set up qbox default banking resource to allow for automatic society account creation in runtime. All you need to do is restart the server!

</details>

## Functions

These are the functions used in our T1GER resources.

{% hint style="info" %}
These are also the functions you want to modify in case you want to integrate your custom society/shared account resource. Simply use `'custom'` in `Config.SocietyAccount` and integrate your export/functions in the if/else statements for `'custom'`.
{% endhint %}

### GetSharedAccount

```lua
GetSharedAccount(society)
-- parameters: society(string)
-- returns account(table or integer (based on resource return value))
```

### CreateSharedAccount

```lua
CreateSharedAccount(society, startBalance)
-- parameters: society(string), startBalance(integer)
-- returns account(table/integer)
```

### GetSharedAccountBalance

```lua
GetSharedAccountBalance(society)
-- parameters: society(string)
-- returns balance(integer)
```

### AddSharedAccountMoney

```lua
AddSharedAccountMoney(society, m)
-- parameters: society(string), m(integer)
-- void: adds m amount to shared account with society/job name
```

### RemoveSharedAccountMoney

```lua
RemoveSharedAccountMoney(society, m)
-- parameters: society(string), m(integer)
-- void: removes m amount from shared account with society/job name
```

### SetSharedAccountMoney

```lua
SetSharedAccountMoney(society, m)
-- parameters: society(string), m(integer)
-- void: sets m amount to shared account with society/job name
```


# Vehicle Properties

Instruction and guide on how to setup vehicle properties for T1GER resources

## Introduction

With the release of [T1GER Tuning System](/resources/t1ger-tuning-system), we needed to introduce our own `vehicleprops.lua` with get and set methods to fully ensure vehicle mods being applied and saved correctly.&#x20;

{% hint style="success" %}
You can easily add your 3rd-party custom edits from your current vehicle properties into our `vehicleprops.lua`.
{% endhint %}

## Setup

This guide will help you setup vehicle properties inside your framework functions.

{% hint style="info" %}
Please note. If you have 3rd-party resources that calls vehicle properties but not using ESX/QB framework functions, then you need to manually replace these with our exports.&#x20;
{% endhint %}

<details>

<summary>ESX</summary>

1. Navigate to `es_extended/client/functions.lua`
2. Find this function:

{% code fullWidth="false" %}

```lua
function ESX.Game.GetVehicleProperties(vehicle)
```

{% endcode %}

3. Take a backup of the whole function (in-case you have some custom edits, you want to transfer).
4. Replace the whole function with this code:

<pre class="language-lua"><code class="lang-lua"><strong>function ESX.Game.GetVehicleProperties(vehicle)
</strong>    return exports['t1ger_lib']:GetVehicleProperties(vehicle)
end
</code></pre>

5. Now find this function:

```lua
function ESX.Game.SetVehicleProperties(vehicle, props)
```

6. As we did in 3., take a backup of the whole function.&#x20;
7. Replace the whole function with this code:

<pre class="language-lua"><code class="lang-lua"><strong>function ESX.Game.SetVehicleProperties(vehicle, props)
</strong>    exports['t1ger_lib']:SetVehicleProperties(vehicle, props)
end
</code></pre>

8. If done correct, it should look like this (please ensure):\
   ![screenshot from es\_extened/client/functions.lua showing the updated changes.](https://2167335559-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MiDWIMbFBeXle-trOlk%2Fuploads%2F3qsldQ4XtiPFlpGo89KP%2Fimage.png?alt=media\&token=4a288139-ad52-4cc2-8e9e-9265205490b2)
9. Restart the server and you are all set!

</details>

<details>

<summary>QB Core</summary>

1. Navigate to `qb-core/client/functions.lua`
2. Find this function:

{% code fullWidth="false" %}

```lua
function QBCore.Functions.GetVehicleProperties(vehicle)
```

{% endcode %}

3. Take a backup of the whole function (in-case you have some custom edits, you want to transfer).
4. Replace the whole function with this code:

<pre class="language-lua"><code class="lang-lua"><strong>function QBCore.Functions.GetVehicleProperties(vehicle)
</strong>    return exports['t1ger_lib']:GetVehicleProperties(vehicle)
end
</code></pre>

5. Now find this function:

```lua
function QBCore.Functions.SetVehicleProperties(vehicle, props)
```

6. As we did in 3., take a backup of the whole function.&#x20;
7. Replace the whole function with this code:

<pre class="language-lua"><code class="lang-lua"><strong>function QBCore.Functions.SetVehicleProperties(vehicle, props)
</strong>    exports['t1ger_lib']:SetVehicleProperties(vehicle, props)
end
</code></pre>

8. If done correct, it should look like this (please ensure):\
   ![screenshot from qb-core/client/functions.lua showing the updated changes.](https://2167335559-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MiDWIMbFBeXle-trOlk%2Fuploads%2FwTPbPBsmB7Bin5rijoLH%2Fimage.png?alt=media\&token=e5cac4a4-8700-44a6-bb48-d0f84a4de77a)
9. Restart the server and you are all set!

</details>

## Functions

The `GetVehicleProperties()` and `SetVehicleProperties()` functions can be found and altered inside `t1ger_lib/vehicleprops.lua`

### GetVehicleProperties

```lua
exports['t1ger_lib']:GetVehicleProperties(vehicle)
-- returns the given vehicle's properties
```

**Parameters:**

* vehicle: entity(vehicle)

### SetVehicleProperties

```lua
exports['t1ger_lib']:SetVehicleProperties(vehicle, props)
-- sets the given vehicle's properties
```

**Parameters:**

* vehicle: entity(vehicle)
* props: table(props)


# Configuration

Instructions & guide on configuration t1ger\_lib

## Config.Debug

```lua
Config.Debug = true -- Enable or disable debug prints
```

* **Type**: `boolean`
* **Description**: Enables or disables debug prints.
* **Usage**: Set to `true` to enable debug prints. Set to `false` to disable them.

## Config.Triggers

```lua
-- Framework Triggers:
Config.Triggers = { -- Triggers to update if you've changed them or if your anticheat requires it:
	['ESX'] = { -- update your triggers/event-names here if changed:
		resource = 'es_extended', -- esx resource name
		obj = 'esx:getSharedObject',
		load = 'esx:playerLoaded',
		job = 'esx:setJob'
	},
	['QB'] = { -- update your triggers/event-names here if changed:
		resource = 'qb-core', -- qb-core resource name
		obj = 'QBCore:GetObject',
		load = 'QBCore:Client:OnPlayerLoaded',
		job = 'QBCore:Client:OnJobUpdate',
		uObjCL = 'QBCore:Client:UpdateObject',
		uObjSV = 'QBCore:Server:UpdateObject',
		dutyToggle = 'QBCore:ToggleDuty',
	},
} -- Do not delete anything from here!!!
```

Do not deleting anything from these options. Only change the trigger names if you are instructed so by your anticheat or if you have some kind of custom triggers.&#x20;

## Config.PoliceJobs

```lua
Config.PoliceJobs = {['police'], ['lspd']} -- Whitelisted police jobs
```

Defines the whitelisted police jobs used to fetch the online police count. Customize this list to match the job names used in your framework.

* **Type**: `table`
* **Default**: `{['police'], ['lspd']}`
* **Description**: Specifies the police jobs that are whitelisted for counting online police.
* **Usage**: Add or remove job names based on your framework's job definitions for police roles.

## Config.PoliceNotification

```lua
Config.PoliceNotification = 'default' -- Set the police notification method
```

Sets the method of police notifications for alerts.

* **Type**: `string`
* **Default**: `'default'`
* **Options**:
  * `'default'` - Built-in police alerts.
  * `'cd_'` - Use Codesign alerts.
  * `'custom'` - Use a custom notification system (requires implementation in `TriggerPoliceNotification` function in `t1ger_lib/utils.lua`).

## Config.AcePermissions

```lua
Config.AcePermissions = {'command'} -- Ace permissions for admin access
```

Specifies the Ace permissions used to check if a player has admin access or specific permissions.

* **Type**: `table`
* **Default**: `{'command'}`
* **Description**: Contains Ace permissions to provide admin access to commands. Modify to include additional permissions as required.
* **Usage**: Add permissions that should be checked for admin access or other command permissions.

## Config.UseFrameworkNotification

```lua
Config.UseFrameworkNotification = false -- Use framework notifications or custom
```

Determines whether to use the default framework (ESX/QB) notifications or a custom notification system.

* **Type**: `boolean`
* **Default**: `false`
* **Description**: Set to `true` to use the default ESX/QB notifications. Set to `false` to use a custom notification system defined in `Lib.Notification`.

## Config.VehicleKeys

```lua
Config.VehicleKeys = 'default' -- Set the vehicle keys handling method
```

Specifies the method for handling vehicle keys.

* **Type**: `string`
* **Default**: `'default'`
* **Options**:
  * `'default'` - Uses native checks for locked/unlocked status.
  * `'t1ger-keys'` - Uses `t1ger_keys` exports.
  * `'custom'` - Uses a custom vehicle keys system.

## Config.VehiclePrice

```lua
Config.VehiclePrice = 'database' -- Set the method for vehicle price retrieval
```

Defines the method for retrieving vehicle prices.

* **Type**: `string`
* **Default**: `'database'`
* **Options**:
  * `'database'` - Vehicle prices are stored in a database table.
  * `'lua'` - Vehicle prices are stored in a Lua file, such as `qb/shared/vehicles.lua`.
  * `'handling'` - Vehicle prices are stored in the vehicle's `handling.meta` file.
* **Usage**: Depending on your selection, you may need to update `server/framework.lua` and the `CreateCoreVehicles` function to align with your data storage method.

## Config.VehicleMeta

```lua
Config.VehicleMeta = {Props = { ['mileage'] = true, ['service'] = true, ['health'] = true }} -- Vehicle metadata properties
```

Defines vehicle metadata properties. This configuration should generally not be modified.

* **Type**: `table`
* **Default**: `{Props = { ['mileage'] = true, ['service'] = true, ['health'] = true }}`
* **Description**: Contains metadata properties for vehicles, such as mileage, service status, and health.
* **Usage**: Typically, this configuration should remain unchanged as it specifies essential vehicle properties.


# T1GER Gang System

Documentation, troubleshooting and support for T1GER Gang System resource

<figure><img src="https://2167335559-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MiDWIMbFBeXle-trOlk%2Fuploads%2F0aYxfVT7KpVE6lnWlcO1%2Fgang_system.png?alt=media&amp;token=1deee6b4-ea8b-4617-83fb-3b376042551e" alt=""><figcaption></figcaption></figure>

#### [**View on Tebex**](https://store.t1ger.net/package/5579989) | [**CFX Forum Post**](https://forum.cfx.re/t/esx-qb-t1ger-gang-system/5048130) | [**YouTube Showcase**](https://youtu.be/7Twa3zFsxMo) | [**Discord**](https://discord.gg/t1ger)

## Highlights

**Admin Gang Menu** - Create and manage gangs effortlessly in-game. Adjust notoriety and cash, change leadership, or disable/delete gangs as needed.

**Player Gang Menu** - Permission-based menu for members to access action menu or request jobs. Higher-ranked members can manage the gang, invite new members, manage markers and ranks.

**Markers** - Create and manage markers for garage, stash, and cash-locker, accessible with/without pin-code.

**Action Menu** - Perform various actions like zip-tying, escorting, place players in vehicle or trunk, use headbags and taking hostages, all with immersive animations.

**Notoriety System**: Reputation-based system influencing gang activities and interactions. Jobs and gang-related activities will impact the gang's notoriety.

**Rackets** - Claim and compete for control of profitable rackets, such as prostitution racket or protection racket, each with their own job or activity to keep gang-members engaged.

**Drug Sale** - Sell drugs to NPCs with configurable prices, sell chances, and bonus areas. Avoid police alerts to build gang notoriety and maximize profits.

**Customization** - Extensive configurable options in config file(s) and a language file to handle all translations.

**Performance** - Maximum optimization resulting in smooth performance with low resource usage, even on large servers.

**Sync** - Fully synced across all players using OneSync Infinity and statebags.

## Information

### Chat Commands

{% hint style="info" %}
Please note, all these command strings are configurable and can be disabled as well.
{% endhint %}

{% tabs %}
{% tab title="client" %}

<table><thead><tr><th width="186">Command</th><th>Description</th></tr></thead><tbody><tr><td><code>/admingang</code></td><td>Open the admin gang menu.</td></tr><tr><td><code>/gangmenu</code></td><td>Open the player gang menu.</td></tr><tr><td><code>/street</code></td><td>Prints street name at player coords (<code>Config.Debug = true</code>).</td></tr></tbody></table>
{% endtab %}
{% endtabs %}

### Exports

{% hint style="info" %}
These are available exports in the resource - use them as you please and find necessary.
{% endhint %}

{% tabs %}
{% tab title="client " %}

#### **Admin Gang Menu**

```lua
exports['t1ger_gangsystem']:AdminGangMenu()
```

Void:

* Opens the admin gang menu.

#### **Player Gang Menu**

```lua
exports['t1ger_gangsystem']:PlayerGangMenu()
```

Void:

* Opens the player gang menu.

#### Is Target Ziptied

```lua
exports['t1ger_gangsystem']:IsTargetZiptied(targetId)
```

Parameters:

* The target handle (target server id).

Returns:

* true/false (booleant)

Gets whether the target player is ziptied or not.
{% endtab %}

{% tab title="server" %}

#### Get Gang Data

```lua
exports['t1ger_gangsystem']:GetGangData(id)
```

Paramters:

* The gang handle (gang id).

Returns:

* id, name, notoriety, cash, leader, ranks, members, markers, disabled, rackets (table)

Gets gang data in a table from gang id.

#### Get Player Gang

```lua
exports['t1ger_gangsystem']:GetPlayerGang(playerSrc)
```

Paramters:

* The player handle (player server id).

Returns:

* id, name, notoriety, cash, leader, ranks, members, markers, disabled, rackets, player(array; name, identifier, rank, rankName) (table).

Gets the player's complete gang data in a table.

#### Get Player Gang Id

```lua
exports['t1ger_gangsystem']:GetPlayerGangId(playerSrc)
```

Paramters:

* The player handle (player server id).

Returns:

* gang id or 0 (int)

Gets the player's gang id or 0 if not a member of any gangs.

#### Get Player Gang Rank

```lua
exports['t1ger_gangsystem']:GetPlayerGangRank(playerSrc)
```

Paramters:

* The player handle (player server id).

Returns:

* rank id (int)
* rank name/label (string)

Gets the player's gang rank and rank name/label.&#x20;

#### Get Gang Notoriety

```lua
exports['t1ger_gangsystem']:GetGangNotoriety(id)
```

Paramters:

* The gang handle (gang id).

Returns:

* gang notoriety (int).

Gets the gang's notoriety points.

#### Plus Gang Notoriety

```lua
exports['t1ger_gangsystem']:PlusGangNotoriety(id, amount)
```

Paramters:

* The gang handle (gang id).
* Amount to plus (int).

Adds x amount of points to the current gang notoriety points.

#### Minus Gang Notoriety

```lua
exports['t1ger_gangsystem']:MinusGangNotoriety(id, amount)
```

Paramters:

* The gang handle (gang id).
* Amount to minus (int).

Deducts x amount of points from the current gang notoriety points.

#### **Is Player Zip Tied**

```lua
exports['t1ger_gangsystem']:IsPlayerZiptied(playerSrc)
```

Paramters:

* The player handle (player server id).

Returns:

* The player's zip tied state (boolean).

Gets whether the player is zip tied or not.

#### **Set Player Zip Tied**

```lua
exports['t1ger_gangsystem']:SetPlayerZiptied(playerSrc, bool)
```

Paramters:

* The player handle (player server id).
* set zip tied (true) or remove zip tied (false)

Sets the player's ziptied state. In case you want to stop a player's ziptied state from another resource.
{% endtab %}
{% endtabs %}

### Events

{% hint style="info" %}
These are optional events that you may need to use from other resources to add compatibility.
{% endhint %}

{% tabs %}
{% tab title="client to server" %}

#### Plus Notoriety Points

```lua
TriggerServerEvent('gangsystem:server:plusNotoriety', gangId, points)
```

Paramters:

* The gang handle (gang id) or `nil` (script will find gang id from the source player).
* points to add (int).

Adds x points to the gangs current notoriety points.

#### Minus Notoriety Points

```lua
TriggerServerEvent('gangsystem:server:minusNotoriety', gangId, points)
```

Paramters:

* The gang handle (gang id) or `nil` (script will find gang id from the source player).
* points to deduct (int).

Deducts x points from the gangs current notoriety points.

#### Plus Gang Cash

```lua
TriggerServerEvent('gangsystem:server:plusGangCash', gangId, cashAmount)
```

Paramters:

* The gang handle (gang id) or `nil` (script will find gang id from the source player).
* cash to add (int).

Adds x cash to the gangs cash locker.

#### Minus Gang Cash

```lua
TriggerServerEvent('gangsystem:server:minusGangCash', gangId, cashAmount)
```

Paramters:

* The gang handle (gang id) or `nil` (script will find gang id from the source player).
* cash to deduct (int).

Deducts x cash from the gangs cash locker.
{% endtab %}
{% endtabs %}

## Support

### Common Issues

Before we proceed, please ensure the following:

1. Resource folder of the package is named: `t1ger_gangsystem`.
2. You have not touched nor edited files inside `t1ger_gangsystem/escrow/`.
3. You have not made any custom changes.

{% hint style="success" %}
**TITLE**\
[❓](https://emojipedia.org/question-mark/)  Question/Issue

[✔️](https://emojiguide.com/symbols/check-mark/) Solution/Answer/Instruction
{% endhint %}

### Error Codes

If you getting an error code in your server- or client-console, then please find the error-code from below and fix your issue with the provided instructions.

{% tabs %}
{% tab title="Client" %}

{% endtab %}

{% tab title="Server" %} <mark style="color:red;">**#7983**</mark> - Inside `Config.DrugSale.Items` you've added/edited a key that does not have a reference to `Config.Items` that handles item names for these keys. Please add your key inside `Config.Items` and a respective item name for the key.
{% endtab %}
{% endtabs %}


# Installation

Resource installation guide and dependencies

### Framework

* [ESX](https://github.com/esx-framework/esx_core)
* [QBCore](https://github.com/qbcore-framework/qb-core)

### Dependencies

<table data-header-hidden><thead><tr><th width="221">Dependency</th><th width="150">Install</th><th width="333.1538461538462">Description</th></tr></thead><tbody><tr><td><strong>Resource</strong></td><td><strong>Install</strong></td><td><strong>Description</strong></td></tr><tr><td><a href="/resources/t1ger-library"><code>t1ger_lib</code></a></td><td>Required</td><td>Framework, inventory, target and etc.</td></tr><tr><td><a href="https://github.com/overextended/ox_lib"><code>ox_lib</code></a></td><td>Required</td><td>Context menu, notification etc.</td></tr></tbody></table>

### 1 - Start

{% hint style="info" %}

1. Download your resource from [FiveM's Keymaster](https://keymaster.fivem.net/asset-grants).
2. Unzip `t1ger_gangsystem.zip` folder and place it into your resource folder.
3. Add `ensure t1ger_gangsystem` to your server start config. Make sure to place anywhere below the framework and dependencies resources.
   {% endhint %}

### 2 - SQL

{% hint style="info" %}
Please open **`main.sql`** and execute the queries into your database or import the SQL file directly into your database.
{% endhint %}

### 3 - Items

{% hint style="danger" %}
Make sure to update `t1ger_gangsystem/config.lua` with the respective item names, so that the resource knows what items to use.&#x20;

You can quickly search for `requiredItem` inside the `config.lua` to find the item entries.

If you already have the items below or have similar items, you can skip the installation for items, just make sure to update `config.lua` with your item names.
{% endhint %}

#### ESX

1. Open your database and find the items table.
2. Run the following query to insert items into your table:

```sql
INSERT IGNORE INTO `items` (`name`, `label`) VALUES
('zipties', 'Zip Ties'), -- required item to zip tie target.
('headbag', 'Headbag'), -- required item to put headbag on target.
('cutter', 'Cutter'); -- useable item to cut zip-ties from target.
```

#### QB Core

1. Navigate to `qb-core/shared/items.lua` and open up the file.
2. Insert the following items into this file:

{% code title="Items for qb-core/shared/items.lua" %}

```lua
['zipties'] 				 = {['name'] = 'zipties', 			  	  	['label'] = 'Zip Ties', 			['weight'] = 1, 		['type'] = 'item', 		['image'] = 'zipties.png', 			['unique'] = false, 	['useable'] = false, 	['shouldClose'] = true,    ['combinable'] = nil,   ['description'] = 'Required for zip tie hands.'},
['headbag'] 				 = {['name'] = 'headbag', 			  	  	['label'] = 'Headbag', 			        ['weight'] = 1, 		['type'] = 'item', 		['image'] = 'headbag.png', 			['unique'] = false, 	['useable'] = false, 	['shouldClose'] = true,    ['combinable'] = nil,   ['description'] = 'Required to put headbag on a target player.'},
['cutter'] 				 = {['name'] = 'cutter', 			  	  	['label'] = 'Cutter', 			        ['weight'] = 1, 		['type'] = 'item', 		['image'] = 'cutter.png', 			['unique'] = false, 	['useable'] = true, 	['shouldClose'] = true,    ['combinable'] = nil,   ['description'] = 'Useable item to cut zip-ties from a target player.'},
```

{% endcode %}

### 4 - Configuration

{% hint style="info" %}
You must go through **all** configurable options & settings in `config.lua` and configure them to your server's preferences.

Also please read the comments at the end of each line, for a brief information on what the option does.&#x20;
{% endhint %}

### 5 - Ensure Dependencies

{% hint style="info" %}
The required dependencies for this resource can be seen in [#dependencies](#dependencies "mention").

* [x] T1GER Library: [documentation](/resources/t1ger-library)
* [x] OX Library: [documentation](https://overextended.github.io/docs/)&#x20;

Make sure to start/ensure these dependencies in your server start config before T1GER Gang System.&#x20;
{% endhint %}

### 6 - Ready

Congratulations, you've successfully installed the resource. Restart the server and you will be all set.


# Gang Garages

Instructions on using the built-in gang garages

The resource offers built-in garage system for gang-members to use or you can use your own garage system.

## Configuration

1. Navigate to `t1ger_gangsystem/config.lua`.
2. Find the table/option called `GangMarkers`.
3. Go through and set the config options to your preferences (read the end-line text comments).&#x20;
4. Set `useBuiltInGarage = true` if you want to use the built in system or set to `false` and use your own garage system.

## Built In Garage

{% hint style="danger" %}
If you do not have any experience with FiveM/LUA coding, please do not engage in this. Seek help from experienced developers.
{% endhint %}

The built-in-garage is a very basic garage system that allows:

* Getting all player owned vehicles and spawn the selected one.
* Store the current vehicle player is using.

### &#x20;Get Player Vehicles

You may find it necessary to customize the built-in garage to fetch vehicles based on a few criteria such as stored/parked state and so on.&#x20;

1. Navigate to `t1ger_gangsystem/client/main.lua`.
2. Find the event named:&#x20;

   ```lua
   'gangsystem:client:getPlayerVehicles'
   ```
3. These are the keys you can use ***(make sure you have updated t1ger-lib with correct values for those keys. See*** [T1GER Library](/resources/t1ger-library#player-owned-vehicles) ***for instructions)***:

   ```lua
   vehicle.plate -- plate of the vehicle
   vehicle.props -- vehicle properties
   vehicle.type -- vehicle type
   vehicle.job -- vehicle job
   vehicle.stored -- vehicle stored/state/parked state
   vehicle.garage -- garage of the vehicle
   vehicle.impound -- is vehicle in impound
   vehicle.sezied -- is vehicle seized?
   vehicle.model -- vehicle model
   vehicle.name -- vehicle name
   vehicle.category -- vehicle category
   vehicle.fuel -- fuel level of vehicle
   vehicle.egine -- engine level of vehicle
   vehicle.body -- body level of vehicle
   ```
4. Now inside the code for the event you can add checks. The checks have to be added as an if statement before the `table.insert()` function is called.
5. See my commented-out example inside the event (`data.marker.id` is a unique name created for each gang garage and you can use this for garage-specific systems).

   <figure><img src="https://2167335559-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MiDWIMbFBeXle-trOlk%2Fuploads%2F8Wg5jVxeMmURBDuLOfkI%2Fexample_spawn_vehicle_checks.png?alt=media&amp;token=dfcc5e84-76d6-4cb5-ba71-6c412e02ba9f" alt=""><figcaption><p>Checks for garage, stored, type and job is used in this example.</p></figcaption></figure>

### Update Owned Vehicle

You may find it necessary to customize the event for updating a specific owned vehicle when the respective vehicle is either spawned from a garage or stored in a garage.&#x20;

By default the resource uses a `TriggerServerEvent` to T1GER Library to update stored, garage and props when a vehicle is spawned/stored. If you havent updated the function to your server settings, please refer to: [T1GER Library](/resources/t1ger-library#update-owned-vehicle).

{% code title="The name of the TriggerServerEvent for updating owned vehicle:" %}

```lua
't1ger_lib:updateOwnedVehicle'
```

{% endcode %}

There are two entries of those in this resource. Navigate to: `t1ger_gangsystem/client/main.lua`.

The first looks like this:&#x20;

{% code title="Storing a vehicle into a gang garage:" %}

```lua
TriggerServerEvent('t1ger_lib:updateOwnedVehicle', true, marker.id, props)
-- true is the stored state, in this case vehicle is being stored into a garage.
-- marker.id (is the unique garage name of the gang).
-- props is the vehicle properties.
```

{% endcode %}

The second entry looks like this:&#x20;

{% code title="Spawning a vehicle from a gang garage:" %}

```lua
TriggerServerEvent('t1ger_lib:updateOwnedVehicle', false, nil, props)
-- false is the stored state, in this case vehicle is being såawned from the garage.
-- nil (garage), vehicle is no longer in any specific garage.
-- props is the vehicle properties.
```

{% endcode %}

You can change the `nil` value to `data.marker.id` if  you want to keep the garage of the vehicle when spawning it but logically it makes no sense. When vehicle is spawned the attached garage should be set to `nil`.

{% hint style="warning" %}
If your garage system / table column for stored/state/parked uses other value than a boolean, let's say an INT. Then update the true/false parameter in the TriggerServerEvent to an INT or whatever value it may be.&#x20;

Make sure to update the Lib.UpdateOwnedVehicle() function from T1GER Library accordingly, so it uses the parsed values instead of boolean. See [T1GER Library](/resources/t1ger-library#update-owned-vehicle) to find the function in T1GER Library.
{% endhint %}


# Product Information

T1GER Gang System

## INTRODUCTION

This comprehensive gang system enhances roleplay for those involved in gang-related activities. Players can build a notorious gang using a reputation system, take control of lucrative rackets to generate income, and defend their businesses from rival gangs. As a side-hustle, members can sell drugs, collect protection money, or work as chauffeurs for the prostitution racket. The Action Menu enables immersive interactions such as taking hostages, using zip ties, and escorting players.

## PREVIEW

{% embed url="<https://youtu.be/7Twa3zFsxMo>" %}

## DESCRIPTION

### Admin Gang Menu

This menu is accessible via command or keybind by server administrators. It provides comprehensive control over gang management, accessible via command or keybind.

Admins can create new gangs or manage existing ones with various options. They can adjust the gang’s notoriety points to influence its reputation, and manage the gang’s cash locker by adding or removing funds. To temporarily restrict a gang’s access without disbanding it, admins can disable the gang and re-enable it when needed. Additionally, they can change the gang’s leader or completely delete the gang if necessary.

This menu offers admins powerful tools to oversee and balance gang activities on the server.

### Player Gang Menu

This menu is accessible via command or keybind and is available exclusively to gang members and operates on a permission-based system determined by rank: rank-1 (leaders), rank-2 (underbosses), and rank-3 (shot-caller).

Gang members can view gang details, request job(s) from claimed rackets - or cancel an ongoing job. They can also access the action menu for immersive player interactions.

Members with rank-3, are able to view and remove members from the gang, while rank-1 and rank-2 can promote, demote and invite new members.

Setup default ranks in the config. The first 3 ranks have special permissions, while any additional ranks created are for roleplay purposes only and do not grant extra permissions. The rank-1 and rank-2 members can decide which ranks to utilize and customize the rank labels in-game to suit their gang's preferences.

Finally rank-1 or rank-2 members can manage the gang's markers.

### Markers

Each gang has 3 markers, respectively a stash for their items, a cash-locker for their money and a garage to store/retrive personal owned vehicles - this is not a shared garage!

Members with rank-1 or rank-2 permission can create and manage these markers with optional pin-code, ultimately allowing non-members access to the markers. The pin-code can be changed at any time and the marker can be moved, although with a configurable cooldown to prevent "power-gaming".

Each marker has a cost price of configurable amount of notoriety points, forcing gangs to build up their reputation before enjoing their perks.

### Action Menu

This menu allows gang members to interact with nearby players through a variety of immersive features.

* Secure a player’s hands with zip-ties using realistic animations. This action requires a zip-tie item in the inventory, which will be consumed upon use.
* Release a restrained player and receive the zip-tie item back into your inventory, restoring their mobility.
* Escort a zip-tied player with synchronized animations. The restrained player will follow your movements, walking or running based on your speed.
* Place or remove players from vehicles, provided the doors are open and the vehicle is unlocked. This allows for dynamic interactions involving transporting or removing players from cars.
* Place or remove players from the trunk of a vehicle. The trunk must be open and the vehicle unlocked for this action. Players inside the trunk will experience restricted vision, simulating a realistic scenario.
* Take players hostage at gunpoint, restricting their movements and actions. You can then choose to safely release the hostage, allowing them to regain control, or execute them, ending the situation with death. This option enables intense roleplay scenarios where hostages can be used as leverage.
* Place a headbag over the head of a zip-tied player, obscuring their vision entirely. The “headbagged” player will only see the inside of the bag, enhancing immersion with a visual prop and corresponding animation.

Each action requires a minimum configurable amount of notoriety points, so to access all actions, the gang must build up their reputation and become truly "notorious."

### Notoriety System

This is a key component of the Gang System, reflecting a gang’s reputation and influence within the server. Gangs earn notoriety points by completing jobs and activies from their claimed rackets or by sucessfully slinging drugs.

Notoriety points serve as both currency and reputation. They are consumed to claim rackets and create markers, while a certain amount is required to unlock full access to the different interactions in the action menu.

Conversely, gangs can lose notoriety by failing jobs experiencing botched drug deals where NPCs alert the police. This drop in reputation limits their capabilities and increases their vulnerability to rivals.

The system encourages strategic gameplay, as gangs must carefully balance their actions to maintain and grow their reputation. The system encourages strategic gameplay, as gangs must carefully balance their actions to maintain and grow their reputation. A high level of notoriety not only grants access to advanced features but also solidifies the gang’s dominance and standing in the criminal underworld.

### Rackets

Rackets are claimed or withdrawn by interacting with the notorious contract NPC. Once a gang claims a racket, it becomes exclusive to them, preventing other gangs from taking control until it is relinquished. This exclusivity fuels rivalry and competition as gangs vie for dominance. Claiming a racket requires notoriety points, making it a valuable resource for strategic gameplay.

* Protection racket allows a gang to collect protection money from designated shops - all locations are configurable. The shop generates money over configurable time and when the collection is ready, a member from said gang can collect it. However, this income is at risk, as other gang members or players can also attempt to collect the protection money, requiring the gang to defend their territory.
* Prostitution racket allow members to request job from their player gang menu, which involves picking up a hooker and safely driving her to the client’s location. The vehicle’s condition must be maintained within a configurable limit, or the job will fail, resulting in notoriety loss. Successfully completing the job, however, boosts the gang’s reputation

This is a different approach to engage in gang rivalries which will keep players on their toes.

### Drug Sale

Players can sell drugs to NPCs using the target system, with configurable base prices, success chances, and quantities for each drug. Operating within designated "hot-streets" grants a bonus to the unit sell price, and additional bonuses are applied when the required number of police are online.

However, failed drug sales may result in NPCs alerting the police, requiring players to intervene to prevent the alert. If the police are notified, the gang loses notoriety. Conversely, successful drug sales contribute to building the gang’s reputation and notoriety.

### Customization

The scripts has config file(s) with an extensive amount of configurable options, allowing extreme customization to make the system work with your roleplay server. A separate language file, containing all strings, makes it very easy for you to translate the system into your preferred language of choice. There's an icon folder with inventory icons for all included items.

### Performance

The script has been rigorously tested to ensure maximum optimization and smooth performance, even on large servers with high player counts. Its low resource usage minimizes server strain, providing a stable and seamless gameplay experience for all users. The focus on efficiency and reliability ensures that the script can handle peak activity without compromising functionality or player immersion, making it a robust choice for any server environment.

### Sync

The script is fully synchronized across all players, utilizing OneSync Infinity and statebags for seamless and reliable synchronization.

## DEPEDENCIES

### Required resources

* es\_extended / qb-core / qbox
* oxmysql / mysql
* t1ger\_lib (included)
* ox\_target / qb-target / meta-target
* ox\_inventory / qb-inventory / qs-inventory / mf-inventory / core-inventory


# T1GER Mechanic System

Documentation, troubleshooting and support for T1GER Gang System resource

<figure><img src="https://2167335559-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MiDWIMbFBeXle-trOlk%2Fuploads%2FARxsOnYKLKvbc4EKnVkR%2Fmech_system.png?alt=media&amp;token=fdfd3daf-96d7-43d0-a79f-ad12e0f89161" alt=""><figcaption></figcaption></figure>

#### [**View on Tebex**](https://store.t1ger.net/package/5719711) | [**CFX Forum Post**](https://forum.cfx.re/t/esx-qb-t1ger-mechanic-system/5123000) | [**YouTube Showcase**](https://youtu.be/yBlY2HB3wNA) | [**Discord**](https://discord.gg/t1ger)

## Information

### Chat Commands

{% hint style="info" %}
Please note, all these command strings are configurable and can be disabled as well.
{% endhint %}

{% tabs %}
{% tab title="client" %}

<table><thead><tr><th width="186">Command</th><th>Description</th></tr></thead><tbody><tr><td><code>/adminmech</code></td><td>Open the admin mechanic menu.</td></tr><tr><td><code>/mechmenu</code></td><td>Open the player mechanic menu.</td></tr><tr><td><code>/tow</code></td><td>Use near a flatbed to use built-in tow trucking feature</td></tr></tbody></table>
{% endtab %}
{% endtabs %}

### Exports

{% hint style="info" %}
These are available exports in the resource - use them as you please and find necessary.
{% endhint %}

{% tabs %}
{% tab title="client " %}

####

{% endtab %}

{% tab title="server" %}

#### Get Player Mech Id

```lua
exports['t1ger_mechanicsystem']:GetPlayerMechId(src)
```

Parameters:

* The player handle (player server id).

Returns:

* mechanic shop id of the player

Gets a player's mechanic shop id. Returns 0 if not hired in any mechanic shops.

#### Plus Mechanic Account

```lua
exports['t1ger_mechanicsystem']:PlusMechanicAccount(id, amount)
```

Paramters:

* The shop handle (shop id).
* Amount to plus (int).

Adds x amount of money to the current shop account balance.

#### Minus Mechanic Account

```lua
exports['t1ger_mechanicsystem']:MinusMechanicAccount(id, amount)
```

Paramters:

* The shop handle (shop id).
* Amount to minus (int).

Deducts x amount of money from the current shop account balance.

#### Get Player Mechanic Shop

```lua
exports['t1ger_mechanicsystem']:GetPlayerMechanicShop(jobName)
```

Parameters:

* The player job name (string).

Returns:

* mechanic shop (table)

Gets the player's shop data based on job name. If job does not match, it returns nil.
{% endtab %}
{% endtabs %}

### Events

{% hint style="info" %}
These are optional events that you may need to use from other resources to add compatibility.
{% endhint %}

{% tabs %}
{% tab title="client to server" %}

####

{% endtab %}
{% endtabs %}

## Support

### Common Issues

Before we proceed, please ensure the following:

1. Resource folder of the package is named: `t1ger_mechanicsystem`.
2. You have not touched nor edited files inside `t1ger_mechanicsystem/escrow/`.
3. You have not made any custom changes.

{% hint style="success" %}
**TITLE**\
[❓](https://emojipedia.org/question-mark/)  Question/Issue

[✔️](https://emojiguide.com/symbols/check-mark/) Solution/Answer/Instruction
{% endhint %}

### Error Codes

If you getting an error code in your server- or client-console, then please find the error-code from below and fix your issue with the provided instructions.

{% tabs %}
{% tab title="Client" %}

{% endtab %}

{% tab title="Server" %}

{% endtab %}
{% endtabs %}


# Installation

Resource installation guide and dependencies

### Framework

* [ESX](https://github.com/esx-framework/esx_core)
* [QBCore](https://github.com/qbcore-framework/qb-core)

### Dependencies

<table data-header-hidden><thead><tr><th width="221">Dependency</th><th width="150">Install</th><th width="333.1538461538462">Description</th></tr></thead><tbody><tr><td><strong>Resource</strong></td><td><strong>Install</strong></td><td><strong>Description</strong></td></tr><tr><td><a href="/resources/t1ger-library"><code>t1ger_lib</code></a></td><td>Required</td><td>Framework, inventory, target and etc.</td></tr><tr><td><a href="https://github.com/overextended/ox_lib"><code>ox_lib</code></a></td><td>Required</td><td>Context menu, notification etc.</td></tr><tr><td><code>t1ger_carlift</code></td><td>Required</td><td>For custom lifts to work</td></tr></tbody></table>

### 1 - Start

{% hint style="info" %}

1. Download T1GER Mechanic System and T1GER Car Lift from [FiveM's Keymaster](https://keymaster.fivem.net/asset-grants).
2. Unzip `t1ger_mechanicsystem.zip` folder and place it into your resource folder.
3. Unzip `t1ger_carlift.zip` folder and place it into your resource folder.
4. Add `ensure t1ger_mechanicsystem` and `t1ger_carlift` to your server start config. Make sure to place anywhere below the framework and dependencies resources.
   {% endhint %}

### 2 - SQL

{% hint style="info" %}
Please open **`main.sql`** and execute the queries into your database or import the SQL file directly into your database.
{% endhint %}

### 3 - Jobs (ESX Framework)

{% hint style="warning" %}
**SKIP IF USING QB-CORE FRAMEWORK**
{% endhint %}

Navigate to `es_extended/server/functions.lua` and paste the below function in the bottom of the file.

{% hint style="danger" %}
With recent updates in es\_extended, this function is already added, so please only insert the function if it doesn't exist in your file.&#x20;
{% endhint %}

```lua
--- Create Job at Runtime
--- @param name string
--- @param label string
--- @param grades table
function ESX.CreateJob(name, label, grades)
	if not name then
		return print('[^3WARNING^7] missing argument `name(string)` while creating a job')
	end

	if not label then
		return print('[^3WARNING^7] missing argument `label(string)` while creating a job')
	end

	if not grades or not next(grades) then
		return print('[^3WARNING^7] missing argument `grades(table)` while creating a job!')
	end

	local parameters = {}
	local job = { name = name, label = label, grades = {} }

	for _, v in pairs(grades) do
		job.grades[tostring(v.grade)] = { job_name = name, grade = v.grade, name = v.name, label = v.label, salary = v.salary, skin_male = v.skin_male or '{}', skin_female = v.skin_female or '{}' }
		parameters[#parameters + 1] = { name, v.grade, v.name, v.label, v.salary, v.skin_male or '{}', v.skin_female or '{}'}
	end

	MySQL.insert('INSERT IGNORE INTO jobs (name, label) VALUES (?, ?)', { name, label })
	MySQL.prepare('INSERT INTO job_grades (job_name, grade, name, label, salary, skin_male, skin_female) VALUES (?, ?, ?, ?, ?, ?, ?)', parameters)

	ESX.Jobs[name] = job
end
```

Make sure to add this function below `ESX.CreateJob` function, which will ensure your job is deleted when a mechanic shop is deleted.

```lua
function ESX.DeleteJob(name)
    --- @param name string
	if not name then
		return print('[^3WARNING^7] missing argument `name(string)` while deleting a job')
	end
	MySQL.update('DELETE FROM jobs WHERE name = ?', {name})
	MySQL.update('DELETE FROM job_grades WHERE job_name = ?', {name})
	ESX.Jobs[name] = nil
end
```

### 4 - Items

{% hint style="danger" %}
If you change item names or already have some items you want to use, make sure to update `t1ger_mechanicsystem/config.lua` with the respective item names, so that the resource knows what items to use.&#x20;

If you already have the items below or have similar items, you can skip the installation for items, just make sure to update `config.lua` with your item names.
{% endhint %}

#### ESX

1. Open your database and find the items table.
2. Run the following query to insert items into your table:

```sql
INSERT IGNORE INTO `items` (`name`, `label`) VALUES
-- Health Parts:
('radiator', 'Radiator'),
('fuel_pump', 'Fuel Pump'),
('brakes', 'Brakes'),
('drive_shaft', 'Drive Shaft'),
('alternator', 'Alternator'),
('clutch', 'Clutch'),
-- Service Parts:
('oil_filter', 'Oil + Filter'),
('air_filter', 'Air Filter'),
('fuel_filter', 'Fuel Filter'),
('coolant', 'Coolant'),
('brake_fluid', 'Brake Fluid'),
('steering_fluid', 'Power Steering Fluid'),
('transmission_fluid', 'Transmission Fluid'),
('spark_plugs', 'Spark Plugs'),
('drive_belt', 'Drive Belt'),
('flywheel', 'Flywheel'),
('tires', 'Tires'),
-- Body Repair Parts:
('part_door', 'Door'),
('part_hood', 'Hood'),
('part_trunk', 'Trunk'),
('part_window', 'Window'),
('part_wheel', 'Wheel'),
-- Kits:
('repairkit', 'Repair Kit'),
('repairkit_adv', 'Repair Kit Advanced'),
('patchkit', 'Patch Kit'),
('carjack', 'Car Jack'),
('fuel_can', 'Fuel Can'),
('jump_starter', 'Jump Starter'),
('tire_repairkit', 'Tire Repair Kit'),
-- Props:
('roadcone', 'Road Cone'),
('toolstrolley', 'Tools Trolley'),
('toolbox', 'Tool Box'),
('enginehoist', 'Engine Hoist'),
('consign', 'Con Sign'),
('roadbarrier', 'Road Barrier'),
-- Materials:
('scrap_metal', 'Scrap Metal'),
('steel', 'Steel'),
('aluminium', 'Aluminium'),
('plastic', 'Plastic'),
('rubber', 'Rubber'),
('electric_scrap', 'Electric Scrap'),
('glass', 'Glass'),
('copper', 'Copper'),
('carbon_fiber', 'Carbon Fiber'),
('brass', 'Brass'),
('synthetic_oil', 'Synthetic Oil'),
('acid', 'Synthetic Acid')
;
```

#### QB Core

1. Navigate to `qb-core/shared/items.lua` and open up the file.
2. Insert the following items into the file:

{% file src="/files/KgslQZAMwu4TrUw3dIqO" %}
You can also download the items.lua and copy paste directly from the file. ⚠️THIS IS NOT REPLACE!!!
{% endfile %}

{% code title="Items for qb-core/shared/items.lua" %}

```lua
-- Health Parts | T1GER Mechanic System
['radiator'] 			= {['name'] = 'radiator', 			['label'] = 'Radiator', 			['weight'] = 1,		['type'] = 'item',		['image'] = 'radiator.png', 			['unique'] = false,		['useable'] = true,		['shouldClose'] = true,		['combinable'] = nil,	['description'] = 'Health Part - Radiator'},
['fuel_pump'] 			= {['name'] = 'fuel_pump', 			['label'] = 'Fuel Pump', 			['weight'] = 1,		['type'] = 'item',		['image'] = 'fuel_pump.png', 			['unique'] = false,		['useable'] = true,		['shouldClose'] = true,		['combinable'] = nil,	['description'] = 'Health Part - Fuel Pump'},
['brakes'] 				= {['name'] = 'brakes', 			['label'] = 'Brakes', 				['weight'] = 1,		['type'] = 'item',		['image'] = 'brakes.png', 				['unique'] = false,		['useable'] = true,		['shouldClose'] = true,		['combinable'] = nil,	['description'] = 'Health Part - Brakes'},
['drive_shaft'] 		= {['name'] = 'drive_shaft',		['label'] = 'Drive Shaft',			['weight'] = 1,		['type'] = 'item',		['image'] = 'drive_shaft.png', 			['unique'] = false,		['useable'] = true,		['shouldClose'] = true,		['combinable'] = nil,	['description'] = 'Health Part - Drive Shaft'},
['alternator'] 			= {['name'] = 'alternator', 		['label'] = 'Alternator', 			['weight'] = 1,		['type'] = 'item',		['image'] = 'alternator.png', 			['unique'] = false,		['useable'] = true,		['shouldClose'] = true,		['combinable'] = nil,	['description'] = 'Health Part - Alternator'},
['clutch'] 				= {['name'] = 'clutch', 			['label'] = 'Clutch', 				['weight'] = 1,		['type'] = 'item',		['image'] = 'clutch.png', 				['unique'] = false,		['useable'] = true,		['shouldClose'] = true,		['combinable'] = nil,	['description'] = 'Health Part - Clutch'},

-- Service Parts | T1GER Mechanic System
['oil_filter'] 			= {['name'] = 'oil_filter', 		['label'] = 'Oil + Filter', 		['weight'] = 1,		['type'] = 'item',		['image'] = 'oil_filter.png', 			['unique'] = false,		['useable'] = true,		['shouldClose'] = true,		['combinable'] = nil,	['description'] = 'Service Part - Oil + Filter'},
['air_filter'] 			= {['name'] = 'air_filter', 		['label'] = 'Air Filter', 			['weight'] = 1,		['type'] = 'item',		['image'] = 'air_filter.png', 			['unique'] = false,		['useable'] = true,		['shouldClose'] = true,		['combinable'] = nil,	['description'] = 'Service Part - Air Filter'},
['fuel_filter']			= {['name'] = 'fuel_filter', 		['label'] = 'Fuel Filter', 			['weight'] = 1,		['type'] = 'item',		['image'] = 'fuel_filter.png', 			['unique'] = false,		['useable'] = true,		['shouldClose'] = true,		['combinable'] = nil,	['description'] = 'Service Part - Fuel Filter'},
['coolant']				= {['name'] = 'coolant',			['label'] = 'Coolant',				['weight'] = 1,		['type'] = 'item',		['image'] = 'coolant.png', 				['unique'] = false,		['useable'] = true,		['shouldClose'] = true,		['combinable'] = nil,	['description'] = 'Service Part - Coolant'},
['brake_fluid']			= {['name'] = 'brake_fluid',		['label'] = 'Brake Fluid', 			['weight'] = 1,		['type'] = 'item',		['image'] = 'brake_fluid.png', 			['unique'] = false,		['useable'] = true,		['shouldClose'] = true,		['combinable'] = nil,	['description'] = 'Service Part - Brake Fluid'},
['steering_fluid']		= {['name'] = 'steering_fluid',		['label'] = 'Power Steering Fluid',	['weight'] = 1,		['type'] = 'item',		['image'] = 'steering_fluid.png', 		['unique'] = false,		['useable'] = true,		['shouldClose'] = true,		['combinable'] = nil,	['description'] = 'Service Part - Power Steering Fluid'},
['transmission_fluid']	= {['name'] = 'transmission_fluid',	['label'] = 'Transmission Fluid', 	['weight'] = 1,		['type'] = 'item',		['image'] = 'transmission_fluid.png',	['unique'] = false,		['useable'] = true,		['shouldClose'] = true,		['combinable'] = nil,	['description'] = 'Service Part - Transmission Fluid'},
['spark_plugs']			= {['name'] = 'spark_plugs', 		['label'] = 'Spark Plugs', 			['weight'] = 1,		['type'] = 'item',		['image'] = 'spark_plugs.png',			['unique'] = false,		['useable'] = true,		['shouldClose'] = true,		['combinable'] = nil,	['description'] = 'Service Part - Spark Plugs'},
['drive_belt']			= {['name'] = 'drive_belt',			['label'] = 'Drive Belt',			['weight'] = 1,		['type'] = 'item',		['image'] = 'drive_belt.png', 			['unique'] = false,		['useable'] = true,		['shouldClose'] = true,		['combinable'] = nil,	['description'] = 'Service Part - Drive Belt'},
['flywheel']			= {['name'] = 'flywheel', 			['label'] = 'Flywheel', 			['weight'] = 1,		['type'] = 'item',		['image'] = 'flywheel.png', 			['unique'] = false,		['useable'] = true,		['shouldClose'] = true,		['combinable'] = nil,	['description'] = 'Service Part - Flywheel'},
['tires']				= {['name'] = 'tires', 				['label'] = 'Tires', 				['weight'] = 1,		['type'] = 'item',		['image'] = 'tires.png', 				['unique'] = false,		['useable'] = true,		['shouldClose'] = true,		['combinable'] = nil,	['description'] = 'Service Part - Tires'},

-- Body Parts | T1GER Mechanic System
['part_door']			= {['name'] = 'part_door', 			['label'] = 'Door Part', 			['weight'] = 1,		['type'] = 'item',		['image'] = 'part_door.png', 			['unique'] = false,		['useable'] = true,		['shouldClose'] = true,		['combinable'] = nil,	['description'] = 'Body Part - Door'},
['part_hood']			= {['name'] = 'part_hood', 			['label'] = 'Hood Part', 			['weight'] = 1,		['type'] = 'item',		['image'] = 'part_hood.png', 			['unique'] = false,		['useable'] = true,		['shouldClose'] = true,		['combinable'] = nil,	['description'] = 'Body Part - Hood'},
['part_trunk']			= {['name'] = 'part_trunk', 		['label'] = 'Trunk Part', 			['weight'] = 1,		['type'] = 'item',		['image'] = 'part_trunk.png', 			['unique'] = false,		['useable'] = true,		['shouldClose'] = true,		['combinable'] = nil,	['description'] = 'Body Part - Trunk'},
['part_window']			= {['name'] = 'part_window',		['label'] = 'Window Part', 			['weight'] = 1,		['type'] = 'item',		['image'] = 'part_window.png', 			['unique'] = false,		['useable'] = true,		['shouldClose'] = true,		['combinable'] = nil,	['description'] = 'Body Part - Window'},
['part_wheel']			= {['name'] = 'part_wheel', 		['label'] = 'Wheel Part', 			['weight'] = 1,		['type'] = 'item',		['image'] = 'part_wheel.png', 			['unique'] = false,		['useable'] = true,		['shouldClose'] = true,		['combinable'] = nil,	['description'] = 'Body Part - Wheel'},

-- Kits | T1GER Mechanic System
['repairkit']			= {['name'] = 'repairkit', 			['label'] = 'Repair Kit', 			['weight'] = 1,		['type'] = 'item',		['image'] = 'repairkit.png', 			['unique'] = false,		['useable'] = true,		['shouldClose'] = true,		['combinable'] = nil,	['description'] = 'Repair Kit'},
['repairkit_adv']		= {['name'] = 'repairkit_adv', 		['label'] = 'Repair Kit Advanced',	['weight'] = 1,		['type'] = 'item',		['image'] = 'repairkit_adv.png', 		['unique'] = false,		['useable'] = true,		['shouldClose'] = true,		['combinable'] = nil,	['description'] = 'Repair Kit Advanced'},
['patchkit']			= {['name'] = 'patchkit', 			['label'] = 'Patch Kit', 			['weight'] = 1,		['type'] = 'item',		['image'] = 'patchkit.png', 			['unique'] = false,		['useable'] = true,		['shouldClose'] = true,		['combinable'] = nil,	['description'] = 'Patch Kit for health/service parts'},
['carjack']			= {['name'] = 'carjack', 			['label'] = 'Car Jack', 			['weight'] = 1,		['type'] = 'item',		['image'] = 'carjack.png', 				['unique'] = false,		['useable'] = true,	['shouldClose'] = true,		['combinable'] = nil,	['description'] = 'Car Jack'},
['fuel_can']			= {['name'] = 'fuel_can', 			['label'] = 'Fuel Can', 			['weight'] = 1,		['type'] = 'item',		['image'] = 'fuel_can.png', 			['unique'] = false,		['useable'] = false,	['shouldClose'] = true,		['combinable'] = nil,	['description'] = 'Fuel Can with fuel'},
['jump_starter']		= {['name'] = 'jump_starter', 		['label'] = 'Jump Starter', 		['weight'] = 1,		['type'] = 'item',		['image'] = 'jump_starter.png', 		['unique'] = false,		['useable'] = false,	['shouldClose'] = true,		['combinable'] = nil,	['description'] = 'Jump Starter for vehicle battery'},
['tire_repairkit']		= {['name'] = 'tire_repairkit', 	['label'] = 'Tire Repair Kit', 		['weight'] = 1,		['type'] = 'item',		['image'] = 'tire_repairkit.png', 		['unique'] = false,		['useable'] = false,	['shouldClose'] = true,		['combinable'] = nil,	['description'] = 'Tire Repair Kit for bursted tires'},

-- Prop Emotes | T1GER Mechanic System
['roadcone']			= {['name'] = 'roadcone', 			['label'] = 'RoadCone', 			['weight'] = 1,		['type'] = 'item',		['image'] = 'roadcone.png', 			['unique'] = false,		['useable'] = true,		['shouldClose'] = true,		['combinable'] = nil,	['description'] = 'Spawn a road cone prop'},
['toolstrolley']		= {['name'] = 'toolstrolley', 		['label'] = 'Tools Trolley', 		['weight'] = 1,		['type'] = 'item',		['image'] = 'toolstrolley.png', 		['unique'] = false,		['useable'] = true,		['shouldClose'] = true,		['combinable'] = nil,	['description'] = 'Spawn a tools trolley prop'},
['toolbox']				= {['name'] = 'toolbox', 			['label'] = 'Tool Box', 			['weight'] = 1,		['type'] = 'item',		['image'] = 'toolbox.png', 				['unique'] = false,		['useable'] = true,		['shouldClose'] = true,		['combinable'] = nil,	['description'] = 'Spawn a toolbox prop'},
['enginehoist']			= {['name'] = 'enginehoist', 		['label'] = 'Engine Hoist', 		['weight'] = 1,		['type'] = 'item',		['image'] = 'enginehoist.png', 			['unique'] = false,		['useable'] = true,		['shouldClose'] = true,		['combinable'] = nil,	['description'] = 'Spawn an engine hoist prop'},
['consign']				= {['name'] = 'consign', 			['label'] = 'Consign', 				['weight'] = 1,		['type'] = 'item',		['image'] = 'consign.png', 				['unique'] = false,		['useable'] = true,		['shouldClose'] = true,		['combinable'] = nil,	['description'] = 'Spawn a consign prop'},
['roadbarrier']			= {['name'] = 'roadbarrier', 		['label'] = 'Road Barrier', 		['weight'] = 1,		['type'] = 'item',		['image'] = 'roadbarrier.png', 			['unique'] = false,		['useable'] = true,		['shouldClose'] = true,		['combinable'] = nil,	['description'] = 'Spawn a road barrier prop'},

-- Materials | T1GER Mechanic System
['scrap_metal']			= {['name'] = 'scrap_metal',		['label'] = 'Scrap Metal', 			['weight'] = 1,		['type'] = 'item',		['image'] = 'scrap_metal.png', 			['unique'] = false,		['useable'] = false,		['shouldClose'] = true,		['combinable'] = nil,	['description'] = 'Material - Scrap Metal'},
['steel']				= {['name'] = 'steel', 				['label'] = 'Steel', 				['weight'] = 1,		['type'] = 'item',		['image'] = 'steel.png', 				['unique'] = false,		['useable'] = false,		['shouldClose'] = true,		['combinable'] = nil,	['description'] = 'Material - Steel'},
['aluminium']			= {['name'] = 'aluminium', 			['label'] = 'Aluminium', 			['weight'] = 1,		['type'] = 'item',		['image'] = 'aluminium.png', 			['unique'] = false,		['useable'] = false,		['shouldClose'] = true,		['combinable'] = nil,	['description'] = 'Material - Aluminium'},
['plastic']				= {['name'] = 'plastic', 			['label'] = 'Plastic', 				['weight'] = 1,		['type'] = 'item',		['image'] = 'plastic.png', 				['unique'] = false,		['useable'] = false,		['shouldClose'] = true,		['combinable'] = nil,	['description'] = 'Material - Plastic'},
['rubber']				= {['name'] = 'rubber', 			['label'] = 'Rubber', 				['weight'] = 1,		['type'] = 'item',		['image'] = 'rubber.png', 				['unique'] = false,		['useable'] = false,		['shouldClose'] = true,		['combinable'] = nil,	['description'] = 'Material - Rubber'},
['electric_scrap']		= {['name'] = 'electric_scrap', 	['label'] = 'Electric Scrap', 		['weight'] = 1,		['type'] = 'item',		['image'] = 'electric_scrap.png', 		['unique'] = false,		['useable'] = false,		['shouldClose'] = true,		['combinable'] = nil,	['description'] = 'Material - Electric Scrap'},
['glass']				= {['name'] = 'glass', 				['label'] = 'Glass', 				['weight'] = 1,		['type'] = 'item',		['image'] = 'glass.png', 				['unique'] = false,		['useable'] = false,		['shouldClose'] = true,		['combinable'] = nil,	['description'] = 'Material - Glass'},
['copper']				= {['name'] = 'copper', 			['label'] = 'Copper', 				['weight'] = 1,		['type'] = 'item',		['image'] = 'copper.png', 				['unique'] = false,		['useable'] = false,		['shouldClose'] = true,		['combinable'] = nil,	['description'] = 'Material - Copper'},
['carbon_fiber']		= {['name'] = 'carbon_fiber', 		['label'] = 'Carbon Fiber', 		['weight'] = 1,		['type'] = 'item',		['image'] = 'carbon_fiber.png', 		['unique'] = false,		['useable'] = false,		['shouldClose'] = true,		['combinable'] = nil,	['description'] = 'Material - Carbon Fiber'},
['brass']				= {['name'] = 'brass', 				['label'] = 'Brass', 				['weight'] = 1,		['type'] = 'item',		['image'] = 'brass.png', 				['unique'] = false,		['useable'] = false,		['shouldClose'] = true,		['combinable'] = nil,	['description'] = 'Material - Brass'},
['synthetic_oil']		= {['name'] = 'synthetic_oil', 		['label'] = 'Synthetic Oil', 		['weight'] = 1,		['type'] = 'item',		['image'] = 'synthetic_oil.png', 		['unique'] = false,		['useable'] = false,		['shouldClose'] = true,		['combinable'] = nil,	['description'] = 'Material - Synthetic Oil'},
['acid']				= {['name'] = 'acid', 				['label'] = 'Synthetic Acid', 		['weight'] = 1,		['type'] = 'item',		['image'] = 'acid.png', 				['unique'] = false,		['useable'] = false,		['shouldClose'] = true,		['combinable'] = nil,	['description'] = 'Material - Synthetic Acid'},
```

{% endcode %}

#### OX Inventory

1. Navigate to `ox_inventory/data/items.lua` and open up the file.
2. Insert the following items into the file:

{% file src="/files/Hck9GZvQobc3cYRwAJzi" %}
You can also download the items.lua and copy paste directly from the file. ⚠️THIS IS NOT REPLACE!!!
{% endfile %}

{% code title="Items for ox\_inventory/data/items.lua" %}

````lua
-- Health Parts | T1GER Mechanic System

    ["radiator"] = {
		label = "Radiator",
		weight = 1,
		stack = true,
		close = true,
	},
    ["fuel_pump"] = {
		label = "Fuel Pump",
		weight = 1,
		stack = true,
		close = true,
	},
    ["brakes"] = {
		label = "Brakes",
		weight = 1,
		stack = true,
		close = true,
	},
    ["drive_shaft"] = {
		label = "Drive Shaft",
		weight = 1,
		stack = true,
		close = true,
	},
    ["alternator"] = {
		label = "Alternator",
		weight = 1,
		stack = true,
		close = true,
	},
    ["clutch"] = {
		label = "Clutch",
		weight = 1,
		stack = true,
		close = true,
	},

-- Service Parts | T1GER Mechanic System

    ["oil_filter"] = {
		label = "Oil & Filter",
		weight = 1,
		stack = true,
		close = true,
	},
    ["air_filter"] = {
		label = "Air Filter",
		weight = 1,
		stack = true,
		close = true,
	},
    ["fuel_filter"] = {
		label = "Fuel Filter",
		weight = 1,
		stack = true,
		close = true,
	},
    ["coolant"] = {
		label = "Coolant",
		weight = 1,
		stack = true,
		close = true,
	},
	["brake_fluid"] = {
		label = "Brake Fluid",
		weight = 1,
		stack = true,
		close = true,
	},
    ["steering_fluid"] = {
		label = "Power Steering Fluid",
		weight = 1,
		stack = true,
		close = true,
	},
    ["transmission_fluid"] = {
		label = "Transmission Fluid",
		weight = 1,
		stack = true,
		close = true,
	},
    ["spark_plugs"] = {
		label = "Spark Plugs",
		weight = 1,
		stack = true,
		close = true,
	},
    ["drive_belt"] = {
		label = "Drive Belt",
		weight = 1,
		stack = true,
		close = true,
	},
    ["flywheel"] = {
		label = "Flywheel",
		weight = 1,
		stack = true,
		close = true,
	},
    ["tires"] = {
		label = "Tires",
		weight = 1,
		stack = true,
		close = true,
	},

-- Body Parts | T1GER Mechanic System

    ["part_door"] = {
		label = "Door",
		weight = 1,
		stack = true,
		close = true,
	},

	["part_hood"] = {
		label = "Hood",
		weight = 1,
		stack = true,
		close = true,
	},

	["part_trunk"] = {
		label = "Trunk",
		weight = 1,
		stack = true,
		close = true,
	},

	["part_wheel"] = {
		label = "Wheel",
		weight = 1,
		stack = true,
		close = true,
	},

	["part_window"] = {
		label = "Window",
		weight = 1,
		stack = true,
		close = true,
	},

-- Kits | T1GER Mechanic System

    ["repairkit"] = {
		label = "Repair Kit",
		weight = 1,
		stack = true,
		close = true,
	},
	["repairkit_adv"] = {
		label = "Repair Kit Advanced",
		weight = 1,
		stack = true,
		close = true,
	},
    ["patchkit"] = {
		label = "Patch Kit",
		weight = 1,
		stack = true,
		close = true,
	},
    ["carjack"] = {
		label = "Car Jack",
		weight = 1,
		stack = true,
		close = true,
	},
    ["fuel_can"] = {
		label = "Fuel Can",
		weight = 1,
		stack = true,
		close = true,
	},
    ["jump_starter"] = {
		label = "Jump Starter",
		weight = 1,
		stack = true,
		close = true,
	},
    ["tire_repairkit"] = {
		label = "Tire Repair Kit",
		weight = 1,
		stack = true,
		close = true,
	},

-- Prop Emotes | T1GER Mechanic System

    ["roadcone"] = {
		label = "Road Cone",
		weight = 1,
		stack = true,
		close = true,
	},
    ["toolstrolley"] = {
		label = "Tools Trolley",
		weight = 1,
		stack = true,
		close = true,
	},
	["toolbox"] = {
		label = "Tool Box",
		weight = 1,
		stack = true,
		close = true,
	},
    ["enginehoist"] = {
		label = "Engine Hoist",
		weight = 1,
		stack = true,
		close = true,
	},
    ["consign"] = {
		label = "Con Sign",
		weight = 1,
		stack = true,
		close = true,
	},
    ["roadbarrier"] = {
		label = "Road Barrier",
		weight = 1,
		stack = true,
		close = true,
	},

-- Materials | T1GER Mechanic System

    ['scrapmetal'] = {
		label = 'Scrap Metal',
		weight = 80,
	},
    ["steel"] = {
		label = "Steel",
		weight = 1,
		stack = true,
		close = true,
	},
    ["aluminium"] = {
		label = "Aluminium",
		weight = 1,
		stack = true,
		close = true,
	},
    ["plastic"] = {
		label = "Plastic",
		weight = 1,
		stack = true,
		close = true,
	},
	["rubber"] = {
		label = "Rubber",
		weight = 1,
		stack = true,
		close = true,
	},
    ["electric_scrap"] = {
		label = "Electric Scrap",
		weight = 1,
		stack = true,
		close = true,
	},
    ["glass"] = {
		label = "Glass",
		weight = 1,
		stack = true,
		close = true,
	},
    ["copper"] = {
		label = "Copper",
		weight = 1,
		stack = true,
		close = true,
	},
    ["carbon_fiber"] = {
		label = "Carbon Fiber",
		weight = 1,
		stack = true,
		close = true,
	},
    ["brass"] = {
		label = "Brass",
		weight = 1,
		stack = true,
		close = true,
	},
    ["synthetic_oil"] = {
		label = "Synthetic Oil",
		weight = 1,
		stack = true,
		close = true,
	},
    ["acid"] = {
		label = "Synthetic Acid",
		weight = 1,
		stack = true,
		close = true,
	},

```
````

{% endcode %}

### 5 - Configuration

{% hint style="info" %}
You must go through **all** configurable options & settings in `config.lua` and configure them to your server's preferences.

Also please read the comments at the end of each line, for a brief information on what the option does.&#x20;
{% endhint %}

### 6 - Ensure Dependencies

{% hint style="info" %}
The required dependencies for this resource can be seen in [#dependencies](#dependencies "mention").

* [x] T1GER Library: [documentation](/resources/t1ger-library)
* [x] OX Library: [documentation](https://overextended.github.io/docs/)&#x20;

Make sure to start/ensure these dependencies in your server start config before T1GER Gang System.&#x20;
{% endhint %}

Start order `in server.cfg` should look like this:

```editorconfig
ensure ox_lib ## mandatory
ensure ox_inventory ##(or other inventory, ex: qb-inventory)
ensure ox_target ##(or other target, ex: qb-target)
ensure t1ger_lib ## mandatory
ensure t1ger_mechanicsystem ## mandatory
ensure t1ger_carlift ## mandatory
```

### 7 - Ready

Congratulations, you've successfully installed the resource. Restart the server and you will be all set.&#x20;


# Shop Account

Instructions on using mechanic shop account in other resources

The resource offers a custom account system that is standalone and not dependent on frameworks.

### Get Shop ID

You can get the player's mechanic shop id with this export:

```lua
local src = source
local shopID = exports['t1ger_mechanicsystem']:GetPlayerMechId(src)
-- src(INT): player server id
```

### Add Account Money

{% hint style="warning" %}
Requires: Mechanic Shop ID (use exports to get the ID based on player's server id or player's job name)
{% endhint %}

```lua
exports['t1ger_mechanicsystem']:PlusMechanicAccount(shopId, amount)
-- shopId(INT): mechanic shop id
-- amount(INT): amount of money to add to the account
```

### Remove Account Money

{% hint style="warning" %}
Requires: Mechanic Shop ID (use exports to get the ID based on player's server id or player's job name)
{% endhint %}

```lua
exports['t1ger_mechanicsystem']:MinusMechanicAccount(shopId, amount)
-- shopId(INT): mechanic shop id
-- amount(INT): amount of money to add to the account
```

### Usage - Example #1

Here's an example to easily add/remove money from a mechanic shop:

<pre class="language-lua"><code class="lang-lua"><strong>local src = source -- player server id
</strong><strong>local amount = 5000 -- how much should be added/removed? 
</strong>
-- export to get the shop id based on player server id:
local shopId = exports['t1ger_mechanicsystem']:GetPlayerMechId(src)

-- add money:
exports['t1ger_mechanicsystem']:PlusMechanicAccount(shopId, amount)

-- remove oney:
exports['t1ger_mechanicsystem']:MinusMechanicAccount(shopId, amount)
</code></pre>

### Usage - Example #2

Here's an alternative example using TriggerEvent (similar to esx\_addonaccount)

```lua
local playerJob = 't1mechanic' -- add function/export to get the player's job here. 
local amount = 5000 -- how much should be added/removed? 

TriggerEvent('mechanicsystem:server:getPlayerMechanicShop', playerJob, function(mechanicShop)
    -- remove money:
    if mechanicShop.account >= amount then
        exports['t1ger_mechanicsystem']:MinusMechanicAccount(mechanicShop.id, amount)
    else
        print("not enough money")
    end
    
    -- add money:
    exports['t1ger_mechanicsystem']:PlusMechanicAccount(mechanicShop.id, amount)
end)
```


# QB Vehicle Failure

Instructions on using QB Vehicle Failure with T1GER Mechanic System

The resource offers degradation of health parts, so you can disable degradation of random components in qb-vehiclefailure.&#x20;

### Download latest version

<https://github.com/qbcore-framework/qb-vehiclefailure>

### Update config.lua

Set `degradeRandomComponents` to false. Should look like this:

<figure><img src="https://2167335559-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MiDWIMbFBeXle-trOlk%2Fuploads%2FW8wqYMhDey7o7PvaWIcN%2Fimage.png?alt=media&amp;token=8b4d75c1-2a3d-4f1d-8fb8-f64fd0e49f7b" alt=""><figcaption><p>degradeRandomComponents = false</p></figcaption></figure>

### Disable qb-mechanicjob?

With this change, you can now disable/delete qb-mechanicjob or keep it.&#x20;

{% hint style="danger" %}
If you keep `qb-mechanicjob` running, make sure to change hotkey/kindbind for mechanic menu, otherwise menu in `t1ger_mechanicsystem` will not work!
{% endhint %}


# Product Information

T1GER Mechanic System

## INTRODUCTION

This comprehensive mechanic system enhances roleplay for those involved in mechanic related activities. It allows admins to create and manage mechanic shops in-game in runtime. Mechanics can operate their own mechanic business, perform detailed vehicle repairs, diagnostics, and maintenance using a wide range of realistic tools and a realistic degradation system based on mileage and collisions. The action menu allows mechanics to interact with vehicles or request NPC calls to engange in immersive jobs.

## PREVIEW

{% embed url="<https://youtu.be/yBlY2HB3wNA>" %}

## DESCRIPTION

### Admin Mechanic Menu

The admin mechanic menu is a comprehensive tool for managing mechanic shops in-game, accessible via command or keybind. Admins can create, view, and manage shops, assign a shop boss, and configure various markers such as boss menu, duty toggles, storage, and garages. Custom vehicle lifts designed by K4MB1 can be spawned as needed. Shops can be temporarily disabled to restrict access or permanently deleted. This menu streamlines shop management and configuration without requiring server restarts.

### Dynamic Shop Creation

The in-game dynamic shop creator, allows admins to set up mechanic shops in real-time without server restarts. Default job settings, including grades, names, labels, and salaries, are pre-configured in the system. When creating a shop, admins enter a job name; if it doesn’t exist, the default settings are applied. If the job already exists, the system automatically pulls the existing data, allowing for the creation of multiple branches using shared job attributes. Each shop can have its own blip, which can be enabled or disabled individually.

### Shop Markers

Each shop has customizable markers that can be enabled or disabled in the config, with admins deciding which markers to create. Mechanics can toggle duty at any time, even if they have another job, as long as they’re hired at a specific shop. The boss menu allows shop bosses to manage accounts, recruit, promote or fire employees, and handle vehicle storage. The workbench provides item crafting based on configurable recipes, and shops have quick repair markers for immediate vehicle fixes. Each shop also includes a storage marker, supporting various inventory systems or menu-based storage options.

### Player Mechanic Menu

The player mechanic "action" menu is accessible by command or keybind and available exclusively to hired mechanics. It offers a range of features including viewing or creating bills, requesting NPC jobs - or cancel an ongoing job, checking vehicle status, performing service checks, diagnosing health parts, and initiating body repairs. Mechanics can also push, flip, unlock, or impound the nearest vehicle, with each feature customizable and able to be disabled in the config.

### Mileage System

The script tracks and saves the mileage of all personal vehicles, with options to track distances in either miles or kilometers. It offers nearly 1:1 accuracy with the actual in-game distance traveled, as seen on the GPS navigation. This feature adds realism to vehicle management by accurately reflecting the wear and usage of each vehicle.

### Vehicle Status

Mechanics can view detailed information about the nearest vehicle, using 3rd-eye-target or menu, including engine and body health, fuel and dirt levels, and engine and oil temperatures. For personal vehicles, it also displays the driven mileage, providing a comprehensive overview of the vehicle’s condition.

### Body Repair

A comprehensive body repair process consisting of three main steps: inspection, damage reporting, and part installation. Mechanics begin by inspecting the vehicle at four designated points to identify any damage. If no damage is found, such as broken or missing doors, hoods, trunks, windows, wheels, or burst tires, the repair process ends automatically with the vehicle restored to its original condition. If damage is detected, a detailed damage report is generated in the mechanic menu, listing all missing or broken parts. This report is updated live as repairs progress. Mechanics can then use specific body parts to replace or install missing components, accompanied by realistic animations and props.

The entire process, including props, animations, skill checks, progress bars, and durations, is fully customizable in the configuration, allowing for a tailored repair experience that enhances roleplay immersion.

### Vehicle Service/Maintenance

All personal-owned vehicles require regular maintenance and servicing to prevent malfunctions over time. Mechanics can perform a detailed service check on each vehicle, receiving a report on the condition and expected lifespan of various service parts: oil filter, air filter, fuel filter, coolant, brake fluid, power steering fluid, transmission fluid, spark plugs, drive belt, flywheel, and tires.

These parts degrade based on the in-game mileage driven, and once they reach their lifespan limit, they are marked as SERVICE DUE, indicating that the part is malfunctioning and will begin to degrade associated health parts if not replaced. Mechanics can repair each service part using the appropriate item, and the old, replaced part will return some materials as scrap.

The system is highly configurable, allowing you to customize the lifespan and degradation rate for each service part, as well as add, edit, or remove parts. Additionally, you can configure the amount and type of returned materials, set degradation percentages and values, and enable or disable features like skill checks, progress bars, animations, and durations for a tailored maintenance experience.

### Health Parts

This system covers essential vehicle components that ensure proper functionality, including the radiator, fuel pump, brakes, drive shaft, alternator, and clutch. Mechanics can diagnose the condition of these parts, receiving a detailed report that categorizes them as OK, WORN, DEFECT, or MECHANICAL FAILURE. Diagnostics require the engine temperature to drop below a configurable value. Health parts degrade due to direct collisions or when associated service parts, like the oil filter, are due for maintenance, which can accelerate the degradation process.

Each part affects the vehicle differently when malfunctioning:

* a damaged radiator causes engine overheating and smoke
* a failing fuel pump leads to stalling and rapid fuel loss
* faulty brakes result in poor braking performance
* a compromised drive shaft makes steering difficult
* an alternator issue causes starting problems
* a defective clutch results in rough gear shifts.

Mechanics can repair these health parts using specific items, returning some materials as scrap from the old parts.

The system is highly customizable, allowing you to configure degradation rates, collision impact, malfunction effects, and associated service parts. You can also add, edit, or remove health parts, adjust skill checks, and customize progress bars, animations, and durations to fit your needs.

### Car Jack

Allows mechanics to spawn a jack using an item, attach it to a vehicle’s wheel, and lift the vehicle on one side for repairs or inspections. This interactive tool enhances realism by enabling detailed work on specific vehicle areas.

### Custom Lifts

The resource includes custom lift props by K4MB1 Maps, providing a realistic and immersive experience for mechanics. These smooth-operating lifts enable detailed vehicle inspections and repairs, enhancing the overall mechanic roleplay with lifelike animations and precise functionality.

### Patch Kits

Patch Kits provide a quick solution to restore both health and service part values for all components that are either due for service or in mechanical failure condition. They instantly repair parts to a configurable amount, effectively delaying further degradation and temporarily preventing malfunctions. This allows mechanics to provide immediate, albeit temporary, fixes to vehicles in critical condition, ensuring they can continue to operate until a full repair is possible. The configuration options allow you to customize the amount restored, making Patch Kits adaptable to different gameplay scenarios and repair needs.

### Repair Kits

There are two types of Repair Kits available — normal and advanced. Advanced kits can be restricted to mechanics only, adding a layer of exclusivity and skill-based gameplay. Each kit type can restore engine health to a specified level, which is configurable in the settings. You can also enable or disable skill checks and customize animations, progress bars, and durations for each repair kit type, providing flexibility to suit various gameplay styles and scenarios.

### Prop Emotes

Mechanics can use various items to perform immersive emotes with props such as tool trolleys, toolboxes, engine hoists, and road cones. All props are configurable, allowing you to add or remove them as needed to enhance roleplay and mechanic interactions

### NPC Jobs & Activities

This system offers three dynamic job types to keep mechanics engaged when there are no customer requests. With over 40 job locations and the option to add more, each job features a configurable distance check to ensure mechanics have a minimum travel distance, preventing tasks from being too close and adding more variety to their work.

* **Break Down Jobs** - Mechanics can respond to breakdown calls, where they must bring a tow truck to assist an NPC with a disabled vehicle. The job requires towing the vehicle and the NPC to a specified drop-off location, with payment received upon completion.
* **Roadside Repairs** - Mechanics attend to NPCs facing random issues such as dead batteries, empty fuel tanks, or burst tires. They must carry the necessary repair kits and complete the job on-site, receiving payment directly from the NPC after resolving the issue.
* **Scrapping** - Mechanics can take on scrapping runs by collecting a vehicle from an NPC and delivering it to the scrapyard. The NPC at the scrapyard reviews the vehicle and rewards the mechanic with materials, which can be used for crafting various items.

These activities ensure mechanics have engaging, varied tasks that require travel and proper preparation, adding depth and realism to their role.

### Tow Trucking

This resource includes an integrated tow trucking system activated by the /tow command. Mechanics can use it to attach and tow vehicles seamlessly within the game. The system is flexible, allowing you to customize or disable it entirely if you prefer to use a different towing script. It provides a straightforward solution for vehicle recovery and transportation, enhancing the mechanic roleplay experience with easy-to-use controls and smooth towing mechanics.

### Billing System

This resource features a comprehensive billing system designed for mechanics to create detailed, itemized bills for their customers. Mechanics can add specific notes for each service or repair performed, providing transparency and clarity for customers. Before the payment is processed, customers must review, confirm, and sign the bill, ensuring they agree with the charges. Mechanics can access a list of all issued bills, which is particularly useful for shop owners to monitor transactions, track completed work, and manage overall shop expenses effectively. This system not only enhances the customer experience with clear communication but also helps shop owners maintain accurate financial records and accountability.

### Vehicle Interaction

Mechanics have access to a variety of immersive interaction options with vehicles. They can push vehicles to move them out of the way, flip overturned vehicles back onto their wheels, unlock locked vehicles, and send vehicles to impound, effectively deleting them from the game. Each feature is fully configurable in the settings, allowing you to enable or disable them as needed. The impound feature is also open for customization, providing the flexibility to integrate your own events or exports for a more tailored experience. These interactions enhance the mechanic roleplay by offering realistic and practical vehicle management options.

### Customization

The scripts has config file(s) with an extensive amount of configurable options, allowing extreme customization to make the system work with your roleplay server. A separate language file, containing all strings, makes it very easy for you to translate the system into your preferred language of choice. There's an icon folder with inventory icons for all included items.

### Performance

The script has been rigorously tested to ensure maximum optimization and smooth performance, even on large servers with high player counts. Its low resource usage minimizes server strain, providing a stable and seamless gameplay experience for all users. The focus on efficiency and reliability ensures that the script can handle peak activity without compromising functionality or player immersion, making it a robust choice for any server environment.

### Sync

The script is fully synchronized across all players, utilizing OneSync Infinity and statebags for seamless and reliable synchronization.

## DEPEDENCIES

### Required resources

* es\_extended / qb-core / qbox
* oxmysql / mysql
* t1ger\_lib (included)
* ox\_target / qb-target / meta-target
* ox\_inventory / qb-inventory / qs-inventory / mf-inventory / core-inventory


# T1GER Tuning System

Documentation, troubleshooting and support for T1GER Tuning System resource

<figure><img src="https://2167335559-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MiDWIMbFBeXle-trOlk%2Fuploads%2FU48S9kmq7urAiPbWmqrK%2Ftuningsystem4.png?alt=media&amp;token=f56c2a2e-c603-4975-8a76-cac5af09edd8" alt=""><figcaption></figcaption></figure>

#### [**View on Tebex**](https://store.t1ger.net/package/6044615) | [**CFX Forum Post**](https://forum.cfx.re/t/esx-qb-t1ger-tuning-system/5275949) | [**YouTube Showcase**](https://youtu.be/fQfBW-U81FI) | [**Discord**](https://discord.gg/t1ger)

## INTRODUCTION

This comprehensive tuning system enhances roleplay for those involved in vehicle customization and performance upgrades. It allows tuners to operate their own tuning businesses, providing a wide range of services such as visual modifications, engine swaps, and performance enhancements. With tools like the tuner tablet and dyno laptop, tuners can manage customer orders, fine-tune vehicle handling, and install nitrous for an immersive and realistic tuning experience that brings real-life automotive passion to your server.

## PREVIEW

{% embed url="<https://youtu.be/fQfBW-U81FI>" %}

## DESCRIPTION

### Admin Management Menu <a href="#admin-mechanic-menu" id="admin-mechanic-menu"></a>

The Admin Management Menu is a powerful tool for efficiently managing and configuring tuner shops within the game. Accessible via command or keybind, this menu allows admins to create, view, and manage tuner shops in real-time.

Using the shop creator tool, admins can fully customize each shop by setting a unique name, enabling or disabling map blips to create hidden or public shops, and integrating the shop with existing server jobs, automatically pulling job grades. Alternatively, admins can create a new job with a custom name and label, using predefined job grades from the configuration. Additionally, admins can set an initial account balance and limit the shop’s services to specific modification categories, enabling the creation of specialized tuner shops. The system comes with the following predefined modification categories: respray, body works, chassis, engine bay, exterior, interior, lights, wheels, and performance.

When managing tuner shops, admins can designate a shop boss, adjust the shop’s account balance, and modify allowed modification categories. Admins can also configure various shop markers, each with distinct functionalities. Multiple instances of the same marker type are supported, providing greater flexibility in shop operations. Each marker can be given a unique name, with customizable blip settings and marker visuals, allowing for a tailored in-game experience.

When overseeing tuner shops, admins can designate a shop boss, manage the shop's account balance or customize the shop's allowed modification categories.

Admins have the ability to configure various shop markers, each offering distinct functionalities. Multiple instances of the same marker type are supported, enhancing shop flexibility. Each marker can be uniquely named, with customizable blip settings and marker visuals for a tailored in-game experience.

Should a shop become redundant, it can be permanently removed with ease. This versatile menu streamlines shop management and configuration without requiring server restarts, ensuring smooth and uninterrupted gameplay administration.

### Tuner Shops

Each tuner shop is equipped with essential markers, each offering unique functionalities necessary for the shop’s operations:

* **Duty Marker**: Allows tuners to toggle their duty status, enabling them to clock in for work or go off-duty as unemployed.
* **Boss Marker**: Grants the shop’s boss the ability to manage the shop’s finances (deposit, withdraw, and view funds), oversee employee management (recruit, fire, promote, and demote employees), and set the shop's markup percentage.
* **Garage Marker**: Provides a dedicated space for storing and retrieving personally owned vehicles. This is a private garage, not a shared one.
* **Storage Marker**: A secure location for storing and accessing items such as mods, tools, kits, and materials. This storage is accessible to all hired employees, ensuring that all staff members have access to the resources they need for their work.
* **Workbench Marker**: Allows tuners to craft usable mod items and tools necessary for their work. Each craftable item has configurable recipes based on available materials, adding depth and customization to the shop's crafting system.
* **Laptop Marker**: Enables tuners to order mods and kits if they lack the necessary materials. The cost is deducted from the shop's account, and items are automatically delivered to a selected storage marker or the tuner’s inventory.
* **Customs Marker**: The area where players can customize their vehicles through self-service, with modifications restricted to the categories enabled for that specific shop. Players have the option to pay immediately for instant modifications at an incentivized price or submit a mod order at a discounted rate, which will require tuners to install the mods.
* **Tuning Bay Marker**: The core workspace for tuners, where they can access and start mod orders, order new engines for engine swaps to alter vehicle sound, or install various nitrous kits. This is the primary area for performing advanced tuning tasks and modifications.

### Vehicle Tuning

At the customs marker in a tuner shop, players can access a self-service customization menu, limited to the modification categories enabled for that shop. There will also be a prompt to quick-repair the vehicle for configurable base price, this feature can also be disabled, encouraging roleplay with mechanics.

Explore all available GTA tuning options, including DLC mods and the latest GTA: Online Chop Shop update, featuring seven new custom plates. Create unique respray combinations or choose from the standard GTA color palette. The system also supports special resprays like chameleon, util, and worn, which can also be applied to certain wheels and interiors.

Players can preview all modifications live before adding them to their basket. Once satisfied with the customization, they have the option to either pay immediately for instant modifications at an incentivized price or submit a mod order at a discounted rate, requiring tuners to complete the installations.

Configurable options in the configuration file allow you to disable specific mods, such as weapon mods, restrict immediate purchases to encourage roleplay opportunities for tuners, and enable or disable incentivized pricing for immediate payments. You can also set a desired incentivized percentage to be added to mod prices for instant purchases.

### Mods Pricing

The Tuning System features an advanced pricing mechanism designed to support a balanced and realistic economy for your roleplay server. The pricing system is highly customizable, offering several key options to fine-tune the cost of modifications:

* **Price Escalation**: This option allows you to set a percentage between 0-100% to progressively increase the prices of mod variants. Setting it to 0 disables escalation, resulting in a flat price for all variants. When enabled, each successive upgrade costs more, reflecting the increased value of higher-tier modifications.
* **Parts Acquisition Costs**: You can choose to include or exclude the cost of acquiring parts in the final mod price. If enabled, the configured item price is added to the calculated mod cost, simulating the expense of sourcing parts. This feature helps cover the costs associated with acquiring materials for more realistic financial management.
* **Tiered Pricing**: This feature bases mod prices on the vehicle’s market value, using a tiered system with specific price caps and multipliers. For example, Tier 1 could apply a 5% multiplier for vehicles priced up to $10,000, making mods for expensive cars costlier than those for cheaper ones. If tiered pricing is disabled, all modifications are priced equally, regardless of the vehicle’s value.
* **Base Price Configuration**: You can set a base price for each mod type within the configuration file, providing a foundation for all mod prices. This allows you to tailor the costs to align with your server’s economic model.

This comprehensive pricing system enables you to create a finely-tuned and sustainable economy, perfectly suited to your roleplay server’s needs and player dynamics.

### Tuner Tablet

The tuner tablet is an essential tool for every tuner, offering a range of functionalities to enhance vehicle diagnostics and shop operations. When connected to a vehicle, it provides vital information such as engine and body health values, fuel level, and details about the installed GTA performance parts, including the engine, brakes, transmission, suspension, turbo, and armor. It also grants access to the dyno for fine-tuning vehicle handling.

When not connected to a vehicle, the tuner tablet allows tuners to create and manage bills, request NPC jobs during low player activity, and view a comprehensive list of submitted mod orders along with detailed information on each order.

### Mod Orders

Mod orders can be managed directly from the tuner tablet, allowing tuners to view or refund orders as needed. To begin working on a mod order, the tuner must bring the specified vehicle to an available tuning bay marker. A custom workflow UI will guide the tuner through each step, requiring the manual installation of all ordered mods using the appropriate items.

When using a mod item, a menu of possible mod variants will appear, and the tuner must select the corresponding variant from the order. A configurable prop representing the mod, with customizable offsets and animations, will appear in the tuner's hands. The tuner must then target the vehicle at the designated interaction points (hood, trunk, side, or wheel), complete a skill check (configurable), and initiate the immersive installation animation. Upon completion, the vehicle’s properties will update with the newly installed mod variant, and the item will be removed.

If the correct mod variant is installed, it will be marked as complete in the workflow UI, allowing the tuner to proceed to the next task. If not, the tuner must repeat the process with the correct item. Once all installations are complete, the pre-paid amount from the customer will be credited to the shop’s account, and the customer can leave with their modified vehicle.

### Drift Tyres

Tuners can enhance vehicle performance by installing drift tires, enabling "drift mode" for improved control during drifting. The system also allows for resetting to standard performance by reinstalling stock tires. Both actions are facilitated through the use of consumable items, adding a layer of immersion with detailed animations and props. This feature brings realistic customization options and dynamic driving mechanics to enhance the player experience.

### Engine Swaps

Configure engines based on vehicle class, allowing for unique engine sounds using either GTA’s default or custom streamed sounds. Each engine can have a custom label, price, and optional icon. The script comes pre-configured with 4-5 engines per vehicle class, giving you the flexibility to maintain realistic sound profiles and prevent mismatches, like a basic car sounding like a supercar—although you have full control over the sound assignments.

Engine swaps do not affect vehicle handling; they are designed solely to alter the vehicle’s sound. Tuners can bring any vehicle to the tuning bay marker, select “Engine Swaps,” and view a list of available engines based on the vehicle's class. Once an engine is ordered, the tuner must prepare and extract the old engine using a hoist, wait for the new engine to arrive, and then install it into the vehicle— all with realistic props and immersive animations.

Engine sounds are synchronized across all players using statebags and saved in the database for owned vehicles, ensuring persistence even after server restarts.

### Nitrous

The built-in advanced nitrous system revolutionizes vehicle performance, offering an immersive and highly configurable nitrous experience for tuners and players. Tuners can install nitrous kits at the Tuning Bay, selecting the kit size in pounds (lb), with each pound providing 10 shots of NOS Burst. The installation process is detailed and immersive, requiring tuners to prepare the engine bay with props and animations to fit the new kit.

To extend the NOS Burst duration, tuners can install burst upgrade kits, which increase the burst threshold from the default value to a maximum configurable limit. The installation follows the same detailed process, complete with props and animations. Admins can set up these burst kits in the configuration file with customized thresholds.

NOS 10-Shots Bottles, containing 1 lb of nitrous each, can be purchased by tuners to refill a vehicle’s NOS capacity, providing 10 shots per use. Empty bottles can be refilled at designated locations around the map, with finite nitrous supplies that reset after each server restart.

The purge button allows players to expel excess nitrous gas while stationary, boosting the effectiveness of the NOS Burst. Each second of purging consumes 1 shot of nitrous, with purge efficiency stacking up to the burst kit’s threshold, achieving 100% efficiency at full purge. Shorter purges offer reduced efficiency (e.g., 70% for a 1-second purge), with all percentages fully configurable. If no purge is used, the efficiency defaults to 30% (configurable), and once the efficiency window expires, it defaults to 50% (configurable). During the efficiency window, NOS Burst operates at the available efficiency.

The burst button significantly boosts vehicle performance, consuming 1 shot of nitrous per second, with the performance directly tied to the purge efficiency. Bursting without purging introduces a medium risk of engine damage, while bursting after the efficiency window expires carries a lower risk. Holding the burst key beyond the burst kit’s threshold creates a high risk of engine damage, with all risk chances configurable.

If players attempt to purge during the nitrous cooldown (can be disabled), triggers when the efficiency window expires, a gas leak may occur, leading to a loss of nitrous shots (configurable). Visuals, particle effects, and sounds accompany purging, bursting, and gas leaks, enhancing immersion. Additionally, tuners can inject a purge dye item into the nitrous kit to apply personalized RGB colors to the purge effects.

The system also tracks key nitrous properties—such as shots, kit size, and burst kits—through vehicle statebags, ensuring persistent and synchronized data across the server. This advanced nitrous system elevates the vehicle tuning experience, providing tuners and players with a dynamic, immersive, and realistic way to customize and boost vehicle performance while adding layers of strategy and risk to roleplay servers.

### Dyno Tuning

Dyno tuning is accessed via the tuner tablet when connected to a vehicle. The dyno provides detailed insights into the vehicle’s current modifiers for torque, power, and brakes, enabling precise performance adjustments.

* **Torque**: Represents the drive force at the wheels.
* **Power**: Determines how quickly the engine revs.
* **Brakes**: Adjusts the braking strength by multiplying the game's deceleration calculation (higher values result in stronger braking).

The fine-tuning slider allows for precise modifications to these performance parameters. A hard reset option is also available to restore all modifiers to their default values.

### NPC Jobs

The Tuning System offers two immersive NPC job opportunities for tuners to engage in during periods of low customer activity at their shop:

1. **Salvage Job**: Tuners are tasked with locating and salvaging junk cars to recover materials and potentially valuable parts for tuning purposes. The tuner must 3rd-eye-target the different bones of the vehicle to salvage it. This job is highly customizable, allowing for the configuration of cooldown intervals between jobs, selection of specific junk car models, and customization of map blips. Additional settings include skill check requirements and customizable rewards, with options to define the probability and quantity of items. The system includes 7 predefined locations, with the flexibility to add more to suit your server’s needs.
2. **Mobile Tuning Job**: This job involves responding to a customer request for on-site performance enhancements or cosmetic modifications. Tuners receive detailed instructions on the required installation and must ensure they have the appropriate part before heading to the location. Upon arrival, the tuner interacts with the NPC to confirm the mod variant needed and then performs the installation using the required item. Accurate installation is essential for successful completion and payment. This job can be tailored with configurable settings such as cooldown periods, car and ped models, blip customization, and minimum and maximum cash rewards. The system includes 12 predefined locations, with the option to add more as desired.

Both job systems are synchronized across players to prevent multiple tuners from receiving the same assignment, ensuring a seamless and engaging roleplay experience.

### Mod Stations

The system includes pre-configured self-service mod stations specifically designed for whitelisted jobs. Each station offers configurable options such as location coordinates, accessible job roles, permitted modifications, and the ability to toggle modification costs and map blip visibility. This feature is particularly beneficial for roles like law enforcement, enabling quick and efficient vehicle modifications before heading out on duty

### Billing System <a href="#billing-system" id="billing-system"></a>

This resource features a comprehensive billing system designed for tuners to create detailed, itemized bills for their customers. Tuners can add specific notes for each service, providing transparency and clarity for customers. Before the payment is processed, customers must review, confirm, and sign the bill, ensuring they agree with the charges. Tuners can access a list of all issued bills, which is particularly useful for shop owners to monitor transactions, track completed work, and manage overall shop expenses effectively. This system not only enhances the customer experience with clear communication but also helps shop owners maintain accurate financial records and accountability.

### Customization <a href="#customization" id="customization"></a>

The scripts has config file(s) with an extensive amount of configurable options, allowing extreme customization to make the system work with your roleplay server. A separate language file, containing all strings, makes it very easy for you to translate the system into your preferred language of choice. There's an icon folder with inventory icons for all included items.

### Performance <a href="#performance" id="performance"></a>

The script has been rigorously tested to ensure maximum optimization and smooth performance, even on large servers with high player counts. Its low resource usage minimizes server strain, providing a stable and seamless gameplay experience for all users. The focus on efficiency and reliability ensures that the script can handle peak activity without compromising functionality or player immersion, making it a robust choice for any server environment.

### Sync <a href="#sync" id="sync"></a>

The script is fully synchronized across all players, utilizing OneSync Infinity and statebags for seamless and reliable synchronization.

## DEPEDENCIES <a href="#depedencies" id="depedencies"></a>

#### Required resources <a href="#required-resources" id="required-resources"></a>

* es\_extended / qb-core / qbox
* oxmysql / mysql
* t1ger\_lib (included)
* ox\_target / qb-target / meta-target
* ox\_inventory / qb-inventory / qs-inventory / mf-inventory / core-inventory


# Installation

Resource installation guide and dependencies

## 1 - Ensure Dependencies

Make sure T1GER Library is installed and the required dependencies are ensured. Please refer to [Installation](/resources/t1ger-library/installation).

## 2 - Get T1GER Tuning System

* Get the `t1ger_tuningsystem` resource from: <https://store.t1ger.net/package/6044615>
* Download from: [FiveM's Keymaster](https://keymaster.fivem.net/login?return_url=/asset-grants).

## 3 - Ensure T1GER Tuning System

* Unzip `t1ger_tuningsystem.zip` folder and place it into your `resource` folder. You can place it in a sub-folder as well.&#x20;
* Add `ensure t1ger_tuningsystem` to your server start config. <mark style="color:red;">Make sure to ensure it after all the dependencies!</mark>

<div align="left"><figure><img src="https://2167335559-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MiDWIMbFBeXle-trOlk%2Fuploads%2FZYoj8lXu8SOIbwLlqYjc%2Fimage.png?alt=media&amp;token=77906c58-78e8-4775-9858-b6f049873782" alt=""><figcaption><p>Example of my startup order in server.cfg</p></figcaption></figure></div>

## 4 - SQL

Open the `main.sql` file and execute the queries into your database (you can also import the SQL file directly into your database).&#x20;

{% code title="main.sql" %}

```sql
DROP TABLE IF EXISTS `t1ger_tunershops`;
CREATE TABLE `t1ger_tunershops` (
	`id` INT(11) NOT NULL AUTO_INCREMENT,
	`name` VARCHAR(100) NOT NULL,
	`account` INT(11) NOT NULL DEFAULT 0,
	`boss` VARCHAR(100) DEFAULT NULL,
	`markup` INT(11) NOT NULL DEFAULT 0,
	`job` LONGTEXT NOT NULL DEFAULT ('[]'),
	`blip` LONGTEXT NOT NULL DEFAULT ('[]'),
	`employees` LONGTEXT NOT NULL DEFAULT ('[]'),
	`markers` LONGTEXT NOT NULL DEFAULT ('[]'),
	`categories` LONGTEXT NOT NULL DEFAULT ('[]'),
	`storage` LONGTEXT NOT NULL DEFAULT ('[]'),
	`billing` LONGTEXT NOT NULL DEFAULT ('[]'),
	`orders` LONGTEXT NOT NULL DEFAULT ('[]'),
	`delivery` LONGTEXT NULL DEFAULT NULL,
	PRIMARY KEY (`id`)
);

DROP TABLE IF EXISTS `t1ger_engineswaps`;
CREATE TABLE `t1ger_engineswaps` (
	`plate` VARCHAR(12) NOT NULL,
	`vehicle` VARCHAR(60) NOT NULL,
	`engine` VARCHAR(60) NOT NULL,
	PRIMARY KEY (`plate`)
);


DROP TABLE IF EXISTS `t1ger_nitrous`;
CREATE TABLE `t1ger_nitrous` (
	`plate` VARCHAR(12) NOT NULL,
	`size` INT(11) NOT NULL,
	`shots` INT(11) NOT NULL DEFAULT 0,
	`burst` INT(11) NOT NULL,
	`color` VARCHAR(255) NOT NULL,
	PRIMARY KEY (`plate`)
);

DROP TABLE IF EXISTS `t1ger_dyno`;
CREATE TABLE `t1ger_dyno` (
	`plate` VARCHAR(12) NOT NULL,
	`torque` FLOAT(11) NOT NULL,
	`power` FLOAT(11) NOT NULL,
	`brakes` FLOAT(11) NOT NULL,
	PRIMARY KEY (`plate`)
);
```

{% endcode %}

## 5 - Items

{% hint style="danger" %}
If you rename items or use your own items, make sure to update inside `t1ger_tuningsystem/shared/config.lua` with the respective item names, otherwise the script might not function.
{% endhint %}

<details>

<summary><strong>ESX</strong></summary>

1. Open your database and find the items table.
2. Run this query in your database to insert the items.

```sql
INSERT IGNORE INTO `items` (`name`, `label`) VALUES
	-- Kits:
	('tuner_tablet', 'Tuner Tablet'),
	('tuner_repairkit', 'Tuner Repair Kit'),
	('tuner_enghoist', 'Tuner Engine Hoist'),
	('nos_shots_bottle', 'NOS 10-Shots (1lb)'),
	('nos_empty_bottle', 'NOS Empty (1lb)'),
	('nos_purge_dye', 'NOS Purge Dye'),
	-- Materials:
	('scrap_metal', 'Scrap Metal'),
	('steel', 'Steel'),
	('aluminium', 'Aluminium'),
	('plastic', 'Plastic'),
	('rubber', 'Rubber'),
	('electric_scrap', 'Electric Scrap'),
	('glass', 'Glass'),
	('copper', 'Copper'),
	('carbon_fiber', 'Carbon Fiber'),
	('brass', 'Brass'),
	('synthetic_oil', 'Synthetic Oil'),
	('acid', 'Synthetic Acid'),
	-- Mods:
	('mod_engine', 'Vehicle Engine'),
	('mod_brakes', 'Vehicle Brake'),
	('mod_transmission', 'Vehicle Transmission'),
	('mod_suspension', 'Vehicle Suspension'),
	('mod_armor', 'Vehicle Armor'),
	('mod_turbo', 'Vehicle Turbo'),
	('mod_exhaust', 'Vehicle Exhaust'),
	('mod_extras', 'Vehicle Extras'),
	('mod_exterior', 'Vehicle Exterior'),
	('mod_interior', 'Vehicle Interior'),
	('mod_fender', 'Vehicle Fender'),
	('mod_frame', 'Vehicle Chassis'),
	('mod_frontbumper', 'Vehicle Front Bumper'),
	('mod_grille', 'Vehicle Grille'),
	('mod_hood', 'Vehicle Hood'),
	('mod_horn', 'Vehicle Horn'),
	('mod_light', 'Vehicle Light'),
	('mod_livery', 'Vehicle Livery'),
	('mod_neon', 'Vehicle Neon'),
	('mod_plate', 'Vehicle Plate'),
	('mod_rearbumper', 'Vehicle Rear Bumper'),
	('mod_respray', 'Vehicle Respray'),
	('mod_rim', 'Vehicle Rim'),
	('mod_roof', 'Vehicle Roof'),
	('mod_sideskirt', 'Vehicle Side Skirt'),
	('mod_spoiler', 'Vehicle Spoiler'),
	('mod_tyresmoke', 'Vehicle Tyre Smoke'),
	('mod_windowtint', 'Vehicle Window Tint'),
	('mod_bullettires', 'Bulletproof Tires'),
	('mod_drifttires', 'Drift Tires'),
	('mod_stocktires', 'Stock Tires')
;
```

</details>

<details>

<summary><strong>QBCore</strong></summary>

1. Navigate to `qb-core/shared/items.lua` and open up the file.
2. Insert the following items into the file:

<pre class="language-lua"><code class="lang-lua">    -- Kits | T1GER Tuning System
    ['tuner_tablet']          = {['name'] = 'tuner_tablet', 		['label'] = 'Tuner Tablet',		['weight'] = 1,		['type'] = 'item',		['image'] = 'tuner_tablet.png',			['unique'] = false,		['useable'] = true,	        ['shouldClose'] = true,		['combinable'] = nil,	['description'] = 'Tuner Tablet used by tuners'},
    ['tuner_repairkit']      = {['name'] = 'tuner_repairkit',	        ['label'] = 'Tuner Repair Kit',		['weight'] = 1,		['type'] = 'item',		['image'] = 'tuner_repairkit.png',		['unique'] = false,		['useable'] = true,	        ['shouldClose'] = true,		['combinable'] = nil,	['description'] = 'Repair Kit used by tuners'},
    ['tuner_enghoist']    = {['name'] = 'tuner_enghoist',	        ['label'] = 'Tuner Engine Hoist',	['weight'] = 1,		['type'] = 'item',		['image'] = 'tuner_enghoist.png',		['unique'] = false,		['useable'] = true,	        ['shouldClose'] = true,		['combinable'] = nil,	['description'] = 'Engine Hoist used by tuners'},
    ['nos_shots_bottle']     = {['name'] = 'nos_shots_bottle',	        ['label'] = 'NOS 10-Shots (1lb)',	['weight'] = 3,		['type'] = 'item',		['image'] = 'nos_shots_bottle.png',		['unique'] = false,		['useable'] = true,	        ['shouldClose'] = true,		['combinable'] = nil,	['description'] = 'NOS Bottle (1lb) containing 10 shots, to be add in vehicles'},
    ['nos_empty_bottle']     = {['name'] = 'nos_empty_bottle',	        ['label'] = 'NOS Empty (1lb)',		['weight'] = 1,		['type'] = 'item',		['image'] = 'nos_empty_bottle.png',		['unique'] = false,		['useable'] = true,	        ['shouldClose'] = true,		['combinable'] = nil,	['description'] = 'Empty NOS Bottle (1lb) without any shots. Can be refilled.'},
    ['nos_purge_dye']     = {['name'] = 'nos_purge_dye',	        ['label'] = 'NOS Purge Dye',		['weight'] = 1,		['type'] = 'item',		['image'] = 'nos_purge_dye.png',		['unique'] = false,		['useable'] = true,	        ['shouldClose'] = true,		['combinable'] = nil,	['description'] = 'NOS Purge Dye to alter color using RGB.'},
    -- Mods | T1GER Tuning System
    ['mod_engine']           = {['name'] = 'mod_engine', 		['label'] = 'Vehicle Engine', 		['weight'] = 1,		['type'] = 'item',		['image'] = 'mod_engine.png', 			['unique'] = false,		['useable'] = true,	        ['shouldClose'] = true,		['combinable'] = nil,	['description'] = 'T1GER Tuning - Vehicle Engine Mod'},
    ['mod_brakes']           = {['name'] = 'mod_brakes', 		['label'] = 'Vehicle Brake', 		['weight'] = 1,		['type'] = 'item',		['image'] = 'mod_brakes.png', 			['unique'] = false,		['useable'] = true,	        ['shouldClose'] = true,		['combinable'] = nil,	['description'] = 'T1GER Tuning - Vehicle Brake Mod'},
    ['mod_transmission']     = {['name'] = 'mod_transmission', 	        ['label'] = 'Vehicle Transmission', ['weight'] = 1,		['type'] = 'item',		['image'] = 'mod_transmission.png', 	['unique'] = false,		['useable'] = true,	        ['shouldClose'] = true,		['combinable'] = nil,	['description'] = 'T1GER Tuning - Vehicle Transmission Mod'},
    ['mod_suspension']       = {['name'] = 'mod_suspension', 	        ['label'] = 'Vehicle Suspension', 	['weight'] = 1,		['type'] = 'item',		['image'] = 'mod_suspension.png', 		['unique'] = false,		['useable'] = true,	        ['shouldClose'] = true,		['combinable'] = nil,	['description'] = 'T1GER Tuning - Vehicle Suspension Mod'},
    ['mod_armor']            = {['name'] = 'mod_armor', 		['label'] = 'Vehicle Armor', 		['weight'] = 1,		['type'] = 'item',		['image'] = 'mod_armor.png', 			['unique'] = false,		['useable'] = true,	        ['shouldClose'] = true,		['combinable'] = nil,	['description'] = 'T1GER Tuning - Vehicle Armor Mod'},
    ['mod_turbo']            = {['name'] = 'mod_turbo', 		['label'] = 'Vehicle Turbo', 		['weight'] = 1,		['type'] = 'item',		['image'] = 'mod_turbo.png', 			['unique'] = false,		['useable'] = true,	        ['shouldClose'] = true,		['combinable'] = nil,	['description'] = 'T1GER Tuning - Vehicle Turbo Mod'},
    ['mod_exhaust']          = {['name'] = 'mod_exhaust', 		['label'] = 'Vehicle Exhaust', 		['weight'] = 1,		['type'] = 'item',		['image'] = 'mod_exhaust.png', 			['unique'] = false,		['useable'] = true,	        ['shouldClose'] = true,		['combinable'] = nil,	['description'] = 'T1GER Tuning - Vehicle Exhaust Mod'},
    ['mod_extras']           = {['name'] = 'mod_extras', 		['label'] = 'Vehicle Extras', 		['weight'] = 1,		['type'] = 'item',		['image'] = 'mod_extras.png', 			['unique'] = false,		['useable'] = true,	        ['shouldClose'] = true,		['combinable'] = nil,	['description'] = 'T1GER Tuning - Vehicle Extras Mod'},
    ['mod_exterior']         = {['name'] = 'mod_exterior', 		['label'] = 'Vehicle Exterior', 	['weight'] = 1,		['type'] = 'item',		['image'] = 'mod_exterior.png', 		['unique'] = false,		['useable'] = true,	        ['shouldClose'] = true,		['combinable'] = nil,	['description'] = 'T1GER Tuning - Vehicle Exterior Mod'},
    ['mod_interior']         = {['name'] = 'mod_interior', 		['label'] = 'Vehicle Interior', 	['weight'] = 1,		['type'] = 'item',		['image'] = 'mod_interior.png', 		['unique'] = false,		['useable'] = true,	        ['shouldClose'] = true,		['combinable'] = nil,	['description'] = 'T1GER Tuning - Vehicle Interior Mod'},
    ['mod_fender']           = {['name'] = 'mod_fender', 		['label'] = 'Vehicle Fender', 		['weight'] = 1,		['type'] = 'item',		['image'] = 'mod_fender.png', 			['unique'] = false,		['useable'] = true,	        ['shouldClose'] = true,		['combinable'] = nil,	['description'] = 'T1GER Tuning - Vehicle Fender Mod'},
    ['mod_frame']            = {['name'] = 'mod_frame', 		['label'] = 'Vehicle Chassis', 		['weight'] = 1,		['type'] = 'item',		['image'] = 'mod_frame.png', 			['unique'] = false,		['useable'] = true,	        ['shouldClose'] = true,		['combinable'] = nil,	['description'] = 'T1GER Tuning - Vehicle Chassis Mod'},
    ['mod_frontbumper']      = {['name'] = 'mod_frontbumper', 	        ['label'] = 'Vehicle Front Bumper', ['weight'] = 1,		['type'] = 'item',		['image'] = 'mod_frontbumper.png', 	    ['unique'] = false,		['useable'] = true,	        ['shouldClose'] = true,		['combinable'] = nil,	['description'] = 'T1GER Tuning - Vehicle Front Bumper Mod'},
    ['mod_grille']           = {['name'] = 'mod_grille', 		['label'] = 'Vehicle Grille', 		['weight'] = 1,		['type'] = 'item',		['image'] = 'mod_grille.png', 			['unique'] = false,		['useable'] = true,	        ['shouldClose'] = true,		['combinable'] = nil,	['description'] = 'T1GER Tuning - Vehicle Grille Mod'},
    ['mod_hood']             = {['name'] = 'mod_hood', 		        ['label'] = 'Vehicle Hood', 		['weight'] = 1,		['type'] = 'item',		['image'] = 'mod_hood.png', 			['unique'] = false,		['useable'] = true,	        ['shouldClose'] = true,		['combinable'] = nil,	['description'] = 'T1GER Tuning - Vehicle Hood Mod'},
    ['mod_horn']             = {['name'] = 'mod_horn', 		        ['label'] = 'Vehicle Horn', 		['weight'] = 1,		['type'] = 'item',		['image'] = 'mod_horn.png', 			['unique'] = false,		['useable'] = true,	        ['shouldClose'] = true,		['combinable'] = nil,	['description'] = 'T1GER Tuning - Vehicle Horn Mod'},
    ['mod_light']            = {['name'] = 'mod_light', 		['label'] = 'Vehicle Light', 		['weight'] = 1,		['type'] = 'item',		['image'] = 'mod_light.png', 			['unique'] = false,		['useable'] = true,	        ['shouldClose'] = true,		['combinable'] = nil,	['description'] = 'T1GER Tuning - Vehicle Light Mod'},
    ['mod_livery']           = {['name'] = 'mod_livery', 		['label'] = 'Vehicle Livery', 		['weight'] = 1,		['type'] = 'item',		['image'] = 'mod_livery.png', 			['unique'] = false,		['useable'] = true,	        ['shouldClose'] = true,		['combinable'] = nil,	['description'] = 'T1GER Tuning - Vehicle Livery Mod'},
    ['mod_neon']             = {['name'] = 'mod_neon', 		        ['label'] = 'Vehicle Neon', 		['weight'] = 1,		['type'] = 'item',		['image'] = 'mod_neon.png', 			['unique'] = false,		['useable'] = true,	        ['shouldClose'] = true,		['combinable'] = nil,	['description'] = 'T1GER Tuning - Vehicle Neon Mod'},
    ['mod_plate']            = {['name'] = 'mod_plate', 		['label'] = 'Vehicle Plate', 		['weight'] = 1,		['type'] = 'item',		['image'] = 'mod_plate.png', 			['unique'] = false,		['useable'] = true,	        ['shouldClose'] = true,		['combinable'] = nil,	['description'] = 'T1GER Tuning - Vehicle Plate Mod'},
    ['mod_rearbumper']       = {['name'] = 'mod_rearbumper', 	        ['label'] = 'Vehicle Rear Bumper', 	['weight'] = 1,		['type'] = 'item',		['image'] = 'mod_rearbumper.png', 		['unique'] = false,		['useable'] = true,	        ['shouldClose'] = true,		['combinable'] = nil,	['description'] = 'T1GER Tuning - Vehicle Rear Bumper Mod'},
    ['mod_respray']          = {['name'] = 'mod_respray', 		['label'] = 'Vehicle Respray', 		['weight'] = 1,		['type'] = 'item',		['image'] = 'mod_respray.png', 			['unique'] = false,		['useable'] = true,	        ['shouldClose'] = true,		['combinable'] = nil,	['description'] = 'T1GER Tuning - Vehicle Respray Mod'},
    ['mod_rim']              = {['name'] = 'mod_rim', 		        ['label'] = 'Vehicle Rim', 		    ['weight'] = 1,		['type'] = 'item',		['image'] = 'mod_rim.png', 				['unique'] = false,		['useable'] = true,	        ['shouldClose'] = true,		['combinable'] = nil,	['description'] = 'T1GER Tuning - Vehicle Rim Mod'},
    ['mod_roof']             = {['name'] = 'mod_roof', 		        ['label'] = 'Vehicle Roof', 		['weight'] = 1,		['type'] = 'item',		['image'] = 'mod_roof.png', 			['unique'] = false,		['useable'] = true,	        ['shouldClose'] = true,		['combinable'] = nil,	['description'] = 'T1GER Tuning - Vehicle Roof Mod'},
    ['mod_sideskirt']        = {['name'] = 'mod_sideskirt', 	        ['label'] = 'Vehicle Side Skirt', 	['weight'] = 1,		['type'] = 'item',		['image'] = 'mod_sideskirt.png', 		['unique'] = false,		['useable'] = true,	        ['shouldClose'] = true,		['combinable'] = nil,	['description'] = 'T1GER Tuning - Vehicle Side Skirt Mod'},
    ['mod_spoiler']          = {['name'] = 'mod_spoiler', 		['label'] = 'Vehicle Spoiler', 		['weight'] = 1,		['type'] = 'item',		['image'] = 'mod_spoiler.png', 			['unique'] = false,		['useable'] = true,	        ['shouldClose'] = true,		['combinable'] = nil,	['description'] = 'T1GER Tuning - Vehicle Spoiler Mod'},
    ['mod_tyresmoke']        = {['name'] = 'mod_tyresmoke', 	        ['label'] = 'Vehicle Tyre Smoke', 	['weight'] = 1,		['type'] = 'item',		['image'] = 'mod_tyresmoke.png', 		['unique'] = false,		['useable'] = true,	        ['shouldClose'] = true,		['combinable'] = nil,	['description'] = 'T1GER Tuning - Vehicle Tyre Smoke Mod'},
    ['mod_windowtint']       = {['name'] = 'mod_windowtint', 	        ['label'] = 'Vehicle Window Tint', 	['weight'] = 1,		['type'] = 'item',		['image'] = 'mod_windowtint.png', 		['unique'] = false,		['useable'] = true,	        ['shouldClose'] = true,		['combinable'] = nil,	['description'] = 'T1GER Tuning - Vehicle Window Tint Mod'},
    ['mod_bullettires']      = {['name'] = 'mod_bullettires', 	        ['label'] = 'Bulletproof Tires', 	['weight'] = 1,		['type'] = 'item',		['image'] = 'mod_bullettires.png', 		['unique'] = false,		['useable'] = true,	        ['shouldClose'] = true,		['combinable'] = nil,	['description'] = 'T1GER Tuning - Bulletproof Tires Mod'},
    ['mod_drifttires']       = {['name'] = 'mod_drifttires', 	        ['label'] = 'Drift Tires', 		    ['weight'] = 1,		['type'] = 'item',		['image'] = 'mod_drifttires.png', 		['unique'] = false,		['useable'] = true,	        ['shouldClose'] = true,		['combinable'] = nil,	['description'] = 'T1GER Tuning - Drift Tires Mod'},
    ['mod_stocktires']       = {['name'] = 'mod_stocktires', 	        ['label'] = 'Stock Tires', 		    ['weight'] = 1,		['type'] = 'item',		['image'] = 'mod_stocktires.png', 		['unique'] = false,		['useable'] = true,	        ['shouldClose'] = true,		['combinable'] = nil,	['description'] = 'T1GER Tuning - Stock Tires Mod'},
    -- Materials | T1GER Tuning System
<strong>    ['scrap_metal']	     = {['name'] = 'scrap_metal',		['label'] = 'Scrap Metal',          ['weight'] = 1,		['type'] = 'item',		['image'] = 'scrap_metal.png', 			['unique'] = false,		['useable'] = false,		['shouldClose'] = true,		['combinable'] = nil,	['description'] = 'Material - Scrap Metal'},
</strong>    ['steel']                = {['name'] = 'steel', 			['label'] = 'Steel', 				['weight'] = 1,		['type'] = 'item',		['image'] = 'steel.png', 				['unique'] = false,		['useable'] = false,		['shouldClose'] = true,		['combinable'] = nil,	['description'] = 'Material - Steel'},
    ['aluminium']            = {['name'] = 'aluminium', 		['label'] = 'Aluminium', 			['weight'] = 1,		['type'] = 'item',		['image'] = 'aluminium.png', 			['unique'] = false,		['useable'] = false,		['shouldClose'] = true,		['combinable'] = nil,	['description'] = 'Material - Aluminium'},
    ['plastic']              = {['name'] = 'plastic', 			['label'] = 'Plastic', 				['weight'] = 1,		['type'] = 'item',		['image'] = 'plastic.png', 				['unique'] = false,		['useable'] = false,		['shouldClose'] = true,		['combinable'] = nil,	['description'] = 'Material - Plastic'},
    ['rubber']               = {['name'] = 'rubber', 			['label'] = 'Rubber', 				['weight'] = 1,		['type'] = 'item',		['image'] = 'rubber.png', 				['unique'] = false,		['useable'] = false,		['shouldClose'] = true,		['combinable'] = nil,	['description'] = 'Material - Rubber'},
    ['electric_scrap']       = {['name'] = 'electric_scrap', 	        ['label'] = 'Electric Scrap', 		['weight'] = 1,		['type'] = 'item',		['image'] = 'electric_scrap.png', 		['unique'] = false,		['useable'] = false,		['shouldClose'] = true,		['combinable'] = nil,	['description'] = 'Material - Electric Scrap'},
    ['glass']                = {['name'] = 'glass', 			['label'] = 'Glass', 				['weight'] = 1,		['type'] = 'item',		['image'] = 'glass.png', 				['unique'] = false,		['useable'] = false,		['shouldClose'] = true,		['combinable'] = nil,	['description'] = 'Material - Glass'},
    ['copper']               = {['name'] = 'copper', 			['label'] = 'Copper', 				['weight'] = 1,		['type'] = 'item',		['image'] = 'copper.png', 				['unique'] = false,		['useable'] = false,		['shouldClose'] = true,		['combinable'] = nil,	['description'] = 'Material - Copper'},
    ['carbon_fiber']         = {['name'] = 'carbon_fiber', 		['label'] = 'Carbon Fiber', 		['weight'] = 1,		['type'] = 'item',		['image'] = 'carbon_fiber.png', 		['unique'] = false,		['useable'] = false,		['shouldClose'] = true,		['combinable'] = nil,	['description'] = 'Material - Carbon Fiber'},
<strong>    ['brass']                = {['name'] = 'brass', 			['label'] = 'Brass', 				['weight'] = 1,		['type'] = 'item',		['image'] = 'brass.png', 				['unique'] = false,		['useable'] = false,		['shouldClose'] = true,		['combinable'] = nil,	['description'] = 'Material - Brass'},
</strong><strong>    ['synthetic_oil']        = {['name'] = 'synthetic_oil', 		['label'] = 'Synthetic Oil', 		['weight'] = 1,		['type'] = 'item',		['image'] = 'synthetic_oil.png', 		['unique'] = false,		['useable'] = false,		['shouldClose'] = true,		['combinable'] = nil,	['description'] = 'Material - Synthetic Oil'},
</strong>    ['acid']                 = {['name'] = 'acid', 				['label'] = 'Synthetic Acid', 		['weight'] = 1,		['type'] = 'item',		['image'] = 'acid.png', 				['unique'] = false,		['useable'] = false,		['shouldClose'] = true,		['combinable'] = nil,	['description'] = 'Material - Synthetic Acid'},
</code></pre>

<mark style="color:orange;">**Please note, if you already have**</mark> [T1GER Mechanic System](/resources/t1ger-mechanic-system) <mark style="color:orange;">**installed, skip the materials as they are already added.**</mark>&#x20;

</details>

<details>

<summary><strong>OX Inventory</strong></summary>

1. Navigate to `ox_inventory/data/items.lua`.
2. Insert the following items into the file:

```lua
    -- Kits
    ["tuner_tablet"] = {
        label = "Tuner Tablet",
        weight = 1,
        stack = true,
        close = true,
    },
    ["tuner_repairkit"] = {
        label = "Tuner Repair Kit",
        weight = 1,
        stack = true,
        close = true,
    },
    ["tuner_enghoist"] = {
        label = "Tuner Engine Hoist",
        weight = 1,
        stack = true,
        close = true,
    },
    ["nos_shots_bottle"] = {
        label = "NOS 10-Shots (1lb)",
        weight = 3,
        stack = true,
        close = true,
    },
    ["nos_empty_bottle"] = {
        label = "NOS Empty (1lb)",
        weight = 1,
        stack = true,
        close = true,
    },
    ["nos_purge_dye"] = {
        label = "NOS Purge Dye",
        weight = 1,
        stack = true,
        close = true,
    },
    -- Materials:
    ["scrap_metal"] = {
        label = "Scrap Metal",
        weight = 1,
        stack = true,
        close = true,
    },
    ["steel"] = {
        label = "Steel",
        weight = 1,
        stack = true,
        close = true,
    },
    ["aluminium"] = {
        label = "Aluminium",
        weight = 1,
        stack = true,
        close = true,
    },
    ["plastic"] = {
        label = "Plastic",
        weight = 1,
        stack = true,
        close = true,
    },
    ["rubber"] = {
        label = "Rubber",
        weight = 1,
        stack = true,
        close = true,
    },
    ["electric_scrap"] = {
        label = "Electric Scrap",
        weight = 1,
        stack = true,
        close = true,
    },
    ["glass"] = {
        label = "Glass",
        weight = 1,
        stack = true,
        close = true,
    },
    ["copper"] = {
        label = "Copper",
        weight = 1,
        stack = true,
        close = true,
    },
    ["carbon_fiber"] = {
        label = "Carbon Fiber",
        weight = 1,
        stack = true,
        close = true,
    },
    ["brass"] = {
        label = "Brass",
        weight = 1,
        stack = true,
        close = true,
    },
    ["synthetic_oil"] = {
        label = "Synthetic Oil",
        weight = 1,
        stack = true,
        close = true,
    },
    ["acid"] = {
        label = "Synthetic Acid",
        weight = 1,
        stack = true,
        close = true,
    },
    -- Mods:
    ["mod_engine"] = {
        label = "Vehicle Engine",
        weight = 1,
        stack = true,
        close = true,
    },
    ["mod_brakes"] = {
        label = "Vehicle Brake",
        weight = 1,
        stack = true,
        close = true,
    },
    ["mod_transmission"] = {
        label = "Vehicle Transmission",
        weight = 1,
        stack = true,
        close = true,
    },
    ["mod_suspension"] = {
        label = "Vehicle Suspension",
        weight = 1,
        stack = true,
        close = true,
    },
    ["mod_armor"] = {
        label = "Vehicle Armor",
        weight = 1,
        stack = true,
        close = true,
    },
    ["mod_turbo"] = {
        label = "Vehicle Turbo",
        weight = 1,
        stack = true,
        close = true,
    },
    ["mod_exhaust"] = {
        label = "Vehicle Exhaust",
        weight = 1,
        stack = true,
        close = true,
    },
    ["mod_extras"] = {
        label = "Vehicle Extras",
        weight = 1,
        stack = true,
        close = true,
    },
    ["mod_exterior"] = {
        label = "Vehicle Exterior",
        weight = 1,
        stack = true,
        close = true,
    },
    ["mod_interior"] = {
        label = "Vehicle Interior",
        weight = 1,
        stack = true,
        close = true,
    },
    ["mod_fender"] = {
        label = "Vehicle Fender",
        weight = 1,
        stack = true,
        close = true,
    },
    ["mod_frame"] = {
        label = "Vehicle Chassis",
        weight = 1,
        stack = true,
        close = true,
    },
    ["mod_frontbumper"] = {
        label = "Vehicle Front Bumper",
        weight = 1,
        stack = true,
        close = true,
    },
    ["mod_grille"] = {
        label = "Vehicle Grille",
        weight = 1,
        stack = true,
        close = true,
    },
    ["mod_hood"] = {
        label = "Vehicle Hood",
        weight = 1,
        stack = true,
        close = true,
    },
    ["mod_horn"] = {
        label = "Vehicle Horn",
        weight = 1,
        stack = true,
        close = true,
    },
    ["mod_light"] = {
        label = "Vehicle Light",
        weight = 1,
        stack = true,
        close = true,
    },
    ["mod_livery"] = {
        label = "Vehicle Livery",
        weight = 1,
        stack = true,
        close = true,
    },
    ["mod_neon"] = {
        label = "Vehicle Neon",
        weight = 1,
        stack = true,
        close = true,
    },
    ["mod_plate"] = {
        label = "Vehicle Plate",
        weight = 1,
        stack = true,
        close = true,
    },
    ["mod_rearbumper"] = {
        label = "Vehicle Rear Bumper",
        weight = 1,
        stack = true,
        close = true,
    },
    ["mod_respray"] = {
        label = "Vehicle Respray",
        weight = 1,
        stack = true,
        close = true,
    },
    ["mod_rim"] = {
        label = "Vehicle Rim",
        weight = 1,
        stack = true,
        close = true,
    },
    ["mod_roof"] = {
        label = "Vehicle Roof",
        weight = 1,
        stack = true,
        close = true,
    },
    ["mod_sideskirt"] = {
        label = "Vehicle Side Skirt",
        weight = 1,
        stack = true,
        close = true,
    },
    ["mod_spoiler"] = {
        label = "Vehicle Spoiler",
        weight = 1,
        stack = true,
        close = true,
    },
    ["mod_tyresmoke"] = {
        label = "Vehicle Tyre Smoke",
        weight = 1,
        stack = true,
        close = true,
    },
    ["mod_windowtint"] = {
        label = "Vehicle Window Tint",
        weight = 1,
        stack = true,
        close = true,
    },
    ["mod_bullettires"] = {
        label = "Bulletproof Tires",
        weight = 1,
        stack = true,
        close = true,
    },
    ["mod_drifttires"] = {
        label = "Drift Tires",
        weight = 1,
        stack = true,
        close = true,
    },
    ["mod_stocktires"] = {
        label = "Stock Tires",
        weight = 1,
        stack = true,
        close = true,
    },
```

<mark style="color:orange;">**Please note, if you already have**</mark> [T1GER Mechanic System](/resources/t1ger-mechanic-system) <mark style="color:orange;">**installed, skip the materials as they are already added.**</mark>&#x20;

</details>

{% hint style="success" %}
Inventory item icons/images can be found in the resource folder or download them directly here:
{% endhint %}

{% file src="/files/F8m9n9LOxDCpgRpm2UN9" %}
Inventory Icons
{% endfile %}

## 6 - (Automatic) Job Creation

The resource features automatic job creation in runtime when creating new shops.

<details>

<summary>ESX</summary>

<mark style="color:red;">**With recent ESX updates, you may need to navigate to**</mark><mark style="color:red;">**&#x20;**</mark><mark style="color:red;">**`es_extended/server/modules/createJob.lua`**</mark><mark style="color:red;">**&#x20;**</mark><mark style="color:red;">**and replace ESX.CreateJob() with the function below.**</mark>&#x20;

If you don't have that folder/file, then navigate to `es_extended/server/functions.lua` and find the following function:

```lua
ESX.CreateJob()
```

If you cannot find the function, do not worry. You can either update your `es_extended` to latest version or insert the following function in the bottom of the file:&#x20;

```lua
--- Create Job at Runtime
--- @param name string
--- @param label string
--- @param grades table
function ESX.CreateJob(name, label, grades)
	if not name then
		return print('[^3WARNING^7] missing argument `name(string)` while creating a job')
	end

	if not label then
		return print('[^3WARNING^7] missing argument `label(string)` while creating a job')
	end

	if not grades or not next(grades) then
		return print('[^3WARNING^7] missing argument `grades(table)` while creating a job!')
	end

	local parameters = {}
	local job = { name = name, label = label, grades = {} }

	for _, v in pairs(grades) do
		job.grades[tostring(v.grade)] = { job_name = name, grade = v.grade, name = v.name, label = v.label, salary = v.salary, skin_male = v.skin_male or '{}', skin_female = v.skin_female or '{}' }
		parameters[#parameters + 1] = { name, v.grade, v.name, v.label, v.salary, v.skin_male or '{}', v.skin_female or '{}'}
	end

	MySQL.insert('INSERT IGNORE INTO jobs (name, label) VALUES (?, ?)', { name, label })
	MySQL.prepare('INSERT INTO job_grades (job_name, grade, name, label, salary, skin_male, skin_female) VALUES (?, ?, ?, ?, ?, ?, ?)', parameters)

	ESX.Jobs[name] = job
end
```

If you already have such function, make sure the function looks exactly like this. If not, then replace the function you have with this.&#x20;

</details>

<details>

<summary>QBCore</summary>

If you are on `qb-core` framework you don't need to alter any functions.&#x20;

However, your 3rd party resources (phones, doorlocks, huds etc.), might not recognize the newly created job or not sync properly.

This happens because those 3rd party resources does not fetch the added jobs, the updated core, and sync it with their resource. For the records, we are using the official `qb-core` [AddJob export](https://docs.qbcore.org/qbcore-documentation/qb-core/shared-exports#exports-qb-core-addjob), so it's totally out of our hands (maybe you can push/encourage them to add support for jobs created in runtime using the export).

Creators of said resources might not put time in to add compatibility for the export by `qb-core`, so here's a temporary workaround you can utilize:

1. Navigate to `qb-core/shared/jobs.lua`.
2. Insert the job you want to use (or the job you already created in-game) and that's it.

#### Example:

Here's an example for a tuner job, called `t1gertuner`.

```lua
['t1gertuner'] = {
    label = 'T1GER Tuner',
    defaultDuty = true,
    offDutyPay = false,
    grades = {
        ['0'] = {
            name = 'Recruit',
            payment = 50
        },
        ['1'] = {
            name = 'Employee',
            payment = 75
        },
        ['2'] = {
            name = 'Boss',
            isboss = true,
            payment = 100
        },
    },
},
```

It's very important that the job name (`'t1gertuner'`) matches the [Broken mention](broken://pages/KfQsoWfkfaudaW0HauXu#job-name) field in the [Broken mention](broken://pages/KfQsoWfkfaudaW0HauXu#create-shop) menu. Also make sure the very last grade you have, has the `isboss = true` parameter.&#x20;

When using the Shop Creator, it will auto-fetch the `job label` and `job grades` based on the `job name` you enter, so this way you can pre-configure some jobs in your `shared/jobs.lua` and use these.&#x20;

The In-game in the shop-creator for this particular job, should look like this:

![](https://2167335559-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MiDWIMbFBeXle-trOlk%2Fuploads%2FJL1GnOttHtjjnBXODz1Q%2Fimage.png?alt=media\&token=714d04e6-48a6-4a7a-b72a-c733191cfcff)

Where:

* Shop Name: is a user-defined name for the shop.
* Job Name: is the job name (<mark style="color:red;">lower char, no spaces and no special chars</mark>).
* Job Label: is the displayed label of the job.

Now, the resource will automatically fetch the stored data for this job.&#x20;

</details>

## 7 - Saving Vehicle Mods

All vehicle mods are saved using `vehicle properties` and in order to sync properly with your 3rd party resources you need to make two simple changes. Refer to [Vehicle Properties](/resources/t1ger-library/installation/vehicle-properties) and follow the [Vehicle Properties](/resources/t1ger-library/installation/vehicle-properties#setup) instructions.&#x20;

## 8 - Configuration

#### Language

Navigate to `t1ger_tuningsystem/shared/language.lua` to customize all strings to translate them into your preferred language.

{% content-ref url="/spaces/-MiDWIMbFBeXle-trOlk/pages/NbWHAEQdayQYQW2Os0RH" %}
[Broken mention](broken://spaces/-MiDWIMbFBeXle-trOlk/pages/NbWHAEQdayQYQW2Os0RH)
{% endcontent-ref %}

#### Config

Navigate to `t1ger_tuningsystem/shared/config.lua` to configure settings & options to your liking. Make sure to read the end-line comments.

* If you enable `UseSocietyAccount` option, make sure you have setup [Society Account](/resources/t1ger-library/installation/society-account) in `t1ger_lib`.

#### Mods

Navigate to `t1ger_tuningsystem/shared/mods.lua` to customize all the mods, including pricing and so on. Refer to [Vehicle Mods](/resources/t1ger-tuning-system/guides/vehicle-mods).

## 9 - Ready

Once you are fully done, you have successfully installed T1GER Tuning System. Now restart your server and enjoy the resource!


# API

In this section you'll find various exports & events to be used/integrated with other 3rd party resources.

{% content-ref url="/spaces/-MiDWIMbFBeXle-trOlk/pages/Aualjc2ZAwkELYruPGny" %}
[Client](/resources/t1ger-tuning-system/api/client)
{% endcontent-ref %}

{% content-ref url="/spaces/-MiDWIMbFBeXle-trOlk/pages/34J1vJqLPCf9PDqBLCsl" %}
[Server](/resources/t1ger-tuning-system/api/server)
{% endcontent-ref %}


# Client

In this section you can find client-sided exports and events to be used/integrated with other resources.

## Exports

### Is Player Tuner

Returns whether the player is tuner or not. If tuner it also returns the shopId.

```lua
exports['t1ger_tuningsystem']:IsPlayerTuner()
-- returns boolean(true/false). If true, also returns INT (shopId)
-- Example:
local isTuner, shopId = exports['t1ger_tuningsystem']:IsPlayerTuner()
```

**Returns:**

* Boolean(true/false)
* INT(shopId) - only returns if boolean is true

### **Get Item Info**

```lua
exports['t1ger_tuningsystem']:GetItemInfo(itemName)
-- itemName (string): the name of the item
-- Example:
local itemInfo = exports['t1ger_tuningsystem']:GetItemInfo(itemName)
```

**Returns:**

* Table(name, label, price, icon)

### **Get Vehicle Nitrous Properties**

```lua
exports['t1ger_tuningsystem']:GetVehicleNitrousProperties(vehicle)
-- vehicle(int): entity handle for the vehicle
-- Example:
local nitrous = exports['t1ger_tuningsystem']:GetVehicleNitrousProperties(vehicle)
```

**Returns:**

* Table(size, shots, burst, color)

### **Get Vehicle Dyno Properties**

```lua
exports['t1ger_tuningsystem']:GetVehicleDynoProperties(vehicle)
-- vehicle(int): entity handle for the vehicle
-- Example:
local dyno = exports['t1ger_tuningsystem']:GetVehicleDynoProperties(vehicle)
```

**Returns:**

* Table(torque, power, brakes)

## Events

### Add Account Money

Adds x money to the given account.

```lua
TriggerServerEvent('tuningsystem:server:addAccountMoney', shopId, amount)
-- shopId(INT): tuner shop id
-- amount(INT): amount of money to add to the account
```

### Remove Account Money

Removes x money from the given account.

```lua
TriggerServerEvent('tuningsystem:server:removeAccountMoney', shopId, amount)
-- shopId(INT): tuner shop id
-- amount(INT): amount of money to remove from the account
```

### Set Account Money

Sets the account balance of the given account to x.

```lua
TriggerServerEvent('tuningsystem:server:setAccountMoney', shopId, amount)
-- shopId(INT): tuner shop id
-- amount(INT): amount of money to set the new account balance to.
```


# Server

In this section you can find server-sided exports and events to be used/integrated with other resources.

## Exports

### Get Account Money

Gets the account balance/money from a given shop.

```lua
exports['t1ger_tuningsystem']:GetAccountMoney(shopId)
-- shopId(INT): tuner shop id
```

### Add Account Money

Adds x money to the given account.

```lua
exports['t1ger_tuningsystem']:AddAccountMoney(shopId, amount)
-- shopId(INT): tuner shop id
-- amount(INT): amount of money to add to the account
```

### Remove Account Money

Removes x money from the given account.&#x20;

```lua
exports['t1ger_tuningsystem']:RemoveAccountMoney(shopId, amount)
-- shopId(INT): tuner shop id
-- amount(INT): amount of money to remove from the account
```

### Set Account Money

Sets the account balance of the given account to x.

```lua
exports['t1ger_tuningsystem']:SetAccountMoney(shopId, amount)
-- shopId(INT): tuner shop id
-- amount(INT): amount of money to set the new account balance to.
```

## Events


# Troubleshoot

All common issues and solutions will be available here.

{% content-ref url="/spaces/-MiDWIMbFBeXle-trOlk/pages/MdS44Is5XZ2BUC9W0KNW" %}
[Common Issues](/resources/t1ger-tuning-system/troubleshoot/common-issues)
{% endcontent-ref %}

{% content-ref url="/spaces/-MiDWIMbFBeXle-trOlk/pages/vlVu1ulRWGLBVunNRqOI" %}
[Error Codes](/resources/t1ger-tuning-system/troubleshoot/error-codes)
{% endcontent-ref %}


# Common Issues

In this section, you'll find a list of frequently encountered issues, along with detailed solutions and troubleshooting steps.

## README

Before we proceed, please ensure the following:

1. You have followed [Installation](/resources/t1ger-tuning-system/installation) correctly and every steps.
2. You have not touched nor edited files, except for `shared/` files.
3. You have not made any custom changes.

## Failed to insert job

If you are getting this message in the console, like this:

<div align="left"><figure><img src="https://2167335559-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MiDWIMbFBeXle-trOlk%2Fuploads%2FpuPMaNLpT7wBkxkYqthI%2Fimage.png?alt=media&amp;token=add67c85-29be-418f-9ad6-da5f7f49907c" alt=""><figcaption></figcaption></figure></div>

1. go to `es_extended/server/modules/createJob.lua`
2. find the function called `ESX.CreateJob`
3. replace the function with this code:

```lua
--- Create Job at Runtime
--- @param name string
--- @param label string
--- @param grades table
function ESX.CreateJob(name, label, grades)
    if not name then
        return print('[^3WARNING^7] missing argument `name(string)` while creating a job')
    end

    if not label then
        return print('[^3WARNING^7] missing argument `label(string)` while creating a job')
    end

    if not grades or not next(grades) then
        return print('[^3WARNING^7] missing argument `grades(table)` while creating a job!')
    end

    local parameters = {}
    local job = { name = name, label = label, grades = {} }

    for _, v in pairs(grades) do
        job.grades[tostring(v.grade)] = { job_name = name, grade = v.grade, name = v.name, label = v.label, salary = v.salary, skin_male = v.skin_male or '{}', skin_female = v.skin_female or '{}' }
        parameters[#parameters + 1] = { name, v.grade, v.name, v.label, v.salary, v.skin_male or '{}', v.skin_female or '{}'}
    end

    MySQL.insert('INSERT IGNORE INTO jobs (name, label) VALUES (?, ?)', { name, label })
    MySQL.prepare('INSERT INTO job_grades (job_name, grade, name, label, salary, skin_male, skin_female) VALUES (?, ?, ?, ?, ?, ?, ?)', parameters)

    ESX.Jobs[name] = job
end
```

## Q/A

{% hint style="success" %}
**QB Inventory**\
[❓](https://emojipedia.org/question-mark/)  Inventory not opening with qb-inventory

[✔️](https://emojiguide.com/symbols/check-mark/) Download latest qb-inventory. If you don't want to update, then navigate to t1ger\_lib/framework.lua and find the OpenStash function. In here you want to comment out the triggerserverevent for the qb inventory and enable the commented out code.&#x20;
{% endhint %}

{% hint style="success" %}
**No such export GetSharedAccount in ESX Addon Account**\
[❓](https://emojipedia.org/question-mark/)  You are getting an error with no such export GetSharedAccount in resource esx\_addonaccount

[✔️](https://emojiguide.com/symbols/check-mark/) All you need to do is update your esx\_addonaccount to the latest: <https://github.com/esx-framework/esx_addonaccount>
{% endhint %}

asdasd


# Error Codes

Lookup error codes in here to quickly resolve your issues.

## Introduction

In-game in client(F8)-console or server-console you'll notice some error codes. These are prints to quickly solve your issues.&#x20;

## Client

### 7542

This error should give you the shopId(`number`) and a class(`string`). You have a shop in your database with a class name that's not defined in your Config.Markers. The only way for this error to occur is if you rename the index/key strings of the markers. Please revert the changes. You are not allowed to edit the class name(string). It's used as an identifier throughout the script and it will not function.&#x20;

If you have the knowledge, then manually edit the markers column for the given row of the shopId in the database table. Else we recommend you to fully delete that shop (you can do it in-game or through database) and recreate the shop & markers.

## Server


# Guides

{% content-ref url="/spaces/-MiDWIMbFBeXle-trOlk/pages/GqswQHZj0LcVBpMsA3P3" %}
[Commands](/resources/t1ger-tuning-system/guides/commands)
{% endcontent-ref %}

{% content-ref url="/spaces/-MiDWIMbFBeXle-trOlk/pages/vr7TO4Gr3xGlR9V4trS3" %}
[Shops](/resources/t1ger-tuning-system/guides/shops)
{% endcontent-ref %}

{% content-ref url="/spaces/-MiDWIMbFBeXle-trOlk/pages/YrgOrbjZtdph7q9vrQz4" %}
[Markers](/resources/t1ger-tuning-system/guides/markers)
{% endcontent-ref %}

{% content-ref url="/pages/kGbpSdFVZ22uKQ4cAc4A" %}
[Mod Stations](/resources/t1ger-tuning-system/guides/mod-stations)
{% endcontent-ref %}

{% content-ref url="/pages/KKFbY3U2I7nGD198Ss6Q" %}
[Pricing](/resources/t1ger-tuning-system/guides/pricing)
{% endcontent-ref %}

{% content-ref url="/pages/SQgileCXTjp78KRHGzvF" %}
[Mod Orders](/resources/t1ger-tuning-system/guides/mod-orders)
{% endcontent-ref %}

{% content-ref url="/pages/jf0kNejlD5FRtOeqrnjx" %}
[Vehicle Mods](/resources/t1ger-tuning-system/guides/vehicle-mods)
{% endcontent-ref %}

{% content-ref url="/pages/SzvteAqdWXP0iOmlX60t" %}
[Engine Swaps](/resources/t1ger-tuning-system/guides/engine-swaps)
{% endcontent-ref %}

{% content-ref url="/pages/ZE3Lx87xrqDn1NnNHhzt" %}
[Nitrous](/resources/t1ger-tuning-system/guides/nitrous)
{% endcontent-ref %}


# Commands

In this section you'll find usefull chat-commands that can be used in-game.

{% hint style="info" %}
Please note, all these command strings are configurable and can be disabled as well.
{% endhint %}

{% tabs %}
{% tab title="client" %}

<table><thead><tr><th width="280">Command</th><th>Description</th></tr></thead><tbody><tr><td><code>/admintuner</code></td><td>Open the admin mechanic menu.</td></tr><tr><td><code>/workflow:toggleCursor</code></td><td>Toggles workflow cursor.</td></tr><tr><td><code>/workflow:close</code></td><td>Closes workflow UI</td></tr><tr><td><code>/workflow:open</code></td><td>Opens workflow UI</td></tr></tbody></table>
{% endtab %}
{% endtabs %}


# Shops

Guide and instructions on how to properly create shops and manage them

## Shop Creator Configuration

{% hint style="info" %}
First you need to configure `Config.ShopCreator` found inside: `t1ger_tuningsystem/shared/config.lua`
{% endhint %}

```lua
Config.ShopCreator = {
	UseSocietyAccounts = true, -- set true to use qb-banking (must update to latest) or esx_addonaccounts instead of custom account column from the database table.
	Blip = {input = true, sprite = 446, display = 4, scale = 0.75, color = 5}, -- if input = true, set sprite/color in-game, else define settings here to apply for created shop
	Grades = { -- default job grades that are created, once a shop is being created
		{grade = 0, name = 'recruit', label = 'Recruit', salary = 50},
		{grade = 1, name = 'employee', label = 'Employee', salary = 75},
		{grade = 2, name = 'boss', label = 'Boss', salary = 100, isboss = true}
		-- make sure boss grade is the very last one and has the 'isboss = true' as the only one!
	},
	DefaultDuty = true, -- QB CORE ONLY - set default duty on qb core jobs (doesnt matter for esx)
	OffDutyPay = false, -- QB CORE ONLY - set off duty payment on qb core jobs (doesnt matter for esx)
}
```

* **UseSocietyAccount:** `boolean`
  * If this option is set to true, it will use [Society Account](/resources/t1ger-library/installation/society-account) (click for setup/guide) or if set to false, it will use the built-in custom column for account management.&#x20;
* **Blip:** `table`
  * Creates a blip with the given settings.
  * input: `boolean` - if input is true, admins can select blip color and sprite in-game when creating a shop. If false, it will read blip settings from here.
  * sprite: `number` - [reference](https://docs.fivem.net/docs/game-references/blips/#blips)
  * display: `number` - [reference](https://docs.fivem.net/natives/?_0x9029B2F3DA924928)
  * scale: `number` - [reference](https://docs.fivem.net/natives/?_0xD38744167B2FA257)
  * color: `number` - [reference](https://docs.fivem.net/docs/game-references/blips/#blip-colors)
* **Grades:** `table`
  * This table sets the default grades for each created job during the shop creation. You edit the current grades, add or remove grades. Just make sure the last grade (boss grade) has the `isboss = true` parameter.&#x20;
  * grade: `number` - first one must always be 0
  * name: `string` - no capital letters, spaces or special chars!
  * label: `string`
  * salary: `number`
  * isboss: `boolean` - only use for the very last grade
* **DefaultDuty:** `boolean`
  * Set default duty on jobs (only applicable for QBCore)
* **OffDutyPay:** `boolean`
  * Set off duty salary/payment (only applicable for QBCore)

## Tuner Admin Menu <a href="#create-shop" id="create-shop"></a>

In order to create a shop you must use the 'tuner-admin-menu'.&#x20;

<div align="left"><figure><img src="https://2167335559-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MiDWIMbFBeXle-trOlk%2Fuploads%2F4WKjuMFoSbpkict1FugL%2Fimage.png?alt=media&amp;token=df1d631a-4e54-4557-a770-bc95bc29dc25" alt=""><figcaption><p>Main menu of tuner-admin-menu</p></figcaption></figure></div>

{% hint style="warning" %}
if you can't open the admin menu, even though you are admin - then make sure you have configured `Config.AcePermission` in `t1ger_lib/config.lua`
{% endhint %}

You can configure command & keybind to access the menu (`Config.AdminMenu` found inside: `t1ger_tuningsystem/shared/config.lua`) :

```lua
Config.AdminMenu = {
	Command = {enable = true, string = 'admintuner'}, -- enable/disable command, set command string.
	Keybind = {enable = true, defaultMapping = 'F10', description = 'Open admin tuner menu'} -- enable/disable keybind, set default mapping (players edit button in-game inside GTA Settings)
}
```

* **Command:** `table`
  * enable: `boolean` - enable/disable command?
  * string: `string` - chat-command to open the menu
* **Keybind:** `table`
  * enable: `boolean` - enable/disable command?
  * defaultMapping: `string` - keybind to open menu
  * description: `string` - keybind description

## Shop Creation

If you click on Create Tuner Shop, this pop-up will appear, which you have to fill out:&#x20;

<div align="left"><figure><img src="https://2167335559-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MiDWIMbFBeXle-trOlk%2Fuploads%2Fewe6AqGMHDBl8XqNoJMk%2Fimage.png?alt=media&amp;token=a35fa692-f041-4ae9-960c-f74a50214ca9" alt=""><figcaption><p>In-game shop creator menu</p></figcaption></figure></div>

* **Shop Name:** `string`
  * Give your shop a name, for example: `T1GER Tuner Shop` or `Los Santos Customs`
* **Job Name:** `string`
  * This is the job name used for the shop. Make sure it's lowercase characters, no special characters and no spaces. You can use existing jobs from your server, simply just enter the correct job name. Examples of job names: `t1gertuner`, `mechanic`, `lscustom`, `tuner`.
* **Job Label:** `string`
  * Give your created job a label, for example: T1GER Tuner, LS Tuner, Custom Tuner and so on. Keep in mind, if you've entered an existing job in `Job Name`, then the script will auto-read the job label from that job.
* **Account Start Balance:** `number`
  * You can give the tuner shop some money to start off with, simply enter the amount in this field.
* **Select Mod Categories:** `table`
  * You can restrict what categories this shop has access to by selecting from the drop-down menu. Simply select all categories to give them access to all categories. This allows to create wheels only shop, respray only shops and so on.
* **Blip Coords:** `array`
  * Shop coords will be the position of the admin that creates the shop.
* **Enable Blip:** `boolean`
  * Check the field to either enable/disable a blip for this shop. Maybe you want to create a secret tuner shop on the map?
* **Blip Sprite:** `number`
  * Set the sprite of the blip in this field. Use this link as reference for blip sprite ids: <https://docs.fivem.net/docs/game-references/blips/#blips>
* **Blip Color:** `number`
  * Set the color of the blip in this field. Use this link as reference for blip color ids: <https://docs.fivem.net/docs/game-references/blips/#blip-colors>

{% hint style="warning" %}
If you are using **`qb-core`** and you feel like your created jobs aren't syncing properly with 3rd-party resources (phones, doorlocks and etc.), then refer to [6 - (Automatic) Job Creation](https://docs.t1ger.net/resources/t1ger-tuning-system/installation#id-6-automatic-job-creation) for a workaround solution.
{% endhint %}

## Shop Management

In order to manage shops there must be shops to manage. If you haven't learned or created any shops, please refer to [#shop-creation](#shop-creation "mention"). You can manage shop in the same `tuning-admin-menu`, by clicking on `view tuner shops`.

<div align="left"><figure><img src="https://2167335559-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MiDWIMbFBeXle-trOlk%2Fuploads%2FKOI89fWCSN7ehlJKNDVF%2Fimage.png?alt=media&amp;token=114f4a6c-4429-4343-af5c-a3a11708cff4" alt=""><figcaption><p>Overview of shops</p></figcaption></figure></div>

Once you've clicked on a shop to manage, you should see a menu like this:

<div align="left"><figure><img src="https://2167335559-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MiDWIMbFBeXle-trOlk%2Fuploads%2FpPrWtcntH4OfRFyN9IJU%2Fimage.png?alt=media&amp;token=60cb3dec-e7d7-4303-b462-1f8247fb75d9" alt=""><figcaption><p>Manage selected shop menu</p></figcaption></figure></div>

* **Set Boss:** This sub-menu allows to set a boss to a newly created shop, replace a boss with a new boss or just remove the boss.&#x20;
* **Set Account Balance:** You can update the shop's account balance with this option.&#x20;
* **Set Mod Categories:** If the shop needs access to more mod categories or need some taken away, this is the option to use!
* **Marker Management:** With this option you can manage markers, create, delete and/or edit them.
* **Delete Shop:** This option is used to delete the shop entirely from the server.&#x20;


# Markers

Guide and instructions on how to properly create markers and manage them

The system offers 7 types of marker classes, each have their own functionality.

<details>

<summary>Duty</summary>

A simple marker to toggle duty. When clocking off-duty it will set the player's job to `unemployed`. When clocking on-duty it will look up whether the player is an employee (hired) in the shop and if so, the appropriate job and grade (registered in the database) will be applied.

The script will auto-read the current duty state of the player.

![](https://2167335559-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MiDWIMbFBeXle-trOlk%2Fuploads%2FPqhf0nI3SFeNlH9OpZUr%2Fimage.png?alt=media\&token=337c45b1-457f-4fdd-bfe1-ffbad1fcd4b2)

* **Clock In/Out:** updates player's job to shop's job name and cached grade or to unemployed.

</details>

<details>

<summary>Boss</summary>

This marker class can be accessed by the boss of the shop only (the very last job grade or the job grade with `isboss = true`).&#x20;

![](https://2167335559-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MiDWIMbFBeXle-trOlk%2Fuploads%2FVkbTZLLUXi5SRIilTfKy%2Fimage.png?alt=media\&token=340fb1bb-fe39-4d9a-a030-54031afce3a5)

* **Account:** manage accounts - withdraw, deposit or view.&#x20;
  * Account Balance: live data on current account funds.
  * Deposit: insert money into shop's account
  * Withdraw: take money from shop's account
  * If `UseSocietyAccount` in [Shops](/resources/t1ger-tuning-system/guides/shops#shop-creator-configuration) is enabled, then refer to: [Society Account](https://docs.t1ger.net/resources/t1ger-library/installation/society-account), ensuring you have set it up correctly.
* **Employees:** manage employees - recruit, fire or promote.\
  ![](https://2167335559-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MiDWIMbFBeXle-trOlk%2Fuploads%2F0xnh8CmZaiXDZpUNnhxZ%2Fimage.png?alt=media\&token=051e383e-b321-4de8-9e39-c8e85ca58075)
  * Manage Employes: fire or promote employees\
    ![](https://2167335559-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MiDWIMbFBeXle-trOlk%2Fuploads%2FjLeNjkSTfIV0xfJAotMF%2Fimage.png?alt=media\&token=cd33131c-9fc2-4428-b02b-e07137e6fd0a)
  * Recruit Employees: a drop-down will pop-up where u can select nearby player's to request a reqruitment. They need to accept the recruitment on their end.
* **Markup:** set the shop's markup % (0-100).
  * Allows the boss to set the markup % value of all mod orders etc.

</details>

<details>

<summary>Garage</summary>

Placing a garage marker will allow the employees to store or get their own personal owned vehicles. Please note it's not a shared garage. It's still a private garage, just a marker to access one's vehicle.

**Config.UseBuiltInGarage**

* If set to true it will use my built-in garage interface using ox\_lib. If set to false, you need to add your own garage export/function.
* Make sure to read and follow steps in [Garage](/resources/t1ger-library/installation/garage) if you are using the built-in garage.

**How to add your own export/function?**

Find the function named: `OpenGarageMenu` in `t1ger_tuningsystem/client/main.lua`and navigate to the bottom of the function where you'll see a comment.&#x20;

<img src="https://2167335559-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MiDWIMbFBeXle-trOlk%2Fuploads%2FIp2PLdyRynsIPdrrmMrW%2Fimage.png?alt=media&amp;token=f5daabd8-ec70-4102-9feb-55e536b7af41" alt="The function in question (please note, line numbers may differ from yours)" data-size="original">

Add your own export/function in there, below the comment "add function for your garage here:" to open a garage menu. Remember, not all custom garage system supports opening a garage like this, so please check with the developer/creator of your resource.&#x20;

</details>

<details>

<summary>Storage/Stash</summary>

You can place as many storage markers for each shop as you like.&#x20;

Make sure you navigate to `t1ger_lib/config.lua` and set your correct inventory. The system supports these inventories:

![Supported inventories](https://docs.t1ger.net/~gitbook/image?url=https%3A%2F%2F2167335559-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252F-MiDWIMbFBeXle-trOlk%252Fuploads%252FZhjApaL32JwegWV33vqp%252Fimage.png%3Falt%3Dmedia%26token%3D7c74ce35-3c2c-41af-8f0c-050b5278eaf6\&width=768\&dpr=4\&quality=100\&sign=66575587\&sv=1)

If using ESX and not any custom inventories, there is menu-based inventory for all created storage markers, with withdraw/deposit options.

If your inventory isn't supported, don't worry. The T1GER Library resource is fully open-source and you can easily integrate your inventory stash functions. You could also suggest it in our official Discord and we can consider adding support for it.

**Config.Stash**

```lua
Config.Stash = {slots = 50, weight = 100000, maxSlots = 500, maxWeight = 999999} -- set default stash info in here and max slots/weight for in-game edits.
```

* slots: `number` - amount of storage slots
* weight: `number` - max weight of the storage unit
* maxSlots: `number` - used in marker editor menu
* maxWeight: `number` - used in marker editor menu

</details>

<details>

<summary>Workbench</summary>

The workbench marker is a menu where you can craft mod items and tools used by tuners.

**Config.UseBuiltInWorkbench**

```lua
Config.UseBuiltInCrafting = true -- otherwise change in functions of tuning system
```

* `boolean`: if set to false, you need to integrate your own crafting function.

**How to add own crafting function?**

Navigate to `t1ger_tuningsystem/client/main.lua` and find the function called `OpenWorkBenchMenu`:

![](https://2167335559-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MiDWIMbFBeXle-trOlk%2Fuploads%2F45jkIV2eJiZPGiU0dG1s%2Fimage.png?alt=media\&token=60072182-31ba-4d4e-9dc6-539707f9cebe)

At the bottom you'll see LUA comment. In here you simply add your own export/function. You might want to reach out to the creator of said crafting resource to make proper implementation if you lack the skills - it's not supported by us!

**Config.Workbench**

Inside `t1ger_tuningsystem/shared/workbench.lua` you'll find the options and recipes for our workbench/crafting feature.

* You can add categories as you like
* You can add recipes and required materials as you like

</details>

<details>

<summary>Laptop</summary>

These markers allows you to have a laptop marker where tuners can order parts from, instead of crafting them.

All payments made from the laptop are deducted from the shop's account.

**Config.OrderedItemsToStash**

```lua
Config.OrderedItemsToStash = true -- set to true to send ordered mod items from laptop to stash directly.
```

* `boolean`:  if set to true, ordered items will go to shop's storage (you'll be able to select which storage if shop has multiple). If false, items will be added in player's inventory.

**Config.LaptopItems**

* category: `string` - give the category a label
* icon: `string` - give the category an icon&#x20;
* items: `array` - added item names in the array. Items must exists inside Config.Items

</details>

<details>

<summary>Mods Bay</summary>

These markers works pretty similar to the standard `esx-lscustom` and/or `qb-custom` marker. Basically a self-service customization/upgrade marker. Drive a vehicle into the marker and customize the visuals and upgrade the performance. Only the enabled mod categories in the shop will be available in this marker.&#x20;

Player's can select to create a mod order when they are done customizing their vehicle. This will send data to the tuner shop and a tuner can start the workflow.&#x20;

**Config.ModsMenu**

```lua
Config.ModsMenu = {
	Menu = {title = 'Mods Menu', position = 'top-left'}, -- mods main menu title and position
	DisablePurchase = false, -- set to true to disable purchase mods from mods bay menu, forcing players to do mod orders and rp with tuners.

	Repair = {
		allow = true, -- allow quick repair for $Repair.price (below) in mod menu marker. Set to false to force customers to go to a mechanic first.
		price = 1000, -- 1000$ to repair vehicle, before installing mods.
		moneyToAccount = true, -- if true, paid fees goes to the shop's account, else the money just disappears.
	},

	IncentivizedPricing = {
		enable = true, -- set to true to enable incentivized pricing. Only applies if purchasing and applying mods directly through the mods menu. This incentivized price is ignored if a mod order is created.
		percent = 25 -- percentage to increase the price of mods in the mod menu, to kinda force players to RP with tuners.
	}
}
```

* **Menu:** `table`
  * title: `string` - title used in mods menu
  * position: `string` - position of the mods menu
* **DisablePurchase:** `boolean`
  * If true, the Purchase Mods option will be gone and players are forced to create mod orders and RP with tuners. Else, they can directly purchase their mods from the mods menu.
* **Repair:** `table`
  * allow: `boolean` - enable/disable repairs done through the mods menu
  * price: `number` - if allow is enabled, then price to repair the vehicle?
  * moneyToAccount: `boolean` - whether the paid repair.price should go to shop's account.
* **IncentivizedPricing:** `table`
  * enable: `boolean` - if enabled makes it more expensive to use self-service mods menu and force player to RP with tuners.
  * percent: `number` - percentage to add on-top of each mod price when doing solo tuning.

</details>

## Configuration

### Config.Markers

```lua
Config.Markers = {
	['duty'] = {
		enable = true, -- set to false to completely disable duty marker.
		interact = {title = Lang['title_duty'], keybind = 38, dist = 1.2, drawDist = 5.0, textUi = Lang['textui_duty'], icon = 'toggle-on', position = 'right-center', style = {borderRadius = 0, backgroundColor = '#48BB78', color = 'white'}},
		blip = {sprite = 280, display = 4, scale = 0.65, color = 0}, -- blip settings
	},
	['boss'] = {
		enable = true, -- set to false to completely disable boss marker.
		interact = {title = Lang['title_boss'], keybind = 38, dist = 1.2, drawDist = 5.0, textUi = Lang['textui_boss'], icon = 'crown', position = 'right-center', style = {borderRadius = 0, backgroundColor = '#48BB78', color = 'white'}},
		blip = {sprite = 164, display = 4, scale = 0.65, color = 0}, -- blip settings
	},
	['garage'] = {
		enable = true, -- set to false to completely disable garage marker.
		interact = {title = Lang['title_garage'], keybind = 38, dist = 1.2, drawDist = 7.0, textUi = Lang['textui_garage'], icon = 'square-parking', position = 'right-center', style = {borderRadius = 0, backgroundColor = '#48BB78', color = 'white'}},
		blip = {sprite = 357, display = 4, scale = 0.65, color = 0}, -- blip settings
	},
	['storage'] = {
		enable = true, -- set to false to completely disable storage marker.
		interact = {title = Lang['title_storage'], keybind = 38, dist = 1.2, drawDist = 5.0, textUi = Lang['textui_storage'], icon = 'box', position = 'right-center', style = {borderRadius = 0, backgroundColor = '#48BB78', color = 'white'}},
		blip = {sprite = 587, display = 4, scale = 0.65, color = 0}, -- blip settings
	},
	['workbench'] = {
		enable = true, -- set to false to completely disable workbench marker.
		interact = {title = Lang['title_workbench'], keybind = 38, dist = 1.2, drawDist = 5.0, textUi = Lang['textui_workbench'], icon = 'screwdriver-wrench', position = 'right-center', style = {borderRadius = 0, backgroundColor = '#48BB78', color = 'white'}},
		blip = {sprite = 566, display = 4, scale = 0.65, color = 0}, -- blip settings
	},
	['laptop'] = { -- marker to order parts etc.
		enable = true, -- set to false to completely disable laptop marker.
		interact = {title = Lang['title_laptop'], keybind = 38, dist = 1.2, drawDist = 5.0, textUi = Lang['textui_laptop'], icon = 'laptop', position = 'right-center', style = {borderRadius = 0, backgroundColor = '#48BB78', color = 'white'}},
		blip = {sprite = 521, display = 4, scale = 0.65, color = 0}, -- blip settings
	},
	['modsbay'] = { -- marker to customize/upgrade vehicles
		enable = true, -- set to false to completely disable mods menu/bay marker.
		interact = {title = Lang['title_modsbay'], keybind = 38, dist = 1.2, drawDist = 7.0, textUi = Lang['textui_modsbay'], icon = 'spray-can', position = 'right-center', style = {borderRadius = 0, backgroundColor = '#48BB78', color = 'white'}},
		blip = {sprite = 402, display = 4, scale = 0.65, color = 0}, -- blip settings
	},
}
```

{% hint style="danger" %}
Do not edit/change the index/key value name for the marker class. Only configure the options inside of each marker class!
{% endhint %}

* **enable:** `boolean`
  * Enable or disable the marker class entirely.&#x20;
* **interact:** `table`
  * Marker interaction settings
  * title: `string` - context menu title
  * keybind: `number` - key to access menu
  * dist: `number` - distance for keypress to work
  * drawDist: `number` - distance to draw marker
  * textUi: `string` - text shown in textUi
  * icon: `string` - icon in textUi
  * position: `string` - the position of textUi
  * style: `table` - style properties for textUi
* **blip:** `table`
  * sprite: `number` - [reference](https://docs.fivem.net/docs/game-references/blips/#blips)
  * display: `number` - [reference](https://docs.fivem.net/natives/?_0x9029B2F3DA924928)
  * scale: `number` - [reference](https://docs.fivem.net/natives/?_0xD38744167B2FA257)
  * color: `number` - [reference](https://docs.fivem.net/docs/game-references/blips/#blip-colors)

### Config.MarkerTeleport

```lua
Config.MarkerTeleport = true -- set to false to disable option in admin menu to TP to marker.
```

* `boolean`: allow admins to TP to a marker from marker management menu.

### Config.MarkerEdit

```lua
Config.MarkerEdit = true -- set to false to disable option in admin menu to edit marker.
```

* `boolean`: allow admins to edit marker from marker management menu.

### Config.MarkerDefaultRGBA&#x20;

```lua
Config.MarkerDefaultRGBA = 'rgba(199, 30, 30, 1)' -- default RGBA color of the marker creator/editor - only change the numbers!!.
```

* `rgba`: default RGBA color shown in marker creation/edit menu. You can always change in-game.

## Marker Creation

To create a marker, you must use the tuner-admin-menu, select a shop to manage and then click on `Marker Management`.&#x20;

{% hint style="success" %}
You can create multiple markers of same class.
{% endhint %}

<div align="left"><figure><img src="https://2167335559-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MiDWIMbFBeXle-trOlk%2Fuploads%2FCSEkRwDfExg4vQCTDnN1%2Fimage.png?alt=media&amp;token=6ac30660-a995-4b97-9ecd-bf663947db89" alt=""><figcaption><p>Marker management main menu</p></figcaption></figure></div>

From here, you click on `Create Marker` and this pop-up will appear:

<div align="left"><figure><img src="https://2167335559-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MiDWIMbFBeXle-trOlk%2Fuploads%2Ftv6KL2dXUgu3nohqRCVF%2Fimage.png?alt=media&amp;token=5be7ded1-fd3b-4481-a2e4-f27baa2edf1e" alt=""><figcaption><p>In-game marker creation menu</p></figcaption></figure></div>

* **Class:** `table`
  * The drop-down allows you to select one of the allowed marker classes (`string`).
* **Name:** `string`
  * You can give the marker a proper name.
* **Coords:** `array`
  * The marker will be created at the current position of the admin.
* **Type:** `number`
  * Marker type - [reference](https://docs.fivem.net/docs/game-references/markers/)
* **Color:** `rgba`
  * Set RGBA color for the marker
* **Bob Up And Down?:** `boolean`
  * Enable or disable
* **Face Camera?:** `boolean`
  * Enable or disable
* **Enable Blip?:** `boolean`
  * Enable or disable blip for the marker, maybe you want a secret marker?

## Marker Management

From the `Marker Management` main menu, you can click on `View Markers` to view and manage a marker.

<div align="left"><figure><img src="https://2167335559-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MiDWIMbFBeXle-trOlk%2Fuploads%2FrM8caDwusMOSANTs0kJq%2Fimage.png?alt=media&amp;token=174eb8e4-bd66-4359-9f79-d3e726aa9a60" alt=""><figcaption><p>Overview of created markers for a shop</p></figcaption></figure></div>

Click on a marker to manage. In this case we clicked on `Mods Bay` marker.

<div align="left"><figure><img src="https://2167335559-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MiDWIMbFBeXle-trOlk%2Fuploads%2FiLot6HJuT6DPxnfo078K%2Fimage.png?alt=media&amp;token=e66b6b68-3236-4166-a57c-bb25085bd8a7" alt=""><figcaption><p>Manage selected marker main menu (Mods Bay)</p></figcaption></figure></div>

* **Teleport:** allows you to teleport to the given marker.
* **Edit:** allows you to customize the marker.
* **Delete:** removes the marker from the shop.

When editing a marker, this pop-up will appear. It's very similar to the marker creation, except you cannot change the class nor the coords.

<div align="left"><figure><img src="https://2167335559-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MiDWIMbFBeXle-trOlk%2Fuploads%2FRNY5ty70OAeo3wOThLAf%2Fimage.png?alt=media&amp;token=501fd669-b59a-4997-99f0-6e6dafd7dd63" alt=""><figcaption><p>Edit marker input menu (similar to marker creation menu)</p></figcaption></figure></div>

When editing storage/stash markers, another two options will be available:

<div align="left"><figure><img src="https://2167335559-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MiDWIMbFBeXle-trOlk%2Fuploads%2FH1yD0UQHyDutlhE3o3y7%2Fimage.png?alt=media&amp;token=36843b2a-8fe5-4b1d-b2bc-a1bad4614e56" alt=""><figcaption><p>Stash Marker Edit</p></figcaption></figure></div>


# Mod Stations

Guide and instructions on how to setup mod stations and use them

These are pre-configured mods menu with whitelisted jobs. These can be really usefull for police and ems jobs or other jobs that you find suitable.

```lua
Config.ModStations = {
	Interact = {keybind = 38, dist = 1.2, drawDist = 7.0, textUi = '[E] Mods Menu', icon = 'spray-can', position = 'right-center', style = {borderRadius = 0, backgroundColor = '#48BB78', color = 'white'}},
	Blip = {name = 'Mod Station', sprite = 72, display = 4, scale = 0.65, color = 0},
	Marker = {type = 20, scale = {0.35, 0.35, 0.35}, rgba = {255, 99, 71, 100}},
	Locations = {
		{ -- mrpd
			pos = vector3(478.68, -1022.33, 28.01), -- pos of the mod station
			jobs = {'police', 'lspd', 'test'}, -- allowed jobs
			mods = {'respray', 'bodyworks', 'chassis', 'enginebay', 'exterior', 'interior', 'lights', 'wheels', 'performance'},
			free = true, -- free of charge?
			blip = true -- enable/disable blip
		}, 
		{ -- pillbox
			pos = vector3(344.53, -554.79, 28.74), -- pos of the mod station
			jobs = {'ambulance', 'ems', 'medic', 'doc'}, -- allowed jobs
			mods = {'respray', 'bodyworks', 'chassis', 'enginebay', 'exterior', 'interior', 'lights', 'wheels', 'performance'},
			free = true, -- free of charge?
			blip = true -- enable/disable blip
		}, 
	}
}
```

* **Interact:** `table`
  * settings to interact with marker/keypress
* **Blip:** `table`
  * blip settings for mod stations
* **Marker:** `table`
  * marker settings for mod stations
* **Locations:** `table`
  * pos: `vector3` - coords for the mod station
  * jobs: `array` - allowed jobs that can accesss
  * mods: `array` - allowed mod categories
  * free: `boolean` - all mods are free?
  * blip: `boolean` - enable/disable blip

You can easily add more mod stations inside .Locations. Make sure to follow the template!


# Pricing

Guide and instructions on how to setup prices for mods

## Config.PriceEscalationPercent

Controls how much mod variant prices increase for each mod variant displayed in the menu. The higher the variant, the more it cost.Setting it to 0 means no price increase and all mod variants cost the same.

```lua
Config.PriceEscalationPercent = 5
-- Type: Integer
-- Range: 0 - 100
```

**Usage:**

* **`0`**: No escalation; all mod variants have the same price defined in `Config.Mods`.
* **`1 - 100`**: Prices increase by the specified percentage for each higher mod variant, calculated on the price of the previous variant. For example, setting this to `5`means each higher mod variant will cost 5% more than the previous one.

## Config.PartAcquisitionCost

Determines whether to include the cost of acquiring parts in the final price of the mod.

```lua
Config.PartAcquisitionCost = true
-- Type: Boolean
-- Values: true, false
```

**Usage:**

* **`true`**: Adds the item price from `Config.Items['mods']` to the mod price, covering the acquisition cost of parts.
* **`false`**: Does not add acquisition costs to the mod price.

## Config.DefaultVehiclePrice

Specifies the fallback vehicle price used when the script cannot retrieve the vehicle value from a database or shared Lua file.

```lua
Config.DefaultVehiclePrice = 50000
-- Type: Integer
```

**Usage:**

* **`50000`**: Sets the default vehicle price to $50,000 if the vehicle value cannot be retrieved from a database or shared file. Adjust this value to suit your pricing needs.

## Config.TieredPricing

Enables or disables tier-based multipliers for mod pricing. If enabled, it uses [`Config.PriceTiers`](#config.pricetiers) to apply different multipliers based on the vehicle price.

```lua
Config.TieredPricing = true
-- Type: Boolean
-- Values: true, false
```

**Usage:**

* **`true`**: Enables tier-based multipliers for mod pricing.
* **`false`**: Disables tier-based multipliers for mod pricing.

## Config.PriceTiers

Defines the tiers for adjusting mod prices based on the vehicle price. Each tier specifies an upper limit and a corresponding multiplier. [`Config.TieredPricing`](#config.tieredpricing) must be enabled!

```lua
Config.PriceTiers = {
    { upperLimit = 10000, multiplier = 0.05 },  -- Tier 1: Integer upperLimit ($10,000), Float multiplier (5%)
    { upperLimit = 50000, multiplier = 0.03 },  -- Tier 2: Integer upperLimit ($50,000), Float multiplier (3%)
    { upperLimit = 100000, multiplier = 0.02 }, -- Tier 3: Integer upperLimit ($100,000), Float multiplier (2%)
    { upperLimit = 500000, multiplier = 0.01 }, -- Tier 4: Integer upperLimit ($500,000), Float multiplier (1%)
    { upperLimit = math.huge, multiplier = 0.005 } -- Tier 5: Integer upperLimit (Infinity), Float multiplier (0.5%)
}
-- Type: Table
```

**Usage:**

* **`upperLimit`**: (integer) The maximum vehicle price for the tier. Use `math.huge` for the last option.
* **`multiplier`**: (float) The percentage applied to mod prices within the tier.

{% hint style="warning" %}
You can add or edit tiers as needed. Ensure that `math.huge` is used as the `upperLimit` for the highest tier to cover all values above the defined limits.
{% endhint %}

W\.I.P


# Mod Orders

Guide and instructions on how to use mod orders

Players can use the [Markers](/resources/t1ger-tuning-system/guides/markers#mods-bay) marker and when done customizing their vehicle, instead of purchasing the mods and pay an incentivized price for each mod installed, they can rather create a mod order and save some money. This allows for roleplay between players and tuners.&#x20;

The tuners can view mod orders from their Tuner Tablet.&#x20;

<pre class="language-lua"><code class="lang-lua"><strong>Config.ModOrder = {
</strong>	MarkupToAccount = true, -- set to false and shop markup won't go into the shop's account.
	PartAcquisitionToAccount = true, -- set to false and item price for each item used, will not be added to shop's account, when customer places the mod order.
	Keymap = {key = 'j', description = 'Toggle Workflow UI Cursor'},
	WorkflowTitle = 'Workflow - %s',
	TaskList = {
		name = '&#x3C;strong>%s (%s)&#x3C;/strong>', -- workflow ui task name
		description = 'Item: %s' -- workflow ui task description
	},
	Icons = {
		customer = 'user',
		paidAmount = 'file-invoice-dollar',
		beginWork = 'circle-play',
		refund = 'hand-holding-dollar',
		stopWork = 'circle-stop',
		taskComplete = 'circle-check',
		taskIncomplete = 'circle-xmark',
	}
}
</code></pre>

* **MarkupToAccount:** `boolean`
  * If true, the shop's markup percentage will go into the shop's account, else not.
* **PartAcquisitionToAccount:** `boolean`
  * If true, the cost of the item from Config.Items will go into the shop's account, else not.
* **Keymap:** `table`
  * Keybind to toggle the cursor/scroll in the workflow UI.
  * key: `string` - keybind
  * description: `string` - description for the keymap
* **WorkflowTitle:** `string`
  * Title for the workflow UI where `%s` is the vehicle plate.
* **TaskList:** `table`
  * How the tasks are displayed in the workflow UI.
  * name: `string` - is the title of the task (values: mod name and variant name)
  * description: `string` - is a description to the task (item label)
* **Icons:** `table`
  * Icons used in the mod order menu.


# Vehicle Mods

Guide & instructions on vehicle mods (cosmetics/performance), pricing and so on.

{% hint style="success" %}
In this file **`t1ger_tuningsystem/shared/mods.lua`** you can access all of these configurable options.
{% endhint %}

## Config.ModCategories

Defines the categories for sorting all mods from `Config.Mods`.

```lua
Config.ModCategories = {
    ['respray'] = {id = 'mod_respray', title = 'Respray', position = 'top-left', icon = 'https://i.ibb.co/T0q9bgj/mod-respray.png'},
    ['bodyworks'] = {id = 'mod_bodyworks', title = 'Body Works', position = 'top-left', icon = 'https://i.ibb.co/YZkqQRj/mod-bodyworks.png'},
    ['chassis'] = {id = 'mod_chassis', title = 'Chassis', position = 'top-left', icon = 'https://i.ibb.co/1XGXthM/mod-chassis.png'},
    ['enginebay'] = {id = 'mod_enginebay', title = 'Engine Bay', position = 'top-left', icon = 'https://i.ibb.co/ngv65rV/mod-enginebay.png'},
    ['exterior'] = {id = 'mod_exterior', title = 'Exterior', position = 'top-left', icon = 'https://i.ibb.co/wz2s9mG/mod-exterior.png'},
    ['interior'] = {id = 'mod_interior', title = 'Interior', position = 'top-left', icon = 'https://i.ibb.co/ZKZS3mP/mod-interior.png'},
    ['lights'] = {id = 'mod_lights', title = 'Lights', position = 'top-left', icon = 'https://i.ibb.co/P56HBBg/mod-lights.png'},
    ['wheels'] = {id = 'mod_wheels', title = 'Wheels', position = 'top-left', icon = 'https://i.ibb.co/8BbyF7y/mod-wheels.png'},
    ['performance'] = {id = 'mod_performance', title = 'Performance', position = 'top-left', icon = 'https://i.ibb.co/MgPCg06/mod-engine.png'}
}
-- Type: Table
```

**Usage:** Each category contains the following properties:

* **`id`**: (String) The unique identifier for the category. <mark style="color:red;">Do not edit this!</mark>
* **`title`**: (String) The displayed title of the category in the menu.
* **`position`**: (String) The position of the category in-game. (`'top-left'` or `'top-right'` or `'bottom-left'` or `'bottom-right').`
* **`icon`**: (String) FontAwesome icon or URL to the icon image displayed in the menu.

{% hint style="danger" %}
You can modify `title`, `position`, and `icon` to fit your needs. Ensure that other properties remain unchanged to maintain script functionality.
{% endhint %}

## Config.DisableMods

Specifies mods that are disabled by default. This array can be customized to include specific mods you want to disable. By default, common weapon mods are disabled, but you can add or remove mods as needed.

```lua
Config.DisableMods = {
    'Primary Weapons', 'Proximity Mine', 'Armor Plating', 'Ram Weapons', 'Imani Tech', 'Blades', 'Spikes', 'Secondary Weapons'
}
-- Type: Array
```

**Usage:**

* **Each entry**: (String) Represents the name of a mod that will be disabled. You can add specific mods to this array if you prefer to disable them. For example, `['Primary Weapons']` disables primary weapon mods.

{% hint style="success" %}
*This configuration helps control which mods players can install, providing flexibility to disable any mods you find unsuitable for your server.*
{% endhint %}

## Config.Mods

Defines all available mods for vehicles. Each mod is controlled by several properties that determine its behavior, appearance and installation process in the game. Customize these mods as needed.

<details>

<summary>Config.Mods (Click to expand)</summary>

```lua
Config.Mods = {
    modSpoilers = {
        label = 'Spoiler', modType = 0, price = 700, category = 'bodyworks', point = 'rear',
        prop = {model = 'imp_prop_impexp_spoiler_01a', pos = {0.0, -0.2, -0.2}, rot = {0.0, 0.0, -180.0}},
        anim = {
            idle = {dict = 'anim@heists@box_carry@', name = 'idle', blendIn = 4.0, blendOut = 1.0, duration = -1, flags = 49},
            install = {dict = 'mini@repair', name = 'fixing_a_player', blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1}
        }
    },
    modFrontBumper = {
        label = 'Front Bumper', modType = 1, price = 2100, category = 'bodyworks', point = 'front',
        prop = {model = 'imp_prop_impexp_front_bumper_01a', pos = {0.0, -0.25, -0.15}, rot = {0.0, 0.0, -180.0}},
        anim = {
            idle = {dict = 'anim@heists@box_carry@', name = 'idle', blendIn = 4.0, blendOut = 1.0, duration = -1, flags = 49},
            install = {dict = 'anim@amb@clubhouse@tutorial@bkr_tut_ig3@', name = 'machinic_loop_mechandplayer', blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1}
        }
    },
    modRearBumper = {
        label = 'Rear Bumper', modType = 2, price = 1800, category = 'bodyworks', point = 'rear',
        prop = {model = 'imp_prop_impexp_rear_bumper_03a', pos = {0.0, -0.25, -0.15}, rot = {-20.0, 0.0, -180.0}},
        anim = {
            idle = {dict = 'anim@heists@box_carry@', name = 'idle', blendIn = 4.0, blendOut = 1.0, duration = -1, flags = 49},
            install = {dict = 'anim@amb@clubhouse@tutorial@bkr_tut_ig3@', name = 'machinic_loop_mechandplayer', blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1}
        }
    },
    modSideSkirt = {
        label = 'Skirt', modType = 3, price = 800, category = 'bodyworks', point = 'vehicle',
        prop = {model = 'imp_prop_impexp_rear_bumper_01a', pos = {0.0, -0.25, -0.15}, rot = {-20.0, 0.0, -180.0}},
        anim = {
            idle = {dict = 'anim@heists@box_carry@', name = 'idle', blendIn = 4.0, blendOut = 1.0, duration = -1, flags = 49},
            install = {dict = 'anim@amb@clubhouse@tutorial@bkr_tut_ig3@', name = 'machinic_loop_mechandplayer', blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1}
        }
    },
    modExhaust = {
        label = 'Exhaust', modType = 4, price = 1000, category = 'bodyworks', point = 'rear',
        prop = {model = 'imp_prop_impexp_exhaust_01', pos = {-0.1, -0.20, -0.20}, rot = {20.0, 10.0, 90.0}},
        anim = {
            idle = {dict = 'anim@heists@box_carry@', name = 'idle', blendIn = 4.0, blendOut = 1.0, duration = -1, flags = 49},
            install = {dict = 'anim@amb@clubhouse@tutorial@bkr_tut_ig3@', name = 'machinic_loop_mechandplayer', blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1}
        }
    },
    modFrame = {
        label = 'Roll Cage', modType = 5, price = 2300, category = 'chassis', point = 'vehicle',
        prop = {model = 'imp_prop_impexp_rear_bars_01b', pos = {0.0, 0.60, -0.26}, rot = {-30.0, 0.0, -180.0}},
        anim = {
            idle = {dict = 'anim@heists@box_carry@', name = 'idle', blendIn = 4.0, blendOut = 1.0, duration = -1, flags = 49},
            install = {dict = 'mini@repair', name = 'fixing_a_player', blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1}
        }
    },
    modGrille = {
        label = 'Grill', modType = 6, price = 900, category = 'exterior', point = 'front',
        prop = {model = 'imp_prop_impexp_radiator_01', pos = {0.0, -0.28, -0.23}, rot = {0.0, 0.0, 0.0}},
        anim = {
            idle = {dict = 'anim@heists@box_carry@', name = 'idle', blendIn = 4.0, blendOut = 1.0, duration = -1, flags = 49},
            install = {dict = 'anim@amb@clubhouse@tutorial@bkr_tut_ig3@', name = 'machinic_loop_mechandplayer', blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1}
        }
    },
    modHood = {
        label = 'Hood', modType = 7, price = 1900, category = 'bodyworks', point = 'front',
        prop = {model = 'imp_prop_impexp_bonnet_04a', pos = {0.0, 0.20, 0.12}, rot = {-20.0, 0.0, 180.0}},
        anim = {
            idle = {dict = 'anim@heists@box_carry@', name = 'idle', blendIn = 4.0, blendOut = 1.0, duration = -1, flags = 49},
            install = {dict = 'mini@repair', name = 'fixing_a_player', blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1}
        }
    },
    modFender = {
        label = 'Left Fender', modType = 8, price = 1200, category = 'bodyworks', point = 'vehicle',
        prop = {model = 'imp_prop_impexp_car_panel_01a', pos = {-0.15, -0.18, -0.16}, rot = {5.0, 0.0, -90.0}},
        anim = {
            idle = {dict = 'anim@heists@box_carry@', name = 'idle', blendIn = 4.0, blendOut = 1.0, duration = -1, flags = 49},
            install = {dict = 'anim@amb@clubhouse@tutorial@bkr_tut_ig3@', name = 'machinic_loop_mechandplayer', blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1}
        }
    },
    modRightFender = {
        label = 'Right Fender', modType = 9, price = 1200, category = 'bodyworks', point = 'vehicle',
        prop = {model = 'imp_prop_impexp_car_panel_01a', pos = {0.0, -0.0, -0.4}, rot = {0.0, 0.0, 90.0}},
        anim = {
            idle = {dict = 'anim@heists@box_carry@', name = 'idle', blendIn = 4.0, blendOut = 1.0, duration = -1, flags = 49},
            install = {dict = 'anim@amb@clubhouse@tutorial@bkr_tut_ig3@', name = 'machinic_loop_mechandplayer', blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1}
        }
    },
    modRoof = {
        label = 'Roof', modType = 10, price = 1100, category = 'bodyworks', point = 'vehicle',
        prop = {model = 'prop_cs_cardbox_01', pos = {0.0, -0.2, -0.1}, rot = {40.0, 0.0, 0.0}},
        anim = {
            idle = {dict = 'anim@heists@box_carry@', name = 'idle', blendIn = 4.0, blendOut = 1.0, duration = -1, flags = 49},
            install = {dict = 'mini@repair', name = 'fixing_a_player', blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1}
        }
    },
    modEngine = {
        label = 'Engine', modType = 11, category = 'performance', point = 'engine', icon = 'https://i.ibb.co/MgPCg06/mod-engine.png',
        variants = {
            ['-1'] = {label = 'Stock Engine', index = -1, price = 3000},
            ['0'] = {label = 'EMS Upg. Level 1', index = 0, price = 5000},
            ['1'] = {label = 'EMS Upg. Level 2', index = 1, price = 7000},
            ['2'] = {label = 'EMS Upg. Level 3', index = 2, price = 9000},
            ['3'] = {label = 'EMS Upg. Level 4', index = 3, price = 12000},
            ['4'] = {label = 'Custom Engine Tune', index = 4, price = 15000}
        },
        prop = {model = 'imp_prop_impexp_engine_part_01a', pos = {0.0, -0.1, -0.20}, rot = {40.0, 0.0, 0.0}},
        anim = {
            idle = {dict = 'anim@heists@box_carry@', name = 'idle', blendIn = 4.0, blendOut = 1.0, duration = -1, flags = 49},
            install = {dict = 'mini@repair', name = 'fixing_a_player', blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1}
        }
    },
    modBrakes = {
        label = 'Brakes', modType = 12, category = 'performance', point = 'wheel', icon = 'https://i.ibb.co/wKxczkS/mod-brakes.png',
        variants = {
            ['-1'] = {label = 'Stock Brakes', index = -1, price = 1500},
            ['0'] = {label = 'Street Brakes', index = 0, price = 2500},
            ['1'] = {label = 'Sports Brakes', index = 1, price = 3500},
            ['2'] = {label = 'Race Brakes', index = 2, price = 4500},
            ['3'] = {label = 'Custom Brakes', index = 3, price = 5500}
        },
        prop = {model = 'imp_prop_impexp_brake_caliper_01a', pos = {0.0, -0.1, -0.2}, rot = {0.0, 90.0, 0.0}},
        anim = {
            idle = {dict = 'anim@heists@box_carry@', name = 'idle', blendIn = 4.0, blendOut = 1.0, duration = -1, flags = 49},
            install = {dict = 'anim@amb@clubhouse@tutorial@bkr_tut_ig3@', name = 'machinic_loop_mechandplayer', blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1}
        }
    },
    modTransmission = {
        label = 'Transmission', modType = 13, category = 'performance', point = 'engine', icon = 'https://i.ibb.co/P1NvFBf/mod-transmission.png',
        variants = {
            ['-1'] = {label = 'Stock Transmission', index = -1, price = 2000},
            ['0'] = {label = 'Street Transmission', index = 0, price = 3500},
            ['1'] = {label = 'Sports Transmission', index = 1, price = 5000},
            ['2'] = {label = 'Race Transmission', index = 2, price = 6500},
            ['3'] = {label = 'Custom Transmission', index = 3, price = 7000}
        },
        prop = {model = 'imp_prop_impexp_gearbox_01', pos = {0.0, -0.1, -0.2}, rot = {0.0, 0.0, 90.0}},
        anim = {
            idle = {dict = 'anim@heists@box_carry@', name = 'idle', blendIn = 4.0, blendOut = 1.0, duration = -1, flags = 49},
            install = {dict = 'mini@repair', name = 'fixing_a_player', blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1}
        }
    },
    modHorns = {
        label = 'Horn', modType = 14, category = 'exterior', point = 'engine',
        variants = {
            ['-1'] = {label = 'Stock',				    index = -1,					price = 250},
            ['0'] = {label = 'Truck Horn',			    index = 0,					price = 400},
            ['1'] = {label = 'Cop Horn',			    index = 1,					price = 400},
            ['2'] = {label = 'Clown Horn',			    index = 2,					price = 400},
            ['3'] = {label = 'Musical Horn 1',		    index = 3,					price = 550},
            ['4'] = {label = 'Musical Horn 2',		    index = 4,					price = 550},
            ['5'] = {label = 'Musical Horn 3',		    index = 5,					price = 550},
            ['6'] = {label = 'Musical Horn 4',		    index = 6,					price = 550},
            ['7'] = {label = 'Musical Horn 5',		    index = 7,					price = 550},
            ['8'] = {label = 'Sad Trombone',		    index = 8,					price = 600},
            ['9'] = {label = 'Classical Horn 1',	    index = 9,					price = 700},
            ['10'] = {label = 'Classical Horn 2',	    index = 10,					price = 700},
            ['11'] = {label = 'Classical Horn 3',	    index = 11,					price = 700},
            ['12'] = {label = 'Classical Horn 4',	    index = 12,					price = 700},
            ['13'] = {label = 'Classical Horn 5',	    index = 13,					price = 700},
            ['14'] = {label = 'Classical Horn 6',	    index = 14,					price = 700},
            ['15'] = {label = 'Classical Horn 7',	    index = 15,					price = 700},
            ['16'] = {label = 'Scale - Do',			    index = 16,					price = 800},
            ['17'] = {label = 'Scale - Re',			    index = 17,					price = 800},
            ['18'] = {label = 'Scale - Mi',			    index = 18,					price = 800},
            ['19'] = {label = 'Scale - Fa',			    index = 19,					price = 800},
            ['20'] = {label = 'Scale - Sol',			index = 20,					price = 800},
            ['21'] = {label = 'Scale - La',			    index = 21,					price = 800},
            ['22'] = {label = 'Scale - Ti',			    index = 22,					price = 800},
            ['23'] = {label = 'Scale - Do',			    index = 23,					price = 800},
            ['24'] = {label = 'Jazz Horn 1',			index = 24,					price = 850},
            ['25'] = {label = 'Jazz Horn 2',			index = 25,					price = 850},
            ['26'] = {label = 'Jazz Horn 3',			index = 26,					price = 850},
            ['27'] = {label = 'Jazz Horn Loop', 		index = 27,					price = 850},
            ['28'] = {label = 'Star Spangled Banner 1', index = 28,				    price = 900},
            ['29'] = {label = 'Star Spangled Banner 2', index = 29,				    price = 900},
            ['30'] = {label = 'Star Spangled Banner 3', index = 30,				    price = 900},
            ['31'] = {label = 'Star Spangled Banner 4', index = 31,				    price = 900},
            ['32'] = {label = 'Classical Horn 8 Loop',  index = 32,				    price = 1000},
            ['33'] = {label = 'Classical Horn 9 Loop',  index = 33,				    price = 1000},
            ['34'] = {label = 'Classical Horn 10 Loop', index = 34,				    price = 1000},
            ['35'] = {label = 'Classical Horn 8', 	    index = 35,					price = 1100},
            ['36'] = {label = 'Classical Horn 9', 	    index = 36,					price = 1100},
            ['37'] = {label = 'Classical Horn 10', 	    index = 37,					price = 1100},
            ['38'] = {label = 'Funeral Loop', 		    index = 38,					price = 1200},
            ['39'] = {label = 'Funeral', 			    index = 39,					price = 1200},
            ['40'] = {label = 'Spooky Loop', 		    index = 40,					price = 1200},
            ['41'] = {label = 'Spooky', 				index = 41,					price = 1200},
            ['42'] = {label = 'San Andreas Loop', 	    index = 42,					price = 1200},
            ['43'] = {label = 'San Andreas', 		    index = 43,					price = 1200},
            ['44'] = {label = 'Liberty City Loop', 	    index = 44,					price = 1200},
            ['45'] = {label = 'Liberty City', 		    index = 45,					price = 1200},
            ['46'] = {label = 'Festive 1 Loop', 		index = 46,					price = 1250},
            ['47'] = {label = 'Festive 1', 			    index = 47,					price = 1250},
            ['48'] = {label = 'Festive 2 Loop', 		index = 48,					price = 1250},
            ['49'] = {label = 'Festive 2', 			    index = 49,					price = 1250},
            ['50'] = {label = 'Festive 3 Loop', 		index = 50,					price = 1250},
            ['51'] = {label = 'Festive 3', 			    index = 51,					price = 1250},
            ['52'] = {label = 'Air Horn Low Loop', 	    index = 52,					price = 1300},
            ['53'] = {label = 'Air Horn Low', 		    index = 53,					price = 1300},
            ['54'] = {label = 'Air Horn Medium Loop',   index = 54,				    price = 1300},
            ['55'] = {label = 'Air Horn Medium', 	    index = 55,					price = 1300},
            ['56'] = {label = 'Air Horn High Loop', 	index = 56,					price = 1300},
            ['57'] = {label = 'Air Horn High', 		    index = 57,					price = 1300}
        },
        prop = {model = 'prop_cs_cardbox_01', pos = {0.0, -0.2, -0.1}, rot = {135.0, 0.0, 0.0}},
        anim = {
            idle = {dict = 'anim@heists@box_carry@', name = 'idle', blendIn = 4.0, blendOut = 1.0, duration = -1, flags = 49},
            install = {dict = 'mini@repair', name = 'fixing_a_player', blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1}
        }
    },
    modSuspension = {
        label = 'Suspension', modType = 15, category = 'performance', point = 'wheel', icon = 'https://i.ibb.co/FYwfm4y/mod-suspension.png',
        variants = {
            ['-1'] = {label = 'Stock Suspension', index = -1, price = 1000},
            ['0'] = {label = 'Lowered Suspension', index = 0, price = 2000},
            ['1'] = {label = 'Street Suspension', index = 1, price = 3000},
            ['2'] = {label = 'Sports Suspension', index = 2, price = 4000},
            ['3'] = {label = 'Competition Suspension', index = 3, price = 5000},
            ['4'] = {label = 'Custom Suspension', index = 4, price = 7500}
        },
        prop = {model = 'prop_cs_cardbox_01', pos = {0.0, -0.2, -0.1}, rot = {135.0, 0.0, 0.0}},
        anim = {
            idle = {dict = 'anim@heists@box_carry@', name = 'idle', blendIn = 4.0, blendOut = 1.0, duration = -1, flags = 49},
            install = {dict = 'anim@amb@clubhouse@tutorial@bkr_tut_ig3@', name = 'machinic_loop_mechandplayer', blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1}
        }
    },
    modArmor = {
        label = 'Armor', modType = 16, category = 'performance', point = 'vehicle', icon = 'https://i.ibb.co/Fby20CQ/mod-armor.png',
        variants = {
            ['-1'] = {label = 'Stock Armor', index = -1, price = 2500},
            ['0'] = {label = '20% Armor', index = 0, price = 5000},
            ['1'] = {label = '40% Armor', index = 1, price = 10000},
            ['2'] = {label = '60% Armor', index = 2, price = 15000},
            ['3'] = {label = '80% Armor', index = 3, price = 20000},
            ['4'] = {label = '100% Armor', index = 4, price = 25000}
        },
        prop = {model = 'prop_cs_cardbox_01', pos = {0.0, -0.2, -0.1}, rot = {135.0, 0.0, 0.0}},
        anim = {
            idle = {dict = 'anim@heists@box_carry@', name = 'idle', blendIn = 4.0, blendOut = 1.0, duration = -1, flags = 49},
            install = {dict = 'mini@repair', name = 'fixing_a_player', blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1}
        }
    },
    modTurbo = {
        label = 'Turbo', modType = 18, category = 'performance', point = 'engine', icon = 'https://i.ibb.co/12BpDZY/mod-turbo.png',
        variants = {
            ['0'] = {label = 'Stock Turbo', index = 0, price = 1500},
            ['1'] = {label = 'Upgraded Turbo', index = 1, price = 7500}
        },
        prop = {model = 'prop_cs_cardbox_01', pos = {0.0, -0.2, -0.1}, rot = {135.0, 0.0, 0.0}},
        anim = {
            idle = {dict = 'anim@heists@box_carry@', name = 'idle', blendIn = 4.0, blendOut = 1.0, duration = -1, flags = 49},
            install = {dict = 'mini@repair', name = 'fixing_a_player', blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1}
        }
    },
    modSmokeEnabled = {
        label = 'Tyre Smoke', modType = 20, category = '', point = 'wheel',
        prop = {model = 'imp_prop_impexp_tyre_01a', pos = {0.0, -0.10, 0.15}, rot = {0.0, 0.0, 0.0}},
        anim = {
            idle = {dict = 'anim@heists@box_carry@', name = 'idle', blendIn = 4.0, blendOut = 1.0, duration = -1, flags = 49},
            install = {dict = 'anim@amb@clubhouse@tutorial@bkr_tut_ig3@', name = 'machinic_loop_mechandplayer', blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1}
        }
    },
    modXenon = {
        label = 'Xenon Kit', modType = 22, category = 'lights', point = 'engine',
        prop = {model = 'prop_cs_package_01', pos = {0.0, -0.05, -0.1}, rot = {100.0, 0.0, 0.0}},
        variants = {
            ['0'] = {label = 'Stock',		index = 0,		price = 100},
            ['1'] = {label = 'Xenon',		index = 1,		price = 2000},
        },
        anim = {
            idle = {dict = 'anim@heists@box_carry@', name = 'idle', blendIn = 4.0, blendOut = 1.0, duration = -1, flags = 49},
            install = {dict = 'mini@repair', name = 'fixing_a_player', blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1}
        }
    },
    modFrontWheels = {
        label = 'Wheels', modType = 23, category = 'wheels', point = 'wheel',
        variants = {
            ['0'] = {label = 'Sport',				index = 0,					price = 1200},
            ['1'] = {label = 'Muscle',				index = 1,					price = 1000},
            ['2'] = {label = 'Lowrider',			index = 2,					price = 1100},
            ['3'] = {label = 'SUV',					index = 3,					price = 1400},
            ['4'] = {label = 'Offroad',				index = 4,					price = 900},
            ['5'] = {label = 'Tuner',				index = 5,					price = 1600},
            ['6'] = {label = 'Bike Front',			index = 6,					price = 700},
            ['7'] = {label = 'High End',			index = 7,					price = 1800},
            ['8'] = {label = 'Benny\'s Original',	index = 8,					price = 1700},
            ['9'] = {label = 'Benny\'s Bespoke',	index = 9,					price = 2000},
            ['10'] = {label = 'Open Wheel',			index = 10,					price = 2200},
            ['11'] = {label = 'Street',				index = 11,					price = 2500},
            ['12'] = {label = 'Track',				index = 12,					price = 3200}
        },
        prop = {model = 'imp_prop_impexp_tyre_01c', pos = {0.0, -0.1, 0.2}, rot = {0.0, 0.0, 0.0}},
        anim = {
            idle = {dict = 'anim@heists@box_carry@', name = 'idle', blendIn = 4.0, blendOut = 1.0, duration = -1, flags = 49},
            install = {dict = 'anim@amb@clubhouse@tutorial@bkr_tut_ig3@', name = 'machinic_loop_mechandplayer', blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1}
        }
    },
    modBackWheels = { -- this is technically not in use; only for the label of modBackWheels. 
        label = 'Wheels Rear', modType = 24, category = '', point = 'wheel',
        prop = {model = 'imp_prop_impexp_tyre_01c', pos = {0.0, -0.1, 0.2}, rot = {0.0, 0.0, 0.0}},
        anim = {
            idle = {dict = 'anim@heists@box_carry@', name = 'idle', blendIn = 4.0, blendOut = 1.0, duration = -1, flags = 49},
            install = {dict = 'anim@amb@clubhouse@tutorial@bkr_tut_ig3@', name = 'machinic_loop_mechandplayer', blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1}
        }
    },
    modPlateHolder = {
        label = 'Plate Holder', modType = 25, category = 'exterior', price = 4.95, point = 'vehicle',
        prop = {model = 'prop_cs_cardbox_01', pos = {0.0, -0.2, -0.1}, rot = {135.0, 0.0, 0.0}},
        anim = {
            idle = {dict = 'anim@heists@box_carry@', name = 'idle', blendIn = 4.0, blendOut = 1.0, duration = -1, flags = 49},
            install = {dict = 'mp_intro_seq@', name = 'mp_mech_fix', blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1}
        }
    },
    modVanityPlate = { -- sometimes is: CANARDS, SPLITTER, 
        label = 'Vanity Plates', modType = 26, category = 'exterior', price = 700, point = 'vehicle',
        prop = {model = 'prop_cs_cardbox_01', pos = {0.0, -0.2, -0.1}, rot = {135.0, 0.0, 0.0}},
        anim = {
            idle = {dict = 'anim@heists@box_carry@', name = 'idle', blendIn = 4.0, blendOut = 1.0, duration = -1, flags = 49},
            install = {dict = 'mp_intro_seq@', name = 'mp_mech_fix', blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1}
        }
    },
    modTrimA = {
        label = 'Trim A', modType = 27, price = 300, category = 'interior', point = 'vehicle',
        prop = {model = 'prop_cs_cardbox_01', pos = {0.0, -0.2, -0.1}, rot = {135.0, 0.0, 0.0}},
        anim = {
            idle = {dict = 'anim@heists@box_carry@', name = 'idle', blendIn = 4.0, blendOut = 1.0, duration = -1, flags = 49},
            install = {dict = 'anim@amb@clubhouse@tutorial@bkr_tut_ig3@', name = 'machinic_loop_mechandplayer', blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1}
        }
    },
    modOrnaments = {
        label = 'Ornaments', modType = 28, price = 250, category = 'interior', point = 'vehicle',
        prop = {model = 'prop_cs_cardbox_01', pos = {0.0, -0.2, -0.1}, rot = {135.0, 0.0, 0.0}},
        anim = {
            idle = {dict = 'anim@heists@box_carry@', name = 'idle', blendIn = 4.0, blendOut = 1.0, duration = -1, flags = 49},
            install = {dict = 'anim@amb@clubhouse@tutorial@bkr_tut_ig3@', name = 'machinic_loop_mechandplayer', blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1}
        }
    },
    modDashboard = {
        label = 'Dashboard', modType = 29, price = 400, category = 'interior', point = 'vehicle',
        prop = {model = 'prop_cs_package_01', pos = {0.0, -0.05, -0.1}, rot = {100.0, 0.0, 0.0}},
        anim = {
            idle = {dict = 'anim@heists@box_carry@', name = 'idle', blendIn = 4.0, blendOut = 1.0, duration = -1, flags = 49},
            install = {dict = 'anim@amb@clubhouse@tutorial@bkr_tut_ig3@', name = 'machinic_loop_mechandplayer', blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1}
        }
    },
    modDial = {
        label = 'Gauges', modType = 30, price = 350, category = 'interior', point = 'vehicle',
        prop = {model = 'prop_cs_cardbox_01', pos = {0.0, -0.2, -0.1}, rot = {135.0, 0.0, 0.0}},
        anim = {
            idle = {dict = 'anim@heists@box_carry@', name = 'idle', blendIn = 4.0, blendOut = 1.0, duration = -1, flags = 49},
            install = {dict = 'anim@amb@clubhouse@tutorial@bkr_tut_ig3@', name = 'machinic_loop_mechandplayer', blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1}
        }
    },
    modDoorSpeaker = {
        label = 'Door Speaker', modType = 31, price = 650, category = 'interior', point = 'vehicle',
        prop = {model = 'prop_cs_cardbox_01', pos = {0.0, -0.2, -0.1}, rot = {135.0, 0.0, 0.0}},
        anim = {
            idle = {dict = 'anim@heists@box_carry@', name = 'idle', blendIn = 4.0, blendOut = 1.0, duration = -1, flags = 49},
            install = {dict = 'anim@amb@clubhouse@tutorial@bkr_tut_ig3@', name = 'machinic_loop_mechandplayer', blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1}
        }
    },
    modSeats = {
        label = 'Seats', modType = 32, price = 1400, category = 'interior', point = 'vehicle',
        prop = {model = 'prop_ejector_seat_01', pos = {0.0, -0.3, 0.07}, rot = {30.0, 0.0, 0.0}},
        anim = {
            idle = {dict = 'anim@heists@box_carry@', name = 'idle', blendIn = 4.0, blendOut = 1.0, duration = -1, flags = 49},
            install = {dict = 'anim@amb@clubhouse@tutorial@bkr_tut_ig3@', name = 'machinic_loop_mechandplayer', blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1}
        }
    },
    modSteeringWheel = {
        label = 'Steering Wheel', modType = 33, price = 950, category = 'interior', point = 'vehicle',
        prop = {model = 'prop_cs_cardbox_01', pos = {0.0, -0.2, -0.1}, rot = {135.0, 0.0, 0.0}},
        anim = {
            idle = {dict = 'anim@heists@box_carry@', name = 'idle', blendIn = 4.0, blendOut = 1.0, duration = -1, flags = 49},
            install = {dict = 'anim@amb@clubhouse@tutorial@bkr_tut_ig3@', name = 'machinic_loop_mechandplayer', blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1}
        }
    },
    modShifterLeavers = {
        label = 'Shifter Leaver', modType = 34, price = 450, category = 'interior', point = 'vehicle',
        prop = {model = 'prop_cs_cardbox_01', pos = {0.0, -0.2, -0.1}, rot = {135.0, 0.0, 0.0}},
        anim = {
            idle = {dict = 'anim@heists@box_carry@', name = 'idle', blendIn = 4.0, blendOut = 1.0, duration = -1, flags = 49},
            install = {dict = 'anim@amb@clubhouse@tutorial@bkr_tut_ig3@', name = 'machinic_loop_mechandplayer', blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1}
        }
    },
    modAPlate = {
        label = 'Plaque', modType = 35, price = 800, category = 'interior', point = 'vehicle',
        prop = {model = 'prop_cs_cardbox_01', pos = {0.0, -0.2, -0.1}, rot = {135.0, 0.0, 0.0}},
        anim = {
            idle = {dict = 'anim@heists@box_carry@', name = 'idle', blendIn = 4.0, blendOut = 1.0, duration = -1, flags = 49},
            install = {dict = 'anim@amb@clubhouse@tutorial@bkr_tut_ig3@', name = 'machinic_loop_mechandplayer', blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1}
        }
    },
    modSpeakers = {
        label = 'Speaker', modType = 36, price = 1200, category = 'interior', point = 'vehicle',
        prop = {model = 'sm_prop_smug_speaker', pos = {0.0, -0.1, -0.2}, rot = {-15.0, 0.0, 0.0}},
        anim = {
            idle = {dict = 'anim@heists@box_carry@', name = 'idle', blendIn = 4.0, blendOut = 1.0, duration = -1, flags = 49},
            install = {dict = 'anim@amb@clubhouse@tutorial@bkr_tut_ig3@', name = 'machinic_loop_mechandplayer', blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1}
        }
    },
    modTrunk = {
        label = 'Trunk', modType = 37, price = 2300, category = 'interior', point = 'rear',
        prop = {model = 'imp_prop_impexp_trunk_01a', pos = {0.0, 0.15, 0.1}, rot = {30.0, 0.0, 0.0}},
        anim = {
            idle = {dict = 'anim@heists@box_carry@', name = 'idle', blendIn = 4.0, blendOut = 1.0, duration = -1, flags = 49},
            install = {dict = 'mini@repair', name = 'fixing_a_player', blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1}
        }
    },
    modHydrolic = {
        label = 'Hydraulics', modType = 38, price = 5400, category = 'exterior', point = 'vehicle',
        prop = {model = 'prop_cs_cardbox_01', pos = {0.0, -0.2, -0.1}, rot = {135.0, 0.0, 0.0}},
        anim = {
            idle = {dict = 'anim@heists@box_carry@', name = 'idle', blendIn = 4.0, blendOut = 1.0, duration = -1, flags = 49},
            install = {dict = 'anim@amb@clubhouse@tutorial@bkr_tut_ig3@', name = 'machinic_loop_mechandplayer', blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1}
        }
    },
    modEngineBlock = {
        label = 'Engine Block', modType = 39, price = 1600, category = 'enginebay', point = 'engine',
        prop = {model = 'prop_cs_cardbox_01', pos = {0.0, -0.2, -0.1}, rot = {135.0, 0.0, 0.0}},
        anim = {
            idle = {dict = 'anim@heists@box_carry@', name = 'idle', blendIn = 4.0, blendOut = 1.0, duration = -1, flags = 49},
            install = {dict = 'mini@repair', name = 'fixing_a_player', blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1}
        }
    },
    modAirFilter = {
        label = 'Air Filters', modType = 40, price = 1300, category = 'enginebay', point = 'engine',
        prop = {model = 'prop_cs_cardbox_01', pos = {0.0, -0.2, -0.1}, rot = {135.0, 0.0, 0.0}},
        anim = {
            idle = {dict = 'anim@heists@box_carry@', name = 'idle', blendIn = 4.0, blendOut = 1.0, duration = -1, flags = 49},
            install = {dict = 'mini@repair', name = 'fixing_a_player', blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1}
        }
    },
    modStruts = {
        label = 'Strut Brace', modType = 41, price = 1400, category = 'enginebay', point = 'engine',
        prop = {model = 'prop_cs_cardbox_01', pos = {0.0, -0.2, -0.1}, rot = {135.0, 0.0, 0.0}},
        anim = {
            idle = {dict = 'anim@heists@box_carry@', name = 'idle', blendIn = 4.0, blendOut = 1.0, duration = -1, flags = 49},
            install = {dict = 'mini@repair', name = 'fixing_a_player', blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1}
        }
    },
    modArchCover = {
        label = 'Arch Cover', modType = 42, price = 900, category = 'chassis', point = 'vehicle',
        prop = {model = 'prop_cs_cardbox_01', pos = {0.0, -0.2, -0.1}, rot = {135.0, 0.0, 0.0}},
        anim = {
            idle = {dict = 'anim@heists@box_carry@', name = 'idle', blendIn = 4.0, blendOut = 1.0, duration = -1, flags = 49},
            install = {dict = 'anim@amb@clubhouse@tutorial@bkr_tut_ig3@', name = 'machinic_loop_mechandplayer', blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1}
        }
    },
    modAerials = {
        label = 'Aerials', modType = 43, price = 600, category = 'chassis', point = 'vehicle',
        prop = {model = 'prop_cs_cardbox_01', pos = {0.0, -0.2, -0.1}, rot = {135.0, 0.0, 0.0}},
        anim = {
            idle = {dict = 'anim@heists@box_carry@', name = 'idle', blendIn = 4.0, blendOut = 1.0, duration = -1, flags = 49},
            install = {dict = 'anim@amb@clubhouse@tutorial@bkr_tut_ig3@', name = 'machinic_loop_mechandplayer', blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1}
        }
    },
    modTrimB = {
        label = 'Trim B', modType = 44, price = 1100, category = 'chassis', point = 'vehicle',
        prop = {model = 'prop_cs_cardbox_01', pos = {0.0, -0.2, -0.1}, rot = {135.0, 0.0, 0.0}},
        anim = {
            idle = {dict = 'anim@heists@box_carry@', name = 'idle', blendIn = 4.0, blendOut = 1.0, duration = -1, flags = 49},
            install = {dict = 'anim@amb@clubhouse@tutorial@bkr_tut_ig3@', name = 'machinic_loop_mechandplayer', blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1}
        }
    },
    modTank = {
        label = 'Fuel Tank', modType = 45, price = 1900, category = 'chassis', point = 'vehicle',
        prop = {model = 'prop_cs_cardbox_01', pos = {0.0, -0.2, -0.1}, rot = {135.0, 0.0, 0.0}},
        anim = {
            idle = {dict = 'anim@heists@box_carry@', name = 'idle', blendIn = 4.0, blendOut = 1.0, duration = -1, flags = 49},
            install = {dict = 'anim@amb@clubhouse@tutorial@bkr_tut_ig3@', name = 'machinic_loop_mechandplayer', blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1}
        }
    },
    modWindows = {
        label = 'Left Door', modType = 46, price = 1700, category = 'exterior', point = 'vehicle',
        prop = {model = 'imp_prop_impexp_car_door_04a', pos = {-0.7, -0.2, 0.0}, rot = {0.0, -10.0, 90.0}},
        anim = {
            idle = {dict = 'anim@heists@box_carry@', name = 'idle', blendIn = 4.0, blendOut = 1.0, duration = -1, flags = 49},
            install = {dict = 'anim@amb@clubhouse@tutorial@bkr_tut_ig3@', name = 'machinic_loop_mechandplayer', blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1}
        }
    },
    modDoorR = {
        label = 'Right Door', modType = 47, price = 1700, category = 'exterior', point = 'vehicle',
        prop = {model = 'imp_prop_impexp_car_door_04a', pos = {-0.7, -0.2, 0.0}, rot = {0.0, -10.0, 90.0}},
        anim = {
            idle = {dict = 'anim@heists@box_carry@', name = 'idle', blendIn = 4.0, blendOut = 1.0, duration = -1, flags = 49},
            install = {dict = 'anim@amb@clubhouse@tutorial@bkr_tut_ig3@', name = 'machinic_loop_mechandplayer', blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1}
        }
    },
    modLivery = {
        label = 'Livery', modType = 48, price = 1500, category = 'respray', point = 'vehicle',
        prop = {model = 'v_ind_cfwrap', pos = {0.0, -0.10, -0.15}, rot = {0.0, 0.0, 0.0}},
        anim = {
            idle = {dict = 'anim@heists@box_carry@', name = 'idle', blendIn = 4.0, blendOut = 1.0, duration = -1, flags = 49},
            install = {dict = 'anim@amb@business@weed@weed_inspecting_lo_med_hi@', name = 'weed_spraybottle_crouch_spraying_03_inspector', blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1}
        }
    },
    modRoofLivery = {
        label = 'Roof Livery', modType = 'modRoofLivery', price = 250, category = 'respray', point = 'vehicle',
        prop = {model = 'v_ind_cfwrap', pos = {0.0, -0.10, -0.15}, rot = {0.0, 0.0, 0.0}},
        anim = {
            idle = {dict = 'anim@heists@box_carry@', name = 'idle', blendIn = 4.0, blendOut = 1.0, duration = -1, flags = 49},
            install = {dict = 'anim@amb@business@weed@weed_inspecting_lo_med_hi@', name = 'weed_spraybottle_crouch_spraying_03_inspector', blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1}
        }
    },
    modLightbar = {
        label = 'Lightbar', modType = 49, price = 900, category = 'exterior', point = 'vehicle',
        prop = {model = 'prop_cs_cardbox_01', pos = {0.0, -0.2, -0.1}, rot = {135.0, 0.0, 0.0}},
        anim = {
            idle = {dict = 'anim@heists@box_carry@', name = 'idle', blendIn = 4.0, blendOut = 1.0, duration = -1, flags = 49},
            install = {dict = 'mini@repair', name = 'fixing_a_player', blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1}
        }
    },
    neonEnabled = {
        label = 'Neon Kits', modType = 'neonEnabled', price = 1000, category = 'lights', point = 'engine',
        variants = {
            ['0'] = {label = 'Left Light Kit',      index = 0},
            ['1'] = {label = 'Right Light Kit',	    index = 1},
            ['2'] = {label = 'Front Light Kit',	    index = 2},
            ['3'] = {label = 'Rear Light Kit',	    index = 3},
        },
        prop = {model = 'prop_cs_package_01', pos = {0.0, -0.05, -0.1}, rot = {100.0, 0.0, 0.0}},
        anim = {
            idle = {dict = 'anim@heists@box_carry@', name = 'idle', blendIn = 4.0, blendOut = 1.0, duration = -1, flags = 49},
            install = {dict = 'mini@repair', name = 'fixing_a_player', blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1}
        }
    },
    xenonColor = {
        label = 'Xenon Colors', modType = 'xenonColor', price = 250, category = 'lights', point = 'engine',
        variants = {
            ['-1'] = {label = 'Default',        index = -1},
            ['0'] = {label = 'White',           index = 0},
            ['1'] = {label = 'Blue',            index = 1},
            ['2'] = {label = 'Electric Blue',   index = 2},
            ['3'] = {label = 'Mint Green', 		index = 3},
            ['4'] = {label = 'Lime Green', 		index = 4},
            ['5'] = {label = 'Yellow', 			index = 5},
            ['6'] = {label = 'Golden Shower', 	index = 6},
            ['7'] = {label = 'Orange', 			index = 7},
            ['8'] = {label = 'Red', 			index = 8},
            ['9'] = {label = 'Pony Pink', 		index = 9},
            ['10'] = {label = 'Hot Pink', 		index = 10},
            ['11'] = {label = 'Purple', 		index = 11},
            ['12'] = {label = 'Blacklight', 	index = 12},
        },
        prop = {model = 'prop_cs_package_01', pos = {0.0, -0.05, -0.1}, rot = {100.0, 0.0, 0.0}},
        anim = {
            idle = {dict = 'anim@heists@box_carry@', name = 'idle', blendIn = 4.0, blendOut = 1.0, duration = -1, flags = 49},
            install = {dict = 'mini@repair', name = 'fixing_a_player', blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1}
        }
    },
    customXenon = {
        label = 'Xenon Custom', modType = 'customXenon', price = 600, category = '', point = 'engine',
        prop = {model = 'prop_cs_package_01', pos = {0.0, -0.05, -0.1}, rot = {100.0, 0.0, 0.0}},
        anim = {
            idle = {dict = 'anim@heists@box_carry@', name = 'idle', blendIn = 4.0, blendOut = 1.0, duration = -1, flags = 49},
            install = {dict = 'mini@repair', name = 'fixing_a_player', blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1}
        }
    },
    neonColor = {
        label = 'Neon Colors', modType = 'neonColor', price = 200, category = 'lights', point = 'engine',
        variants = {
            ['-1'] = {label = 'Stock', 			    rgb = {0, 0, 0}},
            ['0'] = {label = 'White', 				rgb = {222, 222, 255}},
            ['1'] = {label = 'Blue', 				rgb = {2, 21, 255}},
            ['2'] = {label = 'Electric Blue', 		rgb = {3, 83, 255}},
            ['3'] = {label = 'Mint Green', 			rgb = {0, 255, 140}},
            ['4'] = {label = 'Lime Green', 			rgb = {94, 222, 1}},
            ['5'] = {label = 'Yellow', 				rgb = {255, 255, 0}},
            ['6'] = {label = 'Golden Shower',		rgb = {255, 150, 0}},
            ['7'] = {label = 'Orange', 				rgb = {255, 62, 0}},
            ['8'] = {label = 'Red', 				rgb = {255, 1, 1}},
            ['9'] = {label = 'Pony Pink', 			rgb = {255, 50, 100}},
            ['10'] = {label = 'Hot Pink', 			rgb = {255, 5, 190}},
            ['11'] = {label = 'Purple', 			rgb = {35, 1, 255}},
            ['12'] = {label = 'Blacklight', 		rgb = {15, 3, 255}}
        },
        prop = {model = 'prop_cs_package_01', pos = {0.0, -0.05, -0.1}, rot = {100.0, 0.0, 0.0}},
        anim = {
            idle = {dict = 'anim@heists@box_carry@', name = 'idle', blendIn = 4.0, blendOut = 1.0, duration = -1, flags = 49},
            install = {dict = 'mini@repair', name = 'fixing_a_player', blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1}
        }
    },
    tyreSmokeColor = {
        label = 'Tyre Smoke Color', modType = 20, price = 150, category = 'wheels', point = 'wheel',
        variants = {
            ['0'] = {label = 'White',  rgb = {254, 254, 254}},
            ['1'] = {label = 'Black',  rgb = {1, 1, 1}},
            ['2'] = {label = 'Blue',   rgb = {0, 150, 255}},
            ['3'] = {label = 'Yellow', rgb = {255, 255, 50}},
            ['4'] = {label = 'Orange', rgb = {255, 153, 51}},
            ['5'] = {label = 'Red',    rgb = {255, 10, 10}},
            ['6'] = {label = 'Green',  rgb = {10, 255, 10}},
            ['7'] = {label = 'Purple', rgb = {153, 10, 153}},
            ['8'] = {label = 'Pink',   rgb = {255, 102, 178}},
            ['9'] = {label = 'Gray',   rgb = {128, 128, 128}}
        },
        prop = {model = 'imp_prop_impexp_tyre_01a', pos = {0.0, -0.10, 0.15}, rot = {0.0, 0.0, 0.0}},
        anim = {
            idle = {dict = 'anim@heists@box_carry@', name = 'idle', blendIn = 4.0, blendOut = 1.0, duration = -1, flags = 49},
            install = {dict = 'anim@amb@clubhouse@tutorial@bkr_tut_ig3@', name = 'machinic_loop_mechandplayer', blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1}
        }
    },
    extras = {
        label = 'Extras', modType = 'extras', category = 'exterior', point = 'vehicle',
        variants = {
            ['0'] = {label = 'Stock',		index = 1,		price = 200},
            ['1'] = {label = 'Extra',		index = 0,		price = 1000},
        },
        prop = {model = 'prop_cs_package_01', pos = {0.0, -0.05, -0.1}, rot = {100.0, 0.0, 0.0}},
        anim = {
            idle = {dict = 'anim@heists@box_carry@', name = 'idle', blendIn = 4.0, blendOut = 1.0, duration = -1, flags = 49},
            install = {dict = 'mini@repair', name = 'fixing_a_player', blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1}
        }
    },
    plateIndex = {
        label = 'License Plates', modType = 'plateIndex', category = 'exterior', point = 'rear',
        variants = {
            ['0'] = {label = 'Blue on White 1', 	    index = 0,					price = 300},
            ['1'] = {label = 'Yellow on Black', 	    index = 1,					price = 400},
            ['2'] = {label = 'Yellow on Blue', 		    index = 2,					price = 500},
            ['3'] = {label = 'Blue on White 2', 	    index = 3,					price = 600},
            ['4'] = {label = 'Blue on White 3', 	    index = 4,					price = 700},
            ['5'] = {label = 'Yankton', 			    index = 5,					price = 800},
            -- These requires gamebuild 3095:
            ['6'] = {label = 'eCola', 	                index = 6,					price = 900},
            ['7'] = {label = 'Las Venturas', 		    index = 7,					price = 1000},
            ['8'] = {label = 'Liberty City', 	        index = 8,					price = 1100},
            ['9'] = {label = 'Los Santos Car Meet',     index = 9,					price = 1200},
            ['10'] = {label = 'Los Santos Panic',       index = 10,					price = 1300},
            ['11'] = {label = 'Los Santos Pounders',    index = 11,					price = 1400},
            ['12'] = {label = 'Sprunk', 	            index = 12,					price = 1500},
        },
        prop = {model = 'p_num_plate_01', pos = {0.01, -0.1, -0.18}, rot = {-60.0, 0.0, 0.0}},
        anim = {
            idle = {dict = 'anim@heists@box_carry@', name = 'idle', blendIn = 4.0, blendOut = 1.0, duration = -1, flags = 49},
            install = {dict = 'anim@amb@clubhouse@tutorial@bkr_tut_ig3@', name = 'machinic_loop_mechandplayer', blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1}
        }
    },
    windowTint = {
        label = 'Window Tints', modType = 'windowTint', category = 'exterior', point = 'vehicle',
        variants = {
            ['0'] = {label = 'None',				index = 0,					price = 300},
            ['1'] = {label = 'Pure black',			index = 1,					price = 2500},
            ['2'] = {label = 'Dark Smoke',			index = 2,					price = 1800},
            ['3'] = {label = 'Light Smoke',			index = 3,					price = 1200},
            ['4'] = {label = 'Stock',				index = 4,					price = 300},
            ['5'] = {label = 'Green',				index = 5,					price = 2200}
        },
        prop = {model = 'h4_prop_yacht_glass_04', pos = {0.0, -0.1, 0.3}, rot = {0.0, 0.0, 0.0}},
        anim = {
            idle = {dict = 'anim@heists@box_carry@', name = 'idle', blendIn = 4.0, blendOut = 1.0, duration = -1, flags = 49},
            install = {dict = 'mini@repair', name = 'fixing_a_player', blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1}
        }
    },
    color1 = {
        label = 'Primary Color', modType = 'color1', price = 300, category = 'respray', point = 'vehicle',
        prop = {model = 'ng_proc_spraycan01b', pos = {0.072, 0.041, -0.06}, rot = {33.0, 38.0, 0.0}},
        anim = {
            idle = {dict = nil, name = nil, blendIn = 4.0, blendOut = 1.0, duration = -1, flags = 49},
            install = {dict = 'anim@amb@business@weed@weed_inspecting_lo_med_hi@', name = 'weed_spraybottle_crouch_spraying_03_inspector', blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1}
        }
    },
    color2 = {
        label = 'Secondary Color', modType = 'color2', price = 200, category = 'respray', point = 'vehicle',
        prop = {model = 'ng_proc_spraycan01b', pos = {0.072, 0.041, -0.06}, rot = {33.0, 38.0, 0.0}},
        anim = {
            idle = {dict = nil, name = nil, blendIn = 4.0, blendOut = 1.0, duration = -1, flags = 49},
            install = {dict = 'anim@amb@business@weed@weed_inspecting_lo_med_hi@', name = 'weed_spraybottle_crouch_spraying_03_inspector', blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1}
        }
    },
    pearlescentColor = {
        label = 'Pearlescent Color', modType = 'pearlescentColor', price = 100, category = 'respray', point = 'vehicle',
        prop = {model = 'ng_proc_spraycan01b', pos = {0.072, 0.041, -0.06}, rot = {33.0, 38.0, 0.0}},
        anim = {
            idle = {dict = nil, name = nil, blendIn = 4.0, blendOut = 1.0, duration = -1, flags = 49},
            install = {dict = 'anim@amb@business@weed@weed_inspecting_lo_med_hi@', name = 'weed_spraybottle_crouch_spraying_03_inspector', blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1}
        }
    },
    wheelColor = {
        label = 'Wheel Color', modType = 'wheelColor', price = 200, category = 'wheels', point = 'wheel',
        prop = {model = 'ng_proc_spraycan01b', pos = {0.072, 0.041, -0.06}, rot = {33.0, 38.0, 0.0}},
        anim = {
            idle = {dict = nil, name = nil, blendIn = 4.0, blendOut = 1.0, duration = -1, flags = 49},
            install = {dict = 'anim@amb@business@weed@weed_inspecting_lo_med_hi@', name = 'weed_spraybottle_crouch_spraying_03_inspector', blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1}
        }
    },
    dashboardColor = {
        label = 'Dashboard Color', modType = 'dashboardColor', price = 100, category = 'respray', point = 'vehicle',
        prop = {model = 'ng_proc_spraycan01b', pos = {0.072, 0.041, -0.06}, rot = {33.0, 38.0, 0.0}},
        anim = {
            idle = {dict = nil, name = nil, blendIn = 4.0, blendOut = 1.0, duration = -1, flags = 49},
            install = {dict = 'anim@amb@business@weed@weed_inspecting_lo_med_hi@', name = 'weed_spraybottle_crouch_spraying_03_inspector', blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1}
        }
    },
    interiorColor = {
        label = 'Interior Color', modType = 'interiorColor', price = 100, category = 'respray', point = 'vehicle',
        prop = {model = 'ng_proc_spraycan01b', pos = {0.072, 0.041, -0.06}, rot = {33.0, 38.0, 0.0}},
        anim = {
            idle = {dict = nil, name = nil, blendIn = 4.0, blendOut = 1.0, duration = -1, flags = 49},
            install = {dict = 'anim@amb@business@weed@weed_inspecting_lo_med_hi@', name = 'weed_spraybottle_crouch_spraying_03_inspector', blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1}
        }
    },
    driftTyres = {
        label = 'Drift Tyres', modType = 'driftTyres', price = 1000, category = '', point = 'wheel',
        prop = {model = 'imp_prop_impexp_tyre_01a', pos = {0.0, -0.10, 0.15}, rot = {0.0, 0.0, 0.0}},
        anim = {
            idle = {dict = 'anim@heists@box_carry@', name = 'idle', blendIn = 4.0, blendOut = 1.0, duration = -1, flags = 49},
            install = {dict = 'anim@amb@clubhouse@tutorial@bkr_tut_ig3@', name = 'machinic_loop_mechandplayer', blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1}
        }
    },
    bulletProofTyres = {
        label = 'Bulletproof Tyres', modType = 'bulletProofTyres', price = 3500, category = '', point = 'wheel',
        prop = {model = 'imp_prop_impexp_tyre_01a', pos = {0.0, -0.10, 0.15}, rot = {0.0, 0.0, 0.0}},
        anim = {
            idle = {dict = 'anim@heists@box_carry@', name = 'idle', blendIn = 4.0, blendOut = 1.0, duration = -1, flags = 49},
            install = {dict = 'anim@amb@clubhouse@tutorial@bkr_tut_ig3@', name = 'machinic_loop_mechandplayer', blendIn = 2.0, blendOut = 2.0, duration = -1, flag = 1}
        }
    }
}
-- Type: Table
```

</details>

**Usage:** Each mod entry contains:

* **`label`**: (String) Display name for the mod. Used as a fallback if the game label cannot be retrieved.
* **`modType`**: (String or Integer) Identifier the mod. <mark style="color:red;">Do not edit this value!</mark>
* **`price`**: (Integer) Base price for the mod before escalation price and other price modifiers. If the `price` attribute is absent, it is defined in the `variants` attribute for each variant option.
* **`category`**: (String) The category to which the mod option belongs. Refer to [`Config.ModCategories`](#config.modcategories) for available categories. <mark style="color:red;">Some categories are set to</mark> <mark style="color:red;"></mark><mark style="color:red;">`''`</mark><mark style="color:red;">, do not touch these!</mark>
* **`point`**: (String) Specifies the 3rd-eye target position on the vehicle for item-based installations:
  * `'rear'`: Rear end of the vehicle.
  * `'front'`: Front end of the vehicle.
  * `'engine'`: Engine of the vehicle.
  * `'wheels'`: Any closest wheel.
  * `'vehicle'`: The whole vehicle.
* **`prop`**: (Table) Properties for the prop/object created during item-based installations:
  * **`model`**: (String) Model name of the prop.
  * **`pos`**: (Table) Position of the prop relative to the player (offset).
  * **`rot`**: (Table) Rotation offsets for the prop.
* **`anim`**: (Table) Animation details for idle and installation:

  * **`idle`**:  (Table) the idle animation when carrying the spawned prop.
  * **`install`**: (Table) the install animation when installing the selected mod variant.

  Each contains the following properties:

  * **`dict`**: (String) Animation dictionary.
  * **`name`**: (String) Animation name.
  * **`blendIn`**: (Float) Blend-in time.
  * **`blendOut`**: (Float) Blend-out time.
  * **`duration`**: (Integer) Duration of the animation.
  * **`flags`**: (Integer) Animation flags.
* **`variants`**: (Table) Contains different variations of a mod, each with its `label`, `index`, and `price`. Each variant contains:&#x20;
  * **`label`**: (String) Display name of the variant.
  * **`index`**: (Integer) Identifier for the variant. <mark style="color:red;">Do not edit this value!</mark>
  * **`price`**: (Integer) Price for the variant.

{% hint style="warning" %}
We do not assist with getting offset, prop names, anim dicts/names. It's on you. If you mess it up and need assistance, you'll be required to revert back to default.&#x20;
{% endhint %}

## Config.ColorCategories

Defines color categories used with [`Config.Colors`](#config.colors). Each category specifies properties such as `name`, `label`, `paintType`, and `price`. Customize these categories to fit your application needs.

```lua
Config.ColorCategories = {
    {name = 'metallic', label = 'Metallic', paintType = 1, price = 250},
    {name = 'matte', label = 'Matte', paintType = 3, price = 350},
    {name = 'metals', label = 'Metals', paintType = 4, price = 500},
    {name = 'util', label = 'Util', paintType = 1, price = 700},
    {name = 'worn', label = 'Worn', paintType = 1, price = 750},
    {name = 'chameleon', label = 'Chameleon', paintType = 6, price = 1000}
}
-- Type: Table
```

**Usage:** Each color category contains the following properties:

* **`name`**: (String) Name of the category. <mark style="color:red;">Do not change this value as it identifies the category in the system.</mark>
* **`label`**: (String) User-defined label for the category, used for display purposes.
* **`paintType`**: (Integer) GTA paint type for the category. <mark style="color:red;">Do not change this value!</mark>
* **`price`**: (Integer) Additional price for using colors in this category. This price is added on top of the base price defined in [`Config.Mods`](#config.mods).

{% hint style="danger" %}
Customize `label` and `price` to fit your pricing model. Ensure that `name` and `paintType` remain unchanged to maintain functionality.
{% endhint %}

## Config.Colors

Defines the available color options for each [`Config.ColorCategories`](#config.colorcategories) category. Each color includes properties such as `label` and `index`. Customize these colors as needed.

<details>

<summary>Config.Colors (click to expandd)</summary>

<pre class="language-lua" data-full-width="false"><code class="lang-lua"><strong>Config.Colors = {
</strong>	['metallic'] = {
		{label = 'Black', index = 0},
		{label = 'Graphite Black', index = 1},
		{label = 'Black Steel', index = 2},
		{label = 'Dark Silver', index = 3},
		{label = 'Silver', index = 4},
		{label = 'Blue Silver', index = 5},
		{label = 'Steel Grey', index = 6},
		{label = 'Shadow Silver', index = 7},
		{label = 'Stone Silver', index = 8},
		{label = 'Midnight Silver', index = 9},
		{label = 'Gun Metal', index = 10},
		{label = 'Anthracite Grey', index = 11},
		{label = 'Red', index = 27},
		{label = 'Torino Red', index = 28},
		{label = 'Formula Red', index = 29},
		{label = 'Blaze Red', index = 30},
		{label = 'Graceful Red', index = 31},
		{label = 'Garnet Red', index = 32},
		{label = 'Desert Red', index = 33},
		{label = 'Cabernet Red', index = 34},
		{label = 'Candy Red', index = 35},
		{label = 'Sunrise Orange', index = 36},
		{label = 'Classic Gold', index = 37},
		{label = 'Orange', index = 38},
		{label = 'Dark Green', index = 49},
		{label = 'Racing Green', index = 50},
		{label = 'Sea Green', index = 51},
		{label = 'Olive Green', index = 52},
		{label = 'Green', index = 53},
		{label = 'Gasoline Blue Green', index = 54},
		{label = 'Midnight Blue', index = 61},
		{label = 'Dark Blue', index = 62},
		{label = 'Saxony Blue', index = 63},
		{label = 'Blue', index = 64},
		{label = 'Mariner Blue', index = 65},
		{label = 'Harbor Blue', index = 66},
		{label = 'Diamond Blue', index = 67},
		{label = 'Surf Blue', index = 68},
		{label = 'Nautical Blue', index = 69},
		{label = 'Bright Blue', index = 70},
		{label = 'Purple Blue', index = 71},
		{label = 'Spinnaker Blue', index = 72},
		{label = 'Ultra Blue', index = 73},
		{label = 'Light Blue', index = 74},
		{label = 'Taxi Yellow', index = 88},
		{label = 'Race Yellow', index = 89},
		{label = 'Bronze', index = 90},
		{label = 'Yellow Bird', index = 91},
		{label = 'Lime', index = 92},
		{label = 'Champagne', index = 93},
		{label = 'Pueblo Beige', index = 94},
		{label = 'Dark Ivory', index = 95},
		{label = 'Choco Brown', index = 96},
		{label = 'Golden Brown', index = 97},
		{label = 'Light Brown', index = 98},
		{label = 'Straw Beige', index = 99},
		{label = 'Moss Brown', index = 100},
		{label = 'Biston Brown', index = 101},
		{label = 'Beechwood', index = 102},
		{label = 'Dark Beechwood', index = 103},
		{label = 'Choco Orange', index = 104},
		{label = 'Beach Sand', index = 105},
		{label = 'Sun Bleeched Sand', index = 106},
		{label = 'Cream', index = 107},
		{label = 'White', index = 111},
		{label = 'Frost White', index = 112},
		{label = 'Securicor Green', index = 125},
		{label = 'Pure White', index = 134},
		{label = 'Hot Pink', index = 135},
		{label = 'Salmon pink', index = 136},
		{label = 'Vermillion Pink', index = 137},
		{label = 'Bright Orange', index = 138},
		{label = 'Bright Green', index = 139},
		{label = 'Bright Blue', index = 140},
		{label = 'Black Blue', index = 141},
		{label = 'Black Purple', index = 142},
		{label = 'Black Red', index = 143},
		{label = 'Purple', index = 145},
		{label = 'V Dark Blue', index = 146},
		{label = 'Carbon Black', index = 147},
		{label = 'Lava Red', index = 150}
	},
	['matte'] = {
		{label = 'Black', index = 12},
		{label = 'Gray', index = 13},
		{label = 'Light Grey', index = 14},
		{label = 'Red', index = 39},
		{label = 'Dark Red', index = 40},
		{label = 'Orange', index = 41},
		{label = 'Yellow', index = 42},
		{label = 'Lime Green', index = 55},
		{label = 'Dark Blue', index = 82},
		{label = 'Blue', index = 83},
		{label = 'Midnight Blue', index = 84},
		{label = 'Green', index = 128},
		{label = 'Brown', index = 129},
		{label = 'White', index = 131},
		{label = 'Purple', index = 148},
		{label = 'Dark Purple', index = 149},
		{label = 'Forest Green', index = 151},
		{label = 'Olive Drab', index = 152},
		{label = 'Desert Brown', index = 153},
		{label = 'Desert Tan', index = 154},
		{label = 'Foliage Green', index = 155}
	},
	['metals'] = {
		{label = 'Brushed Steel', index = 117},
		{label = 'Brushed Black Steel', index = 118},
		{label = 'Brushed Aluminum', index = 119},
		{label = 'Chrome', index = 120},
		{label = 'Alloy', index = 156},
		{label = 'Epsilon Blue', index = 157},
		{label = 'Pure Gold', index = 158},
		{label = 'Brushed Gold', index = 159}
	},
	['util'] = {
		{label = 'Black', index = 15},
		{label = 'Black Poly', index = 16},
		{label = 'Dark silver', index = 17},
		{label = 'Silver', index = 18},
		{label = 'Gun Metal', index = 19},
		{label = 'Shadow Silver', index = 20},
		{label = 'Red', index = 43},
		{label = 'Bright Red', index = 44},
		{label = 'Garnet Red', index = 45},
		{label = 'Dark Green', index = 56},
		{label = 'Green', index = 57},
		{label = 'Dark Blue', index = 75},
		{label = 'Midnight Blue', index = 76},
		{label = 'Blue', index = 77},
		{label = 'Sea Foam Blue', index = 78},
		{label = 'Lightning blue', index = 79},
		{label = 'Maui Blue Poly', index = 80},
		{label = 'Bright Blue', index = 81},
		{label = 'Brown', index = 108},
		{label = 'Medium Brown', index = 109},
		{label = 'Light Brown', index = 110},
		{label = 'Off White', index = 122}
	},
	['worn'] = {
		{label = 'Black', index = 21},
		{label = 'Graphite', index = 22},
		{label = 'Silver Grey', index = 23},
		{label = 'Silver', index = 24},
		{label = 'Blue Silver', index = 25},
		{label = 'Shadow Silver', index = 26},
		{label = 'Red', index = 46},
		{label = 'Golden Red', index = 47},
		{label = 'Dark Red', index = 48},
		{label = 'Dark Green', index = 58},
		{label = 'Green', index = 59},
		{label = 'Sea Wash', index = 60},
		{label = 'Dark Blue', index = 85},
		{label = 'Blue', index = 86},
		{label = 'Light Blue', index = 87},
		{label = 'Honey Beige', index = 113},
		{label = 'Brown', index = 114},
		{label = 'Dark Brown', index = 115},
		{label = 'Straw Beige', index = 116},
		{label = 'Off White', index = 121},
		{label = 'Orange', index = 123},
		{label = 'Light Orange', index = 124},
		{label = 'Taxi Yellow', index = 126},
		{label = 'Orange 2', index = 130},
		{label = 'White', index = 132},
		{label = 'Olive Army Green', index = 133}
	},
	['chameleon'] = {
        	{label = 'Anodized Red Pearl', index = 161},
        	{label = 'Anodized Wine Pearl', index = 162},
        	{label = 'Anodized Purple Pearl', index = 163},
        	{label = 'Anodized Blue Pearl', index = 164},
        	{label = 'Anodized Green Pearl', index = 165},
        	{label = 'Anodized Lime Pearl', index = 166},
        	{label = 'Anodized Copper Pearl', index = 167},
        	{label = 'Anodized Bronze Pearl', index = 168},
        	{label = 'Anodized Champagne Pearl', index = 169},
        	{label = 'Anodized Gold Pearl', index = 170},
        	{label = 'Green/Blue Flip', index = 171},
        	{label = 'Green/Red Flip', index = 172},
        	{label = 'Green/Brown Flip', index = 173},
        	{label = 'Green/Turquoise Flip', index = 174},
        	{label = 'Green/Purple Flip', index = 175},
        	{label = 'Teal/Purple Flip', index = 176},
        	{label = 'Turquoise/Red Flip', index = 177},
        	{label = 'Turquoise/Purple Flip', index = 178},
        	{label = 'Cyan/Purple Flip', index = 179},
        	{label = 'Blue/Pink Flip', index = 180},
        	{label = 'Blue/Green Flip', index = 181},
        	{label = 'Purple/Red Flip', index = 182},
        	{label = 'Purple/Green Flip', index = 183},
        	{label = 'Magenta/Green Flip', index = 184},
        	{label = 'Magenta/Yellow Flip', index = 185},
        	{label = 'Burgundy/Green Flip', index = 186},
        	{label = 'Magenta/Cyan Flip', index = 187},
        	{label = 'Copper/Purple Flip', index = 188},
        	{label = 'Magenta/Orange Flip', index = 189},
        	{label = 'Red/Orange Flip', index = 190},
        	{label = 'Orange/Purple Flip', index = 191},
        	{label = 'Orange/Blue Flip', index = 192},
        	{label = 'White/Purple Flip', index = 193},
        	{label = 'Red/Rainbow Flip', index = 194},
        	{label = 'Blue/Rainbow Flip', index = 195},
        	{label = 'Dark Green Pearl', index = 196},
        	{label = 'Dark Teal Pearl', index = 197},
        	{label = 'Dark Blue Pearl', index = 198},
        	{label = 'Dark Purple Pearl', index = 199},
        	{label = 'Oil Slick Pearl', index = 200},
        	{label = 'Light Green Pearl', index = 201},
        	{label = 'Light Blue Pearl', index = 202},
        	{label = 'Light Purple Pearl', index = 203},
        	{label = 'Light Pink Pearl', index = 204},
        	{label = 'Off White Pearl', index = 205},
        	{label = 'Cute Pink Pearl', index = 206},
        	{label = 'Baby Yellow Pearl', index = 207},
        	{label = 'Baby Green Pearl', index = 208},
        	{label = 'Baby Blue Pearl', index = 209},
        	{label = 'Cream Pearl', index = 210},
        	{label = 'White Prismatic Pearl', index = 211},
        	{label = 'Graphite Prismatic Pearl', index = 212},
        	{label = 'Blue Prismatic Pearl', index = 213},
        	{label = 'Purple Prismatic Pearl', index = 214},
        	{label = 'Hot Pink Prismatic Pearl', index = 215},
        	{label = 'Red Prismatic Pearl', index = 216},
        	{label = 'Green Prismatic Pearl', index = 217},
        	{label = 'Black Prismatic Pearl', index = 218},
        	{label = 'Oil Spill Prismatic Pearl', index = 219},
        	{label = 'Rainbow Prismatic Pearl', index = 220},
        	{label = 'Black Holographic Pearl', index = 221},
        	{label = 'White Holographic Pearl', index = 222},
        	{label = 'Fubuki-jo Specials: Monochrome', index = 223},
        	{label = 'Fubuki-jo Specials: Night &#x26; Day', index = 224},
        	{label = 'Fubuki-jo Specials: The Verlierer', index = 225},
        	{label = 'Fubuki-jo Specials: Sprunk Extreme', index = 226},
        	{label = 'Fubuki-jo Specials: Vice City', index = 227},
        	{label = 'Fubuki-jo Specials: Synthwave Night', index = 228},
        	{label = 'Fubuki-jo Specials: Four Seasons', index = 229},
        	{label = 'Fubuki-jo Specials: M9 Throwback', index = 230},
        	{label = 'Fubuki-jo Specials: Bubblegum', index = 231},
        	{label = 'Fubuki-jo Specials: Full Rainbow', index = 232},
        	{label = 'Fubuki-jo Specials: Sunset', index = 233},
        	{label = 'Fubuki-jo Specials: The Seven', index = 234},
        	{label = 'Fubuki-jo Specials: Kamen Rider', index = 235},
        	{label = 'Fubuki-jo Specials: Chromatic', index = 236},
        	{label = 'Fubuki-jo Specials: It\'s Christmas!', index = 237},
        	{label = 'Fubuki-jo Specials: Temperature', index = 238},
        	{label = 'Fubuki-jo Specials: HSW Badge', index = 239},
        	{label = 'Fubuki-jo Specials: Anod. Lightning', index = 240},
        	{label = 'Fubuki-jo Specials: Emeralds', index = 241},
        	{label = 'Fubuki-jo Specials: Fubuki Castle', index = 242} 
	}
}
-- Type: Table
</code></pre>

</details>

**Usage:** Each color category is defined in `Config.ColorCategories`, and the corresponding colors are specified here:

* **`label`**: (String) The display name of the color.
* **`index`**: (Integer) The GTA index for the color.

{% hint style="success" %}
Customize `label` for each color as needed. Ensure that `index` corresponds correctly to the desired GTA color index.
{% endhint %}


# Engine Swaps

Guide & instructions on engine swaps. W\.I.P. W\.I.P. W\.I.P. W\.I.P.

{% hint style="success" %}
In this file **`t1ger_tuningsystem/shared/engine_swaps.lua`** you can access all of these configurable options.
{% endhint %}

## Config.EngineSwaps

```lua
Config.EngineSwaps = {

    DefaultIcon = 'gear', -- default icon for listed engines in menu

	Hoist = { -- Hoist Configuration:
		model = 'imp_prop_engine_hoist_02a', -- hoist prop
        removeItem = true, -- set to false and item will not be removed on use. If true, item will be removed on use and re-added, when collecting the hoist.
        keybind = 47, -- keybind to handle hoist (place on ground)
        playSound = true, -- sound effects when attaching/detaching an engine to/from the hoist.
        smoothness = 150, -- number of counts the engine will go/up down (the higher the more smooth)
        delay = 10, -- delay in hoist handle (how fast should engine go(up down))
		boneId = 28422, -- boneId on player

        textUi = { -- textUi when carrying hoist:
            string = '[G] - Detach Hoist', -- string in textUi
            icon = 'location-crosshairs', -- icon 
            position = 'right-center', -- position
            style = {borderRadius = 0, backgroundColor = '#48BB78', color = 'white'} -- css
        },

		anim = {dict = 'anim@heists@box_carry@', name = 'idle', blendIn = 4.0, blendOut = 1.0, duration = -1, flags = 49}, -- carry animation
        offset = {
            ['carry'] = {pos = vector3(0.0, -0.5, -1.3), rot = vector3(-195.0, -180.0, 180.0)}, -- offset for carry animation with player
            ['engine'] = {pos = vector3(-0.2, -0.-1.10, 1.2), rot = vector3(0.0, 0.0, 0.0)}, -- offset for hoist hook attach point for engine
        },

        target = { -- do not change index[''] strings , do not change target.name. Only change icon, label and distance. 
            ['carry'] = {name = 'tuningsystem:target:carryHoist', icon = 'fa-solid fa-up-down-left-right', label = 'Carry Hoist', distance =  2.5}, -- carry target
            ['extract'] = {name = 'tuningsystem:target:extractEngine', icon = 'fa-solid fa-arrow-up-long', label = 'Extract Engine', distance =  2.0}, -- extract target
            ['attach'] = {name = 'tuningsystem:target:attachEngine', icon = 'fa-solid fa-link', label = 'Attach Engine', distance =  2.0}, -- attach target
            ['detach'] = {name = 'tuningsystem:target:detachEngine', icon = 'fa-solid fa-link-slash', label = 'Detach Engine', distance =  2.0}, -- detach target
            ['remove'] = {name = 'tuningsystem:target:removeHoist', icon = 'fa-solid fa-hand', label = 'Collect Hoist', distance =  2.0}, -- remove target
        }
	},

    -- target created on extracted engine to dump/delete the old engine prop:
    ExtractTarget = {
        label = 'Dump Engine', -- target label
        icon = 'fa-solid fa-trash-can', --target icon
        distance = 2.0 -- target distance
    },

    -- target created on vehicle at engien bone pos:
    VehicleTarget = { -- do not change index[''] strings , do not change target.name. Only change icon, label and distance. 
        ['access'] = {name = 'tuningsystem:target:accessVehicleEngine', icon = 'fa-solid fa-screwdriver', label = 'Access Engine Bay', distance =  5.0},
        ['complete'] = {name = 'tuningsystem:target:completeSwap', icon = 'fa-solid fa-screwdriver', label = 'Complete Engine Swap', distance =  5.0}
    },

    -- animation to access engien bay/complete engine swap
    RepairAnimation = {dict = 'mini@repair', name = 'fixing_a_player', blendIn = 2.0, blendOut = 2.0, duration = 3000, flags = 1},

    -- settings for point when extracting engine / installing new engine on the vehicle: 
    VehiclePoint = {
        distance = 5, -- distance for nearby function
        marker = {
            type = 20, -- type for the marker
            scale = vector3(0.25, 0.25, 0.25), -- scale for the marker
            color = { -- do not change the index[''] string names!
                ['default'] = vector4(194, 80, 80, 200), -- rgba color for default marker at engine on the vehicle
                ['success'] = vector4(63, 195, 128, 200), -- rgba color for marker and engine object outline when distance <= precision (success)
            }
        },
        precision = 0.15, -- distance from hoist hook to detach marker. The smaller the more precise player has to be before placing the hoist.
    },

    -- settings for point when attaching new engine to the hoist:
    EnginePoint = {
        distance = 5, -- distance for nearby function
        marker = {
            type = 30, -- type for the markers
            scale = vector3(0.1, 1.0, 1.2), -- scale for the markers
            color = { -- do not change the index[''] string names!
                ['engine'] = vector4(194, 80, 80, 200), -- rgba color for engine marker
                ['hoist'] = vector4(20, 20, 20, 200), -- rgba color for hoist marker
                ['success'] = vector4(63, 195, 128, 200), -- rgba color for engine marker when distance <= precision (success)
            }
        },
        precision = 0.15, -- distance from hoist marker to engine marker. The smaller the more precise player has to be before placing the hoist.
    }
}
```

Read the end-text comments!

## Config.Engines

All engines that can be swapped...




---

[Next Page](/llms-full.txt/1)

