Skip to content

Arma 2 OA Agent Traps Reference

rayswaynl edited this page Jul 8, 2026 · 3 revisions

Arma 2 OA Agent Traps Reference

PR-cited and prompt-cited checklist of Arma 2 OA 1.64 traps that recently cost WASP agents review time. Use this before patching mission SQF, reviewing fleet PRs, or translating a code-review finding into a lane.

Refreshed 2026-07-03 from rayswaynl/a2waspwarfare PR metadata, the live wiki and the Game PC fleet prompt (C:\Users\Game\CODEX-FLEET-PROMPT.md, SHA256 76A3B3156CC9253E34CEEBB54F19A2C2DBF37BCFEAFDCD6B816028B45269632A). This page is a guardrail, not release status: re-check the exact target branch before editing source.

Fast Checklist

Trap Safe shape Burned in
Server-side code calling a client-to-server bridge that ends in publicVariableServer. From the server, that send path can be a no-op for the intended callback. When already on the server, call the server callback directly. For side supply, use the WFBE_SE_FNC_HandleSideSupplyChange shape instead of bouncing through a server-bound PV bridge. PR #370; compare the side-supply false-positive review on PR #288.
Arma 3 command reflexes in OA mission code: isEqualType, isEqualTo, params, pushBack, findIf, selectRandom command, apply, forceFollowRoad, array reveal, worldSize, getPosVisual, A3 string find / substring select, sort-by-CODE and b_inf-style marker types. Verify every command against the BI Arma 2 OA category. Prefer existing OA patterns: typeName, explicit private + select, set [count _array, value] / WFBE_CO_FNC_ArrayPush, forEach scans, BIS_fnc_selectRandom or floor(random count _array), per-entity reveal, visiblePosition, toArray / toString, and existing marker classes. Current Game PC fleet prompt hard rule; command version reference; compatibility audit.
Group receiver getVariable [name, default]. In A2 OA, unset variables on GROUP receivers can return nil instead of the default. For groups, call WFBE_CO_FNC_GroupGetBool or use one-arg _grp getVariable _name followed by isNil default substitution. The 2-arg default form is fine on objects and missionNamespace. Current Game PC fleet prompt; Group Bool getVariable A2-OA trap.
Boolean operands with == or !=. A2 OA rejects Boolean equality operands even when the comparison looks harmless. Use direct gates (if (_flag) then { ... }) or explicit if/else latches when comparing two Boolean states. Keep == / != for numeric, string, side or object identity comparisons after checking operand types. Current Game PC fleet prompt and PR validation rules.
Nested forEach loops reusing _x or _this. An inner loop can overwrite the value the outer loop still needs. Capture the outer value first, for example _veh = _x or _cTown = _x, then use the captured local inside the inner loop or spawned body. PR #34.
Default-off thresholds using 0 as a real threshold. A condition like counter >= threshold can fire immediately when the default is 0. Treat 0 as disabled. Gate with threshold > 0 before comparing counters or latching state. PR #374.
AT launcher detection through primaryWeapon or string isKindOf "Launcher". A2 infantry launchers live in secondaryWeapon, and weapon class strings are not vehicle classes. For broad "has launcher" checks, use non-empty secondaryWeapon _unit. For exact weapon metadata, inspect configFile >> "CfgWeapons" deliberately. PR #374.
Applying isKindOf to the wrong config family. String class checks walk CfgVehicles, so weapon or magazine classnames can silently fail. Match the command to the config family: vehicle object/class checks for CfgVehicles, explicit config reads for CfgWeapons/CfgMagazines. PR #374 and PR #69.
Introducing remembered or mod-derived classnames without proof. A classname that is not in the mission tree can compile but fail only when that branch runs in engine. New classnames must already appear somewhere in the target mission tree, or the PR must include explicit config proof for the target content set. Current Game PC fleet prompt hard rule; config-family review fallout in PR #374.
Case-only review findings. SQF identifiers and string == comparisons are case-insensitive, so spelling-only reports often turn into no-op patches. Prove a case-only issue in the actual context before patching. Do not generalize this to every string-backed storage surface; setVariable / getVariable keys still need exact-source verification. PR #153 and PR #288.
Two-click confirmation paths that clear MenuAction too early. ConfirmAction needs the selected action state to survive the first click so the second click can resolve it. Clear MenuAction only after the confirm/decline branch has consumed the selected action. Test both first-click prompt and second-click execution. PR #380; positive current use in PR #413.
Extending a shared setVariable-backed tuple by auditing only the readers. Growing wfbe_aicom_townorder from 3 to 4 elements passed a reader audit, but two other writers still emitted the old 3-element array and silently truncated the extension mid-flight (~T+210s), reverting the feature in play. Grep every setVariable site for the exact key before extending a shared tuple's element count, not just the getVariable / reader sites. Ship reader and writer changes for the new shape atomically. 2026-07-08, PR #910 adversarial-verify finding D2.
SQF branch-scoped locals feeding shared tail code. A dispatch-write block shared by a bootstrap and a non-bootstrap branch read _mounted / _teamAir, but only the non-bootstrap branch assigned them, so the shared tail threw an undefined-variable error on every match's opening dispatches. Guard reads of branch-scoped locals in shared tail code with isNil "_varname" (string form works across branches) or hoist the assignment above the branch split so every path defines the local before the shared block runs. PR #910 adversarial-verify finding D1.
Parameters.hpp default= values silently overriding SQF constants at mission start. Three features were live-OFF on the test box for this exact reason: SQF declared the constant as 1 (on), but the lobby param's default=0 wins for every match that never touches the params menu. When arming or auditing a feature flag, check the matching Parameters.hpp entry's default= value, not just the SQF constant declaration — the lobby default wins at mission start regardless of what the constant says. 2026-07-08 lobby params audit.

