/* Header: script_macros_common.hpp Description: A general set of useful macro functions for use by CBA itself or by any module that uses CBA. Authors: Sickboy and Spooner */ /* **************************************************** New - Should be exported to general addon Aim: - Simplify (shorten) the amount of characters required for repetitive tasks - Provide a solid structure that can be dynamic and easy editable (Which sometimes means we cannot adhere to Aim #1 ;-) An example is the path that is built from defines. Some available in this file, others in mods and addons. Follows Standard: Object variables: PREFIX_COMPONENT Main-object variables: PREFIX_main Paths: MAINPREFIX\PREFIX\SUBPREFIX\COMPONENT\SCRIPTNAME.sqf e.g: x\six\addons\sys_menu\fDate.sqf Usage: define PREFIX and COMPONENT, then include this file (Note, you could have a main addon for your mod, define the PREFIX in a macros.hpp, and include this script_macros_common.hpp file. Then in your addons, add a component.hpp, define the COMPONENT, and include your mod's script_macros.hpp In your scripts you can then include the addon's component.hpp with relative path) TODO: - Try only to use 1 string type " vs ' - Evaluate double functions, and simplification - Evaluate naming scheme; current = prototype - Evaluate "Debug" features.. - Evaluate "create mini function per precompiled script, that will load the script on first usage, rather than on init" - Also saw "Namespace" typeName, evaluate which we need :P - Single/Multi player gamelogics? (Incase of MP, you would want only 1 gamelogic per component, which is pv'ed from server, etc) */ #ifndef MAINPREFIX #define MAINPREFIX x #endif #ifndef SUBPREFIX #define SUBPREFIX addons #endif #ifndef MAINLOGIC #define MAINLOGIC main #endif #ifndef VERSION #define VERSION 0 #endif #ifndef VERSION_AR #define VERSION_AR VERSION #endif #ifndef VERSION_CONFIG #define VERSION_CONFIG version = VERSION; versionStr = QUOTE(VERSION); versionAr[] = {VERSION_AR} #endif #define ADDON DOUBLES(PREFIX,COMPONENT) #define MAIN_ADDON DOUBLES(PREFIX,main) /* ------------------------------------------- Group: Debugging ------------------------------------------- */ /* ------------------------------------------- Macros: DEBUG_MODE_x Managing debugging based on debug level. According to the *highest* level of debugging that has been defined *before* script_macros_common.hpp is included, only the appropriate debugging commands will be functional. With no level explicitely defined, assume DEBUG_MODE_NORMAL. DEBUG_MODE_FULL - Full debugging output. DEBUG_MODE_NORMAL - All debugging except and (Default setting if none specified). DEBUG_MODE_MINIMAL - Only and enabled. Examples: In order to turn on full debugging for a single file, (begin example) // Top of individual script file. #define DEBUG_MODE_FULL #include "script_component.hpp" (end) In order to force minimal debugging for a single component, (begin example) // Top of addons\\script_component.hpp // Ensure that any FULL and NORMAL setting from the individual files are undefined and MINIMAL is set. #ifdef DEBUG_MODE_FULL #undef DEBUG_MODE_FULL #endif #ifdef DEBUG_MODE_NORMAL #undef DEBUG_MODE_NORMAL #endif #ifndef DEBUG_MODE_MINIMAL #define DEBUG_MODE_MINIMAL #endif #include "script_macros.hpp" (end) In order to turn on full debugging for a whole addon, (begin example) // Top of addons\main\script_macros.hpp #ifndef DEBUG_MODE_FULL #define DEBUG_MODE_FULL #endif #include "\x\cba\addons\main\script_macros_common.hpp" (end) Author: Spooner ------------------------------------------- */ // If DEBUG_MODE_FULL, then also enable DEBUG_MODE_NORMAL. #ifdef DEBUG_MODE_FULL #define DEBUG_MODE_NORMAL #endif // If DEBUG_MODE_NORMAL, then also enable DEBUG_MODE_MINIMAL. #ifdef DEBUG_MODE_NORMAL #define DEBUG_MODE_MINIMAL #endif // If no debug modes specified, use DEBUG_MODE_NORMAL (+ DEBUG_MODE_MINIMAL). #ifndef DEBUG_MODE_MINIMAL #define DEBUG_MODE_NORMAL #define DEBUG_MODE_MINIMAL #endif #ifdef THIS_FILE #define THIS_FILE_ 'THIS_FILE' #else #define THIS_FILE_ __FILE__ #endif /* ------------------------------------------- Macro: LOG() Log a timestamped message into the RPT log. Only run if or higher is defined. Parameters: MESSAGE - Message to record [String] Example: (begin example) LOG("Initiated clog-dancing simulator."); (end) Author: Spooner ------------------------------------------- */ #ifdef DEBUG_MODE_FULL #define LOG(MESSAGE) [THIS_FILE_, __LINE__, MESSAGE] call CBA_fnc_log #else #define LOG(MESSAGE) /* disabled */ #endif /* ------------------------------------------- Macro: WARNING() Record a timestamped, non-critical error in the RPT log. Only run if or higher is defined. Parameters: MESSAGE - Message to record [String] Example: (begin example) WARNING("This function has been deprecated. Please don't use it in future!"); (end) Author: Spooner ------------------------------------------- */ #ifdef DEBUG_MODE_NORMAL #define WARNING(MESSAGE) [THIS_FILE_, __LINE__, ('WARNING: ' + MESSAGE)] call CBA_fnc_log #else #define WARNING(MESSAGE) /* disabled */ #endif /* ------------------------------------------- Macro: ERROR() Record a timestamped, critical error in the RPT log. The heading is "ERROR" (use for a specific title). TODO: Popup an error dialog & throw an exception. Parameters: MESSAGE - Message to record [String] Example: (begin example) ERROR("Value not found","value of frog not found in config ...yada...yada..."); (end) Author: Spooner ------------------------------------------- */ #define ERROR(MESSAGE) \ [THIS_FILE_, __LINE__, "ERROR", MESSAGE] call CBA_fnc_error; /* ------------------------------------------- Macro: ERROR_WITH_TITLE() Record a timestamped, critical error in the RPT log. The title can be specified (in the heading is always just "ERROR") Newlines (\n) in the MESSAGE will be put on separate lines. TODO: Popup an error dialog & throw an exception. Parameters: TITLE - Title of error message [String] MESSAGE - Body of error message [String] Example: (begin example) ERROR_WITH_TITLE("Value not found","Value of frog not found in config ...yada...yada..."); (end) Author: Spooner ------------------------------------------- */ #define ERROR_WITH_TITLE(TITLE,MESSAGE) \ [THIS_FILE_, __LINE__, TITLE, MESSAGE] call CBA_fnc_error; /* ------------------------------------------- Macro: MESSAGE_WITH_TITLE() Record a single line, timestamped log entry in the RPT log. Parameters: TITLE - Title of log message [String] MESSAGE - Body of message [String] Example: (begin example) MESSAGE_WITH_TITLE("Value found","Value of frog found in config "); (end) Author: Killswitch ------------------------------------------- */ #define MESSAGE_WITH_TITLE(TITLE,MESSAGE) \ [THIS_FILE_, __LINE__, TITLE + ': ' + (MESSAGE)] call CBA_fnc_log; /* ------------------------------------------- Macro: RETNIL() If a variable is undefined, return the value nil. Otherwise, return the variable itself. Parameters: VARIABLE - the variable to check Example: (begin example) // _var is undefined hintSilent format ["_var=%1", RETNIL(_var) ]; // "_var=any" (end example) Author: Alef (see CBA issue #8514) ------------------------------------------- */ #define RETNIL(VARIABLE) if (isNil{VARIABLE}) then {nil} else {VARIABLE} /* ------------------------------------------- Macros: TRACE_n() Log a message and 1-8 variables to the RPT log. Only run if is defined. TRACE_1(MESSAGE,A) - Log 1 variable. TRACE_2(MESSAGE,A,B) - Log 2 variables. TRACE_3(MESSAGE,A,B,C) - Log 3 variables. TRACE_4(MESSAGE,A,B,C,D) - Log 4 variables. TRACE_5(MESSAGE,A,B,C,D,E) - Log 5 variables. TRACE_6(MESSAGE,A,B,C,D,E,F) - Log 6 variables. TRACE_7(MESSAGE,A,B,C,D,E,F,G) - Log 7 variables. TRACE_8(MESSAGE,A,B,C,D,E,F,G,H) - Log 8 variables. TRACE_9(MESSAGE,A,B,C,D,E,F,G,H,I) - Log 9 variables. Parameters: MESSAGE - Message to add to the trace [String] A..H - Variable names to log values of [Any] Example: (begin example) TRACE_3("After takeoff",_vehicle player,getPos (_vehicle player), getPosASL (_vehicle player)); (end) Author: Spooner ------------------------------------------- */ #define PFORMAT_1(MESSAGE,A) \ format ['%1: A=%2', MESSAGE, RETNIL(A)] #define PFORMAT_2(MESSAGE,A,B) \ format ['%1: A=%2, B=%3', MESSAGE, RETNIL(A), RETNIL(B)] #define PFORMAT_3(MESSAGE,A,B,C) \ format ['%1: A=%2, B=%3, C=%4', MESSAGE, RETNIL(A), RETNIL(B), RETNIL(C)] #define PFORMAT_4(MESSAGE,A,B,C,D) \ format ['%1: A=%2, B=%3, C=%4, D=%5', MESSAGE, RETNIL(A), RETNIL(B), RETNIL(C), RETNIL(D)] #define PFORMAT_5(MESSAGE,A,B,C,D,E) \ format ['%1: A=%2, B=%3, C=%4, D=%5, E=%6', MESSAGE, RETNIL(A), RETNIL(B), RETNIL(C), RETNIL(D), RETNIL(E)] #define PFORMAT_6(MESSAGE,A,B,C,D,E,F) \ format ['%1: A=%2, B=%3, C=%4, D=%5, E=%6, F=%7', MESSAGE, RETNIL(A), RETNIL(B), RETNIL(C), RETNIL(D), RETNIL(E), RETNIL(F)] #define PFORMAT_7(MESSAGE,A,B,C,D,E,F,G) \ format ['%1: A=%2, B=%3, C=%4, D=%5, E=%6, F=%7, G=%8', MESSAGE, RETNIL(A), RETNIL(B), RETNIL(C), RETNIL(D), RETNIL(E), RETNIL(F), RETNIL(G)] #define PFORMAT_8(MESSAGE,A,B,C,D,E,F,G,H) \ format ['%1: A=%2, B=%3, C=%4, D=%5, E=%6, F=%7, G=%8, H=%9', MESSAGE, RETNIL(A), RETNIL(B), RETNIL(C), RETNIL(D), RETNIL(E), RETNIL(F), RETNIL(G), RETNIL(H)] #define PFORMAT_9(MESSAGE,A,B,C,D,E,F,G,H,I) \ format ['%1: A=%2, B=%3, C=%4, D=%5, E=%6, F=%7, G=%8, H=%9, I=%10', MESSAGE, RETNIL(A), RETNIL(B), RETNIL(C), RETNIL(D), RETNIL(E), RETNIL(F), RETNIL(G), RETNIL(H), RETNIL(I)] #ifdef DEBUG_MODE_FULL #define TRACE_1(MESSAGE,A) \ [THIS_FILE_, __LINE__, PFORMAT_1(MESSAGE,A)] call CBA_fnc_log #define TRACE_2(MESSAGE,A,B) \ [THIS_FILE_, __LINE__, PFORMAT_2(MESSAGE,A,B)] call CBA_fnc_log #define TRACE_3(MESSAGE,A,B,C) \ [THIS_FILE_, __LINE__, PFORMAT_3(MESSAGE,A,B,C)] call CBA_fnc_log #define TRACE_4(MESSAGE,A,B,C,D) \ [THIS_FILE_, __LINE__, PFORMAT_4(MESSAGE,A,B,C,D)] call CBA_fnc_log #define TRACE_5(MESSAGE,A,B,C,D,E) \ [THIS_FILE_, __LINE__, PFORMAT_5(MESSAGE,A,B,C,D,E)] call CBA_fnc_log #define TRACE_6(MESSAGE,A,B,C,D,E,F) \ [THIS_FILE_, __LINE__, PFORMAT_6(MESSAGE,A,B,C,D,E,F)] call CBA_fnc_log #define TRACE_7(MESSAGE,A,B,C,D,E,F,G) \ [THIS_FILE_, __LINE__, PFORMAT_7(MESSAGE,A,B,C,D,E,F,G)] call CBA_fnc_log #define TRACE_8(MESSAGE,A,B,C,D,E,F,G,H) \ [THIS_FILE_, __LINE__, PFORMAT_8(MESSAGE,A,B,C,D,E,F,G,H)] call CBA_fnc_log #define TRACE_9(MESSAGE,A,B,C,D,E,F,G,H,I) \ [THIS_FILE_, __LINE__, PFORMAT_9(MESSAGE,A,B,C,D,E,F,G,H,I)] call CBA_fnc_log #else #define TRACE_1(MESSAGE,A) /* disabled */ #define TRACE_2(MESSAGE,A,B) /* disabled */ #define TRACE_3(MESSAGE,A,B,C) /* disabled */ #define TRACE_4(MESSAGE,A,B,C,D) /* disabled */ #define TRACE_5(MESSAGE,A,B,C,D,E) /* disabled */ #define TRACE_6(MESSAGE,A,B,C,D,E,F) /* disabled */ #define TRACE_7(MESSAGE,A,B,C,D,E,F,G) /* disabled */ #define TRACE_8(MESSAGE,A,B,C,D,E,F,G,H) /* disabled */ #define TRACE_9(MESSAGE,A,B,C,D,E,F,G,H,I) /* disabled */ #endif /* ------------------------------------------- Group: General ------------------------------------------- */ // ************************************* // Internal Functions #define DOUBLES(var1,var2) ##var1##_##var2 #define TRIPLES(var1,var2,var3) ##var1##_##var2##_##var3 #define QUOTE(var1) #var1 #ifdef MODULAR #define COMPONENT_T DOUBLES(t,COMPONENT) #define COMPONENT_M DOUBLES(m,COMPONENT) #define COMPONENT_S DOUBLES(s,COMPONENT) #define COMPONENT_C DOUBLES(c,COMPONENT) #define COMPONENT_F COMPONENT_C #else #define COMPONENT_T COMPONENT #define COMPONENT_M COMPONENT #define COMPONENT_S COMPONENT #define COMPONENT_F COMPONENT #define COMPONENT_C COMPONENT #endif /* ------------------------------------------- Macro: INC() Description: Increase a number by one. Parameters: VAR - Variable to increment [Number] Example: (begin example) _counter = 0; INC(_counter); // _counter => 1 (end) Author: Spooner ------------------------------------------- */ #define INC(var) var = (var) + 1 /* ------------------------------------------- Macro: DEC() Description: Decrease a number by one. Parameters: VAR - Variable to decrement [Number] Example: (begin example) _counter = 99; DEC(_counter); // _counter => 98 (end) Author: Spooner ------------------------------------------- */ #define DEC(var) var = (var) - 1 /* ------------------------------------------- Macro: ADD() Description: Add a value to a variable. Variable and value should be both Numbers or both Strings. Parameters: VAR - Variable to add to [Number or String] VALUE - Value to add [Number or String] Examples: (begin example) _counter = 2; ADD(_counter,3); // _counter => 5 (end) (begin example) _str = "hello"; ADD(_str," "); ADD(_str,"Fred"); // _str => "hello Fred" (end) Author: Sickboy ------------------------------------------- */ #define ADD(var1,var2) var1 = (var1) + (var2) /* ------------------------------------------- Macro: SUB() Description: Subtract a value from a number variable. VAR and VALUE should both be Numbers. Parameters: VAR - Variable to subtract from [Number] VALUE - Value to subtract [Number] Examples: (begin example) _numChickens = 2; SUB(_numChickens,3); // _numChickens => -1 (end) ------------------------------------------- */ #define SUB(var1,var2) var1 = (var1) - (var2) /* ------------------------------------------- Macro: REM() Description: Remove an element from an array each time it occurs. This recreates the entire array, so use BIS_fnc_removeIndex if modification of the original array is required or if only one of the elements that matches ELEMENT needs to be removed. Parameters: ARRAY - Array to modify [Array] ELEMENT - Element to remove [Any] Examples: (begin example) _array = [1, 2, 3, 4, 3, 8]; REM(_array,3); // _array = [1, 2, 4, 8]; (end) Author: Spooner ------------------------------------------- */ #define REM(var1,var2) SUB(var1,[var2]) /* ------------------------------------------- Macro: PUSH() Description: Appends a single value onto the end of an ARRAY. Change is made to the ARRAY itself, not creating a new array. Parameters: ARRAY - Array to push element onto [Array] ELEMENT - Element to push [Any] Examples: (begin example) _fish = ["blue", "green", "smelly"]; PUSH(_fish,"monkey-flavoured"); // _fish => ["blue", "green", "smelly", "monkey-flavoured"] (end) Author: Spooner ------------------------------------------- */ #define PUSH(var1,var2) (var1) pushBack (var2) /* ------------------------------------------- Macro: ISNILS() Description: Sets a variable with a value, but only if it is undefined. Parameters: VARIABLE - Variable to set [Any, not nil] DEFAULT_VALUE - Value to set VARIABLE to if it is undefined [Any, not nil] Examples: (begin example) // _fish is undefined ISNILS(_fish,0); // _fish => 0 (end) (begin example) _fish = 12; // ...later... ISNILS(_fish,0); // _fish => 12 (end) Author: Sickboy ------------------------------------------- */ #define ISNILS(VARIABLE,DEFAULT_VALUE) if (isNil #VARIABLE) then { ##VARIABLE = ##DEFAULT_VALUE } #define ISNILS2(var1,var2,var3,var4) ISNILS(TRIPLES(var1,var2,var3),var4) #define ISNILS3(var1,var2,var3) ISNILS(DOUBLES(var1,var2),var3) #define ISNIL(var1,var2) ISNILS2(PREFIX,COMPONENT,var1,var2) #define ISNILMAIN(var1,var2) ISNILS3(PREFIX,var1,var2) #define CREATELOGICS(var1,var2) ##var1##_##var2## = ([sideLogic] call CBA_fnc_getSharedGroup) createUnit ["LOGIC", [0, 0, 0], [], 0, "NONE"] #define CREATELOGICLOCALS(var1,var2) ##var1##_##var2## = "LOGIC" createVehicleLocal [0, 0, 0] #define CREATELOGICGLOBALS(var1,var2) ##var1##_##var2## = ([sideLogic] call CBA_fnc_getSharedGroup) createUnit ["LOGIC", [0, 0, 0], [], 0, "NONE"]; publicVariable QUOTE(DOUBLES(var1,var2)) #define CREATELOGICGLOBALTESTS(var1,var2) ##var1##_##var2## = ([sideLogic] call CBA_fnc_getSharedGroup) createUnit [QUOTE(DOUBLES(ADDON,logic)), [0, 0, 0], [], 0, "NONE"] #define GETVARS(var1,var2,var3) (##var1##_##var2 getVariable #var3) #define GETVARMAINS(var1,var2) GETVARS(var1,MAINLOGIC,var2) #ifndef PATHTO_SYS #define PATHTO_SYS(var1,var2,var3) \MAINPREFIX\##var1\SUBPREFIX\##var2\##var3.sqf #endif #ifndef PATHTOF_SYS #define PATHTOF_SYS(var1,var2,var3) \MAINPREFIX\##var1\SUBPREFIX\##var2\##var3 #endif #ifndef PATHTOF2_SYS #define PATHTOF2_SYS(var1,var2,var3) MAINPREFIX\##var1\SUBPREFIX\##var2\##var3 #endif #define PATHTO_R(var1) PATHTOF2_SYS(PREFIX,COMPONENT_C,var1) #define PATHTO_T(var1) PATHTOF_SYS(PREFIX,COMPONENT_T,var1) #define PATHTO_M(var1) PATHTOF_SYS(PREFIX,COMPONENT_M,var1) #define PATHTO_S(var1) PATHTOF_SYS(PREFIX,COMPONENT_S,var1) #define PATHTO_C(var1) PATHTOF_SYS(PREFIX,COMPONENT_C,var1) #define PATHTO_F(var1) PATHTO_SYS(PREFIX,COMPONENT_F,var1) // Already quoted "" #define QPATHTO_R(var1) QUOTE(PATHTO_R(var1)) #define QPATHTO_T(var1) QUOTE(PATHTO_T(var1)) #define QPATHTO_M(var1) QUOTE(PATHTO_M(var1)) #define QPATHTO_S(var1) QUOTE(PATHTO_S(var1)) #define QPATHTO_C(var1) QUOTE(PATHTO_C(var1)) #define QPATHTO_F(var1) QUOTE(PATHTO_F(var1)) // This only works for binarized configs after recompiling the pbos // TODO: Reduce amount of calls / code.. #define COMPILE_FILE2_CFG_SYS(var1) compile preProcessFileLineNumbers var1 #define COMPILE_FILE2_SYS(var1) COMPILE_FILE2_CFG_SYS(var1) #define COMPILE_FILE_SYS(var1,var2,var3) COMPILE_FILE2_SYS('PATHTO_SYS(var1,var2,var3)') #define COMPILE_FILE_CFG_SYS(var1,var2,var3) COMPILE_FILE2_CFG_SYS('PATHTO_SYS(var1,var2,var3)') #define SETVARS(var1,var2) ##var1##_##var2 setVariable #define SETVARMAINS(var1) SETVARS(var1,MAINLOGIC) #define GVARMAINS(var1,var2) ##var1##_##var2## #define CFGSETTINGSS(var1,var2) configFile >> "CfgSettings" >> #var1 >> #var2 //#define SETGVARS(var1,var2,var3) ##var1##_##var2##_##var3 = //#define SETGVARMAINS(var1,var2) ##var1##_##var2 = // Compile-Once, JIT: On first use. // #define PREPMAIN_SYS(var1,var2,var3) ##var1##_fnc_##var3 = { ##var1##_fnc_##var3 = COMPILE_FILE_SYS(var1,var2,DOUBLES(fnc,var3)); if (isNil "_this") then { call ##var1##_fnc_##var3 } else { _this call ##var1##_fnc_##var3 } } // #define PREP_SYS(var1,var2,var3) ##var1##_##var2##_fnc_##var3 = { ##var1##_##var2##_fnc_##var3 = COMPILE_FILE_SYS(var1,var2,DOUBLES(fnc,var3)); if (isNil "_this") then { call ##var1##_##var2##_fnc_##var3 } else { _this call ##var1##_##var2##_fnc_##var3 } } // #define PREP_SYS2(var1,var2,var3,var4) ##var1##_##var2##_fnc_##var4 = { ##var1##_##var2##_fnc_##var4 = COMPILE_FILE_SYS(var1,var3,DOUBLES(fnc,var4)); if (isNil "_this") then { call ##var1##_##var2##_fnc_##var4 } else { _this call ##var1##_##var2##_fnc_##var4 } } // Compile-Once, at Macro. As opposed to Compile-Once, on first use. #define PREPMAIN_SYS(var1,var2,var3) ##var1##_fnc_##var3 = COMPILE_FILE_SYS(var1,var2,DOUBLES(fnc,var3)) #define PREP_SYS(var1,var2,var3) ##var1##_##var2##_fnc_##var3 = COMPILE_FILE_SYS(var1,var2,DOUBLES(fnc,var3)) #define PREP_SYS2(var1,var2,var3,var4) ##var1##_##var2##_fnc_##var4 = COMPILE_FILE_SYS(var1,var3,DOUBLES(fnc,var4)) #define LSTR(var1) TRIPLES(ADDON,STR,var1) #define CACHE_DIS_SYS(var1,var2) (isNumber(var1 >> "CfgSettings" >> "CBA" >> "caching" >> QUOTE(var2)) && getNumber(var1 >> "CfgSettings" >> "CBA" >> "caching" >> QUOTE(var2)) != 1) #define CACHE_DIS(var1) (!isNil "CBA_RECOMPILE" || CACHE_DIS_SYS(configFile,var1) || CACHE_DIS_SYS(missionConfigFile,var1)) #ifndef DEBUG_SETTINGS #define DEBUG_SETTINGS [false, true, false] #endif #define MSG_INIT QUOTE(Initializing: ADDON version: VERSION) // ************************************* // User Functions #define CFGSETTINGS CFGSETTINGSS(PREFIX,COMPONENT) #define PATHTO(var1) PATHTO_SYS(PREFIX,COMPONENT_F,var1) #define PATHTOF(var1) PATHTOF_SYS(PREFIX,COMPONENT,var1) #define COMPILE_FILE(var1) COMPILE_FILE_SYS(PREFIX,COMPONENT_F,var1) #define COMPILE_FILE_CFG(var1) COMPILE_FILE_CFG_SYS(PREFIX,COMPONENT_F,var1) #define COMPILE_FILE2(var1) COMPILE_FILE2_SYS('var1') #define COMPILE_FILE2_CFG(var1) COMPILE_FILE2_CFG_SYS('var1') #define VERSIONING_SYS(var1) class CfgSettings \ { \ class CBA \ { \ class Versioning \ { \ class var1 \ { \ }; \ }; \ }; \ }; #define VERSIONING VERSIONING_SYS(PREFIX) /* ------------------------------------------- Macro: GVAR() Get full variable identifier for a global variable owned by this component. Parameters: VARIABLE - Partial name of global variable owned by this component [Any]. Example: (begin example) GVAR(frog) = 12; // In SPON_FrogDancing component, equivalent to SPON_FrogDancing_frog = 12 (end) Author: Sickboy ------------------------------------------- */ #define GVAR(var1) DOUBLES(ADDON,var1) #define EGVAR(var1,var2) DOUBLES(DOUBLES(PREFIX,var1),var2) #define QGVAR(var1) QUOTE(GVAR(var1)) /* ------------------------------------------- Macro: GVARMAIN() Get full variable identifier for a global variable owned by this addon. Parameters: VARIABLE - Partial name of global variable owned by this addon [Any]. Example: (begin example) GVARMAIN(frog) = 12; // In SPON_FrogDancing component, equivalent to SPON_frog = 12 (end) Author: Sickboy ------------------------------------------- */ #define GVARMAIN(var1) GVARMAINS(PREFIX,var1) // TODO: What's this? #define SETTINGS DOUBLES(PREFIX,settings) #define CREATELOGIC CREATELOGICS(PREFIX,COMPONENT) #define CREATELOGICGLOBAL CREATELOGICGLOBALS(PREFIX,COMPONENT) #define CREATELOGICGLOBALTEST CREATELOGICGLOBALTESTS(PREFIX,COMPONENT) #define CREATELOGICLOCAL CREATELOGICLOCALS(PREFIX,COMPONENT) #define CREATELOGICMAIN CREATELOGICS(PREFIX,MAINLOGIC) #define GETVAR(var1) GETVARS(PREFIX,COMPONENT,var1) #define SETVAR SETVARS(PREFIX,COMPONENT) #define SETVARMAIN SETVARMAINS(PREFIX) #define IFCOUNT(var1,var2,var3) if (count ##var1 > ##var2) then { ##var3 = ##var1 select ##var2 }; //#define PREP(var1) PREP_SYS(PREFIX,COMPONENT_F,var1) #ifdef DISABLE_COMPILE_CACHE #define PREP(var1) TRIPLES(ADDON,fnc,var1) = compile preProcessFileLineNumbers 'PATHTO_SYS(PREFIX,COMPONENT_F,DOUBLES(fnc,var1))' #define PREPMAIN(var1) TRIPLES(PREFIX,fnc,var1) = compile preProcessFileLineNumbers 'PATHTO_SYS(PREFIX,COMPONENT_F,DOUBLES(fnc,var1))' #else #define PREP(var1) ['PATHTO_SYS(PREFIX,COMPONENT_F,DOUBLES(fnc,var1))', 'TRIPLES(ADDON,fnc,var1)'] call SLX_XEH_COMPILE_NEW #define PREPMAIN(var1) ['PATHTO_SYS(PREFIX,COMPONENT_F,DOUBLES(fnc,var1))', 'TRIPLES(PREFIX,fnc,var1)'] call SLX_XEH_COMPILE_NEW #endif #define FUNC(var1) TRIPLES(ADDON,fnc,var1) #define FUNCMAIN(var1) TRIPLES(PREFIX,fnc,var1) #define FUNC_INNER(var1,var2) TRIPLES(DOUBLES(PREFIX,var1),fnc,var2) #define EFUNC(var1,var2) FUNC_INNER(var1,var2) #ifndef PRELOAD_ADDONS #define PRELOAD_ADDONS class CfgAddons \ { \ class PreloadAddons \ { \ class ADDON \ { \ list[]={ QUOTE(ADDON) }; \ }; \ }; \ } #endif /* ------------------------------------------- Macros: ARG_#() Select from list of array arguments Parameters: VARIABLE(1-8) - elements for the list Author: Rommel ------------------------------------------- */ #define ARG_1(A,B) ((A) select (B)) #define ARG_2(A,B,C) (ARG_1(ARG_1(A,B),C)) #define ARG_3(A,B,C,D) (ARG_1(ARG_2(A,B,C),D)) #define ARG_4(A,B,C,D,E) (ARG_1(ARG_3(A,B,C,D),E)) #define ARG_5(A,B,C,D,E,F) (ARG_1(ARG_4(A,B,C,D,E),F)) #define ARG_6(A,B,C,D,E,F,G) (ARG_1(ARG_5(A,B,C,D,E,F),G)) #define ARG_7(A,B,C,D,E,F,G,H) (ARG_1(ARG_6(A,B,C,D,E,E,F,G),H)) #define ARG_8(A,B,C,D,E,F,G,H,I) (ARG_1(ARG_7(A,B,C,D,E,E,F,G,H),I)) /* ------------------------------------------- Macros: ARR_#() Create list from arguments. Useful for working around , in macro parameters. 1-8 arguments possible. Parameters: VARIABLE(1-8) - elements for the list Author: Nou ------------------------------------------- */ #define ARR_1(ARG1) ARG1 #define ARR_2(ARG1,ARG2) ARG1, ARG2 #define ARR_3(ARG1,ARG2,ARG3) ARG1, ARG2, ARG3 #define ARR_4(ARG1,ARG2,ARG3,ARG4) ARG1, ARG2, ARG3, ARG4 #define ARR_5(ARG1,ARG2,ARG3,ARG4,ARG5) ARG1, ARG2, ARG3, ARG4, ARG5 #define ARR_6(ARG1,ARG2,ARG3,ARG4,ARG5,ARG6) ARG1, ARG2, ARG3, ARG4, ARG5, ARG6 #define ARR_7(ARG1,ARG2,ARG3,ARG4,ARG5,ARG6,ARG7) ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7 #define ARR_8(ARG1,ARG2,ARG3,ARG4,ARG5,ARG6,ARG7,ARG8) ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7, ARG8 /* ------------------------------------------- Macros: FORMAT_#(STR, ARG1) Format - Useful for working around , in macro parameters. 1-8 arguments possible. Parameters: STRING - string used by format VARIABLE(1-8) - elements for usage in format Author: Nou & Sickboy ------------------------------------------- */ #define FORMAT_1(STR,ARG1) format[STR, ARG1] #define FORMAT_2(STR,ARG1,ARG2) format[STR, ARG1, ARG2] #define FORMAT_3(STR,ARG1,ARG2,ARG3) format[STR, ARG1, ARG2, ARG3] #define FORMAT_4(STR,ARG1,ARG2,ARG3,ARG4) format[STR, ARG1, ARG2, ARG3, ARG4] #define FORMAT_5(STR,ARG1,ARG2,ARG3,ARG4,ARG5) format[STR, ARG1, ARG2, ARG3, ARG4, ARG5] #define FORMAT_6(STR,ARG1,ARG2,ARG3,ARG4,ARG5,ARG6) format[STR, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6] #define FORMAT_7(STR,ARG1,ARG2,ARG3,ARG4,ARG5,ARG6,ARG7) format[STR, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7] #define FORMAT_8(STR,ARG1,ARG2,ARG3,ARG4,ARG5,ARG6,ARG7,ARG8) format[STR, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7, ARG8] // CONTROL(46) 12 #define DISPLAY(A) (findDisplay A) #define CONTROL(A) DISPLAY(A) displayCtrl /* ------------------------------------------- Macros: IS_x() Checking the data types of variables. IS_ARRAY() - Array IS_BOOL() - Boolean IS_BOOLEAN() - UI display handle(synonym for ) IS_CODE() - Code block (i.e a compiled function) IS_CONFIG() - Configuration IS_CONTROL() - UI control handle. IS_DISPLAY() - UI display handle. IS_FUNCTION() - A compiled function (synonym for ) IS_GROUP() - Group. IS_INTEGER() - Is a number a whole number? IS_LOCATION() - World location. IS_NUMBER() - A floating point number (synonym for ) IS_OBJECT() - World object. IS_SCALAR() - Floating point number. IS_SCRIPT() - A script handle (as returned by execVM and spawn commands). IS_SIDE() - Game side. IS_STRING() - World object. IS_TEXT() - Structured text. Parameters: VARIABLE - Variable to check if it is of a particular type [Any, not nil] Author: Spooner ------------------------------------------- */ #define IS_META_SYS(VAR,TYPE) (if (isNil {VAR}) then { false } else { (typeName (VAR)) == TYPE }) #define IS_ARRAY(VAR) IS_META_SYS(VAR,"ARRAY") #define IS_BOOL(VAR) IS_META_SYS(VAR,"BOOL") #define IS_CODE(VAR) IS_META_SYS(VAR,"CODE") #define IS_CONFIG(VAR) IS_META_SYS(VAR,"CONFIG") #define IS_CONTROL(VAR) IS_META_SYS(VAR,"CONTROL") #define IS_DISPLAY(VAR) IS_META_SYS(VAR,"DISPLAY") #define IS_GROUP(VAR) IS_META_SYS(VAR,"GROUP") #define IS_OBJECT(VAR) IS_META_SYS(VAR,"OBJECT") #define IS_SCALAR(VAR) IS_META_SYS(VAR,"SCALAR") #define IS_SCRIPT(VAR) IS_META_SYS(VAR,"SCRIPT") #define IS_SIDE(VAR) IS_META_SYS(VAR,"SIDE") #define IS_STRING(VAR) IS_META_SYS(VAR,"STRING") #define IS_TEXT(VAR) IS_META_SYS(VAR,"TEXT") #define IS_LOCATION(VAR) IS_META_SYS(VAR,"LOCATION") #define IS_BOOLEAN(VAR) IS_BOOL(VAR) #define IS_FUNCTION(VAR) IS_CODE(VAR) #define IS_INTEGER(VAR) if ( IS_SCALAR(VAR) ) then { (floor(VAR) == (VAR)) } else { false } #define IS_NUMBER(VAR) IS_SCALAR(VAR) #define FLOAT_TO_STRING(num) (str parseNumber (str (_this%_this) + str floor abs _this) + "." + (str (abs _this-floor abs _this) select [2]) + "0") /* ------------------------------------------- Macro: SCRIPT() Sets name of script (relies on PREFIX and COMPONENT values being #defined). Parameters: NAME - Name of script [Indentifier] Example: (begin example) SCRIPT(eradicateMuppets); (end) Author: Spooner ------------------------------------------- */ #define SCRIPT(NAME) \ scriptName 'PREFIX\COMPONENT\NAME' /* ------------------------------------------- Macros: EXPLODE_n() DEPRECATED - Use param/params commands added in Arma 3 1.48 Splitting an ARRAY into a number of variables (A, B, C, etc). Note that this NOT does make the created variables private. _PVT variants do. EXPLODE_1(ARRAY,A,B) - Split a 1-element array into separate variable. EXPLODE_2(ARRAY,A,B) - Split a 2-element array into separate variables. EXPLODE_3(ARRAY,A,B,C) - Split a 3-element array into separate variables. EXPLODE_4(ARRAY,A,B,C,D) - Split a 4-element array into separate variables. EXPLODE_5(ARRAY,A,B,C,D,E) - Split a 5-element array into separate variables. EXPLODE_6(ARRAY,A,B,C,D,E,F) - Split a 6-element array into separate variables. EXPLODE_7(ARRAY,A,B,C,D,E,F,G) - Split a 7-element array into separate variables. EXPLODE_8(ARRAY,A,B,C,D,E,F,G,H) - Split a 8-element array into separate variables. EXPLODE_9(ARRAY,A,B,C,D,E,F,G,H,I) - Split a 9-element array into separate variables. Parameters: ARRAY - Array to read from [Array] A..H - Names of variables to set from array [Identifier] Example: (begin example) _array = ["fred", 156.8, 120.9]; EXPLODE_3(_array,_name,_height,_weight); (end) Author: Spooner ------------------------------------------- */ #define EXPLODE_1_SYS(ARRAY,A) A = ARRAY param [0] #define EXPLODE_1(ARRAY,A) EXPLODE_1_SYS(ARRAY,A); TRACE_1("EXPLODE_1, " + QUOTE(ARRAY),A) #define EXPLODE_1_PVT(ARRAY,A) ARRAY params [#A]; TRACE_1("EXPLODE_1, " + QUOTE(ARRAY),A) #define EXPLODE_2_SYS(ARRAY,A,B) EXPLODE_1_SYS(ARRAY,A); B = ARRAY param [1] #define EXPLODE_2(ARRAY,A,B) EXPLODE_2_SYS(ARRAY,A,B); TRACE_2("EXPLODE_2, " + QUOTE(ARRAY),A,B) #define EXPLODE_2_PVT(ARRAY,A,B) ARRAY params [#A,#B]; TRACE_2("EXPLODE_2, " + QUOTE(ARRAY),A,B) #define EXPLODE_3_SYS(ARRAY,A,B,C) EXPLODE_2_SYS(ARRAY,A,B); C = ARRAY param [2] #define EXPLODE_3(ARRAY,A,B,C) EXPLODE_3_SYS(ARRAY,A,B,C); TRACE_3("EXPLODE_3, " + QUOTE(ARRAY),A,B,C) #define EXPLODE_3_PVT(ARRAY,A,B,C) ARRAY params [#A,#B,#C]; TRACE_3("EXPLODE_3, " + QUOTE(ARRAY),A,B,C) #define EXPLODE_4_SYS(ARRAY,A,B,C,D) EXPLODE_3_SYS(ARRAY,A,B,C); D = ARRAY param [3] #define EXPLODE_4(ARRAY,A,B,C,D) EXPLODE_4_SYS(ARRAY,A,B,C,D); TRACE_4("EXPLODE_4, " + QUOTE(ARRAY),A,B,C,D) #define EXPLODE_4_PVT(ARRAY,A,B,C,D) ARRAY params [#A,#B,#C,#D]; TRACE_4("EXPLODE_4, " + QUOTE(ARRAY),A,B,C,D) #define EXPLODE_5_SYS(ARRAY,A,B,C,D,E) EXPLODE_4_SYS(ARRAY,A,B,C,D); E = ARRAY param [4] #define EXPLODE_5(ARRAY,A,B,C,D,E) EXPLODE_5_SYS(ARRAY,A,B,C,D,E); TRACE_5("EXPLODE_5, " + QUOTE(ARRAY),A,B,C,D,E) #define EXPLODE_5_PVT(ARRAY,A,B,C,D,E) ARRAY params [#A,#B,#C,#D,#E]; TRACE_5("EXPLODE_5, " + QUOTE(ARRAY),A,B,C,D,E) #define EXPLODE_6_SYS(ARRAY,A,B,C,D,E,F) EXPLODE_5_SYS(ARRAY,A,B,C,D,E); F = ARRAY param [5] #define EXPLODE_6(ARRAY,A,B,C,D,E,F) EXPLODE_6_SYS(ARRAY,A,B,C,D,E,F); TRACE_6("EXPLODE_6, " + QUOTE(ARRAY),A,B,C,D,E,F) #define EXPLODE_6_PVT(ARRAY,A,B,C,D,E,F) ARRAY params [#A,#B,#C,#D,#E,#F]; TRACE_6("EXPLODE_6, " + QUOTE(ARRAY),A,B,C,D,E,F) #define EXPLODE_7_SYS(ARRAY,A,B,C,D,E,F,G) EXPLODE_6_SYS(ARRAY,A,B,C,D,E,F); G = ARRAY param [6] #define EXPLODE_7(ARRAY,A,B,C,D,E,F,G) EXPLODE_7_SYS(ARRAY,A,B,C,D,E,F,G); TRACE_7("EXPLODE_7, " + QUOTE(ARRAY),A,B,C,D,E,F,G) #define EXPLODE_7_PVT(ARRAY,A,B,C,D,E,F,G) ARRAY params [#A,#B,#C,#D,#E,#F,#G]; TRACE_7("EXPLODE_7, " + QUOTE(ARRAY),A,B,C,D,E,F,G) #define EXPLODE_8_SYS(ARRAY,A,B,C,D,E,F,G,H) EXPLODE_7_SYS(ARRAY,A,B,C,D,E,F,G); H = ARRAY param [7] #define EXPLODE_8(ARRAY,A,B,C,D,E,F,G,H) EXPLODE_8_SYS(ARRAY,A,B,C,D,E,F,G,H); TRACE_8("EXPLODE_8, " + QUOTE(ARRAY),A,B,C,D,E,F,G,H) #define EXPLODE_8_PVT(ARRAY,A,B,C,D,E,F,G,H) ARRAY params [#A,#B,#C,#D,#E,#F,#G,#H]; TRACE_8("EXPLODE_8, " + QUOTE(ARRAY),A,B,C,D,E,F,G,H) #define EXPLODE_9_SYS(ARRAY,A,B,C,D,E,F,G,H,I) EXPLODE_8_SYS(ARRAY,A,B,C,D,E,F,G,H); I = ARRAY param [8] #define EXPLODE_9(ARRAY,A,B,C,D,E,F,G,H,I) EXPLODE_9_SYS(ARRAY,A,B,C,D,E,F,G,H,I); TRACE_9("EXPLODE_9, " + QUOTE(ARRAY),A,B,C,D,E,F,G,H,I) #define EXPLODE_9_PVT(ARRAY,A,B,C,D,E,F,G,H,I) ARRAY params [#A,#B,#C,#D,#E,#F,#G,#H,#I]; TRACE_9("EXPLODE_9, " + QUOTE(ARRAY),A,B,C,D,E,F,G,H,I) /* ------------------------------------------- Macro: xSTRING() Get full string identifier from a stringtable owned by this component. Parameters: VARIABLE - Partial name of global variable owned by this component [Any]. Example: ADDON is CBA_Balls. (begin example) // Localized String (localize command must still be used with it) LSTRING(Example); // STR_CBA_Balls_Example; // Config String (note the $) CSTRING(Example); // $STR_CBA_Balls_Example; (end) Author: Jonpas ------------------------------------------- */ #ifndef STRING_MACROS_GUARD #define STRING_MACROS_GUARD #define LSTRING(var1) QUOTE(TRIPLES(STR,ADDON,var1)) #define ELSTRING(var1,var2) QUOTE(TRIPLES(STR,DOUBLES(PREFIX,var1),var2)) #define CSTRING(var1) QUOTE(TRIPLES($STR,ADDON,var1)) #define ECSTRING(var1,var2) QUOTE(TRIPLES($STR,DOUBLES(PREFIX,var1),var2)) #endif /* ------------------------------------------- Group: Managing Function Parameters ------------------------------------------- */ /* ------------------------------------------- Macros: PARAMS_n() DEPRECATED - Use param/params commands added in Arma 3 1.48 Setting variables based on parameters passed to a function. Each parameter is defines as private and set to the appropriate value from _this. PARAMS_1(A) - Get 1 parameter from the _this array (or _this if it's not an array). PARAMS_2(A,B) - Get 2 parameters from the _this array. PARAMS_3(A,B,C) - Get 3 parameters from the _this array. PARAMS_4(A,B,C,D) - Get 4 parameters from the _this array. PARAMS_5(A,B,C,D,E) - Get 5 parameters from the _this array. PARAMS_6(A,B,C,D,E,F) - Get 6 parameters from the _this array. PARAMS_7(A,B,C,D,E,F,G) - Get 7 parameters from the _this array. PARAMS_8(A,B,C,D,E,F,G,H) - Get 8 parameters from the _this array. Parameters: A..H - Name of variable to read from _this [Identifier] Example: A function called like this: (begin example) [_name,_address,_telephone] call recordPersonalDetails; (end) expects 3 parameters and those variables could be initialised at the start of the function definition with: (begin example) recordPersonalDetails = { PARAMS_3(_name,_address,_telephone); // Rest of function follows... }; (end) Author: Spooner ------------------------------------------- */ #define PARAMS_1(A) EXPLODE_1_PVT(_this,A) #define PARAMS_2(A,B) EXPLODE_2_PVT(_this,A,B) #define PARAMS_3(A,B,C) EXPLODE_3_PVT(_this,A,B,C) #define PARAMS_4(A,B,C,D) EXPLODE_4_PVT(_this,A,B,C,D) #define PARAMS_5(A,B,C,D,E) EXPLODE_5_PVT(_this,A,B,C,D,E) #define PARAMS_6(A,B,C,D,E,F) EXPLODE_6_PVT(_this,A,B,C,D,E,F) #define PARAMS_7(A,B,C,D,E,F,G) EXPLODE_7_PVT(_this,A,B,C,D,E,F,G) #define PARAMS_8(A,B,C,D,E,F,G,H) EXPLODE_8_PVT(_this,A,B,C,D,E,F,G,H) #define PARAMS_9(A,B,C,D,E,F,G,H,I) EXPLODE_9_PVT(_this,A,B,C,D,E,F,G,H,I) /* ------------------------------------------- Macro: DEFAULT_PARAM() DEPRECATED - Use param/params commands added in Arma 3 1.48 Getting a default function parameter. This may be used together with to have a mix of required and optional parameters. Parameters: INDEX - Index of parameter in _this [Integer, 0+] NAME - Name of the variable to set [Identifier] DEF_VALUE - Default value to use in case the array is too short or the value at INDEX is nil [Any] Example: A function called with optional parameters: (begin example) [_name] call myFunction; [_name, _numberOfLegs] call myFunction; [_name, _numberOfLegs, _hasAHead] call myFunction; (end) 1 required parameter and 2 optional parameters. Those variables could be initialised at the start of the function definition with: (begin example) myFunction = { PARAMS_1(_name); DEFAULT_PARAM(1,_numberOfLegs,2); DEFAULT_PARAM(2,_hasAHead,true); // Rest of function follows... }; (end) Author: Spooner ------------------------------------------- */ #define DEFAULT_PARAM(INDEX,NAME,DEF_VALUE) \ private [#NAME,"_this"]; \ ISNILS(_this,[]); \ NAME = _this param [INDEX, DEF_VALUE]; \ TRACE_3("DEFAULT_PARAM",INDEX,NAME,DEF_VALUE) /* ------------------------------------------- Macro: KEY_PARAM() Get value from key in _this list, return default when key is not included in list. Parameters: KEY - Key name [String] NAME - Name of the variable to set [Identifier] DEF_VALUE - Default value to use in case key not found [ANY] Example: Author: Muzzleflash ------------------------------------------- */ #define KEY_PARAM(KEY,NAME,DEF_VALUE) \ private #NAME; \ NAME = [toLower KEY, toUpper KEY, DEF_VALUE, RETNIL(_this)] call CBA_fnc_getArg; \ TRACE_3("KEY_PARAM",KEY,NAME,DEF_VALUE) /* ------------------------------------------- Group: Assertions ------------------------------------------- */ #define ASSERTION_ERROR(MESSAGE) ERROR_WITH_TITLE("Assertion failed!",MESSAGE) /* ------------------------------------------- Macro: ASSERT_TRUE() Asserts that a CONDITION is true. When an assertion fails, an error is raised with the given MESSAGE. Parameters: CONDITION - Condition to assert as true [Boolean] MESSSAGE - Message to display if (A OPERATOR B) is false [String] Example: (begin example) ASSERT_TRUE(_frogIsDead,"The frog is alive"); (end) Author: Spooner ------------------------------------------- */ #define ASSERT_TRUE(CONDITION,MESSAGE) \ if (not (CONDITION)) then \ { \ ASSERTION_ERROR('Assertion (CONDITION) failed!\n\n' + (MESSAGE)); \ } /* ------------------------------------------- Macro: ASSERT_FALSE() Asserts that a CONDITION is false. When an assertion fails, an error is raised with the given MESSAGE. Parameters: CONDITION - Condition to assert as false [Boolean] MESSSAGE - Message to display if (A OPERATOR B) is true [String] Example: (begin example) ASSERT_FALSE(_frogIsDead,"The frog died"); (end) Author: Spooner ------------------------------------------- */ #define ASSERT_FALSE(CONDITION,MESSAGE) \ if (CONDITION) then \ { \ ASSERTION_ERROR('Assertion (not (CONDITION)) failed!\n\n' + (MESSAGE)) \ } /* ------------------------------------------- Macro: ASSERT_OP() Asserts that (A OPERATOR B) is true. When an assertion fails, an error is raised with the given MESSAGE. Parameters: A - First value [Any] OPERATOR - Binary operator to use [Operator] B - Second value [Any] MESSSAGE - Message to display if (A OPERATOR B) is false. [String] Example: (begin example) ASSERT_OP(_fish,>,5,"Too few fish!"); (end) Author: Spooner ------------------------------------------- */ #define ASSERT_OP(A,OPERATOR,B,MESSAGE) \ if (not ((A) OPERATOR (B))) then \ { \ ASSERTION_ERROR('Assertion (A OPERATOR B) failed!\n' + 'A: ' + (str (A)) + '\n' + 'B: ' + (str (B)) + "\n\n" + (MESSAGE)); \ } /* ------------------------------------------- Macro: ASSERT_DEFINED() Asserts that a VARIABLE is defined. When an assertion fails, an error is raised with the given MESSAGE.. Parameters: VARIABLE - Variable to test if defined [String or Function]. MESSAGE - Message to display if variable is undefined [String]. Examples: (begin example) ASSERT_DEFINED("_anUndefinedVar","Too few fish!"); ASSERT_DEFINED({ obj getVariable "anUndefinedVar" },"Too many fish!"); (end) Author: Spooner ------------------------------------------- */ #define ASSERT_DEFINED(VARIABLE,MESSAGE) \ if (isNil VARIABLE) then \ { \ ASSERTION_ERROR('Assertion (VARIABLE is defined) failed!\n\n' + (MESSAGE)); \ } /* ------------------------------------------- Group: Unit tests ------------------------------------------- */ #define TEST_SUCCESS(MESSAGE) MESSAGE_WITH_TITLE("Test OK",MESSAGE) #define TEST_FAIL(MESSAGE) ERROR_WITH_TITLE("Test FAIL",MESSAGE) /* ------------------------------------------- Macro: TEST_TRUE() Tests that a CONDITION is true. If the condition is not true, an error is raised with the given MESSAGE. Parameters: CONDITION - Condition to assert as true [Boolean] MESSSAGE - Message to display if (A OPERATOR B) is false [String] Example: (begin example) TEST_TRUE(_frogIsDead,"The frog is alive"); (end) Author: Killswitch ------------------------------------------- */ #define TEST_TRUE(CONDITION, MESSAGE) \ if (CONDITION) then \ { \ TEST_SUCCESS('(CONDITION)'); \ } \ else \ { \ TEST_FAIL('(CONDITION) ' + (MESSAGE)); \ } /* ------------------------------------------- Macro: TEST_FALSE() Tests that a CONDITION is false. If the condition is not false, an error is raised with the given MESSAGE. Parameters: CONDITION - Condition to test as false [Boolean] MESSSAGE - Message to display if (A OPERATOR B) is true [String] Example: (begin example) TEST_FALSE(_frogIsDead,"The frog died"); (end) Author: Killswitch ------------------------------------------- */ #define TEST_FALSE(CONDITION, MESSAGE) \ if (not (CONDITION)) then \ { \ TEST_SUCCESS('(not (CONDITION))'); \ } \ else \ { \ TEST_FAIL('(not (CONDITION)) ' + (MESSAGE)); \ } /* ------------------------------------------- Macro: TEST_OP() Tests that (A OPERATOR B) is true. If the test fails, an error is raised with the given MESSAGE. Parameters: A - First value [Any] OPERATOR - Binary operator to use [Operator] B - Second value [Any] MESSSAGE - Message to display if (A OPERATOR B) is false. [String] Example: (begin example) TEST_OP(_fish,>,5,"Too few fish!"); (end) Author: Killswitch ------------------------------------------- */ #define TEST_OP(A,OPERATOR,B,MESSAGE) \ if ((A) OPERATOR (B)) then \ { \ TEST_SUCCESS('(A OPERATOR B)') \ } \ else \ { \ TEST_FAIL('(A OPERATOR B)') \ }; /* ------------------------------------------- Macro: TEST_DEFINED() Tests that a VARIABLE is defined. Parameters: VARIABLE - Variable to test if defined [String or Function]. MESSAGE - Message to display if variable is undefined [String]. Examples: (begin example) TEST_DEFINED("_anUndefinedVar","Too few fish!"); TEST_DEFINED({ obj getVariable "anUndefinedVar" },"Too many fish!"); (end) Author: Killswitch ------------------------------------------- */ #define TEST_DEFINED(VARIABLE,MESSAGE) \ if (not isNil VARIABLE) then \ { \ TEST_SUCCESS('(' + VARIABLE + ' is defined)'); \ } \ else \ { \ TEST_FAIL('(' + VARIABLE + ' is not defined)' + (MESSAGE)); \ } /* ------------------------------------------- Group: Managing Deprecation ------------------------------------------- */ /* ------------------------------------------- Macro: DEPRECATE_SYS() Allow deprecation of a function that has been renamed. Replaces an old OLD_FUNCTION (which will have PREFIX_ prepended) with a NEW_FUNCTION (PREFIX_ prepended) with the intention that the old function will be disabled in the future. Shows a warning in RPT each time the deprecated function is used, but runs the new function. Parameters: OLD_FUNCTION - Full name of old function [Identifier for function that does not exist any more] NEW_FUNCTION - Full name of new function [Function] Example: (begin example) // After renaming CBA_fnc_frog as CBA_fnc_fish DEPRECATE_SYS(CBA_fnc_frog,CBA_fnc_fish); (end) Author: Sickboy ------------------------------------------- */ #define DEPRECATE_SYS(OLD_FUNCTION,NEW_FUNCTION) \ OLD_FUNCTION = { \ WARNING('Deprecated function used: OLD_FUNCTION (new: NEW_FUNCTION) in ADDON'); \ if (isNil "_this") then { call NEW_FUNCTION } else { _this call NEW_FUNCTION }; \ } /* ------------------------------------------- Macro: DEPRECATE() Allow deprecation of a function, in the current component, that has been renamed. Replaces an OLD_FUNCTION (which will have PREFIX_ prepended) with a NEW_FUNCTION (PREFIX_ prepended) with the intention that the old function will be disabled in the future. Shows a warning in RPT each time the deprecated function is used, but runs the new function. Parameters: OLD_FUNCTION - Name of old function, assuming PREFIX [Identifier for function that does not exist any more] NEW_FUNCTION - Name of new function, assuming PREFIX [Function] Example: (begin example) // After renaming CBA_fnc_frog as CBA_fnc_fish DEPRECATE(fnc_frog,fnc_fish); (end) Author: Sickboy ------------------------------------------- */ #define DEPRECATE(OLD_FUNCTION,NEW_FUNCTION) \ DEPRECATE_SYS(DOUBLES(PREFIX,OLD_FUNCTION),DOUBLES(PREFIX,NEW_FUNCTION)) /* ------------------------------------------- Macro: OBSOLETE_SYS() Replace a function that has become obsolete. Replace an obsolete OLD_FUNCTION with a simple COMMAND_FUNCTION, with the intention that anyone using the function should replace it with the simple command, since the function will be disabled in the future. Shows a warning in RPT each time the deprecated function is used, and runs the command function. Parameters: OLD_FUNCTION - Full name of old function [Identifier for function that does not exist any more] COMMAND_CODE - Code to replace the old function [Function] Example: (begin example) // In Arma2, currentWeapon command made the CBA_fMyWeapon function obsolete: OBSOLETE_SYS(CBA_fMyWeapon,{ currentWeapon player }); (end) Author: Spooner ------------------------------------------- */ #define OBSOLETE_SYS(OLD_FUNCTION,COMMAND_CODE) \ OLD_FUNCTION = { \ WARNING('Obsolete function used: (use: OLD_FUNCTION) in ADDON'); \ if (isNil "_this") then { call COMMAND_CODE } else { _this call COMMAND_CODE }; \ } /* ------------------------------------------- Macro: OBSOLETE() Replace a function, in the current component, that has become obsolete. Replace an obsolete OLD_FUNCTION (which will have PREFIX_ prepended) with a simple COMMAND_CODE, with the intention that anyone using the function should replace it with the simple command. Shows a warning in RPT each time the deprecated function is used. Parameters: OLD_FUNCTION - Name of old function, assuming PREFIX [Identifier for function that does not exist any more] COMMAND_CODE - Code to replace the old function [Function] Example: (begin example) // In Arma2, currentWeapon command made the CBA_fMyWeapon function obsolete: OBSOLETE(fMyWeapon,{ currentWeapon player }); (end) Author: Spooner ------------------------------------------- */ #define OBSOLETE(OLD_FUNCTION,COMMAND_CODE) \ OBSOLETE_SYS(DOUBLES(PREFIX,OLD_FUNCTION),COMMAND_CODE) #define BWC_CONFIG(NAME) class NAME { \ units[] = {}; \ weapons[] = {}; \ requiredVersion = REQUIRED_VERSION; \ requiredAddons[] = {}; \ version = VERSION; \ } // XEH Specific #define XEH_DISABLED class EventHandlers {}; SLX_XEH_DISABLED = 1 #define XEH_ENABLED class EventHandlers { EXTENDED_EVENTHANDLERS }; delete SLX_XEH_DISABLED // TODO: These are actually outdated; _Once ? #define XEH_PRE_INIT QUOTE(call COMPILE_FILE(XEH_PreInit_Once)) #define XEH_PRE_CINIT QUOTE(call COMPILE_FILE(XEH_PreClientInit_Once)) #define XEH_PRE_SINIT QUOTE(call COMPILE_FILE(XEH_PreServerInit_Once)) #define XEH_POST_INIT QUOTE(call COMPILE_FILE(XEH_PostInit_Once)) #define XEH_POST_CINIT QUOTE(call COMPILE_FILE(XEH_PostClientInit_Once)) #define XEH_POST_SINIT QUOTE(call COMPILE_FILE(XEH_PostServerInit_Once))