Skip to content

Explosive Devices

Explosive Devices adds a deployable bomb case and an operator-and-tablet defuse minigame to FiveM. Players place the case, attach one of four payloads, and arm it.

Defusing it means working the physical device against a private rulebook tablet. One player can do both jobs, or an operator can work with one or more nearby tablet viewers. The puzzle is generated fresh for every bomb.

If the timer runs out, the payload detonates and leaves a hazard zone behind: fire, a biohazard cloud, a radiation zone, or an EMP blackout.

This page covers installation and configuration. For gameplay, see the Player Guide for planting a bomb, the Defuse Guide for the response and minigame, and Biohazard & Infection for the effects left by a biohazard payload.

  • Placeable bomb case: Place it precisely with a live preview, rotation, height, and ground snap.
  • Four payload types: Explosive, biohazard, nuclear, and EMP, each with its own defuse difficulty and aftermath.
  • Solo or co-op defuse minigame: One operator can work the device and rulebook alone, or another authorised tablet holder can relay the rulebook in co-op mode.
  • Generated per bomb: Wires, protocol, serial, symbol sequence, module meter, and code are generated fresh for every case.
  • Transmitter and remote detonation: Optional transmitter link with a signal grace period, plus remote and countdown detonation.
  • Responder scanner and scene markers: A group-restricted scanner that sweeps for bomb signals and hazard zones, with synced scene blips.
  • Hazard zones that outlast the bomb: Radiation, biohazard, fire, explosive, and EMP presets with damage, status effects, NPC panic, visuals, audio, and blackouts.
  • Progressive biohazard infection: The pathogen agent can apply one of the configured staged infections with symptoms, transmission, linked outbreaks, temporary stabilisation, and framework-aware persistence.
  • Protective clothing support: Clothing profiles or your own hooks decide who can enter a radiation or biohazard zone safely.
  • Optional acquisition loop: Buy bomb intel from a ped, follow a randomised stash lead, and claim the case before it expires.
  • Framework and inventory adapters: Ox, QBCore, QBox, and ESX, plus six inventory adapters.
  • ox_lib v3.30.0 or newer.
  • ox_target v1.17.0 or newer. This is the only supported target resource.
  • kf-defuse-assets, the streamed asset resource with the case, payload, transmitter, and scanner models.
  • One supported inventory adapter set in Config.inventory:
    • ox_inventory (2.43.0 or newer)
    • codem-inventory
    • qb-inventory
    • qs-inventory
    • origen_inventory
    • tgiann-inventory
  • Optionally one supported framework for group checks, cash, and status effects:
    • es_extended (1.0.0 or newer)
    • qb-core (1.0.0 or newer)
    • qbx_core (1.0.0 or newer)
    • ox_core (0.21.3 or newer)
  1. Download the latest granted asset from the Cfx.re Portal.

  2. Install and start ox_lib, ox_target, and your inventory resource.

  3. Place both folders in your server resources directory:

    • kf-defuse
    • kf-defuse-assets
  4. Start dependencies before Explosive Devices, and start the asset resource before the script. The custom weapons, case models, and payload models have to be registered first, otherwise you’ll get an invisible case and a blank device screen.

    server.cfg
    ensure ox_lib
    ensure ox_target
    # Start your inventory.
    ensure ox_inventory
    ensure kf-defuse-assets
    ensure kf-defuse
  5. Open config.lua and set the inventory, target, and notification adapters for your server.

    config.lua
    Config.inventory = 'ox_inventory'
    Config.target = 'ox_target'
    Config.notifications = true
    Config.notify = 'ox_lib'

    You can use Config.inventory = 'auto' when exactly one supported inventory resource is started. If you run more than one, set it explicitly.

  6. Add the bomb case, the transmitter, and the responder scanner to your weapons config. Do not mark the bomb case as throwable; players deploy it through Place Case.

    Default location:

    resources/[ox]/ox_inventory/data/weapons.lua
    weapons.lua
    ['WEAPON_KFDEFUSE'] = {
    label = 'Bomb Case',
    weight = 15000,
    },
    ['WEAPON_KFDEFUSETRANSMITTER'] = {
    label = 'Transmitter',
    weight = 1000,
    throwable = true,
    },
    ['WEAPON_KFDEFUSESCANNER'] = {
    label = 'Bomb Scanner',
    weight = 2000,
    },
  7. Add the payload, tablet, and antidote items

    Section titled “Add the payload, tablet, and antidote items”

    Add the four payloads, defuse tablet, and infection antidote to your items config.

    Default location:

    resources/[ox]/ox_inventory/data/items.lua
    items.lua
    ['kf_defuse_payload_explosive'] = {
    label = 'Explosive Payload',
    weight = 8000,
    stack = false,
    close = true,
    },
    ['kf_defuse_payload_biohazard'] = {
    label = 'Biohazard Payload',
    weight = 8000,
    stack = false,
    close = true,
    },
    ['kf_defuse_payload_nuclear'] = {
    label = 'Nuclear Payload',
    weight = 8000,
    stack = false,
    close = true,
    },
    ['kf_defuse_payload_emp'] = {
    label = 'EMP Payload',
    weight = 8000,
    stack = false,
    close = true,
    },
    ['kf_defuse_tablet'] = {
    label = 'Defuse Tablet',
    weight = 1000,
    stack = false,
    close = true,
    client = {
    export = 'kf-defuse.useDefuseTablet',
    },
    },
    ['kf_defuse_antidote'] = {
    label = 'Infection Antidote',
    weight = 250,
    stack = true,
    close = true,
    consume = 0,
    client = {
    export = 'kf-defuse.useAntidote',
    },
    },
  8. Add the images to the inventory images folder

    Section titled “Add the images to the inventory images folder”

    Add all the image files from kf-defuse/inventory-images into the ox_inventory images folder.

    Default location:

    resources/[ox]/ox_inventory/web/images

    The files are named after the items they belong to, so you only need to rename them if you changed an item name in config.lua or config_payloads.lua.

  9. Add the case, payloads, transmitter, scanner, and tablet to your armoury, shop, loot table, DutyKit, or other item dispenser. Scanners usually belong in a police armoury rather than a general shop.

    You can skip the bomb case here if you want players to get it only through the acquisition loop.