Review Notes

Public variables and side supply

Transport direction is not authority, and it is not always symmetric. If the producer is already server-local, do not route a state change through a helper whose final hop is publicVariableServer. The current server-side pattern for supply rewards is a direct callback into the side-supply handler, matching the review fix recorded on PR #370.

PR #288 is a separate lesson: its review found the advertised side-supply desync was not proved as a functional bug. Keep this distinction sharp in future reviews:

  • publicVariableServer from server-side producer code is a direction trap.
  • Case-only or formatting-only key differences are often false positives until proven on the exact branch.

Prompt hard-rule command sweep

The current fleet prompt treats A3-only command reflexes as auto-rejects because OA 1.64 will not run them. Before source work, scan the diff for the prompt list: isEqualType, isEqualTo, params, pushBack, findIf, selectRandom, apply, forceFollowRoad, array reveal, worldSize, getPosVisual, A3 string find / substring select, sort-by-CODE and b_inf-style marker types.

Use Arma 2 OA command versions for the local wiki quick check, then verify any uncertain command against Bohemia's Arma 2 OA scripting command category before opening a source PR. Keep these distinctions straight:

  • _arr call BIS_fnc_selectRandom is an OA-safe function call; selectRandom _arr is the A3 command form.
  • visiblePosition is the OA-safe replacement for the getPosVisual overlay trap recorded in the compatibility audit.
  • WFBE_CO_FNC_ArrayPush / set [count _array, value] is the OA append idiom; do not modernize it into pushBack.
  • toArray / toString plus a manual loop is the OA string fallback; do not paste A3 substring select or string find snippets into mission code.

Group receiver defaults

The group getVariable [name, default] trap is receiver-specific. Objects, side logics and missionNamespace can use the two-arg default form, but GROUP receivers need the helper or the one-arg getVariable + isNil shape. This matters most for AI commander and group-GC state because most groups never have every flag set.

Do not "simplify" existing WFBE_CO_FNC_GroupGetBool calls into inline two-arg group reads during review cleanup. That loses the exact A2/OA compatibility guard the helper exists to provide.

Boolean equality

Treat _flag == true, _flag != false and _a == _b where both operands are Boolean as A2/OA hazards. The safe forms are direct conditions for one flag and explicit latches when two Boolean states must be compared. Numeric thresholds, string keys, side values and object identity checks can still use == / !=; the point is operand type, not the glyph itself.

Loop locals

SQF loop magic variables are convenient but fragile in nested code. Before adding an inner forEach, capture any outer _x / _this value that will be needed later. This is especially important in spawned bodies, town scans, vehicle scans and capture scoring where the old value can be used several lines after the inner loop.

Thresholds and default-off flags

Fleet features default off. When a feature uses a numeric threshold, the default 0 should mean "disabled", not "fire at zero". The robust shape is:

if (_threshold > 0) then {
    if (_count >= _threshold) then {
        // latch or apply the feature.
    };
};

Weapons and config family checks

Do not ask CfgVehicles questions about CfgWeapons classnames. For an infantry unit object:

  • primaryWeapon _unit is the rifle slot.
  • secondaryWeapon _unit is the launcher slot.
  • A non-empty secondaryWeapon is the simple "has launcher" signal used by recent review fixes.
  • If the exact launcher class matters, read configFile >> "CfgWeapons" >> _weaponClass rather than using a vehicle-class predicate.

The related classname rule is simple: do not introduce classnames from memory. Either the class already appears in the target mission tree, or the PR body needs explicit config proof for the intended content set.

Confirmation state

WFBE_CL_FNC_ConfirmAction style interactions are stateful. The first click records or displays confirmation state; the second click resolves it. If the surrounding handler writes MenuAction = -1 before the second click path runs, the confirm helper has nothing left to match and the action becomes unreachable.

Shared-variable shape extensions

Extending a shared tuple's element count is a writer-audit problem, not a reader-audit problem. wfbe_aicom_townorder grew from 3 to 4 elements; the reader audit passed because every reader was updated to expect 4 elements, but two other setVariable writers for the same key were missed and kept emitting 3-element arrays. The extension silently reverted mid-match (~T+210s) once one of the stale writers ran after the reader change landed. Before extending any shared setVariable-backed tuple, grep every setVariable site for the exact key — not only getVariable call sites — and land the writer and reader changes together.

Branch-scoped locals in shared tail code

A dispatch-write block shared by a bootstrap branch and a non-bootstrap branch relied on _mounted and _teamAir, but only the non-bootstrap branch assigned those locals before falling into the shared tail. Every match's opening dispatches ran the bootstrap branch first and hit an undefined-variable error the moment the shared tail read the unassigned locals. When a then/else split feeds into shared tail code, either hoist the assignment above the split so both branches define the local, or guard the read with isNil "_varname" (the string form works regardless of which branch executed).

Lobby parameter defaults vs SQF constants

A SQF constant declaring a feature "on" does not mean the feature is on in a live match. Parameters.hpp default= values win at mission start for any player who does not touch the lobby params menu, and three features were confirmed live-OFF on the test box because their lobby param default was 0 while the matching SQF constant said 1. When arming, auditing, or reasoning about a feature flag, check the Parameters.hpp entry's default= alongside the SQF constant — checking the constant alone is not sufficient proof of the flag's live state.

Related Pages

Continue Reading

Previous: Arma 2 OA compatibility audit | Next: Arma 2 OA command versions

Main map: Home | Fast path: Quickstart | Agent pack: LLM agent entry pack

Sidebar

Clone this wiki locally