Skip to content

Control Flow

ffredyk edited this page Jul 23, 2026 · 1 revision

Control Flow

SQ# provides standard control flow constructs. Unlike SQF, then is optional after if.

if / else

// Basic if
if (_hp <= 0) {
    handleDeath();
};

// if-else
if (_alive) {
    attack();
} else {
    retreat();
};

// if-else if-else chain
if (_score > 100) {
    rank = "A";
} else {
    if (_score > 50) {
        rank = "B";
    } else {
        rank = "C";
    };
};

// then is optional (both work)
if (_cond) then { action(); };
if (_cond) { action(); };

// Ternary-like (returns value)
_result = if (_cond) then { "yes" } else { "no" };

while

// Basic while loop
_i = 0;
while { _i < 10 } do {
    print f"Index: {_i}";
    _i = _i + 1;
};

// Infinite loop with exit
while { true } do {
    if (_done) exitWith {};
    sleep 0.1;
};

// Condition re-evaluated each iteration
while { count _queue > 0 } do {
    processItem(_queue deleteAt 0);
};

The condition must be wrapped in {} — it's a code block that is re-evaluated every iteration.

for

// for-from-to
for "_i" from 0 to 9 do {
    print f"Index: {_i}";
};

// for-from-to-step
for "_i" from 0 to 100 step 10 do {
    print f"Step: {_i}";       // 0, 10, 20, ..., 100
};

// Reverse (step negative)
for "_i" from 10 to 0 step -1 do {
    print f"Countdown: {_i}";
};

// Iterate array
for "_i" from 0 to (count _arr - 1) do {
    _elem = _arr select _i;
    process(_elem);
};

forEach

Iterate array elements. Magic variables inside the block:

  • _x — current element
  • _forEachIndex — zero-based index
  • _this[element, index, array] (SQF compat)
[1, 2, 3] forEach {
    print f"Element {_forEachIndex}: {_x}";
};

// Early exit with exitWith
_arr forEach {
    if (_x == "target") exitWith {
        print "Found!";
    };
};

switch / case

switch (_state) do {
    case "idle": {
        playIdle();
    };
    case "patrol": {
        startPatrol();
    };
    case "combat": {
        engage();
    };
    default {
        print "Unknown state";
    };
};

// Multiple cases
switch (_key) do {
    case "w";
    case "W": {
        moveForward();
    };
    case "s";
    case "S": {
        moveBackward();
    };
};

exitWith

Exits the current scope (loop or code block):

// Exit loop
while { true } do {
    _item = getNext();
    if (isNil "_item") exitWith {};
    process(_item);
};

// Exit forEach
_arr forEach {
    if (_x == target) exitWith {
        _found = _x;
    };
};

try / catch

Structured error handling:

try {
    if (_hp <= 0) then { throw "Unit is dead"; };
    doWork();
} catch {
    print f"Error: {_exception}";
};

// _exception contains the thrown value
// It is an SqError with: .message, .file, .line, .col

return

Returns a value from a function/code block:

_calc = {
    params ["_a", "_b"];
    if (_b == 0) exitWith { return 0; };  // early return
    _a / _b
};

_result = [10, 2] call _calc;  // 5

Important: canSuspend

sleep, await, and suspending commands only work in scheduled code (spawned fibers):

// Check if suspension is allowed:
if (canSuspend nil) then {
    sleep 1;    // OK — in spawned code
};

// call-executed code CANNOT suspend:
call {
    sleep 1;    // ERROR!
};
Context canSuspend sleep/await
spawn { ... } true
execVM "file.sqf" true
call { ... } from spawned true
call { ... } from unscheduled false
callUnscheduled { ... } false

See Also

SQ# Wiki

Home

Engine Docs

Migration

Commands

Value Constructors

Arithmetic

Comparison

Logic

Array

String

Math

Random

Type & Introspection

HashMap

Code Execution

Concurrency

Scheduler

Thread Safety

Error

Output

Time

Multiplayer

Compiler

Clone this wiki locally