Skip to content

Server Exports ​

Bombs & Breakable Walls provides server-side exports for placing, breaching, and repairing walls, planting and handing out bombs, and managing workbenches, plus server events to react to explosions, breaches, and defusals.

Return values

Exports that change something return true (or the new ID) on success, and false - often with a reason - on failure. A reason is either a short code (breachWall) or a locale key from locales/en.json, e.g. 'bench.holds_parts'.

Walls ​

A wall is a run - one straight stretch of one style, 3 m tall, any length in steps of 0.25 m. Coordinates are the ground position of the run's centre, and the heading the wall faces. See the Walls Reference for every style and hole shape.

Style keys

Every wall export takes a wall's style key - 'brick_red', 'concrete_reinforced', 'steel_plate' - listed under Wall Styles and returned by getWallStyles. It is not the wall-kit item name: pass 'brick_red', not 'wallkit_brick_red'.

placeWall ​

Place a wall.

Syntax

lua
local id = exports['sd-bombs']:placeWall(style, coords, opts)
ParameterTypeDescription
stylestringThe wall's style key, e.g. 'brick_red' - see Wall Styles. Not the wall-kit item name
coordsvector4Ground position of the run's centre, and its heading
optstable?Options (below)
OptionTypeDefaultDescription
lengthnumber2Metres, rounded up to 0.25 (max 40)
colorstring?-A paint colour the style comes in, e.g. 'navy'
persistentbooleanfalseSave it, so it comes back after a restart
tagstring?-Your own label - remove every wall with it at once with removeWallsByTag
scriptOnlybooleanfalseGame explosions and planted bombs never breach it - only breachWall / breakWall (and staff) open it
autoRepairbooleantruefalse = it never rebuilds itself: it stays breached until repairWall

Returns the new wall's id, or nil for an unknown style.

Example

lua
-- A 6 m reinforced concrete wall across a vault corridor, rebuilt by the heist every time
local id = exports['sd-bombs']:placeWall('concrete_reinforced', vec4(255.1, 225.4, 101.9, 160.0), {
    length = 6.0,
    tag = 'pacific-vault',
})

Scripted walls

A heist that puts its walls up itself should leave persistent off and give them a tag: it rebuilds its own set each time and clears it with removeWallsByTag, and nothing is left behind in data/walls.json.

placeWallBetween ​

Place a wall that closes the gap between two points - its length and heading are worked out for you.

Syntax

