Skip to content
BlockFrontBlockFront DocsOfficial Documentation for BlockFront

Lua API reference

This page is generated from the mod, here from BlockFront 0.9.0.64b. For how these fit together, read Scripting first.

Functions that wait, such as anything named wait, only work inside a section or a thread.

  • notify(key, event, ...): Raises an event, waking every waittill on that key and event; extra arguments are handed to them
  • log(...): Writes a line to the game log
  • wait(seconds): Pauses the calling thread for seconds
  • waittill(key, event, timeout): Pauses the calling thread until notify(key, event) fires and returns its arguments; an optional timeout in seconds returns nil when it runs out
  • thread(fn, ...): Runs fn on a new thread alongside the caller; extra arguments go to fn
  • endon(key, event): Kills the calling thread the moment the event fires
  • waittillAny(...): Waits for whichever {key, event} pair fires first (optional trailing timeout in seconds); returns key, event, args… or nil on timeout
  • include(name): Runs another Lua file of the mission folder in place (its locals stay its own; share through globals or the file’s return value): local village = include("village.lua")
  • delay(seconds, fn, ...): Runs fn after a delay, on its own thread
  • runUntil(key, event, fn, ...): Runs fn on its own thread and blocks until it finishes, unless {key, event} fires first: then fn’s thread dies where it stands and this returns false. True when fn ran to the end. Only a future firing cuts it, so check any state the event already set before calling. Extra args go to fn. An error in fn returns false (and is reported as fn’s thread error)
  • waitUntil(fn, interval, timeout): Blocks until fn() is true, polling every interval seconds (0.25); an optional timeout returns false when it runs out
  • waittillDetected(timeout): Blocks until an unaware hostile spots the squad; an optional timeout in seconds returns nil
  • tr(key, ...): Translatable text for say, objective titles and prompts, mission.fail and the zone and friendly-fire messages: a lang key from the pack’s assets/<pack>/lang files, whose en_us.json holds the English. Further arguments fill %1$s, %2$s in the line; pass character(id) for a character’s name. A plain string in place of tr(…) is shown as written
  • character(id): A character’s display name, as an argument of tr(…)
  • say(speaker, text, opts): A subtitled line from a character or actor; text is a string or tr(…). opts: duration (s, from the word count), sound (the speaker’s character voice), reverb, volume, talkTicks (mouth movement, about the spoken length; 0 keeps the mouth still). Returns the duration
  • sayAndWait(speaker, text, opts): As say, then waits for the line to finish
  • mission.api(version): Declares the Lua API version the script targets; required at the top of mission.lua
  • mission.section(name, [opts], fn): Registers a section; opts.start names the marker the squad starts it at. The first one registered runs first
  • mission.gotoSection(name): Ends the running section and starts the named one
  • mission.complete(): Ends the mission as a success
  • mission.checkpoint(markerName): Saves progress: a restart or a resume after this puts the squad at the marker, in this section
  • mission.fail(reason): Fails the mission with the reason on screen; reason is a string or tr(…)
  • mission.friendlyFire(opts): Friendly-fire rule: a second hit on a squad mate inside opts.window seconds (3) fails the mission with opts.message; nil switches the rule off
  • flag.set(name)
  • flag.clear(name)
  • flag.get(name)
  • flag.wait(name)
  • draw.point(id, p, opts)
  • draw.box(id, min, max, opts)
  • draw.clear(prefix)
  • trigger.wait(name, opts)
  • trigger.isInside(name)
  • trigger.contains(name, x, y, z): Whether a world position lies inside the named trigger box
  • trigger.waitAny(names): Blocks until a player is inside any of the named boxes; returns that name. Rides the per-tick engine poll, so the wait shows on the debug HUD too