PurposeItem nameNotes
Bomb caseWEAPON_KFDEFUSEHeld weapon used to place a case.
TransmitterWEAPON_KFDEFUSETRANSMITTERCustom held weapon used to link a case and hold its signal.
Responder scannerWEAPON_KFDEFUSESCANNERHeld to sweep for bomb signals and hazard zones.
Defuse tabletkf_defuse_tabletPrivate rulebook for the operator and tablet viewers.
Infection antidotekf_defuse_antidoteUsable item that cures one persistent infection.
Explosive payloadkf_defuse_payload_explosive
Biohazard payloadkf_defuse_payload_biohazard
Nuclear payloadkf_defuse_payload_nuclear
EMP payloadkf_defuse_payload_emp

Item names live in config.lua (case, transmitter, scanner, tablet), config_payloads.lua (payloads), and config_infections.lua (antidote). Rename the values, not the payload keys.

Explosive Devices ships with an optional in-world way to obtain a bomb case, so you don’t have to sell one in a shop. Item dispensers work just as well.

A ped sells bomb intel. When a player buys it, the server picks an unused stash from that source’s pool, creates a personal lead, sets a waypoint and route blip, and spawns a bag at the stash. Only the buyer can claim it, and only before the lead expires.

The values in this example are illustrative; use the source values configured for your server.

config.lua
sandy_intel = {
label = 'Bomb Intel',
price = 25000,
antidotePrice = 25000,
payloadType = 'explosive',
offerLifetimeMs = 900000,
coords = vector3(1737.02, 3709.64, 34.14),
stashPool = {
{ id = 'grapeseed_barn', coords = vector3(2445.84, 4967.55, 46.81) },
{ id = 'harmony_rear_lot', coords = vector3(573.85, 2788.57, 42.19) },
{ id = 'redwood_container', coords = vector3(1335.73, 4348.57, 44.34) },
},
},

