Files
CTI34-KPLIB-Ruha/AGENTS.md

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 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):

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 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):

// 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 __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:

_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, 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):

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:

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):

  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

[_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 literals0 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)

/*
    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 — 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

# 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