Mission area (the safe zone): where the squad is expected to be for this beat. A player outside it gets opts.seconds (10) to return before the mission fails with opts.message. Shapes: a zone name from spatial.json (/mission zone add, drawn by /mission debug), a trigger name, a box { min = { x, y, z }, max = { x, y, z } } (what /mission region copies in AABB mode), a footprint polygon { { x, z }, { x, z }, … } of any height (boundary mode), or a list mixing them. set replaces the previous area, clear lifts it (runtime restarts clear it too). Crossing the edge raises (“zone”, “left”, playerName) / (“zone”, “returned”, playerName)

  • zone.set(shapes, opts)
  • zone.clear()
  • zone.contains(x, y, z): Whether a world position lies inside the area (everywhere while none is set)
  • marker.pos(name)
  • objective.add(id, title, opts): opts.waypoint (a marker/trigger/actor id, an {x, y, z} block, or a list of them) and opts.prompt set the waypoint in the same breath; title and prompt take a string or tr(…)
  • objective.complete(id)
  • objective.waypoint(id, target, prompt)
  • objective.progress(id, done, total): progress(id, done, total) shows (done/total) after the title; a total of 0 clears it
  • actor.spawn(id)
  • actor.spawnAll()
  • actor.remove(id)
  • actor.exists(id)
  • actor.stance(id, stance): stance: “stand”, “crouch”, “lie” (on the back), “prone” (face down) or “sit” (hostile actors only)
  • actor.setAware(id, aware)
  • actor.isAware(id)
  • actor.setVigilant(id, vigilant): A blind lookout: setVigilant(id, false) keeps an unaware actor out of the detection sweep and gunshot hearing (a direct hit still wakes him)
  • actor.setCurious(id, curious): Whether an unaware actor leaves his post to look into a noise the squad makes (off by default). Wanting to hear gunfire is setVigilant; wanting to go and look is this
  • actor.patrol(id, markerSet, opts): opts: speed (patrol pace multiplier, default 0.6)
  • actor.stopPatrol(id)
  • actor.follow(id, target, opts)
  • actor.stopFollow(id)
  • actor.lookAt(id, target): Face a target until stopLook: “player” (nearest), an actor/character id, a player name, or a marker
  • actor.stopLook(id)
  • actor.face(id, yaw, pitch): Face an exact yaw/pitch (degrees) until stopLook
  • actor.lookAtPos(id, x, y, z): Face an exact position (x, y, z or {x, y, z}), or the centre of a block, until stopLook
  • actor.lookAtBlock(id, x, y, z)
  • actor.useItem(id): Raise/lower the held item spyglass-style (binoculars), with its use sounds
  • actor.stopUseItem(id)
  • actor.aim(id, aiming): Raise/lower the held gun along the gaze
  • actor.spawnAt(id, pos, opts): Spawns an actor at {x, y, z} from a placed actor used as a template (opts.template, default = the same id); opts.name overrides the nameplate, opts.yaw the facing and opts.parachute = true drops it in under a chute
  • actor.isParachuting(id)
  • actor.isInvestigating(id): Whether a noise has taken him off his post to go and look. Raised as (“stealth”, “suspicious”, id, x, y, z) and closed by (“stealth”, “dismissed”, id)
  • actor.waitLanded(id): Waits for a dropped actor to touch down (returns at once if it is dead)
  • actor.holdPosition(id, hold): A hostile fights from wherever its scripted move takes it instead of hunting
  • actor.swing(id): One arm swing; with an empty hand it reads as a point or a gesture
  • actor.teleport(id, target, opts): Drops an actor at a marker or {x, y, z} (opts.yaw overrides the facing); for restarts, since it cuts any walk short
  • actor.sweep(id, yawFrom, yawTo, pitch, seconds): Pans an unaware guard’s gaze between two yaws (degrees) over seconds, back and forth, until the actor dies or wakes; returns at once
  • actor.gesture(id, target, opts): Empties the hand, faces the target (if any) and jabs the arm a few times, then restores opts.restore to the hand; blocks for the gesture (~1.4 s by default)
  • actor.reload(id, opts): Reload sound + pose; opts.duration seconds (default: the gun’s reload time). Returns the duration
  • actor.reloadAndWait(id, opts)
  • actor.shoot(id): Fire the held gun once, dead on the current gaze (or facing)
  • actor.moveToPos(id, x, y, z, opts): Exact-position moves (same opts as moveTo); the position as x, y, z or {x, y, z}
  • actor.moveToPosAndWait(id, x, y, z, opts)
  • actor.attack(id, opts): Combat: engage the aware hostiles the game picks. opts: range (32), aimError degrees (4), advance (true = close in on targets out of sight or too far), damage (1.0, multiplier on the actor’s hits; keep squad mates weak so the player gets the kills). Scripted moves pause while a target is held and resume afterwards
  • actor.stopAttack(id)
  • actor.waitCombatIdle(id): Blocks until no hostile has been in reach for a few seconds
  • actor.attackThenReturn(id, returnTo, opts): Fight, then return: to a marker, or (nil) to where he stood, unless a scripted move is pending (that walk resumes by itself after the fight). The pending check is made again at the end, since the walk he is owed is usually ordered mid-fight
  • actor.setTargetable(id, targetable): Whether hostile bots may target this actor (default true)
  • actor.setInvincible(id, invincible)
  • actor.setHealth(id, health): Sets a live actor’s health (clamped to its max): a near-death set piece
  • actor.canSeePlayer(id, playerName): Whether the actor has an eye-to-eye line of sight to the named squad player
  • actor.moveTo(id, markerName, opts): opts: speed, arrive, crouch (shift-walk + hold crouch on arrival), sprint, stay (true: the spot is his post afterwards, and shoved off it by a squadmate or a player he walks back and takes up his pose again; false for a passing move)
  • actor.moveToAndWait(id, markerName, opts)
  • actor.moveAlong(id, markerSet, opts)
  • actor.toPost(id, dest, opts): The walk-to-post idiom the missions share: drop attack and look (opts.stop = false keeps them), stand for the walk, then settle on arrival: opts.stance (“crouch” | “stand”, crouch), the dest’s facing when it carries one, opts.aim, opts.attack (actor.attack opts). dest: a marker name, an {x, y, z}, or a post { {x, y, z}, yaw, pitch }. opts: speed (1.2), arrive (0.8), sprint, async (return at once, walk in a thread)
  • actor.holdItem(id, itemId)
  • actor.pos(id): x, y, z of a live actor, or nil
  • actor.toss(id, itemId, playerName): Tosses a bag item toward the named squad player (nil = the nearest); dropAmmo and dropMedkit are the ammo box and the medic bag
  • actor.dropAmmo(id, playerName)
  • actor.dropMedkit(id, playerName)
  • actor.throw(id, itemId, yaw, pitch, opts): Throws a grenade item along yaw/pitch (degrees); opts.force (1.2). The blast reaches the script as (“actor:<id>”, “impact”, x, y, z)
  • actor.waitDead(...)
  • actor.waitInteract(id)
  • actor.kill(id): Kills an actor outright (a scripted death under fire)
  • actor.spray(id, opts): Suppressive fire from a hostile bot, whatever it sees: pans between opts.yaw = {a, b} / opts.pitch = {a, b} (degrees) over opts.period seconds per pass, firing bursts of opts.burst = {min, max} seconds with opts.pause = {min, max} seconds between, off an endless belt (opts.belt seconds per change, 2); until stopSpray or death, or opts.seconds if given. opts.at = {x, y, z} aims the arc at a point instead (plus or minus opts.wobble degrees, 2). opts.rate scales the gun’s own fire rate; opts.track = true fires on a player in view instead of the arc, back on the arc once he is lost. The bot stands where it is meanwhile
  • actor.stopSpray(id)
  • actor.jam(id, jammed): Jams a hostile bot’s gun (the spray stops, he fumbles with it and fires no more) until jam(id, false)

