ThrowPhone
The ThrowPhone & ThrowBall Negotiation Script introduces a realistic law-enforcement tool for hostage and crisis negotiations in FiveM. Inspired by real-world tactical equipment, it allows police negotiators to establish secure communication without physically exposing themselves too long or at all.
The ThrowPhone system allows law enforcement to deploy specialized communication devices into a building or area occupied by suspects. Criminals can retrieve the device and communicate directly with negotiators, while police maintain distance, control, and oversight.
Showcase: https://youtu.be/HgORbMqlxSs
Features
Section titled “Features”- Local-Object Optimization: Uses non-networked (local) objects for the phone while keeping state synced across clients, reducing network overhead.
- Optimised: In game 0.00ms idle and 0.01-0.02ms client/server with deployed phones.
- Control Box Management: Issue, manage, and listen to deployed phones from a dedicated control box.
- Live Camera & GPS Tracking: View the throw phone camera and track the handset location when enabled.
- Automatic Cleanup: Phones, prompts, and voice channels clear themselves when the scene wraps up, keeping your server tidy.
- Permissions: Gate access by job/role (ESX, QBCore, QBox, Ox) or ACE permission.
Perfect For
Section titled “Perfect For”- Hostage negotiations where SWAT tosses in a phone and monitors from cover.
- Undercover stings that need a disposable, hard-to-trace comms line.
- Event control or heist scenarios that benefit from isolated, object-based voice channels.
Getting Started
Section titled “Getting Started”-
Download the latest version from Cfx.re Portal
Section titled “Download the latest version from Cfx.re Portal” -
Download Dependencies
Section titled “Download Dependencies”- ox_lib: Must be version
v3.30.0or higher. - Voice (one of)
- Target (one of)
- Inventory (one of)
- ox_inventory
- codem-inventory
- qb-inventory
- qs-inventory
- qs-inventory-pro
- origen_inventory
- tgiann-inventory
- standalone
- ox_lib: Must be version
-
Install
Section titled “Install”Move the dependencies and the folders
kf-throw-phone&kf-throw-phone-assetsinto your server’sresourcesdirectory. -
Add to
Section titled “Add to server.cfg”server.cfgserver.cfg ensure ox_libensure pma-voiceensure ox_targetensure ox_inventoryensure kf-throw-phoneensure kf-throw-phone-assetsOptional ACE gate for control-box access. This only applies when
Config.controlBoxAcePermissionis set to the same ACE string:server.cfg add_ace group.police kfthrowphone.use allow -
Choose your deployment mode
Section titled “Choose your deployment mode”- Inventory mode: Use one of the supported inventory resources and follow the
ox_inventoryexample below for item/weapon setup. - Standalone command mode: Set
Config.inventory = 'standalone'and configureConfig.controlBoxCommandto the client command you want players to use, for examplethrowphone. In this mode the control box is deployed from the command instead of an inventory item, and control-box retrieval uses the native weapon system for throw phones.
- Inventory mode: Use one of the supported inventory resources and follow the
-
The following item setup is for
Section titled “The following item setup is for ox_inventory only. Please refer to the documentation for other supported inventory resources.”ox_inventoryonly. Please refer to the documentation for other supported inventory resources. -
Add the control box to the inventory item config file.
Section titled “Add the control box to the inventory item config file.”Add to the ox_inventory items config file. Default location:
resources/[ox]/ox_inventory/data/items.luaitems.lua ['kf_throwphone_control'] = {label = 'Throw Phone Control',weight = 8000,stack = false,close = true,client = {export = 'kf-throw-phone.deployControl'}}, -
Add the throwables to the inventory weapon config file.
Section titled “Add the throwables to the inventory weapon config file.”Add to the ox_inventory weapons config file. Default location:
resources/[ox]/ox_inventory/data/weapons.luaweapons.lua ['WEAPON_KFTHROWPHONE'] = {label = 'Throw Phone Case',weight = 1000,throwable = true,},['WEAPON_KFTHROWPHONE_BALL'] = {label = 'Throw Phone Ball',weight = 300,throwable = true,},['WEAPON_KFTHROWPHONE_HANDSET'] = {label = 'Throw Phone',weight = 190,throwable = true,}, -
Add the images to the inventory images folder
Section titled “Add the images to the inventory images folder”Add all the images files from
kf-throw-phone/inventory-images/ingameORkf-throw-phone/inventory-images/stylizedinto the ox_inventory images folder. Default location:resources/[ox]/ox_inventory/web/images -
Add the control box to your item dispesner method
Section titled “Add the control box to your item dispesner method”Add only
kf_throwphone_controlto your item dispenser method (armoury, loot, etc). The other items are retrieved from the control box.
Configuration
Section titled “Configuration”The main configuration is located in config.lua.
Config = { debug = false, notifications = true, textUiEnabled = true, -- The notification resource to use, one of: 'ox_lib', 'esx_notify', 'qb-core', 'qbx_core', 'okokNotify', 'wasabi_notify', notify = 'ox_lib', -- The inventory resource to use -- one of: 'ox_inventory', 'codem-inventory', 'qb-inventory', 'qs-inventory', 'qs-inventory-pro', 'origen_inventory', 'tgiann-inventory', 'standalone' inventory = 'ox_inventory', -- The target resource to use, one of: 'ox_target', 'sleepless_interact', or 'qb-target' target = 'ox_target',
-- Control box -- Allowed groups to use the control box - leave empty to allow all groups -- List format (no grade requirement): -- { 'police', 'sheriff', 'fbi' } -- Grade format (minimum grade): -- { police = 2, sheriff = 1 } -- ESX also supports grade_name aliases: -- { police = 'boss' } controlBoxAllowedJobs = { -- Example: -- police = 2, }, -- Optional ACE permission for control box access. Set to a string like 'kfthrowphone.use' to require it, -- or leave false to disable ACE checks. When both ACE and jobs are configured, either permission path grants access. controlBoxAcePermission = false, controlBoxMaxDeployed = 1, controlBoxMaxPhones = 5, controlBoxAllowBallRetrieve = true, -- Client command name used to start control box placement in standalone mode (eg: 'throwphone'). Set to false to disable. controlBoxCommand = false, -- Control box return mode: -- 'inventory' = only return by removing a phone item from player inventory (default) -- 'inventory_or_deployed' = if no inventory phone is found, return one deployed phone linked to this control box instead controlBoxReturnMode = 'inventory', -- Phone return mode: -- 'equipped_only' = return-to-case requires actively holding phone weapon (default) -- 'inventory_or_equipped' = return-to-case allows matching phone item in inventory even if not actively held -- 'owner_fallback' = if matching phone item is missing, allow return by phone ownership state phoneReturnMode = 'equipped_only', -- Case call join behavior: -- 'phone' = case phones join by retrieving a phone from the case -- 'interact' = case phones join and leave through case/control box interactions instead of handset retrieval caseJoinCall = { mode = 'phone', -- 'phone' | 'interact' interact = { -- when enabled, players in an interact-mode case call automatically leave when they move away autoLeave = { enabled = true, proximity = 6.0, }, }, }, controlBoxJoinCall = { mode = 'phone', -- 'phone' | 'interact' interact = { autoLeave = { enabled = true, proximity = 6.0, }, }, }, -- When true, only the player who deployed the control box can interact with it. controlBoxRequireOwnership = false, ballJoinRadius = 3.0, projectileVisibilityDistance = 150.0, ringtone = { -- When true, enables audio spatial ringtone support for deployed throw phone cases enabled = false, -- Relative path inside this resource for the ringtone asset, eg: 'web/build/ringtone.mp3'. file = 'web/build/ringtone.mp3', loop = true, maxDurationMs = 30000, updateIntervalMs = 200, maxDistance = 15.0, refDistance = 1.25, rolloffFactor = 1.6, volume = 0.6, },
-- Enable so that players must hold attack for at least phoneThrowHoldDurationMs before release will throw the phone; quick taps show an info hint instead of throwing. phoneThrowHoldEnabled = false, phoneThrowHoldDurationMs = 450,
-- Throw phone camera cameraEnabled = true, cameraEnabledByType = { case = false, phone = true, ball = true, }, cameraNightVisionToggleEnabled = true, cameraThermalVisionToggleEnabled = true, cameraFOV = 100.0, cameraRequireApproval = true, -- require nearby players to approve camera access -- How nearby players approve camera requests: 'dialog' shows an approve/deny popup; 'target' prompts them to use the case/phone/ball target option; 'both' enables both methods. cameraApprovalMethod = 'target', -- 'dialog', 'target', or 'both' cameraApprovalTimeout = 300000, -- milliseconds camera approval timeout (0 to disable) cameraViewTimeout = 300000, -- milliseconds active camera view timeout (0 to disable) cameraApprovalRange = 20.0, cameraMouseRotationEnabled = true, cameraKeyboardPitchYawEnabled = true,
-- GPS tracker gpsTrackerEnabled = true, gpsTrackerUpdateInterval = 5000, -- milliseconds between GPS coordinate refreshes gpsTrackerBlipSprite = 459, -- blip sprite gpsTrackerBlipColour = 38, -- blip colour gpsTrackerBlipScale = 0.8, -- blip scale gpsTrackerBlipShortRange = true, -- blip short range on minimap}