From b74175ec9e0054155268bde7648cf22ca6cc8339 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nicol=C3=A1s=20Badano?=
Date: Sun, 15 Feb 2015 17:24:24 -0300
Subject: [PATCH 01/36] Don't allow adjusting range if only rangefinder is
available
---
addons/fcs/initKeybinds.sqf | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/addons/fcs/initKeybinds.sqf b/addons/fcs/initKeybinds.sqf
index dd1a94b78e..cbda9bdecc 100644
--- a/addons/fcs/initKeybinds.sqf
+++ b/addons/fcs/initKeybinds.sqf
@@ -51,7 +51,7 @@
_exceptions = [];
if !(_exceptions call EGVAR(common,canInteract)) exitWith {false};
// Conditions: specific
- if !(call FUNC(canUseRangefinder) || FUNC(canUseFCS)) exitWith {false};
+ if !(FUNC(canUseFCS)) exitWith {false};
// Statement
[vehicle ACE_player, [ACE_player] call EFUNC(common,getTurretIndex), 50] call FUNC(adjustRange);
@@ -69,7 +69,7 @@
_exceptions = [];
if !(_exceptions call EGVAR(common,canInteract)) exitWith {false};
// Conditions: specific
- if !(call FUNC(canUseRangefinder) || FUNC(canUseFCS)) exitWith {false};
+ if !(FUNC(canUseFCS)) exitWith {false};
// Statement
[vehicle ACE_player, [ACE_player] call EFUNC(common,getTurretIndex), -50] call FUNC(adjustRange);
From cb15a7106cd01927a62946b4ee56009ed2fcd04a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nicol=C3=A1s=20Badano?=
Date: Sun, 15 Feb 2015 17:26:08 -0300
Subject: [PATCH 02/36] Allow adding FCS to static weapons
---
addons/fcs/CfgEventHandlers.hpp | 15 +++++++++++++++
1 file changed, 15 insertions(+)
diff --git a/addons/fcs/CfgEventHandlers.hpp b/addons/fcs/CfgEventHandlers.hpp
index 961a05b27d..a03ca847ea 100644
--- a/addons/fcs/CfgEventHandlers.hpp
+++ b/addons/fcs/CfgEventHandlers.hpp
@@ -36,6 +36,11 @@ class Extended_Init_EventHandlers {
serverInit = QUOTE(_this call FUNC(vehicleInit));
};
};
+ class StaticWeapon {
+ class ADDON {
+ serverInit = QUOTE(_this call FUNC(vehicleInit));
+ };
+ };
};
class Extended_Respawn_EventHandlers {
@@ -64,6 +69,11 @@ class Extended_Respawn_EventHandlers {
respawn = QUOTE(_this call FUNC(vehicleInit));
};
};
+ class StaticWeapon {
+ class ADDON {
+ respawn = QUOTE(_this call FUNC(vehicleInit));
+ };
+ };
};
class Extended_FiredBIS_EventHandlers {
@@ -92,4 +102,9 @@ class Extended_FiredBIS_EventHandlers {
firedBIS = QUOTE(_this call FUNC(firedEH));
};
};
+ class StaticWeapon {
+ class ADDON {
+ firedBIS = QUOTE(_this call FUNC(firedEH));
+ };
+ };
};
From 08af51c4a78f0c0264b56e98a50a77d209da2d88 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nicol=C3=A1s=20Badano?=
Date: Sun, 15 Feb 2015 17:29:54 -0300
Subject: [PATCH 03/36] Allow overpressure for static weapons
---
addons/overpressure/CfgEventHandlers.hpp | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/addons/overpressure/CfgEventHandlers.hpp b/addons/overpressure/CfgEventHandlers.hpp
index 40c3b32a57..fa70cab5ea 100644
--- a/addons/overpressure/CfgEventHandlers.hpp
+++ b/addons/overpressure/CfgEventHandlers.hpp
@@ -43,4 +43,9 @@ class Extended_FiredBIS_EventHandlers {
firedBIS = QUOTE(if (local (_this select 0) && {getNumber (configfile >> 'CfgWeapons' >> _this select 1 >> QUOTE(QGVAR(Damage))) > 0}) then {_this call DFUNC(fireOverpressureZone)});
};
};
+ class StaticWeapons {
+ class ADDON {
+ firedBIS = QUOTE(if (local (_this select 0) && {getNumber (configfile >> 'CfgWeapons' >> _this select 1 >> QUOTE(QGVAR(Damage))) > 0}) then {_this call DFUNC(fireOverpressureZone)});
+ };
+ };
};
From 2105bc18db2d11d71782cc182ade12b781f72dc0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nicol=C3=A1s=20Badano?=
Date: Sun, 15 Feb 2015 17:43:57 -0300
Subject: [PATCH 04/36] Fixes for the FCS; it was missing a lot of `call`s
before `FUNC`s.
That made the rangefinder only work once. The flag for preventing holding is not needed becase GVAR(enabled) serving the same purpose.
---
addons/fcs/functions/fnc_keyDown.sqf | 2 +-
addons/fcs/initKeybinds.sqf | 15 ++++-----------
2 files changed, 5 insertions(+), 12 deletions(-)
diff --git a/addons/fcs/functions/fnc_keyDown.sqf b/addons/fcs/functions/fnc_keyDown.sqf
index 7699b82a20..5e2fabccc9 100644
--- a/addons/fcs/functions/fnc_keyDown.sqf
+++ b/addons/fcs/functions/fnc_keyDown.sqf
@@ -19,7 +19,7 @@ _turret = _this select 1;
_distance = call FUNC(getRange);
-if !(!GVAR(enabled) && FUNC(canUseFCS)) exitWith {};
+if !(!GVAR(enabled) && [] call FUNC(canUseFCS)) exitWith {};
GVAR(Enabled) = true;
GVAR(Time) = time;
diff --git a/addons/fcs/initKeybinds.sqf b/addons/fcs/initKeybinds.sqf
index cbda9bdecc..b9ca0a927a 100644
--- a/addons/fcs/initKeybinds.sqf
+++ b/addons/fcs/initKeybinds.sqf
@@ -7,11 +7,7 @@
_exceptions = [];
if !(_exceptions call EGVAR(common,canInteract)) exitWith {false};
// Conditions: specific
- if !((!GVAR(enabled) && FUNC(canUseFCS)) || FUNC(canUseRangefinder)) exitWith {false};
-
- // prevent holding down
- if (GETGVAR(isDownStateKey1,false)) exitWith {false};
- GVAR(isDownStateKey1) = true;
+ if !((!GVAR(enabled) && [] call FUNC(canUseFCS)) || [] call FUNC(canUseRangefinder)) exitWith {false};
// Statement
[vehicle ACE_player, [ACE_player] call EFUNC(common,getTurretIndex)] call FUNC(keyDown);
@@ -26,14 +22,11 @@
["ACE3",
localize "STR_ACE_FCS_LaseTarget",
{
- // prevent holding down
- GVAR(isDownStateKey1) = false;
-
// Conditions: canInteract
_exceptions = [];
if !(_exceptions call EGVAR(common,canInteract)) exitWith {false};
// Conditions: specific
- if !(GVAR(enabled) && FUNC(canUseFCS)) exitWith {false};
+ if !(GVAR(enabled) && [] call FUNC(canUseFCS)) exitWith {false};
// Statement
[vehicle ACE_player, [ACE_player] call EFUNC(common,getTurretIndex)] call FUNC(keyUp);
@@ -51,7 +44,7 @@
_exceptions = [];
if !(_exceptions call EGVAR(common,canInteract)) exitWith {false};
// Conditions: specific
- if !(FUNC(canUseFCS)) exitWith {false};
+ if !([] call FUNC(canUseFCS)) exitWith {false};
// Statement
[vehicle ACE_player, [ACE_player] call EFUNC(common,getTurretIndex), 50] call FUNC(adjustRange);
@@ -69,7 +62,7 @@
_exceptions = [];
if !(_exceptions call EGVAR(common,canInteract)) exitWith {false};
// Conditions: specific
- if !(FUNC(canUseFCS)) exitWith {false};
+ if !([] call FUNC(canUseFCS)) exitWith {false};
// Statement
[vehicle ACE_player, [ACE_player] call EFUNC(common,getTurretIndex), -50] call FUNC(adjustRange);
From a1e5931f4ef0579411ce71e54baf806508e2feab Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nicol=C3=A1s=20Badano?=
Date: Sun, 15 Feb 2015 18:06:17 -0300
Subject: [PATCH 05/36] avoid having to compute distance when it's already
passed as a parameter
---
addons/fcs/functions/fnc_keyDown.sqf | 3 ++-
addons/fcs/functions/fnc_keyUp.sqf | 26 +++++++++++++-------------
2 files changed, 15 insertions(+), 14 deletions(-)
diff --git a/addons/fcs/functions/fnc_keyDown.sqf b/addons/fcs/functions/fnc_keyDown.sqf
index 5e2fabccc9..24e4a7611d 100644
--- a/addons/fcs/functions/fnc_keyDown.sqf
+++ b/addons/fcs/functions/fnc_keyDown.sqf
@@ -19,7 +19,8 @@ _turret = _this select 1;
_distance = call FUNC(getRange);
-if !(!GVAR(enabled) && [] call FUNC(canUseFCS)) exitWith {};
+if (GVAR(Enabled)) exitWith {};
+if !([] call FUNC(canUseFCS)) exitWith {};
GVAR(Enabled) = true;
GVAR(Time) = time;
diff --git a/addons/fcs/functions/fnc_keyUp.sqf b/addons/fcs/functions/fnc_keyUp.sqf
index 1e5878f0b5..b893262e88 100644
--- a/addons/fcs/functions/fnc_keyUp.sqf
+++ b/addons/fcs/functions/fnc_keyUp.sqf
@@ -19,18 +19,22 @@ _turret = _this select 1;
_turretConfig = [configFile >> "CfgVehicles" >> typeOf _vehicle, _turret] call EFUNC(common,getTurretConfigPath);
-_distance = call FUNC(getRange);
+_distance = 0;
+if (count _this > 2) then {
+ _distance = _this select 2;
+} else {
+ _distance = call FUNC(getRange);
+ if (_distance == 0) then {
+ _distance = [
+ getNumber (_turretConfig >> QGVAR(DistanceInterval)),
+ getNumber (_turretConfig >> QGVAR(MaxDistance)),
+ getNumber (_turretConfig >> QGVAR(MinDistance))
+ ] call EFUNC(common,getTargetDistance); // maximum distance: 5000m, 5m precision
+ };
+};
_magazines = _vehicle magazinesTurret _turret;
-if (_distance == 0) then {
- _distance = [
- getNumber (_turretConfig >> QGVAR(DistanceInterval)),
- getNumber (_turretConfig >> QGVAR(MaxDistance)),
- getNumber (_turretConfig >> QGVAR(MinDistance))
- ] call EFUNC(common,getTargetDistance); // maximum distance: 5000m, 5m precision
-};
-
private ["_weaponDirection", "_angleTarget"];
_weaponDirection = _vehicle weaponDirection (_vehicle currentWeaponTurret _turret); // @todo doesn't work for sub turrets
@@ -45,10 +49,6 @@ if (_weaponDirection isEqualTo [0,0,0]) then { // dummy value for non main turr
_angleTarget = asin (_weaponDirection select 2);
-if (count _this > 2) then {
- _distance = _this select 2;
-};
-
if (!(isNil QGVAR(backgroundCalculation)) and {!(scriptDone GVAR(backgroundCalculation))}) then {
terminate GVAR(backgroundCalculation);
};
From d7430065669c586c0dcf48e983bce72a586c86f5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nicol=C3=A1s=20Badano?=
Date: Sun, 15 Feb 2015 18:38:08 -0300
Subject: [PATCH 06/36] make vector keybinds return false so they don't block
fcs keyup EH
---
addons/vector/initKeybinds.sqf | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/addons/vector/initKeybinds.sqf b/addons/vector/initKeybinds.sqf
index f81c280905..fb00e7acb3 100644
--- a/addons/vector/initKeybinds.sqf
+++ b/addons/vector/initKeybinds.sqf
@@ -15,7 +15,7 @@
// Statement
["azimuth"] call FUNC(onKeyDown);
- true
+ false
},
[15, [false, false, false]],
false,
@@ -34,7 +34,7 @@
// Statement
["azimuth"] call FUNC(onKeyUp);
- true
+ false
},
[15, [false, false, false]],
false,
From 58212f5ce0a6329b9082ad0af6c30644d97f5fd5 Mon Sep 17 00:00:00 2001
From: commy2
Date: Sat, 14 Mar 2015 12:05:43 +0100
Subject: [PATCH 07/36] add PBO to drag objects
---
addons/dragging/$PBOPREFIX$ | 1 +
addons/dragging/CfgEventHandlers.hpp | 6 ++++++
addons/dragging/XEH_preInit.sqf | 7 +++++++
addons/dragging/config.cpp | 15 +++++++++++++++
addons/dragging/functions/fnc_empty.sqf | 3 +++
addons/dragging/functions/script_component.hpp | 1 +
addons/dragging/script_component.hpp | 12 ++++++++++++
7 files changed, 45 insertions(+)
create mode 100644 addons/dragging/$PBOPREFIX$
create mode 100644 addons/dragging/CfgEventHandlers.hpp
create mode 100644 addons/dragging/XEH_preInit.sqf
create mode 100644 addons/dragging/config.cpp
create mode 100644 addons/dragging/functions/fnc_empty.sqf
create mode 100644 addons/dragging/functions/script_component.hpp
create mode 100644 addons/dragging/script_component.hpp
diff --git a/addons/dragging/$PBOPREFIX$ b/addons/dragging/$PBOPREFIX$
new file mode 100644
index 0000000000..4090738414
--- /dev/null
+++ b/addons/dragging/$PBOPREFIX$
@@ -0,0 +1 @@
+z\ace\addons\dragging
\ No newline at end of file
diff --git a/addons/dragging/CfgEventHandlers.hpp b/addons/dragging/CfgEventHandlers.hpp
new file mode 100644
index 0000000000..f0a9f14d91
--- /dev/null
+++ b/addons/dragging/CfgEventHandlers.hpp
@@ -0,0 +1,6 @@
+
+class Extended_PreInit_EventHandlers {
+ class ADDON {
+ init = QUOTE(call COMPILE_FILE(XEH_preInit));
+ };
+};
diff --git a/addons/dragging/XEH_preInit.sqf b/addons/dragging/XEH_preInit.sqf
new file mode 100644
index 0000000000..69abb46fa9
--- /dev/null
+++ b/addons/dragging/XEH_preInit.sqf
@@ -0,0 +1,7 @@
+#include "script_component.hpp"
+
+ADDON = false;
+
+PREP(empty);
+
+ADDON = true;
diff --git a/addons/dragging/config.cpp b/addons/dragging/config.cpp
new file mode 100644
index 0000000000..ce4613ae39
--- /dev/null
+++ b/addons/dragging/config.cpp
@@ -0,0 +1,15 @@
+#include "script_component.hpp"
+
+class CfgPatches {
+ class ADDON {
+ units[] = {};
+ weapons[] = {};
+ requiredVersion = REQUIRED_VERSION;
+ requiredAddons[] = {"ace_common","ace_interact_menu"};
+ author[] = {"https://github.com/commy2/"};
+ authorUrl = "";
+ VERSION_CONFIG;
+ };
+};
+
+#include "CfgEventHandlers.hpp"
diff --git a/addons/dragging/functions/fnc_empty.sqf b/addons/dragging/functions/fnc_empty.sqf
new file mode 100644
index 0000000000..c60a82b2d8
--- /dev/null
+++ b/addons/dragging/functions/fnc_empty.sqf
@@ -0,0 +1,3 @@
+#include "script_component.hpp"
+
+diag_log text format["This is here as an example!!!"];
diff --git a/addons/dragging/functions/script_component.hpp b/addons/dragging/functions/script_component.hpp
new file mode 100644
index 0000000000..9d257a69d3
--- /dev/null
+++ b/addons/dragging/functions/script_component.hpp
@@ -0,0 +1 @@
+#include "\z\ace\addons\dragging\script_component.hpp"
\ No newline at end of file
diff --git a/addons/dragging/script_component.hpp b/addons/dragging/script_component.hpp
new file mode 100644
index 0000000000..3e8c54519b
--- /dev/null
+++ b/addons/dragging/script_component.hpp
@@ -0,0 +1,12 @@
+#define COMPONENT dragging
+#include "\z\ace\addons\main\script_mod.hpp"
+
+#ifdef DEBUG_ENABLED_DRAGGING
+ #define DEBUG_MODE_FULL
+#endif
+
+#ifdef DEBUG_ENABLED_DRAGGING
+ #define DEBUG_SETTINGS DEBUG_ENABLED_DRAGGING
+#endif
+
+#include "\z\ace\addons\main\script_macros.hpp"
\ No newline at end of file
From f3f20439c851b0cbb417dca94001b84f5551421c Mon Sep 17 00:00:00 2001
From: commy2
Date: Sat, 14 Mar 2015 13:51:23 +0100
Subject: [PATCH 08/36] config stuff, functions to make objects dragable
---
addons/dragging/CfgEventHandlers.hpp | 14 +++++
addons/dragging/CfgVehicles.hpp | 43 +++++++++++++++
addons/dragging/XEH_postInit.sqf | 11 ++++
addons/dragging/XEH_preInit.sqf | 3 +-
addons/dragging/config.cpp | 1 +
addons/dragging/functions/fnc_empty.sqf | 3 -
addons/dragging/functions/fnc_initObject.sqf | 25 +++++++++
.../dragging/functions/fnc_setDraggable.sqf | 55 +++++++++++++++++++
8 files changed, 151 insertions(+), 4 deletions(-)
create mode 100644 addons/dragging/CfgVehicles.hpp
create mode 100644 addons/dragging/XEH_postInit.sqf
delete mode 100644 addons/dragging/functions/fnc_empty.sqf
create mode 100644 addons/dragging/functions/fnc_initObject.sqf
create mode 100644 addons/dragging/functions/fnc_setDraggable.sqf
diff --git a/addons/dragging/CfgEventHandlers.hpp b/addons/dragging/CfgEventHandlers.hpp
index f0a9f14d91..463ae20ddc 100644
--- a/addons/dragging/CfgEventHandlers.hpp
+++ b/addons/dragging/CfgEventHandlers.hpp
@@ -4,3 +4,17 @@ class Extended_PreInit_EventHandlers {
init = QUOTE(call COMPILE_FILE(XEH_preInit));
};
};
+
+class Extended_PostInit_EventHandlers {
+ class ADDON {
+ init = QUOTE(call COMPILE_FILE(XEH_preInit));
+ };
+};
+
+class Extended_Init_EventHandlers {
+ class ThingX {
+ class ADDON {
+ init = QUOTE(if (local (_this select 0)) then {_this call DFUNC(initObject)};);
+ };
+ };
+};
diff --git a/addons/dragging/CfgVehicles.hpp b/addons/dragging/CfgVehicles.hpp
new file mode 100644
index 0000000000..e20cc9f6e9
--- /dev/null
+++ b/addons/dragging/CfgVehicles.hpp
@@ -0,0 +1,43 @@
+
+class CfgVehicles {
+ class ThingX;
+ class ReammoBox_F: ThingX {
+ GVAR(canDrag) = 0;
+ GVAR(dragPosition[]) = {0,1,1};
+ GVAR(dragDirection) = 0;
+ };
+
+ class Slingload_base_F: ReammoBox_F {
+ GVAR(canDrag) = 0;
+ };
+
+ class EAST_Box_Base: ReammoBox_F {
+ GVAR(canDrag) = 1;
+ };
+ class IND_Box_Base: ReammoBox_F {
+ GVAR(canDrag) = 1;
+ };
+ /*class FIA_Box_Base_F: ReammoBox_F {
+ GVAR(canDrag) = 1;
+ };*/
+ class NATO_Box_Base: ReammoBox_F {
+ GVAR(canDrag) = 1;
+ };
+
+ // Remove Larger crate dragging support.
+ // Would be better to allow some sort of joint push/drag functionality
+ // Requiring 2 units to access the larger crates and attaching them together (a crappy method of doing it)
+ // in order to move the bigger ones. Currently simply remove support.
+ // I believe these crates are currently broken (hitbox doesn't work or something) in 1.22 (2014-07-04)
+ class Box_East_AmmoVeh_F: EAST_Box_Base {
+ GVAR(canDrag) = 0;
+ };
+
+ class Box_NATO_AmmoVeh_F: NATO_Box_Base {
+ GVAR(canDrag) = 0;
+ };
+
+ class Box_IND_AmmoVeh_F: IND_Box_Base {
+ GVAR(canDrag) = 0;
+ };
+};
diff --git a/addons/dragging/XEH_postInit.sqf b/addons/dragging/XEH_postInit.sqf
new file mode 100644
index 0000000000..18dff50699
--- /dev/null
+++ b/addons/dragging/XEH_postInit.sqf
@@ -0,0 +1,11 @@
+// by PabstMirror
+
+#include "script_component.hpp"
+
+GVAR(currentHeightChange) = 0;
+
+[{_this call DFUNC(handleScrollWheel)}] call FUNC(common,addScrollWheelEventHandler);
+
+if (isNil QGVAR(maxWeight)) then {
+ GVAR(maxWeight) = 800;
+};
diff --git a/addons/dragging/XEH_preInit.sqf b/addons/dragging/XEH_preInit.sqf
index 69abb46fa9..3825d1b429 100644
--- a/addons/dragging/XEH_preInit.sqf
+++ b/addons/dragging/XEH_preInit.sqf
@@ -2,6 +2,7 @@
ADDON = false;
-PREP(empty);
+PREP(initObject);
+PREP(setDraggable);
ADDON = true;
diff --git a/addons/dragging/config.cpp b/addons/dragging/config.cpp
index ce4613ae39..35f9f6d492 100644
--- a/addons/dragging/config.cpp
+++ b/addons/dragging/config.cpp
@@ -13,3 +13,4 @@ class CfgPatches {
};
#include "CfgEventHandlers.hpp"
+#include "CfgVehicles.hpp"
diff --git a/addons/dragging/functions/fnc_empty.sqf b/addons/dragging/functions/fnc_empty.sqf
deleted file mode 100644
index c60a82b2d8..0000000000
--- a/addons/dragging/functions/fnc_empty.sqf
+++ /dev/null
@@ -1,3 +0,0 @@
-#include "script_component.hpp"
-
-diag_log text format["This is here as an example!!!"];
diff --git a/addons/dragging/functions/fnc_initObject.sqf b/addons/dragging/functions/fnc_initObject.sqf
new file mode 100644
index 0000000000..3d1f51ad21
--- /dev/null
+++ b/addons/dragging/functions/fnc_initObject.sqf
@@ -0,0 +1,25 @@
+/*
+ * Author: commy2
+ *
+ * Initialize variables for dragable objects. Called from init EH.
+ *
+ * Argument:
+ * 0: Any object (Object)
+ *
+ * Return value:
+ * NONE.
+ */
+#include "script_component.hpp"
+
+private "_object";
+
+_object = _this select 0;
+
+if (getNumber (configFile >> "CfgVehicles" >> typeOf _object >> QGVAR(canDrag)) == 1) then {
+ private ["_position", "_direction"];
+
+ _position = getArray (configFile >> "CfgVehicles" >> typeOf _object >> QGVAR(dragPosition));
+ _direction = getNumber (configFile >> "CfgVehicles" >> typeOf _object >> QGVAR(dragDirection));
+
+ [_object, true, _position, _direction] call FUNC(setDraggable);
+};
diff --git a/addons/dragging/functions/fnc_setDraggable.sqf b/addons/dragging/functions/fnc_setDraggable.sqf
new file mode 100644
index 0000000000..6c068540a6
--- /dev/null
+++ b/addons/dragging/functions/fnc_setDraggable.sqf
@@ -0,0 +1,55 @@
+/*
+ * Author: commy2
+ *
+ * Enable the object to be dragged.
+ *
+ * Argument:
+ * 0: Any object (Object)
+ * 1: true to enable dragging, false to disable (Bool)
+ * 2: Position offset for attachTo command (Array, optinal; default: [0,0,0])
+ * 3: Direction in degree to rotate the object after attachTo (Number, optional; default: 0)
+ *
+ * Return value:
+ * NONE.
+ */
+#include "script_component.hpp"
+
+private ["_object", "_enableDrag", "_position", "_direction"];
+
+_this resize 4;
+
+_object = _this select 0;
+_enableDrag = _this select 1;
+_position = _this select 2;
+_direction = _this select 3;
+
+if (isNil "_position") then {
+ _position = _object getVariable [QGVAR(dragPosition), [0,0,0]];
+};
+
+if (isNil "_direction") then {
+ _direction = _object getVariable [QGVAR(dragDirection), 0];
+};
+
+// update variables
+_object setVariable [QGVAR(canDrag), _enableDrag, true];
+_object setVariable [QGVAR(dragPosition), _position, true];
+_object setVariable [QGVAR(dragDirection), _direction, true];
+
+// add action to class if it is not already present
+private ["_type", "_initializedClasses"];
+
+_initializedClasses = GETMVAR(GVAR(initializedClasses),[]);
+
+// do nothing if the class is already initialized
+if (_type in _initializedClasses) exitWith {};
+
+private ["_name", "_icon", "_selection", "_statement", "_condition"];
+
+_name = "drag";
+_icon = "";
+_selection = "";
+_statement = {hint str _target};
+_condition = {true};
+
+[_type, 0, [_name], _name, _icon, _selection, _statement, _condition, 2] call EFUNC(interact_menu,addClassAction);
From b79978116da8facfb896777a964035f98b98c97b Mon Sep 17 00:00:00 2001
From: commy2
Date: Sat, 14 Mar 2015 18:38:44 +0100
Subject: [PATCH 09/36] some functions
---
addons/dragging/functions/fnc_canDrag.sqf | 0
addons/dragging/functions/fnc_startDrag.sqf | 0
2 files changed, 0 insertions(+), 0 deletions(-)
create mode 100644 addons/dragging/functions/fnc_canDrag.sqf
create mode 100644 addons/dragging/functions/fnc_startDrag.sqf
diff --git a/addons/dragging/functions/fnc_canDrag.sqf b/addons/dragging/functions/fnc_canDrag.sqf
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/addons/dragging/functions/fnc_startDrag.sqf b/addons/dragging/functions/fnc_startDrag.sqf
new file mode 100644
index 0000000000..e69de29bb2
From efb3657da3f6bee0f1223dbb592286ea564ef555 Mon Sep 17 00:00:00 2001
From: commy2
Date: Mon, 16 Mar 2015 14:31:16 +0100
Subject: [PATCH 10/36] drag boxes
---
addons/dragging/CfgEventHandlers.hpp | 4 ++--
addons/dragging/CfgVehicles.hpp | 1 +
addons/dragging/XEH_preInit.sqf | 2 ++
addons/dragging/functions/fnc_canDrag.sqf | 1 +
addons/dragging/functions/fnc_setDraggable.sqf | 10 ++++------
addons/dragging/functions/fnc_startDrag.sqf | 2 ++
addons/interact_menu/functions/fnc_compileMenu.sqf | 2 +-
addons/main/script_macros.hpp | 1 +
8 files changed, 14 insertions(+), 9 deletions(-)
diff --git a/addons/dragging/CfgEventHandlers.hpp b/addons/dragging/CfgEventHandlers.hpp
index 463ae20ddc..2821f3d307 100644
--- a/addons/dragging/CfgEventHandlers.hpp
+++ b/addons/dragging/CfgEventHandlers.hpp
@@ -12,9 +12,9 @@ class Extended_PostInit_EventHandlers {
};
class Extended_Init_EventHandlers {
- class ThingX {
+ class ReammoBox_F {
class ADDON {
- init = QUOTE(if (local (_this select 0)) then {_this call DFUNC(initObject)};);
+ init = QUOTE(_this call DFUNC(initObject));
};
};
};
diff --git a/addons/dragging/CfgVehicles.hpp b/addons/dragging/CfgVehicles.hpp
index e20cc9f6e9..3b7f43fead 100644
--- a/addons/dragging/CfgVehicles.hpp
+++ b/addons/dragging/CfgVehicles.hpp
@@ -2,6 +2,7 @@
class CfgVehicles {
class ThingX;
class ReammoBox_F: ThingX {
+ XEH_ENABLED;
GVAR(canDrag) = 0;
GVAR(dragPosition[]) = {0,1,1};
GVAR(dragDirection) = 0;
diff --git a/addons/dragging/XEH_preInit.sqf b/addons/dragging/XEH_preInit.sqf
index 3825d1b429..ba4327f9e2 100644
--- a/addons/dragging/XEH_preInit.sqf
+++ b/addons/dragging/XEH_preInit.sqf
@@ -2,7 +2,9 @@
ADDON = false;
+PREP(canDrag);
PREP(initObject);
PREP(setDraggable);
+PREP(startDrag);
ADDON = true;
diff --git a/addons/dragging/functions/fnc_canDrag.sqf b/addons/dragging/functions/fnc_canDrag.sqf
index e69de29bb2..f32a5804e2 100644
--- a/addons/dragging/functions/fnc_canDrag.sqf
+++ b/addons/dragging/functions/fnc_canDrag.sqf
@@ -0,0 +1 @@
+true
\ No newline at end of file
diff --git a/addons/dragging/functions/fnc_setDraggable.sqf b/addons/dragging/functions/fnc_setDraggable.sqf
index 6c068540a6..3e185cf81f 100644
--- a/addons/dragging/functions/fnc_setDraggable.sqf
+++ b/addons/dragging/functions/fnc_setDraggable.sqf
@@ -32,9 +32,9 @@ if (isNil "_direction") then {
};
// update variables
-_object setVariable [QGVAR(canDrag), _enableDrag, true];
-_object setVariable [QGVAR(dragPosition), _position, true];
-_object setVariable [QGVAR(dragDirection), _direction, true];
+_object setVariable [QGVAR(canDrag), _enableDrag];
+_object setVariable [QGVAR(dragPosition), _position];
+_object setVariable [QGVAR(dragDirection), _direction];
// add action to class if it is not already present
private ["_type", "_initializedClasses"];
@@ -49,7 +49,5 @@ private ["_name", "_icon", "_selection", "_statement", "_condition"];
_name = "drag";
_icon = "";
_selection = "";
-_statement = {hint str _target};
-_condition = {true};
-[_type, 0, [_name], _name, _icon, _selection, _statement, _condition, 2] call EFUNC(interact_menu,addClassAction);
+[_type, 0, [_name], _name, _icon, _selection, FUNC(startDrag), FUNC(canDrag), 2] call EFUNC(interact_menu,addClassAction);
diff --git a/addons/dragging/functions/fnc_startDrag.sqf b/addons/dragging/functions/fnc_startDrag.sqf
index e69de29bb2..324bf850d5 100644
--- a/addons/dragging/functions/fnc_startDrag.sqf
+++ b/addons/dragging/functions/fnc_startDrag.sqf
@@ -0,0 +1,2 @@
+
+hint str _target
diff --git a/addons/interact_menu/functions/fnc_compileMenu.sqf b/addons/interact_menu/functions/fnc_compileMenu.sqf
index e6a2744f03..fe3da17917 100644
--- a/addons/interact_menu/functions/fnc_compileMenu.sqf
+++ b/addons/interact_menu/functions/fnc_compileMenu.sqf
@@ -18,7 +18,7 @@ private ["_objectType","_actionsVarName"];
_objectType = _target;
if (typeName _target == "OBJECT") then {
_objectType = typeOf _target;
-};
+};systemChat _objectType;
_actionsVarName = format [QGVAR(Act_%1), _objectType];
// Exit if the action menu is already compiled for this class
diff --git a/addons/main/script_macros.hpp b/addons/main/script_macros.hpp
index 33f1037905..8425c4ad1e 100644
--- a/addons/main/script_macros.hpp
+++ b/addons/main/script_macros.hpp
@@ -1,4 +1,5 @@
#include "\x\cba\addons\main\script_macros_common.hpp"
+#include "\x\cba\addons\xeh\script_xeh.hpp"
// Default versioning level
#define DEFAULT_VERSIONING_LEVEL 2
From ad181de5786899f47e451f43127c93956718d98e Mon Sep 17 00:00:00 2001
From: commy2
Date: Mon, 16 Mar 2015 15:41:55 +0100
Subject: [PATCH 11/36] main me nu for reammo_box
---
addons/dragging/functions/fnc_setDraggable.sqf | 8 ++++++--
addons/interaction/CfgVehicles.hpp | 13 +++++++++++++
2 files changed, 19 insertions(+), 2 deletions(-)
diff --git a/addons/dragging/functions/fnc_setDraggable.sqf b/addons/dragging/functions/fnc_setDraggable.sqf
index 3e185cf81f..6ffa3476cc 100644
--- a/addons/dragging/functions/fnc_setDraggable.sqf
+++ b/addons/dragging/functions/fnc_setDraggable.sqf
@@ -39,15 +39,19 @@ _object setVariable [QGVAR(dragDirection), _direction];
// add action to class if it is not already present
private ["_type", "_initializedClasses"];
-_initializedClasses = GETMVAR(GVAR(initializedClasses),[]);
+_type = typeOf _object;
+_initializedClasses = GETGVAR(initializedClasses,[]);
// do nothing if the class is already initialized
if (_type in _initializedClasses) exitWith {};
+_initializedClasses pushBack _type;
+GVAR(initializedClasses) = _initializedClasses;
+
private ["_name", "_icon", "_selection", "_statement", "_condition"];
_name = "drag";
_icon = "";
_selection = "";
-[_type, 0, [_name], _name, _icon, _selection, FUNC(startDrag), FUNC(canDrag), 2] call EFUNC(interact_menu,addClassAction);
+[_type, 0, ["ACE_MainActions", _name], _name, _icon, _selection, FUNC(startDrag), FUNC(canDrag), 2] call EFUNC(interact_menu,addClassAction);
diff --git a/addons/interaction/CfgVehicles.hpp b/addons/interaction/CfgVehicles.hpp
index 947c2e2579..1bd1e81be2 100644
--- a/addons/interaction/CfgVehicles.hpp
+++ b/addons/interaction/CfgVehicles.hpp
@@ -497,4 +497,17 @@ class CfgVehicles {
class ACE_SelfActions {};
};
+ class thingX;
+ class ReammoBox_F: thingX {
+ class ACE_Actions {
+ class ACE_MainActions {
+ displayName = "$STR_ACE_Interaction_MainAction";
+ selection = "";
+ distance = 2;
+ condition = "true";
+ };
+ };
+ class ACE_SelfActions {};
+ };
+
};
From 27404fed1b97084031688e84f3825073f08fa317 Mon Sep 17 00:00:00 2001
From: commy2
Date: Mon, 16 Mar 2015 19:25:29 +0100
Subject: [PATCH 12/36] function to drop object, fix position event
---
addons/common/XEH_postInit.sqf | 2 +
addons/common/XEH_preInit.sqf | 1 +
addons/common/functions/fnc_fixPosition.sqf | 29 ++++++++++
addons/dragging/CfgEventHandlers.hpp | 2 +-
addons/dragging/CfgVehicles.hpp | 2 +-
addons/dragging/XEH_clientInit.sqf | 13 +++++
addons/dragging/XEH_postInit.sqf | 11 ----
addons/dragging/XEH_preInit.sqf | 4 ++
addons/dragging/functions/fnc_dragObject.sqf | 54 +++++++++++++++++++
.../dragging/functions/fnc_dragObjectPFH.sqf | 30 +++++++++++
addons/dragging/functions/fnc_dropObject.sqf | 36 +++++++++++++
.../dragging/functions/fnc_setDraggable.sqf | 2 +-
addons/dragging/functions/fnc_startDrag.sqf | 37 ++++++++++++-
.../dragging/functions/fnc_startDragPFH.sqf | 20 +++++++
addons/dragging/script_component.hpp | 4 +-
15 files changed, 231 insertions(+), 16 deletions(-)
create mode 100644 addons/common/functions/fnc_fixPosition.sqf
create mode 100644 addons/dragging/XEH_clientInit.sqf
delete mode 100644 addons/dragging/XEH_postInit.sqf
create mode 100644 addons/dragging/functions/fnc_dragObject.sqf
create mode 100644 addons/dragging/functions/fnc_dragObjectPFH.sqf
create mode 100644 addons/dragging/functions/fnc_dropObject.sqf
create mode 100644 addons/dragging/functions/fnc_startDragPFH.sqf
diff --git a/addons/common/XEH_postInit.sqf b/addons/common/XEH_postInit.sqf
index 970eec92b4..1a26553ed7 100644
--- a/addons/common/XEH_postInit.sqf
+++ b/addons/common/XEH_postInit.sqf
@@ -20,6 +20,8 @@ if (hasInterface) then {
};
}] call FUNC(addEventhandler);
+["fixPosition", FUNC(fixPosition)] call FUNC(addEventhandler);
+
// hack to get PFH to work in briefing
[QGVAR(onBriefingPFH), "onEachFrame", {
if (time > 0) exitWith {
diff --git a/addons/common/XEH_preInit.sqf b/addons/common/XEH_preInit.sqf
index 73fe903684..c822de6d47 100644
--- a/addons/common/XEH_preInit.sqf
+++ b/addons/common/XEH_preInit.sqf
@@ -56,6 +56,7 @@ PREP(execRemoteFnc);
PREP(executePersistent);
PREP(filter);
PREP(fixLoweredRifleAnimation);
+PREP(fixPosition);
PREP(getAllDefinedSetVariables);
PREP(getAllGear);
PREP(getCaptivityStatus);
diff --git a/addons/common/functions/fnc_fixPosition.sqf b/addons/common/functions/fnc_fixPosition.sqf
new file mode 100644
index 0000000000..a59c509a96
--- /dev/null
+++ b/addons/common/functions/fnc_fixPosition.sqf
@@ -0,0 +1,29 @@
+/*
+ * Author: commy2
+ *
+ * Fixes position of an object. E.g. moves object above ground and adjusts to terrain slope. Requires local object.
+ *
+ * Argument:
+ * Object (Object)
+ *
+ * Return value:
+ * NONE
+ */
+#include "script_component.hpp"
+
+// setVectorUp requires local object
+if (!local _this) exitWith {};
+
+private "_position";
+_position = getPos _this;
+
+// don't place the object below the ground
+if (_position select 2 < 0) then {
+ _position set [2, 0];
+ _this setPos _position;
+};
+
+// adjust position to sloped terrain, if placed on ground
+if (getPosATL _this select 2 == _position select 2) then {
+ _this setVectorUp surfaceNormal _position;
+};
diff --git a/addons/dragging/CfgEventHandlers.hpp b/addons/dragging/CfgEventHandlers.hpp
index 2821f3d307..2ab440414c 100644
--- a/addons/dragging/CfgEventHandlers.hpp
+++ b/addons/dragging/CfgEventHandlers.hpp
@@ -7,7 +7,7 @@ class Extended_PreInit_EventHandlers {
class Extended_PostInit_EventHandlers {
class ADDON {
- init = QUOTE(call COMPILE_FILE(XEH_preInit));
+ clientInit = QUOTE(call COMPILE_FILE(XEH_clientInit));
};
};
diff --git a/addons/dragging/CfgVehicles.hpp b/addons/dragging/CfgVehicles.hpp
index 3b7f43fead..89721efd97 100644
--- a/addons/dragging/CfgVehicles.hpp
+++ b/addons/dragging/CfgVehicles.hpp
@@ -4,7 +4,7 @@ class CfgVehicles {
class ReammoBox_F: ThingX {
XEH_ENABLED;
GVAR(canDrag) = 0;
- GVAR(dragPosition[]) = {0,1,1};
+ GVAR(dragPosition[]) = {0,1.2,0};
GVAR(dragDirection) = 0;
};
diff --git a/addons/dragging/XEH_clientInit.sqf b/addons/dragging/XEH_clientInit.sqf
new file mode 100644
index 0000000000..339b7f590f
--- /dev/null
+++ b/addons/dragging/XEH_clientInit.sqf
@@ -0,0 +1,13 @@
+// by PabstMirror, commy2
+
+#include "script_component.hpp"
+
+GVAR(currentHeightChange) = 0;
+
+//[{_this call DFUNC(handleScrollWheel)}] call FUNC(common,addScrollWheelEventHandler);
+
+if (isNil QGVAR(maxWeight)) then {
+ GVAR(maxWeight) = 800;
+};
+
+["isNotDragging", {!((_this select 0) getVariable [QGVAR(isDragging), false])}] call EFUNC(common,addCanInteractWithCondition);
diff --git a/addons/dragging/XEH_postInit.sqf b/addons/dragging/XEH_postInit.sqf
deleted file mode 100644
index 18dff50699..0000000000
--- a/addons/dragging/XEH_postInit.sqf
+++ /dev/null
@@ -1,11 +0,0 @@
-// by PabstMirror
-
-#include "script_component.hpp"
-
-GVAR(currentHeightChange) = 0;
-
-[{_this call DFUNC(handleScrollWheel)}] call FUNC(common,addScrollWheelEventHandler);
-
-if (isNil QGVAR(maxWeight)) then {
- GVAR(maxWeight) = 800;
-};
diff --git a/addons/dragging/XEH_preInit.sqf b/addons/dragging/XEH_preInit.sqf
index ba4327f9e2..88bd1d3d22 100644
--- a/addons/dragging/XEH_preInit.sqf
+++ b/addons/dragging/XEH_preInit.sqf
@@ -3,8 +3,12 @@
ADDON = false;
PREP(canDrag);
+PREP(dragObject);
+PREP(dragObjectPFH);
+PREP(dropObject);
PREP(initObject);
PREP(setDraggable);
PREP(startDrag);
+PREP(startDragPFH);
ADDON = true;
diff --git a/addons/dragging/functions/fnc_dragObject.sqf b/addons/dragging/functions/fnc_dragObject.sqf
new file mode 100644
index 0000000000..9120c049b1
--- /dev/null
+++ b/addons/dragging/functions/fnc_dragObject.sqf
@@ -0,0 +1,54 @@
+/*
+ * Author: commy2
+ *
+ * Drag an object. Called from ace_dragging_fnc_startDrag
+ *
+ * Argument:
+ * 0: Unit that should do the dragging (Object)
+ * 1: Object to drag (Object)
+ *
+ * Return value:
+ * NONE.
+ */
+#include "script_component.hpp"
+
+private ["_unit", "_target"];
+
+_unit = _this select 0;
+_target = _this select 1;
+
+// get attachTo offset and direction.
+private ["_position", "_direction"];
+
+_position = _target getVariable [QGVAR(dragPosition), [0, 0, 0]];
+_direction = _target getVariable [QGVAR(dragDirection), 0];
+
+// add height offset of model
+private "_offset";
+_offset = (_target modelToWorld [0, 0, 0] select 2) - (_unit modelToWorld [0, 0, 0] select 2);
+
+_position = _position vectorAdd [0, 0, _offset];
+
+// attach object
+_target attachTo [_unit, _position];
+_target setDir _direction;
+
+// add scrollwheel action to release object
+/*
+ _actionID = _unit getVariable ["AGM_Drag_ReleaseActionID", -1];
+
+ if (_actionID != -1) then {
+ _unit removeAction _actionID;
+ };
+ _actionID = _unit addAction [format ["%1", localize "STR_AGM_Drag_EndDrag"], "player call AGM_Drag_fnc_releaseObject;", nil, 20, false, true, "","player call AGM_Drag_fnc_isDraggingObject"];
+
+ _unit setVariable ["AGM_Drag_ReleaseActionID", _actionID];
+*/
+
+_unit setVariable [QGVAR(isDragging), true, true];
+
+// check everything
+[FUNC(dragObjectPFH), 0, [_unit, _target]] call CBA_fnc_addPerFrameHandler;
+
+// reset current dragging height.
+GVAR(currentHeightChange) = 0;
diff --git a/addons/dragging/functions/fnc_dragObjectPFH.sqf b/addons/dragging/functions/fnc_dragObjectPFH.sqf
new file mode 100644
index 0000000000..cf8e710474
--- /dev/null
+++ b/addons/dragging/functions/fnc_dragObjectPFH.sqf
@@ -0,0 +1,30 @@
+// by commy2
+#include "script_component.hpp"
+
+private ["_unit", "_target"];
+
+_unit = _this select 0 select 0;
+_target = _this select 0 select 1;
+
+// drop if the player is dead
+if !([_unit] call EFUNC(common,isAlive)) exitWith {
+ [_unit, _target] call FUNC(dropObject);
+ [_this select 1] call CBA_fnc_removePerFrameHandler;
+};
+
+// drop if the crate is destroyed
+if !([_target] call EFUNC(common,isAlive)) exitWith {
+ [_unit, _target] call FUNC(dropObject);
+ [_this select 1] call CBA_fnc_removePerFrameHandler;
+};
+
+// drop if not in dragging anim. This also exits when entering a vehicle.
+if !(animationState _unit in DRAG_ANIMATIONS) exitWith {
+ [_unit, _target] call FUNC(dropObject);
+ [_this select 1] call CBA_fnc_removePerFrameHandler;
+};
+
+if !([_unit] call EFUNC(common,isPlayer)) exitWith {
+ [_unit, _target] call FUNC(dropObject);
+ [_this select 1] call CBA_fnc_removePerFrameHandler;
+};
diff --git a/addons/dragging/functions/fnc_dropObject.sqf b/addons/dragging/functions/fnc_dropObject.sqf
new file mode 100644
index 0000000000..77c928513d
--- /dev/null
+++ b/addons/dragging/functions/fnc_dropObject.sqf
@@ -0,0 +1,36 @@
+/*
+ * Author: commy2
+ *
+ * Drop a dragged object.
+ *
+ * Argument:
+ * 0: Unit that drags the other object (Object)
+ * 1: Dragged object to drop (Object)
+ *
+ * Return value:
+ * NONE.
+ */
+#include "script_component.hpp"
+
+private ["_unit", "_target"];
+
+_unit = _this select 0;
+_target = _this select 1;
+
+// remove scroll wheel action
+/*
+_this removeAction (_this getVariable ["AGM_Drag_ReleaseActionID", -1]);
+*/
+
+// play release animation
+_unit playAction "released";
+
+// release object
+detach _target;
+
+_unit setVariable [QGVAR(isDragging), false, true];
+
+// make object accesable for other units
+[objNull, _target, true] call EFUNC(common,claim);
+
+["fixPosition", _target, _target] call EFUNC(common,targetEvent);
diff --git a/addons/dragging/functions/fnc_setDraggable.sqf b/addons/dragging/functions/fnc_setDraggable.sqf
index 6ffa3476cc..e63f453d29 100644
--- a/addons/dragging/functions/fnc_setDraggable.sqf
+++ b/addons/dragging/functions/fnc_setDraggable.sqf
@@ -54,4 +54,4 @@ _name = "drag";
_icon = "";
_selection = "";
-[_type, 0, ["ACE_MainActions", _name], _name, _icon, _selection, FUNC(startDrag), FUNC(canDrag), 2] call EFUNC(interact_menu,addClassAction);
+[_type, 0, ["ACE_MainActions", _name], _name, _icon, _selection, {[_player, _target] call FUNC(startDrag)}, {[_player, _target] call FUNC(canDrag)}, 2] call EFUNC(interact_menu,addClassAction);
diff --git a/addons/dragging/functions/fnc_startDrag.sqf b/addons/dragging/functions/fnc_startDrag.sqf
index 324bf850d5..8c96dbe630 100644
--- a/addons/dragging/functions/fnc_startDrag.sqf
+++ b/addons/dragging/functions/fnc_startDrag.sqf
@@ -1,2 +1,37 @@
+/*
+ * Author: commy2
+ *
+ * Start the dragging process.
+ *
+ * Argument:
+ * 0: Unit that should do the dragging (Object)
+ * 1: Object to drag (Object)
+ *
+ * Return value:
+ * NONE.
+ */
+#include "script_component.hpp"
-hint str _target
+private ["_unit", "_target"];
+
+_unit = _this select 0;
+_target = _this select 1;
+
+// @todo check weight
+//_ableToDrag = ((_draggedObject call AGM_Drag_fnc_GetWeight) <= AGM_Drag_MaxWeight);
+
+// add a primary weapon if the unit has none.
+// @todo prevent opening inventory when equipped with a fake weapon
+if (primaryWeapon _unit == "") then {
+ _unit addWeapon "ACE_FakePrimaryWeapon";
+};
+
+// select primary, otherwise the drag animation actions don't work.
+_unit selectWeapon primaryWeapon _unit;
+
+// prevent multiple players from accessing the same object
+[_unit, _target, true] call EFUNC(common,claim);
+
+_unit playActionNow "grabDrag";
+
+[FUNC(startDragPFH), 0.2, [_unit, _target, time + 5]] call CBA_fnc_addPerFrameHandler;
diff --git a/addons/dragging/functions/fnc_startDragPFH.sqf b/addons/dragging/functions/fnc_startDragPFH.sqf
new file mode 100644
index 0000000000..b6515aa2d9
--- /dev/null
+++ b/addons/dragging/functions/fnc_startDragPFH.sqf
@@ -0,0 +1,20 @@
+// by commy2
+#include "script_component.hpp"
+
+private ["_unit", "_target", "_timeOut"];
+
+_unit = _this select 0 select 0;
+_target = _this select 0 select 1;
+_timeOut = _this select 0 select 2;
+
+// timeout. Do nothing. Quit. time, because anim length is linked to ingame time.
+if (time > _timeOut) exitWith {
+ [_this select 1] call CBA_fnc_removePerFrameHandler;
+};
+
+// unit is ready to start dragging
+if (animationState _unit in DRAG_ANIMATIONS) exitWith {
+ [_unit, _target] call FUNC(dragObject);
+
+ [_this select 1] call CBA_fnc_removePerFrameHandler;
+};
diff --git a/addons/dragging/script_component.hpp b/addons/dragging/script_component.hpp
index 3e8c54519b..0f601ae8d9 100644
--- a/addons/dragging/script_component.hpp
+++ b/addons/dragging/script_component.hpp
@@ -9,4 +9,6 @@
#define DEBUG_SETTINGS DEBUG_ENABLED_DRAGGING
#endif
-#include "\z\ace\addons\main\script_macros.hpp"
\ No newline at end of file
+#include "\z\ace\addons\main\script_macros.hpp"
+
+#define DRAG_ANIMATIONS ["amovpercmstpslowwrfldnon_acinpknlmwlkslowwrfldb_2", "amovpercmstpsraswpstdnon_acinpknlmwlksnonwpstdb_2", "amovpercmstpsnonwnondnon_acinpknlmwlksnonwnondb_2", "acinpknlmstpsraswrfldnon", "acinpknlmstpsnonwpstdnon", "acinpknlmstpsnonwnondnon", "acinpknlmwlksraswrfldb", "acinpknlmwlksnonwnondb"]
From 2da0eee1e278da6653829e331de7f5321c340fc2 Mon Sep 17 00:00:00 2001
From: commy2
Date: Mon, 16 Mar 2015 20:09:54 +0100
Subject: [PATCH 13/36] add drop dragged object action
---
addons/dragging/XEH_preInit.sqf | 1 +
addons/dragging/functions/fnc_canDrop.sqf | 1 +
addons/dragging/functions/fnc_dragObject.sqf | 34 ++++++++++++-------
addons/dragging/functions/fnc_dropObject.sqf | 5 ++-
.../dragging/functions/fnc_setDraggable.sqf | 9 ++---
5 files changed, 28 insertions(+), 22 deletions(-)
create mode 100644 addons/dragging/functions/fnc_canDrop.sqf
diff --git a/addons/dragging/XEH_preInit.sqf b/addons/dragging/XEH_preInit.sqf
index 88bd1d3d22..4ed8925e48 100644
--- a/addons/dragging/XEH_preInit.sqf
+++ b/addons/dragging/XEH_preInit.sqf
@@ -3,6 +3,7 @@
ADDON = false;
PREP(canDrag);
+PREP(canDrop);
PREP(dragObject);
PREP(dragObjectPFH);
PREP(dropObject);
diff --git a/addons/dragging/functions/fnc_canDrop.sqf b/addons/dragging/functions/fnc_canDrop.sqf
new file mode 100644
index 0000000000..f32a5804e2
--- /dev/null
+++ b/addons/dragging/functions/fnc_canDrop.sqf
@@ -0,0 +1 @@
+true
\ No newline at end of file
diff --git a/addons/dragging/functions/fnc_dragObject.sqf b/addons/dragging/functions/fnc_dragObject.sqf
index 9120c049b1..75a3c0cb2a 100644
--- a/addons/dragging/functions/fnc_dragObject.sqf
+++ b/addons/dragging/functions/fnc_dragObject.sqf
@@ -33,19 +33,29 @@ _position = _position vectorAdd [0, 0, _offset];
_target attachTo [_unit, _position];
_target setDir _direction;
-// add scrollwheel action to release object
-/*
- _actionID = _unit getVariable ["AGM_Drag_ReleaseActionID", -1];
-
- if (_actionID != -1) then {
- _unit removeAction _actionID;
- };
- _actionID = _unit addAction [format ["%1", localize "STR_AGM_Drag_EndDrag"], "player call AGM_Drag_fnc_releaseObject;", nil, 20, false, true, "","player call AGM_Drag_fnc_isDraggingObject"];
-
- _unit setVariable ["AGM_Drag_ReleaseActionID", _actionID];
-*/
-
_unit setVariable [QGVAR(isDragging), true, true];
+_unit setVariable [QGVAR(draggedObject), _target, true];
+
+// add scrollwheel action to release object
+private "_actionID";
+_actionID = _unit getVariable [QGVAR(ReleaseActionID), -1];
+
+if (_actionID != -1) then {
+ _unit removeAction _actionID;
+};
+
+_actionID = _unit addAction [
+ format ["%1", "STR_AGM_Drag_EndDrag"],
+ QUOTE([ARR_2(_this select 0, (_this select 0) getVariable [ARR_2(QUOTE(QGVAR(draggedObject)),objNull)])] call FUNC(dropObject)),
+ nil,
+ 20,
+ false,
+ true,
+ "",
+ QUOTE(!isNull (_this getVariable [ARR_2(QUOTE(QGVAR(draggedObject)),objNull)]))
+];
+
+_unit setVariable [QGVAR(ReleaseActionID), _actionID];
// check everything
[FUNC(dragObjectPFH), 0, [_unit, _target]] call CBA_fnc_addPerFrameHandler;
diff --git a/addons/dragging/functions/fnc_dropObject.sqf b/addons/dragging/functions/fnc_dropObject.sqf
index 77c928513d..35952af48e 100644
--- a/addons/dragging/functions/fnc_dropObject.sqf
+++ b/addons/dragging/functions/fnc_dropObject.sqf
@@ -18,9 +18,7 @@ _unit = _this select 0;
_target = _this select 1;
// remove scroll wheel action
-/*
-_this removeAction (_this getVariable ["AGM_Drag_ReleaseActionID", -1]);
-*/
+_unit removeAction (_unit getVariable [QGVAR(ReleaseActionID), -1]);
// play release animation
_unit playAction "released";
@@ -29,6 +27,7 @@ _unit playAction "released";
detach _target;
_unit setVariable [QGVAR(isDragging), false, true];
+_unit setVariable [QGVAR(draggedObject), objNull, true];
// make object accesable for other units
[objNull, _target, true] call EFUNC(common,claim);
diff --git a/addons/dragging/functions/fnc_setDraggable.sqf b/addons/dragging/functions/fnc_setDraggable.sqf
index e63f453d29..38e9438ca0 100644
--- a/addons/dragging/functions/fnc_setDraggable.sqf
+++ b/addons/dragging/functions/fnc_setDraggable.sqf
@@ -48,10 +48,5 @@ if (_type in _initializedClasses) exitWith {};
_initializedClasses pushBack _type;
GVAR(initializedClasses) = _initializedClasses;
-private ["_name", "_icon", "_selection", "_statement", "_condition"];
-
-_name = "drag";
-_icon = "";
-_selection = "";
-
-[_type, 0, ["ACE_MainActions", _name], _name, _icon, _selection, {[_player, _target] call FUNC(startDrag)}, {[_player, _target] call FUNC(canDrag)}, 2] call EFUNC(interact_menu,addClassAction);
+[_type, 0, ["ACE_MainActions", QGVAR(drag)], "drg", "", "", {[_player, _target] call FUNC(startDrag)}, {[_player, _target] call FUNC(canDrag)}, 2] call EFUNC(interact_menu,addClassAction);
+[_type, 0, ["ACE_MainActions", QGVAR(drop)], "drp", "", "", {[_player, _target] call FUNC(dropObject)}, {[_player, _target] call FUNC(canDrop)}, 2] call EFUNC(interact_menu,addClassAction);
From 2aaef08c1d0699f00aea1fb3f1c068f0c6d0a609 Mon Sep 17 00:00:00 2001
From: commy2
Date: Mon, 16 Mar 2015 20:39:49 +0100
Subject: [PATCH 14/36] can drag / drop functions, localization
---
addons/dragging/functions/fnc_canDrag.sqf | 24 ++++++++-
addons/dragging/functions/fnc_canDrop.sqf | 23 +++++++-
addons/dragging/functions/fnc_dragObject.sqf | 2 +-
.../dragging/functions/fnc_setDraggable.sqf | 4 +-
addons/dragging/stringtable.xml | 54 +++++++++++++++++++
5 files changed, 102 insertions(+), 5 deletions(-)
create mode 100644 addons/dragging/stringtable.xml
diff --git a/addons/dragging/functions/fnc_canDrag.sqf b/addons/dragging/functions/fnc_canDrag.sqf
index f32a5804e2..17c2ffb901 100644
--- a/addons/dragging/functions/fnc_canDrag.sqf
+++ b/addons/dragging/functions/fnc_canDrag.sqf
@@ -1 +1,23 @@
-true
\ No newline at end of file
+/*
+ * Author: commy2
+ *
+ * Check if unit can drag the object. Doesn't check weight.
+ *
+ * Argument:
+ * 0: Unit that should do the dragging (Object)
+ * 1: Object to drag (Object)
+ *
+ * Return value:
+ * Can the unit drag the object? (Bool)
+ */
+#include "script_component.hpp"
+
+private ["_unit", "_target"];
+
+_unit = _this select 0;
+_target = _this select 1;
+
+if !([_unit, _target, []] call EFUNC(common,canInteractWith)) exitWith {false};
+
+// a static weapon has to be empty for dragging
+if ((typeOf _target) isKindOf "StaticWeapon" && {count crew _target > 0}) exitWith {false};
diff --git a/addons/dragging/functions/fnc_canDrop.sqf b/addons/dragging/functions/fnc_canDrop.sqf
index f32a5804e2..df75b9540f 100644
--- a/addons/dragging/functions/fnc_canDrop.sqf
+++ b/addons/dragging/functions/fnc_canDrop.sqf
@@ -1 +1,22 @@
-true
\ No newline at end of file
+/*
+ * Author: commy2
+ *
+ * Check if unit can drop the object.
+ *
+ * Argument:
+ * 0: Unit that currently drags a object (Object)
+ * 1: Object that is dragged (Object)
+ *
+ * Return value:
+ * Can the unit drop the object? (Bool)
+ */
+#include "script_component.hpp"
+
+private ["_unit", "_target"];
+
+_unit = _this select 0;
+_target = _this select 1;
+
+if !([_unit, _target, ["isNotDragging"]] call EFUNC(common,canInteractWith)) exitWith {false};
+
+_unit getVariable [QGVAR(draggedObject), objNull] == _target
diff --git a/addons/dragging/functions/fnc_dragObject.sqf b/addons/dragging/functions/fnc_dragObject.sqf
index 75a3c0cb2a..2f04e0e599 100644
--- a/addons/dragging/functions/fnc_dragObject.sqf
+++ b/addons/dragging/functions/fnc_dragObject.sqf
@@ -45,7 +45,7 @@ if (_actionID != -1) then {
};
_actionID = _unit addAction [
- format ["%1", "STR_AGM_Drag_EndDrag"],
+ format ["%1", localize "STR_ACE_Dragging_Drop"],
QUOTE([ARR_2(_this select 0, (_this select 0) getVariable [ARR_2(QUOTE(QGVAR(draggedObject)),objNull)])] call FUNC(dropObject)),
nil,
20,
diff --git a/addons/dragging/functions/fnc_setDraggable.sqf b/addons/dragging/functions/fnc_setDraggable.sqf
index 38e9438ca0..82ebc201e2 100644
--- a/addons/dragging/functions/fnc_setDraggable.sqf
+++ b/addons/dragging/functions/fnc_setDraggable.sqf
@@ -48,5 +48,5 @@ if (_type in _initializedClasses) exitWith {};
_initializedClasses pushBack _type;
GVAR(initializedClasses) = _initializedClasses;
-[_type, 0, ["ACE_MainActions", QGVAR(drag)], "drg", "", "", {[_player, _target] call FUNC(startDrag)}, {[_player, _target] call FUNC(canDrag)}, 2] call EFUNC(interact_menu,addClassAction);
-[_type, 0, ["ACE_MainActions", QGVAR(drop)], "drp", "", "", {[_player, _target] call FUNC(dropObject)}, {[_player, _target] call FUNC(canDrop)}, 2] call EFUNC(interact_menu,addClassAction);
+[_type, 0, ["ACE_MainActions", QGVAR(drag)], localize "STR_ACE_Dragging_Drag", "", "", {[_player, _target] call FUNC(startDrag)}, {[_player, _target] call FUNC(canDrag)}, 2] call EFUNC(interact_menu,addClassAction);
+[_type, 0, ["ACE_MainActions", QGVAR(drop)], localize "STR_ACE_Dragging_Drop", "", "", {[_player, _target] call FUNC(dropObject)}, {[_player, _target] call FUNC(canDrop)}, 2] call EFUNC(interact_menu,addClassAction);
diff --git a/addons/dragging/stringtable.xml b/addons/dragging/stringtable.xml
new file mode 100644
index 0000000000..d8f4f1981a
--- /dev/null
+++ b/addons/dragging/stringtable.xml
@@ -0,0 +1,54 @@
+
+
+
+
+
+ Drag
+ Тащить
+ Arrastrar
+ Ciągnij
+ Táhnout
+ Tracter
+ Ziehen
+ Arrastar
+ Trascina
+ Húzás
+
+
+ Release
+ Отпустить
+ Soltar
+ Puść
+ Položit
+ Lâcher
+ Loslassen
+ Largar
+ Lascia
+ Elengedés
+
+
+ Unable to drag item due to weight
+ Слишком тяжелый предмет
+ No se puede arrastrar el objeto debido a su peso
+ Nie można ciągnąć tego przedmiotu z powodu jego wagi
+ Předmět je příliž těžký!
+ Trop lourd pour être tracté
+ Dieser Gegenstand kann nicht gezogen werden, da er zu schwer ist.
+ Não é possível carregar o item devido a seu peso
+ Non è possibile trascinare l'oggetto a causa del suo peso
+ Túl nehéz ahhoz, hogy elhúzd
+
+
+ Carry
+ Tragen
+ Portar
+ Nieś
+ Porter
+ Nést
+ Carregar
+ Trascina
+ Felvesz
+ Нести
+
+
+
From fef150cff2fa83a23c5f4f9e9e2e0fb2c174e83c Mon Sep 17 00:00:00 2001
From: commy2
Date: Tue, 17 Mar 2015 00:24:25 +0100
Subject: [PATCH 15/36] attempt to fix collisions
---
addons/common/XEH_preInit.sqf | 1 +
addons/common/functions/fnc_fixCollisions.sqf | 55 +++++++++++++++++++
addons/dragging/functions/fnc_dropObject.sqf | 2 +
3 files changed, 58 insertions(+)
create mode 100644 addons/common/functions/fnc_fixCollisions.sqf
diff --git a/addons/common/XEH_preInit.sqf b/addons/common/XEH_preInit.sqf
index c822de6d47..a70014c25d 100644
--- a/addons/common/XEH_preInit.sqf
+++ b/addons/common/XEH_preInit.sqf
@@ -55,6 +55,7 @@ PREP(execPersistentFnc);
PREP(execRemoteFnc);
PREP(executePersistent);
PREP(filter);
+PREP(fixCollisions);
PREP(fixLoweredRifleAnimation);
PREP(fixPosition);
PREP(getAllDefinedSetVariables);
diff --git a/addons/common/functions/fnc_fixCollisions.sqf b/addons/common/functions/fnc_fixCollisions.sqf
new file mode 100644
index 0000000000..2f4078bb1f
--- /dev/null
+++ b/addons/common/functions/fnc_fixCollisions.sqf
@@ -0,0 +1,55 @@
+/*
+ * Author: commy2
+ * Attempt to fix physx collisions causing unreasonable impact forces and damage.
+ *
+ * Arguments:
+ * 0: Object
Requires the latest version of CBA A3 | BIF thread
-**ACE 3** is a joint effort by the teams behind **ACE2**, **AGM** and **CSE** to improve the realism and authenticity of Arma 3.
+**ACE3** is a joint effort by the teams behind **ACE2**, **AGM** and **CSE** to improve the realism and authenticity of Arma 3.
This mod is entirely **open-source**, and everyone is free to propose changes or maintain their own, customized version as long as they make their changes open to the public in accordance with the GNU General Public License (for more information check the license file attached to this project).
From b7c73f705cc64cf50b194b70fe26625a2e41bdf7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nicol=C3=A1s=20Badano?=
Date: Thu, 19 Mar 2015 15:04:48 -0300
Subject: [PATCH 32/36] Interact menu usability improvements: - Submenu scale
as a function of the number of children - Added menu expansion animation to
better communicate where the options come from - Unused action point are
faded as soon as the user hovers a certain action point
---
addons/interact_menu/XEH_preInit.sqf | 1 +
addons/interact_menu/functions/fnc_render.sqf | 1 +
.../functions/fnc_renderMenu.sqf | 34 ++++++++++++++-----
3 files changed, 28 insertions(+), 8 deletions(-)
diff --git a/addons/interact_menu/XEH_preInit.sqf b/addons/interact_menu/XEH_preInit.sqf
index 487f1c017f..b42e8c5507 100644
--- a/addons/interact_menu/XEH_preInit.sqf
+++ b/addons/interact_menu/XEH_preInit.sqf
@@ -40,6 +40,7 @@ GVAR(lastPath) = [];
GVAR(expanded) = false;
GVAR(startHoverTime) = diag_tickTime;
+GVAR(expandedTime) = diag_tickTime;
GVAR(iconCtrls) = [];
GVAR(iconCount) = 0;
diff --git a/addons/interact_menu/functions/fnc_render.sqf b/addons/interact_menu/functions/fnc_render.sqf
index 3930068c25..187201a821 100644
--- a/addons/interact_menu/functions/fnc_render.sqf
+++ b/addons/interact_menu/functions/fnc_render.sqf
@@ -166,6 +166,7 @@ if(GVAR(keyDown) || GVAR(keyDownSelfAction)) then {
} else {
if(!GVAR(expanded) && diag_tickTime-GVAR(startHoverTime) > 0.25) then {
GVAR(expanded) = true;
+ GVAR(expandedTime) = diag_tickTime;
GVAR(menuDepthPath) = +GVAR(lastPath);
// Execute the current action if it's run on hover
diff --git a/addons/interact_menu/functions/fnc_renderMenu.sqf b/addons/interact_menu/functions/fnc_renderMenu.sqf
index ad604b9fa5..d2cf16c3a0 100644
--- a/addons/interact_menu/functions/fnc_renderMenu.sqf
+++ b/addons/interact_menu/functions/fnc_renderMenu.sqf
@@ -21,7 +21,7 @@ EXPLODE_4_PVT(_this,_object,_action,_pos,_angles);
EXPLODE_2_PVT(_action,_actionData,_activeChildren);
EXPLODE_2_PVT(_angles,_centerAngle,_maxAngleSpan);
-_menuDepth = (count GVAR(menuDepthPath)) - 1;
+_menuDepth = (count GVAR(menuDepthPath));
// Store path to action
_path = [_object] + (_actionData select 7);
@@ -42,7 +42,7 @@ _menuInSelectedPath = true;
_color = "#FFFFFFFF";
if(!_menuInSelectedPath) then { //_menuDepth > 0 &&
if (_menuDepth > 0) then {
- _color = format ["#%1FFFFFF", [255 * ((((count _path) - 2)/_menuDepth) max 0.25)] call EFUNC(common,toHex)];
+ _color = format ["#%1FFFFFF", [255 * ((((count _path) - 1)/_menuDepth) max 0.25)] call EFUNC(common,toHex)];
} else {
_color = format ["#%1FFFFFF", [255 * 0.75] call EFUNC(common,toHex)];
};
@@ -55,24 +55,42 @@ GVAR(currentOptions) pushBack [_this, _pos, _path];
// Exit without rendering children if it isn't
if !(_menuInSelectedPath) exitWith {true};
-private ["_angleSpan","_angle"];
+private ["_angleSpan","_angle","_angleInterval","_scale"];
_angleSpan = _maxAngleSpan min (55 * ((count _activeChildren) - 1));
if (_angleSpan >= 305) then {
_angleSpan = 360;
};
+_angleInterval = 55;
+if (_angleSpan < 360) then {
+ if (count _activeChildren > 1) then {
+ _angleInterval = _angleSpan / (count _activeChildren - 1);
+ };
+} else {
+ _angleSpan / (count _activeChildren);
+};
+if (count _activeChildren == 1) then {
+ _angleInterval = 60;
+};
+
+// Scale menu based on distance
+_scale = (0.15 max (0.15 * ((positionCameraToWorld [0, 0, 0]) distance _pos))) / GVAR(selfMenuScale);
+// Scale menu based on the amount of children
+_scale = _scale * (((0.8 * (0.46 / sin (0.5 * _angleInterval))) min 1.4) max 0.5);
+// Animate menu scale
+if (_menuInSelectedPath && (_menuDepth == count _path)) then {
+ _scale = _scale * (0.3 + 0.7 * (((diag_tickTime - GVAR(expandedTime)) * 8) min 1));
+};
_angle = _centerAngle - _angleSpan / 2;
{
_target = _object;
_player = ACE_player;
- _mod = (0.15 max (0.15 * ((positionCameraToWorld [0, 0, 0]) distance _pos))) / GVAR(selfMenuScale);
-
- _offset = ((GVAR(refSystem) select 1) vectorMultiply (-_mod * cos _angle)) vectorAdd
- ((GVAR(refSystem) select 2) vectorMultiply (-_mod * sin _angle));
+ _offset = ((GVAR(refSystem) select 1) vectorMultiply (-_scale * cos _angle)) vectorAdd
+ ((GVAR(refSystem) select 2) vectorMultiply (-_scale * sin _angle));
_newPos = ((_pos call EFUNC(common,positionToASL)) vectorAdd _offset) call EFUNC(common,ASLToPosition);
- //drawLine3D [_pos, _newPos, [1,0,0,0.5]];
+ //drawLine3D [_pos, _newPos, [1,0,0,0.8]];
[_object, _x, _newPos, [_angle, 140]] call FUNC(renderMenu);
From a146be57f2f35b3a501f30cb2d2c0c20c3a5d57a Mon Sep 17 00:00:00 2001
From: PabstMirror
Date: Fri, 20 Mar 2015 13:04:54 -0500
Subject: [PATCH 33/36] Modifyed build tool for pboProject problems
Should work on last release of mikero's tools
(because that version of rapify struggles with some CBA macros)
Runs config.cpp though cfgConvert twice to "demacro" config.cpp
Then restores backup when finished
---
.../pabstFrankensteinBuilder.py | 776 ++++++++++++++++++
1 file changed, 776 insertions(+)
create mode 100644 tools/ace_build_tool/pabstFrankensteinBuilder.py
diff --git a/tools/ace_build_tool/pabstFrankensteinBuilder.py b/tools/ace_build_tool/pabstFrankensteinBuilder.py
new file mode 100644
index 0000000000..eb35f1c7e5
--- /dev/null
+++ b/tools/ace_build_tool/pabstFrankensteinBuilder.py
@@ -0,0 +1,776 @@
+#!/usr/bin/env python
+# vim: set fileencoding=utf-8 :
+
+# make.py
+# An Arma 3 addon build system
+
+###############################################################################
+
+# The MIT License (MIT)
+
+# Copyright (c) 2013-2014 Ryan Schultz
+
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+
+###############################################################################
+
+__version__ = "0.3dev"
+
+import sys
+
+if sys.version_info[0] == 2:
+ print("Python 3 is required.")
+ sys.exit(1)
+
+import os
+import os.path
+import shutil
+import platform
+import glob
+import subprocess
+import hashlib
+import configparser
+import json
+import traceback
+
+if sys.platform == "win32":
+ import winreg
+
+###############################################################################
+# http://akiscode.com/articles/sha-1directoryhash.shtml
+# Copyright (c) 2009 Stephen Akiki
+# MIT License (Means you can do whatever you want with this)
+# See http://www.opensource.org/licenses/mit-license.php
+# Error Codes:
+# -1 -> Directory does not exist
+# -2 -> General error (see stack traceback)
+def get_directory_hash(directory):
+ directory_hash = hashlib.sha1()
+ if not os.path.exists (directory):
+ return -1
+
+ try:
+ for root, dirs, files in os.walk(directory):
+ for names in files:
+ path = os.path.join(root, names)
+ try:
+ f = open(path, 'rb')
+ except:
+ # You can't open the file for some reason
+ f.close()
+ continue
+
+ while 1:
+ # Read file in as little chunks
+ buf = f.read(4096)
+ if not buf: break
+ new = hashlib.sha1(buf)
+ directory_hash.update(new.digest())
+ f.close()
+
+ except:
+ # Print the stack traceback
+ traceback.print_exc()
+ return -2
+
+ return directory_hash.hexdigest()
+
+# Copyright (c) André Burgaud
+# http://www.burgaud.com/bring-colors-to-the-windows-console-with-python/
+if sys.platform == "win32":
+ from ctypes import windll, Structure, c_short, c_ushort, byref
+
+ SHORT = c_short
+ WORD = c_ushort
+
+ class COORD(Structure):
+ """struct in wincon.h."""
+ _fields_ = [
+ ("X", SHORT),
+ ("Y", SHORT)]
+
+ class SMALL_RECT(Structure):
+ """struct in wincon.h."""
+ _fields_ = [
+ ("Left", SHORT),
+ ("Top", SHORT),
+ ("Right", SHORT),
+ ("Bottom", SHORT)]
+
+ class CONSOLE_SCREEN_BUFFER_INFO(Structure):
+ """struct in wincon.h."""
+ _fields_ = [
+ ("dwSize", COORD),
+ ("dwCursorPosition", COORD),
+ ("wAttributes", WORD),
+ ("srWindow", SMALL_RECT),
+ ("dwMaximumWindowSize", COORD)]
+
+ # winbase.h
+ STD_INPUT_HANDLE = -10
+ STD_OUTPUT_HANDLE = -11
+ STD_ERROR_HANDLE = -12
+
+ # wincon.h
+ FOREGROUND_BLACK = 0x0000
+ FOREGROUND_BLUE = 0x0001
+ FOREGROUND_GREEN = 0x0002
+ FOREGROUND_CYAN = 0x0003
+ FOREGROUND_RED = 0x0004
+ FOREGROUND_MAGENTA = 0x0005
+ FOREGROUND_YELLOW = 0x0006
+ FOREGROUND_GREY = 0x0007
+ FOREGROUND_INTENSITY = 0x0008 # foreground color is intensified.
+
+ BACKGROUND_BLACK = 0x0000
+ BACKGROUND_BLUE = 0x0010
+ BACKGROUND_GREEN = 0x0020
+ BACKGROUND_CYAN = 0x0030
+ BACKGROUND_RED = 0x0040
+ BACKGROUND_MAGENTA = 0x0050
+ BACKGROUND_YELLOW = 0x0060
+ BACKGROUND_GREY = 0x0070
+ BACKGROUND_INTENSITY = 0x0080 # background color is intensified.
+
+ stdout_handle = windll.kernel32.GetStdHandle(STD_OUTPUT_HANDLE)
+ SetConsoleTextAttribute = windll.kernel32.SetConsoleTextAttribute
+ GetConsoleScreenBufferInfo = windll.kernel32.GetConsoleScreenBufferInfo
+
+ def get_text_attr():
+ """Returns the character attributes (colors) of the console screen
+ buffer."""
+ csbi = CONSOLE_SCREEN_BUFFER_INFO()
+ GetConsoleScreenBufferInfo(stdout_handle, byref(csbi))
+ return csbi.wAttributes
+
+ def set_text_attr(color):
+ """Sets the character attributes (colors) of the console screen
+ buffer. Color is a combination of foreground and background color,
+ foreground and background intensity."""
+ SetConsoleTextAttribute(stdout_handle, color)
+###############################################################################
+
+def find_bi_tools(work_drive):
+ """Find BI tools."""
+
+ reg = winreg.ConnectRegistry(None, winreg.HKEY_CURRENT_USER)
+ try:
+ k = winreg.OpenKey(reg, r"Software\bohemia interactive\arma 3 tools")
+ arma3tools_path = winreg.QueryValueEx(k, "path")[0]
+ winreg.CloseKey(k)
+ except:
+ raise Exception("BadTools","Arma 3 Tools are not installed correctly or the P: drive needs to be created.")
+
+ addonbuilder_path = os.path.join(arma3tools_path, "AddonBuilder", "AddonBuilder.exe")
+ dssignfile_path = os.path.join(arma3tools_path, "DSSignFile", "DSSignFile.exe")
+ dscreatekey_path = os.path.join(arma3tools_path, "DSSignFile", "DSCreateKey.exe")
+
+ if os.path.isfile(addonbuilder_path) and os.path.isfile(dssignfile_path) and os.path.isfile(dscreatekey_path):
+ return [addonbuilder_path, dssignfile_path, dscreatekey_path]
+ else:
+ raise Exception("BadTools","Arma 3 Tools are not installed correctly or the P: drive needs to be created.")
+
+def find_depbo_tools():
+ """Use registry entries to find DePBO-based tools."""
+
+ reg = winreg.ConnectRegistry(None, winreg.HKEY_CURRENT_USER)
+ try:
+ k = winreg.OpenKey(reg, r"Software\Mikero\pboProject")
+ try:
+ pboproject_path = winreg.QueryValueEx(k, "exe")[0]
+ winreg.CloseKey(k)
+ print("Found pboproject.")
+ except:
+ print_error("ERROR: Could not find pboProject.")
+
+ k = winreg.OpenKey(reg, r"Software\Mikero\rapify")
+ try:
+ rapify_path = winreg.QueryValueEx(k, "exe")[0]
+ winreg.CloseKey(k)
+ print("Found rapify.")
+ except:
+ print_error("Could not find rapify.")
+
+ k = winreg.OpenKey(reg, r"Software\Mikero\MakePbo")
+ try:
+ makepbo_path = winreg.QueryValueEx(k, "exe")[0]
+ winreg.CloseKey(k)
+ print("Found makepbo.")
+ except:
+ print_error("Could not find makepbo.")
+ except:
+ raise Exception("BadDePBO", "DePBO tools not installed correctly")
+
+ #Strip any quotations from the path due to a MikeRo tool bug which leaves a trailing space in some of its registry paths.
+ return [pboproject_path.strip('"'),rapify_path.strip('"'),makepbo_path.strip('"')]
+
+def color(color):
+ """Set the color. Works on Win32 and normal terminals."""
+ if sys.platform == "win32":
+ if color == "green":
+ set_text_attr(FOREGROUND_GREEN | get_text_attr() & 0x0070 | FOREGROUND_INTENSITY)
+ elif color == "red":
+ set_text_attr(FOREGROUND_RED | get_text_attr() & 0x0070 | FOREGROUND_INTENSITY)
+ elif color == "blue":
+ set_text_attr(FOREGROUND_BLUE | get_text_attr() & 0x0070 | FOREGROUND_INTENSITY)
+ elif color == "reset":
+ set_text_attr(FOREGROUND_GREY | get_text_attr() & 0x0070)
+ elif color == "grey":
+ set_text_attr(FOREGROUND_GREY | get_text_attr() & 0x0070)
+ else :
+ if color == "green":
+ sys.stdout.write('\033[92m')
+ elif color == "red":
+ sys.stdout.write('\033[91m')
+ elif color == "blue":
+ sys.stdout.write('\033[94m')
+ elif color == "reset":
+ sys.stdout.write('\033[0m')
+
+def print_error(msg):
+ color("red")
+ print ("ERROR: " + msg)
+ color("reset")
+
+def print_green(msg):
+ color("green")
+ print(msg)
+ color("reset")
+
+def print_blue(msg):
+ color("blue")
+ print(msg)
+ color("reset")
+
+def print_yellow(msg):
+ color("yellow")
+ print(msg)
+ color("reset")
+
+###############################################################################
+
+def main(argv):
+ """Build an Arma addon suite in a directory from rules in a make.cfg file."""
+ print_blue(("\nmake.py for Arma, v" + __version__))
+
+ if sys.platform != "win32":
+ print_error("Non-Windows platform (Cygwin?). Please re-run from cmd.")
+ sys.exit(1)
+
+ reg = winreg.ConnectRegistry(None, winreg.HKEY_CURRENT_USER)
+ try:
+ k = winreg.OpenKey(reg, r"Software\bohemia interactive\arma 3 tools")
+ arma3tools_path = winreg.QueryValueEx(k, "path")[0]
+ winreg.CloseKey(k)
+ except:
+ raise Exception("BadTools","Arma 3 Tools are not installed correctly or the P: drive needs to be created.")
+
+ # Default behaviors
+ test = False # Copy to Arma 3 directory?
+ arg_modules = False # Only build modules on command line?
+ make_release = False # Make zip file from the release?
+ release_version = 0 # Version of release
+ use_pboproject = True # Default to pboProject build tool
+ make_target = "DEFAULT" # Which section in make.cfg to use for the build
+ new_key = False # Make a new key and use it to sign?
+ quiet = False # Suppress output from build tool?
+
+ # Parse arguments
+ if "help" in argv or "-h" in argv or "--help" in argv:
+ print ("""
+make.py [help] [test] [force] [key ] [target ] [release ]
+ [module name] [module name] [...]
+
+test -- Copy result to Arma 3.
+release -- Make archive with .
+force -- Ignore cache and build all.
+target -- Use rules in make.cfg under heading [] rather than
+ default [Make]
+key -- Use key in working directory with to sign. If it does not
+ exist, create key.
+quiet -- Suppress command line output from build tool.
+
+If module names are specified, only those modules will be built.
+
+Examples:
+ make.py force test
+ Build all modules (ignoring cache) and copy the mod folder to the Arma 3
+ directory.
+ make.py mymodule_gun
+ Only build the module named 'mymodule_gun'.
+ make.py force key MyNewKey release 1.0
+ Build all modules (ignoring cache), sign them with NewKey, and pack them
+ into a zip file for release with version 1.0.
+
+
+If a file called $NOBIN$ is found in the module directory, that module will not be binarized.
+
+See the make.cfg file for additional build options.
+""")
+ sys.exit(0)
+
+ if "force" in argv:
+ argv.remove("force")
+ force_build = True
+ else:
+ force_build = False
+
+ if "test" in argv:
+ test = True
+ argv.remove("test")
+
+ if "release" in argv:
+ make_release = True
+ release_version = argv[argv.index("release") + 1]
+ argv.remove(release_version)
+ argv.remove("release")
+
+ if "target" in argv:
+ make_target = argv[argv.index("target") + 1]
+ argv.remove("target")
+ argv.remove(make_target)
+ force_build = True
+
+ if "key" in argv:
+ new_key = True
+ key_name = argv[argv.index("key") + 1]
+ argv.remove("key")
+ argv.remove(key_name)
+
+ if "quiet" in argv:
+ quiet = True
+ argv.remove("quiet")
+
+ # Get the directory the make script is in.
+ make_root = os.path.dirname(os.path.realpath(__file__))
+ make_root_parent = os.path.abspath(os.path.join(os.getcwd(), os.pardir))
+ os.chdir(make_root)
+
+ cfg = configparser.ConfigParser();
+ try:
+ cfg.read(os.path.join(make_root, "make.cfg"))
+
+ # Project name (with @ symbol)
+ project = cfg.get(make_target, "project", fallback="@"+os.path.basename(os.getcwd()))
+
+ # Private key path
+ key = cfg.get(make_target, "key", fallback=None)
+
+ # Project prefix (folder path)
+ prefix = cfg.get(make_target, "prefix", fallback="")
+
+ # Should we autodetect modules on a complete build?
+ module_autodetect = cfg.getboolean(make_target, "module_autodetect", fallback=True)
+
+ # Manual list of modules to build for a complete build
+ modules = cfg.get(make_target, "modules", fallback=None)
+ # Parse it out
+ if modules:
+ modules = [x.strip() for x in modules.split(',')]
+ else:
+ modules = []
+
+ # List of directories to ignore when detecting
+ ignore = [x.strip() for x in cfg.get(make_target, "ignore", fallback="release").split(',')]
+
+ # BI Tools work drive on Windows
+ work_drive = cfg.get(make_target, "work_drive", fallback="P:\\")
+
+ # Which build tool should we use?
+ build_tool = "pboproject"
+
+ # Release/build directory, relative to script dir
+ release_dir = cfg.get(make_target, "release_dir", fallback="release")
+
+ # Project PBO file prefix (files are renamed to prefix_name.pbo)
+ pbo_name_prefix = cfg.get(make_target, "pbo_name_prefix", fallback=None)
+
+ # Project module Root
+ module_root_parent = os.path.abspath(os.path.join(os.path.join(work_drive, prefix), os.pardir))
+ module_root = cfg.get(make_target, "module_root", fallback=os.path.join(make_root_parent, "addons"))
+ print_green ("module_root: " + module_root)
+ if (os.path.isdir(module_root)):
+ os.chdir(module_root)
+ else:
+ print_error ("Directory " + module_root + " does not exist.")
+ sys.exit()
+
+ except:
+ raise
+ print_error("Could not parse make.cfg.")
+ sys.exit(1)
+
+
+
+ # See if we have been given specific modules to build from command line.
+ if len(argv) > 1 and not make_release:
+ arg_modules = True
+ modules = argv[1:]
+
+ # Find the tools we need.
+ try:
+ tools = find_bi_tools(work_drive)
+ addonbuilder = tools[0]
+ dssignfile = tools[1]
+ dscreatekey = tools[2]
+
+ except:
+ print_error("Arma 3 Tools are not installed correctly or the P: drive has not been created.")
+ sys.exit(1)
+
+ if build_tool == "pboproject":
+ try:
+ depbo_tools = find_depbo_tools()
+ pboproject = depbo_tools[0]
+ rapifyTool = depbo_tools[1]
+ makepboTool = depbo_tools[2]
+ except:
+ raise
+ print_error("Could not find dePBO tools. Download the needed tools from: https://dev.withsix.com/projects/mikero-pbodll/files")
+ sys.exit(1)
+
+ # Try to open and deserialize build cache file.
+ try:
+ cache = {}
+ with open(os.path.join(make_root, "make.cache"), 'r') as f:
+ cache_raw = f.read()
+
+ cache = json.loads(cache_raw)
+
+ except:
+ print ("No cache found.")
+ cache = {}
+
+ # Get list of subdirs in make root.
+ dirs = next(os.walk(module_root))[1]
+
+ # Autodetect what directories to build.
+ if module_autodetect and not arg_modules:
+ modules = []
+ for path in dirs:
+ # Any dir that has a config.cpp in its root is an addon to build.
+ config_path = os.path.join(path, 'config.cpp')
+ if os.path.isfile(config_path) and not path in ignore:
+ modules.append(path)
+
+ # Make the key specified from command line if necessary.
+ if new_key:
+ if not os.path.isfile(os.path.join(module_root, key_name + ".biprivatekey")):
+ print_green("\nRequested key does not exist.")
+ ret = subprocess.call([dscreatekey, key_name]) # Created in make_root
+ if ret == 0:
+ print_blue("Created: " + os.path.join(module_root, key_name + ".biprivatekey"))
+ else:
+ print_error("Failed to create key!")
+
+ try:
+ print_blue("Copying public key to release directory.")
+
+ try:
+ os.makedirs(os.path.join(module_root, release_dir, "Keys"))
+ except:
+ pass
+
+ shutil.copyfile(os.path.join(module_root, key_name + ".bikey"), os.path.join(module_root, release_dir, "Keys", key_name + ".bikey"))
+
+ except:
+ raise
+ print_error("Could not copy key to release directory.")
+
+ else:
+ print_green("\nNOTE: Using key " + os.path.join(module_root, key_name + ".biprivatekey"))
+
+ key = os.path.join(module_root, key_name + ".biprivatekey")
+
+
+ # For each module, prep files and then build.
+ for module in modules:
+ print_green("\nMaking " + module + "-"*max(1, (60-len(module))))
+
+ # Cache check
+ if module in cache:
+ old_sha = cache[module]
+ else:
+ old_sha = ""
+
+ # Hash the module
+ new_sha = get_directory_hash(os.path.join(module_root, module))
+
+ # Check if it needs rebuilt
+ # print ("Hash:", new_sha)
+ if old_sha == new_sha:
+ if not force_build:
+ print("Module has not changed.")
+ # Skip everything else
+ continue
+
+ # Only do this if the project isn't stored directly on the work drive.
+ # Split the path at the drive name and see if they are on the same drive (usually P:)
+ if os.path.splitdrive(module_root)[0] != os.path.splitdrive(work_drive)[0]:
+ try:
+ # Remove old work drive version (ignore errors)
+ shutil.rmtree(os.path.join(work_drive, prefix, module), True)
+
+ # Copy module to the work drive
+ shutil.copytree(module, os.path.join(work_drive, prefix, module))
+
+ except:
+ raise
+ print_error("ERROR: Could not copy module to work drive. Does the module exist?")
+ input("Press Enter to continue...")
+ print("Resuming build...")
+ continue
+ else:
+ print("WARNING: Module is stored on work drive (" + work_drive + ").")
+
+ try:
+ # Remove the old pbo, key, and log
+ old = os.path.join(module_root, release_dir, project, "Addons", module) + "*"
+ files = glob.glob(old)
+ for f in files:
+ os.remove(f)
+
+ if pbo_name_prefix:
+ old = os.path.join(module_root, release_dir, project, "Addons", pbo_name_prefix+module) + "*"
+ files = glob.glob(old)
+ for f in files:
+ os.remove(f)
+ except:
+ raise
+ print_error("ERROR: Could not copy module to work drive. Does the module exist?")
+ input("Press Enter to continue...")
+ print("Resuming build...")
+ continue
+
+ # Build the module into a pbo
+ print_blue("Building: " + os.path.join(work_drive, prefix, module))
+ print_blue("Destination: " + os.path.join(module_root, release_dir, project, "Addons"))
+
+ # Make destination folder (if needed)
+ try:
+ os.makedirs(os.path.join(module_root, release_dir, project, "Addons"))
+ except:
+ pass
+
+ # Run build tool
+ build_successful = False
+ if build_tool == "pboproject":
+ try:
+ #PABST: Convert config (run the macro'd config.cpp through CfgConvert twice to produce a de-macro'd cpp that pboProject can read without fucking up:
+ os.chdir("P:\\CfgConvert")
+ shutil.copyfile(os.path.join(work_drive, prefix, module, "config.cpp"), os.path.join(work_drive, prefix, module, "config.backup"))
+ print_green("\Pabst (double converting):" + "cfgConvertGUI.exe " + os.path.join(work_drive, prefix, module, "config.cpp"))
+ ret = subprocess.call(["cfgConvertGUI.exe", os.path.join(work_drive, prefix, module, "config.cpp")])
+ ret = subprocess.call(["cfgConvertGUI.exe", os.path.join(work_drive, prefix, module, "config.bin")])
+
+ # Call pboProject
+ os.chdir("P:\\")
+
+ if os.path.isfile(os.path.join(work_drive, prefix, module, "$NOBIN$")):
+ print_green("$NOBIN$ Found. Proceeding with non-binarizing!")
+ cmd = [makepboTool, "-P","-A","-L","-N","-G", os.path.join(work_drive, prefix, module),os.path.join(module_root, release_dir, project,"Addons")]
+
+ else:
+ cmd = [pboproject, "-P", os.path.join(work_drive, prefix, module), "+Engine=Arma3", "-S","+Noisy", "+X", "+Clean", "+Mod="+os.path.join(module_root, release_dir, project), "-Key"]
+
+ color("grey")
+ if quiet:
+ devnull = open(os.devnull, 'w')
+ ret = subprocess.call(cmd, stdout=devnull)
+ devnull.close()
+ else:
+ ret = subprocess.call(cmd)
+ color("reset")
+
+ if ret == 0:
+ print_green("pboProject return code == " + str(ret))
+ # Prettyprefix rename the PBO if requested.
+ if pbo_name_prefix:
+ try:
+ os.rename(os.path.join(module_root, release_dir, project, "Addons", module+".pbo"), os.path.join(module_root, release_dir, project, "Addons", pbo_name_prefix+module+".pbo"))
+ except:
+ raise
+ print_error("Could not rename built PBO with prefix.")
+ # Sign result
+ if key:
+ print("Signing with " + key + ".")
+ if pbo_name_prefix:
+ ret = subprocess.call([dssignfile, key, os.path.join(module_root, release_dir, project, "Addons", pbo_name_prefix + module + ".pbo")])
+ else:
+ ret = subprocess.call([dssignfile, key, os.path.join(module_root, release_dir, project, "Addons", module + ".pbo")])
+
+ if ret == 0:
+ build_successful = True
+ else:
+ build_successful = True
+
+ if not build_successful:
+ print_error("pboProject return code == " + str(ret))
+ print_error("Module not successfully built/signed.")
+ #input("Press Enter to continue...")
+ print ("Resuming build...")
+ continue
+
+ #PABST: cleanup config BS (you could comment this out to see the "de-macroed" cpp
+ print_green("\Pabst (restoring): " + os.path.join(work_drive, prefix, module, "config.cpp"))
+ os.remove(os.path.join(work_drive, prefix, module, "config.cpp"))
+ os.remove(os.path.join(work_drive, prefix, module, "config.bin"))
+ os.rename(os.path.join(work_drive, prefix, module, "config.backup"), os.path.join(work_drive, prefix, module, "config.cpp"))
+
+ # Back to the root
+ os.chdir(module_root)
+
+ except:
+ raise
+ print_error("Could not run Addon Builder.")
+ input("Press Enter to continue...")
+ print ("Resuming build...")
+ continue
+
+ elif build_tool== "addonbuilder":
+ # Detect $NOBIN$ and do not binarize if found.
+ if os.path.isfile(os.path.join(work_drive, prefix, module, "$NOBIN$")):
+ do_binarize = False
+ print("$NOBIN$ file found in module, packing only.")
+ else:
+ do_binarize = True
+ try:
+ # Call AddonBuilder
+ os.chdir("P:\\")
+
+ cmd = [addonbuilder, os.path.join(work_drive, prefix, module), os.path.join(make_root, release_dir, project, "Addons"), "-clear", "-project="+work_drive]
+ if not do_binarize:
+ cmd.append("-packonly")
+
+ if quiet:
+ previousDirectory = os.getcwd()
+ os.chdir(arma3tools_path)
+ devnull = open(os.devnull, 'w')
+ ret = subprocess.call(cmd, stdout=devnull)
+ devnull.close()
+ os.chdir(previousDirectory)
+ else:
+ previousDirectory = os.getcwd()
+ os.chdir(arma3tools_path)
+ print_error("Current directory - " + os.getcwd())
+ ret = subprocess.call(cmd)
+ os.chdir(previousDirectory)
+ print_error("Current directory - " + os.getcwd())
+ color("reset")
+ print_green("completed")
+ # Prettyprefix rename the PBO if requested.
+ if pbo_name_prefix:
+ try:
+ os.rename(os.path.join(make_root, release_dir, project, "Addons", module+".pbo"), os.path.join(make_root, release_dir, project, "Addons", pbo_name_prefix+module+".pbo"))
+ except:
+ raise
+ print_error("Could not rename built PBO with prefix.")
+
+ if ret == 0:
+ # Sign result
+ if key:
+ print("Signing with " + key + ".")
+ if pbo_name_prefix:
+ ret = subprocess.call([dssignfile, key, os.path.join(make_root, release_dir, project, "Addons", pbo_name_prefix + module + ".pbo")])
+ else:
+ ret = subprocess.call([dssignfile, key, os.path.join(make_root, release_dir, project, "Addons", module + ".pbo")])
+
+ if ret == 0:
+ build_successful = True
+ else:
+ build_successful = True
+
+ if not build_successful:
+ print_error("Module not successfully built.")
+
+ # Back to the root
+ os.chdir(make_root)
+
+ except:
+ raise
+ print_error("Could not run Addon Builder.")
+ input("Press Enter to continue...")
+ print ("Resuming build...")
+ continue
+
+ else:
+ print_error("Unknown build_tool " + build_tool + "!")
+
+ # Update the hash for a successfully built module
+ if build_successful:
+ cache[module] = new_sha
+
+ # Done building all modules!
+
+ # Write out the cache state
+ cache_out = json.dumps(cache)
+ with open(os.path.join(make_root, "make.cache"), 'w') as f:
+ f.write(cache_out)
+
+ # Delete the pboproject temp files if building a release.
+ if make_release and build_tool == "pboproject":
+ try:
+ shutil.rmtree(os.path.join(module_root, release_dir, project, "temp"), True)
+ except:
+ print_error("ERROR: Could not delete pboProject temp files.")
+
+ print_green("\nDone.")
+
+ # Make release
+ if make_release:
+ print_blue("\nMaking release: " + project + "-" + release_version + ".zip")
+
+ try:
+ # Delete all log files
+ for root, dirs, files in os.walk(os.path.join(module_root, release_dir, project, "Addons")):
+ for currentFile in files:
+ if currentFile.lower().endswith("log"):
+ os.remove(os.path.join(root, currentFile))
+
+ # Create a zip with the contents of release/ in it
+ shutil.make_archive(project + "-" + release_version, "zip", os.path.join(module_root, release_dir))
+ except:
+ raise
+ print_error("Could not make release.")
+
+ # Copy to Arma 3 folder for testing
+ if test:
+ print_blue("\nCopying to Arma 3.")
+
+ if sys.platform == "win32":
+ reg = winreg.ConnectRegistry(None, winreg.HKEY_LOCAL_MACHINE)
+ try:
+ k = winreg.OpenKey(reg, r"SOFTWARE\Wow6432Node\Bohemia Interactive\Arma 3")
+ a3_path = winreg.EnumValue(k, 1)[1]
+ winreg.CloseKey(k)
+ except:
+ print_error("Could not find Arma 3's directory in the registry.")
+ else:
+ a3_path = cygwin_a3path
+
+ if os.path.exists(a3_path):
+ try:
+ shutil.rmtree(os.path.join(a3_path, project), True)
+ shutil.copytree(os.path.join(module_root, release_dir, project), os.path.join(a3_path, project))
+ except:
+ print_error("Could not copy files. Is Arma 3 running?")
+
+if __name__ == "__main__":
+ main(sys.argv)
+input("Press Enter to continue...")
\ No newline at end of file
From 955506dbe8fa47cd5dfcf3b43204e94bfa259f13 Mon Sep 17 00:00:00 2001
From: commy2
Date: Fri, 20 Mar 2015 19:56:39 +0100
Subject: [PATCH 34/36] stuff in to merge folder
---
TO_MERGE/agm/Optics/agm_optics_pip.p3d | Bin 0 -> 16770 bytes
TO_MERGE/agm/Optics/clientInit.sqf | 25 +
TO_MERGE/agm/Optics/config.cpp | 454 ++++++++++++++++++
.../Optics/data/arco/arco-bodyNight_ca.paa | Bin 0 -> 158939 bytes
.../agm/Optics/data/arco/arco-body_ca.paa | Bin 0 -> 268132 bytes
.../data/arco/arco-reticle65Illum_ca.paa | Bin 0 -> 107517 bytes
.../Optics/data/arco/arco-reticle65_ca.paa | Bin 0 -> 75808 bytes
TO_MERGE/agm/Optics/data/black.rvmat | 8 +
TO_MERGE/agm/Optics/data/em.rvmat | 20 +
.../Optics/data/hamr/hamr-bodyNight_ca.paa | Bin 0 -> 200010 bytes
.../agm/Optics/data/hamr/hamr-body_ca.paa | Bin 0 -> 325672 bytes
.../data/hamr/hamr-reticle65Illum_ca.paa | Bin 0 -> 84702 bytes
.../Optics/data/hamr/hamr-reticle65_ca.paa | Bin 0 -> 76786 bytes
.../Optics/data/mrco/mrco-bodyNight_ca.paa | Bin 0 -> 215859 bytes
.../agm/Optics/data/mrco/mrco-body_ca.paa | Bin 0 -> 451128 bytes
.../data/mrco/mrco-reticle556Illum_ca.paa | Bin 0 -> 101934 bytes
.../Optics/data/mrco/mrco-reticle556_ca.paa | Bin 0 -> 69617 bytes
.../agm/Optics/data/scopeblack-100_ca.paa | Bin 0 -> 38854 bytes
TO_MERGE/agm/Optics/data/scopeblack-70_ca.paa | Bin 0 -> 38525 bytes
TO_MERGE/agm/Optics/data/scopeblack-80_ca.paa | Bin 0 -> 38494 bytes
TO_MERGE/agm/Optics/data/scopeblack-90_ca.paa | Bin 0 -> 38531 bytes
.../agm/Optics/data/sos/sos-bodyNight_ca.paa | Bin 0 -> 486270 bytes
TO_MERGE/agm/Optics/data/sos/sos-body_ca.paa | Bin 0 -> 548243 bytes
.../data/sos/sos-reticleMLRIllum_ca.paa | Bin 0 -> 98484 bytes
.../agm/Optics/data/sos/sos-reticleMLR_ca.paa | Bin 0 -> 74319 bytes
.../agm/Optics/data/tmr_optics_reticle100.p3d | Bin 0 -> 3326 bytes
.../agm/Optics/data/tmr_optics_reticle70.p3d | Bin 0 -> 3349 bytes
.../agm/Optics/data/tmr_optics_reticle80.p3d | Bin 0 -> 3349 bytes
.../agm/Optics/data/tmr_optics_reticle90.p3d | Bin 0 -> 3349 bytes
.../agm/Optics/data/tmr_reticle_clear.p3d | Bin 0 -> 316 bytes
TO_MERGE/agm/Optics/functions/fn_firedEH.sqf | 149 ++++++
.../agm/Optics/functions/fn_hideScope.sqf | 19 +
.../agm/Optics/functions/fn_initScope.sqf | 25 +
TO_MERGE/agm/Optics/functions/fn_mainLoop.sqf | 94 ++++
34 files changed, 794 insertions(+)
create mode 100644 TO_MERGE/agm/Optics/agm_optics_pip.p3d
create mode 100644 TO_MERGE/agm/Optics/clientInit.sqf
create mode 100644 TO_MERGE/agm/Optics/config.cpp
create mode 100644 TO_MERGE/agm/Optics/data/arco/arco-bodyNight_ca.paa
create mode 100644 TO_MERGE/agm/Optics/data/arco/arco-body_ca.paa
create mode 100644 TO_MERGE/agm/Optics/data/arco/arco-reticle65Illum_ca.paa
create mode 100644 TO_MERGE/agm/Optics/data/arco/arco-reticle65_ca.paa
create mode 100644 TO_MERGE/agm/Optics/data/black.rvmat
create mode 100644 TO_MERGE/agm/Optics/data/em.rvmat
create mode 100644 TO_MERGE/agm/Optics/data/hamr/hamr-bodyNight_ca.paa
create mode 100644 TO_MERGE/agm/Optics/data/hamr/hamr-body_ca.paa
create mode 100644 TO_MERGE/agm/Optics/data/hamr/hamr-reticle65Illum_ca.paa
create mode 100644 TO_MERGE/agm/Optics/data/hamr/hamr-reticle65_ca.paa
create mode 100644 TO_MERGE/agm/Optics/data/mrco/mrco-bodyNight_ca.paa
create mode 100644 TO_MERGE/agm/Optics/data/mrco/mrco-body_ca.paa
create mode 100644 TO_MERGE/agm/Optics/data/mrco/mrco-reticle556Illum_ca.paa
create mode 100644 TO_MERGE/agm/Optics/data/mrco/mrco-reticle556_ca.paa
create mode 100644 TO_MERGE/agm/Optics/data/scopeblack-100_ca.paa
create mode 100644 TO_MERGE/agm/Optics/data/scopeblack-70_ca.paa
create mode 100644 TO_MERGE/agm/Optics/data/scopeblack-80_ca.paa
create mode 100644 TO_MERGE/agm/Optics/data/scopeblack-90_ca.paa
create mode 100644 TO_MERGE/agm/Optics/data/sos/sos-bodyNight_ca.paa
create mode 100644 TO_MERGE/agm/Optics/data/sos/sos-body_ca.paa
create mode 100644 TO_MERGE/agm/Optics/data/sos/sos-reticleMLRIllum_ca.paa
create mode 100644 TO_MERGE/agm/Optics/data/sos/sos-reticleMLR_ca.paa
create mode 100644 TO_MERGE/agm/Optics/data/tmr_optics_reticle100.p3d
create mode 100644 TO_MERGE/agm/Optics/data/tmr_optics_reticle70.p3d
create mode 100644 TO_MERGE/agm/Optics/data/tmr_optics_reticle80.p3d
create mode 100644 TO_MERGE/agm/Optics/data/tmr_optics_reticle90.p3d
create mode 100644 TO_MERGE/agm/Optics/data/tmr_reticle_clear.p3d
create mode 100644 TO_MERGE/agm/Optics/functions/fn_firedEH.sqf
create mode 100644 TO_MERGE/agm/Optics/functions/fn_hideScope.sqf
create mode 100644 TO_MERGE/agm/Optics/functions/fn_initScope.sqf
create mode 100644 TO_MERGE/agm/Optics/functions/fn_mainLoop.sqf
diff --git a/TO_MERGE/agm/Optics/agm_optics_pip.p3d b/TO_MERGE/agm/Optics/agm_optics_pip.p3d
new file mode 100644
index 0000000000000000000000000000000000000000..d331ce4acd688cef9fcbad0d6e24356c8e7b5c60
GIT binary patch
literal 16770
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%0A3IR{+V3cStL6PHVNDxN7~~J
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