Demolition charges and satchels (bf:demolition_charge, bf:satchel, handed out with player.give). arm(id, {x, y, z}, opts) makes the block a demolition charge spot: a charge used on it (or within opts.radius blocks of it, 1.5) is consumed and shows on the wall. armArea(id, from, to, opts) makes the tops of the ground blocks between two corners a satchel spot, outlined while a satchel is in hand: holding use stood on them plants one at the player’s feet, which beeps for opts.fuse seconds (10), then raises (“charge:<id>”, “detonated”, x, y, z). Either plant raises (“charge:<id>”, “planted”, x, y, z, playerName). waitPlanted(id) / waitDetonated(id) block for those; detonate(id, opts) sets it off (opts as fx.explode; the script swaps the wall itself; a satchel’s blast was already seen, so only its damage is dealt); pos(id) is the planted charge’s {x, y, z}; disarm(id) withdraws an unplanted spot

  • charge.arm(id, p, opts)
  • charge.armArea(id, from, to, opts)
  • charge.disarm(id)
  • charge.waitPlanted(id)
  • charge.waitDetonated(id)
  • charge.detonate(id, opts)
  • charge.pos(id)
  • group.define(name, members)
  • group.members(name)
  • group.each(name, fn)
  • group.spawn(name)
  • group.remove(name)
  • group.stance(name, s)
  • group.setAware(name, aware)
  • group.alert(name, origin, opts): Raises the group the way a shout carries, instead of all at once: origin (a member id, or an {x, y, z}) is aware from the start, then each remaining unaware member wakes once the alarm has crossed the gap from the nearest man already alerted, so it relays outward hop by hop. Each hop takes opts.minDelay (0.25 s) + gap / opts.speed (35 blocks per second) + up to opts.jitter (0.3 s); opts.onAlert(id) runs for every relayed man. Returns at once and runs in its own thread; members alerted meanwhile by other means (shot at, saw the player) join the relay as sources.
  • group.patrol(name, markerSet)
  • group.move(name, markerSet, opts)
  • group.waitDead(name)
  • group.anyAlive(name): Whether any member is still alive