The ped exposes separate bomb-intel and antidote-intel options. A player can hold only one lead, so choosing an antidote stash prevents them from taking a bomb-equipment lead until the first lead is claimed or cleared. Bomb stashes grant the case and source payload plus the configured transmitter and tablet. Antidote stashes grant one antidote only.

Players can only hold one lead at a time, and the same stash can’t be handed to two active leads from one source. Leads clear on claim, expiry, disconnect, and resource stop.

To turn the loop off, empty Config.acquisition.sources.

Configuration is split across five focused files. Use the file that owns the system you want to change.

FileContents
config.luaFramework adapters, notifications, responder access and tools, protective clothing, acquisition sources, and the bomb case’s placement, arming, transmitter, detonation, and world-behaviour settings.
config_infections.luaInfection persistence and progression, exposure and transmission, outbreak rules, medical stabilisation, non-persistent gas agents, and strain symptoms.
config_payloads.luaPayload identity and inventory presentation, streamed models, per-payload defuse requirements, detonation behaviour, and the effects assigned to each payload.
config_effects.luaReusable radiation, biohazard, fire, explosive, and EMP hazard presets, including their area behaviour, damage and status effects, NPC response, visuals, audio, scanner markers, and blackouts.
config_defuse.luaDefuse camera and interaction behaviour, solo/co-op rules, countdown and failure handling, the optional Summary tab, optional puzzle rules, and the generated lookup data.

Difficulty comes from how big the lookup pools are and how often extra rules get rolled. It all lives in config_defuse.lua.

  • wireColors, protocols, moduleIds, and symbolSequences are the pools the puzzle is built from. Rename entries freely. If you add or remove any, update protocolRules and moduleRules to match, since each rule refers to a pool entry by name.
  • Per-payload wire counts live in config_payloads.lua. wireCountMax can’t be higher than the number of configured wireColors.
  • protocolDecoyCount, serialRowCount, and symbolFolderEntryCount set how much decoy data the tablet user has to search through.
  • extraRules sets the chances for the optional twists: a required countdown digit, a timed window after the code, and a wrong code detonating on the spot. For digit rules, the padded zero at the front of the displayed timer does not count.

Configure this to make hazmat gear count. Players wearing a configured outfit take no damage or status effects from radiation and biohazard zones.

config.lua
Config.protectiveClothing = {
enabled = true,
effects = { radiation = true, biohazard = true },
profiles = {
{
model = `mp_m_freemode_01`,
components = {
{ id = 11, collection = 'collection_name', drawable = 0 },
},
props = {},
},
},
isClientProtected = function(ped, effectType) return false end,
isServerProtected = function(source, effectType) return false end,
}

Add your hazmat outfits to profiles, or use the hooks if another resource already tracks protective gear. isServerProtected is the right place for authoritative inventory or state checks.

The client clothing profiles and reports can prevent normal zone damage and status effects. Persistent biohazard infection is stricter: isServerProtected must return true on the server. A client-only outfit check does not prevent infection.

The biohazard payload selects one agent in config_payloads.lua:

config_payloads.lua
Config.bomb.payloads.biohazard.agent = 'pathogen' -- 'pathogen' | 'cs' | 'kog'
  • pathogen is the default. After an unprotected player remains in the area for the configured dwell time, the server can assign one of the configured progressive strains. Infectious strains can then spread between nearby players.
  • cs causes eye irritation, coughing, and impaired vision while the player is inside the cloud, followed by a short visual recovery. It does not create an infection state.
  • kog knocks out an unprotected player after its dwell time and applies post-wake impairment. It does not create an infection state.

Only one agent runs for the biohazard payload. See Biohazard & Infection for the player effects and configured timings.