lua
local id = exports['sd-bombs']:placeWallBetween(style, a, b, opts)
ParameterTypeDescription
stylestringThe wall's style key, e.g. 'brick_red' - see Wall Styles. Not the wall-kit item name
avector3One side of the gap
bvector3The other side
optstable?As placeWall, without length. z sets the height of the wall's foot - by default the lower of the two points' heights, so give ground-level points (a player's GetEntityCoords is about 1 m above the ground)

Returns nil when the points are less than 5 cm apart.

removeWall ​

Syntax

lua
local removed = exports['sd-bombs']:removeWall(id)

Returns true when the wall was there.

removeWallsByTag ​

Remove every wall carrying a tag.

Syntax

lua
local count = exports['sd-bombs']:removeWallsByTag(tag)

Returns how many walls were removed.

moveWall ​

Syntax

lua
local moved = exports['sd-bombs']:moveWall(id, coords)
ParameterTypeDescription
idnumberThe wall ID
coordsvector4New ground position of the run's centre, and heading

The wall keeps its holes.

resizeWall ​

Syntax

lua
local resized = exports['sd-bombs']:resizeWall(id, length, anchor)
ParameterTypeDescription
idnumberThe wall ID
lengthnumberNew length in metres, rounded up to 0.25
anchornumber?Which end stays put: -1 its start, 1 its end, 0 (default) grow or shrink from the middle

Holes that no longer fit are closed.

extendWall ​

Add a 2 m section at one end.

Syntax

lua
local extended = exports['sd-bombs']:extendWall(id, side)
ParameterTypeDescription
idnumberThe wall ID
sidenumber1 at its end, -1 at its start

setWallStyle ​

Rebuild a wall in another style where it stands. Its holes stay; so does its colour if the new style comes in it.

Syntax

lua
local changed = exports['sd-bombs']:setWallStyle(id, style, color)
ParameterTypeDescription
idnumberThe wall ID
stylestringThe wall's style key, e.g. 'brick_red' - see Wall Styles. Not the wall-kit item name
colorstring?A colour to repaint it in at the same time

setWallColor ​

Syntax

lua
local changed = exports['sd-bombs']:setWallColor(id, color)
ParameterTypeDescription
idnumberThe wall ID
colorstring?A colour the style comes in, or nil for the style as it comes

startWallPlacement ​

Let a player put up one wall of a style with the placement tool - no item and no admin permission needed. A job that builds barricades, a shop that sells the service, a heist crew fortifying a door. The licence lasts 5 minutes, or until the wall stands or the tool is cancelled.

Syntax

lua
local started = exports['sd-bombs']:startWallPlacement(source, style, opts)
ParameterTypeDescription
sourcenumberThe player's server ID
stylestringThe wall's style key, e.g. 'brick_red' - see Wall Styles. Not the wall-kit item name
optstable?{ persistent = boolean (default true), tag = string? }

Returns false for an unknown style or player. Listen for wallPlaced to get the wall's ID once it stands.

Example

lua
RegisterNetEvent('my-job:server:buildBarricade', function()
    local src = source
    if exports.ox_inventory:RemoveItem(src, 'plywood', 4) then
        exports['sd-bombs']:startWallPlacement(src, 'wood_planks', { persistent = false, tag = 'barricade' })
    end
end)

setWallRules ​

Change how a wall may be breached, and whether it rebuilds itself. A field left out stays as it is.

Syntax

lua
local changed = exports['sd-bombs']:setWallRules(id, rules)
Field (rules)TypeDescription
scriptOnlyboolean?true = explosions and bombs never breach it; false = they do again
autoRepairboolean?false = it never rebuilds itself; true = it does after RepairAfter

Example

lua
-- The vault wall only your thermite opens - until the alarm is cut, then anything goes
exports['sd-bombs']:setWallRules(vaultWall, { scriptOnly = false })

breachWall ​

Blow a hole in a wall - the shape you want, where you want it.

Not needed for bombs and explosions

Planted bombs and game explosions breach walls by themselves - you do not call anything for that. Use breachWall when a wall should open without an explosion (a thermite or torch minigame, a scripted scene) or exactly the way your script chooses. To stop explosions opening your wall at all, place it with scriptOnly = true (or setWallRules).

Syntax

lua
local ok, hole = exports['sd-bombs']:breachWall(id, shape, opts)
ParameterTypeDescription
idnumberThe wall ID
shapestring | number | nil'doorway' (or 'breach'), 'split', 'wide', 'low', 'vehicle', 'collapse', 'window', 'top', 'end', 'corner' - or 1-10. nil picks one the way an explosion does (by opts.power)
optstable?Where and why (below)
OptionTypeDescription
alongnumber?Metres from the run's start where the hole is centred
coordsvector3?Instead of along: centred as close to this point as the run allows
sidestring?For 'end' and 'corner': 'start' or 'end' of the run. Default: the end nearer along / coords
powernumber?With no shape: the blast's power - the more it has to spare over the wall's toughness, the bigger the hole
typestring?What caused it, passed to the wallBreaking / wallBroken events. Default 'script'
sourcenumber?A player to credit, passed to the events
ReturnTypeDescription
okbooleanWhether the wall was breached
holetable | stringOn success { at, variant, shape, flip?, widened }, else a reason: 'unknown_wall', 'unknown_shape', 'no_room', or 'cancelled' (a wallBreaking handler said no)

hole.at is where the hole starts along the run, in metres. widened is true when the blast went into a hole that was already there and made it bigger instead.

Example

lua
-- A thermite charge opens a doorway right where the player set it
local ok, hole = exports['sd-bombs']:breachWall(wallId, 'doorway', { coords = GetEntityCoords(GetPlayerPed(source)), type = 'thermite', source = source })
if not ok then
    print('Wall still standing: ' .. hole)
end

-- Knock the end off a wall, or bring a 4 m section down in the middle
exports['sd-bombs']:breachWall(wallId, 'end', { side = 'end' })
exports['sd-bombs']:breachWall(wallId, 'collapse', { along = 4.0 })

When a shape does not fit

A 4 m shape (vehicle, collapse) with no 4 m of wall free falls back to the biggest 2 m one. A shape asked for where a hole already is makes that hole bigger (hole.widened). end and corner need the end of the run free. 'no_room' means nothing could be done anywhere near.

breakWall ​

The lower-level form of breachWall: breach a wall from a cause table - the same one the events carry.

Syntax

lua
local broken = exports['sd-bombs']:breakWall(id, cause)
Field (cause)TypeDescription
typestringWhat caused it, e.g. 'explosion', 'script'
coordsvector3?Where the blast was - the hole is centred on it
alongnumber?Instead of coords: metres from the run's start
powernumber?The blast's power
variantnumber?A hole shape, 1-10
sourcenumber?A player to credit

Returns true when the wall was breached.

breakWallsNear ​

Breach every intact wall around a point, as an explosion there would.

Syntax

lua
local ids = exports['sd-bombs']:breakWallsNear(coords, radius, power, cause)
ParameterTypeDescription
coordsvector3Where the blast is
radiusnumberMetres, to the nearest point of each wall
powernumberBreaches every wall whose toughness it meets
causetable?As breakWall; coords and power are filled in

Returns the IDs of the walls that were breached.

repairWall / repairAllWalls ​

Rebuild a breached wall - every hole is closed - or every breached wall.

Syntax

lua
local repaired = exports['sd-bombs']:repairWall(id)
local count = exports['sd-bombs']:repairAllWalls()

getWall ​

Syntax

lua
local wall = exports['sd-bombs']:getWall(id)
FieldTypeDescription
idnumberWall ID
stylestringThe wall's style key, e.g. 'brick_red'
colorstring?Paint colour
statestring'intact' or 'broken'
lengthnumberMetres
holestable[]{ at, variant, flip? } for every hole
coordsvector4Ground position of the run's centre, and heading
persistentbooleanSaved across restarts
tagstring?Its tag
brokenAtnumber?When it was last breached (unix seconds)
scriptOnlybooleanOnly scripts breach it, never explosions or bombs
autoRepairbooleanRebuilds itself after RepairAfter

getWalls ​

Syntax

lua
local walls = exports['sd-bombs']:getWalls(tag)
ParameterTypeDescription
tagstring?Only walls carrying this tag

Returns a list of walls, as getWall.

getNearestWall ​

Syntax

lua
local id, distance = exports['sd-bombs']:getNearestWall(coords, maxDist, state)
ParameterTypeDescription
coordsvector3Where to look from
maxDistnumberMetres
statestring?Only 'intact' or 'broken' walls

isWallBroken ​

Syntax

lua
local broken = exports['sd-bombs']:isWallBroken(id)

getWallStyles ​

Every wall style.

Syntax

lua
local styles = exports['sd-bombs']:getWallStyles()
FieldTypeDescription
keystringThe style key - what the wall exports take, e.g. 'brick_red'
labelstringDisplay name
toughnessnumber1-4
fxstringBreach effect: 'plaster', 'wood', 'metal', or 'masonry'
colorsstring[]?The paint colours it comes in

getHoleShapes ​

The ten hole shapes breachWall takes.

Syntax

lua
local shapes = exports['sd-bombs']:getHoleShapes()
FieldTypeDescription
idnumber1-10
namestringe.g. 'breach', 'window'
widthnumberMetres of wall it takes: 2, or 4 for vehicle / collapse
edgebooleanOnly opens at a run's end (end, corner)

Bombs ​

plantBomb ​

Plant an armed bomb. Its clock starts at once.

Syntax

lua
local id = exports['sd-bombs']:plantBomb(coords, opts)
ParameterTypeDescription
coordsvector4Ground position and heading - the bomb's front faces back along the heading
optstable?Options (below)
OptionTypeDefaultDescription
secondsnumber300The countdown
strikesnumber3Strikes allowed, 1-5
modulesnumber5How many modules are dealt, 1-11 - more than 5 spill onto the back face
needybooleanfalseAlso deal 1-2 needy modules - they can never be solved, only kept quiet
seedstring?randomSix characters - the same seed always deals the same bomb
yieldnumber3Blocks of explosive, 1-6: how hard it hits walls
variantstring?-'small', 'medium', or 'large' - a compact casing instead of the Extra Large
layoutstring?-Exactly which module sits in which bay, e.g. 'f1:timer,f0:wires,f2:button'
edgestring?dealtThe edgework, as the bench fits it
rotvector3?-Pitch, roll, yaw: stick the casing exactly at coords, turned so - on a wall or a ceiling
surfacestring?-'floor', 'wall', or 'ceiling'
dudbooleanfalseIts clock runs, but at zero it only clicks

Example

lua
-- A two-minute bomb on the vault door, packed to bring the wall down
local id = exports['sd-bombs']:plantBomb(vec4(255.2, 223.8, 101.7, 160.0), {
    seconds = 120,
    strikes = 2,
    modules = 7,
    yield = 6,
})

plantBombInFrontOf ​

Plant a bomb on the ground in front of a player.

Syntax

lua
local id = exports['sd-bombs']:plantBombInFrontOf(source, opts)
ParameterTypeDescription
sourcenumberThe player's server ID
optstable?As plantBomb

removeBomb ​

Take a bomb away without a bang.

Syntax

lua
local removed = exports['sd-bombs']:removeBomb(id)

detonateBomb ​

Set an armed bomb off now.

Syntax

lua
local detonated = exports['sd-bombs']:detonateBomb(id, reason)
ParameterTypeDescription
idnumberThe bomb ID
reasonstring?Logged, and passed to the exploded event

getBombs / getBomb ​

Syntax

lua
local bombs = exports['sd-bombs']:getBombs()
local bomb = exports['sd-bombs']:getBomb(id)
FieldTypeDescription
idnumberBomb ID
x, y, z, headingnumberWhere it is
statusstring'armed', 'defused', or 'dud' (a bomb that went off is gone)
secondsLeftnumberSeconds on the clock while armed
seedstringIts seed
modulesnumberHow many modules
needybooleanHas a needy module
strikesnumberStrikes allowed
yieldnumberBlocks of explosive
variantstring?Compact casing size
builtbooleanBuilt at a workbench (has a layout)
dudbooleanSigned off with its arming pin in
defusernumber?Server ID of whoever is defusing it right now
defuserNamestring?Their name

giveBomb ​

Hand a player a finished bomb as an item - exactly as a workbench turns one out. Planted, that bomb is the one that gets defused.

Syntax

lua
local ok, why = exports['sd-bombs']:giveBomb(source, build)
Field (build)TypeDescription
variantstring?'small', 'medium', 'large', or nil for the Extra Large
layoutstringWhich module sits in which bay, e.g. 'f1:timer,f0:wires'
seedstringSix characters
secondsnumberThe countdown
strikesnumberStrikes allowed
chargenumberBlocks of explosive - no more than the size holds
edgestring?The edgework
dudboolean?Signed off with its arming pin in

Returns false and a locale key when the build is not one a bench could have made.

TIP

The admin panel's Bombs tab builds bombs bay by bay and has a Give button - the easiest way to find a valid layout and edge to copy.

Workbenches ​

Workbenches are where bombs are built. Coordinates are the ground position and heading; the builder stands on the bench's front side.

placeBench ​

Stand a workbench. It is saved and comes back after a restart.

Syntax

lua
local id = exports['sd-bombs']:placeBench(coords, opts)
ParameterTypeDescription
coordsvector4Ground position and heading
optstable?{ owner = source | identifier } - that character can pack it up again with the workbench item

removeBench ​

Syntax

lua
local ok, why = exports['sd-bombs']:removeBench(id, force)
ParameterTypeDescription
idnumberThe bench ID
forceboolean?Remove it even if parts still lie on it - they are lost

Fails with 'bench.from_config' for a bench from the config, 'bench.holds_parts' for one that still holds parts (without force), and 'admin.bench_in_use' while somebody works at it.

moveBench ​

Stand a bench somewhere else. What lies on it goes with it.

Syntax

lua
local ok, why = exports['sd-bombs']:moveBench(id, coords)

setBenchOwner ​

Hand a bench to a character, or to nobody (then only staff can take it away).

Syntax

lua
local ok, why = exports['sd-bombs']:setBenchOwner(id, owner)
ParameterTypeDescription
idnumberThe bench ID
ownernumber | string | nilA player's server ID, a framework identifier (citizenid / license), or nil

getBench / getBenches ​

Syntax

lua
local bench = exports['sd-bombs']:getBench(id)
local benches = exports['sd-bombs']:getBenches()
FieldTypeDescription
idnumberBench ID
coordsvector4Where it stands
placedbooleanPlaced in-game (saved); false for one from the config
ownerstring?The identifier of the character who owns it
usernumber?Server ID of whoever is building at it right now
holdstableWhat lies on it: { tools, book, brackets, reel, cup, casing, loose, empty }

stockBench ​

Kit a bench out.

Syntax

lua
local done, why = exports['sd-bombs']:stockBench(id, loadout)
Field (loadout)TypeDescription
toolsstring[]?Tools to hang on its pegboard, e.g. { 'driver', 'hexkey', 'knife' }
handbookboolean?The handbook on its lectern
bracketsboolean?A set of charge brackets
reelboolean?A stocked wire rack
cupboolean?A cup of screws

Returns what went onto it.

clearBench ​

Sweep a bench clean: everything on it - a build in progress included - is gone.

Syntax

lua
local ok, why = exports['sd-bombs']:clearBench(id)

Events ​

Server events other resources can listen to with AddEventHandler.

explosion ​

Fires for every explosion in the world, before any wall is touched. CancelEvent() spares the walls from that explosion (it does not stop the explosion itself).

lua
AddEventHandler('sd-bombs:server:explosion', function(data)
    -- data: { coords, explosionType, power, reach, source, damageScale, invisible, bombId? }
    if data.explosionType == 2 and IsInSafeZone(data.coords) then
        CancelEvent() -- sticky bombs never breach walls here
    end
end)

wallBreaking ​

Fires before a wall is breached. CancelEvent() keeps the wall standing.

lua
AddEventHandler('sd-bombs:server:wallBreaking', function(wall, cause)
    if wall.tag == 'pacific-vault' and not HeistIsActive() then
        CancelEvent()
    end
end)

wallBroken ​

Fires once a wall has been breached.

lua
AddEventHandler('sd-bombs:server:wallBroken', function(wall, cause)
    -- cause: { type, coords?, power?, source?, hole = { at, variant, flip? }, holes, widened? }
    if wall.tag == 'pacific-vault' then
        TriggerEvent('my-heist:server:vaultOpen')
    end
end)

wallPlaced / wallRemoved / wallRepaired ​

lua
AddEventHandler('sd-bombs:server:wallPlaced', function(wall) end)
AddEventHandler('sd-bombs:server:wallRemoved', function(wall) end)
AddEventHandler('sd-bombs:server:wallRepaired', function(wall) end)

exploded ​

Fires when a bomb goes off - its clock ran out, it took its last strike, or it was detonated.

lua
AddEventHandler('sd-bombs:server:exploded', function(data)
    -- data: { id, coords, seed, reason, defuser?, yield }
end)

defused ​

lua
AddEventHandler('sd-bombs:server:defused', function(data)
    -- data: { id, coords, seed, defuser }
    if data.defuser then
        exports['my-rewards']:give(data.defuser, 'bomb_defused')
    end
end)

fizzled ​

Fires when a dud - a bomb signed off with its arming pin in - reaches zero: it only clicks.

lua
AddEventHandler('sd-bombs:server:fizzled', function(data)
    -- data: { id, coords, seed, reason, defuser? }
end)