# 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):
```sqf
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 | `||`, `or` |
| 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 block
- `comment "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):**
```sqf
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)

```sqf
// 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 0` or `_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):**
```sqf
// 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):**
```hpp
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):**
```sqf
kill_manager = compileFinal preprocessFileLineNumbers "scripts\shared\kill_manager.sqf";
```
Usage: `[] call kill_manager;`

**Function parameter conventions:**
```sqf
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:**
```sqf
#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:
```sqf
#define GET_PARAM(outVar, paramName, paramDefault) \
    outVar = [paramName,paramDefault] call KPLIB_fnc_getSaveableParam; \
    publicVariable #outVar;
```

**`#include` — file inclusion:**
```sqf
#include "defines.hpp"
#include <file.txt>     // brackets = quotes (equivalent)
```

**`__LINE__`, `__FILE__`** — debug directives (added by `preprocessFileLineNumbers`)

**`#ifdef` / `#ifndef` / `#endif`** — conditional compilation

**Critical pitfalls:**
- No `__EXEC` or `__EVAL` in 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)
- `loadFile` does NOT preprocess; `preprocessFile` and `preprocessFileLineNumbers` DO

### 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:
```sqf
_code = compileFinal preprocessFileLineNumbers "file.sqf";
```

### 2.9 Networking / Remote Execution

```sqf
// 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`, no `config.cpp`, no PBO prefix header. Lives in `mpmissions/`.
- **Addon PBO:** Contains `config.cpp`/`config.bin`, has PBO property header (`prefix=...`). Lives in `addons/`.

**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):
```sqf
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 metadata
- `respawn`, `respawnDelay`, `respawnOnStart` — Respawn settings
- `class CfgDebriefing {}` — End-mission screens
- `class Header { gameType = CTI; ... }` — MP lobby info

### 3.4 Init Order (Lifecycle)

1. `description.ext` parsed
2. `mission.sqm` loaded (all editor-placed objects, triggers, markers)
3. `init.sqf` runs on all machines (if not using `enableDynamicSimulation`)
4. JIP players run `init.sqf` on 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)

- `class` keyword 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.sqf`
- `remote_call_endgame.sqf`
- `remote_call_fob.sqf`
- `remote_call_incoming.sqf`
- `remote_call_intel.sqf`
- `remote_call_prisonner.sqf`
- `remote_call_sector.sqf`

**Client → Server files** (in `scripts/server/remotecall/`):
- `build_remote_call.sqf`
- `build_fob_remote_call.sqf`
- `cancel_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:
```sqf
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

```hpp
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):
1. `infantry_units` — Page 1
2. `light_vehicles` — Page 2
3. `heavy_vehicles` — Page 3
4. `air_vehicles` — Page 4
5. `sea_vehicles` — Page 5
6. `buildings` — Page 6
7. `support_vehicles` — Page 7

Plus:
- `squads` — AI squad compositions
- `elite_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

```sqf
[_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 `00` number literals** — `0` not `00` (SQF parses `00` as 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)

```sqf
/*
    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:
```sqf
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`** — use `params` instead
- **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); use `execVM` or `call`/`spawn`
- **Do NOT introduce semicolons after closing braces** `};` unless followed by another statement on the same line

### 5.6 Best Practices

- `params` with type filtering for ALL function parameters
- `private` for ALL local variables to prevent scope pollution
- `compileFinal preprocessFileLineNumbers` for reusable compiled code
- Debug flags for subsystem verbosity (not commented-out code)
- Use `arrayIntersect` for deduplication, `apply` for transformations
- Use `remoteExecCall` over `remoteExec` when 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
```bash
# 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:debian` Docker image
- Produces artifact: `CTI_34_KP_Liberation_v0.96.7a_Ruha.ruha.pbo`
- Includes disabled `deploy` job 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
