diff --git a/SQF/dayz_code/traps/beartrap.sqf b/SQF/dayz_code/traps/beartrap.sqf new file mode 100644 index 000000000..11295d3a5 --- /dev/null +++ b/SQF/dayz_code/traps/beartrap.sqf @@ -0,0 +1,92 @@ +_init = { + //if (isServer) then { + [_trap] call setup_trap; + + if (_trap getVariable ["armed", false]) then { + [] call _arm; + } else { + [] call _disarm; + }; + //}; +}; + +_arm = { + //if (isServer) then { + _trap animate ["LeftShutter", 0]; + _trap animate ["RightShutter", 0]; + + _trigger = createTrigger ["EmptyDetector", getPosATL _trap]; + _trigger setpos getPosATL _trap; + _trigger setTriggerArea [0.5, 0.5, 0, false]; + _trigger setTriggerActivation ["ANY", "PRESENT", false]; + _trigger setTriggerStatements [ + "this", + "['trigger', thisTrigger, thisList] spawn beartrap;", + "" + ]; + + [_trap, _trigger] call arm_trap; + //} else { + _trap setVariable ["armed", true, true]; + //}; +}; + +_disarm = { + if (isServer) then { + [_trap] call disarm_trap; + } else { + _trap setVariable ["armed", false, true]; + }; +}; + +_remove = { + if (isServer) then { + [_trap] call remove_trap; + } else { + [_trap] call remove_trap; + [0,0,0,["cfgMagazines","TrapBear",_trap]] spawn object_pickup; + }; +}; + +_trigger = { + if (isServer) then { + private ["_entity"]; + _entity = _this select 0; + + _trap animate ["LeftShutter", 1]; + _trap animate ["RightShutter", 1]; + + [nil,_trap,rSAY,["trap_bear_0",60]] call RE; + + if (_entity isKindOf "Animal") then { + _entity setDamage 1; + } else { + [_entity, "Legs", [_entity]] call server_sendToClient; + }; + + [_trap] call trigger_trap; + }; +}; + +private ["_event", "_trap", "_args"]; +_event = _this select 0; +_trap = if (typeOf (_this select 1) == "EmptyDetector") then { dayz_traps_active select (dayz_traps_trigger find (_this select 1)) } else { _this select 1 }; +_args = if (count _this > 2) then { _this select 2 } else { [] }; + +switch (_event) do { + case "init": { + [] call _init; + }; + case "remove": { + [] call _remove; + }; + case "arm": { + [] call _arm; + }; + case "disarm": { + [] call _disarm; + }; + case "trigger": { + _args call _trigger; + }; +}; diff --git a/SQF/dayz_code/traps/beartrapflare.sqf b/SQF/dayz_code/traps/beartrapflare.sqf new file mode 100644 index 000000000..4e82735c8 --- /dev/null +++ b/SQF/dayz_code/traps/beartrapflare.sqf @@ -0,0 +1,111 @@ +_init = { + //if (isServer) then { + [_trap] call setup_trap; + + if (_trap getVariable ["armed", false]) then { + [] call _arm; + } else { + [] call _disarm; + }; + //}; +}; + +_arm = { + //if (isServer) then { + // don't work (due to proxies n stuff) + //_trap animate ["LeftShutter", 0]; + //_trap animate ["RightShutter", 0]; + + _trigger = createTrigger ["EmptyDetector", getPosATL _trap]; + _trigger setpos getPosATL _trap; + _trigger setTriggerArea [0.5, 0.5, 0, false]; + _trigger setTriggerActivation ["ANY", "PRESENT", false]; + _trigger setTriggerStatements [ + "this", + "['trigger', thisTrigger, thisList] spawn beartrapflare;", + "" + ]; + + [_trap, _trigger] call arm_trap; + //} else { + _trap setVariable ["armed", true, true]; + //}; +}; + +_disarm = { + if (isServer) then { + [_trap] call disarm_trap; + } else { + _trap setVariable ["armed", false, true]; + }; +}; + +_remove = { + if (isServer) then { + [_trap] call remove_trap; + } else { + [_trap] call remove_trap; + [0,0,0,["cfgMagazines","ItemTrapBearTrapFlare",_trap]] spawn object_pickup; + }; +}; + +_trigger = { + if (isServer) then { + private ["_entity"]; + _entity = _this select 0; + + // don't work (due to proxies n stuff) + //_trap animate ["LeftShutter", 1]; + //_trap animate ["RightShutter", 1]; + + [nil,_trap,rSAY,["trap_bear_0",60]] call RE; + + if (_entity isKindOf "Animal") then { + _entity setDamage 1; + } else { + [_entity, "Legs", [_entity]] call server_sendToClient; + }; + + _flare = createVehicle ["RoadFlare", getPosATL _trap, [], 0, "CAN_COLLIDE"]; + + [_flare,0] spawn object_roadFlare; + PVDZ_obj_RoadFlare = [_flare,0]; + publicVariable "PVDZ_obj_RoadFlare"; + + [_trap] call trigger_trap; + + // allow rSAY to finish actually playing the sound + _timeout = diag_tickTime + 2; + waitUntil { diag_tickTime >= _timeout }; + + // needs to be after trigger_trap because of DB removal + _pos = getPosATL _trap; + deleteVehicle _trap; + + _lootpile = createVehicle ["WeaponHolder", _pos, [], 0, "CAN_COLLIDE"]; + _lootpile addMagazineCargoGlobal ["TrapBear", 1]; + }; +}; + +private ["_event", "_trap", "_args"]; +_event = _this select 0; +_trap = if (typeOf (_this select 1) == "EmptyDetector") then { dayz_traps_active select (dayz_traps_trigger find (_this select 1)) } else { _this select 1 }; +_args = if (count _this > 2) then { _this select 2 } else { [] }; + +switch (_event) do { + case "init": { + [] call _init; + }; + case "remove": { + [] call _remove; + }; + case "arm": { + [] call _arm; + }; + case "disarm": { + [] call _disarm; + }; + case "trigger": { + _args call _trigger; + }; +}; diff --git a/SQF/dayz_code/traps/beartrapsmoke.sqf b/SQF/dayz_code/traps/beartrapsmoke.sqf new file mode 100644 index 000000000..1acda5189 --- /dev/null +++ b/SQF/dayz_code/traps/beartrapsmoke.sqf @@ -0,0 +1,107 @@ +_init = { + //if (isServer) then { + [_trap] call setup_trap; + + if (_trap getVariable ["armed", false]) then { + [] call _arm; + } else { + [] call _disarm; + }; + //}; +}; + +_arm = { + //if (isServer) then { + // don't work (due to proxies n stuff) + //_trap animate ["LeftShutter", 0]; + //_trap animate ["RightShutter", 0]; + + _trigger = createTrigger ["EmptyDetector", getPosATL _trap]; + _trigger setpos getPosATL _trap; + _trigger setTriggerArea [0.5, 0.5, 0, false]; + _trigger setTriggerActivation ["ANY", "PRESENT", false]; + _trigger setTriggerStatements [ + "this", + "['trigger', thisTrigger, thisList] spawn beartrapsmoke;", + "" + ]; + + [_trap, _trigger] call arm_trap; + //} else { + _trap setVariable ["armed", true, true]; + //}; +}; + +_disarm = { + if (isServer) then { + [_trap] call disarm_trap; + } else { + _trap setVariable ["armed", false, true]; + }; +}; + +_remove = { + if (isServer) then { + [_trap] call remove_trap; + } else { + [_trap] call remove_trap; + [0,0,0,["cfgMagazines","ItemTrapBearTrapSmoke",_trap]] spawn object_pickup; + }; +}; + +_trigger = { + if (isServer) then { + private ["_entity"]; + _entity = _this select 0; + + // don't work (due to proxies n stuff) + //_trap animate ["LeftShutter", 1]; + //_trap animate ["RightShutter", 1]; + + [nil,_trap,rSAY,["trap_bear_0",60]] call RE; + + if (_entity isKindOf "Animal") then { + _entity setDamage 1; + } else { + [_entity, "Legs", [_entity]] call server_sendToClient; + }; + + createVehicle ["SmokeShell", getPosATL _trap, [], 0, "CAN_COLLIDE"]; + + [_trap] call trigger_trap; + + // allow rSAY to finish actually playing the sound + _timeout = diag_tickTime + 2; + waitUntil { diag_tickTime >= _timeout }; + + // needs to be after trigger_trap because of DB removal + _pos = getPosATL _trap; + deleteVehicle _trap; + + _lootpile = createVehicle ["WeaponHolder", _pos, [], 0, "CAN_COLLIDE"]; + _lootpile addMagazineCargoGlobal ["TrapBear", 1]; + }; +}; + +private ["_event", "_trap", "_args"]; +_event = _this select 0; +_trap = if (typeOf (_this select 1) == "EmptyDetector") then { dayz_traps_active select (dayz_traps_trigger find (_this select 1)) } else { _this select 1 }; +_args = if (count _this > 2) then { _this select 2 } else { [] }; + +switch (_event) do { + case "init": { + [] call _init; + }; + case "remove": { + [] call _remove; + }; + case "arm": { + [] call _arm; + }; + case "disarm": { + [] call _disarm; + }; + case "trigger": { + _args call _trigger; + }; +}; diff --git a/SQF/dayz_code/traps/functions/arm.sqf b/SQF/dayz_code/traps/functions/arm.sqf new file mode 100644 index 000000000..dfaedd94f --- /dev/null +++ b/SQF/dayz_code/traps/functions/arm.sqf @@ -0,0 +1,12 @@ +_trap = _this select 0; +_trigger = _this select 1; + +_trap animate ['LeftShutter', 0]; +_trap animate ['RightShutter', 0]; + +_trap setVariable ["armed", true, true]; +PVDZ_veh_Save = [_trap, "gear"]; +publicVariableServer "PVDZ_veh_Save"; + +dayz_traps_active set [count dayz_traps_active, _trap]; +dayz_traps_trigger set [count dayz_traps_trigger, _trigger]; diff --git a/SQF/dayz_code/traps/functions/disarm.sqf b/SQF/dayz_code/traps/functions/disarm.sqf new file mode 100644 index 000000000..c426a6b25 --- /dev/null +++ b/SQF/dayz_code/traps/functions/disarm.sqf @@ -0,0 +1,14 @@ +_trap = _this select 0; + +_trap animate ['LeftShutter', 1]; +_trap animate ['RightShutter', 1]; + +_trap setVariable ["armed", false, true]; +PVDZ_veh_Save = [_trap, "gear"]; +publicVariableServer "PVDZ_veh_Save"; + +if (_trap in dayz_traps_active) then { + deleteVehicle (dayz_traps_trigger select (dayz_traps_active find _trap)); + dayz_traps_trigger = dayz_traps_trigger - [dayz_traps_trigger select (dayz_traps_active find _trap)]; + dayz_traps_active = dayz_traps_active - [_trap]; +}; diff --git a/SQF/dayz_code/traps/functions/remove.sqf b/SQF/dayz_code/traps/functions/remove.sqf new file mode 100644 index 000000000..48a4b179a --- /dev/null +++ b/SQF/dayz_code/traps/functions/remove.sqf @@ -0,0 +1 @@ +[nil,nil,nil,_this select 0] call compile preprocessFileLineNumbers "\z\addons\dayz_code\actions\remove.sqf" \ No newline at end of file diff --git a/SQF/dayz_code/traps/functions/setup.sqf b/SQF/dayz_code/traps/functions/setup.sqf new file mode 100644 index 000000000..721bb51f2 --- /dev/null +++ b/SQF/dayz_code/traps/functions/setup.sqf @@ -0,0 +1,18 @@ +private ["_id", "_uid", "_armed"]; +_trap = _this select 0; + +if (!isNull _trap) then { + while { true } do { + _id = _trap getVariable ["ObjectID", "0"]; + _uid = _trap getVariable ["ObjectUID", "0"]; + _armed = _trap getVariable "armed"; + + if (isNull _trap) exitWith { /* break from loop */ }; + + if (((parseNumber _id > 0) || (parseNumber _uid > 0)) && !isNil "_armed") exitWith { + dayz_traps set [count dayz_traps, _trap]; + }; + + sleep 0.5; + }; +}; diff --git a/SQF/dayz_code/traps/functions/trigger.sqf b/SQF/dayz_code/traps/functions/trigger.sqf new file mode 100644 index 000000000..44b3cd072 --- /dev/null +++ b/SQF/dayz_code/traps/functions/trigger.sqf @@ -0,0 +1,7 @@ +_trap = _this select 0; + +if (getNumber (configFile >> "CfgVehicles" >> typeOf _trap >> "singleUse") > 0) then { + [_trap] call remove_trap; +} else { + [_trap] call disarm_trap; +}; diff --git a/SQF/dayz_code/traps/init.sqf b/SQF/dayz_code/traps/init.sqf new file mode 100644 index 000000000..7a5d5ee6c --- /dev/null +++ b/SQF/dayz_code/traps/init.sqf @@ -0,0 +1,15 @@ +// functions +setup_trap = compile preprocessFileLineNumbers "\z\addons\dayz_code\traps\functions\setup.sqf"; +arm_trap = compile preprocessFileLineNumbers "\z\addons\dayz_code\traps\functions\arm.sqf"; +disarm_trap = compile preprocessFileLineNumbers "\z\addons\dayz_code\traps\functions\disarm.sqf"; +remove_trap = compile preprocessFileLineNumbers "\z\addons\dayz_code\traps\functions\remove.sqf"; +trigger_trap = compile preprocessFileLineNumbers "\z\addons\dayz_code\traps\functions\trigger.sqf"; + +// traps +beartrap = compile preprocessFileLineNumbers "\z\addons\dayz_code\traps\beartrap.sqf"; +beartrapflare = compile preprocessFileLineNumbers "\z\addons\dayz_code\traps\beartrapflare.sqf"; +beartrapsmoke = compile preprocessFileLineNumbers "\z\addons\dayz_code\traps\beartrapsmoke.sqf"; +tripcans = compile preprocessFileLineNumbers "\z\addons\dayz_code\traps\tripcans.sqf"; +tripflare = compile preprocessFileLineNumbers "\z\addons\dayz_code\traps\tripflare.sqf"; +tripgrenade = compile preprocessFileLineNumbers "\z\addons\dayz_code\traps\tripgrenade.sqf"; +tripsmoke = compile preprocessFileLineNumbers "\z\addons\dayz_code\traps\tripsmoke.sqf"; diff --git a/SQF/dayz_code/traps/tripcans.sqf b/SQF/dayz_code/traps/tripcans.sqf new file mode 100644 index 000000000..fc9078c1d --- /dev/null +++ b/SQF/dayz_code/traps/tripcans.sqf @@ -0,0 +1,85 @@ +_init = { + //if (isServer) then { + [_trap] call setup_trap; + + if (_trap getVariable ["armed", false]) then { + [] call _arm; + } else { + [] call _disarm; + }; + //}; +}; + +_arm = { + //if (isServer) then { + _pos = getPosATL _trap; + _pos1 = _trap modelToWorld (_trap selectionPosition "TripA"); + _pos2 = _trap modelToWorld (_trap selectionPosition "TripB"); + + _trigger = createTrigger ["EmptyDetector", _pos]; + _trigger setpos _pos; + _trigger setTriggerArea [1, ([_pos1, _pos2] call BIS_fnc_distance2D) / 2, [_pos1, _pos2] call BIS_fnc_dirTo, true]; + _trigger setTriggerActivation ["ANY", "PRESENT", false]; + _trigger setTriggerStatements [ + "this", + "['trigger', thisTrigger, thisList] spawn tripcans;", + "" + ]; + + [_trap, _trigger] call arm_trap; + //} else { + _trap setVariable ["armed", true, true]; + //}; +}; + +_disarm = { + if (isServer) then { + [_trap] call disarm_trap; + } else { + _trap setVariable ["armed", false, true]; + }; +}; + +_remove = { + if (isServer) then { + [_trap] call remove_trap; + } else { + [_trap] call remove_trap; + [0,0,0,["cfgMagazines","ItemTrapTripwireCans",_trap]] spawn object_pickup; + }; +}; + +_trigger = { + if (isServer) then { + private ["_entity"]; + _entity = _this select 0; + + [nil,_trap,rSAY,["z_trap_trigger_0",60]] call RE; + [nil,_trap,rSAY,[format["z_trap_cans_%1", round (random 2)],60]] call RE; + + [_trap] call trigger_trap; + }; +}; + +private ["_event", "_trap", "_args"]; +_event = _this select 0; +_trap = if (typeOf (_this select 1) == "EmptyDetector") then { dayz_traps_active select (dayz_traps_trigger find (_this select 1)) } else { _this select 1 }; +_args = if (count _this > 2) then { _this select 2 } else { [] }; + +switch (_event) do { + case "init": { + [] call _init; + }; + case "remove": { + [] call _remove; + }; + case "arm": { + [] call _arm; + }; + case "disarm": { + [] call _disarm; + }; + case "trigger": { + _args call _trigger; + }; +}; diff --git a/SQF/dayz_code/traps/tripflare.sqf b/SQF/dayz_code/traps/tripflare.sqf new file mode 100644 index 000000000..c271d2230 --- /dev/null +++ b/SQF/dayz_code/traps/tripflare.sqf @@ -0,0 +1,93 @@ +_init = { + //if (isServer) then { + [_trap] call setup_trap; + + if (_trap getVariable ["armed", false]) then { + [] call _arm; + } else { + [] call _disarm; + }; + //}; +}; + +_arm = { + //if (isServer) then { + _pos = getPosATL _trap; + _pos1 = _trap modelToWorld (_trap selectionPosition "TripA"); + _pos2 = _trap modelToWorld (_trap selectionPosition "TripB"); + + _trigger = createTrigger ["EmptyDetector", _pos]; + _trigger setpos _pos; + _trigger setTriggerArea [1, ([_pos1, _pos2] call BIS_fnc_distance2D) / 2, [_pos1, _pos2] call BIS_fnc_dirTo, true]; + _trigger setTriggerActivation ["ANY", "PRESENT", false]; + _trigger setTriggerStatements [ + "this", + "['trigger', thisTrigger, thisList] spawn tripflare;", + "" + ]; + + [_trap, _trigger] call arm_trap; + //} else { + _trap setVariable ["armed", true, true]; + //}; +}; + +_disarm = { + if (isServer) then { + [_trap] call disarm_trap; + } else { + _trap setVariable ["armed", false, true]; + }; +}; + +_remove = { + if (isServer) then { + [_trap] call remove_trap; + } else { + [_trap] call remove_trap; + [0,0,0,["cfgMagazines","ItemTrapTripwireFlare",_trap]] spawn object_pickup; + }; +}; + +_trigger = { + if (isServer) then { + private ["_entity"]; + _entity = _this select 0; + + [nil,_trap,rSAY,["z_trap_trigger_0",60]] call RE; + + _position = _trap modelToWorld (_trap selectionPosition "TripA"); + _position set [2, 0]; + + _flare = createVehicle ["RoadFlare", _position, [], 0, "CAN_COLLIDE"]; + + [_flare,0] spawn object_roadFlare; + PVDZ_obj_RoadFlare = [_flare,0]; + publicVariable "PVDZ_obj_RoadFlare"; + + [_trap] call trigger_trap; + }; +}; + +private ["_event", "_trap", "_args"]; +_event = _this select 0; +_trap = if (typeOf (_this select 1) == "EmptyDetector") then { dayz_traps_active select (dayz_traps_trigger find (_this select 1)) } else { _this select 1 }; +_args = if (count _this > 2) then { _this select 2 } else { [] }; + +switch (_event) do { + case "init": { + [] call _init; + }; + case "remove": { + [] call _remove; + }; + case "arm": { + [] call _arm; + }; + case "disarm": { + [] call _disarm; + }; + case "trigger": { + _args call _trigger; + }; +}; diff --git a/SQF/dayz_code/traps/tripgrenade.sqf b/SQF/dayz_code/traps/tripgrenade.sqf new file mode 100644 index 000000000..9351cc593 --- /dev/null +++ b/SQF/dayz_code/traps/tripgrenade.sqf @@ -0,0 +1,89 @@ +_init = { + //if (isServer) then { + [_trap] call setup_trap; + + if (_trap getVariable ["armed", false]) then { + [] call _arm; + } else { + [] call _disarm; + }; + //}; +}; + +_arm = { + //if (isServer) then { + _pos = getPosATL _trap; + _pos1 = _trap modelToWorld (_trap selectionPosition "TripA"); + _pos2 = _trap modelToWorld (_trap selectionPosition "TripB"); + + _trigger = createTrigger ["EmptyDetector", _pos]; + _trigger setpos _pos; + _trigger setTriggerArea [1, ([_pos1, _pos2] call BIS_fnc_distance2D) / 2, [_pos1, _pos2] call BIS_fnc_dirTo, true]; + _trigger setTriggerActivation ["ANY", "PRESENT", false]; + _trigger setTriggerStatements [ + "this", + "['trigger', thisTrigger, thisList] spawn tripgrenade;", + "" + ]; + + [_trap, _trigger] call arm_trap; + //} else { + _trap setVariable ["armed", true, true]; + //}; +}; + +_disarm = { + if (isServer) then { + [_trap] call disarm_trap; + } else { + _trap setVariable ["armed", false, true]; + }; +}; + +_remove = { + if (isServer) then { + [_trap] call remove_trap; + } else { + [_trap] call remove_trap; + [0,0,0,["cfgMagazines","ItemTrapTripwireGrenade",_trap]] spawn object_pickup; + }; +}; + +_trigger = { + if (isServer) then { + private ["_entity"]; + _entity = _this select 0; + + [nil,_trap,rSAY,["z_trap_trigger_0",60]] call RE; + + _position = _trap modelToWorld (_trap selectionPosition "TripA"); + _position set [2, 0]; + + _flare = createVehicle ["GrenadeHandTimedWest_DZ", _position, [], 0, "CAN_COLLIDE"]; + + [_trap] call trigger_trap; + }; +}; + +private ["_event", "_trap", "_args"]; +_event = _this select 0; +_trap = if (typeOf (_this select 1) == "EmptyDetector") then { dayz_traps_active select (dayz_traps_trigger find (_this select 1)) } else { _this select 1 }; +_args = if (count _this > 2) then { _this select 2 } else { [] }; + +switch (_event) do { + case "init": { + [] call _init; + }; + case "remove": { + [] call _remove; + }; + case "arm": { + [] call _arm; + }; + case "disarm": { + [] call _disarm; + }; + case "trigger": { + _args call _trigger; + }; +}; diff --git a/SQF/dayz_code/traps/tripsmoke.sqf b/SQF/dayz_code/traps/tripsmoke.sqf new file mode 100644 index 000000000..077906ecb --- /dev/null +++ b/SQF/dayz_code/traps/tripsmoke.sqf @@ -0,0 +1,89 @@ +_init = { + //if (isServer) then { + [_trap] call setup_trap; + + if (_trap getVariable ["armed", false]) then { + [] call _arm; + } else { + [] call _disarm; + }; + //}; +}; + +_arm = { + //if (isServer) then { + _pos = getPosATL _trap; + _pos1 = _trap modelToWorld (_trap selectionPosition "TripA"); + _pos2 = _trap modelToWorld (_trap selectionPosition "TripB"); + + _trigger = createTrigger ["EmptyDetector", _pos]; + _trigger setpos _pos; + _trigger setTriggerArea [1, ([_pos1, _pos2] call BIS_fnc_distance2D) / 2, [_pos1, _pos2] call BIS_fnc_dirTo, true]; + _trigger setTriggerActivation ["ANY", "PRESENT", false]; + _trigger setTriggerStatements [ + "this", + "['trigger', thisTrigger, thisList] spawn tripsmoke;", + "" + ]; + + [_trap, _trigger] call arm_trap; + //} else { + _trap setVariable ["armed", true, true]; + //}; +}; + +_disarm = { + if (isServer) then { + [_trap] call disarm_trap; + } else { + _trap setVariable ["armed", false, true]; + }; +}; + +_remove = { + if (isServer) then { + [_trap] call remove_trap; + } else { + [_trap] call remove_trap; + [0,0,0,["cfgMagazines","ItemTrapTripwireSmoke",_trap]] spawn object_pickup; + }; +}; + +_trigger = { + //if (isServer) then { + private ["_entity"]; + _entity = _this select 0; + + [nil,_trap,rSAY,["z_trap_trigger_0",60]] call RE; + + _position = _trap modelToWorld (_trap selectionPosition "TripA"); + _position set [2, 0]; + + _flare = createVehicle ["SmokeShell", _position, [], 0, "CAN_COLLIDE"]; + + [_trap] call trigger_trap; + //}; +}; + +private ["_event", "_trap", "_args"]; +_event = _this select 0; +_trap = if (typeOf (_this select 1) == "EmptyDetector") then { dayz_traps_active select (dayz_traps_trigger find (_this select 1)) } else { _this select 1 }; +_args = if (count _this > 2) then { _this select 2 } else { [] }; + +switch (_event) do { + case "init": { + [] call _init; + }; + case "remove": { + [] call _remove; + }; + case "arm": { + [] call _arm; + }; + case "disarm": { + [] call _disarm; + }; + case "trigger": { + _args call _trigger; + }; +}; diff --git a/SQF/dayz_code/util/Array.hpp b/SQF/dayz_code/util/Array.hpp new file mode 100644 index 000000000..c4ac55a5f --- /dev/null +++ b/SQF/dayz_code/util/Array.hpp @@ -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 \ No newline at end of file diff --git a/SQF/dayz_code/util/Debug.hpp b/SQF/dayz_code/util/Debug.hpp new file mode 100644 index 000000000..42e84edd1 --- /dev/null +++ b/SQF/dayz_code/util/Debug.hpp @@ -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 \ No newline at end of file diff --git a/SQF/dayz_code/util/Dictionary.hpp b/SQF/dayz_code/util/Dictionary.hpp new file mode 100644 index 000000000..cba363d2a --- /dev/null +++ b/SQF/dayz_code/util/Dictionary.hpp @@ -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 \ No newline at end of file diff --git a/SQF/dayz_code/util/Math.hpp b/SQF/dayz_code/util/Math.hpp new file mode 100644 index 000000000..a85660e96 --- /dev/null +++ b/SQF/dayz_code/util/Math.hpp @@ -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 \ No newline at end of file diff --git a/SQF/dayz_code/util/Mutex.hpp b/SQF/dayz_code/util/Mutex.hpp new file mode 100644 index 000000000..99a08ce05 --- /dev/null +++ b/SQF/dayz_code/util/Mutex.hpp @@ -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 \ No newline at end of file diff --git a/SQF/dayz_code/util/Player.hpp b/SQF/dayz_code/util/Player.hpp new file mode 100644 index 000000000..67f475db2 --- /dev/null +++ b/SQF/dayz_code/util/Player.hpp @@ -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 \ No newline at end of file diff --git a/SQF/dayz_code/util/Queue.hpp b/SQF/dayz_code/util/Queue.hpp new file mode 100644 index 000000000..440eff35f --- /dev/null +++ b/SQF/dayz_code/util/Queue.hpp @@ -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 \ No newline at end of file diff --git a/SQF/dayz_code/util/Reference.hpp b/SQF/dayz_code/util/Reference.hpp new file mode 100644 index 000000000..679316f3e --- /dev/null +++ b/SQF/dayz_code/util/Reference.hpp @@ -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 \ No newline at end of file diff --git a/SQF/dayz_code/util/Request.hpp b/SQF/dayz_code/util/Request.hpp new file mode 100644 index 000000000..1cfb124a0 --- /dev/null +++ b/SQF/dayz_code/util/Request.hpp @@ -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 \ No newline at end of file diff --git a/SQF/dayz_code/util/Request_Server.hpp b/SQF/dayz_code/util/Request_Server.hpp new file mode 100644 index 000000000..5951bc871 --- /dev/null +++ b/SQF/dayz_code/util/Request_Server.hpp @@ -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 \ No newline at end of file diff --git a/SQF/dayz_code/util/Stack.hpp b/SQF/dayz_code/util/Stack.hpp new file mode 100644 index 000000000..14e0fac72 --- /dev/null +++ b/SQF/dayz_code/util/Stack.hpp @@ -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 \ No newline at end of file diff --git a/SQF/dayz_code/util/String.hpp b/SQF/dayz_code/util/String.hpp new file mode 100644 index 000000000..d449c6934 --- /dev/null +++ b/SQF/dayz_code/util/String.hpp @@ -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 \ No newline at end of file diff --git a/SQF/dayz_code/util/Task.hpp b/SQF/dayz_code/util/Task.hpp new file mode 100644 index 000000000..0d7b299d0 --- /dev/null +++ b/SQF/dayz_code/util/Task.hpp @@ -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 \ No newline at end of file diff --git a/SQF/dayz_code/util/Util.hpp b/SQF/dayz_code/util/Util.hpp new file mode 100644 index 000000000..265af8e66 --- /dev/null +++ b/SQF/dayz_code/util/Util.hpp @@ -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 \ No newline at end of file diff --git a/SQF/dayz_code/util/Vector.hpp b/SQF/dayz_code/util/Vector.hpp new file mode 100644 index 000000000..93af4bd51 --- /dev/null +++ b/SQF/dayz_code/util/Vector.hpp @@ -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 \ No newline at end of file diff --git a/SQF/dayz_code/util/array.sqf b/SQF/dayz_code/util/array.sqf new file mode 100644 index 000000000..ae746391e --- /dev/null +++ b/SQF/dayz_code/util/array.sqf @@ -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 +}; \ No newline at end of file diff --git a/SQF/dayz_code/util/compile.sqf b/SQF/dayz_code/util/compile.sqf new file mode 100644 index 000000000..9e08c4be1 --- /dev/null +++ b/SQF/dayz_code/util/compile.sqf @@ -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); \ No newline at end of file diff --git a/SQF/dayz_code/util/debug.sqf b/SQF/dayz_code/util/debug.sqf new file mode 100644 index 000000000..54bea0334 --- /dev/null +++ b/SQF/dayz_code/util/debug.sqf @@ -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 diff --git a/SQF/dayz_code/util/dictionary.sqf b/SQF/dayz_code/util/dictionary.sqf new file mode 100644 index 000000000..f7df7f255 --- /dev/null +++ b/SQF/dayz_code/util/dictionary.sqf @@ -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]; +}; \ No newline at end of file diff --git a/SQF/dayz_code/util/math.sqf b/SQF/dayz_code/util/math.sqf new file mode 100644 index 000000000..e3dbeddd8 --- /dev/null +++ b/SQF/dayz_code/util/math.sqf @@ -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)) +}; \ No newline at end of file diff --git a/SQF/dayz_code/util/mutex.sqf b/SQF/dayz_code/util/mutex.sqf new file mode 100644 index 000000000..c45ebc112 --- /dev/null +++ b/SQF/dayz_code/util/mutex.sqf @@ -0,0 +1,11 @@ +#include "Mutex.hpp" + +dz_fn_mutex_tryLock = +{ + Mutex_TryLock_Fast(_this); +}; + +dz_fn_mutex_waitLock = +{ + Mutex_WaitLock_Fast(_this); +}; \ No newline at end of file diff --git a/SQF/dayz_code/util/player.sqf b/SQF/dayz_code/util/player.sqf new file mode 100644 index 000000000..8e71b53f5 --- /dev/null +++ b/SQF/dayz_code/util/player.sqf @@ -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 +}; \ No newline at end of file diff --git a/SQF/dayz_code/util/queue.sqf b/SQF/dayz_code/util/queue.sqf new file mode 100644 index 000000000..e9d7e3d5e --- /dev/null +++ b/SQF/dayz_code/util/queue.sqf @@ -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); +}; \ No newline at end of file diff --git a/SQF/dayz_code/util/readme.txt b/SQF/dayz_code/util/readme.txt new file mode 100644 index 000000000..fbbdfbd1f --- /dev/null +++ b/SQF/dayz_code/util/readme.txt @@ -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)); \ No newline at end of file diff --git a/SQF/dayz_code/util/request.sqf b/SQF/dayz_code/util/request.sqf new file mode 100644 index 000000000..b147f2b8a --- /dev/null +++ b/SQF/dayz_code/util/request.sqf @@ -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;*/ + }; + }; +}; \ No newline at end of file diff --git a/SQF/dayz_code/util/stack.sqf b/SQF/dayz_code/util/stack.sqf new file mode 100644 index 000000000..8bf9a4537 --- /dev/null +++ b/SQF/dayz_code/util/stack.sqf @@ -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) +}; \ No newline at end of file diff --git a/SQF/dayz_code/util/task.sqf b/SQF/dayz_code/util/task.sqf new file mode 100644 index 000000000..ff548b288 --- /dev/null +++ b/SQF/dayz_code/util/task.sqf @@ -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 +};*/ \ No newline at end of file diff --git a/SQF/dayz_code/util/util.sqf b/SQF/dayz_code/util/util.sqf new file mode 100644 index 000000000..633d1aac9 --- /dev/null +++ b/SQF/dayz_code/util/util.sqf @@ -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); +}; \ No newline at end of file diff --git a/SQF/dayz_code/util/vector.sqf b/SQF/dayz_code/util/vector.sqf new file mode 100644 index 000000000..bbf54bf01 --- /dev/null +++ b/SQF/dayz_code/util/vector.sqf @@ -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 +}; \ No newline at end of file