Infection settings now live in config_infections.lua:

config_infections.lua
Config.infection = {
enabled = true,
progressionClock = 'wall', -- 'wall' | 'online'
progressionTimeScale = 1.0,
antidoteItemName = 'kf_defuse_antidote',
stabilizationMinutes = 15,
stabilizeOn = {
hospital_respawn = false,
revive = false,
},
hospitalInteractionDistance = 2.0,
hospitalPatientDistance = 5.0,
treatmentDurationMs = 15000,
treatmentCooldownMs = 15000,
hospitalLocations = {
vec3(308.36, -595.25, 43.28),
},
safety = {
allowLethalSymptoms = true,
},
-- Exposure, transmission, outbreak, agent, and strain settings follow.
}

wall progression continues while a persisted character is offline. online counts connected play time and periodically checkpoints it. progressionTimeScale is useful for reaching later stages more quickly while testing.

Stabilisation suppresses symptoms and contagiousness for stabilizationMinutes; when that time expires, the same infection resumes at its current progression stage. An antidote permanently clears the infection and is consumed only after the server accepts the cure. Set allowLethalSymptoms = false to make configured infection damage stop before it kills the player.

FrameworkInfection state
QBCore, QBox, ESXStored in character metadata and restored when that character returns.
ox_coreKept in server memory for the current session. It is lost when the player disconnects or the resource/server restarts.

Symptoms, transmission, outbreaks, stabilisation, and debug controls still work with ox_core. Only persistence is unavailable.

Pathogen infection and KOG knockout require server-verified biohazard protection through Config.protectiveClothing.isServerProtected(source, 'biohazard'). A client clothing profile on its own can prevent local area effects, including CS irritation and coughing, but it cannot authoritatively prevent infection or KOG knockout.

At a configured hospital point, target a nearby player to expose Stabilize infection and Cure infection. Both actions take 15 seconds and can be cancelled. Cure consumes the patient’s antidote first, then the caregiver’s. Using an antidote directly from inventory runs the same treatment flow on the item holder.

stabilizeOn controls automatic treatment from hospital respawn and revive events. Both are disabled by default because the hospital target interaction is the default treatment path.

config_infections.lua
hospitalEvents = {
disabled = {},
additionalTrustedServer = {
-- { name = 'medical:server:playerRespawned', outcome = 'hospital_respawn' },
},
additionalClientReports = {
-- { name = 'medical:client:playerRespawned', outcome = 'hospital_respawn' },
},
}
  • Prefer additionalTrustedServer when your medical resource emits a server event. The invoking resource is checked, and the target player’s server ID must be the first argument.
  • Use additionalClientReports only when the medical resource has no suitable server event. Client reports are validated against a recent recorded death, the player’s alive state, a report cooldown, and the configured hospital radius for hospital respawns.
  • Leaving hospitalLocations empty disables only the hospital proximity check. Add your hospital coordinates when you want that validation.
  • Add an event name to disabled to turn off a built-in or additional listener.

Explosive Devices includes hooks for the common QB hospital, QBox medical, and ESX spawn/revive flows. Custom medical resources should use the trusted server path whenever possible.

Target options, notifications, placement controls, and the on-screen defuse prompts all come from a locale file. English ships in locales/en.json.

To translate or reword them, copy en.json to your language code and set the locale in server.cfg:

server.cfg
setr ox_locale "de"
kf-defuse/locales/de.json

Keep the keys exactly as they are and translate the values. Some strings have %s placeholders that get filled in at runtime, like a payload name or a countdown value, so leave those where they are.

If you just want to reword a few lines rather than add a language, edit en.json directly.

