Skip to content

AI — Object AI Script (.AI)

Each .AI file defines the AI behaviour for one object class using a custom goto-based scripting language — plain ASCII text, CRLF line endings, 9 files in FA_2.LIB. A companion compiled .BI file exists for each script of the same base name — see BI.md.

Tools

fx

fx ai compile   <file.AI> -o <file.BI>  # full parse + compile to BI bytecode DLL
fx bi decompile <file.BI>               # recover AI source from fx-compiled bytecode

fx ai compile is a complete parser/validator for the language documented below. fx bi decompile (BI.md) is its inverse: it reconstructs AI source whose recompilation is byte-identical to the input, closing the compile→decompile→recompile loop for every BI fx produces. Synthesized labels (L####) replace the original label names, and comments are not recovered.

File Layout

Plain text; no binary fields.

Execution Model

The engine calls each object's AI script once per tick. Execution starts at the top of the file and falls through the opening if dispatch chain. The first condition that matches jumps to the corresponding handler label. exit returns control to the engine; restart re-enters the script from the top on the next tick.

; top-level dispatch (evaluated every tick)
if do_nothing goto nothing
if do_ir_launch goto ir_launch
...
exit

nothing:
  exit

ir_launch:
  <instructions>
  restart

Syntax

Comments:

; anything after semicolon is a comment

Labels: any identifier followed by :. Labels are local to the file.

Variables: four general-purpose integer registers: %a, %b, %c, %d.

%a = <expr>          ; assign
%a = alt             ; read numeric attribute
%a = random 100      ; random 0–99
%a = h + 45          ; arithmetic on engine values
%a = turnRadius * 3
%a = 50 - random 20

Conditional branches — single-line: if <condition> goto <label>; block form:

.if <condition>
    <instructions>
.else              ; optional
    <instructions>
.endif

Conditions may be combined with &&, ||, and not. Trailing , is equivalent to && (observed in F.AI).

Control flow:

Statement Description
exit Return to engine; script resumes at top next tick
restart Re-enter script from top immediately
goto <label> Unconditional jump

Engine State Flags (do_*)

Set by the engine before each tick. All 9 files dispatch on at least do_nothing through do_attack.

Flag Meaning
do_nothing No action required
do_ir_launch Fire IR (heat-seeking) weapon
do_radar_launch Fire radar-guided weapon
do_hit Object has been hit
do_evade Evade incoming threat
do_attack Engage target

Conditions

Boolean attributes:

Attribute Description
tgt Has an active target
tgtAhead Target is within forward arc
tgtFacing Target is facing this object
tgtIsPlane Target is an aircraft (not ground unit)
tgtIsFighter Target is fighter class
tgtHumanControl Target is human-controlled
canClimb / canclimb Aircraft has energy to climb
betterSpeed Speed advantage over target
betterTwr Thrust-to-weight advantage over target
wingCombat Wingman is currently engaged
wingApproach Wingman is on approach

Numeric attributes (used in comparisons: <, >, <=, >=, ==):

Attribute Description
alt Current altitude (feet)
speed Current airspeed
distToTgt 3D distance to target
hrzDistToTgt Horizontal distance to target
altDiff / altdiff Altitude difference vs target
hdiff Heading difference vs target
pdiff Pitch difference vs target
tgtOffBeam Target off-beam angle (degrees)
speedDiff Speed difference vs target
turnRadius Current turn radius
minSpeed Minimum flyable speed
skill AI skill level (integer, 0 = lowest)
b Internal counter (used in loop constructs)
p Internal parameter

Arithmetic is valid in comparisons: alt < turnRadius * 3, distToTgt < minSpeed + 500.

Probability conditions:

Condition Description
chance <int> True if a global counter equals the value — used as a sparse timer
percent <int> True with probability N% (0–100)
random <int> Evaluates to a random value 0–(N−1); used in expressions like random 3 > 1

Instructions

Movement:

Instruction Signature Description
move move <hdg> <angle> <alt> <speed_mode> <duration> Fly to heading/altitude. <angle> = bank angle (0 = wings level, 180 = inverted); <alt> scaled ×0xb6 internally (0x7fffffff = altitude-unlimited); <speed_mode> = one of corner/max/etc.; <duration> = integer 0–15. Confirmed from _CTDo_move (0x465cc0) bytecode pop order: heading, angle, altitude, speed, duration.
moveToAlt moveToAlt <hdg> <alt> maxSpeed <value> Climb or descend to altitude
homePos homePos <hdg> <alt> <alt2> corner <value> Return to home position
homeAngle homeAngle <hdg> <alt> <speed_mode> <roll> <value> Fly to home angle
jink jink <hdg> <defl_angle> <defl1> <defl2> … <count> <speed_mode> <duration> Jinking evasive maneuver. <defl_angle> = base deflection; <defl1>/<defl2> = alternating left/right deflection magnitudes; <count> = jink repetitions 0–4; <speed_mode> = speed control (same domain as move speed — clamped to COMinSpeed..COMaxSpeed by FUN_00465e00); <duration> = integer 0–15. Confirmed from _CTDo_jink (0x4663f0) → _MVRJink@40 (0x4ac9e0): param_8=count, param_9=speed, param_10=duration, param_3/param_4=deflection angles.
circle circle <cx> <cy> <cz> <radius> <alt> <speed> Orbit a point (AC130 only)
wm_break wm_break <angle> engageP Break away from wingman
wm_approach wm_approach <offset> <engageP\|int> corner Wingman approach

move roll argument: any = no bank constraint (engine picks optimal); 0 = wings level (upright); 180 = inverted. Comments in F.AI confirm: move %a 0 180 corner 1 = "roll over on my back, staying horizontal"; move %a + 180 0 0 corner 0 = "roll out to level". The engageP keyword is a valid value for the <alt> argument (altitude of the engage/attack waypoint), not the roll argument.

Maneuvers:

Instruction Description
maneuver "<name>" Execute a named preset maneuver (displayed to player)
immelman corner Immelmann turn
invert Push-over / invert
yoyo <alt> corner <value> Yo-yo maneuver
btoh Barrel turn onto heading

Control:

Instruction Signature Description
switch switch random <N> <label1> … <labelN> Jump to one of N labels chosen uniformly at random

Named Maneuvers

Maneuver names are trilingual strings: "<English>;<German>;<French>". The UI displays the locale-appropriate segment.

Name
"BREAK LEFT;LINKS ABDREHEN;APPROCHE GAUCHE"
"BREAK RIGHT;RECHTS ABDREHEN;APPROCHE DROITE"
"CLIMB;STEIGEN;MONTEE"
"DIVE BOMB;STURZANGRIFF;BOMBARDER"
"DIVE;STURZFLUG;PIQUE"
"FAST-HIGH;SCHNELL-HOCH;APPROCHE DU HAUT"
"GND ATTACK;BODENANGRIFF;ATTAQUE AU SOL"
"LOOP;LOOPING;BOUCLE"
"OFFSET PASS;VORBEIFLUG SEITE;PASSE LATERALE"
"OVERHEAD PASS;VORBEIFLUG OBEN;PASSE HAUTE"
"OVERSHOOT;ÜBERSCHUSS;OVERSHOOT"
"POP-UP;POP-UP;ATTAQUE SURPRISE"
"PURSUIT;VERFOLGUNG;POURSUITE"
"REVERSE;ABSCHWUNG;180"
"SCISSORS;SCISSORS;CISEAUX"
"SEPARATE;LÖSEN;SEPARATION"
"SPLIT-S;SPLIT-S;IMMELMANN"
"STRAIGHT;GERADEAUS;TOUT DROIT"
"UNDERNEATH PASS;VORBEIFLUG UNTEN;AU-DESSOUS"
"VERT SCISSORS;VERTIKALSCHERE;CISEAUX VERTIC."

Engine-defined switch target labels (no maneuver string needed): fastHigh, popup, offsetPass, overheadPass, homeOnTgtRear, homeAboveBelow, straightClimb, homeOnTarget, straightDive, vertScissors, split_s, immelman, breakLeft, breakRight, h_jink, v_jink, turnAround.

File Inventory

File Size Object class
AC130.AI 3,728 B AC-130 Spectre gunship
B.AI 3,970 B Bomber
F.AI 20,616 B Fighter (primary; shared by most aircraft)
F117.AI 18,823 B F-117 stealth (based on F.AI)
H.AI 12,412 B Helicopter
HYDRO.AI 1,816 B Hydrofoil / fast patrol boat
LARGE.AI 960 B Large ship
LINER.AI 917 B Ocean liner
MOTH.AI 18,422 B Moth (variant of F.AI)

All 9 live in FA_2.LIB.

Engine Notes

The _CTDo_* and _CTEval_* condition/action dispatcher functions exist in the game executable itself at VA range 0x464C80–0x467110 — not only in the companion .BI DLL files. This means the interpreter core is compiled into the main executable; the .BI DLLs supply per-object script data but delegate dispatch back to the game executable's built-in handlers.

Formats: BI — compiled binary companion, one per .AI file; BRF — object type records (.OT, .NT, .PT) that reference AI files by name.