{"name":"waitUntil","operator":null,"title":"waitUntil","type":"command","url":"https://community.bistudio.com/wiki/waitUntil","revid":378959,"updated":"2026-09-03T14:52:35Z","groups":["Program Flow"],"status":"ok","replaced_by":[],"games":[{"game":"arma1","name":"Armed Assault","version":"1.00"},{"game":"arma2","name":"Arma 2","version":"1.00"},{"game":"arma2oa","name":"Arma 2: Operation Arrowhead","version":"1.50"},{"game":"tkoh","name":"Take On Helicopters","version":"1.00"},{"game":"arma3","name":"Arma 3","version":"0.50"}],"since":{"game":"arma1","name":"Armed Assault","version":"1.00"},"arma3_since":"0.50","branch":null,"locality":{"argument":null,"effect":null,"server_exec":false},"exec":null,"description":"Suspends execution of scheduled script until the given condition satisfied.\n- This command will loop and call the code inside `{}` **mostly every frame**, depends on complexity of the condition and the overall engine load, until the code returns true\n- If the very first execution of the code returns true the command will exit immediately, therefore it will not produce any \"Suspending not allowed in this context\" error when used inside non-scheduled script. For all other uses it must be executed in environment that allows suspension (canSuspend), such as spawned or execVMed code\n- Avoid doing `waitUntil { time > 20 };` and use `sleep 20;` instead!\n- If you can, add a sleep to the condition to save some cpu cycles `waitUntil { sleep 1; !alive player };`\n\n> [!NOTE]\n> **Arma 3:** Since Arma 3 v1.94, a *condition* returning anything other than true or false **will** result in an appropriate type error.","syntaxes":[{"syntax":"waitUntil condition","since":null,"effect":null,"exec":null,"params":[{"name":"condition","type":"Code","optional":false,"default":null,"description":"the expression that **must** return a Boolean, true to finish waiting or false to continue waiting","types":["Code"],"since":null,"text":"condition: Code - the expression that **must** return a Boolean, true to finish waiting or false to continue waiting"}],"returns":{"type":"Anything","types":["Anything"],"description":"the value the condition evaluates to when the wait is over (normally true)","text":"Anything - the value the condition evaluates to when the wait is over (normally true)"},"form":"unary","operator":null,"left":null,"right":{"text":"condition","types":["Code"]}},{"syntax":"waitUntil [condition, timeout, interval]","since":"arma3 2.22","effect":null,"exec":null,"params":[{"name":"condition","type":"Code","optional":false,"default":null,"description":"the expression that **must** return a Boolean, true to finish waiting or false to continue waiting","types":["Code"],"since":null,"text":"condition: Code - the expression that **must** return a Boolean, true to finish waiting or false to continue waiting"},{"name":"timeout","type":"Number","optional":false,"default":null,"description":"a timeout in seconds of game time (sleep vs uiSleep). The timeout is only checked after the condition was checked. **Any negative value disables the timeout**","types":["Number"],"since":null,"text":"timeout: Number - a timeout in seconds of game time (sleep vs uiSleep). The timeout is only checked after the condition was checked. **Any negative value disables the timeout**"},{"name":"interval","type":"Number","optional":true,"default":"0","description":"the time interval in seconds of game time between condition checks, this is equivalent to using a \"sleep\" after the condition.","types":["Number"],"since":null,"text":"interval: Number - (Optional, default 0) the time interval in seconds of game time between condition checks, this is equivalent to using a \"sleep\" after the condition."}],"returns":{"type":"Anything","types":["Anything"],"description":"the value the condition evaluates to when the wait is over (normally true), or Nothing if the timeout ended the wait","text":"Anything - the value the condition evaluates to when the wait is over (normally true), or Nothing if the timeout ended the wait"},"form":"unary","operator":null,"left":null,"right":{"text":"[condition, timeout, interval]","types":["Array"]}},{"syntax":"waitUntil scriptHandle","since":"arma3 2.22","effect":null,"exec":null,"params":[{"name":"scriptHandle","type":"Script Handle","optional":false,"default":null,"description":"a script handle or promise to wait on","types":["Script Handle"],"since":null,"text":"scriptHandle: Script Handle - a script handle or promise to wait on"}],"returns":{"type":"Anything","types":["Anything"],"description":"The result of the script or Promise","text":"Anything - The result of the script or Promise"},"form":"unary","operator":null,"left":null,"right":{"text":"scriptHandle","types":["Script Handle"]}},{"syntax":"waitUntil [scriptHandle, timeout]","since":"arma3 2.22","effect":null,"exec":null,"params":[{"name":"scriptHandle","type":"Script Handle","optional":false,"default":null,"description":"a script handle or promise to wait on","types":["Script Handle"],"since":null,"text":"scriptHandle: Script Handle - a script handle or promise to wait on"},{"name":"timeout","type":"Number","optional":false,"default":null,"description":"a timeout in seconds of game time (sleep vs uiSleep)","types":["Number"],"since":null,"text":"timeout: Number - a timeout in seconds of game time (sleep vs uiSleep)"}],"returns":{"type":"Anything","types":["Anything"],"description":"the result of the script or Promise. Or Nothing if timed out.","text":"Anything - the result of the script or Promise. Or Nothing if timed out."},"form":"unary","operator":null,"left":null,"right":{"text":"[scriptHandle, timeout]","types":["Array"]}}],"examples":[{"text":"```sqf\nwaitUntil { not alive player };\n```","code":["waitUntil { not alive player };"]},{"text":"```sqf\n_i = 0; waitUntil { _i = _i + 1; _i >= 100 };\n```","code":["_i = 0; waitUntil { _i = _i + 1; _i >= 100 };"]},{"text":"waitUntil can lead to performance loss if used improperly:\n\n```sqf\nwaitUntil { not alive player };            // bad\nwaitUntil { sleep 1; not alive player };    // good - checks every 1 second\nplayer addEventHandler [\"Killed\", {  }];    // best - don't forget about Event Handlers\n```","code":["waitUntil { not alive player };\t\t\t// bad\nwaitUntil { sleep 1; not alive player };\t// good - checks every 1 second\nplayer addEventHandler [\"Killed\", {  }];\t// best - don't forget about Event Handlers"]},{"text":"An on-the-fly custom event handler:\n\n```sqf\n_myEH = [\"ZoomIn\"] spawn {\n    while { true } do\n    {\n        waitUntil { inputAction (_this select 0) == 1 };\n        diag_log format [\"%1 @ %2\", _this select 0, diag_tickTime];\n    };\n};\n```\n\nAlthough it may be better to use onEachFrame (stacked) mission Event Handler, depending on the application.","code":["_myEH = [\"ZoomIn\"] spawn {\n\twhile { true } do\n\t{\n\t\twaitUntil { inputAction (_this select 0) == 1 };\n\t\tdiag_log format [\"%1 @ %2\", _this select 0, diag_tickTime];\n\t};\n};"]},{"text":"Use getVariable with default value to prevent unexcepted script errors:\n\n```sqf\nwaitUntil { bank getVariable [\"money\", 0] > 0 };\nwaitUntil { missionNamespace getVariable [\"isready\", false] };\n```","code":["waitUntil { bank getVariable [\"money\", 0] > 0 };\nwaitUntil { missionNamespace getVariable [\"isready\", false] };"]},{"text":"Always return Boolean:\n\n```sqf\nwaitUntil { sleep 1; if (not alive player) exitWith {}; _time = _time + 1 };                // bad\nwaitUntil { sleep 1; if (not alive player) exitWith { true }; _time = _time + 1; false };    // good\nwaitUntil { sleep 1; not alive player };                                                    // perfect\n```","code":["waitUntil { sleep 1; if (not alive player) exitWith {}; _time = _time + 1 };\t\t\t\t// bad\nwaitUntil { sleep 1; if (not alive player) exitWith { true }; _time = _time + 1; false };\t// good\nwaitUntil { sleep 1; not alive player };\t\t\t\t\t\t\t\t\t\t\t\t\t// perfect"]}],"multiplayer":null,"problems":"For some unknown reason if you have waitUntil loop active and game is **saved/loaded**, some variables in the expression may appear undefined for a short time. As a workaround, assign expression to a variable and make sure it is defined before waitUntil checks it:\n\n```sqf\nwaitUntil { private _expression = someBooleanVar && (someNumberVar > 10); !isNil \"_expression\" && { _expression } };\n```","aliases":[],"see_also":["sleep","uiSleep","canSuspend","spawn","execVM","while","Control Structures"],"notes":[{"user":"CrashDome","date":"2006-12-20T19:55:00Z","text":"waitUntil suspends both SQF functions and SQF scripts. In functions, the calling script is still in suspension due to waiting for a return from the call command. The game engine will continue, however. See Function for more detail."},{"user":"RoehrenRadio","date":"2010-04-02T17:10:00Z","text":"Prior to Arma 3 v1.94 if waitUntil uses an undefined call code, waitUntil won't release, even when this code is separated from other conditions through or. Be warned that this won't cause an error message."},{"user":"Commy2","date":"2014-12-13T23:25:00Z","text":"If you want to use waitUntil together with exitWith, remember that the loop only exits if the code block returns true.\n\nIt should look like this:\n\n```sqf\nwaitUntil {\n    // exit loop if the unit gets deleted\n    if (isNull _unit) exitWith { true }; // has to return true to continue\n\n    !alive _unit;\n};\n```"},{"user":"AgentRev","date":"2022-04-19T06:05:01Z","text":"It's a good idea to include a timeout with the condition if there's any possibility that it never becomes true:\n\n```sqf\ndisableUserInput true;\nplayer moveInDriver _vehicle; // this command is asynchronous and can fail sometimes\n_time = time;\nwaitUntil {vehicle player == _vehicle || time - _time > 3};\ndisableUserInput false;\n```"}],"categories":["ArmA: Armed Assault: New Scripting Commands","ArmA: Armed Assault: Scripting Commands","Arma 2: Operation Arrowhead: Scripting Commands","Arma 2: Scripting Commands","Arma 3: Scripting Commands","Command Group: Program Flow","Introduced with Armed Assault version 1.00","Scripting Commands","Take On Helicopters: Scripting Commands"]}