Expendable friendlies who man a list of slots (a wall, a house), refilled from the sky when they fall. squad.new(opts) makes one. opts: template (placement to clone), weapon (item drawn once landed), slots ({x, y, z} list, one man each, optionally {x, y, z, yaw, pitch} to face once crouched on it), dropPoints ({x, y, z} list the sticks come out over), dropSpread (6), names (surname bag, each used once before it recycles), namePrefix (“”), attack (actor.attack opts once in position), refill ({6, 12} seconds before a fallen man’s replacement drops), idPrefix (“pvt”), key (“squad”, the advance event key). setRoute({markerSet, …}, opts) lays an authored corridor: a man far from his slot walks it first, joining at the node nearest him and leaving at the node nearest his slot, so long treks follow hand- placed nodes instead of raw pathfinding; swap the list to divert at a split (a missing marker set is skipped, opts.speed sets the corridor pace, nil clears). Setting s.rallyPoint = {x, y, z} makes replacements run in on foot from there (held until no player can see the spot, up to ten seconds) instead of parachuting at the drop points; nil restores the drops. On the squad: drop(slot, name) parachutes a new man in for a slot and returns his id; armOnLanding(id, {reload}) waits for touchdown and draws the weapon (false if he died); place(slot, name, yaw) spawns a man standing on his slot, armed (jump-tos); hold(slot, id) keeps the slot manned (walk there, crouch, fight, a replacement drops when he falls) until the runtime ends; advance(slots) moves every holder to a new slot list; holder(slot) is the live man on a slot, or nil

  • squad.new(opts)
  • player.give(name, itemId, opts): give(name, itemId, opts): opts.barrel picks a gun barrel; opts.select = true puts the item in the player’s hand (a handoff), when it lands in the hotbar
  • player.isCrouching(name)
  • player.name(): The first squad player’s name, for dialogue
  • player.hasItem(name, itemId): Whether the named player (“*” or nil = any squad player) carries the item
  • player.take(name, itemId): Takes one of the item off the named player (“*” or nil = whoever is carrying it), for a scripted hand-over; returns whether there was one to take
  • player.canSee(p): Whether any squad player has a clear line of sight to {x, y, z}
  • player.pos(name): A living squad player’s position as x, y, z (nil name = the first one), or nil
  • player.names(): Every living squad player’s name
  • player.waitHasItem(name, itemId)
  • player.parachuteDrop(opts): Drops the squad in under parachutes: lifts every player opts.height (64) blocks straight up, fading in from black; the chute releases on touchdown
  • player.shellshock(seconds): Deafens the squad for seconds (6): the blast, a ring held under it, then the ears coming back over the last two seconds. Under two seconds is just the ears coming back; 0 ends one already running
  • player.isParachuting()
  • player.waitLanded(): Waits for every dropped squad player to touch down

Items dropped into the world for the squad, addressed as {x, y, z}; cleared with the actors on restarts. opts.locked = true stages the item in place until unlock(p) frees everything lying within a few blocks of p

  • item.spawn(itemId, p, opts)
  • item.unlock(p)

