22 KiB
AGENTS.md — Arma 3 KP Liberation Mission Project Specification
1. Project Overview
Mission: CTI 34 KP Liberation v0.96.7a Ruha.ruha
Type: Arma 3 CTI (Capture the Island) multiplayer mission
Max Players: 34
Map: Ruha
Framework: KP Liberation v0.96.7a (fork of GreuhZbug → KillahPotatoes)
Repository: https://github.com/KillahPotatoes/KP-Liberation
This is a Ukraine-themed fork with custom BLUFOR preset using UA_Azov, b_afougf, FA_UAF, UF_ mod classnames.
File Inventory
| File Type | Count | Lines of Code |
|---|---|---|
.sqf |
~393 | ~47,570 |
.hpp |
~33 | ~6,827 |
.xml |
1 | 7,321 |
.sqm |
1 | 189 |
.fsm |
3 | — |
| Other | ~46 | — |
| Total | ~477 | ~62,000+ |
Top-level Directory Layout
/
├── mission.sqm — Binary editor file (Arma Eden)
├── description.ext — Mission config (configFile syntax)
├── CfgFunctions.hpp — Function registry
├── init.sqf — Entry point
├── kp_liberation_config.sqf — Main gameplay configuration
├── kp_objectInits.sqf — Object-specific triggers
├── onPlayerRespawn.sqf — Respawn handler
├── whitelist.sqf — Commander whitelist
├── stringtable.xml — Locale strings
├── pbo.json — PBO compression config
├── AGENTS.md — This file
├── scripts/ — Shared/client/server scripts
│ ├── shared/ — Runs on all machines
│ ├── client/ — Client-only (40+ files, 14 subdirs)
│ ├── server/ — Server-only (70+ files, 17 subdirs)
│ └── fob_templates/ — FOB building layouts
├── functions/ — Compiled KPLIB functions (84 files)
│ ├── curator/ — Zeus curator handlers
│ └── ui/ — Overlay UI
├── presets/ — Faction unit pricing
│ ├── init_presets.sqf — Preset loader
│ ├── blufor/ — 16 faction presets
│ ├── opfor/ — 16 faction presets
│ ├── resistance/ — 9 faction presets
│ └── civilians/ — 9 faction presets
├── arsenal_presets/ — Arsenal unlock definitions (16 files)
├── ui/ — HUD/dialog definitions (21 files)
├── KP/ — KP modules
│ ├── KPGUI/ — GUI framework (defines, classes)
│ └── KPPLM/ — Player menu (functions, UI)
├── GREUH/ — Legacy GREUH module
│ ├── Scripts/ — 10 legacy scripts
│ └── UI/ — Interface HPP
└── res/ — Assets (PAA, OGG, JPG)
2. SQF Language Specification
SQF (Status Quo Function) is Arma 3's primary scripting language — a C-like, preprocessed, operator-based language with no formal keyword grammar for control flow (control structures are operators that accept code blocks as arguments).
2.1 Grammar & Syntax Rules
Statements — every expression MUST end with ; (semicolon):
private _x = 5;
hint str _x;
Expressions — there are only three expression types:
- Nular — zero arguments, like a computed variable:
player,time,side player - Unary — one argument on the right:
!alive,hint "hello",west - Binary — two arguments:
a + b,str _x,a isEqualTo b
Operator precedence follows a strict table (highest 11 → lowest 1):
| Precedence | Operators |
|---|---|
| 11 | *, /, %, mod, atan2 |
| 10 | +, -, : (config) |
| 9 | select |
| 8 | ^ |
| 7 | ==, !=, <, >, <=, >=, isEqualTo, isNotEqualTo |
| 6 | !, not |
| 5 | &&, and |
| 4 | ` |
| 3 | > (binary), >= (binary), < (binary), <= (binary) |
| 2 | then, do, count, apply, findIf |
| 1 | else, exitWith |
Brackets:
()— override precedence or group expressions[]— define arrays{}— code blocks (Code data type)
Comments:
//single-line (preprocessor removes them)/* */multi-line blockcomment "text"runtime comment command (SQF level, not preprocessor)
2.2 Data Types
| Type | Examples | Notes |
|---|---|---|
| Scalar (Number) | 42, -3.14, 1e6 |
Double precision |
| Boolean | true, false |
|
| String | "hello" |
Double quotes only in SQF |
| Array | [1, "a", player] |
0-indexed, heterogeneous |
| Code | { hint "hi" } |
Block, assigned or passed |
| Object | player, cursorTarget |
In-game entity reference |
| Side | west, east, independent, civilian |
|
| Group | group player |
Unit group |
| Config | configFile >> "CfgVehicles" |
Config tree reference |
| Display | findDisplay 46 |
UI display |
| Control | _display displayCtrl 1000 |
UI control |
| Namespace | missionNamespace, uiNamespace |
Variable containers |
| Script | _handle = _x spawn _code |
Script handle |
| NaN | objNull, nil |
Special null values |
| HashMap | createHashMap |
Arma 3 v2.01+ |
2.3 Variables
Scope rules:
- Global: no prefix —
KP_liberation_version - Private (local):
_prefix —_myVar - Mission namespace:
missionNamespace setVariable ["varname", value]
Declaration via private keyword (MANDATORY to avoid upper-scope pollution):
private _myVar = 42;
private ["_a", "_b", "_c"]; // array form (legacy)
params ["_param1", "_param2"]; // auto-private via params
Naming conventions observed in this project:
| Pattern | Example | Scope |
|---|---|---|
KP_liberation_* |
KP_liberation_ace |
Global config |
GRLIB_* |
GRLIB_sector_size |
Legacy global |
KPLIB_* |
KPLIB_init |
Mission global |
_under_score |
_sector, _nearestFob |
Local variable |
_i, _x, _forEachIndex |
_i |
Loop iteration |
MACRO_NAME |
COLOR_GREEN |
#define constant (UPPER_SNAKE_CASE mandatory) |
2.4 Control Structures (Operator-based, no reserved keywords)
// if-then-else
if (_a > _b) then { hint "bigger" } else { hint "smaller" };
// while-do
while { _i < 10 } do { _i = _i + 1 };
// for-do (range)
for "_i" from 0 to 9 do { systemChat str _i };
// for-do (array iteration — forEach)
{ hint _x } forEach [1,2,3];
// switch-do
switch (_var) do {
case 1: { hint "one" };
case 2: { hint "two" };
default { hint "other" };
};
// exitWith (early return)
if (_condition) exitWith { _defaultValue };
// waitUntil
waitUntil { !isNil "KPLIB_init" };
2.5 Arrays
- 0-indexed, dynamic, heterogeneous
- Access:
_arr select 0or_arr #0 - Slicing:
_arr select [0, 3] - Range syntax:
_arr # [0, 3](Arma 3 v2.14+) - Common operators:
pushBack,append,apply,select,resize,deleteAt,arrayIntersect,in,findIf,count
Preset arrays (this project):
// Multi-dimensional with resource costs
infantry_units = [
["classname", supplies, ammunition, fuel],
["B_soldier_F", 20, 0, 0]
];
// Last element MUST NOT have a trailing comma
2.6 Functions
Compiled via CfgFunctions.hpp (preferred):
class KPLIB {
class functions {
file = "functions";
class log {};
class checkClass {};
class spawnVehicle {};
};
};
Usage: [_text, "TAG"] call KPLIB_fnc_log;
Compiled inline (this project's secondary pattern):
kill_manager = compileFinal preprocessFileLineNumbers "scripts\shared\kill_manager.sqf";
Usage: [] call kill_manager;
Function parameter conventions:
params [
["_text", "", [""] ], // Default: "", Type filter: String
["_tag", "INFO", [""] ], // Default: "INFO", Type filter: String
["_debug", false, [true] ] // Default: false, Type filter: Boolean
];
2.7 Preprocessor (# directives, C-like)
Case-sensitive in Arma 3.
#define — constant macro:
#define COLOR_GREEN { 0.2, 0.23, 0.18, 0.75 }
#define FACTION_BLUFOR(k) (k == 0)
Macro arguments — whole-word replacement by default. Use ## for word-part concatenation:
#define GET_PARAM(outVar, paramName, paramDefault) \
outVar = [paramName,paramDefault] call KPLIB_fnc_getSaveableParam; \
publicVariable #outVar;
#include — file inclusion:
#include "defines.hpp"
#include <file.txt> // brackets = quotes (equivalent)
__LINE__, __FILE__ — debug directives (added by preprocessFileLineNumbers)
#ifdef / #ifndef / #endif — conditional compilation
Critical pitfalls:
- No
__EXECor__EVALin SQF scripts (only in configs) - Macro body swallows spaces around non-space characters; tabs are NOT spaces
- Backslash
\for multi-line macros MUST be the last character on the line - Macros do NOT propagate across files (each file preprocessed independently)
loadFiledoes NOT preprocess;preprocessFileandpreprocessFileLineNumbersDO
2.8 File I/O & Script Execution
| Method | Preprocesses? | Returns | Use Case |
|---|---|---|---|
preprocessFileLineNumbers |
Yes | String (with #line info) |
Compiling functions |
preprocessFile |
Yes | String (no line info) | Loading config text |
loadFile |
No | String (raw) | Raw file content |
execVM |
Yes | Script handle | Fire-and-forget scripts |
compileFinal |
No* | Code | Lock compiled code |
call |
— | Any | Synchronous execution |
spawn |
— | Script handle | Async execution |
*compileFinal does NOT preprocess; pass it preprocessed string:
_code = compileFinal preprocessFileLineNumbers "file.sqf";
2.9 Networking / Remote Execution
// Execute on all clients
[_arg1, _arg2] remoteExec ["functionName", 0];
// Execute on server only
remoteExecCall ["fnc_name", 2];
// Execute on specific client (owner ID)
remoteExecCall ["fnc_name", _ownerID];
// JIP (Join In Progress) persistent
remoteExecCall ["fnc_name", 0, _jipObject];
This project's pattern: Server-to-client via remote_call_*.sqf compiled scripts, Client-to-server via remoteExecCall targeting server (ID 2).
3. Arma 3 Mission Editing Conventions
3.1 Mission File Types
| File | Purpose | Format |
|---|---|---|
mission.sqm |
Editor-placed entities, markers, triggers, waypoints | Binary/text hybrid |
description.ext |
Mission config (CfgDebriefing, CfgRespawnInventory, etc.) | Config class syntax |
CfgFunctions.hpp |
Function registry (included by description.ext) | SQF preprocessed |
init.sqf |
Entry point, runs on all machines | SQF |
stringtable.xml |
Multi-language localization | XML |
*.hpp |
Header/includes (macros, UI classes, function registries) | SQF preprocessed |
*.sqf |
Script files | SQF |
*.fsm |
Finite State Machine definitions | FSM format |
3.2 PBO Format
Two types:
- Mission PBO: Contains
mission.sqm, noconfig.cpp, no PBO prefix header. Lives inmpmissions/. - Addon PBO: Contains
config.cpp/config.bin, has PBO property header (prefix=...). Lives inaddons/.
PBO structure (binary):
[Header entries (21-byte records)] [Data blocks] [Optional SHA-1 signature]
Each header entry: null-terminated filename (ASCIIZ) + 4-byte MIME type + 4x ulong fields.
Building on Linux: Use armake2 pack for missions (no binarization), armake2 build for addons.
3.3 description.ext (Config syntax)
Uses config-class syntax (similar to C++ classes but preprocessed):
class CfgDebriefing {
class Victory {
title = "Mission Complete";
subtitle = "All sectors captured";
description = "The island has been liberated.";
picture = "bg_victory";
};
};
Key attributes set in this project's description.ext:
briefingName,overviewText,author— Mission metadatarespawn,respawnDelay,respawnOnStart— Respawn settingsclass CfgDebriefing {}— End-mission screensclass Header { gameType = CTI; ... }— MP lobby info
3.4 Init Order (Lifecycle)
description.extparsedmission.sqmloaded (all editor-placed objects, triggers, markers)init.sqfruns on all machines (if not usingenableDynamicSimulation)- JIP players run
init.sqfon join
KP Liberation init flow (init.sqf:22-64):
1. Set version, disable saving
2. KPLIB_fnc_initSectors()
3. #include "scripts/shared/defines.hpp"
4. Call fetch_params.sqf (mission params)
5. Call kp_liberation_config.sqf (hardcoded config)
6. Call init_presets.sqf (faction load)
7. Call kp_objectInits.sqf (triggers)
8. KPPLM or GREUH player menu init
9. Call init_shared.sqf (compile shared)
10. Call init_server.sqf (server only)
11. HC manager
12. Client init (if player)
13. Revive system init
3.5 Config Class Syntax (ext / cpp)
classkeyword MUST be lowercase- Properties use
=not: - Strings:
"double quotes" - Arrays:
{ element, element }in configs,[element, element]in SQF - Semicolons required after each property
- Inheritance:
class MyClass : BaseClass {}
3.6 mod.cpp vs description.ext
- mod.cpp — placed in
@modname/root, defines mod metadata in Steam Workshop - description.ext — placed in mission root, defines mission-specific settings
- config.cpp — placed in addons, defines
CfgPatches,CfgVehicles, etc.
4. KP Liberation Architecture
4.1 Namespace Conventions
| Prefix | Scope | Definition |
|---|---|---|
KPLIB_ |
Mission globals | CfgFunctions.hpp namespace (KPLIB_fnc_*) |
KP_liberation_ |
Configuration/state | kp_liberation_config.sqf |
GRLIB_ |
Legacy (original Liberation) | Config/system globals |
KPPLM_ |
Player menu module | KPPLM_functions.hpp |
KPGUI_ |
GUI framework | KPGUI_defines.hpp |
GREUH_ |
Legacy GREUH module | GREUH_config.sqf |
F_ |
Legacy function prefix (sparse) | Inline compiled scripts |
4.2 Init Flags
| Variable | Description |
|---|---|
KPLIB_init |
All init complete |
KPLIB_initServer |
Server init complete |
KPLIB_initPresets |
Presets loaded |
KP_serverParamsFetched |
Mission params received |
GRLIB_respawn_marker |
Respawn position set |
GRLIB_player_configured |
Player loadout configured |
4.3 Remote Call Architecture
Server → Client files (in scripts/client/remotecall/):
remote_call_battlegroup.sqfremote_call_endgame.sqfremote_call_fob.sqfremote_call_incoming.sqfremote_call_intel.sqfremote_call_prisonner.sqfremote_call_sector.sqf
Client → Server files (in scripts/server/remotecall/):
build_remote_call.sqfbuild_fob_remote_call.sqfcancel_build_remote_call.sqf- Plus logistics (add_logi*, del_logi*, save_logi*)
4.4 Subsystem Debug Flags
Set in kp_liberation_config.sqf, enable verbose logging:
KP_liberation_kill_debug = false;
KP_liberation_civrep_debug = false;
KP_liberation_asymmetric_debug = false;
KP_liberation_logging = false; // Master switch
4.5 CfgFunctions.hpp Structure
class KPLIB {
// Server-agnostic functions (in functions/)
class functions {
file = "functions";
class log {};
class checkClass {};
class getSaveData {};
class setSaveData {};
class getLoadout {};
class setLoadout {};
// ... 80 entries
};
// Zeus curator
class functions_curator {
file = "functions\curator";
class initCuratorHandlers {};
class requestZeus {};
};
// Overlay UI
class functions_ui {
file = "functions\ui";
class overlayUpdateResources {};
};
};
#include "scripts\client\CfgFunctions.hpp" // Client tutorials
#include "scripts\server\CfgFunctions.hpp" // Server sector, HC
#include "KP\KPPLM\KPPLM_functions.hpp" // Player menu
4.6 Preset System
Each preset file exports arrays indexed by build menu page (7 pages):
infantry_units— Page 1light_vehicles— Page 2heavy_vehicles— Page 3air_vehicles— Page 4sea_vehicles— Page 5buildings— Page 6support_vehicles— Page 7
Plus:
squads— AI squad compositionselite_vehicles— Military-base-unlockable vehicles
Array format: ["classname", supplies, ammo, fuel]
Arsenal presets define GRLIB_arsenal_weapons, GRLIB_arsenal_magazines, GRLIB_arsenal_items, GRLIB_arsenal_backpacks arrays of classname strings.
4.7 Logging System
[_message, _tag] call KPLIB_fnc_log;
// Output: [KPLIB] [TAG] message text (via diag_log)
Tags used: PARAM, PRESETS, MISSIONSTART, STATS, KILL, MOD, CIVREP, CIVINFO, ASYMMETRIC, SECTORSPAWN, SUPPORTMODULES, ERROR, BLACKLIST, INFO
5. Coding Standards & Conventions (for this project)
5.1 Syntax Rules
- Every statement MUST end with
;— no exceptions - No trailing commas in arrays — last element before
]must not have, - No
00number literals —0not00(SQF parses00as octal or breaks) - No double semicolons
;;— causes SQF parse errors - Strings require double quotes
"..."— single quotes are only for config paths - Round brackets
()are optional in control structure conditions but RECOMMENDED for readability and correct precedence
5.2 Naming
| Construct | Convention | Example |
|---|---|---|
| Global variables | Prefix_lowercase_camelCase |
KP_liberation_ace, GRLIB_unitcap |
| Private variables | _lowercase_camelCase |
_sectorPos, _nearestFob |
Constants (#define) |
UPPER_SNAKE_CASE |
COLOR_GREEN, GUI_GRID_W |
| KPLIB functions | KPLIB_fnc_descriptiveName |
KPLIB_fnc_log |
| Script files | descriptive_name.sqf |
kill_manager.sqf, do_build.sqf |
| Function files | fn_descriptiveName.sqf |
fn_log.sqf, fn_checkClass.sqf |
| UI HPP files | liberation_name.hpp |
liberation_build.hpp |
| Preset files | faction_variant.sqf |
rhs_usaf_wdl.sqf |
5.3 File Prologue (all functions/ files)
/*
File: fn_functionName.sqf
Author: KP Liberation Dev Team - https://github.com/KillahPotatoes
Date: 2020-04-16
Last Update: 2020-04-20
License: MIT License - http://www.opensource.org/licenses/MIT
Description:
Brief one-paragraph description.
*/
5.4 Indentation
- 4 spaces per indent level
- Align array elements vertically for readability:
blufor_squad_inf_light = [
["B_soldier_F", 20, 0, 0],
["B_soldier_AR_F",25, 0, 0]
];
5.5 What To Avoid
- Do NOT add
0 =prefix to command calls (unnecessary since Arma 3 v2.04) - Do NOT use
_this select N— useparamsinstead - Do NOT use SQS (deprecated); use SQF exclusively
- Do NOT use
goto/labels — use structured control flow - Do NOT put code in unit init boxes in mission.sqm (runs client-side per connection)
- Do NOT modify GREUH/ files unless explicitly asked (legacy, separate maintainer)
- Do NOT use
exec(SQS); useexecVMorcall/spawn - Do NOT introduce semicolons after closing braces
};unless followed by another statement on the same line
5.6 Best Practices
paramswith type filtering for ALL function parametersprivatefor ALL local variables to prevent scope pollutioncompileFinal preprocessFileLineNumbersfor reusable compiled code- Debug flags for subsystem verbosity (not commented-out code)
- Use
arrayIntersectfor deduplication,applyfor transformations - Use
remoteExecCalloverremoteExecwhen return value is not needed (faster) - Always include JIP object parameter for persistent remoteExec
5.7 Common Pitfalls & Error Patterns
| Mistake | Symptom | Fix |
|---|---|---|
00 numeric literal |
Parse error or octal value | Use 0 instead |
;; double semicolon |
Parse error | Remove extra ; |
| Trailing comma in array | Parse error | Remove last , |
| Mismatched brackets | Silent runtime failure | Count ( vs ) and [ vs ] |
| Non-private variable shadows global | Unexpected behavior | Add private keyword |
Missing ; |
Parse error cascades | Add semicolon |
| Unquoted string macro arg with comma | Macro breaks | Wrap in "" or use ## |
#include path starting with \ |
File not found | Use relative path without leading \ |
Using localize inside #define |
Hardcoded language | Use $STR_XXX reference instead |
| Wrong bracket type in config | Class parse error | Configs use {} not [] for arrays |
Semicolon after } of control struct |
Usually valid, but redundant/wrong when followed by else |
Remove ; before else |
6. PBO Build & Deployment
6.1 Local Build
# Pack mission folder (no binarization)
armake2 pack "CTI 34 KP Liberation v0.96.7a Ruha.ruha" "CTI_34_KP_Liberation_v0.96.7a_Ruha.ruha.pbo"
# Verify
armake2 inspect "CTI_34_KP_Liberation_v0.96.7a_Ruha.ruha.pbo"
6.2 CI/CD (Gitea Actions)
Workflow file: .gitea/workflows/build.yml
- Trigger: push to main/master, tags
v*, manual - Uses
arwynfr/armake2:debianDocker image - Produces artifact:
CTI_34_KP_Liberation_v0.96.7a_Ruha.ruha.pbo - Includes disabled
deployjob template for SCP-to-server
7. References
- SQF Syntax: https://community.bistudio.com/wiki/SQF_Syntax
- Control Structures: https://community.bistudio.com/wiki/Control_Structures
- PreProcessor Commands: https://community.bistudio.com/wiki/PreProcessor_Commands
- Code Best Practices: https://community.bistudio.com/wiki/Code_Best_Practices
- Description.ext: https://community.bohemia.net/wiki/Description.ext
- PBO File Format: https://community.bistudio.com/wiki/PBO_File_Format
- KP Liberation: https://github.com/KillahPotatoes/KP-Liberation
- armake2: https://github.com/KoffeinFlummi/armake2
- Code Optimisation: https://community.bistudio.com/wiki/Code_Optimisation
- Multiplayer Scripting: https://community.bistudio.com/wiki/Multiplayer_Scripting