-- Client: open the private tablet view for the calling player.
exports['kf-defuse']:useDefuseTablet()
-- Server: trigger the tablet flow for a player.
exports['kf-defuse']:useDefuseTablet(source)
-- Client: use an antidote from the calling player's inventory.
exports['kf-defuse']:useAntidote()
-- Server: trigger the 15-second antidote flow for a player.
exports['kf-defuse']:useAntidote(source)
-- Client: tell Explosive Devices that a player entered or left an EMP effect area.
-- Only needed when an external system manages that presence.
exports['kf-defuse']:setEmpEffectAreaPresence(areaId, inside)
-- Server: read a connected player's current infection diagnosis.
local diagnosis = exports['kf-defuse']:get_infection_diagnosis(source)

get_infection_diagnosis returns nil when the source is not connected. Otherwise it returns the strain ID, infection and stabilisation timestamps, elapsed progression, current stage, and whether the player is stabilised, contagious, symptomatic, or in a lethal stage. An uninfected player receives the same diagnosis shape with no strain or stage.

These files are escrow-ignored, so you can adapt Explosive Devices to a custom server stack without editing locked code:

  • config.lua
  • config_infections.lua
  • config_payloads.lua
  • config_effects.lua
  • config_defuse.lua
  • client/framework/*.lua
  • client/interface/*.lua
  • client/inventory/*.lua
  • client/target/*.lua
  • server/framework/*.lua
  • server/inventory/*.lua

Inventory adapters must provide:

ServerFramework.addInventoryItem(player, itemName, amount, metadata)
ServerFramework.removeInventoryItem(player, itemName, amount, metadata, slot)
ServerFramework.getInventoryItem(player, itemName, preferredVariation)

Notification adapters are expected to provide:

ClientFramework.notify(data)

No notifications are showing up. Check that Config.notifications = true and that Config.notify names a resource you actually run.

The case is invisible, or the device screen is blank. kf-defuse-assets is either missing or starting after kf-defuse. The asset resource has to come first in server.cfg.

The Place Case option is missing. Equip WEAPON_KFDEFUSE, then check that ox_target is running and Config.target is set to ox_target. Players can have up to the configured number of cases deployed at a time.

There are no target options on the case. Open, payload, arm, recover, and detonation options are available to any nearby player within the configured interaction range; placer ownership is not required. Defuse Device shows up for players allowed by Config.responderTools.groups once the case is armed.

The scanner and marker options are missing. The player isn’t in one of the Config.responderTools.groups, or isn’t holding WEAPON_KFDEFUSESCANNER. Placing a marker also needs them within the configured marker interaction range of the case.

Attaching a payload fails. The payload item has to exist in the inventory under the exact name from config_payloads.lua. Detaching only returns the item if there’s space for it.

Explosive Devices creates and uses the following model names. The custom case, payload, component, and weapon assets are provided by kf-defuse-assets; the tablet, acquisition, and scanner entries use runtime or base-game models.

UseModel name
Active world and placement casekf_gas_defuse_case_open_anime
Held bomb-case weaponkf_explosive_hand_held_case
Transmitter weaponw_kf_throwphone_handset
Responder scanner weaponw_am_digiscanner_reh

These payload models are attached to the case while a payload is installed:

PayloadModel name
Explosivekf_bomb_payload_c4_explosive_canister
Biohazardkf_bomb_payload_gas_canister
Nuclearkf_bomb_payload_dirty_canister
EMPkf_bomb_payload_emp_canister
Gas canister fallbackkf_bomb_payload_gas_canister_2

These component models are attached to the case during the defuse sequence:

ComponentModel name
Red lightkf_red_light
Green lightkf_green_light
Gauge indicatorkf_gas_defuse_case_gauge_indicator
Rotation switchkf_gas_defuse_case_rotation_switch
Green wirekf_wire_green
Red wirekf_wire_red
Blue wirekf_wire_blue
Yellow wirekf_yellow_wire
White wirekf_wire_white
Crimson wirekf_wire_crimson

Utility and acquisition entities (configurable)

Section titled “Utility and acquisition entities (configurable)”
UseModel name
Defuse tablet propxs_prop_arena_tablet_drone_01
Acquisition stashprop_cs_heist_bag_02
Acquisition source pedg_m_m_armgoon_01