> For the complete documentation index, see [llms.txt](https://codeforge.gitbook.io/codeforge/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://codeforge.gitbook.io/codeforge/phone/smartphone.md).

# SMARTPHONE

### Overview

Forge Phone replaces legacy phone scripts with a cohesive mobile experience:

* **FORGE OS** — lock screen, home screen, dock, control center, notifications, app store, themes and wallpapers.
* **Real-time communication** — SMS-style messages, group chats, voice calls through **pma-voice**, and optional **WebRTC video calls**.
* **Life simulation** — camera with cloud upload, gallery, email, classified ads, dating, social feeds, and streaming.
* **Economy hooks** — bank transfers, invoices, and a **ByteMe** mobile data system that gates online actions.
* **Underworld & law enforcement** — a retro **burner phone** excluded from wiretap, and a **police tablet** for surveillance dossiers.

Open the phone with the configured key (default **M**), the `/phone` command, or by using the phone item from inventory.

***

### Features

| Feature          | Description                                                                      |
| ---------------- | -------------------------------------------------------------------------------- |
| Voice calls      | Outgoing/incoming calls with history, contact integration, and pma-voice routing |
| Video calls      | WebRTC peer video with STUN/TURN support and in-game cell camera                 |
| Messages         | Direct chats with read state, media, and contact requests                        |
| Contacts         | Full address book synced to the server                                           |
| Camera & Gallery | In-game photos uploaded to FiveManage, stored per character                      |
| App Store        | Install/uninstall downloadable apps defined in `Config.Apps`                     |
| ByteMe (InetMax) | Mobile data balance consumed by calls, posts, transfers, and messages            |
| Bank (Wallet)    | Balance, transfers, and bill payments with framework or ds\_banking              |
| Mail             | Inbox for receipts, ads, and server announcements                                |
| Services         | Ticket threads to police, EMS, taxi, businesses, and more                        |
| Social apps      | Bleeter, Insta, WhatsUP groups, Spark dating, LifeInvader ads                    |
| Play TV          | Video streaming surface inside the phone                                         |
| Burner phone     | Separate disposable device with its own number pool                              |
| Police wiretap   | Tablet UI for GPS, message/call history, live intercept, and dossiers            |
| Signal zones     | Optional dead zones where sending/calling is blocked                             |
| i18n             | English and Spanish locales in the phone UI                                      |
| Themes           | Accent color, wallpaper, and OS personalization in Settings                      |

***

### Apps

#### Pre-installed (System)

These apps ship on every phone and **cannot be uninstalled**:

| ID         | Display name | Purpose                                  |
| ---------- | ------------ | ---------------------------------------- |
| `phone`    | Phone        | Dialer, recent calls, contact requests   |
| `messages` | Messages     | Direct messaging                         |
| `contacts` | Contacts     | Address book                             |
| `camera`   | Camera       | Take photos in-world                     |
| `settings` | Settings     | Theme, wallpaper, notifications, privacy |
| `appstore` | App Store    | Browse and manage downloadable apps      |
| `gallery`  | Photos       | Photo library                            |

#### Downloadable (App Store)

Users install these from the App Store. Only IDs listed in `Config.Apps.Downloadable` are available:

| ID          | Display name | Category      | Description                         |
| ----------- | ------------ | ------------- | ----------------------------------- |
| `wallet`    | Bank         | Finance       | Balance, transfers, bills           |
| `email`     | Mail         | Productivity  | Character inbox                     |
| `services`  | Services     | Utilities     | Contact jobs and emergency services |
| `loops`     | Bleeter      | Social        | Twitter-style posts and comments    |
| `ads`       | Ads          | Utilities     | Classified listings with photos     |
| `inetmax`   | ByteMe       | Utilities     | Top up and monitor mobile data      |
| `playtv`    | Play TV      | Entertainment | Stream videos on the go             |
| `lovy`      | Spark        | Social        | Dating / swipe profiles             |
| `snapmatic` | Insta        | Social        | Photo feed, likes, comments         |
| `whatsup`   | WhatsUP      | Social        | Group chat rooms                    |

To change which apps are system vs downloadable, edit `Config.Apps` in `config/config.lua`.

***

### Requirements

Start dependencies **before** `forge-phone`:

```cfg
ensure ox_lib
ensure oxmysql
ensure screenshot-basic
ensure pma-voice
ensure forge-phone
```

| Dependency                                                        | Role                                    |
| ----------------------------------------------------------------- | --------------------------------------- |
| [ox\_lib](https://github.com/overextended/ox_lib)                 | Callbacks, UI helpers, shared utilities |
| [oxmysql](https://github.com/overextended/oxmysql)                | Database queries and migrations         |
| [screenshot-basic](https://github.com/citizenfx/screenshot-basic) | Camera capture pipeline                 |
| [pma-voice](https://github.com/AvarianKnight/pma-voice)           | Voice calls and wiretap audio bridge    |

**Optional integrations**

* **FiveManage** — photo upload API (see Camera & Photo Upload)
* **ds\_banking** — external banking when `Config.Banking.Resource = 'auto'`
* **MugShotBase64** — live mugshots on the wiretap tablet
* **interact-sound** — ring tones (customize in `config/open_functions.lua`)

If your server uses another voice resource, override `ForgePhone.JoinVoiceCall`, `ForgePhone.LeaveVoiceCall`, and the wiretap voice helpers in `config/open_functions.lua`.

***

### Installation

#### 1. Add the resource

Place the folder in your resources directory as `forge-phone` and ensure it in `server.cfg` after the dependencies.

#### 2. Set your framework

In `config/config.lua`:

```lua
Config.Core = "QBX" -- "QB", "QBX" or "ESX"
```

#### 3. Configure item names

```lua
Config.PhoneItem = 'phone'
Config.Burner.Item = 'burner_phone'
```

#### 4. Register inventory items

Add the phone and burner items to your inventory system (see Inventory Items).

#### 5. Database

On first start, Forge Phone creates and migrates its database tables automatically.

If your host blocks automatic DDL, import `forge-phone.sql` manually before starting the resource.

#### 6. FiveManage API key

Add your media API key to `server.cfg` **before** the resource starts:

```cfg
set FIVEMANAGE_MEDIA_API_KEY "your_fivemanage_media_api_key"
```

Never expose the API key outside `server.cfg` (no public configs, screenshots, or shared paste links).

#### 7. Optional bridges

Adjust hooks in:

* `config/open_functions.lua` — sounds, voice, mugshots
* `config/bridge_client.lua` — client framework bridge
* `config/bridge_server.lua` — server framework bridge, money, jobs, items

***

### Inventory Items

The normal phone opens with `forge-phone:client:open`.\
The burner opens with `forge-phone:client:openBurner`.

Use **non-consumable** items. The script verifies the player still has the item before opening and while burner call state is active.

#### ox\_inventory

Add to `ox_inventory/data/items.lua`:

```lua
['phone'] = {
    label = 'Phone',
    weight = 300,
    stack = false,
    close = true,
    consume = 0,
    client = {
        event = 'forge-phone:client:open',
    },
    description = 'Forge smartphone',
},

['burner_phone'] = {
    label = 'Burner Phone',
    weight = 250,
    stack = false,
    close = true,
    consume = 0,
    client = {
        event = 'forge-phone:client:openBurner',
    },
    description = 'Disposable phone',
},
```

#### QBCore / qb-inventory

Add to `qb-core/shared/items.lua`:

```lua
['phone'] = {
    name = 'phone',
    label = 'Phone',
    weight = 300,
    type = 'item',
    image = 'phone.png',
    unique = true,
    useable = true,
    shouldClose = true,
    combinable = nil,
    description = 'Forge smartphone',
},

['burner_phone'] = {
    name = 'burner_phone',
    label = 'Burner Phone',
    weight = 250,
    type = 'item',
    image = 'burner_phone.png',
    unique = true,
    useable = true,
    shouldClose = true,
    combinable = nil,
    description = 'Disposable phone',
},
```

Register usable callbacks server-side (after `qb-core` loads):

```lua
local QBCore = exports['qb-core']:GetCoreObject()

QBCore.Functions.CreateUseableItem('phone', function(source, item)
    local Player = QBCore.Functions.GetPlayer(source)
    if not Player or not Player.Functions.GetItemByName(item.name) then return end
    TriggerClientEvent('forge-phone:client:open', source)
end)

QBCore.Functions.CreateUseableItem('burner_phone', function(source, item)
    local Player = QBCore.Functions.GetPlayer(source)
    if not Player or not Player.Functions.GetItemByName(item.name) then return end
    TriggerClientEvent('forge-phone:client:openBurner', source)
end)
```

#### QBX / qbx\_core

If you use QBX with `ox_inventory`, use the ox\_inventory definitions above.

Otherwise:

```lua
exports.qbx_core:CreateUseableItem('phone', function(source)
    TriggerClientEvent('forge-phone:client:open', source)
end)

exports.qbx_core:CreateUseableItem('burner_phone', function(source)
    TriggerClientEvent('forge-phone:client:openBurner', source)
end)
```

#### ESX

SQL for the legacy `items` table:

```sql
INSERT INTO `items` (`name`, `label`, `weight`, `rare`, `can_remove`) VALUES
    ('phone', 'Phone', 300, 0, 1),
    ('burner_phone', 'Burner Phone', 250, 0, 1)
ON DUPLICATE KEY UPDATE
    `label` = VALUES(`label`),
    `weight` = VALUES(`weight`);
```

If your table only has `name`, `label`, and `weight`, remove `rare` and `can_remove`.

Server callbacks:

```lua
ESX.RegisterUsableItem('phone', function(source)
    TriggerClientEvent('forge-phone:client:open', source)
end)

ESX.RegisterUsableItem('burner_phone', function(source)
    TriggerClientEvent('forge-phone:client:openBurner', source)
end)
```

#### qs-inventory

Add to `qs-inventory/shared/items.lua`:

```lua
['phone'] = {
    ['name'] = 'phone',
    ['label'] = 'Phone',
    ['weight'] = 300,
    ['type'] = 'item',
    ['image'] = 'phone.png',
    ['unique'] = true,
    ['useable'] = true,
    ['shouldClose'] = true,
    ['combinable'] = nil,
    ['description'] = 'Forge smartphone',
},

['burner_phone'] = {
    ['name'] = 'burner_phone',
    ['label'] = 'Burner Phone',
    ['weight'] = 250,
    ['type'] = 'item',
    ['image'] = 'burner_phone.png',
    ['unique'] = true,
    ['useable'] = true,
    ['shouldClose'] = true,
    ['combinable'] = nil,
    ['description'] = 'Disposable phone',
},
```

QS setups based on QBCore still need the `CreateUseableItem` callbacks unless your QS version binds its own client events.

***

### Configuration

All customization is done through these files:

```
config/config.lua          — core settings, apps, wiretap, video, signal, services
config/vehicles.lua        — vehicle-related helpers
config/open_functions.lua  — voice, sounds, mugshots (client hooks)
config/bridge_client.lua   — framework client bridge
config/bridge_server.lua   — framework server bridge
config/logs_server.lua     — server logging hooks
```

#### Essential settings

```lua
Config.Core = "QBX"
Config.OpenPhone = 'M'
Config.PhoneItem = 'phone'
Config.AllowWalkingWhilePhoneOpen = true

Config.Burner.Enabled = true
Config.Burner.Item = 'burner_phone'
Config.Burner.Command = 'burnerphone'
```

#### App catalog

```lua
Config.Apps = {
    System = {
        'phone', 'messages', 'contacts', 'camera',
        'settings', 'appstore', 'gallery',
    },
    Downloadable = {
        'email', 'wallet', 'services', 'loops', 'ads',
        'inetmax', 'playtv', 'lovy', 'snapmatic', 'whatsup',
    },
}
```

Only apps listed in `Config.Apps.System` or `Config.Apps.Downloadable` can be installed or removed.

#### Call settings

```lua
Config.RepeatTimeout = 3000   -- ms between ring tones
Config.CallRepeats = 5        -- rings before missed call
```

#### Notification texts

Customize player-facing strings in `Config.Texts` and per-feature `Texts` tables (burner, wiretap, etc.).

***

### Burner Phone

The burner is a **separate disposable device** with a retro UI and its own number table. It is intentionally **excluded from police wiretap and tracking**.

| Setting                            | Default        | Notes                         |
| ---------------------------------- | -------------- | ----------------------------- |
| `Config.Burner.Enabled`            | `true`         | Master switch                 |
| `Config.Burner.Item`               | `burner_phone` | Inventory item                |
| `Config.Burner.Command`            | `burnerphone`  | Opens without item if enabled |
| `Config.Burner.AllowIncomingCalls` | `true`         | Incoming burner calls         |
| `Config.Burner.NumberMin/Max`      | `1000`–`9999`  | Short number pool             |

Features toggled under `Config.Burner.Features`: outgoing calls, contacts, settings.

**Behaviour highlights**

* Cannot open the main phone and burner at the same time during active calls.
* Uses prop model `npds_oldphone_base` (see Props).
* Numbers are stored separately from the main phone profile.

***

### Police Wiretap Tablet

Judicial surveillance tool for configured police jobs. Open with `/poltablet` (configurable).

```lua
Config.Wiretap = {
    Enabled = true,
    Command = 'poltablet',
    Jobs = {
        ['police'] = 0,
        ['sheriff'] = 0,
    },
    MaxSessionsPerOfficer = 1,
    LocationUpdateIntervalMs = 2000,
    JoinVoiceOnActiveCall = true,
    Features = {
        HistoricalMessages = true,
        HistoricalCalls = true,
        HistoricalSocialActivity = true,
        LiveMessages = true,
        LiveCallAudio = true,
        LocationTracking = true,
        PortraitCapture = true,
    },
}
```

#### What officers can do

* **Target dossiers** — save suspects with labels (suspect, witness, victim, etc.), notes, and display names.
* **GPS tracking** — live map with periodic position updates from the target client.
* **Message history** — SMS and service threads linked to the target number.
* **Call history** — past call metadata.
* **Live intercept** — real-time messages while a wiretap session is active.
* **Live call audio** — when enabled, the officer joins the target's pma-voice call in listen-only mode.
* **Portrait** — mugshot from DB avatar, optional MugShotBase64 resource, or native capture.

#### Limits

* Burner phones are **never** wiretappable.
* `MaxSessionsPerOfficer` prevents abuse.
* History rows are capped by `Config.Wiretap.HistoryLimits`.

Preset labels: `suspect`, `witness`, `victim`, `person_of_interest`, `accomplice`, `informant`, `other`.

***

### Video Calls

WebRTC video calls run between two players in an active phone call.

```lua
Config.VideoCall = {
    Enabled = true,
    STUNServers = {
        "stun:stun1.l.google.com:19302",
        "stun:stun2.l.google.com:19302",
    },
    TURNServers = {}, -- add your TURN credentials for strict NAT
    InetMaxUsage = math.random(300000, 800000),
}
```

**Requirements**

* `Config.VideoCall.Enabled = true`
* Both players need sufficient **ByteMe** data when InetMax is enabled.
* pma-voice handles call audio; video uses WebRTC with the STUN/TURN settings below.

For production servers behind strict firewalls, configure **TURN** servers in `TURNServers`. Google STUN alone is enough for many home networks but not all datacenter setups.

***

### ByteMe — Mobile Data

**ByteMe** (`inetmax` app) is Forge Phone's mobile data economy. When `Config.App.InetMax.IsUseInetMax = true`, online actions consume KB from the character balance.

#### Top-up

```lua
Config.App.InetMax.TopupRate = {
    InKB = 1000000,  -- 1 GB per unit
    Price = 100,     -- price per unit
}
Config.App.InetMax.SocietySeller = "government"
```

#### Usage examples (randomized ranges in KB)

| Action                 | Config key                           |
| ---------------------- | ------------------------------------ |
| Send message           | `MessageSend`                        |
| Bleeter post / comment | `LoopsPostTweet`, `LoopsPostComment` |
| Insta post / comment   | `SnapmaticPost`, `SnapmaticComment`  |
| Ads post               | `AdsPost`                            |
| Voice call             | `PhoneCall`                          |
| Video call             | `Config.VideoCall.InetMaxUsage`      |
| Bank transfer          | `BankTransfer`                       |
| Service message        | `ServicesMessage`                    |

If the balance is too low, players see `Config.MsgNotEnoughInternetData` and the action is blocked.

***

### Camera & Photo Upload

Photos are captured through `screenshot-basic` and uploaded to **FiveManage**:

```lua
Config.PhotoUpload = {
    provider = 'fivemanage',
    endpoint = 'https://api.fivemanage.com/api/v3/file/base64',
    timeout = 10000,
    encoding = 'webp',
    quality = 0.85,
    path = 'forge-phone/photos',
}
```

**server.cfg**

```cfg
set FIVEMANAGE_MEDIA_API_KEY "your_fivemanage_media_api_key"
```

Saved URLs are stored in the gallery and can be used in Bleeter, Insta, Ads, Spark, and profile avatars.

***

### Banking & Wallet

```lua
Config.Banking = {
    Resource = 'auto', -- auto, framework, ds_banking
    AutoDetect = { 'ds_banking' },
}
```

| Mode         | Behaviour                                                    |
| ------------ | ------------------------------------------------------------ |
| `auto`       | Tries listed external banks, falls back to framework account |
| `framework`  | Uses QB/QBX/ESX bank balance only                            |
| `ds_banking` | Forces ds\_banking integration                               |

The Wallet app supports transfers, balance checks, and invoice payments. Top-ups for ByteMe credit the configured society account.

**Admin diagnostic**

`/fpbankdiag` prints banking diagnostics but requires ACE permission `forgephone.bankdiag` (or generic `command` ace).

***

### Signal Zones

Optional coverage simulation. Disabled by default.

```lua
Config.Signal = {
    IsUse = false,
    DefaultSignalZones = "FULL_SIGNAL",
    Zones = {
        ["FULL_SIGNAL"] = {
            CenterCoords = vec3(49.58, -1560.84, 29.38),
            Radius = 3,
            ChanceSignal = 1.0,
        },
        -- add more zones with ChanceSignal 0.0 – 1.0
    },
}
```

When `IsUse = true`, players inside low-signal zones cannot send messages or place calls. Message: `Config.MsgSignalZone` (`"No Signal"`).

***

### Services App

Pre-configured service desks in `Config.Services`. Each entry maps a **job name** to a ticket channel:

| Key          | Job        | Type      |
| ------------ | ---------- | --------- |
| `goverment`  | goverment  | General   |
| `police`     | police     | General   |
| `ambulance`  | ambulance  | Health    |
| `realestate` | realestate | Property  |
| `taxi`       | taxi       | Transport |
| `burgershot` | burgershot | Food      |
| `kfc`        | kfc        | Food      |

Add or rename entries to match your server's jobs. `minGrade` controls which job grade can respond to tickets.

***

### Props & Stream Files

Phone and burner props are streamed from `stream/`:

```
stream/npds_phone_base.ydr      — main smartphone prop
stream/npds_oldphone_base.ydr     — burner phone prop
stream/npds_phone_prop.ytyp     — archetype metadata
```

Manifest entry:

```lua
data_file "DLC_ITYP_REQUEST" "stream/npds_phone_prop.ytyp"
```

| Device       | Model                |
| ------------ | -------------------- |
| Main phone   | `npds_phone_base`    |
| Burner phone | `npds_oldphone_base` |

If a prop appears **grey or untextured**, the drawable loaded but the texture dictionary did not. Add matching `.ytd` files from the NPDS prop package to `stream/` if included, restart the resource, and clear client cache if needed.

These props are created by **Nukepug Designs** — see Special Thanks.

***

### Debug & Troubleshooting

#### Enable debug logs

```lua
Config.Debug = false

Config.DebugScopes = {
    all = true,
    bridge = true,
    camera = true,
    database = true,
    phone = true,
    props = true,
    signal = true,
    web = true,
    wiretap = true,
}
```

Set `Config.Debug = true`. Use `all = false` and enable individual scopes to reduce console noise.

#### Common issues

| Symptom                   | Check                                                                    |
| ------------------------- | ------------------------------------------------------------------------ |
| Phone does not open       | Item registered, `Config.PhoneItem` matches, player has item             |
| No photos / gallery empty | `FIVEMANAGE_MEDIA_API_KEY` in server.cfg, screenshot-basic running       |
| No voice in calls         | pma-voice started, `ForgePhone.JoinVoiceCall` not overridden incorrectly |
| Video call black screen   | TURN servers, firewall, `Config.VideoCall.Enabled`                       |
| Wiretap no GPS            | Target online, tap session active, `LocationTracking` enabled            |
| Database errors           | oxmysql connection, run `forge-phone.sql` manually if DDL blocked        |
| Grey phone prop           | Missing `.ytd` textures in `stream/`                                     |

#### Commands

| Command        | Access                    | Purpose                          |
| -------------- | ------------------------- | -------------------------------- |
| `/phone`       | All                       | Open phone (if item checks pass) |
| `/burnerphone` | All                       | Open burner (if enabled)         |
| `/poltablet`   | Wiretap jobs              | Open police surveillance tablet  |
| `/fpbankdiag`  | ACE `forgephone.bankdiag` | Banking diagnostics              |

***

### Special Thanks

Forge Phone uses community-made props for the in-hand phone models. Huge thanks to **Nukepug Designs (NukePugs)** for creating and sharing high-quality props and scripts for the FiveM community.

|             | Link                                                |
| ----------- | --------------------------------------------------- |
| **Discord** | [Nukepug Design's](https://discord.gg/DXe7vZwN2A)   |
| **GitHub**  | [NukepugDesigns](https://github.com/NukepugDesigns) |

Nukepug Designs publishes prop packs, MLOs, minigames, and more for roleplay servers. If you use Forge Phone props in trailers or showcases, consider crediting **Nukepug Designs** and supporting their work.

**Props used in this resource**

* `npds_phone_base` — main smartphone
* `npds_oldphone_base` — burner phone
* `npds_phone_prop.ytyp` — prop metadata

***

### License & Support

Forge Phone is distributed by **CodeForge**. Refer to your Tebex or purchase page for license terms, updates, and official support channels.

For configuration questions, start with this document and the files under `config/`. Enable scoped debug logging before opening support tickets so staff can diagnose issues quickly.