Enemy waves: spawn(name, opts) drops opts.count hostiles cloned from the placed actor opts.template at opts.at = {x, y, z}, opts.batch at a time every opts.interval seconds (in its own thread), aware from the start so they hunt the squad; the wave is also the group name. opts.hold = {x, y, z} sends each man to that spot to fight from it (a window, sandbags), or a list of spots the men take in turn; opts.via = a list of {x, y, z} walked in order first (a door). opts.replace = true drops the next man only once the previous one is dead. stop(name) ends a wave’s spawning (the men already out keep fighting; waitSpawned then returns nil for men who never came). waitDead(name) waits for every man in a wave to fall; waitDeadOrTimeout(names, seconds) returns true if they all fell in time. Each man fires (“wave:<name>”, “spawned”, id, index, count); waitSpawned(name, index) waits for the index-th man (default the last) and returns his id. opts.unseen = true holds each man until no player can see where his eyes would be (up to opts.unseenTimeout seconds, 10), so nobody pops in on screen. opts.holdSpawn = true keeps each man fighting from the spot he spawned on (alert, engages on sight from any angle, never hunts or wanders); opts.aware = false instead spawns the men unaware, standing down until the squad is seen, shoots nearby or hits them.

  • wave.spawn(name, opts)
  • wave.waitSpawned(name, index)
  • wave.stop(name)
  • wave.isAlive(name)
  • wave.waitDead(name)
  • wave.waitDeadOrTimeout(names, seconds)

Signal smoke: find(trigger) returns x, y, z of a burning canister inside the named trigger box (nil trigger = anywhere near the squad), or nil; wait(trigger) polls for one

  • signal.find(triggerName)
  • signal.wait(triggerName)

Mission music: “auto” follows the fight (stealth loop, combat loop while an alerted hostile is on the squad), “stealth” / “combat” pin a loop, “off” stops it

  • music.set(mode)

Stealth tuning: how far a shot carries to unaware hostiles (blocks)

  • stealth.setHearingRadius(radius, suppressedRadius)

Map effects switchable by effectId (e.g. searchlights); on/off take any number of ids

  • effects.on(...)
  • effects.off(...)
  • effects.isDone(id): Whether an effect that runs its course (a pathed vehicle) has finished
  • effects.waitDone(id, opts): Waits for it, up to opts.timeout seconds (60); returns true when it finished

Scripted blasts at {x, y, z}. opts: radius (4, blast damage reach in blocks), damage (true; false = looks and sound only), type (“generic” | “artillery” | “vehicle”)

  • fx.explode(p, opts)
  • fx.clearCorpses(): Clears every corpse on the squad’s clients (restarts and section jumps do this on their own)

One-shot 3D sounds at a marker, an actor, or an {x, y, z} position; volume extends range (16 blocks per unit)

  • sound.play(target, soundId, opts)

The squad’s screens. fadeOut(seconds, opts) fades to black over seconds (2), holds it there and releases it, so a mission can bow out on black. opts.quote = true holds a random war quote (texts/war_quotes.json) on the black for QUOTE_SECONDS first. Returns the seconds the whole beat runs for, so a script can wait it out before concluding

  • screen.fadeOut(seconds, opts)

Block-state properties by world position (e.g. “lit”); values are booleans, numbers or property names. Errors when the block has no such property

  • block.set(x, y, z, name, value)
  • block.get(x, y, z, name)

Swappable block structures declared with /mission structure (a wall intact vs blown open, each a region of the map). set copies a named variant onto the structure’s anchor, reset the default one, get returns the variant showing now, anchor returns the anchor block’s centre as {x, y, z} (handy for fx.explode). Every runtime (re)start and the mission end put all defaults back

  • structure.set(id, variant)
  • structure.reset(id)
  • structure.get(id)
  • structure.anchor(id)

Objective documents (bf:objective_document blocks), addressed as {x, y, z} block positions; a pickup raises (“document”, “collected”, x, y, z, playerName)

  • documents.reset(list): Puts every listed document back on its table; section tops call this
  • documents.isCollected(p)
  • documents.place(p, collected): Makes sure a document stands at p (putting one there if the spot is empty) and says whether it has already been taken. A taken one is invisible and cannot be picked up
  • documents.scatter(list, count): Scatters count documents over the given candidate spots: every spot is filled and marked taken, then that many are picked at random and put back out to be found. Returns the chosen spots, which is what collectAll should be pointed at
  • documents.remaining(list): The listed documents not yet collected
  • documents.collectAll(objectiveId, list, prompt): Points the objective at every uncollected document (with the right-click prompt), counts them off in its title and waits until all are taken, trimming the waypoints as they go
  • sequence.prepare(name, opts): While another sequence is performing, prepare lets it finish before the walk begins; pass { interrupt = true } to cut it immediately
  • sequence.play(name)
  • sequence.playAndWait(name)
  • sequence.stop()
  • sequence.isActive()