1.8.7 player_switchWeapon updates

This commit is contained in:
ebaydayz
2016-03-03 21:31:32 -05:00
parent e660704f97
commit 479097e7a8
37 changed files with 1883 additions and 202 deletions

View File

@@ -825,7 +825,7 @@ class RscDisplayGear {
h = 0.174;
color[] = {1,1,1,0.5};
colorActive[] = {1,1,1,0.8};
action = "[""gear""] call player_switchWeapon";
action = "0 call dz_fn_switchWeapon";
};
class Button2: RscActiveText {
@@ -840,7 +840,7 @@ class RscDisplayGear {
h = 0.174;
color[] = {1,1,1,0.5};
colorActive[] = {1,1,1,0.8};
action = "[""gear""] call player_switchWeapon";
action = "0 call dz_fn_switchWeapon";
};
};
};

View File

@@ -1,214 +1,281 @@
private ["_event", "_onLadder", "_inVehicle", "_isOk", "_primary", "_current", "_rifle", "_pistol", "_melee"];
_event = if (count _this > 1) then { _this select 3 } else { _this select 0 };
#include "\z\addons\dayz_code\util\mutex.hpp"
#include "\z\addons\dayz_code\util\player.hpp"
_findRifle = {
private ["_return", "_primary"];
_return = "";
_primary = primaryWeapon player;
#define BANDAID
if (_primary != "") then {
if !(_primary in MeleeWeapons) then {
_return = _primary;
};
};
#define TIMEOUT 2
if (dayz_onBack != "" && _return == "") then {
if !(dayz_onBack in MeleeWeapons) then {
_return = dayz_onBack;
};
};
#define IS_PRIMARY(wpn) (getNumber (configFile >> "CfgWeapons" >> wpn >> "type") == 1)
#define MELEE(wpn) getNumber (configFile >> "CfgWeapons" >> wpn >> "melee")
#define IS_MELEE(wpn) (MELEE(wpn) == 1)
_return;
};
//0 if not found, 1 if in primary slot, 2 if on back
#define FIND_RIFLE() (0 call dz_fn_switchWeapon_find)
#define FIND_MELEE() (1 call dz_fn_switchWeapon_find)
_findMelee = {
private ["_return", "_primary"];
_return = "";
dz_switchWeapon_mutex = Mutex_New();
_primary = primaryWeapon player;
if (_primary != "") then {
if (_primary in MeleeWeapons) then {
_return = _primary;
};
};
if (dayz_onBack != "" && _return == "") then {
if (dayz_onBack in MeleeWeapons) then {
_return = dayz_onBack;
};
};
_return;
};
_findPistol = {
private ["_return"];
_return = "";
{
if (getNumber (configFile >> "CfgWeapons" >> _x >> "type") == 2) then {
_return = _x;
};
} foreach (weapons player);
_return;
};
_selectMuzzle = {
private ["_return", "_wpn", "_muzzles"];
_wpn = _this select 0;
_muzzles = getArray(configFile >> "cfgWeapons" >> _wpn >> "muzzles");
if (_muzzles select 0 != "this") then {
_return = (_muzzles select 0);
} else {
_return = _wpn;
};
_return;
};
_clearActions = {
if (s_player_equip_carry > -1) then {
player removeAction s_player_equip_carry;
s_player_equip_carry = -1;
};
};
_switchPrimary = {
private ["_primary", "_current"];
_primary = primaryWeapon player;
//0: switch rifle/melee instantly and update gear
//1: switch rifle/melee with animation
//2: switch to rifle
//3: switch to pistol
//4: switch to melee
dz_fn_switchWeapon =
{
if (vehicle player != player) exitWith {};
if Player_IsOnLadder() exitWith {};
private ["_current", "_primary", "_secondary"];
_current = currentWeapon player;
_timer = 0;
[] call _clearActions;
if (_primary != "") then {
// check if player is still in the 'open gear' animation state and force him out of it (caused major issues)
_animState = animationState player;
switch (true) do {
// current weapon is a rifle
case (_animState == "amovpknlmstpsraswrfldnon_gear" || _animState == "amovpercmstpsraswrfldnon_gear"): {
player playMove "amovpknlmstpslowwrfldnon_amovpknlmstpsraswrfldnon";
waitUntil { animationState player == "amovpknlmstpslowwrfldnon_amovpknlmstpsraswrfldnon" };
switch _this do
{
//Instantly switch primary and carry, also update gear
case 0:
{
if (IS_PRIMARY(_current)) then
{ true call dz_fn_switchWeapon_swap; }
else
{ false call dz_fn_switchWeapon_swap; };
/*call _swapWeapons;
if (IS_PRIMARY(_current)) then
{ player selectWeapon primaryWeapon player; };*/
[[(findDisplay 106)],"onLBSelChanged"] execVM "\z\addons\dayz_code\system\handleGear.sqf";
};
//Switch primary and carry
case 1:
{
if (dayz_quickSwitch) then
{
true call dz_fn_switchWeapon_swap;
#ifdef BANDAID
call dayz_meleeMagazineCheck;
#endif
}
else
{ call dz_fn_switchWeapon_swapSecure; };
};
//Switch to rifle
case 2:
{
//No current weapon
if (_current == "") exitWith
{
switch FIND_RIFLE() do
{
//In primary
case 1:
{
player selectWeapon primaryWeapon player;
};
//On back
case 2:
{
true call dz_fn_switchWeapon_swap;
};
};
};
// current weapon is a pistol
case (_animState == "amovpknlmstpsraswpstdnon_gear" || _animState == "amovpercmstpsraswpstdnon_gear"): {
player playMove "amovpknlmstpslowwpstdnon_gear_amovpknlmstpsraswpstdnon";
waitUntil { animationState player == "amovpknlmstpslowwpstdnon_gear_amovpknlmstpsraswpstdnon" };
//Current weapon is primary
if (IS_PRIMARY(_current)) exitWith
{
//if current is melee and on back is rifle
if (IS_MELEE(_current) && { !IS_MELEE(dayz_onBack) }) then
{
if (dayz_quickSwitch) then
{ true call dz_fn_switchWeapon_swap; }
else
{ call dz_fn_switchWeapon_swapSecure; };
};
};
// is standing with weapon lowered
case (["aidlpercmstpslowwrfldnon", _animState] call fnc_inString): {
player playMove "amovpercmstpslowwrfldnon_amovpercmstpsraswrfldnon";
waitUntil { animationState player == "amovpercmstpslowwrfldnon_amovpercmstpsraswrfldnon" };
//Current is pistol
switch FIND_RIFLE() do
{
//In primary
case 1:
{
player selectWeapon primaryWeapon player;
};
//On back
case 2:
{
if (diag_tickTime - dz_switchWeapon_pistolTime < 1) exitWith {};
true call dz_fn_switchWeapon_swap;
};
};
};
player removeWeapon _primary;
// make sure animation is playing to prevent instant switch (if current weapon is not pisol)
if (!dayz_quickSwitch) then {
if (_current != [] call _findPistol) then {
_timeout = diag_tickTime + 2;
_animArray = [
"amovpercmstpsraswrfldnon_amovpercmstpsnonwnondnon", // is standing, has no pistol / is crouched, has no pistol
"amovpercmstpsraswrfldnon_amovpercmstpsraswpstdnon", // is standing, has pistol
"amovpknlmstpsraswrfldnon_amovpknlmstpsraswpstdnon", // is crouched, has pistol
"amovppnemstpsraswrfldnon_amovppnemstpsnonwnondnon", // is prone, has no pistol
"amovppnemstpsraswrfldnon_amovppnemstpsraswpstdnon" // is prone, has pistol
];
waitUntil { (animationState player) in _animArray || diag_tickTime >= _timeout };
waitUntil { !((animationState player) in _animArray) || diag_tickTime >= _timeout };
//Switch to pistol
case 3:
{
//If current weapon is primary
if (IS_PRIMARY(_current)) then
{
_secondary = Player_GetSidearm();
if (!isNil "_secondary") then
{
player selectWeapon _secondary;
dz_switchWeapon_pistolTime = diag_tickTime;
};
};
};
//Switch to melee
case 4:
{
//No current weapon
if (_current == "") exitWith
{
switch FIND_MELEE() do
{
//In primary
case 1:
{
player selectWeapon primaryWeapon player;
};
//On back
case 2:
{
true call dz_fn_switchWeapon_swap;
#ifdef BANDAID
call dayz_meleeMagazineCheck;
#endif
};
};
};
//Current weapon is primary
if (IS_PRIMARY(_current)) exitWith
{
//if current is rifle and on back is melee
if (!IS_MELEE(_current) && { IS_MELEE(dayz_onBack) }) then
{
if (dayz_quickSwitch) then
{
true call dz_fn_switchWeapon_swap;
#ifdef BANDAID
call dayz_meleeMagazineCheck;
#endif
}
else
{ call dz_fn_switchWeapon_swapSecure; };
};
};
//Current is pistol
//Find melee weapon
switch FIND_MELEE() do
{
//In primary
case 1:
{
player selectWeapon primaryWeapon player;
};
//On back
case 2:
{
if (diag_tickTime - dz_switchWeapon_pistolTime < 1) exitWith {};
true call dz_fn_switchWeapon_swap;
};
};
};
};
};
//See FIND_RIFLE() and FIND_MELEE()
dz_fn_switchWeapon_find =
{
_primary = primaryWeapon player;
if (_primary != "" && { _this == MELEE(_primary) })
exitWith { 1 };
if (dayz_onBack != "" && { _this == MELEE(dayz_onBack) })
exitWith { 2 };
0
};
//Swaps rifle / melee instantly without animation
dz_fn_switchWeapon_swap =
{
if (dayz_onBack == "") then
{
//Must be in a single statement to ensure atomicity in the scheduled environment.
dayz_onBack =
[
primaryWeapon player,
player removeWeapon primaryWeapon player
] select 0;
}
else
{
dayz_onBack =
[
primaryWeapon player,
player removeWeapon primaryWeapon player,
player addWeapon dayz_onBack
] select 0;
};
if (dayz_onBack != "") then {
player addWeapon dayz_onBack;
player selectWeapon ([dayz_onBack] call _selectMuzzle);
};
dayz_onBack = _primary;
call dayz_meleeMagazineCheck;
if (_this) then
{ player selectWeapon primaryWeapon player; };
};
_switchPrimaryUI = {
private ["_primary", "_current"];
_primary = primaryWeapon player;
_current = currentWeapon player;
[] call _clearActions;
if (_primary != "") then {
player removeWeapon _primary;
};
if (dayz_onBack != "") then {
player addWeapon dayz_onBack;
if (_primary == _current) then {
player selectWeapon ([dayz_onBack] call _selectMuzzle);
};
};
dayz_onBack = _primary;
[[(findDisplay 106)],"onLBSelChanged"] execVM "\z\addons\dayz_code\system\handleGear.sqf"; // update gear dialog
//Swaps rifle / melee forcing an animation
dz_fn_switchWeapon_swapSecure =
{
if (!Mutex_TryLock_Fast(dz_switchWeapon_mutex)) exitWith {};
//animation states are in the form "AmovPerc...", "AmovPknl...", "AmovPpne..."
dz_switchWeapon_anim = format
[
"AmovP%1MstpSrasWrflDnon_AmovP%1MstpSrasWpstDnon",
//Switch on the 6th letter of the animation class
switch ((toArray animationState player) select 5) do
{
case 101: { "erc" }; //e for erc for erected
case 107: { "knl" }; //k for knl for kneeling
case 112: { "pne" }; //p for pne for prone
}
];
//Add AnimDone event handler to wait until current weapon is put away
dz_switchWeapon_handler = player addEventHandler ["AnimDone", dz_fn_switchWeapon_animDone];
player playMoveNow dz_switchWeapon_anim;
dz_switchWeapon_time = diag_tickTime;
};
_onLadder = (getNumber (configFile >> "CfgMovesMaleSdr" >> "States" >> (animationState player) >> "onLadder")) == 1;
_inVehicle = (vehicle player != player);
_isOK = (!_onLadder && !_inVehicle && !r_player_unconscious && !dayz_onBackActive);
if (_isOK) then { dayz_onBackActive = true };
switch (_event) do {
case "action": {
if (_isOK) then {
[] call _switchPrimary;
};
dz_fn_switchWeapon_animDone =
{
//Wait at most TIMEOUT seconds
if (dz_switchWeapon_time - diag_tickTime > TIMEOUT) exitWith
{
player removeEventHandler ["AnimDone", dz_switchWeapon_handler];
Mutex_Unlock(dz_switchWeapon_mutex);
};
case "gear": {
[] call _switchPrimaryUI;
};
case "rifle": {
if (_isOK) then {
_rifle = [] call _findRifle;
if (_rifle != "") then {
if (_rifle == dayz_onBack) then {
[] call _switchPrimary;
} else {
player selectWeapon ([_rifle] call _selectMuzzle);
};
};
};
};
case "pistol": {
if (_isOK) then {
_pistol = [] call _findPistol;
if (_pistol != "") then {
player selectWeapon ([_pistol] call _selectMuzzle);
};
};
};
case "melee": {
if (_isOK) then {
_melee = [] call _findMelee;
if (_melee != "") then {
if (_melee == dayz_onBack) then {
[] call _switchPrimary;
} else {
player selectWeapon ([_melee] call _selectMuzzle);
};
};
};
};
};
if (_isOK) then { dayz_onBackActive = false };
//Check if finished animation is the correct one
if ((_this select 1) != dz_switchWeapon_anim) exitWith {};
true call dz_fn_switchWeapon_swap;
//Remove eventhandler
player removeEventHandler ["AnimDone", dz_switchWeapon_handler];
Mutex_Unlock(dz_switchWeapon_mutex);
#ifdef BANDAID
if (IS_MELEE(primaryWeapon player)) then
{ call dayz_meleeMagazineCheck; };
#endif
};

View File

@@ -0,0 +1 @@
1 call dz_fn_switchWeapon;

View File

@@ -38,6 +38,27 @@ if (_canPickLight && !dayz_hasLight && !_isPZombie) then {
s_player_removeflare = -1;
};
if (s_player_equip_carry < 0) then
{
if (dayz_onBack != "" && { !_inVehicle && { !_onLadder && { !r_player_unconscious } } }) then
{
dz_plr_carryActionItem = dayz_onBack;
_text = getText (configFile >> "CfgWeapons" >> dz_plr_carryActionItem >> "displayName");
s_player_equip_carry = player addAction [
format [localize "STR_ACTIONS_WEAPON", _text],
"\z\addons\dayz_code\actions\player_switchWeapon_action.sqf",
nil, 0.5, false, true];
};
}
else
{
if (dayz_onBack != dz_plr_carryActionItem || { _inVehicle || { _onLadder || { r_player_unconscious } } } ) then
{
player removeAction s_player_equip_carry;
s_player_equip_carry = -1;
};
};
if (_inVehicle && {_vehicleOwnerID != "0"} && {!(_vehicle isKindOf "Bicycle")}) then {
if (s_player_lockUnlockInside_ctrl < 0) then {
DZE_myVehicle = _vehicle;

View File

@@ -44,15 +44,15 @@ if (isNil "keyboard_keys") then {
_handled = true;
};
_rifle = {
["rifle"] spawn player_switchWeapon;
2 call dz_fn_switchWeapon;
_handled = true;
};
_pistol = {
["pistol"] spawn player_switchWeapon;
3 call dz_fn_switchWeapon;
_handled = true;
};
_melee = {
["melee"] spawn player_switchWeapon;
4 call dz_fn_switchWeapon;
_handled = true;
};
_throwable = { // select next non empty throwable weapon
@@ -74,7 +74,7 @@ if (isNil "keyboard_keys") then {
};
} forEach getArray(configFile >> "cfgWeapons" >> _weapon >> _muzz >> "magazines");
} forEach _muzzles;
} forEach [ "Flare", "Throw" ];
} forEach [ "Throw"];
_magCount = count _ammo_throwable;
if (_magCount > 0) then {

View File

@@ -5,6 +5,8 @@
if (!isDedicated) then {
"filmic" setToneMappingParams [0.07, 0.31, 0.23, 0.37, 0.011, 3.750, 6, 4]; setToneMapping "Filmic";
call compile preprocessFileLineNumbers "\z\addons\dayz_code\util\compile.sqf";
BIS_Effects_Burn = compile preprocessFile "\ca\Data\ParticleEffects\SCRIPTS\destruction\burn.sqf";
player_zombieCheck = compile preprocessFileLineNumbers "\z\addons\dayz_code\compile\player_zombieCheck.sqf"; //Run on a players computer, checks if the player is near a zombie
@@ -108,7 +110,7 @@ if (!isDedicated) then {
player_wearClothes = compile preprocessFileLineNumbers "\z\addons\dayz_code\actions\player_wearClothes.sqf";
object_pickup = compile preprocessFileLineNumbers "\z\addons\dayz_code\actions\object_pickup.sqf";
player_switchWeapon = compile preprocessFileLineNumbers "\z\addons\dayz_code\actions\player_switchWeapon.sqf";
call compile preprocessFileLineNumbers "\z\addons\dayz_code\actions\player_switchWeapon.sqf";
player_flipvehicle = compile preprocessFileLineNumbers "\z\addons\dayz_code\actions\player_flipvehicle.sqf";
player_sleep = compile preprocessFileLineNumbers "\z\addons\dayz_code\actions\player_sleep.sqf";
player_antiWall = compile preprocessFileLineNumbers "\z\addons\dayz_code\compile\player_antiWall.sqf";

View File

@@ -767,7 +767,6 @@ if(!isDedicated) then {
// dayzDebug = true;
//};
dayz_onBack = "";
dayz_onBackActive = false;
DZE_ActionInProgress = false;
// DayZ Epoch Client only variables

View File

@@ -0,0 +1,61 @@
/* Provides functions for working with arrays.
Author: Foxy
*/
#ifndef _INCLUDE_GUARD_ARRAY
#define _INCLUDE_GUARD_ARRAY
//Get or set the element at specific index.
#define Array_Get(array, index) ((array) select (index))
#define Array_Set(array, index, value) ((array) set [index, value])
//Atomically retrieve and replace the value at specified index.
#define Array_GetSet(array, index, value) ([array, index, value] call dz_fn_array_getSet)
#define Array_GetSet_Fast(array, index, value) ([(array) select (index), (array) set [index, value]] select 0)
//Returns true if any of the array elements matches the specified predicate
#define Array_Any(arr, predicate) ([arr, predicate] call dz_fn_array_any)
//Returns true if all of the array elements match the specified predicate
#define Array_All(p_arr,p_pred) ([arr, predicate] call dz_fn_array_all)
//Returns the first element of the array that matches the specified predicate
#define Array_First(arr, predicate) ([arr, predicate] call dz_fn_array_first)
//Selects a random element from the specified array
#define Array_SelectRandom(arr) ((arr) call dz_fn_array_selectRandom)
#define Array_SelectRandom_Fast(arr) ((arr) select floor random count (arr))
//Shuffles the given array. Modifies the passed in array and returns it.
//To preserve the original pass in a copy: Array_Shuffle(+myArray)
//Algorithm: Fisher-Yates Complexity: O(n)
#define Array_Shuffle(arr) ((arr) call dz_fn_array_shuffle)
//Sorts the given array using specified comparer function.
//To preserve the original pass in a copy: Array_MergeSort(+myArray, myComparer)
//Algorithm: Merge Sort Complexity: O(n log n)
#define Array_MergeSort(arr, comparer) ([arr, comparer] call dz_fn_array_mergeSort)
//Array initialization macros for passing arrays as macro arguments.
#define Array_New() []
#define Array_New1(p0) [p0]
#define Array_New2(p0,p1) [p0,p1]
#define Array_New3(p0,p1,p2) [p0,p1,p2]
#define Array_New4(p0,p1,p2,p3) [p0,p1,p2,p3]
#define Array_New5(p0,p1,p2,p3,p4) [p0,p1,p2,p3,p4]
#define Array_New6(p0,p1,p2,p3,p4,p5) [p0,p1,p2,p3,p4,p5]
#define Array_New7(p0,p1,p2,p3,p4,p5,p6) [p0,p1,p2,p3,p4,p5,p6]
#define Array_New8(p0,p1,p2,p3,p4,p5,p6,p7) [p0,p1,p2,p3,p4,p5,p6,p7]
#define Array_New9(p0,p1,p2,p3,p4,p5,p6,p7,p8) [p0,p1,p2,p3,p4,p5,p6,p7,p8]
#define Array_New10(p0,p1,p2,p3,p4,p5,p6,p7,p8,p9) [p0,p1,p2,p3,p4,p5,p6,p7,p8,p9]
#define Array_New11(p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10) [p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10]
#define Array_New12(p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11) [p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11]
#define Array_New13(p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12) [p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12]
#define Array_New14(p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12,p13) [p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12,p13]
#define Array_New15(p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12,p13,p14) [p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12,p13,p14]
#define Array_New16(p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12,p13,p14,p15) [p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12,p13,p14,p15]
#endif

View File

@@ -0,0 +1,121 @@
/* Defines macros for debugging.
Care must be taken to only include this header once as it cannot use an include guard.
The _DEBUG_ constant can be used outside this header to define custom debug code.
Author: Foxy
P.s. Why does this piece of shit not have variadic macros?!
*/
//Comment out to disable debugging
//#define _DEBUG_
//DEBUG ENABLED
#ifdef _DEBUG_
//Logs the specified value
#define Debug_Log(val) (diag_log str (val))
/* Logs generic debug information
File name
Line number
Tick time
Frame number
*/
#define Debug_LogGeneric() (diag_log format ["DEBUG: File:%1 Line:%2 Time:%3 Frame:%4", __FILE__, __LINE__, diag_tickTime, diag_frameno])
//Assert
#define Debug_Assert(condition) (assert (condition))
/* Validates the array member types.
Example:
//Scalar, string and array
Debug_CheckTypes3("SCALAR","STRING","ARRAY");
//Boolean and scalar or string
Debug_CheckTypes2("BOOL",Array_New2("SCALAR","STRING"));
//Object or nil and any
Debug_CheckTypes2(Array_New2("OBJECT","NIL"),"ANY");
See https://community.bistudio.com/wiki/Data_Types
*/
#define Debug_CheckTypes1(arr, p0) ([arr,[p0],__FILE__,__LINE__] call dz_fn_debug_checkTypes)
#define Debug_CheckTypes2(arr, p0,p1) ([arr,[p0,p1],__FILE__,__LINE__] call dz_fn_debug_checkTypes)
#define Debug_CheckTypes3(arr, p0,p1,p2) ([arr,[p0,p1,p2],__FILE__,__LINE__] call dz_fn_debug_checkTypes)
#define Debug_CheckTypes4(arr, p0,p1,p2,p3) ([arr,[p0,p1,p2,p3],__FILE__,__LINE__] call dz_fn_debug_checkTypes)
#define Debug_CheckTypes5(arr, p0,p1,p2,p3,p4) ([arr,[p0,p1,p2,p3,p4],__FILE__,__LINE__] call dz_fn_debug_checkTypes)
#define Debug_CheckTypes6(arr, p0,p1,p2,p3,p4,p5) ([arr,[p0,p1,p2,p3,p4,p5],__FILE__,__LINE__] call dz_fn_debug_checkTypes)
#define Debug_CheckTypes7(arr, p0,p1,p2,p3,p4,p5,p6) ([arr,[p0,p1,p2,p3,p4,p5,p6],__FILE__,__LINE__] call dz_fn_debug_checkTypes)
#define Debug_CheckTypes8(arr, p0,p1,p2,p3,p4,p5,p6,p7) ([arr,[p0,p1,p2,p3,p4,p5,p6,p7],__FILE__,__LINE__] call dz_fn_debug_checkTypes)
#define Debug_CheckTypes9(arr, p0,p1,p2,p3,p4,p5,p6,p7,p8) ([arr,[p0,p1,p2,p3,p4,p5,p6,p7,p8],__FILE__,__LINE__] call dz_fn_debug_checkTypes)
#define Debug_CheckTypes10(arr, p0,p1,p2,p3,p4,p5,p6,p7,p8,p9) ([arr,[p0,p1,p2,p3,p4,p5,p6,p7,p8,p9],__FILE__,__LINE__] call dz_fn_debug_checkTypes)
#define Debug_CheckTypes11(arr, p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10) ([arr,[p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10],__FILE__,__LINE__] call dz_fn_debug_checkTypes)
#define Debug_CheckTypes12(arr, p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11) ([arr,[p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11],__FILE__,__LINE__] call dz_fn_debug_checkTypes)
#define Debug_CheckTypes13(arr, p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12) ([arr,[p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12],__FILE__,__LINE__] call dz_fn_debug_checkTypes)
#define Debug_CheckTypes14(arr, p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12,p13) ([arr,[p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12,p13],__FILE__,__LINE__] call dz_fn_debug_checkTypes)
#define Debug_CheckTypes15(arr, p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12,p13,p14) ([arr,[p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12,p13,p14],__FILE__,__LINE__] call dz_fn_debug_checkTypes)
#define Debug_CheckTypes16(arr, p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12,p13,p14,p15) ([arr,[p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12,p13,p14,p15],__FILE__,__LINE__] call dz_fn_debug_checkTypes)
//See Debug_CheckTypes. Used for checking script parameters.
#define Debug_CheckParams1(p0) Debug_CheckTypes1(_this,p0)
#define Debug_CheckParams2(p0,p1) Debug_CheckTypes2(_this,p0,p1)
#define Debug_CheckParams3(p0,p1,p2) Debug_CheckTypes3(_this,p0,p1,p2)
#define Debug_CheckParams4(p0,p1,p2,p3) Debug_CheckTypes4(_this,p0,p1,p2,p3)
#define Debug_CheckParams5(p0,p1,p2,p3,p4) Debug_CheckTypes5(_this,p0,p1,p2,p3,p4)
#define Debug_CheckParams6(p0,p1,p2,p3,p4,p5) Debug_CheckTypes6(_this,p0,p1,p2,p3,p4,p5)
#define Debug_CheckParams7(p0,p1,p2,p3,p4,p5,p6) Debug_CheckTypes7(_this,p0,p1,p2,p3,p4,p5,p6)
#define Debug_CheckParams8(p0,p1,p2,p3,p4,p5,p6,p7) Debug_CheckTypes8(_this,p0,p1,p2,p3,p4,p5,p6,p7)
#define Debug_CheckParams9(p0,p1,p2,p3,p4,p5,p6,p7,p8) Debug_CheckTypes9(_this,p0,p1,p2,p3,p4,p5,p6,p7,p8)
#define Debug_CheckParams10(p0,p1,p2,p3,p4,p5,p6,p7,p8,p9) Debug_CheckTypes10(_this,p0,p1,p2,p3,p4,p5,p6,p7,p8,p9)
#define Debug_CheckParams11(p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10) Debug_CheckTypes11(_this,p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10)
#define Debug_CheckParams12(p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11) Debug_CheckTypes12(_this,p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11)
#define Debug_CheckParams13(p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12) Debug_CheckTypes13(_this,p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12)
#define Debug_CheckParams14(p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12,p13) Debug_CheckTypes14(_this,p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12,p13)
#define Debug_CheckParams15(p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12,p13,p14) Debug_CheckTypes15(_this,p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12,p13,p14)
#define Debug_CheckParams16(p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12,p13,p14,p15) Debug_CheckTypes16(_this,p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12,p13,p14,p15)
// DEBUG DISABLED
#else
#define Debug_Log(val)
#define Debug_LogGeneric()
#define Debug_Assert(condition)
#define Debug_CheckTypes1(arr,p0)
#define Debug_CheckTypes2(arr,p0,p1)
#define Debug_CheckTypes3(arr,p0,p1,p2)
#define Debug_CheckTypes4(arr,p0,p1,p2,p3)
#define Debug_CheckTypes5(arr,p0,p1,p2,p3,p4)
#define Debug_CheckTypes6(arr,p0,p1,p2,p3,p4,p5)
#define Debug_CheckTypes7(arr,p0,p1,p2,p3,p4,p5,p6)
#define Debug_CheckTypes8(arr,p0,p1,p2,p3,p4,p5,p6,p7)
#define Debug_CheckTypes9(arr,p0,p1,p2,p3,p4,p5,p6,p7,p8)
#define Debug_CheckTypes10(arr,p0,p1,p2,p3,p4,p5,p6,p7,p8,p9)
#define Debug_CheckTypes11(arr,p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10)
#define Debug_CheckTypes12(arr,p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11)
#define Debug_CheckTypes13(arr,p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12)
#define Debug_CheckTypes14(arr,p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12,p13)
#define Debug_CheckTypes15(arr,p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12,p13,p14)
#define Debug_CheckTypes16(arr,p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12,p13,p14,p15)
#define Debug_CheckParams1(p0)
#define Debug_CheckParams2(p0,p1)
#define Debug_CheckParams3(p0,p1,p2)
#define Debug_CheckParams4(p0,p1,p2,p3)
#define Debug_CheckParams5(p0,p1,p2,p3,p4)
#define Debug_CheckParams6(p0,p1,p2,p3,p4,p5)
#define Debug_CheckParams7(p0,p1,p2,p3,p4,p5,p6)
#define Debug_CheckParams8(p0,p1,p2,p3,p4,p5,p6,p7)
#define Debug_CheckParams9(p0,p1,p2,p3,p4,p5,p6,p7,p8)
#define Debug_CheckParams10(p0,p1,p2,p3,p4,p5,p6,p7,p8,p9)
#define Debug_CheckParams11(p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10)
#define Debug_CheckParams12(p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11)
#define Debug_CheckParams13(p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12)
#define Debug_CheckParams14(p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12,p13)
#define Debug_CheckParams15(p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12,p13,p14)
#define Debug_CheckParams16(p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12,p13,p14,p15)
#endif
//Type check define generator http://pastebin.com/kBTVtBzz

View File

@@ -0,0 +1,29 @@
/* Defines member functions for a dictionary class.
Can be used to associate data with a key.
See https://en.wikipedia.org/wiki/Associative_array
Author: Foxy
*/
#ifndef _INCLUDE_GUARD_DICTIONARY
#define _INCLUDE_GUARD_DICTIONARY
//Initializes a new dictionary
#define Dictionary_New() [0, [], []]
//Adds a key value pair to the specified dictionary.
#define Dictionary_Add(d, key, value) ([d, key, value] call dz_fn_dictionary_add)
//Removes a value from the dictionary using specified key.
#define Dictionary_Remove(d, key) ([d, key] call dz_fn_ictionary_remove)
//Retrieves a value from the dictionary using specified key.
#define Dictionary_Get(d, key) ([d, key] call dz_fn_dictionary_get)
//Determines whether the dictionary contains the specified key.
#define Dictionary_ContainsKey(d, key) ([d, key] call dz_fn_dictionary_containsKey)
//Rearranges the internal data structure of the dictionary to free unused memory.
#define Dictionary_Compact(d) ((d) call dz_fn_dictionary_compact)
#endif

View File

@@ -0,0 +1,22 @@
/* Defines generic math functions.
Author: Foxy
*/
#ifndef _INCLUDE_GUARD_MATH
#define _INCLUDE_GUARD_MATH
//Calculates the greatest common divisor of two numbers
#define Math_GCD(a, b) ([a, b] call dz_fn_math_gcd)
//Calculates the greatest common divisor of all elements of the given array
#define Math_GCDArray(a) ((a) call dz_fn_math_gcdx)
//Selects a random value in the specified range [min, max)
#define Math_RandomRange(min, max) ([min, max] call dz_fn_math_randomRange)
#define Math_RandomRange_Fast(min, max) ((min) + random ((max) - (min)))
//Restricts a value to the specified range [pmin, pmax]
#define Math_Clamp(value, pmin, pmax) (pmin max (pmax min value))
#endif

View File

@@ -0,0 +1,28 @@
/* Provides a simple mutex implementation.
See https://en.wikipedia.org/wiki/Mutual_exclusion
Author: Foxy
*/
#ifndef _INCLUDE_GUARD_MUTEX
#define _INCLUDE_GUARD_MUTEX
//Initializes a new unlocked mutex.
#define Mutex_New() [true]
//Attempts to lock the specified mutex. Returns true if the mutex was locked.
#define Mutex_TryLock(mtx) ((mtx) call dz_fn_mutex_tryLock)
#define Mutex_TryLock_Fast(mtx) ([(mtx) select 0, (mtx) set [0, false]] select 0)
//Determines if the mutex is locked.
//Note: if access to critical section is required use TryLock() instead.
#define Mutex_IsLocked(mtx) (!(mtx) select 0)
//Waits until the mutex becomes available and locks it.
#define Mutex_WaitLock(mtx) ((mtx) call dz_fn_mutex_waitLock)
#define Mutex_WaitLock_Fast(mtx) waitUntil {Mutex_TryLock_Fast(mtx)}
//Unlocks the mutex. Use only when you have previously obtained lock yourself.
#define Mutex_Unlock(mtx) ((mtx) set [0, true])
#endif

View File

@@ -0,0 +1,43 @@
/* Defines functions working with the player object.
Author: Foxy
*/
#ifndef _INCLUDE_GUARD_PLAYER
#define _INCLUDE_GUARD_PLAYER
#define Player_BASE "DZ_PlayerBase_M"
//True if player is on a ladder, otherwise false
#define Player_IsOnLadder() ((getNumber (configFile >> "CfgMovesMaleSdr" >> "States" >> (animationState player) >> "onLadder")) == 1)
#define Player_IsInVehicle() (player != vehicle player);
//Gets the classname of the player's sidearm. nil if the player has no sidearm.
#define Player_GetSidearm() ({ if ((getNumber (configFile >> "CfgWeapons" >> _x >> "type")) == 2) exitWith { _x }; nil } foreach weapons player)
//Returns the number of slots in of the specified type in the player inventory.
#define Player_NumSlots(type) (dz_player_invSlots select (dz_player_invTypes find (type)))
//Returns the number of empty slots of the specified type in the player inventory.
#define Player_NumEmptySlots(type) ((type) call dz_fn_player_numEmptySlots)
//Returns the number of items of the specified type in the player inventory.
#define Player_NumItems(type) ((type) call dz_fn_player_numItems)
/* Adds the specified item to player inventory, vehicle inventory, or on the ground below.
Return value indicates if and where the item was placed. */
#define Player_AddWeapon(class) ([0, class] call dz_fn_player_addItem)
#define Player_AddMagazine(class) ([1, class] call dz_fn_player_addItem)
#define Player_AddItem_RESULT_FAILURE 0
#define Player_AddItem_RESULT_PLAYER 1
#define Player_AddItem_RESULT_GROUND 2
#define Player_AddItem_RESULT_VEHICLE 3
/* Adds the specifed item on the ground at the player's feet.
The weaponholder containing the item is returned. Returns null if the function fails.*/
#define Player_DropWeapon(class) ([0, class] call dz_fn_player_dropItem)
#define Player_DropMagazine(class) ([1, class] call dz_fn_player_dropItem)
#endif

View File

@@ -0,0 +1,36 @@
/* Provides a FIFO data structure implementation.
See https://en.wikipedia.org/wiki/FIFO_(computing_and_electronics)
Author: Foxy
*/
#ifndef _INCLUDE_GUARD_QUEUE
#define _INCLUDE_GUARD_QUEUE
//Initializes a new queue with the specified size
#define Queue_New(size) ((size) call dz_fn_queue_new)
//Attempts to add the specified object to the end of the queue.
//Returns false if queue is full, otherwise true.
#define Queue_Enqueue(q, element) ([q, element] call dz_fn_queue_enqueue)
//Attempts to remove the first object from the head of the queue.
//Returns nil if queue is empty.
#define Queue_Dequeue(q) ((q) call dz_fn_queue_dequeue)
//Attempts to retrieve the first object from the head of the queue without removing it.
//Returns nil if queue is empty.
#define Queue_Peek(q) ((q) call dz_fn_queue_peek)
//Returns the maximum capacity of the queue.
#define Queue_Size(q) (count ((q) select 2))
//Returns the number of items in the queue.
#define Queue_Count(q) ((q) select 0)
//Determines whether the queue is full.
#define Queue_IsFull(q) ((q) call dz_fn_queue_isFull)
//#define Queue_Resize(q, s) ([q, s] call dz_fn_queue_resize)
#endif

View File

@@ -0,0 +1,19 @@
/* Provides means for passing objects by reference.
Reference cannot point to itself or create a loop of references.
Author: Foxy
*/
#ifndef _INCLUDE_GUARD_REFERENCE
#define _INCLUDE_GUARD_REFERENCE
//Initializes a new reference pointing to the specified object.
#define Ref_New(val) [val]
//Retrieves the object pointed to by the reference.
#define Ref_Get(ref) ((ref) select 0)
//Sets the reference to point to the specified object.
#define Ref_Set(ref, val) ((ref) set [0, val])
#endif

View File

@@ -0,0 +1,49 @@
/* Provides means for a client to send requests to the server and subsequently receive a reply.
Do not use this header on the server.
Author: Foxy*/
#include "Dictionary.hpp"
#ifndef _INCLUDE_GUARD_REQUEST
#define _INCLUDE_GUARD_REQUEST
assert (!isServer);
#define Request_IsInitialized() (!isNil "dz_owner")
//Waits for initialization to be completed.
#define Request_WaitInit() waitUntil {Request_IsInitialized()}
/* Send request to server.
Parameters:
string/scalar request
Request type. Various request types can be defined by the server.
See Request_Server.hpp.
any args
Argument(s) sent to the server.
boolean reply
Whether a reply is wanted from the server.
Return:
Request object which or can be waited and provides the result once completed.
See Request_Wait() and Request_GetResult().
Returns nil if no reply is expected.
Example:
_myRequest = Request_Send("GetDate", nil, true);
Request_Wait(_myRequest);
_myDate = Request_GetResult(_myRequest);
*/
#define Request_Send(request, args, reply) ([request, args, reply] call dz_fn_request_send)
//Determines whether the specified request is completed.
#define Request_IsDone(request) (count (request) > 2)
//Waits for the request to complete.
#define Request_Wait(request) waitUntil {Request_IsDone(request)}
//Retrieves the result of the request.
#define Request_GetResult(request) ((request) select 2)
#undef

View File

@@ -0,0 +1,33 @@
/* See Request.hpp
Do not use this header on the client.
Author: Foxy
*/
#include "Array.hpp"
#include "Dictionary.hpp"
#ifndef _INCLUDE_GUARD_REQUEST
#define _INCLUDE_GUARD_REQUEST
assert (isServer);
/* Registers a request handler.
Parameters:
string/scalar id
String or number used as an identifier for the function.
String identifiers are case sensitive.
code handler
Function that handles the request.
If handler return nil an empty array is instead sent to the client.
boolean async
Indicates whether the request should be handled asynchronously (handler is spawned).
Example:
Request_RegisterHandler("GetDate", {my_global_date_variable}, false);
Request_RegisterHandler("GetObjectOwner", {owner _this}, false);
Request_RegisterHandler("DoSomething", _my_complicated_asynchronous_handler, true);
*/
#define Request_RegisterHandler(id, handler, async) Dictionary_Add(dz_request_handlers, id, Array_New2(handler, async))
#undef

View File

@@ -0,0 +1,30 @@
/* Provides a LIFO data structure implementation.
See https://en.wikipedia.org/wiki/Stack_(abstract_data_type)
Author: Foxy
*/
#ifndef _INCLUDE_GUARD_STACK
#define _INCLUDE_GUARD_STACK
//Initializes a new stack object
#define Stack_New() [0,[nil,nil]]
//Pushes the specified object onto the top of the stack.
#define Stack_Push(s, element) ([s, element] call dz_fn_stack_push)
//Removes the object on top of the stack and returns it.
//Returns nil if the stack is empty.
#define Stack_Pop(s) ((s) call dz_fn_stack_pop)
//Retrieves the object on top of the stack without removing it.
//Returns nil if the stack is empty.
#define Stack_Peek(s) ((s) call dz_fn_stack_peek)
//Returns the current capacity of the stack.
//#define Stack_Size(s) (count ((s) select 1))
//Returns the number of items currently on the stack.
#define Stack_Count(stack) ((stack) select 0)
#endif

View File

@@ -0,0 +1,22 @@
#ifndef _INCLUDE_GUARD_STRING
#define _INCLUDE_GUARD_STRING
//Same as format [STRING, ANY...]
#define String_Format1(string,p0) (format [string,p0])
#define String_Format2(string,p0,p1) (format [string,p0,p1])
#define String_Format3(string,p0,p1,p2) (format [string,p0,p1,p2])
#define String_Format4(string,p0,p1,p2,p3) (format [string,p0,p1,p2,p3])
#define String_Format5(string,p0,p1,p2,p3,p4) (format [string,p0,p1,p2,p3,p4])
#define String_Format6(string,p0,p1,p2,p3,p4,p5) (format [string,p0,p1,p2,p3,p4,p5])
#define String_Format7(string,p0,p1,p2,p3,p4,p5,p6) (format [string,p0,p1,p2,p3,p4,p5,p6])
#define String_Format8(string,p0,p1,p2,p3,p4,p5,p6,p7) (format [string,p0,p1,p2,p3,p4,p5,p6,p7])
#define String_Format9(string,p0,p1,p2,p3,p4,p5,p6,p7,p8) (format [string,p0,p1,p2,p3,p4,p5,p6,p7,p8])
#define String_Format10(string,p0,p1,p2,p3,p4,p5,p6,p7,p8,p9) (format [string,p0,p1,p2,p3,p4,p5,p6,p7,p8,p9])
#define String_Format11(string,p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10) (format [string,p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10])
#define String_Format12(string,p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11) (format [string,p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11])
#define String_Format13(string,p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12) (format [string,p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12])
#define String_Format14(string,p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12,p13) (format [string,p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12,p13])
#define String_Format15(string,p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12,p13,p14) (format [string,p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12,p13,p14])
#define String_Format16(string,p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12,p13,p14,p15) (format [string,p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12,p13,p14,p15])
#endif

View File

@@ -0,0 +1,41 @@
/* Provides means for monitoring the execution and retrieving the result of asynchronous operations.
Author: Foxy
*/
#ifndef _INCLUDE_GUARD_TASK
#define _INCLUDE_GUARD_TASK
//Creates a new task using the specified function
#define Task_New(fnc) [fnc, nil, 0, nil]
//Starts the task with the specified parameters.
//Returns the task if succesfully started, otherwise nil.
#define Task_Start(task, params) ([task, params] call dz_fn_task_start)
//Cancels a currently running task.
//Returns true if succesfully canceled, otherwise false.
#define Task_Cancel(task) ([task] call dz_fn_task_cancel)
//Gets the task result. Returns nil if not completed.
//Note that nil may also be returned if the task function did not return a value.
#define Task_Result(task) ((task) select 3)
//Waits for the task to complete and returns the result.
//Cannot be called in the unscheduled environment.
//Waits for completion even if the task has not yet been started.
#define Task_Wait(task) ((task) call dz_fn_task_wait)
//Determines whether the task has been started (may have since completed or been canceled).
#define Task_IsStarted(task) (((task) select 2) != 0)
//Determines whether the task is currently running.
#define Task_IsRunning(task) (((task) select 2) == 1)
//Determines whether the task has completed normally.
#define Task_IsCompleted(task) (((task) select 2) == 2)
//Determines whether the task has canceled prior to completion.
#define Task_IsCanceled(task) (((task) select 2) == 3)
#endif

View File

@@ -0,0 +1,26 @@
#ifndef _INCLUDE_GUARD_UTIL
#define _INCLUDE_GUARD_UTIL
//Returns true if the current script is running in the unscheduled environment and otherwise false.
//If true a script error is also produced however this can be ignored.
//#define Util_IsUncheduled() ([diag_frameNo, sleep 0.005, diag_frameNo] call { _this select 0 == _this select 2 })
/* Send public variables atomically without fear of race conditions. The previous value of the
variable is restored automatically after transmission. For example:
my_variable = 1;
Util_PublicVariable(my_variable, 1337);
diag_log str my_variable; //1
*/
#define Util_PublicVariable(variable, value) ([variable, value] call dz_fn_util_pv)
#define Util_PublicVariable_Fast(variable, value) (missionNamespace setVariable [variable, [missionNamespace getVariable (variable), missionNamespace setVariable [variable, value], publicVariable (variable)] select 0])
#define Util_PublicVariableServer(variable, value) ([variable, value] call dz_fn_util_pvs)
#define Util_PublicVariableServer_Fast(variable, value) (missionNamespace setVariable [variable, [missionNamespace getVariable (variable), missionNamespace setVariable [variable, value], publicVariableServer (variable)] select 0])
#define Util_PublicVariableClient(variable, value, client) ([variable, value, client] call dz_fn_util_pvc)
#define Util_PublicVariableClient_Fast(variable, value, client) (missionNamespace setVariable [variable, [missionNamespace getVariable (variable), missionNamespace setVariable [variable, value], (client) publicVariableClient (variable)] select 0])
//Waits until the specified predicate is true, or at most the specified time in seconds.
//Returns true if the predicate is true, false if timed out.
//Note: the predicate is evaluated once each frame. Expensive operations may cause performance issues.
#define Util_WaitUntil(predicate, timeout) ([_this, predicate, timeout, diag_tickTime] call dz_fn_util_waitUntil)
#endif

View File

@@ -0,0 +1,87 @@
/* Provides functions and constants for working with 3D vectors.
Author: Foxy
*/
#ifndef _INCLUDE_GUARD_VECTOR
#define _INCLUDE_GUARD_VECTOR
//Vector constants
#define Vector_NULL [ 0, 0, 0]
#define Vector_UP [ 0, 0, 1]
#define Vector_DOWN [ 0, 0,-1]
#define Vector_NORTH [ 0, 1, 0]
#define Vector_SOUTH [ 0,-1, 0]
#define Vector_EAST [ 1, 0, 0]
#define Vector_WEST [-1, 0, 0]
#define Vector_FRONT Vector_NORTH
#define Vector_BACK Vector_SOUTH
#define Vector_RIGHT Vector_EAST
#define Vector_LEFT Vector_WEST
#define Vector_New(x,y,z) [z,y,z]
//Accessors
#define Vector_X(v) ((v) select 0)
#define Vector_Y(v) ((v) select 1)
#define Vector_Z(v) ((v) select 2)
//Setters
#define Vector_SetX(v, x) ((v) set [0, x])
#define Vector_SetY(v, x) ((v) set [1, x])
#define Vector_SetZ(v, x) ((v) set [2, x])
//Calculates the dot product of the given vectors
#define Vector_DotProduct(a,b) ([a,b] call dz_fn_vector_dotProduct)
#define Vector_DotProduct_Fast(a,b) (Vector_X(a) * Vector_X(b) + Vector_Y(a) * Vector_Y(b) + Vector_Z(a) * Vector_Z(b))
//Calculates the cross product of the given vectors
#define Vector_CrossProduct(a,b) ([a,b] call dz_fn_vector_crossProduct)
#define Vector_CrossProduct_Fast(a,b) [Vector_Y(a) * Vector_Z(b) - Vector_Z(a) * Vector_Y(b), Vector_Z(a) * Vector_X(b) - Vector_X(a) * Vector_Z(b), Vector_X(a) * Vector_Y(b) - Vector_Y(a) * Vector_X(b)]
//Magnitude (length) of the vector
#define Vector_Magnitude(v) ((v) call dz_fn_vector_magnitude)
#define Vector_Magnitude_Fast(v) (sqrt( Vector_X(v)^2 + Vector_Y(v)^2 + Vector_Z(v)^2))
//Adds two vectors together
#define Vector_Add(a,b) ([a,b] call dz_fn_vector_add)
#define Vector_Add_Fast(a,b) [Vector_X(a) + Vector_X(b), Vector_Y(a) + Vector_Y(b), Vector_Z(a) + Vector_Z(b)]
//Subtract second vector from the first
#define Vector_Subtract(a,b) ([a,b] call dz_fn_vector_subtract)
#define Vector_Subtract_Fast(a,b) [Vector_X(a) - Vector_X(b), Vector_Y(a) - Vector_Y(b), Vector_Z(a) - Vector_Z(b)]
//Returns the opposite vector of the given vector
#define Vector_Negate(v) ((v) call dz_fn_vector_negate)
#define Vector_Negate_Fast(v) [-Vector_X(v), -Vector_Y(v), -Vector_Z(v)]
//Multiplies the vector by a real number
#define Vector_Multiply(v,d) ([v,d] call dz_fn_vector_multiply)
#define Vector_Multiply_Fast(v,d) [Vector_X(v) * (d), Vector_Y(v) * (d), Vector_Z(v) * (d)]
//Divides the vector by a real number
#define Vector_Divide(v,d) ([v,d] call dz_fn_vector_divide)
#define Vector_Divide_Fast(v,d) [Vector_X(v) / (d), Vector_Y(v) / (d), Vector_Z(v) / (d)]
//Calculates the angle between two given vectors
#define Vector_Angle(a,b) ([a,b] call dz_fn_vector_angle)
#define Vector_Angle_Fast(a,b) (acos(Vector_DotProduct_Fast(a,b) / Vector_Magnitude_Fast(a) * Vector_Magnitude_Fast(b)))
//Returns a vector with the same direction as the argument and a magnitude of 1.
#define Vector_Normalize(v) ((v) call dz_fn_vector_normalize)
#define Vector_Normalize_Fast(v) Vector_Divide(v, Vector_Magnitude_Fast(v))
//TODO: performance profiling Divide vs Divide_Fast
//Returns a horizontal unit vector pointing in the specified direction (degrees).
#define Vector_FromDir(deg) ((deg) call dz_fn_vector_fromDir)
#define Vector_FromDir_Fast(deg) [sin (deg), cos (deg), 0]
//Rotates the vector around the global Z (up) axis by the specified angle in degrees
#define Vector_Rotate2D(v, deg) ([v, deg] call dz_fn_vector_rotate2d)
#define Vector_Rotate2D_Fast(v, deg) [Vector_X(v) * cos -(deg) - Vector_Y(v) * sin -(deg), Vector_X(v) * sin -(deg) + Vector_Y(v) * cos -(deg), Vector_Z(v)]
//Rotates the vector around the specified axis by the specified angle in degrees, in three dimensions.
#define Vector_Rotate3D(v, u, deg) ([v, u, deg] call dz_fn_vector_rotate3d)
#define Vector_Rotate3D_Fast(v, u, deg) [((v)select0)*(((u)select0)^2*(1-cos(deg))+cos(deg))+((v)select1)*(((u)select0)*((u)select1)*(1-cos(deg))-((u)select2)*sin(deg))+((v)select2)*(((u)select0)*((u)select2)*(1-cos(deg))+((u)select1)*sin(deg)),((v)select0)*(((u)select1)*((u)select0)*(1-cos(deg))+((u)select2)*sin(deg))+((v)select1)*(((u)select1)^2*(1-cos(deg))+cos(deg))+((v)select2)*(((u)select1)*((u)select2)*(1-cos(deg))-((u)select0)*sin(deg)),((v)select0)*(((u)select2)*((u)select0)*(1-cos(deg))-((u)select1)*sin(deg))+((v)select1)*(((u)select2)*((u)select1)*(1-cos(deg))+((u)select0)*sin(deg))+((v)select2)*(((u)select2)^2*(1-cos(deg))+cos(deg))]
#endif

View File

@@ -0,0 +1,137 @@
#include "Array.hpp"
//Returns true if the given predicate evaluates to true for any element in the array
dz_fn_array_any =
{
{
if (_x call (_this select 1)) exitWith { true };
false
}
foreach (_this select 0);
};
//Returns true if the given predicate evaluates to true for all elements in the array
dz_fn_array_all =
{
{
if !(_x call (_this select 1)) exitWith { false };
true
}
foreach (_this select 0);
};
//Returns the first element in the array for which the given predicate evaluates to true. nil if not found
dz_fn_array_first =
{
{
if (_x call (_this select 1)) exitWith { _x };
nil
}
foreach (_this select 0);
};
dz_fn_array_getSet =
{
Array_GetSet_Fast(_this select 0, _this select 1, _this select 2);
};
//Selects a random element from the array
dz_fn_array_selectRandom =
{
_this select floor random count _this
};
//Shuffle using the Fisher-Yates algorithm. Complexity: O(n)
dz_fn_array_shuffle =
{
private ["_i", "_r", "_t"];
for "_i" from (count _this) - 1 to 1 step -1 do
{
//Select random index
_r = floor random (_i + 1);
//Swap
if (_i != _r) then
{
_t = _this select _i;
_this set [_i, _this select _r];
_this set [_r, _t];
};
};
_this
};
dz_fn_array_mergeSort =
{
private ["_offset", "_length", "_alen", "_blen", "_ai", "_bi", "_temp"];
//Root call
if (count _this == 2) then
{
_offset = 0;
_length = count (_this select 0);
}
//Recursive call
else
{
_offset = _this select 2;
_length = _this select 3;
};
if (_length <= 1) exitWith {};
_alen = round (_length / 2);
_blen = _length - _alen;
[_this select 0, _this select 1, _offset, _alen] call dz_fn_array_mergeSort;
[_this select 0, _this select 1, _offset + _alen, _blen] call dz_fn_array_mergeSort;
_ai = 0;
_bi = 0;
_temp = [];
_temp resize _length;
#define A_NEXT (_this select 0) select (_offset + _ai)
#define B_NEXT (_this select 0) select (_offset + _alen + _bi)
for "_i" from 0 to _length - 1 do
{
switch (true) do
{
case (_ai == _alen):
{
_temp set [_i, B_NEXT];
_bi = _bi + 1;
};
case (_bi == _blen):
{
_temp set [_i, A_NEXT];
_ai = _ai + 1;
};
case (([A_NEXT, B_NEXT] call (_this select 1)) > 0):
{
_temp set [_i, A_NEXT];
_ai = _ai + 1;
};
default
{
_temp set [_i, B_NEXT];
_bi = _bi + 1;
};
};
};
#undef A_NEXT
#undef B_NEXT
for "_i" from 0 to _length - 1 do
{
(_this select 0) set [_offset + _i, _temp select _i];
};
_this select 0
};

View File

@@ -0,0 +1,22 @@
#define STRINGIFY(x) #x
#define PATH(sub_path) STRINGIFY(\z\addons\dayz_code\util\sub_path)
#define CCPP call compile preprocessFileLineNumbers
//Debug
CCPP PATH(debug.sqf);
//Very generic utilities
CCPP PATH(util.sqf);
CCPP PATH(mutex.sqf);
CCPP PATH(math.sqf);
CCPP PATH(array.sqf);
//Collections
CCPP PATH(stack.sqf);
CCPP PATH(queue.sqf);
CCPP PATH(dictionary.sqf);
//Specialized
CCPP PATH(vector.sqf);
CCPP PATH(task.sqf);
CCPP PATH(request.sqf);

View File

@@ -0,0 +1,42 @@
#include "Debug.hpp"
#ifdef _DEBUG_
dz_fn_debug_checkType =
{
#define IS_ARRAY(x) (typeName x == typeName [])
if (_exp == "ANY")
exitWith { true };
if (isNil "_x")
exitWith { _exp == "NIL" || { IS_ARRAY(_exp) && { "NIL" in _exp } } };
typeName _x == _exp || { IS_ARRAY(_exp) && { typeName _x in _exp } }
#undef IS_ARRAY
};
dz_fn_debug_checkTypes =
{
private "_exp";
{
_exp = (_this select 1) select (_foreachIndex min (count (_this select 1) - 1));
if (!call dz_fn_debug_checkType) then
{
assert false;
diag_log format ['ERROR: Type check failed in file "%1" on line %2. Index:%3 Type:%4 Expected:%5',
_this select 2,
_this select 3,
_foreachIndex,
if (isNil "_x") then { "nil" } else { typeName _x },
_exp];
};
}
foreach (_this select 0);
};
#endif

View File

@@ -0,0 +1,67 @@
#define GET_COUNT(d) ((d) select 0)
#define SET_COUNT(d, c) ((d) set [0, c])
#define GET_SIZE(d) (count GET_KEYS(d))
#define GET_KEYS(d) ((d) select 1)
#define GET_VALUES(d) ((d) select 2)
#define GET_INDEX(d, k) (GET_KEYS(d) find (k))
dz_fn_dictionary_containsKey =
{
GET_INDEX(_this select 0, _this select 1) != -1
};
dz_fn_dictionary_add =
{
if (GET_INDEX(_this select 0, _this select 1) == -1) exitWith {false};
private "_index";
_index = count GET_KEYS(_this select 0);
GET_KEYS(_this select 0) set [_index, _this select 1];
GET_VALUES(_this select 0) set [_index, _this select 2];
SET_COUNT(_this select 0, GET_COUNT(_this select 0) + 1);
true
};
dz_fn_dictionary_get =
{
private "_index";
_index = GET_INDEX(_this select 0, _this select 1);
if (_index == -1) exitWith {nil};
GET_VALUES(_this select 0) select _index
};
dz_fn_dictionary_remove =
{
private "_index";
_index = GET_INDEX(_this select 0, _this select 1);
if (_index == -1) exitWith {false};
GET_KEYS(_this select 0) set [_index, nil];
GET_VALUES(_this select 0) set [_index, nil];
SET_COUNT(_this select 0, GET_COUNT(_this select 0) - 1);
true
};
dz_fn_dictionary_compact =
{
private ["_keys", "_values", "_i"];
_keys = [];
_values = [];
_keys resize (_this);
_values resize (_this);
_i = 0;
{
if (!isNil "_x") then
{
_keys set [_i, _x];
_values set [_i, GET_VALUES(_this) select _forEachIndex];
_i = _i + 1;
};
}
foreach GET_KEYS(_this);
_this set [1, _keys];
_this set [2, _values];
};

View File

@@ -0,0 +1,40 @@
dz_fn_math_gcd =
{
private ["_a","_b","_t"];
_a = _this select 0;
_b = _this select 1;
while {_b != 0} do
{
_t = _b;
_b = _a % _b;
_a = _t;
};
_a
};
dz_fn_math_gcdx =
{
if ((count _this) == 0) exitWith { 1 };
if ((count _this) == 1) exitWith { _this select 0 };
private "_gcd";
_gcd = [_this select 0, _this select 1] call dz_fn_math_gcd;
for "_i" from 2 to (count _this) - 1 do
{
if (_gcd == 1) exitWith {};
_gcd = [_gcd, _this select _i] call dz_fn_math_gcd;
};
_gcd
};
dz_fn_math_randomRange =
{
(_this select 0) + random ((_this select 1) - (_this select 0))
};

View File

@@ -0,0 +1,11 @@
#include "Mutex.hpp"
dz_fn_mutex_tryLock =
{
Mutex_TryLock_Fast(_this);
};
dz_fn_mutex_waitLock =
{
Mutex_WaitLock_Fast(_this);
};

View File

@@ -0,0 +1,151 @@
#define DEBUG_STEP() call { dbg_step = false; waitUntil {dbg_step}; }
#include "Debug.hpp"
#include "Player.hpp"
#define WeaponSlotPrimary 1
#define WeaponSlotHandGun 2
#define WeaponSlotSecondary 4
#define WeaponSlotHandGunItem 16
#define WeaponSlotItem 256
#define WeaponSlotBinocular 4096
#define WeaponHardMounted 65536
#define WeaponSlotInventory 131072
#define IS_MAGAZINE(type) (type == WeaponSlotHandGunItem || type == WeaponSlotItem)
dz_player_invTypes = [WeaponSlotPrimary, WeaponSlotHandGun, WeaponSlotSecondary, WeaponSlotHandGunItem, WeaponSlotItem, WeaponSlotBinocular, WeaponHardMounted, WeaponSlotInventory];
dz_player_invSlots = [call compile getText (configFile >> "CfgVehicles" >> Player_BASE)] call BIS_FNC_invCodeToArray;
//dz_player_invSlots = [1,1,1,8,12,2,0,12];
dz_fn_player_numItems =
{
if (_this == 0) exitWith { 0 };
Debug_Assert(_this in dz_player_invTypes);
if (IS_MAGAZINE(_this)) then
{ { _this == getNumber (configFile >> "CfgMagazines" >> _x >> "type") } count magazines player; }
else
{ { _this == getNumber (configFile >> "CfgWeapons" >> _x >> "type") } count weapons player; };
};
dz_fn_player_numEmptySlots =
{
if (_this == 0) exitWith { 1000000 };
Debug_Assert(_this in dz_player_invTypes);
Player_NumSlots(_this) - Player_NumItems(_this);
};
dz_fn_player_addItem =
{
Debug_CheckParams2("SCALAR","STRING");
private ["_type", "_veh", "_num"];
switch (_this select 0) do
{
case 0:
{
_type = getNumber (configFile >> "CfgWeapons" >> _this select 1 >> "type");
if (_type == 0 || { Player_NumEmptySlots(_type) > 0 } ) exitWith
{
player addWeapon (_this select 1);
Player_AddItem_RESULT_PLAYER
};
_veh = vehicle player;
if (player != _veh) exitWith
{
_num = 0;
{ _num = _num + _x; } foreach (getWeaponCargo _veh select 1);
if (_num < getNumber (configFile >> "CfgVehicles" >> typeOf _veh >> "transportMaxWeapons")) exitWith
{
_veh addWeaponCargoGlobal [_this select 1, 1];
Player_AddItem_RESULT_VEHICLE
};
Player_AddItem_RESULT_FAILURE
};
Player_DropWeapon(_this select 1);
Player_AddItem_RESULT_GROUND
};
case 1:
{
_type = getNumber (configFile >> "CfgMagazines" >> _this select 1 >> "type");
if (_type == 0 || { Player_NumEmptySlots(_type) > 0 } ) exitWith
{
player addMagazine (_this select 1);
Player_AddItem_RESULT_PLAYER
};
_veh = vehicle player;
if (player != _veh) exitWith
{
_num = 0;
{ _num = _num + _x; } foreach (getMagazineCargo _veh select 1);
if (_num < getNumber (configFile >> "CfgVehicles" >> typeOf _veh >> "transportMaxMagazines")) exitWith
{
_veh addMagazineCargoGlobal [_this select 1, 1];
Player_AddItem_RESULT_VEHICLE
};
Player_AddItem_RESULT_FAILURE
};
Player_DropMagazine(_this select 1);
Player_AddItem_RESULT_GROUND
};
};
};
dz_fn_player_dropItem =
{
#define DROP_ITEM_WEAPON_HOLDER_SEARCH_RADIUS 2
#define DROP_ITEM_WEAPON_HOLDER_PLAYER_OFFSET [0,0,0]
Debug_Assert(!Player_IsOnLadder());
if (Player_IsInVehicle()) exitWith
{
diag_log "WARNING: dz_fn_player_dropItem called while player was in a vehicle.";
objNull
};
private ["_pos","_near","_wh"];
//Lets get the location of the player in the world
_pos = player modeltoWorld DROP_ITEM_WEAPON_HOLDER_PLAYER_OFFSET;
_pos set [2, 0];
//Find WeaponHolders close to the player.
_near = _pos nearObjects ["WeaponHolder", DROP_ITEM_WEAPON_HOLDER_SEARCH_RADIUS];
_wh = nil;
if (count _near == 0) then
{ _wh = createVehicle ["WeaponHolder", _pos, [], 0, "CAN_COLLIDE"]; }
else
{ _wh = _near select 0; };
if (_this select 0 == 0) then
{ _wh addWeaponCargoGlobal [_this select 1, 1]; }
else
{ _wh addMagazineCargoGlobal [_this select 1, 1]; };
//Reveal the item
player reveal _wh;
_wh
#undef DROP_ITEM_WEAPON_HOLDER_SEARCH_RADIUS
#undef DROP_ITEM_WEAPON_HOLDER_PLAYER_OFFSET
};

View File

@@ -0,0 +1,55 @@
/* Implemented as a circular buffer.
See https://en.wikipedia.org/wiki/Circular_buffer
*/
#define GET_COUNT(q) ((q) select 0)
#define GET_FRONT(q) ((q) select 1)
#define GET_ARRAY(q) ((q) select 2)
#define GET_SIZE(q) (count GET_ARRAY(q))
#define SET_COUNT(q, p) ((q) set [0, p])
#define SET_FRONT(q, p) ((q) set [1, p])
#define GET_INDEX(q) ((GET_FRONT(q) + GET_COUNT(q) - 1) % GET_SIZE(q))
dz_fn_queue_new =
{
private "_q";
_q = [0, 0, []];
GET_ARRAY(_q) resize _this;
_q
};
dz_fn_queue_enqueue =
{
if (GET_COUNT(_this select 0) == GET_SIZE(_this select 0)) exitWith {false};
SET_COUNT(_this select 0, GET_COUNT(_this select 0) + 1);
GET_ARRAY(_this select 0) set [GET_INDEX(_this select 0), _this select 1];
true
};
dz_fn_queue_dequeue =
{
if (GET_COUNT(_this) == 0) exitWith {nil};
private "_e";
_e = GET_ARRAY(_this) select GET_FRONT(_this);
GET_ARRAY(_this) set [GET_FRONT(_this), nil];
SET_COUNT(_this, GET_COUNT(_this) - 1);
SET_FRONT(_this, (GET_FRONT(_this) + 1) % GET_SIZE(_this));
_e
};
dz_fn_queue_peek =
{
if (GET_COUNT(_this) == 0) exitWith {nil};
GET_ARRAY(_this) select GET_INDEX(_this);
};
dz_fn_queue_isFull =
{
GET_COUNT(_this) == GET_SIZE(_this)
};
//TODO: Queue::Resize()
dz_fn_queue_resize =
{
assert (false);
};

View File

@@ -0,0 +1,41 @@
Author: Foxy https://github.com/AsFoxy
Here are defined in their own header and code files a variety of utility classes. See the header
files for more information about each class and their functions.
Object oriented classes like Dictionary and Mutex are used to create and utilize objects in a way
similar to object oriented C. The object in member functions is always the first parameter. For
example:
_myDictionary = Dictionary_New();
Dictionary_Add(_myDictionary, _myKey, _myValue);
Some headers define functions suffixed with "Fast" alongside normal counterparts. For example
Vector_DotProduct and Vector_DotProduct_Fast in Vector.hpp. The suffixed functions are inlined and
as such have very slightly less overhead. The unsuffixed functions should be used when one of the
arguments passed is a complex or intensive expression. Each expression passed may be evaluated
multiple times when using the suffixed functions. Because of this especially expressions with side
effects should not be used. For example:
//Good
Vector_Multiply_Fast(_myVector, _this select 3);
//Totally fine but slightly less performant
Vector_Multiply(_myVector, _this select 3);
//BAD!
Vector_Multiply_Fast(_myVector, call _my_heavy_function_with_side_effects);
//Good
Vector_Multiply(_myVector, call _my_heavy_function_with_side_effects);
Function macros parsed by the Arma preprocessor in general must receive arguments that do not
contain commas, unless wrapped by another function macro. For example:
//Does not work
_result = Vector_Add([1,2,3], [4,5,6]);
//Instead:
_myVector1 = [1,2,3];
_myVector2 = [4,5,6];
_result = Vector_Add(_myVector1, _myVector2);
//Or:
_result = Vector_Add(Vector_New(1,2,3), Vector_New(4,5,6));

View File

@@ -0,0 +1,174 @@
#include "Util.hpp"
#include "Request.hpp"
#include "Array.hpp"
#include "Mutex.hpp"
#include "Dictionary.hpp"
#include "Debug.hpp"
#define Request_New(id) [dz_owner, id]
#define Request_GetOwner(request) ((request) select 0)
#define Request_GetID(request) ((request) select 1)
#define Request_SetResult(request, result) ((request) set [2, result])
#define Request_GetResult(request) ((request) select 2)
#define Reply_GetID(reply) ((reply) select 0)
#define Reply_GetResult(reply) ((reply) select 1)
#define Request_Server_GetFunc(request) ((request) select 2)
#define Request_Server_GetArgs(request) ((request) select 3)
#define Request_Server_ExpectsReply(request) (Request_GetID(request) >= 0)
//TODO: make work for non-dedicated server as well?
if (!isServer) then //CLIENT
{
dz_request_mutex = Mutex_New();
dz_request_list = [];
//Send request
dz_fn_request_send = // [type, args, reply]
{
Debug_Assert(Request_IsInitialized());
Debug_CheckParams3(Array_New2("SCALAR","STRING"),"ANY","BOOL");
private ["_id", "_request"];
//Expecting reply
if (_this select 2) exitWith
{
//Acquire lock
Mutex_WaitLock_Fast(dz_request_mutex);
//Find first valid id and assign the new request to it
_id = dz_request_list find 0;
if (_id < 0) then { _id = count dz_request_list; };
_request = [dz_owner, _id];
dz_request_list set [_id, _request];
Mutex_Unlock(dz_request_mutex);
Util_PublicVariableServer_Fast("dz_pvs_request", _request + Array_New2(_this select 0, _this select 1));
/*//send request to server
dz_pvs_request = _request + [_this select 0, _this select 1];
publicVariableServer "dz_pvs_request";*/
//return the request object
_request
};
//Not expecting reply
Util_PublicVariableServer_Fast("dz_pvs_request", Array_New4(dz_owner, -1, _this select 0, _this select 1));
/*//Acquire lock
Mutex_WaitLock_Fast(dz_request_mutex);
//Send request to server
dz_pvs_request = Request_New(-1) + [_this select 0, _this select 1];
publicVariableServer "dz_pvs_request";
//Unlock
Mutex_Unlock(dz_request_mutex);*/
//Return nil
nil
};
//receive reply
"dz_pvc_request" addPublicVariableEventHandler
{
_id = Reply_GetID(_this select 1);
//retrieve and remove request from global list
_request = dz_request_list select _id;
dz_request_list set [_id, 0];
//set result in request object
Request_SetResult(_request, Reply_GetResult(_this select 1));
};
}
else //SERVER
{
//dz_request_mutex = Mutex_New();
dz_request_handlers = Dictionary_New();
//receive request
"dz_pvs_request" addPublicVariableEventHandler
{
//request handler [handler, async]
_handler = Dictionary_Get(dz_request_handlers, Request_Server_GetFunc(_this select 1));
//No handler found
if (isNil "_handler") exitWith
{
diag_log format ["ERROR: Received an invalid request:%1 ClientID:%2",
Request_Server_GetFunc(_this select 1),
Request_GetOwner(_this select 1) ];
//Send reply to prevent client deadlock
if (Request_Server_ExpectsReply(_this select 1)) then
{
Util_PublicVariableClient_Fast("dz_pvc_request", DEFAULT_REPLY, Request_GetOwner(_this select 1));
//Return default value (empty array)
/*_temp = dz_pvc_request;
dz_pvc_request = DEFAULT_REPLY;
Request_GetOwner(_this select 1) publicVariableClient "dz_pvc_request";
dz_pvc_request = _temp;*/
};
};
//Async
if (_handler select 1) then
{
//Spawn a new thread to handle request asynchronously
[_this select 1, _handler select 0] spawn
{
__reply = Request_Server_ExpectsReply(_this select 0);
_result = Request_Server_GetArgs(_this select 0) call (_this select 1);
if (!__reply) exitWith {};
_result = [Request_GetID(_this select 0), _result];
Util_PublicVariableClient_Fast("dz_pvc_request", _result, Request_GetOwner(_this select 0));
/*//Acquire lock to prevent race conditions with other asynchronous handlers
Mutex_WaitLock_Fast(dz_request_mutex);
//Send reply
dz_pvc_request = _result;
Request_GetOwner(_this select 0) publicVariableClient "dz_pvc_request";
//Unlock
Mutex_Unlock(dz_request_mutex);*/
};
}
else //Sync
{
//Whether client expects a reply.
//If the handler knows that the player has disconnected they can set this to false to prevent replying.
__reply = Request_Server_ExpectsReply(_this select 1);
//Execute handler
_result = Request_Server_GetArgs(_this select 1) call (_handler select 0);
if (!__reply) exitWith {};
_result = [Request_GetID(_this select 1), _result];
Util_PublicVariableClient_Fast("dz_pvc_request", _result, Request_GetOwner(_this select 1));
//store previous value in case it's being used by a scheduled thread
/*_temp = dz_pvc_request;
//Send reply
dz_pvc_request = _result;
Request_GetOwner(_this select 1) publicVariableClient "dz_pvc_request";
//restore previous value
dz_pvc_request = _temp;*/
};
};
};

View File

@@ -0,0 +1,36 @@
#define GET_COUNT(s) ((s) select 0)
#define GET_ARRAY(s) ((s) select 1)
#define GET_SIZE(s) (count GET_ARRAY(s))
#define SET_COUNT(s, p) ((s) set [0, p])
dz_fn_stack_push =
{
if (GET_COUNT(_this select 0) == GET_SIZE(_this select 0)) then
{
GET_ARRAY(_this select 0) resize (GET_SIZE(_this select 0) * 2);
};
GET_ARRAY(_this select 0) set [GET_COUNT(_this select 0), _this select 1];
SET_COUNT(_this select 0, GET_COUNT(_this select 0) + 1);
};
dz_fn_stack_pop =
{
if (GET_COUNT(_this) == 0) exitWith {nil};
private "_e";
SET_COUNT(_this, GET_COUNT(_this) - 1);
_e = GET_ARRAY(_this) select GET_COUNT(_this);
GET_ARRAY(_this) set [GET_COUNT(_this), nil];
_e
};
dz_fn_stack_peek =
{
GET_ARRAY(_this) select (GET_COUNT(_this) - 1)
};
dz_fn_stack_size =
{
count GET_ARRAY(_this)
};

View File

@@ -0,0 +1,96 @@
/* Task structure
code task function
script script handle
int task status
any task result
*/
#define STATUS_WAITING 0
#define STATUS_STARTED 1
#define STATUS_COMPLETED 2
#define STATUS_CANCELED 3
#define GET_CODE(task) ((task) select 0)
#define GET_SCRIPT(task) ((task) select 1)
#define SET_SCRIPT(task, script) ((task) set [1, script])
#define GET_STATUS(task) ((task) select 2)
#define SET_STATUS(task, status) ((task) set [2, status])
#define GET_RESULT(task) ((task) select 3)
#define SET_RESULT(task, result) ((task) set [3, result])
dz_fn_task_start =
{
if (GET_STATUS(_this select 0) != STATUS_WAITING) exitWith { nil };
private "_handle";
SET_STATUS(_this select 0, STATUS_STARTED);
_handle = _this spawn
{
SET_RESULT(_this select 0, (_this select 1) call GET_CODE(_this select 0));
SET_STATUS(_this select 0, STATUS_COMPLETED);
};
SET_SCRIPT(_this select 0, _handle);
_this select 0
};
dz_fn_task_cancel =
{
if (GET_STATUS(_this) != STATUS_STARTED) exitWith { false };
terminate GET_SCRIPT(_this);
SET_STATUS(_this, STATUS_CANCELED);
true
};
dz_fn_task_wait =
{
waitUntil {GET_STATUS(_this) > 1};
GET_RESULT(_this)
};
/*dz_fn_task_waitAny =
{
_index = nil;
_w = false;
waitUntil
{
for "_i" from 0 to count _this - 1 do
{
if (GET_STATUS(_this select _i) > 1)
exitWith {_w = true; _index = _this select _i; };
};
_w
};
_index
};
dz_fn_task_waitAll =
{
waitUntil
{
_w = true;
for "_i" from 0 to count _this - 1 do
{
if (GET_STATUS(_this select _i) <= 1)
exitWith {_w = false};
};
_w
};
nil
};*/

View File

@@ -0,0 +1,11 @@
#include "Util.hpp"
dz_fn_util_pv = { Util_PublicVariable_Fast(_this select 0, _this select 1); };
dz_fn_util_pvs = { Util_PublicVariableServer_Fast(_this select 0, _this select 1); };
dz_fn_util_pvc = { Util_PublicVariableClient_Fast(_this select 0, _this select 1, _this select 2); };
dz_fn_util_waitUntil =
{
waitUntil { ((_this select 2) + (_this select 3)) > diag_tickTime || { (_this select 0) call (_this select 1) } };
(_this select 0) call (_this select 1);
};

View File

@@ -0,0 +1,53 @@
#include "Vector.hpp"
#define P0 _this select 0
#define P1 _this select 1
dz_fn_vector_dotProduct = { Vector_DotProduct_Fast(P0, P1); };
dz_fn_vector_crossProduct = { Vector_CrossProduct_Fast(P0, P1); };
dz_fn_vector_magnitude = { Vector_Magnitude_Fast(_this); };
dz_fn_vector_add = { Vector_Add_Fast(P0, P1); };
dz_fn_vector_subtract = { Vector_Subtract_Fast(P0, P1); };
dz_fn_vector_negate = { Vector_Negate_Fast(_this); };
dz_fn_vector_multiply = { Vector_Multiply_Fast(P0, P1); };
dz_fn_vector_divide = { Vector_Divide_Fast(P0, P1); };
dz_fn_vector_angle = { Vector_Angle_Fast(P0, P1); };
dz_fn_vector_normalize = { Vector_Normalize_Fast(_this); };
dz_fn_vector_fromDir = { Vector_FromDir_Fast(_this); };
dz_fn_vector_rotate2d = { Vector_Rotate2D_Fast(P0, P1); };
dz_fn_vector_rotate3d =
{
#define VX (_this select 0 select 0)
#define VY (_this select 0 select 1)
#define VZ (_this select 0 select 2)
#define UX (_this select 1 select 0)
#define UY (_this select 1 select 1)
#define UZ (_this select 1 select 2)
private ["_sin", "_cos", "_icos"];
_sin = sin (_this select 2);
_cos = cos (_this select 2);
_icos = 1 - _cos;
[
VX * ( UX ^ 2 * _icos + _cos ) +
VY * ( UX * UY * _icos - UZ * _sin ) +
VZ * ( UX * UZ * _icos + UY * _sin )
,
VX * ( UY * UX * _icos + UZ * _sin ) +
VY * ( UY ^ 2 * _icos + _cos ) +
VZ * ( UY * UZ * _icos - UX * _sin )
,
VX * ( UZ * UX * _icos - UY * _sin ) +
VY * ( UZ * UY * _icos + UX * _sin ) +
VZ * ( UZ ^ 2 * _icos + _cos )
]
#undef VX
#undef VY
#undef VZ
#undef UX
#undef UY
#undef UZ
};

View File

@@ -1796,6 +1796,14 @@
<French>Vous ne pouvez pas effectuer une autre transfusion sanguine si vite, attendez %1 secondes.</French>
<Czech>Nemůžete provádět další krevní transfuzi tak rychle, počkejte %1 sekund.</Czech>
</Key>
<Key ID="STR_ACTIONS_WEAPON">
<English>Weapon %1</English>
<Spanish>Arma: %1</Spanish>
<Russian>Оружие %1</Russian>
<Czech>Zbraň: %1</Czech>
<French>Arme: %1</French>
<German>Zu %1 wechseln</German>
</Key>
<Key ID="str_action_studybody">
<Original>Study Body</Original>
<English>Study Body</English>