From 33314f8a9e7675f7e6694ebf86062d9e02213924 Mon Sep 17 00:00:00 2001 From: SilentSpike Date: Fri, 31 Jul 2015 23:32:25 +0100 Subject: [PATCH 01/91] Adjust spectator camera boom speed Vertical camera movement (boom) was previously at a constant speed. However this felt too slow at times, half the horizontal (dolly) speed should improve this. --- addons/spectator/functions/fnc_handleInterface.sqf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addons/spectator/functions/fnc_handleInterface.sqf b/addons/spectator/functions/fnc_handleInterface.sqf index 864ae32adc..709c0263b2 100644 --- a/addons/spectator/functions/fnc_handleInterface.sqf +++ b/addons/spectator/functions/fnc_handleInterface.sqf @@ -224,7 +224,7 @@ switch (toLower _mode) do { [_display,nil,nil,true] call FUNC(toggleInterface); }; case 16: { // Q - GVAR(camBoom) = 0.5; + GVAR(camBoom) = 0.5 * GVAR(camSpeed); }; case 17: { // W GVAR(camDolly) set [1, GVAR(camSpeed)]; @@ -245,7 +245,7 @@ switch (toLower _mode) do { [_display,nil,true] call FUNC(toggleInterface); }; case 44: { // Z - GVAR(camBoom) = -0.5; + GVAR(camBoom) = -0.5 * GVAR(camSpeed); }; case 49: { // N if (_ctrl) then { From 612aa2d679515c0d74156c823852efe10083bf5a Mon Sep 17 00:00:00 2001 From: SilentSpike Date: Sat, 1 Aug 2015 18:10:11 +0100 Subject: [PATCH 02/91] Separate spectator physical and virtual states With the changes planned to allow spectator in the true death state, physical changes aren't applicable in all of the possible usage cases. This separates the physical process into new function ace_spectator_fnc_stageSpectator --- addons/spectator/XEH_preInit.sqf | 1 + .../spectator/functions/fnc_setSpectator.sqf | 49 +++---------- .../functions/fnc_stageSpectator.sqf | 68 +++++++++++++++++++ 3 files changed, 77 insertions(+), 41 deletions(-) create mode 100644 addons/spectator/functions/fnc_stageSpectator.sqf diff --git a/addons/spectator/XEH_preInit.sqf b/addons/spectator/XEH_preInit.sqf index e5872c3272..2cc65602cc 100644 --- a/addons/spectator/XEH_preInit.sqf +++ b/addons/spectator/XEH_preInit.sqf @@ -16,6 +16,7 @@ PREP(handleUnits); PREP(moduleSpectatorSettings); PREP(setCameraAttributes); PREP(setSpectator); +PREP(stageSpectator); PREP(transitionCamera); PREP(toggleInterface); PREP(updateCameraModes); diff --git a/addons/spectator/functions/fnc_setSpectator.sqf b/addons/spectator/functions/fnc_setSpectator.sqf index fd3dd9861c..f4dc86c3da 100644 --- a/addons/spectator/functions/fnc_setSpectator.sqf +++ b/addons/spectator/functions/fnc_setSpectator.sqf @@ -1,10 +1,14 @@ /* * Author: SilentSpike - * Sets target unit to the given spectator state + * Sets target unit to the given spectator state (virtually) + * To physically handle a spectator see ace_spectator_fnc_stageSpectator + * + * Units will be able to communicate in ACRE/TFAR as appropriate + * The spectator interface will be opened/closed * * Arguments: * 0: Unit to put into spectator state - * 1: New spectator state + * 1: Spectator state * * Return Value: * None @@ -17,10 +21,7 @@ #include "script_component.hpp" -params ["_unit",["_set",true,[true]],["_target",objNull,[objNull]]]; - -// No change, no service (but allow spectators who respawn to be reset) -if !(_set || (_unit getVariable [QGVAR(isSpectator), false])) exitWith {}; +params ["_unit", ["_set",true,[true]]]; // Only run for player units if !(isPlayer _unit) exitWith {}; @@ -29,49 +30,15 @@ if !(local _unit) exitwith { [[_unit, _set, _target], QFUNC(setSpectator), _unit] call EFUNC(common,execRemoteFnc); }; -// Prevent player falling into water -_unit enableSimulation !_set; - -// Move to/from group as appropriate -[_unit, _set, QGVAR(isSpectator), side group _unit] call EFUNC(common,switchToGroupSide); - if (_set) then { - // Move and hide the player ASAP to avoid being seen - _unit setPos (getMarkerPos QGVAR(respawn)); - - // Ghosts can't talk - [_unit, QGVAR(isSpectator)] call EFUNC(common,hideUnit); - [_unit, QGVAR(isSpectator)] call EFUNC(common,muteUnit); - ["open"] call FUNC(handleInterface); } else { ["close"] call FUNC(handleInterface); - - // Physical beings can talk - [_unit, QGVAR(isSpectator)] call EFUNC(common,unhideUnit); - [_unit, QGVAR(isSpectator)] call EFUNC(common,unmuteUnit); - - private "_marker"; - _marker = ["respawn_west","respawn_east","respawn_guerrila","respawn_civilian"] select ([west,east,resistance,civilian] find (side group _unit)); - _unit setPos (getMarkerPos _marker); }; -// Enable/disable input as appropriate -//[QGVAR(isSpectator), _set] call EFUNC(common,setDisableUserInputStatus); - // Handle common addon audio if (["ace_hearing"] call EFUNC(common,isModLoaded)) then {EGVAR(hearing,disableVolumeUpdate) = _set}; if (["acre_sys_radio"] call EFUNC(common,isModLoaded)) then {[_set] call acre_api_fnc_setSpectator}; if (["task_force_radio"] call EFUNC(common,isModLoaded)) then {[_unit, _set] call TFAR_fnc_forceSpectator}; -// Spectators ignore damage (vanilla and ace_medical) -_unit allowDamage !_set; -_unit setVariable [QEGVAR(medical,allowDamage), !_set]; - -// No theoretical change if an existing spectator was reset -if !(_set && (_unit getVariable [QGVAR(isSpectator), false])) then { - // Mark spectator state for reference - _unit setVariable [QGVAR(isSpectator), _set, true]; - - ["spectatorChanged",[_set]] call EFUNC(common,localEvent); -}; +["spectatorSet",[_set]] call EFUNC(common,localEvent); diff --git a/addons/spectator/functions/fnc_stageSpectator.sqf b/addons/spectator/functions/fnc_stageSpectator.sqf new file mode 100644 index 0000000000..2f6741e35a --- /dev/null +++ b/addons/spectator/functions/fnc_stageSpectator.sqf @@ -0,0 +1,68 @@ +/* + * Author: SilentSpike + * Sets target unit to the given spectator state (physically) + * To virtually handle a spectator see ace_spectator_fnc_setSpectator + * + * Units will be gathered at marker ace_spectator_respawn (or [0,0,0] by default) + * Upon unstage, units will be moved to the position they were in upon staging + * + * Arguments: + * 0: Unit to put into spectator stage + * 1: Spectator stage + * + * Return Value: + * None + * + * Example: + * [player, false] call ace_spectator_fnc_stageSpectator + * + * Public: Yes + */ + +#include "script_component.hpp" + +params ["_unit", ["_set",true,[true]]]; + +// No change, no service (but allow spectators who respawn to be reset) +if !(_set || (GETVAR(_unit,GVAR(isSpectator),false))) exitWith {}; + +// Only run for player units +if !(isPlayer _unit) exitWith {}; + +if !(local _unit) exitwith { + [[_unit, _set, _target], QFUNC(stageSpectator), _unit] call EFUNC(common,execRemoteFnc); +}; + +// Prevent player falling into water +_unit enableSimulation !_set; + +// Move to/from group as appropriate +[_unit, _set, QGVAR(isSpectator), side group _unit] call EFUNC(common,switchToGroupSide); + +if (_set) then { + // Move and hide the player ASAP to avoid being seen + GVAR(oldPos) = getPosATL _unit; + _unit setPos (getMarkerPos QGVAR(respawn)); + + // Ghosts can't talk + [_unit, QGVAR(isSpectator)] call EFUNC(common,hideUnit); + [_unit, QGVAR(isSpectator)] call EFUNC(common,muteUnit); +} else { + // Physical beings can talk + [_unit, QGVAR(isSpectator)] call EFUNC(common,unhideUnit); + [_unit, QGVAR(isSpectator)] call EFUNC(common,unmuteUnit); + + _unit setPosATL GVAR(oldPos); +}; + +// Spectators ignore damage (vanilla and ace_medical) +_unit allowDamage !_set; +_unit setVariable [QEGVAR(medical,allowDamage), !_set]; + +// No theoretical change if an existing spectator was reset +if !(_set isEqualTo (GETVAR(_unit,GVAR(isSpectator),false))) then { + // Mark spectator state for reference + _unit setVariable [QGVAR(isSpectator), _set, true]; + + ["spectatorStaged",[_set]] call EFUNC(common,localEvent); +}; From 38e08d513a91fe0c084ecfd2d8dfd575224961d2 Mon Sep 17 00:00:00 2001 From: SilentSpike Date: Sun, 2 Aug 2015 12:34:35 +0100 Subject: [PATCH 03/91] Clear spectator display variable at preInit uiNamespace persists between missions and should be reset on mission start --- addons/spectator/XEH_preInit.sqf | 2 ++ addons/spectator/functions/fnc_handleInterface.sqf | 8 ++------ 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/addons/spectator/XEH_preInit.sqf b/addons/spectator/XEH_preInit.sqf index 2cc65602cc..a77d731478 100644 --- a/addons/spectator/XEH_preInit.sqf +++ b/addons/spectator/XEH_preInit.sqf @@ -38,6 +38,8 @@ GVAR(camUnit) = objNull; GVAR(camVision) = -2; GVAR(camZoom) = 1.25; +SETUVAR(GVAR(display),nil); + GVAR(showComp) = true; GVAR(showHelp) = true; GVAR(showIcons) = true; diff --git a/addons/spectator/functions/fnc_handleInterface.sqf b/addons/spectator/functions/fnc_handleInterface.sqf index 709c0263b2..2fa0d1439c 100644 --- a/addons/spectator/functions/fnc_handleInterface.sqf +++ b/addons/spectator/functions/fnc_handleInterface.sqf @@ -95,9 +95,7 @@ switch (toLower _mode) do { case "onload": { _args params ["_display"]; - with uiNamespace do { - GVAR(display) = _display; - }; + SETUVAR(GVAR(display),_display); // Always show interface and hide map upon opening [_display,nil,nil,!GVAR(showInterface),GVAR(showMap)] call FUNC(toggleInterface); @@ -151,9 +149,7 @@ switch (toLower _mode) do { //_display displayAddEventHandler ["KeyDown", {[_this,'keydown'] call CBA_events_fnc_keyHandler}]; }; case "onunload": { - with uiNamespace do { - GVAR(display) = nil; - }; + SETUVAR(GVAR(display),nil); GVAR(camHandler) = nil; GVAR(compHandler) = nil; From 63c034e348421d22a01e84f923841b48e76deebc Mon Sep 17 00:00:00 2001 From: SilentSpike Date: Sun, 2 Aug 2015 12:47:26 +0100 Subject: [PATCH 04/91] Differentiate between staged and set spectators Existing variable "ace_spectator_isSpectator" split into counterparts "ace_spectator_isSet" and "ace_spectator_isStaged" in order to better manage spectator events --- addons/spectator/XEH_postInit.sqf | 2 +- .../spectator/functions/fnc_setSpectator.sqf | 11 ++++++++++- .../spectator/functions/fnc_stageSpectator.sqf | 18 +++++++++--------- addons/spectator/functions/fnc_updateUnits.sqf | 2 +- 4 files changed, 21 insertions(+), 12 deletions(-) diff --git a/addons/spectator/XEH_postInit.sqf b/addons/spectator/XEH_postInit.sqf index bad3758c19..45ac78e89c 100644 --- a/addons/spectator/XEH_postInit.sqf +++ b/addons/spectator/XEH_postInit.sqf @@ -2,7 +2,7 @@ //#include "initKeybinds.sqf"; // Add interaction menu exception -["isNotSpectating", {!((_this select 0) getVariable [QGVAR(isSpectator), false])}] call EFUNC(common,addCanInteractWithCondition); +["isNotSpectating", {!(GETVAR((_this select 0),GVAR(isStaged),false))}] call EFUNC(common,addCanInteractWithCondition); ["SettingsInitialized", { GVAR(availableModes) = [[0,1,2], [1,2], [0], [1], [2]] select GVAR(restrictModes); diff --git a/addons/spectator/functions/fnc_setSpectator.sqf b/addons/spectator/functions/fnc_setSpectator.sqf index f4dc86c3da..2f8e1d3c2d 100644 --- a/addons/spectator/functions/fnc_setSpectator.sqf +++ b/addons/spectator/functions/fnc_setSpectator.sqf @@ -23,6 +23,9 @@ params ["_unit", ["_set",true,[true]]]; +// No change, no service (but allow spectators to be reset) +if !(_set || (GETVAR(_unit,GVAR(isSet),false))) exitWith {}; + // Only run for player units if !(isPlayer _unit) exitWith {}; @@ -41,4 +44,10 @@ if (["ace_hearing"] call EFUNC(common,isModLoaded)) then {EGVAR(hearing,disableV if (["acre_sys_radio"] call EFUNC(common,isModLoaded)) then {[_set] call acre_api_fnc_setSpectator}; if (["task_force_radio"] call EFUNC(common,isModLoaded)) then {[_unit, _set] call TFAR_fnc_forceSpectator}; -["spectatorSet",[_set]] call EFUNC(common,localEvent); +// No theoretical change if an existing spectator was reset +if !(_set isEqualTo (GETVAR(_unit,GVAR(isSet),false))) then { + // Mark spectator state for reference + _unit setVariable [QGVAR(isSet), _set, true]; + + ["spectatorSet",[_set]] call EFUNC(common,localEvent); +}; diff --git a/addons/spectator/functions/fnc_stageSpectator.sqf b/addons/spectator/functions/fnc_stageSpectator.sqf index 2f6741e35a..84bd6ffced 100644 --- a/addons/spectator/functions/fnc_stageSpectator.sqf +++ b/addons/spectator/functions/fnc_stageSpectator.sqf @@ -23,8 +23,8 @@ params ["_unit", ["_set",true,[true]]]; -// No change, no service (but allow spectators who respawn to be reset) -if !(_set || (GETVAR(_unit,GVAR(isSpectator),false))) exitWith {}; +// No change, no service (but allow spectators to be reset) +if !(_set || (GETVAR(_unit,GVAR(isStaged),false))) exitWith {}; // Only run for player units if !(isPlayer _unit) exitWith {}; @@ -37,7 +37,7 @@ if !(local _unit) exitwith { _unit enableSimulation !_set; // Move to/from group as appropriate -[_unit, _set, QGVAR(isSpectator), side group _unit] call EFUNC(common,switchToGroupSide); +[_unit, _set, QGVAR(isStaged), side group _unit] call EFUNC(common,switchToGroupSide); if (_set) then { // Move and hide the player ASAP to avoid being seen @@ -45,12 +45,12 @@ if (_set) then { _unit setPos (getMarkerPos QGVAR(respawn)); // Ghosts can't talk - [_unit, QGVAR(isSpectator)] call EFUNC(common,hideUnit); - [_unit, QGVAR(isSpectator)] call EFUNC(common,muteUnit); + [_unit, QGVAR(isStaged)] call EFUNC(common,hideUnit); + [_unit, QGVAR(isStaged)] call EFUNC(common,muteUnit); } else { // Physical beings can talk - [_unit, QGVAR(isSpectator)] call EFUNC(common,unhideUnit); - [_unit, QGVAR(isSpectator)] call EFUNC(common,unmuteUnit); + [_unit, QGVAR(isStaged)] call EFUNC(common,unhideUnit); + [_unit, QGVAR(isStaged)] call EFUNC(common,unmuteUnit); _unit setPosATL GVAR(oldPos); }; @@ -60,9 +60,9 @@ _unit allowDamage !_set; _unit setVariable [QEGVAR(medical,allowDamage), !_set]; // No theoretical change if an existing spectator was reset -if !(_set isEqualTo (GETVAR(_unit,GVAR(isSpectator),false))) then { +if !(_set isEqualTo (GETVAR(_unit,GVAR(isStaged),false))) then { // Mark spectator state for reference - _unit setVariable [QGVAR(isSpectator), _set, true]; + _unit setVariable [QGVAR(isStaged), _set, true]; ["spectatorStaged",[_set]] call EFUNC(common,localEvent); }; diff --git a/addons/spectator/functions/fnc_updateUnits.sqf b/addons/spectator/functions/fnc_updateUnits.sqf index 0393fa0e36..ef8fc3b4f1 100644 --- a/addons/spectator/functions/fnc_updateUnits.sqf +++ b/addons/spectator/functions/fnc_updateUnits.sqf @@ -55,7 +55,7 @@ _filteredUnits = []; {(_x isKindOf "CAManBase")} && {(side group _x) in _sides} && // Side filter {simulationEnabled _x} && - {!(_x getVariable [QGVAR(isSpectator), false])} // Who watches the watchmen? + {!(_x getVariable [QGVAR(isStaged), false])} // Who watches the watchmen? ) then { _filteredUnits pushBack _x; }; From 52460182c9c662dacc76e27f21a5d9e8b37786e8 Mon Sep 17 00:00:00 2001 From: SilentSpike Date: Sun, 2 Aug 2015 16:42:24 +0100 Subject: [PATCH 05/91] Enable spectator on death system New spectator on death system should enter spectator mode upon dying and exit upon respawning. Only virtual spectator state is suitable for this system since the body should remain as is. --- addons/spectator/functions/fnc_handleKilled.sqf | 9 ++++----- addons/spectator/functions/fnc_handleRespawn.sqf | 6 +++--- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/addons/spectator/functions/fnc_handleKilled.sqf b/addons/spectator/functions/fnc_handleKilled.sqf index 67c556cc3f..05671ed749 100644 --- a/addons/spectator/functions/fnc_handleKilled.sqf +++ b/addons/spectator/functions/fnc_handleKilled.sqf @@ -1,7 +1,7 @@ /* * Author: SilentSpike - * Cache necessary details and process unit for spectator on death - * Part of the basic spectator system + * Set inital camera attributes and set as spectator on death + * Part of the spectator during death system * * Arguments: * 0: Corpse @@ -17,11 +17,10 @@ params ["_unit","_killer"]; -// Remove from group to prevent appearing on HUD upon respawn -[_unit, true, QGVAR(isSpectator), side group _unit] call EFUNC(common,switchToGroupSide); - if (isNull _killer) then { [2,_unit] call FUNC(setCameraAttributes); } else { [2,_killer] call FUNC(setCameraAttributes); }; + +[_unit] call FUNC(setSpectator); diff --git a/addons/spectator/functions/fnc_handleRespawn.sqf b/addons/spectator/functions/fnc_handleRespawn.sqf index 9b6b0bb802..3e7dfa41f3 100644 --- a/addons/spectator/functions/fnc_handleRespawn.sqf +++ b/addons/spectator/functions/fnc_handleRespawn.sqf @@ -1,7 +1,7 @@ /* * Author: SilentSpike - * Start the interface on respawn - * Part of the basic spectator system + * Un-set as spectator on respawn + * Part of the spectator during death system * * Arguments: * 0: New unit @@ -15,4 +15,4 @@ #include "script_component.hpp" -[_this select 0] call FUNC(setSpectator); +[_unit,false] call FUNC(setSpectator); From 9b764bbba45a3980114676842d07c260379c55c2 Mon Sep 17 00:00:00 2001 From: SilentSpike Date: Sun, 2 Aug 2015 17:27:32 +0100 Subject: [PATCH 06/91] Preserve Polish translations from master branch Since spectator was pushed back to a feature branch from the release branch these translations from a PR were also lost (as the commits were prior to the removal commit) when it was merged after the fact. --- addons/spectator/stringtable.xml | 70 +++++++++++++++++++++++++++++--- 1 file changed, 64 insertions(+), 6 deletions(-) diff --git a/addons/spectator/stringtable.xml b/addons/spectator/stringtable.xml index 8b91608981..1f74d08c43 100644 --- a/addons/spectator/stringtable.xml +++ b/addons/spectator/stringtable.xml @@ -3,195 +3,253 @@ Spectator Settings + Ustawienia obserwatora Configure how the spectator system will operate by default. + Skonfiguruj domyślne ustawienia obserwatora. Spectate on death + Obserwator po śmierci Enables spectator upon death. + Włącz obserwatora po śmierci Unit filter + Filtr jednostek Method of filtering spectatable units. + Wybierz jednostki, jakie będzie można obserwować po uruchomeniu obserwatora. No units + Brak jednostek Only players + Tylko gracze All units + Wszystkie jednostki Side filter + Filtr stron Method of filtering spectatable sides. + Wybierz strony, jakie będzie można obserwować po uruchomeniu obserwatora. Player side + Strona gracza Friendly sides + Strony sojusznicze Hostile sides + Strony wrogie All sides + Wszystkie strony Camera modes + Tryby kamery Camera modes that can be used. + Tryby kamery, jakie mogą być używane. All + Wszystkie Free only + Tylko wolna Internal only + Tylko wewnętrzna External only + Tylko zewnętrzna Internal and external + Wewnętrzna i zewnętrzna Vision modes + Tryby wizji Vision modes that can be used. + Tryby wizji, jakie mogą być używane. Night vision + Noktowizja Thermal imaging + Termowizja Unit icons + Ikony jednostek Render icons above spectatable units. + Renderuj ikony nad głowami jednostek, które można obserwować. - Spectator Controls + Sterowanie obserwatorem Free + Wolna Internal + Wewnętrzna External + Zewnętrzna Normal + Normalna Night + Noc Thermal + Termo - Free Camera Controls + Wolne sterowanie kamerą Camera Forward + Kamera naprzód Camera Backward + Kamera w tył Camera Left + Kamera w lewo Camera Right + Kamera w prawo Camera Up + Kamera w górę Camera Down + Kamera w dół Pan Camera + Panoramowanie Dolly Camera + Płynna kamera Lock Camera to Target + Zablokuj kamerę na celu - Zoom In/Out + Zoom +/- + Zoom +/- - Speed Up/Down + Speed +/- + Prędkość +/- Next Vision Mode + Następny tryb wizji Previous Vision Mode + Poprzedni tryb wizji - Interface Controls + Sterowanie interfejsem Toggle Interface + Przełącz interfejs Toggle Unit Icons + Przełącz ikony jednostek Toggle Unit List + Przełącz listę jednostek Toggle Toolbar + Przełącz pasek narzędzi Toggle Compass + Przełącz kompas Toggle Map + Przełącz mapę Toggle Help + Przełącz pomoc - Other Controls + Pozostałe sterowanie Next Camera + Następna kamera Previous Camera + Poprzednia kamera Next Unit + Następna jednostka Previous Unit + Poprzednia jednostka From b87b4ea16aba273aca2ad287239bd45f60c890c5 Mon Sep 17 00:00:00 2001 From: SilentSpike Date: Mon, 3 Aug 2015 00:22:50 +0100 Subject: [PATCH 07/91] Improve spectator GUI reopening prevention Using boolean instead of simply checking for the display. Checking for diplay was unreliable since it can be technically closed while theoretically open during the escape menu and such. --- addons/spectator/XEH_preInit.sqf | 2 +- addons/spectator/functions/fnc_handleInterface.sqf | 12 +++++------- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/addons/spectator/XEH_preInit.sqf b/addons/spectator/XEH_preInit.sqf index a77d731478..3b317ba904 100644 --- a/addons/spectator/XEH_preInit.sqf +++ b/addons/spectator/XEH_preInit.sqf @@ -38,7 +38,7 @@ GVAR(camUnit) = objNull; GVAR(camVision) = -2; GVAR(camZoom) = 1.25; -SETUVAR(GVAR(display),nil); +GVAR(open) = false; GVAR(showComp) = true; GVAR(showHelp) = true; diff --git a/addons/spectator/functions/fnc_handleInterface.sqf b/addons/spectator/functions/fnc_handleInterface.sqf index 2fa0d1439c..114f4e163b 100644 --- a/addons/spectator/functions/fnc_handleInterface.sqf +++ b/addons/spectator/functions/fnc_handleInterface.sqf @@ -23,7 +23,8 @@ switch (toLower _mode) do { // Safely open/close the interface case "open": { // Prevent reopening - if !(isNull (GETUVAR(GVAR(display),displayNull))) exitWith {}; + if (GVAR(open)) exitWith {}; + GVAR(open) = true; // Initalize camera variables GVAR(camBoom) = 0; @@ -57,13 +58,13 @@ switch (toLower _mode) do { }; case "close": { // Can't close a second time - if (isNull (GETUVAR(GVAR(display),displayNull))) exitWith {}; + if !(GVAR(open)) exitWith {}; + GVAR(open) = false; // Terminate interface while {dialog} do { closeDialog 0; }; - GETUVAR(GVAR(display),displayNull) closeDisplay 0; // Terminate camera GVAR(camera) cameraEffect ["terminate", "back"]; @@ -95,8 +96,6 @@ switch (toLower _mode) do { case "onload": { _args params ["_display"]; - SETUVAR(GVAR(display),_display); - // Always show interface and hide map upon opening [_display,nil,nil,!GVAR(showInterface),GVAR(showMap)] call FUNC(toggleInterface); @@ -149,8 +148,7 @@ switch (toLower _mode) do { //_display displayAddEventHandler ["KeyDown", {[_this,'keydown'] call CBA_events_fnc_keyHandler}]; }; case "onunload": { - SETUVAR(GVAR(display),nil); - + // Kill GUI PFHs GVAR(camHandler) = nil; GVAR(compHandler) = nil; GVAR(iconHandler) = nil; From 98b088f26f717d172c3bdb5e1a0695412ce38c5a Mon Sep 17 00:00:00 2001 From: SilentSpike Date: Mon, 3 Aug 2015 00:24:36 +0100 Subject: [PATCH 08/91] Fix pre-spectator position saving When staging a spectator (physically applying the spectator state) the unit position is saved for potential later restoration. This shouldn't be done multiple times since the function can be called again to reset staged units. --- addons/spectator/functions/fnc_handleRespawn.sqf | 2 ++ addons/spectator/functions/fnc_stageSpectator.sqf | 9 ++++++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/addons/spectator/functions/fnc_handleRespawn.sqf b/addons/spectator/functions/fnc_handleRespawn.sqf index 3e7dfa41f3..aa695dd553 100644 --- a/addons/spectator/functions/fnc_handleRespawn.sqf +++ b/addons/spectator/functions/fnc_handleRespawn.sqf @@ -15,4 +15,6 @@ #include "script_component.hpp" +params ["_unit","_oldUnit"]; + [_unit,false] call FUNC(setSpectator); diff --git a/addons/spectator/functions/fnc_stageSpectator.sqf b/addons/spectator/functions/fnc_stageSpectator.sqf index 84bd6ffced..bac5174601 100644 --- a/addons/spectator/functions/fnc_stageSpectator.sqf +++ b/addons/spectator/functions/fnc_stageSpectator.sqf @@ -40,13 +40,16 @@ _unit enableSimulation !_set; [_unit, _set, QGVAR(isStaged), side group _unit] call EFUNC(common,switchToGroupSide); if (_set) then { - // Move and hide the player ASAP to avoid being seen - GVAR(oldPos) = getPosATL _unit; - _unit setPos (getMarkerPos QGVAR(respawn)); + // Position should only be saved on first entry + if !(GETVAR(_unit,GVAR(isStaged),false)) then { + GVAR(oldPos) = getPosATL _unit; + }; // Ghosts can't talk [_unit, QGVAR(isStaged)] call EFUNC(common,hideUnit); [_unit, QGVAR(isStaged)] call EFUNC(common,muteUnit); + + _unit setPos (getMarkerPos QGVAR(respawn)); } else { // Physical beings can talk [_unit, QGVAR(isStaged)] call EFUNC(common,unhideUnit); From f5e7185aec965d0166cf8cae2e85a6b81d717a44 Mon Sep 17 00:00:00 2001 From: SilentSpike Date: Mon, 3 Aug 2015 13:04:36 +0100 Subject: [PATCH 09/91] Fix spectator camera exiting mechanism When using ACE_Player the camera would return to the dead body. It makes sense to simply pass the reset unit by reference to the camera exit code. --- addons/spectator/functions/fnc_handleInterface.sqf | 4 +++- addons/spectator/functions/fnc_setSpectator.sqf | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/addons/spectator/functions/fnc_handleInterface.sqf b/addons/spectator/functions/fnc_handleInterface.sqf index 114f4e163b..255d282983 100644 --- a/addons/spectator/functions/fnc_handleInterface.sqf +++ b/addons/spectator/functions/fnc_handleInterface.sqf @@ -57,6 +57,8 @@ switch (toLower _mode) do { }; }; case "close": { + _args params ["_unit"]; + // Can't close a second time if !(GVAR(open)) exitWith {}; GVAR(open) = false; @@ -71,7 +73,7 @@ switch (toLower _mode) do { camDestroy GVAR(camera); // Return to player view - ACE_Player switchCamera "internal"; + _unit switchCamera "internal"; // Cleanup camera variables GVAR(camera) = nil; diff --git a/addons/spectator/functions/fnc_setSpectator.sqf b/addons/spectator/functions/fnc_setSpectator.sqf index 2f8e1d3c2d..b6e85926c5 100644 --- a/addons/spectator/functions/fnc_setSpectator.sqf +++ b/addons/spectator/functions/fnc_setSpectator.sqf @@ -36,7 +36,7 @@ if !(local _unit) exitwith { if (_set) then { ["open"] call FUNC(handleInterface); } else { - ["close"] call FUNC(handleInterface); + ["close",_unit] call FUNC(handleInterface); }; // Handle common addon audio From 5bfa4e597113356d534d28cef9b5dc011b761e6f Mon Sep 17 00:00:00 2001 From: SilentSpike Date: Mon, 3 Aug 2015 15:18:09 +0100 Subject: [PATCH 10/91] Improve spectator camera vision mode on start The spectator camera should start in night vision mode if the sun to moon transition state is appropriate --- addons/spectator/functions/fnc_handleInterface.sqf | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/addons/spectator/functions/fnc_handleInterface.sqf b/addons/spectator/functions/fnc_handleInterface.sqf index 255d282983..315398ab0c 100644 --- a/addons/spectator/functions/fnc_handleInterface.sqf +++ b/addons/spectator/functions/fnc_handleInterface.sqf @@ -37,6 +37,11 @@ switch (toLower _mode) do { GVAR(mouse) = [false,false]; GVAR(mousePos) = [0.5,0.5]; + // Camera starts with night vision if it's dark + if (sunOrMoon < 1) then { + [nil,nil,-1] call FUNC(setCameraAttributes); + }; + // Initalize the camera view GVAR(camera) = "Camera" camCreate (ASLtoATL GVAR(camPos)); [] call FUNC(transitionCamera); From 7e9500f2ca6a240458b16031153565ff8e451efa Mon Sep 17 00:00:00 2001 From: SilentSpike Date: Mon, 3 Aug 2015 21:38:44 +0100 Subject: [PATCH 11/91] Enable ace_spectator respawn framework integration Seamlessly integrates the spectator system with the vanilla respawn framework when the onDeath setting is enabled. This commit makes a lot of changes: - Edit BI functions used by the vanilla respawn framework to enable support for ace_spectator. - Set spectator state is now tracked using a GVAR for the local player since using a unit won't be reliable all of the time. However unit is still marked for any filtering purposes. - Instead of NV being used based on the sun to moon transition state by default, that functionality only takes place in the integrated system so that custom frameworks can do what they want. - Seagull units are hidden when using framework integration since they're spawned by the engine with respawn type 1 and they just hang around undesirably --- addons/spectator/XEH_postInit.sqf | 7 - addons/spectator/XEH_preInit.sqf | 12 +- addons/spectator/config.cpp | 35 +++ .../functions/fnc_bi_respawnBase.sqf | 35 +++ .../functions/fnc_bi_respawnCounter.sqf | 35 +++ .../functions/fnc_bi_respawnEndMission.sqf | 62 ++++ .../functions/fnc_bi_respawnInstant.sqf | 35 +++ .../functions/fnc_bi_respawnNone.sqf | 293 ++++++++++++++++++ .../functions/fnc_bi_respawnSeagull.sqf | 101 ++++++ .../functions/fnc_bi_respawnSpectator.sqf | 59 ++++ .../functions/fnc_bi_respawnWave.sqf | 43 +++ .../functions/fnc_handleInterface.sqf | 22 +- .../spectator/functions/fnc_handleKilled.sqf | 26 -- .../spectator/functions/fnc_handleRespawn.sqf | 20 -- .../functions/fnc_setCameraAttributes.sqf | 2 +- .../spectator/functions/fnc_setSpectator.sqf | 31 +- .../functions/fnc_stageSpectator.sqf | 4 +- 17 files changed, 736 insertions(+), 86 deletions(-) create mode 100644 addons/spectator/functions/fnc_bi_respawnBase.sqf create mode 100644 addons/spectator/functions/fnc_bi_respawnCounter.sqf create mode 100644 addons/spectator/functions/fnc_bi_respawnEndMission.sqf create mode 100644 addons/spectator/functions/fnc_bi_respawnInstant.sqf create mode 100644 addons/spectator/functions/fnc_bi_respawnNone.sqf create mode 100644 addons/spectator/functions/fnc_bi_respawnSeagull.sqf create mode 100644 addons/spectator/functions/fnc_bi_respawnSpectator.sqf create mode 100644 addons/spectator/functions/fnc_bi_respawnWave.sqf delete mode 100644 addons/spectator/functions/fnc_handleKilled.sqf delete mode 100644 addons/spectator/functions/fnc_handleRespawn.sqf diff --git a/addons/spectator/XEH_postInit.sqf b/addons/spectator/XEH_postInit.sqf index 45ac78e89c..35b463837f 100644 --- a/addons/spectator/XEH_postInit.sqf +++ b/addons/spectator/XEH_postInit.sqf @@ -7,11 +7,4 @@ ["SettingsInitialized", { GVAR(availableModes) = [[0,1,2], [1,2], [0], [1], [2]] select GVAR(restrictModes); GVAR(availableVisions) = [[-2,-1,0,1], [-2,-1], [-2,0,1], [-2]] select GVAR(restrictVisions); - - if !(hasInterface) exitWith {}; - - if (GVAR(onDeath)) then { - player addEventHandler ["Killed",FUNC(handleKilled)]; - player addEventHandler ["Respawn",FUNC(handleRespawn)]; - }; }] call EFUNC(common,addEventHandler); diff --git a/addons/spectator/XEH_preInit.sqf b/addons/spectator/XEH_preInit.sqf index 3b317ba904..73c629a0ce 100644 --- a/addons/spectator/XEH_preInit.sqf +++ b/addons/spectator/XEH_preInit.sqf @@ -2,15 +2,21 @@ ADDON = false; +PREP(bi_respawnBase); +PREP(bi_respawnCounter); +PREP(bi_respawnEndMission); +PREP(bi_respawnInstant); +PREP(bi_respawnNone); +PREP(bi_respawnSeagull); +PREP(bi_respawnSpectator); +PREP(bi_respawnWave); PREP(cacheUnitInfo); PREP(cycleCamera); PREP(handleCamera); PREP(handleCompass); PREP(handleIcons); PREP(handleInterface); -PREP(handleKilled); PREP(handleMouse); -PREP(handleRespawn); PREP(handleToolbar); PREP(handleUnits); PREP(moduleSpectatorSettings); @@ -38,7 +44,7 @@ GVAR(camUnit) = objNull; GVAR(camVision) = -2; GVAR(camZoom) = 1.25; -GVAR(open) = false; +GVAR(isSet) = false; GVAR(showComp) = true; GVAR(showHelp) = true; diff --git a/addons/spectator/config.cpp b/addons/spectator/config.cpp index e686c75294..eb73761e5f 100644 --- a/addons/spectator/config.cpp +++ b/addons/spectator/config.cpp @@ -16,3 +16,38 @@ class CfgPatches { #include "CfgEventHandlers.hpp" #include "CfgVehicles.hpp" #include "ui\interface.hpp" + +class CfgRespawnTemplates { + class None { + onPlayerKilled = QFUNC(bi_respawnNone); + }; + class Spectator { + onPlayerKilled = QFUNC(bi_respawnSpectator); + onPlayerRespawn = QFUNC(bi_respawnSpectator); + }; + class Instant { + onPlayerKilled = QFUNC(bi_respawnInstant); + onPlayerRespawn = QFUNC(bi_respawnInstant); + }; + class Base { + onPlayerKilled = QFUNC(bi_respawnBase); + onPlayerRespawn = QFUNC(bi_respawnBase); + }; + class EndMission + { + onPlayerKilled = QFUNC(bi_respawnEndMission); + onPlayerRespawn = QFUNC(bi_respawnEndMission); + }; + class Seagull { + onPlayerRespawn = QFUNC(bi_respawnSeagull); + }; + class Wave + { + onPlayerKilled = QFUNC(bi_respawnWave); + onPlayerRespawn = QFUNC(bi_respawnWave); + }; + class Counter { + onPlayerKilled = QFUNC(bi_respawnCounter); + onPlayerRespawn = QFUNC(bi_respawnCounter); + }; +}; diff --git a/addons/spectator/functions/fnc_bi_respawnBase.sqf b/addons/spectator/functions/fnc_bi_respawnBase.sqf new file mode 100644 index 0000000000..7ea5b0c745 --- /dev/null +++ b/addons/spectator/functions/fnc_bi_respawnBase.sqf @@ -0,0 +1,35 @@ +/* + * Author: Bohemia Interactive + * Part of the BI respawn framework + * Handles base respawn type (respawn on marker) + * Edited to support ace_spectator integration + * + * Arguments: + * 0: Corpse/New Unit + * 1: Killer/Old Unit + * 2: Respawn Type + * 3: Respawn Delay + * + * Return Value: + * None + * + * Public: No + */ + +#include "script_component.hpp" + +if !(GVAR(onDeath)) exitWith {}; + +params [["_unit",objNull,[objNull]], ["_killer",objNull,[objNull]]]; + +if (alive _unit) then { + [_unit,false] call FUNC(setSpectator); +} else { + private ["_vision","_pos"]; + if (isNull _killer) then {_killer = _unit}; + _vision = [-2,-1] select (sunOrMoon < 1); + _pos = (getPosATL _unit) vectorAdd [0,0,5]; + + [2,_killer,_vision,_pos,getDir _unit] call FUNC(setCameraAttributes); + [_unit] call FUNC(setSpectator); +}; diff --git a/addons/spectator/functions/fnc_bi_respawnCounter.sqf b/addons/spectator/functions/fnc_bi_respawnCounter.sqf new file mode 100644 index 0000000000..0bee90ec61 --- /dev/null +++ b/addons/spectator/functions/fnc_bi_respawnCounter.sqf @@ -0,0 +1,35 @@ +/* + * Author: Bohemia Interactive (Karel Moricky) + * Part of the BI respawn framework + * Handles the respawn timer display + * Edited to disable counter when spectator is opened + * + * Arguments: + * 0: Corpse/New Unit + * 1: Killer/Old Unit + * 2: Respawn Type + * 3: Respawn Delay + * + * Return Value: + * None + * + * Public: No + */ + +#include "script_component.hpp" + +_player = [_this,0,objNull,[objnull]] call bis_fnc_param; + +_respawnDelay = [_this,3,0,[0]] call bis_fnc_param; + +if (!isplayer _player && !isnull _player && _respawnDelay > 0) exitwith {["Attempting to use the function on AI unit %1, can be used only on players."] call bis_fnc_error;}; + +//--- Engine-triggered respawn +_layer = "BIS_fnc_respawnCounter" call bis_fnc_rscLayer; + +if (!alive _player) then { + if (GVAR(onDeath) || (playerrespawntime < 1)) exitwith {}; + _layer cutrsc ["RscRespawnCounter","plain"]; +} else { + _layer cuttext ["","plain"]; +}; diff --git a/addons/spectator/functions/fnc_bi_respawnEndMission.sqf b/addons/spectator/functions/fnc_bi_respawnEndMission.sqf new file mode 100644 index 0000000000..23b8dacc17 --- /dev/null +++ b/addons/spectator/functions/fnc_bi_respawnEndMission.sqf @@ -0,0 +1,62 @@ +/* + * Author: Bohemia Interactive (Karel Moricky) + * Part of the BI respawn framework + * Ends the mission when all players are dead + * Edited to support ace_spectator integration + * + * Arguments: + * 0: Corpse/New Unit + * 1: Killer/Old Unit + * 2: Respawn Type + * 3: Respawn Delay + * + * Return Value: + * None + * + * Public: No + */ + +#include "script_component.hpp" + +params [["_unit",objNull,[objNull]], ["_killer",objNull,[objNull]]]; +private ["_vision","_pos"]; + +if (isNull _killer) then {_killer = _unit}; +_vision = [-2,-1] select (sunOrMoon < 1); +_pos = (getPosATL _unit) vectorAdd [0,0,5]; + +if (ismultiplayer) then { + + _respawnType = 0 call bis_fnc_missionRespawnType; + if (_respawnType in [0,1,4,5]) then { + + //--- No more respawn slots + if ({isplayer _x && alive _x} count playableunits == 0) then { + [["endDeath",false],"bis_fnc_endmission"] call bis_fnc_mp; + } else { + if (GVAR(onDeath) && (_respawnType in [0,1])) then { + [2,_killer,_vision,_pos,getDir _unit] call FUNC(setCameraAttributes); + [_unit] call FUNC(setSpectator); + }; + }; + + //--- Don't end the script to prevent premature mission end + waituntil {false}; + } else { + + if (!alive _unit) then { + + //--- No more respawn tickets + if ([] call bis_fnc_respawntickets == 0 && {isplayer _x} count playableunits == 0) then { + [["endDeath",false],"bis_fnc_endmission"] call bis_fnc_mp; + } else { + if (GVAR(onDeath)) then { + [2,_killer,_vision,_pos,getDir _unit] call FUNC(setCameraAttributes); + [_unit] call FUNC(setSpectator); + }; + }; + } else { + [_unit,false] call FUNC(setSpectator); + }; + }; +}; diff --git a/addons/spectator/functions/fnc_bi_respawnInstant.sqf b/addons/spectator/functions/fnc_bi_respawnInstant.sqf new file mode 100644 index 0000000000..fd1d255cf9 --- /dev/null +++ b/addons/spectator/functions/fnc_bi_respawnInstant.sqf @@ -0,0 +1,35 @@ +/* + * Author: Bohemia Interactive + * Part of the BI respawn framework + * Handles instant respawn type (respawn at position of death) + * Edited to support ace_spectator integration + * + * Arguments: + * 0: Corpse/New Unit + * 1: Killer/Old Unit + * 2: Respawn Type + * 3: Respawn Delay + * + * Return Value: + * None + * + * Public: No + */ + +#include "script_component.hpp" + +if !(GVAR(onDeath)) exitWith {}; + +params [["_unit",objNull,[objNull]], ["_killer",objNull,[objNull]]]; + +if (alive _unit) then { + [_unit,false] call FUNC(setSpectator); +} else { + private ["_vision","_pos"]; + if (isNull _killer) then {_killer = _unit}; + _vision = [-2,-1] select (sunOrMoon < 1); + _pos = (getPosATL _unit) vectorAdd [0,0,5]; + + [2,_killer,_vision,_pos,getDir _unit] call FUNC(setCameraAttributes); + [_unit] call FUNC(setSpectator); +}; diff --git a/addons/spectator/functions/fnc_bi_respawnNone.sqf b/addons/spectator/functions/fnc_bi_respawnNone.sqf new file mode 100644 index 0000000000..a5031a8fd9 --- /dev/null +++ b/addons/spectator/functions/fnc_bi_respawnNone.sqf @@ -0,0 +1,293 @@ +/* + * Author: Bohemia Interactive (Karel Moricky) + * Part of the BI respawn framework + * Shows death screen for respawn type "None" + * Edited to support ace_spectator integration + * + * Arguments: + * 0: Corpse + * 1: Killer + * 2: Respawn Type + * 3: Respawn Delay + * + * Return Value: + * None + * + * Public: No + */ +private ["_soundvolume","_musicvolume"]; + +#define BI_CONTROL (_display displayctrl _n) + +#include "script_component.hpp" + +disableserialization; +_player = _this select 0; +_killer = _this select 1; +if (isnull _killer) then {_killer = _player}; + +_musicvolume = musicvolume; +_soundvolume = soundvolume; //MUF-TODO: check if this is done before sound is faded in fn_feedbackMain.fsm + +_start = isnil "bis_fnc_respawnNone_start"; +if (_start) then { + bis_fnc_respawnNone_start = [daytime,time / 3600]; + + //3.5 fadesound 0; //MUF-commented + + sleep 2; + if (alive player) exitwith {}; + cutText ["","BLACK OUT",1]; + sleep 1.5; + BIS_fnc_feedback_allowPP = false; //MUF-switch health PP off + //(["HealthPP_black"] call bis_fnc_rscLayer) cutText ["","BLACK IN",1];//MUF-black in (remove black screen that was launched in FSM PP) + + if (ismultiplayer) then { + if (GVAR(onDeath)) then { + private ["_vision","_pos"]; + _vision = [-2,-1] select (sunOrMoon < 1); + _pos = (getPosATL _player) vectorAdd [0,0,5]; + + [2,_killer,_vision,_pos,getDir _player] call FUNC(setCameraAttributes); + [_player] call FUNC(setSpectator); + } else { + (finddisplay 46) createdisplay "RscDisplayMissionEnd"; + }; + } else {enableenddialog}; +}; +if (alive player) exitwith { + [player,false] call FUNC(setSpectator); + cuttext ["","plain"]; +}; //--- Terminate when player manages to switch do different unit already + +if (GVAR(onDeath)) exitWith {}; + +waituntil {!isnull (finddisplay 58)}; +_display = finddisplay 58; + +//--- Black fade in +_n = 1060; +BI_CONTROL ctrlsetfade 1; +if (_start) then { + + //--- Play ambient radio + setacctime 1; + 0 fademusic 0; + 4 fademusic 0.8; + playmusic format ['RadioAmbient%1',ceil random 1/*30*/]; + _musicEH = addMusicEventHandler ["MusicStop",{[] spawn {playmusic format ['RadioAmbient%1',ceil random 1/*30*/];};}]; + uinamespace setvariable ["bis_fnc_respawnNone_musicEH",_musicEH]; + _display displayaddeventhandler ["unload","removeMusicEventHandler ['MusicStop',uinamespace getvariable ['bis_fnc_respawnNone_musicEH',-1]];"]; + + BI_CONTROL ctrlcommit 4; +} else { + BI_CONTROL ctrlcommit 0; +}; +cuttext ["","plain"]; + +//--- HUD +_n = 5800; +BI_CONTROL ctrlsettext gettext (configfile >> "cfgingameui" >> "cursor" >> "select"); +BI_CONTROL ctrlsetposition [-10,-10,safezoneH * 0.07 * 3/4,safezoneH * 0.07]; +BI_CONTROL ctrlsettextcolor [1,1,1,1]; +BI_CONTROL ctrlcommit 0; + +//--- SITREP (ToDO: Localize) +_sitrep = "SITREP||"; +if (name _player != "Error: No unit") then { + _sitrep = _sitrep + "KIA: %4. %5|"; +}; +_sitrep = _sitrep + "TOD: %2 [%3]|LOC: %6 \ %7"; +if (_killer != _player) then { + _sitrep = _sitrep + "||ENY: %8"; + if (currentweapon _killer != "") then { + _sitrep = _sitrep + "|ENW: %9" + }; +}; +_sitrep = format [ + _sitrep, + 1 * safezoneH, + [bis_fnc_respawnNone_start select 0,"HH:MM:SS"] call bis_fnc_timetostring, + [bis_fnc_respawnNone_start select 1,"HH:MM:SS"] call bis_fnc_timetostring, + toupper localize format ["STR_SHORT_%1",rank _player], + toupper name _player, + mapGridPosition _player, + toupper worldname, + toupper ((configfile >> "cfgvehicles" >> typeof _killer) call bis_fnc_displayname), + toupper ((configfile >> "cfgweapons" >> currentweapon _killer) call bis_fnc_displayname) + +]; + +_n = 11000; +_bcgPos = ctrlposition BI_CONTROL; +_n = 5858; +//BI_CONTROL ctrlsetposition [_bcgPos select 0,safezoneY + ((_bcgPos select 0) - safezoneX) * 4/3,safezoneW - 2 * (_bcgPos select 2),safezoneH / 2]; +BI_CONTROL ctrlsetposition [(((safezoneW / safezoneH) min 1.2) / 40) + (safezoneX), + ((((safezoneW / safezoneH) min 1.2) / 1.2) / 25) + (safezoneY), + safezoneW - 2 * (_bcgPos select 2), + safezoneH / 2]; +BI_CONTROL ctrlcommit 0; +[BI_CONTROL,_sitrep] spawn { + scriptname "bis_fnc_respawnNone: SITREP"; + disableserialization; + _control = _this select 0; + _sitrepArray = toarray (_this select 1); + {_sitrepArray set [_foreachindex,tostring [_x]]} foreach _sitrepArray; + _sitrep = ""; + //_sitrepFormat = "%1"; + _sitrepFormat = "%1"; + + sleep 1; + for "_i" from 0 to (count _sitrepArray - 1) do { + _letter = _sitrepArray select _i; + _delay = if (_letter == "|") then {_letter = "
"; 1} else {0.01}; + _sitrep = _sitrep + _letter; + _control ctrlsetstructuredtext parsetext format [_sitrepFormat,_sitrep + "_"]; + //playsound ["IncomingChallenge",true]; + sleep _delay; + if (isnull _control) exitwith {}; + }; + _control ctrlsetstructuredtext parsetext format [_sitrepFormat,_sitrep]; +}; + + +//--- Create UAV camera +_camera = "camera" camcreate position player; +_camera cameraeffect ["internal","back"]; +_camera campreparefov 0.4; +_camera campreparetarget _killer; +showcinemaborder false; + +//--- Set PP effects +_saturation = 0.0 + random 0.3; +_ppColor = ppEffectCreate ["ColorCorrections", 1999]; +_ppColor ppEffectEnable true; +_ppColor ppEffectAdjust [1, 1, 0, [1, 1, 1, 0], [1 - _saturation, 1 - _saturation, 1 - _saturation, _saturation], [1, 0.25, 0, 1.0]]; +_ppColor ppEffectCommit 0; + +_ppGrain = ppEffectCreate ["filmGrain", 2012]; +_ppGrain ppEffectEnable true; +_ppGrain ppEffectAdjust [random 0.2, 1, 1, 0, 1]; +_ppGrain ppEffectCommit 0; + +//--- Camera update executed every frame +bis_fnc_respawnNone_player = _player; +bis_fnc_respawnNone_killer = _killer; +bis_fnc_respawnNone_camera = _camera; +bis_fnc_respawnNone_loop = { + scriptname "bis_fnc_respawnNone: camera"; + _display = _this select 0; + _player = bis_fnc_respawnNone_player; + _killer = bis_fnc_respawnNone_killer; + _camera = bis_fnc_respawnNone_camera; + + _sin = 20 * sin (time * 7); + _killerPos = [ + (visiblepositionasl _killer select 0), + (visiblepositionasl _killer select 1) + (_sin), + (visiblepositionasl _killer select 2) + (_sin) + ]; + + _dirToKiller = if (_killer == _player) then { + direction _player; + } else { + ([_player,_killerPos] call bis_fnc_dirto) + _sin; + }; + _pos = [ + visiblepositionasl _player, + -20, + _dirToKiller + ] call bis_fnc_relpos; + _pos set [2,((_pos select 2) + 7) max (getterrainheightasl _pos + 7)]; + + //--- Pitch + _heightCamera = getterrainheightasl _pos; + _heightKiller = getterrainheightasl _killerPos; + _height = _heightCamera - _heightKiller; + _dis = _killerPos distance _pos; + _angle = (asin (_height/_dis)); + + _camera setdir _dirtokiller; + [_camera,-_angle,_sin] call bis_fnc_setpitchbank; + _camera setposasl _pos; + + //--- HUD + _n = 5800; + _hudPos = (worldtoscreen position _player); + if (count _hudPos > 0) then { + _hudPosW = ctrlposition BI_CONTROL select 2; + _hudPosH = ctrlposition BI_CONTROL select 3; + _hudPos = [ + (_hudPos select 0) - _hudPosW / 2, + (_hudPos select 1) - _hudPosH / 2, + _hudPosW, + _hudPosH + ]; + BI_CONTROL ctrlsetposition _hudPos; + BI_CONTROL ctrlcommit 0; + }; +}; + +bis_fnc_respawnNone_keydown = { + _key = _this select 1; + + if (_key in (actionkeys 'nightvision') || _key < 0) then { + bis_fnc_respawnNone_vision = bis_fnc_respawnNone_vision + 1; + _vision = bis_fnc_respawnNone_vision % 4; + switch (_vision) do { + case 0: { + camusenvg false; + call compile 'false SetCamUseTi 0'; + }; + case 1: { + camusenvg true; + call compile 'false SetCamUseTi 0'; + }; + case 2: { + camusenvg false; + call compile 'true SetCamUseTi 0'; + }; + case 3: { + camusenvg false; + call compile 'true SetCamUseTi 1'; + }; + }; + }; +}; +//bis_fnc_respawnNone_vision = (1 + floor random 3) % 4; //--- Random vision (not NVG) +bis_fnc_respawnNone_vision = -1; +if (sunormoon < 1) then {bis_fnc_respawnNone_vision = 0;}; +[-1,-1] call bis_fnc_respawnNone_keydown; + +_display displayaddeventhandler ["mousemoving","_this call bis_fnc_respawnNone_loop"]; +_display displayaddeventhandler ["mouseholding","_this call bis_fnc_respawnNone_loop"]; +_display displayaddeventhandler ["keydown","_this call bis_fnc_respawnNone_keydown"]; + + +//--- Team Switch display opened +waituntil {isnull _display}; +_displayTeamSwitch = finddisplay 632; + +//--- Team Switch display closed - cleanup and restart the view +waituntil {isnull _displayTeamSwitch}; + +_camera cameraeffect ["terminate","back"]; +camdestroy _camera; + +bis_fnc_respawnNone_player = nil; +bis_fnc_respawnNone_killer = nil; +bis_fnc_respawnNone_camera = nil; +bis_fnc_respawnNone_loop = nil; + +ppeffectdestroy _ppColor; +ppeffectdestroy _ppGrain; + +if (!alive player) exitwith {_this call bis_fnc_respawnNone;}; + + +//--- Resurrection! +BIS_fnc_feedback_allowPP = true; +0 fadesound _soundvolume; +0 fademusic _musicvolume; +playmusic ""; +bis_fnc_respawnNone_start = nil; diff --git a/addons/spectator/functions/fnc_bi_respawnSeagull.sqf b/addons/spectator/functions/fnc_bi_respawnSeagull.sqf new file mode 100644 index 0000000000..2e01ffa6ea --- /dev/null +++ b/addons/spectator/functions/fnc_bi_respawnSeagull.sqf @@ -0,0 +1,101 @@ +/* + * Author: Bohemia Interactive + * Part of the BI respawn framework + * Correctly handles seagull respawn (not used by default) + * Edited to support ace_spectator integration + * + * Arguments: + * 0: Corpse/New Unit + * 1: Killer/Old Unit + * 2: Respawn Type + * 3: Respawn Delay + * + * Return Value: + * None + * + * Public: No + */ + +#include "script_component.hpp" + +_seagull = _this select 0; +_player = _this select 1; +_this call bis_fnc_log; + +if (!isplayer _player && !isplayer _seagull) exitwith {["Attempting to use the function on AI unit %1, can be used only on players."] call bis_fnc_error;}; + +waituntil {missionnamespace getvariable ["BIS_fnc_feedback_allowDeathScreen",true]}; +BIS_fnc_feedback_allowPP = false; +//(["HealthPP_black"] call bis_fnc_rscLayer) cutText ["","BLACK IN",8]; + +if (GVAR(onDeath)) exitWith { + private ["_vision","_pos"]; + + if (isNull _player) then {_player = _seagull}; + _vision = [-2,-1] select (sunOrMoon < 1); + _pos = (getPosATL _player) vectorAdd [0,0,5]; + + [_seagull,QGVAR(isSeagull)] call EFUNC(common,hideUnit); + [2,_player,_vision,_pos,getDir _seagull] call FUNC(setCameraAttributes); + [_seagull] call FUNC(setSpectator); +}; + +_camera = "camera" camCreate [(position _player select 0)-0.75, (position _player select 1)-0.75,(position _player select 2) + 0.5]; +_camera cameraEffect ["internal","back"]; +_camera camSetFOV 0.800; +_camera camCommit 0; +waituntil {camCommitted _camera}; + +0 fadeMusic 0.5; +playMusic "Track06_Abandoned_Battlespace"; + +_camera camSetTarget vehicle _player; +_camera camSetRelPos [-0.82,-3.12,3.38]; +_camera camSetFOV 0.800; +_camera camCommit 7; + +sleep 1; +_preload = _player spawn {waitUntil {(preloadCamera getPos _this) && (2 preloadObject _this)}}; +sleep 5; +waituntil {camCommitted _camera}; + +_camera camSetRelPos [1.17,-21.71,2.07]; +_camera camSetFOV 0.400; +_camera camCommit 10; +sleep 2; +terminate _preload; +sleep 3; +_preload = _player spawn {waitUntil {(preloadCamera getPos _this) && (3 preloadObject _this)}}; +waituntil {camCommitted _camera}; + +_camera camSetTarget vehicle _player; +_camera camSetRelPos [5.80,1.29,5.07]; +_camera camSetFOV 0.300; +_camera camCommit 7; +sleep 2; +terminate _preload; +_preload = _seagull spawn {waitUntil {(preloadCamera getPos _this) && (4 preloadObject _this)}}; +waituntil {camCommitted _camera}; + +_camera camSetRelPos [2.71,19.55,12.94]; +_camera camSetFOV 0.700; +_camera camCommit 2; +waituntil {camCommitted _camera}; + +_camera camSetTarget _seagull; +_camera camSetRelPos [-6.66,18.99,2.59]; +_camera camSetFOV 0.700; +_camera camCommit 3; +waituntil {camCommitted _camera}; + +3 fadeMusic 0; + +_camera camSetRelPos [1.17,-21.71,-1.07]; +_camera camSetFOV 0.300; +_camera camCommit 3; +waituntil {camCommitted _camera}; +terminate _preload; + +_seagull switchCamera "EXTERNAL"; +_seagull cameraEffect ["terminate","back"]; +camDestroy _camera; diff --git a/addons/spectator/functions/fnc_bi_respawnSpectator.sqf b/addons/spectator/functions/fnc_bi_respawnSpectator.sqf new file mode 100644 index 0000000000..5097b61ab2 --- /dev/null +++ b/addons/spectator/functions/fnc_bi_respawnSpectator.sqf @@ -0,0 +1,59 @@ +/* + * Author: Bohemia Interactive + * Part of the BI respawn framework + * Opens BI spectator interface (default used by seagull respawn) + * Edited to support ace_spectator integration + * + * Arguments: + * 0: Corpse/New Unit + * 1: Killer/Old Unit + * 2: Respawn Type + * 3: Respawn Delay + * + * Return Value: + * None + * + * Public: No + */ + +#include "script_component.hpp" + +params [["_unit",objNull,[objNull]], ["_killer",objNull,[objNull]], ["_respawn",-1,[0]]]; +private ["_vision","_pos"]; + +if (isNull _killer) then {_killer = _unit}; +_vision = [-2,-1] select (sunOrMoon < 1); +_pos = (getPosATL _unit) vectorAdd [0,0,5]; + +_layer = "BIS_fnc_respawnSpectator" call bis_fnc_rscLayer; + +if (!alive _unit) then { + if (GVAR(onDeath)) then { + [2,_killer,_vision,_pos,getDir _unit] call FUNC(setCameraAttributes); + [_unit] call FUNC(setSpectator); + } else { + _layer cutrsc ["RscSpectator","plain"]; + }; +} else { + if (_respawn == 1) then { + + //--- Open + waituntil {missionnamespace getvariable ["BIS_fnc_feedback_allowDeathScreen",true]}; + BIS_fnc_feedback_allowPP = false; + //(["HealthPP_black"] call bis_fnc_rscLayer) cutText ["","BLACK IN",1]; + if (GVAR(onDeath)) then { + [_unit,QGVAR(isSeagull)] call EFUNC(common,hideUnit); + [2,_killer,_vision,_pos,getDir _unit] call FUNC(setCameraAttributes); + [_unit] call FUNC(setSpectator); + } else { + _layer cutrsc ["RscSpectator","plain"]; + }; + } else { + if (GVAR(onDeath)) then { + [_unit,false] call FUNC(setSpectator); + }; + + //--- Close + _layer cuttext ["","plain"]; + }; +}; diff --git a/addons/spectator/functions/fnc_bi_respawnWave.sqf b/addons/spectator/functions/fnc_bi_respawnWave.sqf new file mode 100644 index 0000000000..371a8edcdc --- /dev/null +++ b/addons/spectator/functions/fnc_bi_respawnWave.sqf @@ -0,0 +1,43 @@ +/* + * Author: Bohemia Interactive + * Part of the BI respawn framework + * Handles wave respawning system + * Edited to support ace_spectator integration + * + * Arguments: + * 0: Corpse/New Unit + * 1: Killer/Old Unit + * 2: Respawn Type + * 3: Respawn Delay + * + * Return Value: + * None + * + * Public: No + */ + +#include "script_component.hpp" + +params [["_unit",objNull,[objNull]], ["_killer",objNull,[objNull]], ["_respawn",0,[0]], ["_respawnDelay",0,[0]]]; + +if (!isplayer _unit && !isnull _unit) exitwith {["Attempting to use the function on AI unit %1, can be used only on players."] call bis_fnc_error;}; + +if (!alive _unit) then { + //--- Set the time only when it was not modified already + if (_respawnDelay != 0 && _respawnDelay == playerrespawntime) then { + setplayerrespawntime (_respawnDelay + _respawnDelay - (servertime % _respawnDelay)); + + if !(GVAR(onDeath)) exitWith {}; + private ["_vision","_pos"]; + + if (isNull _killer) then {_killer = _unit}; + _vision = [-2,-1] select (sunOrMoon < 1); + _pos = (getPosATL _unit) vectorAdd [0,0,5]; + + [2,_killer,_vision,_pos,getDir _unit] call FUNC(setCameraAttributes); + [_unit] call FUNC(setSpectator); + }; +} else { + setplayerrespawntime _respawndelay; + [_unit,false] call FUNC(setSpectator); +}; diff --git a/addons/spectator/functions/fnc_handleInterface.sqf b/addons/spectator/functions/fnc_handleInterface.sqf index 315398ab0c..5c8c958451 100644 --- a/addons/spectator/functions/fnc_handleInterface.sqf +++ b/addons/spectator/functions/fnc_handleInterface.sqf @@ -23,8 +23,7 @@ switch (toLower _mode) do { // Safely open/close the interface case "open": { // Prevent reopening - if (GVAR(open)) exitWith {}; - GVAR(open) = true; + if (GVAR(isSet)) exitWith {}; // Initalize camera variables GVAR(camBoom) = 0; @@ -37,15 +36,17 @@ switch (toLower _mode) do { GVAR(mouse) = [false,false]; GVAR(mousePos) = [0.5,0.5]; - // Camera starts with night vision if it's dark - if (sunOrMoon < 1) then { - [nil,nil,-1] call FUNC(setCameraAttributes); - }; - // Initalize the camera view GVAR(camera) = "Camera" camCreate (ASLtoATL GVAR(camPos)); [] call FUNC(transitionCamera); + // Close map + openMap [false,false]; + + // Close any BI layers/effects + BIS_fnc_feedback_allowPP = false; + ("BIS_fnc_respawnCounter" call BIS_fnc_rscLayer) cutText ["","plain"]; + // Close all existing dialogs while {dialog} do { closeDialog 0; @@ -65,8 +66,7 @@ switch (toLower _mode) do { _args params ["_unit"]; // Can't close a second time - if !(GVAR(open)) exitWith {}; - GVAR(open) = false; + if !(GVAR(isSet)) exitWith {}; // Terminate interface while {dialog} do { @@ -80,6 +80,10 @@ switch (toLower _mode) do { // Return to player view _unit switchCamera "internal"; + // Re-enable any BI effects + BIS_fnc_feedback_allowPP = true; + BIS_fnc_respawnNone_start = nil; + // Cleanup camera variables GVAR(camera) = nil; GVAR(camBoom) = nil; diff --git a/addons/spectator/functions/fnc_handleKilled.sqf b/addons/spectator/functions/fnc_handleKilled.sqf deleted file mode 100644 index 05671ed749..0000000000 --- a/addons/spectator/functions/fnc_handleKilled.sqf +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Author: SilentSpike - * Set inital camera attributes and set as spectator on death - * Part of the spectator during death system - * - * Arguments: - * 0: Corpse - * 1: Killer - * - * Return Value: - * None - * - * Public: No - */ - -#include "script_component.hpp" - -params ["_unit","_killer"]; - -if (isNull _killer) then { - [2,_unit] call FUNC(setCameraAttributes); -} else { - [2,_killer] call FUNC(setCameraAttributes); -}; - -[_unit] call FUNC(setSpectator); diff --git a/addons/spectator/functions/fnc_handleRespawn.sqf b/addons/spectator/functions/fnc_handleRespawn.sqf deleted file mode 100644 index aa695dd553..0000000000 --- a/addons/spectator/functions/fnc_handleRespawn.sqf +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Author: SilentSpike - * Un-set as spectator on respawn - * Part of the spectator during death system - * - * Arguments: - * 0: New unit - * 1: Old unit - * - * Return Value: - * None - * - * Public: No - */ - -#include "script_component.hpp" - -params ["_unit","_oldUnit"]; - -[_unit,false] call FUNC(setSpectator); diff --git a/addons/spectator/functions/fnc_setCameraAttributes.sqf b/addons/spectator/functions/fnc_setCameraAttributes.sqf index da2373318d..278a8c4758 100644 --- a/addons/spectator/functions/fnc_setCameraAttributes.sqf +++ b/addons/spectator/functions/fnc_setCameraAttributes.sqf @@ -51,7 +51,7 @@ if !(_vision in GVAR(availableVisions)) then { }; GVAR(camPan) = _heading % 360; -GVAR(camPosition) = (ATLtoASL _position); +GVAR(camPos) = (ATLtoASL _position); GVAR(camSpeed) = (_speed max 0.05) min 10; GVAR(camTilt) = (_tilt max -89) min 89; GVAR(camUnit) = _unit; diff --git a/addons/spectator/functions/fnc_setSpectator.sqf b/addons/spectator/functions/fnc_setSpectator.sqf index b6e85926c5..2d5ada415c 100644 --- a/addons/spectator/functions/fnc_setSpectator.sqf +++ b/addons/spectator/functions/fnc_setSpectator.sqf @@ -1,9 +1,9 @@ /* * Author: SilentSpike - * Sets target unit to the given spectator state (virtually) + * Sets target player to the given spectator state (virtually) * To physically handle a spectator see ace_spectator_fnc_stageSpectator * - * Units will be able to communicate in ACRE/TFAR as appropriate + * Player will be able to communicate in ACRE/TFAR as appropriate * The spectator interface will be opened/closed * * Arguments: @@ -23,20 +23,11 @@ params ["_unit", ["_set",true,[true]]]; -// No change, no service (but allow spectators to be reset) -if !(_set || (GETVAR(_unit,GVAR(isSet),false))) exitWith {}; - // Only run for player units if !(isPlayer _unit) exitWith {}; if !(local _unit) exitwith { - [[_unit, _set, _target], QFUNC(setSpectator), _unit] call EFUNC(common,execRemoteFnc); -}; - -if (_set) then { - ["open"] call FUNC(handleInterface); -} else { - ["close",_unit] call FUNC(handleInterface); + [[_unit, _set], QFUNC(setSpectator), _unit] call EFUNC(common,execRemoteFnc); }; // Handle common addon audio @@ -44,10 +35,14 @@ if (["ace_hearing"] call EFUNC(common,isModLoaded)) then {EGVAR(hearing,disableV if (["acre_sys_radio"] call EFUNC(common,isModLoaded)) then {[_set] call acre_api_fnc_setSpectator}; if (["task_force_radio"] call EFUNC(common,isModLoaded)) then {[_unit, _set] call TFAR_fnc_forceSpectator}; -// No theoretical change if an existing spectator was reset -if !(_set isEqualTo (GETVAR(_unit,GVAR(isSet),false))) then { - // Mark spectator state for reference - _unit setVariable [QGVAR(isSet), _set, true]; - - ["spectatorSet",[_set]] call EFUNC(common,localEvent); +if (_set) then { + ["open"] call FUNC(handleInterface); +} else { + ["close",_unit] call FUNC(handleInterface); }; + +// Mark spectator state for reference +_unit setVariable [QGVAR(isSet), _set, true]; +GVAR(isSet) = _set; + +["spectatorSet",[_set,_unit]] call EFUNC(common,localEvent); diff --git a/addons/spectator/functions/fnc_stageSpectator.sqf b/addons/spectator/functions/fnc_stageSpectator.sqf index bac5174601..3e17235e3e 100644 --- a/addons/spectator/functions/fnc_stageSpectator.sqf +++ b/addons/spectator/functions/fnc_stageSpectator.sqf @@ -30,7 +30,7 @@ if !(_set || (GETVAR(_unit,GVAR(isStaged),false))) exitWith {}; if !(isPlayer _unit) exitWith {}; if !(local _unit) exitwith { - [[_unit, _set, _target], QFUNC(stageSpectator), _unit] call EFUNC(common,execRemoteFnc); + [[_unit, _set], QFUNC(stageSpectator), _unit] call EFUNC(common,execRemoteFnc); }; // Prevent player falling into water @@ -49,7 +49,7 @@ if (_set) then { [_unit, QGVAR(isStaged)] call EFUNC(common,hideUnit); [_unit, QGVAR(isStaged)] call EFUNC(common,muteUnit); - _unit setPos (getMarkerPos QGVAR(respawn)); + _unit setPos (markerPos QGVAR(respawn)); } else { // Physical beings can talk [_unit, QGVAR(isStaged)] call EFUNC(common,unhideUnit); From 1b12d3728437a948d4e6779f724f7a6387e50396 Mon Sep 17 00:00:00 2001 From: SilentSpike Date: Tue, 4 Aug 2015 22:11:34 +0100 Subject: [PATCH 12/91] Replace spectator respawn changes with a template Hacking the BI respawn framework to support a spectator setting was intrusive and limiting. Instead of using a setting, I've opted to introduce a new respawn template that can be used within BI's respawn framework. The benefits of this approach are: - Compatibility isn't a concern, that responsibility is shifted onto mission designers. - Mission designers can use the functionality of the BI framework alongside the spectator system (combining templates, using different templates for different sides, etc.). - If a custom respawn framework is used, then this doesn't change anything. Custom frameworks are still fully supported via the public functions provided. - Remains simple to set up, just requires a description.ext edit --- addons/spectator/ACE_Settings.hpp | 4 - addons/spectator/CfgVehicles.hpp | 6 - addons/spectator/XEH_preInit.sqf | 10 +- addons/spectator/config.cpp | 34 +- .../functions/fnc_bi_respawnBase.sqf | 35 --- .../functions/fnc_bi_respawnCounter.sqf | 35 --- .../functions/fnc_bi_respawnEndMission.sqf | 62 ---- .../functions/fnc_bi_respawnInstant.sqf | 35 --- .../functions/fnc_bi_respawnNone.sqf | 293 ------------------ .../functions/fnc_bi_respawnSeagull.sqf | 101 ------ .../functions/fnc_bi_respawnSpectator.sqf | 59 ---- .../functions/fnc_bi_respawnWave.sqf | 43 --- .../functions/fnc_handleInterface.sqf | 5 +- .../functions/fnc_moduleSpectatorSettings.sqf | 1 - .../functions/fnc_respawnTemplate.sqf | 39 +++ .../functions/fnc_transitionCamera.sqf | 8 +- addons/spectator/stringtable.xml | 8 - 17 files changed, 52 insertions(+), 726 deletions(-) delete mode 100644 addons/spectator/functions/fnc_bi_respawnBase.sqf delete mode 100644 addons/spectator/functions/fnc_bi_respawnCounter.sqf delete mode 100644 addons/spectator/functions/fnc_bi_respawnEndMission.sqf delete mode 100644 addons/spectator/functions/fnc_bi_respawnInstant.sqf delete mode 100644 addons/spectator/functions/fnc_bi_respawnNone.sqf delete mode 100644 addons/spectator/functions/fnc_bi_respawnSeagull.sqf delete mode 100644 addons/spectator/functions/fnc_bi_respawnSpectator.sqf delete mode 100644 addons/spectator/functions/fnc_bi_respawnWave.sqf create mode 100644 addons/spectator/functions/fnc_respawnTemplate.sqf diff --git a/addons/spectator/ACE_Settings.hpp b/addons/spectator/ACE_Settings.hpp index 5e7907d19f..539f7cef2d 100644 --- a/addons/spectator/ACE_Settings.hpp +++ b/addons/spectator/ACE_Settings.hpp @@ -1,8 +1,4 @@ class ACE_Settings { - class GVAR(onDeath) { - typeName = "BOOL"; - value = 0; - }; class GVAR(filterUnits) { typeName = "SCALAR"; value = 1; diff --git a/addons/spectator/CfgVehicles.hpp b/addons/spectator/CfgVehicles.hpp index 7067257f23..8e685dae07 100644 --- a/addons/spectator/CfgVehicles.hpp +++ b/addons/spectator/CfgVehicles.hpp @@ -9,12 +9,6 @@ class CfgVehicles { isGlobal = 1; author = ECSTRING(common,ACETeam); class Arguments { - class systemEnable { - displayName = CSTRING(system_DisplayName); - description = CSTRING(system_Description); - typeName = "BOOL"; - defaultValue = 0; - }; class unitsFilter { displayName = CSTRING(units_DisplayName); description = CSTRING(units_Description); diff --git a/addons/spectator/XEH_preInit.sqf b/addons/spectator/XEH_preInit.sqf index 73c629a0ce..95c18f4a54 100644 --- a/addons/spectator/XEH_preInit.sqf +++ b/addons/spectator/XEH_preInit.sqf @@ -2,14 +2,6 @@ ADDON = false; -PREP(bi_respawnBase); -PREP(bi_respawnCounter); -PREP(bi_respawnEndMission); -PREP(bi_respawnInstant); -PREP(bi_respawnNone); -PREP(bi_respawnSeagull); -PREP(bi_respawnSpectator); -PREP(bi_respawnWave); PREP(cacheUnitInfo); PREP(cycleCamera); PREP(handleCamera); @@ -20,6 +12,7 @@ PREP(handleMouse); PREP(handleToolbar); PREP(handleUnits); PREP(moduleSpectatorSettings); +PREP(respawnTemplate); PREP(setCameraAttributes); PREP(setSpectator); PREP(stageSpectator); @@ -35,6 +28,7 @@ GVAR(availableModes) = [0,1,2]; GVAR(availableSides) = [west,east,resistance,civilian]; GVAR(availableVisions) = [-2,-1,0,1]; +GVAR(camAgent) = objNull; GVAR(camMode) = 0; GVAR(camPan) = 0; GVAR(camPos) = ATLtoASL [worldSize * 0.5, worldSize * 0.5, 20]; diff --git a/addons/spectator/config.cpp b/addons/spectator/config.cpp index eb73761e5f..6e32ed0413 100644 --- a/addons/spectator/config.cpp +++ b/addons/spectator/config.cpp @@ -18,36 +18,8 @@ class CfgPatches { #include "ui\interface.hpp" class CfgRespawnTemplates { - class None { - onPlayerKilled = QFUNC(bi_respawnNone); - }; - class Spectator { - onPlayerKilled = QFUNC(bi_respawnSpectator); - onPlayerRespawn = QFUNC(bi_respawnSpectator); - }; - class Instant { - onPlayerKilled = QFUNC(bi_respawnInstant); - onPlayerRespawn = QFUNC(bi_respawnInstant); - }; - class Base { - onPlayerKilled = QFUNC(bi_respawnBase); - onPlayerRespawn = QFUNC(bi_respawnBase); - }; - class EndMission - { - onPlayerKilled = QFUNC(bi_respawnEndMission); - onPlayerRespawn = QFUNC(bi_respawnEndMission); - }; - class Seagull { - onPlayerRespawn = QFUNC(bi_respawnSeagull); - }; - class Wave - { - onPlayerKilled = QFUNC(bi_respawnWave); - onPlayerRespawn = QFUNC(bi_respawnWave); - }; - class Counter { - onPlayerKilled = QFUNC(bi_respawnCounter); - onPlayerRespawn = QFUNC(bi_respawnCounter); + class ADDON { + onPlayerKilled = QFUNC(respawnTemplate); + onPlayerRespawn = QFUNC(respawnTemplate); }; }; diff --git a/addons/spectator/functions/fnc_bi_respawnBase.sqf b/addons/spectator/functions/fnc_bi_respawnBase.sqf deleted file mode 100644 index 7ea5b0c745..0000000000 --- a/addons/spectator/functions/fnc_bi_respawnBase.sqf +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Author: Bohemia Interactive - * Part of the BI respawn framework - * Handles base respawn type (respawn on marker) - * Edited to support ace_spectator integration - * - * Arguments: - * 0: Corpse/New Unit - * 1: Killer/Old Unit - * 2: Respawn Type - * 3: Respawn Delay - * - * Return Value: - * None - * - * Public: No - */ - -#include "script_component.hpp" - -if !(GVAR(onDeath)) exitWith {}; - -params [["_unit",objNull,[objNull]], ["_killer",objNull,[objNull]]]; - -if (alive _unit) then { - [_unit,false] call FUNC(setSpectator); -} else { - private ["_vision","_pos"]; - if (isNull _killer) then {_killer = _unit}; - _vision = [-2,-1] select (sunOrMoon < 1); - _pos = (getPosATL _unit) vectorAdd [0,0,5]; - - [2,_killer,_vision,_pos,getDir _unit] call FUNC(setCameraAttributes); - [_unit] call FUNC(setSpectator); -}; diff --git a/addons/spectator/functions/fnc_bi_respawnCounter.sqf b/addons/spectator/functions/fnc_bi_respawnCounter.sqf deleted file mode 100644 index 0bee90ec61..0000000000 --- a/addons/spectator/functions/fnc_bi_respawnCounter.sqf +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Author: Bohemia Interactive (Karel Moricky) - * Part of the BI respawn framework - * Handles the respawn timer display - * Edited to disable counter when spectator is opened - * - * Arguments: - * 0: Corpse/New Unit - * 1: Killer/Old Unit - * 2: Respawn Type - * 3: Respawn Delay - * - * Return Value: - * None - * - * Public: No - */ - -#include "script_component.hpp" - -_player = [_this,0,objNull,[objnull]] call bis_fnc_param; - -_respawnDelay = [_this,3,0,[0]] call bis_fnc_param; - -if (!isplayer _player && !isnull _player && _respawnDelay > 0) exitwith {["Attempting to use the function on AI unit %1, can be used only on players."] call bis_fnc_error;}; - -//--- Engine-triggered respawn -_layer = "BIS_fnc_respawnCounter" call bis_fnc_rscLayer; - -if (!alive _player) then { - if (GVAR(onDeath) || (playerrespawntime < 1)) exitwith {}; - _layer cutrsc ["RscRespawnCounter","plain"]; -} else { - _layer cuttext ["","plain"]; -}; diff --git a/addons/spectator/functions/fnc_bi_respawnEndMission.sqf b/addons/spectator/functions/fnc_bi_respawnEndMission.sqf deleted file mode 100644 index 23b8dacc17..0000000000 --- a/addons/spectator/functions/fnc_bi_respawnEndMission.sqf +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Author: Bohemia Interactive (Karel Moricky) - * Part of the BI respawn framework - * Ends the mission when all players are dead - * Edited to support ace_spectator integration - * - * Arguments: - * 0: Corpse/New Unit - * 1: Killer/Old Unit - * 2: Respawn Type - * 3: Respawn Delay - * - * Return Value: - * None - * - * Public: No - */ - -#include "script_component.hpp" - -params [["_unit",objNull,[objNull]], ["_killer",objNull,[objNull]]]; -private ["_vision","_pos"]; - -if (isNull _killer) then {_killer = _unit}; -_vision = [-2,-1] select (sunOrMoon < 1); -_pos = (getPosATL _unit) vectorAdd [0,0,5]; - -if (ismultiplayer) then { - - _respawnType = 0 call bis_fnc_missionRespawnType; - if (_respawnType in [0,1,4,5]) then { - - //--- No more respawn slots - if ({isplayer _x && alive _x} count playableunits == 0) then { - [["endDeath",false],"bis_fnc_endmission"] call bis_fnc_mp; - } else { - if (GVAR(onDeath) && (_respawnType in [0,1])) then { - [2,_killer,_vision,_pos,getDir _unit] call FUNC(setCameraAttributes); - [_unit] call FUNC(setSpectator); - }; - }; - - //--- Don't end the script to prevent premature mission end - waituntil {false}; - } else { - - if (!alive _unit) then { - - //--- No more respawn tickets - if ([] call bis_fnc_respawntickets == 0 && {isplayer _x} count playableunits == 0) then { - [["endDeath",false],"bis_fnc_endmission"] call bis_fnc_mp; - } else { - if (GVAR(onDeath)) then { - [2,_killer,_vision,_pos,getDir _unit] call FUNC(setCameraAttributes); - [_unit] call FUNC(setSpectator); - }; - }; - } else { - [_unit,false] call FUNC(setSpectator); - }; - }; -}; diff --git a/addons/spectator/functions/fnc_bi_respawnInstant.sqf b/addons/spectator/functions/fnc_bi_respawnInstant.sqf deleted file mode 100644 index fd1d255cf9..0000000000 --- a/addons/spectator/functions/fnc_bi_respawnInstant.sqf +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Author: Bohemia Interactive - * Part of the BI respawn framework - * Handles instant respawn type (respawn at position of death) - * Edited to support ace_spectator integration - * - * Arguments: - * 0: Corpse/New Unit - * 1: Killer/Old Unit - * 2: Respawn Type - * 3: Respawn Delay - * - * Return Value: - * None - * - * Public: No - */ - -#include "script_component.hpp" - -if !(GVAR(onDeath)) exitWith {}; - -params [["_unit",objNull,[objNull]], ["_killer",objNull,[objNull]]]; - -if (alive _unit) then { - [_unit,false] call FUNC(setSpectator); -} else { - private ["_vision","_pos"]; - if (isNull _killer) then {_killer = _unit}; - _vision = [-2,-1] select (sunOrMoon < 1); - _pos = (getPosATL _unit) vectorAdd [0,0,5]; - - [2,_killer,_vision,_pos,getDir _unit] call FUNC(setCameraAttributes); - [_unit] call FUNC(setSpectator); -}; diff --git a/addons/spectator/functions/fnc_bi_respawnNone.sqf b/addons/spectator/functions/fnc_bi_respawnNone.sqf deleted file mode 100644 index a5031a8fd9..0000000000 --- a/addons/spectator/functions/fnc_bi_respawnNone.sqf +++ /dev/null @@ -1,293 +0,0 @@ -/* - * Author: Bohemia Interactive (Karel Moricky) - * Part of the BI respawn framework - * Shows death screen for respawn type "None" - * Edited to support ace_spectator integration - * - * Arguments: - * 0: Corpse - * 1: Killer - * 2: Respawn Type - * 3: Respawn Delay - * - * Return Value: - * None - * - * Public: No - */ -private ["_soundvolume","_musicvolume"]; - -#define BI_CONTROL (_display displayctrl _n) - -#include "script_component.hpp" - -disableserialization; -_player = _this select 0; -_killer = _this select 1; -if (isnull _killer) then {_killer = _player}; - -_musicvolume = musicvolume; -_soundvolume = soundvolume; //MUF-TODO: check if this is done before sound is faded in fn_feedbackMain.fsm - -_start = isnil "bis_fnc_respawnNone_start"; -if (_start) then { - bis_fnc_respawnNone_start = [daytime,time / 3600]; - - //3.5 fadesound 0; //MUF-commented - - sleep 2; - if (alive player) exitwith {}; - cutText ["","BLACK OUT",1]; - sleep 1.5; - BIS_fnc_feedback_allowPP = false; //MUF-switch health PP off - //(["HealthPP_black"] call bis_fnc_rscLayer) cutText ["","BLACK IN",1];//MUF-black in (remove black screen that was launched in FSM PP) - - if (ismultiplayer) then { - if (GVAR(onDeath)) then { - private ["_vision","_pos"]; - _vision = [-2,-1] select (sunOrMoon < 1); - _pos = (getPosATL _player) vectorAdd [0,0,5]; - - [2,_killer,_vision,_pos,getDir _player] call FUNC(setCameraAttributes); - [_player] call FUNC(setSpectator); - } else { - (finddisplay 46) createdisplay "RscDisplayMissionEnd"; - }; - } else {enableenddialog}; -}; -if (alive player) exitwith { - [player,false] call FUNC(setSpectator); - cuttext ["","plain"]; -}; //--- Terminate when player manages to switch do different unit already - -if (GVAR(onDeath)) exitWith {}; - -waituntil {!isnull (finddisplay 58)}; -_display = finddisplay 58; - -//--- Black fade in -_n = 1060; -BI_CONTROL ctrlsetfade 1; -if (_start) then { - - //--- Play ambient radio - setacctime 1; - 0 fademusic 0; - 4 fademusic 0.8; - playmusic format ['RadioAmbient%1',ceil random 1/*30*/]; - _musicEH = addMusicEventHandler ["MusicStop",{[] spawn {playmusic format ['RadioAmbient%1',ceil random 1/*30*/];};}]; - uinamespace setvariable ["bis_fnc_respawnNone_musicEH",_musicEH]; - _display displayaddeventhandler ["unload","removeMusicEventHandler ['MusicStop',uinamespace getvariable ['bis_fnc_respawnNone_musicEH',-1]];"]; - - BI_CONTROL ctrlcommit 4; -} else { - BI_CONTROL ctrlcommit 0; -}; -cuttext ["","plain"]; - -//--- HUD -_n = 5800; -BI_CONTROL ctrlsettext gettext (configfile >> "cfgingameui" >> "cursor" >> "select"); -BI_CONTROL ctrlsetposition [-10,-10,safezoneH * 0.07 * 3/4,safezoneH * 0.07]; -BI_CONTROL ctrlsettextcolor [1,1,1,1]; -BI_CONTROL ctrlcommit 0; - -//--- SITREP (ToDO: Localize) -_sitrep = "SITREP||"; -if (name _player != "Error: No unit") then { - _sitrep = _sitrep + "KIA: %4. %5|"; -}; -_sitrep = _sitrep + "TOD: %2 [%3]|LOC: %6 \ %7"; -if (_killer != _player) then { - _sitrep = _sitrep + "||ENY: %8"; - if (currentweapon _killer != "") then { - _sitrep = _sitrep + "|ENW: %9" - }; -}; -_sitrep = format [ - _sitrep, - 1 * safezoneH, - [bis_fnc_respawnNone_start select 0,"HH:MM:SS"] call bis_fnc_timetostring, - [bis_fnc_respawnNone_start select 1,"HH:MM:SS"] call bis_fnc_timetostring, - toupper localize format ["STR_SHORT_%1",rank _player], - toupper name _player, - mapGridPosition _player, - toupper worldname, - toupper ((configfile >> "cfgvehicles" >> typeof _killer) call bis_fnc_displayname), - toupper ((configfile >> "cfgweapons" >> currentweapon _killer) call bis_fnc_displayname) - -]; - -_n = 11000; -_bcgPos = ctrlposition BI_CONTROL; -_n = 5858; -//BI_CONTROL ctrlsetposition [_bcgPos select 0,safezoneY + ((_bcgPos select 0) - safezoneX) * 4/3,safezoneW - 2 * (_bcgPos select 2),safezoneH / 2]; -BI_CONTROL ctrlsetposition [(((safezoneW / safezoneH) min 1.2) / 40) + (safezoneX), - ((((safezoneW / safezoneH) min 1.2) / 1.2) / 25) + (safezoneY), - safezoneW - 2 * (_bcgPos select 2), - safezoneH / 2]; -BI_CONTROL ctrlcommit 0; -[BI_CONTROL,_sitrep] spawn { - scriptname "bis_fnc_respawnNone: SITREP"; - disableserialization; - _control = _this select 0; - _sitrepArray = toarray (_this select 1); - {_sitrepArray set [_foreachindex,tostring [_x]]} foreach _sitrepArray; - _sitrep = ""; - //_sitrepFormat = "%1"; - _sitrepFormat = "%1"; - - sleep 1; - for "_i" from 0 to (count _sitrepArray - 1) do { - _letter = _sitrepArray select _i; - _delay = if (_letter == "|") then {_letter = "
"; 1} else {0.01}; - _sitrep = _sitrep + _letter; - _control ctrlsetstructuredtext parsetext format [_sitrepFormat,_sitrep + "_"]; - //playsound ["IncomingChallenge",true]; - sleep _delay; - if (isnull _control) exitwith {}; - }; - _control ctrlsetstructuredtext parsetext format [_sitrepFormat,_sitrep]; -}; - - -//--- Create UAV camera -_camera = "camera" camcreate position player; -_camera cameraeffect ["internal","back"]; -_camera campreparefov 0.4; -_camera campreparetarget _killer; -showcinemaborder false; - -//--- Set PP effects -_saturation = 0.0 + random 0.3; -_ppColor = ppEffectCreate ["ColorCorrections", 1999]; -_ppColor ppEffectEnable true; -_ppColor ppEffectAdjust [1, 1, 0, [1, 1, 1, 0], [1 - _saturation, 1 - _saturation, 1 - _saturation, _saturation], [1, 0.25, 0, 1.0]]; -_ppColor ppEffectCommit 0; - -_ppGrain = ppEffectCreate ["filmGrain", 2012]; -_ppGrain ppEffectEnable true; -_ppGrain ppEffectAdjust [random 0.2, 1, 1, 0, 1]; -_ppGrain ppEffectCommit 0; - -//--- Camera update executed every frame -bis_fnc_respawnNone_player = _player; -bis_fnc_respawnNone_killer = _killer; -bis_fnc_respawnNone_camera = _camera; -bis_fnc_respawnNone_loop = { - scriptname "bis_fnc_respawnNone: camera"; - _display = _this select 0; - _player = bis_fnc_respawnNone_player; - _killer = bis_fnc_respawnNone_killer; - _camera = bis_fnc_respawnNone_camera; - - _sin = 20 * sin (time * 7); - _killerPos = [ - (visiblepositionasl _killer select 0), - (visiblepositionasl _killer select 1) + (_sin), - (visiblepositionasl _killer select 2) + (_sin) - ]; - - _dirToKiller = if (_killer == _player) then { - direction _player; - } else { - ([_player,_killerPos] call bis_fnc_dirto) + _sin; - }; - _pos = [ - visiblepositionasl _player, - -20, - _dirToKiller - ] call bis_fnc_relpos; - _pos set [2,((_pos select 2) + 7) max (getterrainheightasl _pos + 7)]; - - //--- Pitch - _heightCamera = getterrainheightasl _pos; - _heightKiller = getterrainheightasl _killerPos; - _height = _heightCamera - _heightKiller; - _dis = _killerPos distance _pos; - _angle = (asin (_height/_dis)); - - _camera setdir _dirtokiller; - [_camera,-_angle,_sin] call bis_fnc_setpitchbank; - _camera setposasl _pos; - - //--- HUD - _n = 5800; - _hudPos = (worldtoscreen position _player); - if (count _hudPos > 0) then { - _hudPosW = ctrlposition BI_CONTROL select 2; - _hudPosH = ctrlposition BI_CONTROL select 3; - _hudPos = [ - (_hudPos select 0) - _hudPosW / 2, - (_hudPos select 1) - _hudPosH / 2, - _hudPosW, - _hudPosH - ]; - BI_CONTROL ctrlsetposition _hudPos; - BI_CONTROL ctrlcommit 0; - }; -}; - -bis_fnc_respawnNone_keydown = { - _key = _this select 1; - - if (_key in (actionkeys 'nightvision') || _key < 0) then { - bis_fnc_respawnNone_vision = bis_fnc_respawnNone_vision + 1; - _vision = bis_fnc_respawnNone_vision % 4; - switch (_vision) do { - case 0: { - camusenvg false; - call compile 'false SetCamUseTi 0'; - }; - case 1: { - camusenvg true; - call compile 'false SetCamUseTi 0'; - }; - case 2: { - camusenvg false; - call compile 'true SetCamUseTi 0'; - }; - case 3: { - camusenvg false; - call compile 'true SetCamUseTi 1'; - }; - }; - }; -}; -//bis_fnc_respawnNone_vision = (1 + floor random 3) % 4; //--- Random vision (not NVG) -bis_fnc_respawnNone_vision = -1; -if (sunormoon < 1) then {bis_fnc_respawnNone_vision = 0;}; -[-1,-1] call bis_fnc_respawnNone_keydown; - -_display displayaddeventhandler ["mousemoving","_this call bis_fnc_respawnNone_loop"]; -_display displayaddeventhandler ["mouseholding","_this call bis_fnc_respawnNone_loop"]; -_display displayaddeventhandler ["keydown","_this call bis_fnc_respawnNone_keydown"]; - - -//--- Team Switch display opened -waituntil {isnull _display}; -_displayTeamSwitch = finddisplay 632; - -//--- Team Switch display closed - cleanup and restart the view -waituntil {isnull _displayTeamSwitch}; - -_camera cameraeffect ["terminate","back"]; -camdestroy _camera; - -bis_fnc_respawnNone_player = nil; -bis_fnc_respawnNone_killer = nil; -bis_fnc_respawnNone_camera = nil; -bis_fnc_respawnNone_loop = nil; - -ppeffectdestroy _ppColor; -ppeffectdestroy _ppGrain; - -if (!alive player) exitwith {_this call bis_fnc_respawnNone;}; - - -//--- Resurrection! -BIS_fnc_feedback_allowPP = true; -0 fadesound _soundvolume; -0 fademusic _musicvolume; -playmusic ""; -bis_fnc_respawnNone_start = nil; diff --git a/addons/spectator/functions/fnc_bi_respawnSeagull.sqf b/addons/spectator/functions/fnc_bi_respawnSeagull.sqf deleted file mode 100644 index 2e01ffa6ea..0000000000 --- a/addons/spectator/functions/fnc_bi_respawnSeagull.sqf +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Author: Bohemia Interactive - * Part of the BI respawn framework - * Correctly handles seagull respawn (not used by default) - * Edited to support ace_spectator integration - * - * Arguments: - * 0: Corpse/New Unit - * 1: Killer/Old Unit - * 2: Respawn Type - * 3: Respawn Delay - * - * Return Value: - * None - * - * Public: No - */ - -#include "script_component.hpp" - -_seagull = _this select 0; -_player = _this select 1; -_this call bis_fnc_log; - -if (!isplayer _player && !isplayer _seagull) exitwith {["Attempting to use the function on AI unit %1, can be used only on players."] call bis_fnc_error;}; - -waituntil {missionnamespace getvariable ["BIS_fnc_feedback_allowDeathScreen",true]}; -BIS_fnc_feedback_allowPP = false; -//(["HealthPP_black"] call bis_fnc_rscLayer) cutText ["","BLACK IN",8]; - -if (GVAR(onDeath)) exitWith { - private ["_vision","_pos"]; - - if (isNull _player) then {_player = _seagull}; - _vision = [-2,-1] select (sunOrMoon < 1); - _pos = (getPosATL _player) vectorAdd [0,0,5]; - - [_seagull,QGVAR(isSeagull)] call EFUNC(common,hideUnit); - [2,_player,_vision,_pos,getDir _seagull] call FUNC(setCameraAttributes); - [_seagull] call FUNC(setSpectator); -}; - -_camera = "camera" camCreate [(position _player select 0)-0.75, (position _player select 1)-0.75,(position _player select 2) + 0.5]; -_camera cameraEffect ["internal","back"]; -_camera camSetFOV 0.800; -_camera camCommit 0; -waituntil {camCommitted _camera}; - -0 fadeMusic 0.5; -playMusic "Track06_Abandoned_Battlespace"; - -_camera camSetTarget vehicle _player; -_camera camSetRelPos [-0.82,-3.12,3.38]; -_camera camSetFOV 0.800; -_camera camCommit 7; - -sleep 1; -_preload = _player spawn {waitUntil {(preloadCamera getPos _this) && (2 preloadObject _this)}}; -sleep 5; -waituntil {camCommitted _camera}; - -_camera camSetRelPos [1.17,-21.71,2.07]; -_camera camSetFOV 0.400; -_camera camCommit 10; -sleep 2; -terminate _preload; -sleep 3; -_preload = _player spawn {waitUntil {(preloadCamera getPos _this) && (3 preloadObject _this)}}; -waituntil {camCommitted _camera}; - -_camera camSetTarget vehicle _player; -_camera camSetRelPos [5.80,1.29,5.07]; -_camera camSetFOV 0.300; -_camera camCommit 7; -sleep 2; -terminate _preload; -_preload = _seagull spawn {waitUntil {(preloadCamera getPos _this) && (4 preloadObject _this)}}; -waituntil {camCommitted _camera}; - -_camera camSetRelPos [2.71,19.55,12.94]; -_camera camSetFOV 0.700; -_camera camCommit 2; -waituntil {camCommitted _camera}; - -_camera camSetTarget _seagull; -_camera camSetRelPos [-6.66,18.99,2.59]; -_camera camSetFOV 0.700; -_camera camCommit 3; -waituntil {camCommitted _camera}; - -3 fadeMusic 0; - -_camera camSetRelPos [1.17,-21.71,-1.07]; -_camera camSetFOV 0.300; -_camera camCommit 3; -waituntil {camCommitted _camera}; -terminate _preload; - -_seagull switchCamera "EXTERNAL"; -_seagull cameraEffect ["terminate","back"]; -camDestroy _camera; diff --git a/addons/spectator/functions/fnc_bi_respawnSpectator.sqf b/addons/spectator/functions/fnc_bi_respawnSpectator.sqf deleted file mode 100644 index 5097b61ab2..0000000000 --- a/addons/spectator/functions/fnc_bi_respawnSpectator.sqf +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Author: Bohemia Interactive - * Part of the BI respawn framework - * Opens BI spectator interface (default used by seagull respawn) - * Edited to support ace_spectator integration - * - * Arguments: - * 0: Corpse/New Unit - * 1: Killer/Old Unit - * 2: Respawn Type - * 3: Respawn Delay - * - * Return Value: - * None - * - * Public: No - */ - -#include "script_component.hpp" - -params [["_unit",objNull,[objNull]], ["_killer",objNull,[objNull]], ["_respawn",-1,[0]]]; -private ["_vision","_pos"]; - -if (isNull _killer) then {_killer = _unit}; -_vision = [-2,-1] select (sunOrMoon < 1); -_pos = (getPosATL _unit) vectorAdd [0,0,5]; - -_layer = "BIS_fnc_respawnSpectator" call bis_fnc_rscLayer; - -if (!alive _unit) then { - if (GVAR(onDeath)) then { - [2,_killer,_vision,_pos,getDir _unit] call FUNC(setCameraAttributes); - [_unit] call FUNC(setSpectator); - } else { - _layer cutrsc ["RscSpectator","plain"]; - }; -} else { - if (_respawn == 1) then { - - //--- Open - waituntil {missionnamespace getvariable ["BIS_fnc_feedback_allowDeathScreen",true]}; - BIS_fnc_feedback_allowPP = false; - //(["HealthPP_black"] call bis_fnc_rscLayer) cutText ["","BLACK IN",1]; - if (GVAR(onDeath)) then { - [_unit,QGVAR(isSeagull)] call EFUNC(common,hideUnit); - [2,_killer,_vision,_pos,getDir _unit] call FUNC(setCameraAttributes); - [_unit] call FUNC(setSpectator); - } else { - _layer cutrsc ["RscSpectator","plain"]; - }; - } else { - if (GVAR(onDeath)) then { - [_unit,false] call FUNC(setSpectator); - }; - - //--- Close - _layer cuttext ["","plain"]; - }; -}; diff --git a/addons/spectator/functions/fnc_bi_respawnWave.sqf b/addons/spectator/functions/fnc_bi_respawnWave.sqf deleted file mode 100644 index 371a8edcdc..0000000000 --- a/addons/spectator/functions/fnc_bi_respawnWave.sqf +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Author: Bohemia Interactive - * Part of the BI respawn framework - * Handles wave respawning system - * Edited to support ace_spectator integration - * - * Arguments: - * 0: Corpse/New Unit - * 1: Killer/Old Unit - * 2: Respawn Type - * 3: Respawn Delay - * - * Return Value: - * None - * - * Public: No - */ - -#include "script_component.hpp" - -params [["_unit",objNull,[objNull]], ["_killer",objNull,[objNull]], ["_respawn",0,[0]], ["_respawnDelay",0,[0]]]; - -if (!isplayer _unit && !isnull _unit) exitwith {["Attempting to use the function on AI unit %1, can be used only on players."] call bis_fnc_error;}; - -if (!alive _unit) then { - //--- Set the time only when it was not modified already - if (_respawnDelay != 0 && _respawnDelay == playerrespawntime) then { - setplayerrespawntime (_respawnDelay + _respawnDelay - (servertime % _respawnDelay)); - - if !(GVAR(onDeath)) exitWith {}; - private ["_vision","_pos"]; - - if (isNull _killer) then {_killer = _unit}; - _vision = [-2,-1] select (sunOrMoon < 1); - _pos = (getPosATL _unit) vectorAdd [0,0,5]; - - [2,_killer,_vision,_pos,getDir _unit] call FUNC(setCameraAttributes); - [_unit] call FUNC(setSpectator); - }; -} else { - setplayerrespawntime _respawndelay; - [_unit,false] call FUNC(setSpectator); -}; diff --git a/addons/spectator/functions/fnc_handleInterface.sqf b/addons/spectator/functions/fnc_handleInterface.sqf index 5c8c958451..777e8d2ea9 100644 --- a/addons/spectator/functions/fnc_handleInterface.sqf +++ b/addons/spectator/functions/fnc_handleInterface.sqf @@ -43,7 +43,7 @@ switch (toLower _mode) do { // Close map openMap [false,false]; - // Close any BI layers/effects + // Disable BI damage effects and remove counter layer BIS_fnc_feedback_allowPP = false; ("BIS_fnc_respawnCounter" call BIS_fnc_rscLayer) cutText ["","plain"]; @@ -80,9 +80,8 @@ switch (toLower _mode) do { // Return to player view _unit switchCamera "internal"; - // Re-enable any BI effects + // Re-enable BI damage effects BIS_fnc_feedback_allowPP = true; - BIS_fnc_respawnNone_start = nil; // Cleanup camera variables GVAR(camera) = nil; diff --git a/addons/spectator/functions/fnc_moduleSpectatorSettings.sqf b/addons/spectator/functions/fnc_moduleSpectatorSettings.sqf index 1fd20f50e4..c23fb7ad20 100644 --- a/addons/spectator/functions/fnc_moduleSpectatorSettings.sqf +++ b/addons/spectator/functions/fnc_moduleSpectatorSettings.sqf @@ -19,7 +19,6 @@ params ["_logic", "_units", "_activated"]; if !(_activated) exitWith {}; -[_logic, QGVAR(onDeath), "systemEnable"] call EFUNC(common,readSettingFromModule); [_logic, QGVAR(filterUnits), "unitsFilter"] call EFUNC(common,readSettingFromModule); [_logic, QGVAR(filterSides), "sidesFilter"] call EFUNC(common,readSettingFromModule); [_logic, QGVAR(restrictModes), "cameraModes"] call EFUNC(common,readSettingFromModule); diff --git a/addons/spectator/functions/fnc_respawnTemplate.sqf b/addons/spectator/functions/fnc_respawnTemplate.sqf new file mode 100644 index 0000000000..b03c6dfb06 --- /dev/null +++ b/addons/spectator/functions/fnc_respawnTemplate.sqf @@ -0,0 +1,39 @@ +/* + * Author: SilentSpike + * The ace_spectator respawn template, handles killed + respawn + * Can be used via BI's respawn framework, see: + * https://community.bistudio.com/wiki/Arma_3_Respawn + * + * Arguments: + * 0: Corpse/New Unit + * 1: Killer/Old Unit + * 2: Respawn Type + * 3: Respawn Delay + * + * Return Value: + * None + * + * Public: No + */ + +#include "script_component.hpp" + +params [["_unit",objNull,[objNull]], ["_killer",objNull,[objNull]], ["_respawn",0,[0]], ["_respawnDelay",0,[0]]]; +private ["_vision","_pos"]; + +if (isNull _killer) then {_killer = _unit}; +_vision = [-2,-1] select (sunOrMoon < 1); +_pos = (getPosATL _unit) vectorAdd [0,0,5]; + +if (alive _unit) then { + if (_respawn == 1) then { + [_unit,QGVAR(isSeagull)] call EFUNC(common,hideUnit); + [2,_killer,_vision,_pos,getDir _unit] call FUNC(setCameraAttributes); + [_unit] call FUNC(setSpectator); + } else { + [_unit,false] call FUNC(setSpectator); + }; +} else { + [2,_killer,_vision,_pos,getDir _unit] call FUNC(setCameraAttributes); + [_unit] call FUNC(setSpectator); +}; diff --git a/addons/spectator/functions/fnc_transitionCamera.sqf b/addons/spectator/functions/fnc_transitionCamera.sqf index 07abbc94ab..a4d99445fb 100644 --- a/addons/spectator/functions/fnc_transitionCamera.sqf +++ b/addons/spectator/functions/fnc_transitionCamera.sqf @@ -53,8 +53,12 @@ if (_newMode == 0) then { // Free GVAR(camera) camSetFov -(linearConversion [0.01,2,GVAR(camZoom),-2,-0.01,true]); GVAR(camera) camCommit 0; - // Switch to camera to stop AI group chat - ACE_Player switchCamera "internal"; + // Agent is switched to in free cam to hide death table and prevent AI chat + if (isNull GVAR(camAgent)) then { + GVAR(camAgent) = createAgent ["VirtualMan_F",markerPos QGVAR(respawn),[],0,""]; + }; + + GVAR(camAgent) switchCamera "internal"; clearRadio; // If new vision isn't available then keep current (unless current also isn't) diff --git a/addons/spectator/stringtable.xml b/addons/spectator/stringtable.xml index 1f74d08c43..4eb0e25c0a 100644 --- a/addons/spectator/stringtable.xml +++ b/addons/spectator/stringtable.xml @@ -9,14 +9,6 @@ Configure how the spectator system will operate by default. Skonfiguruj domyślne ustawienia obserwatora. - - Spectate on death - Obserwator po śmierci - - - Enables spectator upon death. - Włącz obserwatora po śmierci - Unit filter Filtr jednostek From 79e607836b20f828f00f5c0525c42a779e64d123 Mon Sep 17 00:00:00 2001 From: SilentSpike Date: Wed, 5 Aug 2015 12:51:13 +0100 Subject: [PATCH 13/91] Add contributor email for Head --- AUTHORS.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/AUTHORS.txt b/AUTHORS.txt index 70bd7af086..814ab311a3 100644 --- a/AUTHORS.txt +++ b/AUTHORS.txt @@ -68,8 +68,8 @@ Hamburger SV Harakhti havena Hawkins -Head -jokoho482 ` +Head +jokoho482 Jonpas Karneck Kavinsky From 07e09b60faa7b4b09663d53cb7baa414259bdbb8 Mon Sep 17 00:00:00 2001 From: SilentSpike Date: Wed, 5 Aug 2015 13:19:47 +0100 Subject: [PATCH 14/91] Stop spectator camera unit changing on corpses Previously the camera would be automatically moved away from corpses (when the unit currently being watched dies). This changes it to stay on them until the view is manually switched as users might want to stick around and watch whatever was going on at the time of death. --- addons/spectator/functions/fnc_handleInterface.sqf | 1 + addons/spectator/functions/fnc_handleUnits.sqf | 6 ++++-- addons/spectator/functions/fnc_transitionCamera.sqf | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/addons/spectator/functions/fnc_handleInterface.sqf b/addons/spectator/functions/fnc_handleInterface.sqf index 777e8d2ea9..b85e73dabb 100644 --- a/addons/spectator/functions/fnc_handleInterface.sqf +++ b/addons/spectator/functions/fnc_handleInterface.sqf @@ -78,6 +78,7 @@ switch (toLower _mode) do { camDestroy GVAR(camera); // Return to player view + clearRadio; _unit switchCamera "internal"; // Re-enable BI damage effects diff --git a/addons/spectator/functions/fnc_handleUnits.sqf b/addons/spectator/functions/fnc_handleUnits.sqf index b64a1a2717..e8cd561da0 100644 --- a/addons/spectator/functions/fnc_handleUnits.sqf +++ b/addons/spectator/functions/fnc_handleUnits.sqf @@ -26,9 +26,11 @@ if (isNull _display) exitWith { [_this select 1] call CBA_fnc_removePerFrameHand // Remove all dead and null units from the list [] call FUNC(updateUnits); -// Camera shouldn't stay on unit that isn't in the list +// Camera shouldn't stay on unit that isn't in the list (unless dead) if !(GVAR(camUnit) in GVAR(unitList)) then { - [nil,1] call FUNC(cycleCamera); + if (alive GVAR(camUnit) || isNull GVAR(camUnit)) then { + [nil,1] call FUNC(cycleCamera); + }; }; // Reduce overhead when unit tree is hidden diff --git a/addons/spectator/functions/fnc_transitionCamera.sqf b/addons/spectator/functions/fnc_transitionCamera.sqf index a4d99445fb..4957540fa4 100644 --- a/addons/spectator/functions/fnc_transitionCamera.sqf +++ b/addons/spectator/functions/fnc_transitionCamera.sqf @@ -33,7 +33,7 @@ if !(_newMode in GVAR(availableModes)) then { }; // When no units available to spectate, exit to freecam -if (GVAR(unitList) isEqualTo []) then { +if ((GVAR(unitList) isEqualTo []) && (alive _newUnit || isNull _newUnit)) then { _newMode = 0; _newUnit = objNull; }; From 5200fd6a0298a593fc21d4233de494ff2867a927 Mon Sep 17 00:00:00 2001 From: SilentSpike Date: Wed, 5 Aug 2015 14:15:27 +0100 Subject: [PATCH 15/91] Add new option to spectator unit filter setting Adds an option to use playableUnits for scenarios where AI playable units are enabled. --- addons/spectator/ACE_Settings.hpp | 4 ++-- addons/spectator/CfgVehicles.hpp | 6 +++++- addons/spectator/functions/fnc_updateUnits.sqf | 2 +- addons/spectator/stringtable.xml | 3 +++ 4 files changed, 11 insertions(+), 4 deletions(-) diff --git a/addons/spectator/ACE_Settings.hpp b/addons/spectator/ACE_Settings.hpp index 539f7cef2d..2889fd2e0f 100644 --- a/addons/spectator/ACE_Settings.hpp +++ b/addons/spectator/ACE_Settings.hpp @@ -1,8 +1,8 @@ class ACE_Settings { class GVAR(filterUnits) { typeName = "SCALAR"; - value = 1; - values[] = {CSTRING(units_none), CSTRING(units_players), CSTRING(units_all)}; + value = 2; + values[] = {CSTRING(units_none), CSTRING(units_players), CSTRING(units_playable), CSTRING(units_all)}; }; class GVAR(filterSides) { typeName = "SCALAR"; diff --git a/addons/spectator/CfgVehicles.hpp b/addons/spectator/CfgVehicles.hpp index 8e685dae07..b63f349b0a 100644 --- a/addons/spectator/CfgVehicles.hpp +++ b/addons/spectator/CfgVehicles.hpp @@ -21,11 +21,15 @@ class CfgVehicles { class players { name = CSTRING(units_players); value = 1; + }; + class playable { + name = CSTRING(units_playable); + value = 2; default = 1; }; class all { name = CSTRING(units_all); - value = 2; + value = 3; }; }; }; diff --git a/addons/spectator/functions/fnc_updateUnits.sqf b/addons/spectator/functions/fnc_updateUnits.sqf index ef8fc3b4f1..75f1402179 100644 --- a/addons/spectator/functions/fnc_updateUnits.sqf +++ b/addons/spectator/functions/fnc_updateUnits.sqf @@ -36,7 +36,7 @@ if !(_newUnits isEqualTo []) exitWith { private ["_sides","_cond","_filteredUnits","_color","_icon"]; // Unit setting filter -_newUnits = [[],allPlayers,allUnits] select GVAR(filterUnits); +_newUnits = [[],allPlayers,playableUnits,allUnits] select GVAR(filterUnits); // Side setting filter _sides = []; diff --git a/addons/spectator/stringtable.xml b/addons/spectator/stringtable.xml index 4eb0e25c0a..5219ba7e2d 100644 --- a/addons/spectator/stringtable.xml +++ b/addons/spectator/stringtable.xml @@ -25,6 +25,9 @@ Only players Tylko gracze + + Playable Units + All units Wszystkie jednostki From 42b5abae116c27cad907aee5cc5dd85ad978c59c Mon Sep 17 00:00:00 2001 From: SilentSpike Date: Wed, 5 Aug 2015 19:25:38 +0100 Subject: [PATCH 16/91] Add support for respawn counter to spectator UI Rather than hiding the BI respawn counter, it should be "integrated" into the UI via code if present. --- addons/spectator/UI/interface.hpp | 11 +++++- .../functions/fnc_handleInterface.sqf | 35 +++++++++++++++---- 2 files changed, 39 insertions(+), 7 deletions(-) diff --git a/addons/spectator/UI/interface.hpp b/addons/spectator/UI/interface.hpp index e8df31c280..bd6d34339f 100644 --- a/addons/spectator/UI/interface.hpp +++ b/addons/spectator/UI/interface.hpp @@ -1,6 +1,15 @@ +// Temporary fix until BI take care of it +class RscFrame { + x = 0; + y = 0; + w = 0; + h = 0; +}; + + class RscButtonMenu; class RscControlsGroupNoScrollbars; -class RscFrame; +//class RscFrame; class RscListNBox; class RscMapControl; class RscPicture; diff --git a/addons/spectator/functions/fnc_handleInterface.sqf b/addons/spectator/functions/fnc_handleInterface.sqf index b85e73dabb..b6608959b7 100644 --- a/addons/spectator/functions/fnc_handleInterface.sqf +++ b/addons/spectator/functions/fnc_handleInterface.sqf @@ -43,9 +43,8 @@ switch (toLower _mode) do { // Close map openMap [false,false]; - // Disable BI damage effects and remove counter layer + // Disable BI damage effects BIS_fnc_feedback_allowPP = false; - ("BIS_fnc_respawnCounter" call BIS_fnc_rscLayer) cutText ["","plain"]; // Close all existing dialogs while {dialog} do { @@ -81,7 +80,7 @@ switch (toLower _mode) do { clearRadio; _unit switchCamera "internal"; - // Re-enable BI damage effects + // Enable BI damage effects BIS_fnc_feedback_allowPP = true; // Cleanup camera variables @@ -154,9 +153,33 @@ switch (toLower _mode) do { [localize LSTRING(prevUnit),"Left Arrow"] ]; - // Hacky way to enable keybindings - //_display displayAddEventHandler ["KeyUp", {[_this,'keyup'] call CBA_events_fnc_keyHandler}]; - //_display displayAddEventHandler ["KeyDown", {[_this,'keydown'] call CBA_events_fnc_keyHandler}]; + // Handle support for BI's respawn counter + [{ + if !(isNull (GETUVAR(RscRespawnCounter,displayNull))) then { + disableSerialization; + private ["_counter","_title","_back","_timer","_frame","_x","_y"]; + _counter = GETUVAR(RscRespawnCounter,displayNull); + _title = _counter displayCtrl 1001; + _back = _counter displayCtrl 1002; + _timer = _counter displayCtrl 1003; + _frame = _counter ctrlCreate ["RscFrame",1008]; + + _x = safeZoneX + safeZoneW - TOOL_W * 4 - MARGIN * 3; + _y = safeZoneY + safeZoneH - TOOL_H; + + // Timer + _title ctrlSetPosition [_x,_y,TOOL_W,TOOL_H]; + _back ctrlSetPosition [_x,_y,TOOL_W,TOOL_H]; + _timer ctrlSetPosition [_x,_y,TOOL_W,TOOL_H]; + _frame ctrlSetPosition [_x,_y,TOOL_W,TOOL_H]; + _timer ctrlSetFontHeight TOOL_H; + + _title ctrlCommit 0; + _back ctrlCommit 0; + _timer ctrlCommit 0; + _frame ctrlCommit 0; + }; + },[],0.5] call EFUNC(common,waitAndExecute); }; case "onunload": { // Kill GUI PFHs From c808021c7c9ae480d2d27a4735516ed02f688049 Mon Sep 17 00:00:00 2001 From: SilentSpike Date: Wed, 5 Aug 2015 21:11:25 +0100 Subject: [PATCH 17/91] Tweak spectator interface layout - Swap the FOV and vision mode tools into a more logical order. - Shorten the unit list to prevent overlay with main UI - Fix name tool on dead units --- addons/spectator/UI/interface.hpp | 14 +++++++------- addons/spectator/functions/fnc_handleToolbar.sqf | 12 ++++++------ 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/addons/spectator/UI/interface.hpp b/addons/spectator/UI/interface.hpp index bd6d34339f..2ac33e4a64 100644 --- a/addons/spectator/UI/interface.hpp +++ b/addons/spectator/UI/interface.hpp @@ -121,11 +121,11 @@ class GVAR(interface) { idc = -1; style = 64; }; - class fovTool: viewTool { - idc = IDC_TOOL_FOV; + class visionTool: viewTool { + idc = IDC_TOOL_VISION; x = TOOL_W * 3 + MARGIN * 2; }; - class fovFrame: fovTool { + class visionFrame: visionTool { idc = -1; style = 64; }; @@ -137,11 +137,11 @@ class GVAR(interface) { idc = -1; style = 64; }; - class visionTool: viewTool { - idc = IDC_TOOL_VISION; + class fovTool: viewTool { + idc = IDC_TOOL_FOV; x = safeZoneW - TOOL_W * 2 - MARGIN; }; - class visionFrame: visionTool { + class fovFrame: fovTool { idc = -1; style = 64; }; @@ -160,7 +160,7 @@ class GVAR(interface) { x = safeZoneX; y = safeZoneY + TOOL_H * 2; w = TOOL_W * 2; - h = safeZoneH - TOOL_H * 4; + h = safeZoneH - TOOL_H * 6; sizeEx = H_PART(0.8); borderSize = 1; colorBorder[] = {COL_FORE}; diff --git a/addons/spectator/functions/fnc_handleToolbar.sqf b/addons/spectator/functions/fnc_handleToolbar.sqf index fd29ca532e..878f3e46de 100644 --- a/addons/spectator/functions/fnc_handleToolbar.sqf +++ b/addons/spectator/functions/fnc_handleToolbar.sqf @@ -1,6 +1,6 @@ /* * Author: Karel Moricky, SilentSpike - * Handles the spectator UI toolbar values and applies them to the camera + * Handles the spectator UI toolbar values * * Arguments: * 0: Parameters @@ -31,15 +31,15 @@ if (GVAR(camMode) == 0) then { _fov = format ["%1x", floor(GVAR(camZoom) * 100) * 0.01]; _speed = format ["%1 m/s", floor(GVAR(camSpeed) * 100) * 0.01]; } else { - _vision = format ["%1 m", floor(getPosASL GVAR(camUnit) select 2)]; - _fov = [side group GVAR(camUnit)] call BIS_fnc_sideName; + _vision = [side group GVAR(camUnit)] call BIS_fnc_sideName; + _fov = format ["%1 m", floor(getPosASL GVAR(camUnit) select 2)]; _speed = format ["%1 km/h", floor(speed GVAR(camUnit)) max 0]; }; -if (isNull GVAR(camUnit)) then { - _name = localize "STR_Special_None"; -} else { +if (alive GVAR(camUnit)) then { _name = GETVAR(GVAR(camUnit),GVAR(uName),""); +} else { + _name = localize "STR_Special_None"; }; _mode = [localize LSTRING(ViewFree),localize LSTRING(ViewInternal),localize LSTRING(ViewExternal)] select GVAR(camMode); From d1975a593dc6d88755b5792b1bd627181bc6d9f0 Mon Sep 17 00:00:00 2001 From: SilentSpike Date: Thu, 6 Aug 2015 00:39:14 +0100 Subject: [PATCH 18/91] Improve spectator pause menu emulation Makes the fake pause menu closer to the real thing for UX purposes --- .../functions/fnc_handleInterface.sqf | 40 ++++++++++--------- 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/addons/spectator/functions/fnc_handleInterface.sqf b/addons/spectator/functions/fnc_handleInterface.sqf index b6608959b7..fdd84ee5ef 100644 --- a/addons/spectator/functions/fnc_handleInterface.sqf +++ b/addons/spectator/functions/fnc_handleInterface.sqf @@ -457,10 +457,10 @@ switch (toLower _mode) do { }; } forEach GVAR(unitList); }; - // Other + // Break from interface for escape menu case "escape": { _args params ["_display"]; - private ["_dlg","_key","_index","_ctrl","_config"]; + private "_dlg"; // Kill display _display closeDisplay 0; @@ -474,7 +474,6 @@ switch (toLower _mode) do { GVAR(mouse) = [false,false]; GVAR(mousePos) = [0.5,0.5]; - // Below is from EFUNC(common,disableUserInput) createDialog (["RscDisplayInterrupt", "RscDisplayMPInterrupt"] select isMultiplayer); disableSerialization; @@ -484,30 +483,35 @@ switch (toLower _mode) do { !(_key == 1) }]; - for "_index" from 100 to 2000 do { - (_dlg displayCtrl _index) ctrlEnable false; + // Disable save, respawn, options & manual buttons + (_dlg displayCtrl 103) ctrlEnable false; + if !(alive player) then { + (_dlg displayCtrl 1010) ctrlEnable false; }; + (_dlg displayCtrl 101) ctrlEnable false; + (_dlg displayCtrl 122) ctrlEnable false; - _ctrl = _dlg displayctrl 103; - _ctrl ctrlSetEventHandler ["buttonClick", QUOTE(while {dialog} do {closeDialog 0}; failMission 'LOSER';)]; - _ctrl ctrlEnable true; - _ctrl ctrlSetText "ABORT"; - _ctrl ctrlSetTooltip "Abort."; - - _ctrl = _dlg displayctrl ([104, 1010] select isMultiplayer); - _ctrl ctrlSetEventHandler ["buttonClick", QUOTE(closeDialog 0; player setDamage 1;)]; - _ctrl ctrlEnable (call {_config = missionConfigFile >> "respawnButton"; !isNumber _config || {getNumber _config == 1}}); - _ctrl ctrlSetText "RESPAWN"; - _ctrl ctrlSetTooltip "Respawn."; + // Initalize abort button (the "spawn" is a necessary evil) + (_dlg displayCtrl 104) ctrlAddEventHandler ["ButtonClick",{_this spawn { + disableSerialization; + _display = ctrlparent (_this select 0); + _abort = [localize "str_msg_confirm_return_lobby",nil,localize "str_disp_xbox_hint_yes",localize "str_disp_xbox_hint_no",_display,nil,true] call BIS_fnc_guiMessage; + if (_abort) then {_display closeDisplay 2; failMission "loser"}; + }}]; // PFH to re-open display when menu closes [{ if !(isNull (findDisplay 49)) exitWith {}; - createDialog QGVAR(interface); - [] call FUNC(transitionCamera); + // If still a spectator then re-enter the interface + if (GVAR(isSet)) then { + createDialog QGVAR(interface); + [] call FUNC(transitionCamera); + }; [_this select 1] call CBA_fnc_removePerFrameHandler; },0] call CBA_fnc_addPerFrameHandler; + + true }; }; From d6cc14a39d20afbd4734ab4c90ddfdbde63cee12 Mon Sep 17 00:00:00 2001 From: SilentSpike Date: Thu, 6 Aug 2015 00:52:39 +0100 Subject: [PATCH 19/91] Add zeus support to spectator UI Can only use zeus while alive, so it won't work using the respawn template. However it's useful for communities usign custom frameworks --- .../functions/fnc_handleInterface.sqf | 38 ++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/addons/spectator/functions/fnc_handleInterface.sqf b/addons/spectator/functions/fnc_handleInterface.sqf index fdd84ee5ef..defe5332ba 100644 --- a/addons/spectator/functions/fnc_handleInterface.sqf +++ b/addons/spectator/functions/fnc_handleInterface.sqf @@ -225,6 +225,10 @@ switch (toLower _mode) do { case "onkeydown": { _args params ["_display","_dik","_shift","_ctrl","_alt"]; + if ((alive player) && {_dik in (actionKeys "curatorInterface")} && {!isNull (getAssignedCuratorLogic player)}) exitWith { + ["zeus", [_display]] call FUNC(handleInterface); + }; + // Handle held keys (prevent repeat calling) if (_dik in GVAR(heldKeys)) exitwith {}; // Exclude movement keys so that speed can be adjusted on fly @@ -457,7 +461,7 @@ switch (toLower _mode) do { }; } forEach GVAR(unitList); }; - // Break from interface for escape menu + // Break from interface for eexternal events case "escape": { _args params ["_display"]; private "_dlg"; @@ -511,6 +515,38 @@ switch (toLower _mode) do { [_this select 1] call CBA_fnc_removePerFrameHandler; },0] call CBA_fnc_addPerFrameHandler; + }; + case "zeus": { + _args params ["_display"]; + + // Kill display + _display closeDisplay 0; + + // Reset cam/UI vars + GVAR(camBoom) = 0; + GVAR(camDolly) = [0,0]; + + GVAR(ctrlKey) = false; + GVAR(heldKeys) = []; + GVAR(mouse) = [false,false]; + GVAR(mousePos) = [0.5,0.5]; + + openCuratorInterface; + + [{ + // PFH to re-open display when menu closes + [{ + if !((isNull curatorCamera) && {isNull (GETMVAR(bis_fnc_moduleRemoteControl_unit,objNull))}) exitWith {}; + + // If still a spectator then re-enter the interface + if (GVAR(isSet)) then { + createDialog QGVAR(interface); + [] call FUNC(transitionCamera); + }; + + [_this select 1] call CBA_fnc_removePerFrameHandler; + },0] call CBA_fnc_addPerFrameHandler; + },[],5] call EFUNC(common,waitAndExecute); true }; From 92ef0bfe995632527c255099d45862a99a913a3f Mon Sep 17 00:00:00 2001 From: SilentSpike Date: Thu, 6 Aug 2015 11:34:24 +0100 Subject: [PATCH 20/91] Whitelist spectator free camera boom keys Now that booming the free camera is influenced by the camera speed, the keys should be whitelisted from the held-key prevention system to allow the speed to be adjusted on the move. Also includes a failed attempt to fix the free camera map teleporting functionality. --- addons/spectator/UI/interface.hpp | 2 +- addons/spectator/functions/fnc_handleInterface.sqf | 12 +++++++----- addons/spectator/functions/fnc_transitionCamera.sqf | 4 +++- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/addons/spectator/UI/interface.hpp b/addons/spectator/UI/interface.hpp index 2ac33e4a64..182263e7b4 100644 --- a/addons/spectator/UI/interface.hpp +++ b/addons/spectator/UI/interface.hpp @@ -180,7 +180,7 @@ class GVAR(interface) { y = safeZoneY; w = safeZoneW; h = safeZoneH; - onMouseButtonDblClick = QUOTE([ARR_2('onMapDblClick',_this)] call FUNC(handleInterface)); + onMouseButtonDown = QUOTE([ARR_2('onMapClick',_this)] call FUNC(handleInterface)); onDraw = QUOTE([ARR_2('onDraw',_this)] call FUNC(handleInterface)); }; class helpSplash: RscControlsGroupNoScrollbars { diff --git a/addons/spectator/functions/fnc_handleInterface.sqf b/addons/spectator/functions/fnc_handleInterface.sqf index defe5332ba..502ce65fd4 100644 --- a/addons/spectator/functions/fnc_handleInterface.sqf +++ b/addons/spectator/functions/fnc_handleInterface.sqf @@ -40,8 +40,9 @@ switch (toLower _mode) do { GVAR(camera) = "Camera" camCreate (ASLtoATL GVAR(camPos)); [] call FUNC(transitionCamera); - // Close map + // Close map and clear radio openMap [false,false]; + clearRadio; // Disable BI damage effects BIS_fnc_feedback_allowPP = false; @@ -76,8 +77,9 @@ switch (toLower _mode) do { GVAR(camera) cameraEffect ["terminate", "back"]; camDestroy GVAR(camera); - // Return to player view clearRadio; + + // Return to player view _unit switchCamera "internal"; // Enable BI damage effects @@ -232,7 +234,7 @@ switch (toLower _mode) do { // Handle held keys (prevent repeat calling) if (_dik in GVAR(heldKeys)) exitwith {}; // Exclude movement keys so that speed can be adjusted on fly - if !(_dik in [17,30,31,32]) then { + if !(_dik in [16,17,30,31,32,44]) then { GVAR(heldKeys) pushBack _dik; }; @@ -422,8 +424,8 @@ switch (toLower _mode) do { _tree tvSort [[],false]; }; // Map events - case "onmapdblclick": { - _args params ["_map","_button","_x","_y"]; + case "onmapclick": { + _args params ["_map","_button","_x","_y","_shift","_ctrl","_alt"]; private ["_newPos","_oldZ"]; if ((GVAR(camMode) == 0) && (_button == 0)) then { diff --git a/addons/spectator/functions/fnc_transitionCamera.sqf b/addons/spectator/functions/fnc_transitionCamera.sqf index 4957540fa4..90a2dc776b 100644 --- a/addons/spectator/functions/fnc_transitionCamera.sqf +++ b/addons/spectator/functions/fnc_transitionCamera.sqf @@ -53,7 +53,9 @@ if (_newMode == 0) then { // Free GVAR(camera) camSetFov -(linearConversion [0.01,2,GVAR(camZoom),-2,-0.01,true]); GVAR(camera) camCommit 0; - // Agent is switched to in free cam to hide death table and prevent AI chat + // Agent is switched to in free cam to hide death table and prevent AI chat while allowing icons to draw + // However, map click events don't fire in free cam for some reason... + // (Why is so much stuff tied into the current camera unit BI?!) if (isNull GVAR(camAgent)) then { GVAR(camAgent) = createAgent ["VirtualMan_F",markerPos QGVAR(respawn),[],0,""]; }; From bcb21b782e1ed9d52ca5c7ac61b30d09e90ef795 Mon Sep 17 00:00:00 2001 From: SilentSpike Date: Thu, 6 Aug 2015 13:42:31 +0100 Subject: [PATCH 21/91] Overhaul spectator icon handling and rendering - Optimize and improve 3D icon drawing - Combine 2D and 3D PFHs into 1 - Render group icons outside of 200m, unit icons within - Store list of groups on units update to cut down on what needs to be done each frame - Change map control type to 100 to remove all default unit icons - Improve colour caching, group colours don't change, unit colours do - Remove icon setting, toggling should be at users discretion --- addons/spectator/ACE_Settings.hpp | 4 -- addons/spectator/UI/interface.hpp | 3 +- addons/spectator/XEH_preInit.sqf | 2 + .../spectator/functions/fnc_cacheUnitInfo.sqf | 11 +++- .../spectator/functions/fnc_handleIcons.sqf | 57 ++++++++----------- .../functions/fnc_handleInterface.sqf | 32 ++--------- addons/spectator/functions/fnc_handleMap.sqf | 46 +++++++++++++++ .../functions/fnc_transitionCamera.sqf | 6 -- .../spectator/functions/fnc_updateUnits.sqf | 7 ++- addons/spectator/stringtable.xml | 8 --- 10 files changed, 90 insertions(+), 86 deletions(-) create mode 100644 addons/spectator/functions/fnc_handleMap.sqf diff --git a/addons/spectator/ACE_Settings.hpp b/addons/spectator/ACE_Settings.hpp index 2889fd2e0f..78402cff23 100644 --- a/addons/spectator/ACE_Settings.hpp +++ b/addons/spectator/ACE_Settings.hpp @@ -19,8 +19,4 @@ class ACE_Settings { value = 0; values[] = {CSTRING(modes_all), CSTRING(visions_nv), CSTRING(visions_ti), "$STR_Special_None"}; }; - class GVAR(unitIcons) { - typeName = "BOOL"; - value = 1; - }; }; diff --git a/addons/spectator/UI/interface.hpp b/addons/spectator/UI/interface.hpp index 182263e7b4..0b4d33ea75 100644 --- a/addons/spectator/UI/interface.hpp +++ b/addons/spectator/UI/interface.hpp @@ -176,12 +176,13 @@ class GVAR(interface) { }; class mapOverlay: RscMapControl { idc = IDC_MAP; + type = 100; x = safeZoneX; y = safeZoneY; w = safeZoneW; h = safeZoneH; onMouseButtonDown = QUOTE([ARR_2('onMapClick',_this)] call FUNC(handleInterface)); - onDraw = QUOTE([ARR_2('onDraw',_this)] call FUNC(handleInterface)); + onDraw = QUOTE(_this call FUNC(handleMap)); }; class helpSplash: RscControlsGroupNoScrollbars { idc = IDC_HELP; diff --git a/addons/spectator/XEH_preInit.sqf b/addons/spectator/XEH_preInit.sqf index 95c18f4a54..2c29598ebc 100644 --- a/addons/spectator/XEH_preInit.sqf +++ b/addons/spectator/XEH_preInit.sqf @@ -8,6 +8,7 @@ PREP(handleCamera); PREP(handleCompass); PREP(handleIcons); PREP(handleInterface); +PREP(handleMap); PREP(handleMouse); PREP(handleToolbar); PREP(handleUnits); @@ -51,5 +52,6 @@ GVAR(showUnit) = true; GVAR(unitList) = []; GVAR(unitBlacklist) = []; GVAR(unitWhitelist) = []; +GVAR(groupList) = []; ADDON = true; diff --git a/addons/spectator/functions/fnc_cacheUnitInfo.sqf b/addons/spectator/functions/fnc_cacheUnitInfo.sqf index 13977bf398..9f40651748 100644 --- a/addons/spectator/functions/fnc_cacheUnitInfo.sqf +++ b/addons/spectator/functions/fnc_cacheUnitInfo.sqf @@ -19,15 +19,20 @@ params ["_unit"]; private ["_color","_icon","_name"]; -_color = [side group _unit] call BIS_fnc_sideColor; +// Group info only needs to be cached once (groups can't change) +if (isNil { GETVAR((group _unit),GVAR(gColor),nil) }) then { + _color = [side group _unit] call BIS_fnc_sideColor; + SETVAR((group _unit),GVAR(gColor),_color); +}; + +// Unit info should be updated each time _icon = getText (configFile >> "CfgVehicles" >> typeOf _unit >> "Icon"); _name = [_unit,false] call EFUNC(common,getName); // Handle CfgVehicleIcons -if isText (configFile >> "CfgVehicleIcons" >> _icon) then { +if (isText (configFile >> "CfgVehicleIcons" >> _icon)) then { _icon = getText (configFile >> "CfgVehicleIcons" >> _icon); }; -SETVAR(_unit,GVAR(uColor),_color); SETVAR(_unit,GVAR(uIcon),_icon); SETVAR(_unit,GVAR(uName),_name); diff --git a/addons/spectator/functions/fnc_handleIcons.sqf b/addons/spectator/functions/fnc_handleIcons.sqf index c52943ad10..72c0d7dee6 100644 --- a/addons/spectator/functions/fnc_handleIcons.sqf +++ b/addons/spectator/functions/fnc_handleIcons.sqf @@ -1,5 +1,5 @@ /* - * Author: SilentSpike + * Author: Head, SilentSpike * Handles rendering the spectator 3D unit icons * * Arguments: @@ -17,41 +17,30 @@ #include "script_component.hpp" -// Kill PFH when not in free cam (or display is closed) -if (isNil QGVAR(iconHandler)) exitWith { [_this select 1] call CBA_fnc_removePerFrameHandler; }; - if !(GVAR(showIcons)) exitWith {}; +private ["_refPoint","_drawVehicles","_leader","_color","_txt","_unit"]; -private ["_cachedVehicles","_unit","_cameraPos","_cameraDir","_lambda","_uPos","_cmd","_txt"]; -_cachedVehicles = []; +// Draw groups unless leader is within distance +_refPoint = [GVAR(camera),GVAR(camUnit)] select (GVAR(camMode) > 0); +_drawVehicles = []; { - _unit = vehicle _x; + _leader = leader _x; + if ((_leader distanceSqr _refPoint) > 40000) then { + _color = GETVAR(_x,GVAR(gColor),[ARR_4(0,0,0,0)]); + _txt = groupID _x; - // Only try each vehicle once - if !(_unit in _cachedVehicles) then { - _cachedVehicles pushBack _unit; - - // Within 200m - if ((GVAR(camera) distanceSqr _unit) < 40000) then { - _cameraPos = (positionCameraToWorld [0, 0, 0]) call EFUNC(common,positionToASL); - _cameraDir = ((positionCameraToWorld [0, 0, 1]) call EFUNC(common,positionToASL)) vectorDiff _cameraPos; - - // Quick oclussion test (taken from interact_menu) - _lambda = ((getPosASL _x) vectorDiff _cameraPos) vectorDotProduct _cameraDir; - if (_lambda > -1) then { - _uPos = worldToScreen (visiblePosition _unit); - - // Only draw if onscreen - if ((_uPos select 0 > safeZoneXAbs) && (_uPos select 0 < safeZoneXAbs + safeZoneWAbs)) then { - if ((_uPos select 1 > safeZoneY) && (_uPos select 1 < safeZoneY + safeZoneH)) then { - // Use commander's info if available - _cmd = [_x, effectiveCommander _unit] select ((effectiveCommander _unit) in GVAR(unitList)); - _txt = ["", GETVAR(_cmd,GVAR(uName),"")] select (isPlayer _cmd); - - drawIcon3D ["\A3\ui_f\data\map\markers\military\dot_CA.paa", GETVAR(_cmd,GVAR(uColor),[ARR_4(0,0,0,0)]), _unit modelToWorldVisual [0,0,3], 0.7, 0.7, 0, _txt, 1, 0.02]; - }; - }; - }; - }; + drawIcon3D ["\A3\ui_f\data\map\markers\nato\b_inf.paa", _color, _leader modelToWorldVisual [0,0,30], 1, 1, 0, _txt, 2, 0.02]; + } else { + _drawVehicles append (units _x); }; -} forEach GVAR(unitList); + false +} count GVAR(groupList); + +// Draw units for groups within distance +{ + _color = GETVAR((group _x),GVAR(gColor),[ARR_4(0,0,0,0)]); + _txt = ["", GETVAR(_x,GVAR(uName),"")] select (isPlayer _x); + + drawIcon3D ["\A3\ui_f\data\map\markers\military\dot_CA.paa", _color, _x modelToWorldVisual [0,0,3], 0.7, 0.7, 0, _txt, 1, 0.02]; + false +} count (_drawVehicles arrayIntersect GVAR(unitList)); diff --git a/addons/spectator/functions/fnc_handleInterface.sqf b/addons/spectator/functions/fnc_handleInterface.sqf index 502ce65fd4..d58566968c 100644 --- a/addons/spectator/functions/fnc_handleInterface.sqf +++ b/addons/spectator/functions/fnc_handleInterface.sqf @@ -114,6 +114,9 @@ switch (toLower _mode) do { // Keep unit list and tree up to date [FUNC(handleUnits), 21, _display] call CBA_fnc_addPerFrameHandler; + // Handle unit icons on map and 3D + GVAR(iconHandler) = addMissionEventHandler ["Draw3D",FUNC(handleIcons)]; + // Populate the help splash private "_help"; _help = (_display displayCtrl IDC_HELP) controlsGroupCtrl IDC_HELP_LIST; @@ -187,6 +190,7 @@ switch (toLower _mode) do { // Kill GUI PFHs GVAR(camHandler) = nil; GVAR(compHandler) = nil; + removeMissionEventHandler ["Draw3D",GVAR(iconHandler)]; GVAR(iconHandler) = nil; GVAR(toolHandler) = nil; }; @@ -435,34 +439,6 @@ switch (toLower _mode) do { [nil,nil,nil, _newPos] call FUNC(setCameraAttributes); }; }; - case "ondraw": { - _args params ["_map"]; - - if (GVAR(camMode) == 0) then { - _map drawIcon ["\A3\UI_F\Data\GUI\Rsc\RscDisplayMissionEditor\iconcamera_ca.paa",[0,0,0,1],GVAR(camera),24,24,GVAR(camPan)]; - }; - - if !(GVAR(showIcons)) exitWith {}; - - private ["_cachedVehicles","_unit","_color","_icon"]; - _cachedVehicles = []; - { - _unit = vehicle _x; - - if !(_unit in _cachedVehicles) then { - _cachedVehicles pushBack _unit; - - // Use previously cached info where possible - if (isNil { GETVAR(_unit,GVAR(uIcon),nil) }) then { - [_unit] call FUNC(cacheUnitInfo); - }; - - _color = GETVAR(_unit,GVAR(uColor),[ARR_4(0,0,0,0)]); - _icon = GETVAR(_unit,GVAR(uIcon),""); - _map drawIcon [_icon, _color, _unit, 24, 24, getDir _unit]; - }; - } forEach GVAR(unitList); - }; // Break from interface for eexternal events case "escape": { _args params ["_display"]; diff --git a/addons/spectator/functions/fnc_handleMap.sqf b/addons/spectator/functions/fnc_handleMap.sqf new file mode 100644 index 0000000000..a0000718bd --- /dev/null +++ b/addons/spectator/functions/fnc_handleMap.sqf @@ -0,0 +1,46 @@ +/* + * Author: Head, SilentSpike + * Handles rendering the spectator map icons + * + * Arguments: + * 0: Parameters + * 1: PFH handle + * + * Return Value: + * None + * + * Example: + * [ace_spectator_fnc_handleIcons, 0] call CBA_fnc_addPerFrameHandler; + * + * Public: No + */ + +#include "script_component.hpp" + +params ["_map"]; +private ["_cachedVehicles","_unit","_color","_icon"]; + +if (GVAR(camMode) == 0) then { + _map drawIcon ["\A3\UI_F\Data\GUI\Rsc\RscDisplayMissionEditor\iconcamera_ca.paa",[0,0,0,1],GVAR(camera),20,20,GVAR(camPan)]; +}; + +_cachedVehicles = []; +{ + _unit = vehicle _x; + + if !(_unit in _cachedVehicles) then { + _cachedVehicles pushBack _unit; + + // Use previously cached info where possible + if (GETVAR(_unit,GVAR(uIcon),"") == "") then { + [_unit] call FUNC(cacheUnitInfo); + }; + + // Function has caching built in + _color = [side effectiveCommander _unit] call BIS_fnc_sideColor; + _icon = GETVAR(_unit,GVAR(uIcon),""); + + _map drawIcon [_icon, _color, _unit, 19, 19, getDir _unit]; + }; + false +} count GVAR(unitList); diff --git a/addons/spectator/functions/fnc_transitionCamera.sqf b/addons/spectator/functions/fnc_transitionCamera.sqf index 90a2dc776b..b35b61b311 100644 --- a/addons/spectator/functions/fnc_transitionCamera.sqf +++ b/addons/spectator/functions/fnc_transitionCamera.sqf @@ -79,11 +79,6 @@ if (_newMode == 0) then { // Free // Handle camera movement if (isNil QGVAR(camHandler)) then { GVAR(camHandler) = [FUNC(handleCamera), 0] call CBA_fnc_addPerFrameHandler; }; - - // Handle unit icons - if (GVAR(unitIcons)) then { - if (isNil QGVAR(iconHandler)) then { GVAR(iconHandler) = [FUNC(handleIcons), 0] call CBA_fnc_addPerFrameHandler; }; - }; } else { // When null unit is given choose random if (isNull _newUnit) then { @@ -111,7 +106,6 @@ if (_newMode == 0) then { // Free // Terminate camera view GVAR(camera) cameraEffect ["terminate", "back"]; GVAR(camHandler) = nil; - GVAR(iconHandler) = nil; cameraEffectEnableHUD true; }; diff --git a/addons/spectator/functions/fnc_updateUnits.sqf b/addons/spectator/functions/fnc_updateUnits.sqf index 75f1402179..50494cf499 100644 --- a/addons/spectator/functions/fnc_updateUnits.sqf +++ b/addons/spectator/functions/fnc_updateUnits.sqf @@ -33,7 +33,7 @@ if !(_newUnits isEqualTo []) exitWith { }; }; -private ["_sides","_cond","_filteredUnits","_color","_icon"]; +private ["_sides","_cond","_filteredUnits","_filteredGroups"]; // Unit setting filter _newUnits = [[],allPlayers,playableUnits,allUnits] select GVAR(filterUnits); @@ -63,10 +63,13 @@ _filteredUnits = []; _filteredUnits append GVAR(unitWhitelist); // Cache icons and colour for drawing +_filteredGroups = []; { // Intentionally re-applied to units in case their status changes [_x] call FUNC(cacheUnitInfo); + _filteredGroups pushBack (group _x); } forEach _filteredUnits; -// Replace previous list entirely (removes any no longer valid) +// Replace previous lists entirely (removes any no longer valid) GVAR(unitList) = _filteredUnits arrayIntersect _filteredUnits; +GVAR(groupList) = _filteredGroups arrayIntersect _filteredGroups; diff --git a/addons/spectator/stringtable.xml b/addons/spectator/stringtable.xml index 5219ba7e2d..4d615d4e1e 100644 --- a/addons/spectator/stringtable.xml +++ b/addons/spectator/stringtable.xml @@ -100,14 +100,6 @@ Thermal imaging Termowizja - - Unit icons - Ikony jednostek - - - Render icons above spectatable units. - Renderuj ikony nad głowami jednostek, które można obserwować. - Spectator Controls From 4c9b6e94cfa915a70b3911d18acda892c7ff8c66 Mon Sep 17 00:00:00 2001 From: SilentSpike Date: Fri, 7 Aug 2015 00:05:21 +0100 Subject: [PATCH 22/91] Overhaul and improve spectator unit tree UX The old method of refreshing the tree on each update would reset all expanded/collapsed nodes. Now the code will cull any units/groups/sides no longer spectatable from the list and cache the ones that are still valid. The cached data is then used to populate the list with new units. Add coloured unit icons beside units in the list for quick user reference of side and type. Store group netIDs in respective nodes for possible use in code. --- addons/spectator/UI/interface.hpp | 4 +- .../functions/fnc_handleInterface.sqf | 85 ++++++++++++------- 2 files changed, 55 insertions(+), 34 deletions(-) diff --git a/addons/spectator/UI/interface.hpp b/addons/spectator/UI/interface.hpp index 0b4d33ea75..ea5f5f0e53 100644 --- a/addons/spectator/UI/interface.hpp +++ b/addons/spectator/UI/interface.hpp @@ -158,9 +158,9 @@ class GVAR(interface) { class unitTree: RscTree { idc = IDC_UNIT; x = safeZoneX; - y = safeZoneY + TOOL_H * 2; + y = safeZoneY + TOOL_H * 6; w = TOOL_W * 2; - h = safeZoneH - TOOL_H * 6; + h = safeZoneH - TOOL_H * 13; sizeEx = H_PART(0.8); borderSize = 1; colorBorder[] = {COL_FORE}; diff --git a/addons/spectator/functions/fnc_handleInterface.sqf b/addons/spectator/functions/fnc_handleInterface.sqf index d58566968c..9687ba8b2a 100644 --- a/addons/spectator/functions/fnc_handleInterface.sqf +++ b/addons/spectator/functions/fnc_handleInterface.sqf @@ -367,17 +367,43 @@ switch (toLower _mode) do { }; case "onunitsupdate": { _args params ["_tree"]; - private ["_curSelData","_cachedGrps","_cachedSides","_grp","_side","_sNode","_gNode","_uNode"]; + private ["_cachedUnits","_cachedGrps","_cachedSides","_s","_g","_grp","_u","_unit","_side"]; - // Cache current selection - _curSelData = _tree tvData (tvCurSel _tree); - - // Clear the tree - tvClear _tree; - - // Update the tree from the unit list + // Cache existing group and side nodes and cull removed data + _cachedUnits = []; _cachedGrps = []; _cachedSides = []; + for "_s" from 0 to ((_tree tvCount []) - 1) do { + for "_g" from 0 to ((_tree tvCount [_s]) - 1) do { + _grp = groupFromNetID (_tree tvData [_s,_g]); + + if (_grp in GVAR(groupList)) then { + _cachedGrps pushBack _grp; + _cachedGrps pushBack _g; + + for "_u" from 0 to ((_tree tvCount [_s,_g])) do { + _unit = objectFromNetId (_tree tvData [_s,_g,_u]); + + if (_unit in GVAR(unitList)) then { + _cachedUnits pushBack _unit; + } else { + _tree tvDelete [_s,_g,_u]; + }; + }; + } else { + _tree tvDelete [_s,_g]; + }; + }; + + if ((_tree tvCount [_s]) > 0) then { + _cachedSides pushBack (_tree tvText [_s]); + _cachedSides pushBack _s; + } else { + _tree tvDelete [_s]; + }; + }; + + // Update the tree from the unit list { _grp = group _x; _side = [side _grp] call BIS_fnc_sideName; @@ -385,47 +411,42 @@ switch (toLower _mode) do { // Use correct side node if !(_side in _cachedSides) then { // Add side node - _sNode = _tree tvAdd [[], _side]; + _s = _tree tvAdd [[], _side]; + _tree tvExpand [_s]; _cachedSides pushBack _side; - _cachedSides pushBack _sNode; + _cachedSides pushBack _s; } else { // If side already processed, use existing node - _sNode = _cachedSides select ((_cachedSides find _side) + 1); + _s = _cachedSides select ((_cachedSides find _side) + 1); }; // Use correct group node if !(_grp in _cachedGrps) then { // Add group node - _gNode = _tree tvAdd [[_sNode], groupID _grp]; + _g = _tree tvAdd [[_s], groupID _grp]; + _tree tvSetData [[_s,_g], netID _grp]; _cachedGrps pushBack _grp; - _cachedGrps pushBack _gNode; + _cachedGrps pushBack _g; } else { // If group already processed, use existing node - _gNode = _cachedGrps select ((_cachedGrps find _grp) + 1); + _g = _cachedGrps select ((_cachedGrps find _grp) + 1); }; - _uNode = _tree tvAdd [[_sNode,_gNode], GETVAR(_x,GVAR(uName),"")]; - _tree tvSetData [[_sNode,_gNode,_uNode], netID _x]; + _u = _tree tvAdd [[_s,_g], GETVAR(_x,GVAR(uName),"")]; + _tree tvSetData [[_s,_g,_u], netID _x]; + _tree tvSetPicture [[_s,_g,_u], GETVAR(_x,GVAR(uIcon),"")]; + _tree tvSetPictureColor [[_s,_g,_u], GETVAR(_grp,GVAR(gColor),[ARR_4(1,1,1,1)])]; - // Preserve the previous selection - if (_curSelData == (_tree tvData [_sNode,_gNode,_uNode])) then { - _tree tvSetCurSel [_sNode,_gNode,_uNode]; - }; - - _tree tvSort [[_sNode,_gNode],false]; - _tree tvExpand [_sNode,_gNode]; - } forEach GVAR(unitList); - - { - if (typeName _x == "SCALAR") then { - _tree tvSort [[_x],false]; - _tree tvExpand [_x]; - }; - } forEach _cachedSides; + _tree tvSort [[_s,_g],false]; + } forEach (GVAR(unitList) - _cachedUnits); _tree tvSort [[],false]; + + if ((_tree tvCount []) <= 0) then { + _tree tvAdd [[], localize LSTRING(units_none)]; + }; }; // Map events case "onmapclick": { @@ -439,7 +460,7 @@ switch (toLower _mode) do { [nil,nil,nil, _newPos] call FUNC(setCameraAttributes); }; }; - // Break from interface for eexternal events + // Break from interface for external events case "escape": { _args params ["_display"]; private "_dlg"; From f59536b5a3c26c1bee28f77ae01c8d739c06ad19 Mon Sep 17 00:00:00 2001 From: SilentSpike Date: Fri, 7 Aug 2015 00:28:54 +0100 Subject: [PATCH 23/91] Remove legacy spectator settings module argument --- addons/spectator/CfgVehicles.hpp | 6 ------ addons/spectator/functions/fnc_moduleSpectatorSettings.sqf | 1 - 2 files changed, 7 deletions(-) diff --git a/addons/spectator/CfgVehicles.hpp b/addons/spectator/CfgVehicles.hpp index b63f349b0a..f6869462ac 100644 --- a/addons/spectator/CfgVehicles.hpp +++ b/addons/spectator/CfgVehicles.hpp @@ -109,12 +109,6 @@ class CfgVehicles { }; }; }; - class unitIcons { - displayName = CSTRING(icons_DisplayName); - description = CSTRING(icons_Description); - typeName = "BOOL"; - defaultValue = 1; - }; }; class ModuleDescription { description = CSTRING(Settings_Description); diff --git a/addons/spectator/functions/fnc_moduleSpectatorSettings.sqf b/addons/spectator/functions/fnc_moduleSpectatorSettings.sqf index c23fb7ad20..52b6e5d8fa 100644 --- a/addons/spectator/functions/fnc_moduleSpectatorSettings.sqf +++ b/addons/spectator/functions/fnc_moduleSpectatorSettings.sqf @@ -23,4 +23,3 @@ if !(_activated) exitWith {}; [_logic, QGVAR(filterSides), "sidesFilter"] call EFUNC(common,readSettingFromModule); [_logic, QGVAR(restrictModes), "cameraModes"] call EFUNC(common,readSettingFromModule); [_logic, QGVAR(restrictVisions), "visionModes"] call EFUNC(common,readSettingFromModule); -[_logic, QGVAR(unitIcons), "unitIcons"] call EFUNC(common,readSettingFromModule); From 043c5c47c5765c64d32e8df23d408db87a8df75b Mon Sep 17 00:00:00 2001 From: SilentSpike Date: Fri, 7 Aug 2015 01:44:32 +0100 Subject: [PATCH 24/91] Improve spectator help window layout Having the help window in the centre of the screen blocked too much of the users view and also clashed with the MPTable element (the table that appears on death, aka "respawnDialog"). It was moved to the right of the screen and now mirrors the unit list. To save screen space, the action keys are given as tooltips for the listbox entries so users must mouse over for more info. --- addons/spectator/UI/interface.hpp | 53 +++++++++++-------- .../functions/fnc_handleInterface.sqf | 39 +++++++------- 2 files changed, 50 insertions(+), 42 deletions(-) diff --git a/addons/spectator/UI/interface.hpp b/addons/spectator/UI/interface.hpp index ea5f5f0e53..5dbea22273 100644 --- a/addons/spectator/UI/interface.hpp +++ b/addons/spectator/UI/interface.hpp @@ -10,7 +10,7 @@ class RscFrame { class RscButtonMenu; class RscControlsGroupNoScrollbars; //class RscFrame; -class RscListNBox; +class RscListBox; class RscMapControl; class RscPicture; class RscText; @@ -163,12 +163,13 @@ class GVAR(interface) { h = safeZoneH - TOOL_H * 13; sizeEx = H_PART(0.8); borderSize = 1; + colorText[] = {COL_FORE}; colorBorder[] = {COL_FORE}; colorBackground[] = {COL_BACK}; colorSelect[] = { - "(profilenamespace getvariable ['GUI_BCG_RGB_R',0.77])", - "(profilenamespace getvariable ['GUI_BCG_RGB_G',0.51])", - "(profilenamespace getvariable ['GUI_BCG_RGB_B',0.08])", + QUOTE(GETPRVAR(GUI_BCG_RGB_R,0.77)), + QUOTE(GETPRVAR(GUI_BCG_RGB_G,0.51)), + QUOTE(GETPRVAR(GUI_BCG_RGB_B,0.08)), 1 }; multiselectEnabled = 0; @@ -184,35 +185,43 @@ class GVAR(interface) { onMouseButtonDown = QUOTE([ARR_2('onMapClick',_this)] call FUNC(handleInterface)); onDraw = QUOTE(_this call FUNC(handleMap)); }; - class helpSplash: RscControlsGroupNoScrollbars { + class helpWindow: RscControlsGroupNoScrollbars { idc = IDC_HELP; - x = 0.5 - W_PART(12); - y = 0.5 - H_PART(12); - w = W_PART(24); - h = H_PART(24); + x = safeZoneX + safeZoneW - TOOL_W * 2; + y = safeZoneY + TOOL_H * 6; + w = TOOL_W * 2; + h = safeZoneH - TOOL_H * 13; + colorText[] = {COL_FORE}; + colorSelectBackground[] = {COL_FORE_D}; + colorSelectBackground2[] = {COL_BACK}; + colorBackground[] = {0,0,0,0}; class controls { - class helpBack: RscText { + class helpTitle: RscText { x = 0; y = 0; - w = W_PART(24); - h = H_PART(24); - colorBackground[] = {COL_BACK}; - }; - class helpTitle: helpBack { + w = TOOL_W * 2; h = H_PART(1); - colorText[]={COL_FORE}; + colorText[] = {COL_FORE}; colorBackground[] = {COL_FORE_D}; sizeEx = H_PART(1); text = CSTRING(HelpTitle); }; - class helpContent: RscListNBox { + class helpContent: RscListBox { idc = IDC_HELP_LIST; - x = W_PART(1); - y = H_PART(2); - W = W_PART(22); - H = H_PART(21); + x = 0; + y = H_PART(1); + w = TOOL_W * 2; + h = safeZoneH - TOOL_H * 14; + colorBackground[] = {COL_BACK}; default = 1; - columns[] = {0.01,0.5}; + }; + class helpFrame: RscText { + x = 0; + y = 0; + w = TOOL_W * 2; + h = safeZoneH - TOOL_H * 13; + colorText[] = {COL_FORE}; + style = 64; }; }; }; diff --git a/addons/spectator/functions/fnc_handleInterface.sqf b/addons/spectator/functions/fnc_handleInterface.sqf index 9687ba8b2a..ef3363b72c 100644 --- a/addons/spectator/functions/fnc_handleInterface.sqf +++ b/addons/spectator/functions/fnc_handleInterface.sqf @@ -117,27 +117,27 @@ switch (toLower _mode) do { // Handle unit icons on map and 3D GVAR(iconHandler) = addMissionEventHandler ["Draw3D",FUNC(handleIcons)]; - // Populate the help splash + // Populate the help window private "_help"; _help = (_display displayCtrl IDC_HELP) controlsGroupCtrl IDC_HELP_LIST; { - // Add space before category titles - if (count _x == 1) then { - _help lnbAddRow [""]; + _i = _help lbAdd (_x select 0); + if ((_x select 1) == "") then { + _help lbSetPicture [_i,"\A3\ui_f\data\map\markers\military\dot_CA.paa"]; + _help lbSetPictureColor [_i,[COL_FORE]]; + } else { + _help lbSetTooltip [_i,_x select 1]; }; - - _help lnbAddRow _x; } forEach [ [localize LSTRING(uiControls),""], - [localize LSTRING(uiToggleHelp),"H"], - [localize LSTRING(uiToggleMap),"M"], [localize LSTRING(uiToggleUnits),"1"], - [localize LSTRING(uiToggleTools),"2"], - [localize LSTRING(uiToggleCompass),"3"], - [localize LSTRING(uiToggleIcons),"4"], + [localize LSTRING(uiToggleHelp),"2"], + [localize LSTRING(uiToggleTools),"3"], + [localize LSTRING(uiToggleCompass),"4"], + [localize LSTRING(uiToggleIcons),"5"], + [localize LSTRING(uiToggleMap),"M"], [localize LSTRING(uiToggleInterface),"Backspace"], - - [localize LSTRING(freeCamControls)], + [localize LSTRING(freeCamControls),""], [localize LSTRING(freeCamForward),"W"], [localize LSTRING(freeCamBackward),"S"], [localize LSTRING(freeCamLeft),"A"], @@ -150,8 +150,7 @@ switch (toLower _mode) do { [localize LSTRING(freeCamZoom),"Ctrl + Scrollwheel"], [localize LSTRING(freeCamNextVis),"N"], [localize LSTRING(freeCamPrevVis),"Ctrl + N"], - - [localize LSTRING(otherControls)], + [localize LSTRING(otherControls),""], [localize LSTRING(nextCam),"Up Arrow"], [localize LSTRING(prevCam),"Down Arrow"], [localize LSTRING(nextUnit),"Right Arrow"], @@ -250,12 +249,15 @@ switch (toLower _mode) do { [_display,nil,nil,nil,nil,nil,true] call FUNC(toggleInterface); }; case 3: { // 2 - [_display,nil,nil,nil,nil,true] call FUNC(toggleInterface); + [_display,nil,true] call FUNC(toggleInterface); }; case 4: { // 3 - [_display,true] call FUNC(toggleInterface); + [_display,nil,nil,nil,nil,true] call FUNC(toggleInterface); }; case 5: { // 4 + [_display,true] call FUNC(toggleInterface); + }; + case 6: { // 5 GVAR(showIcons) = !GVAR(showIcons); }; case 14: { // Backspace @@ -279,9 +281,6 @@ switch (toLower _mode) do { case 32: { // D GVAR(camDolly) set [0, GVAR(camSpeed)]; }; - case 35: { // H - [_display,nil,true] call FUNC(toggleInterface); - }; case 44: { // Z GVAR(camBoom) = -0.5 * GVAR(camSpeed); }; From 485f9438bb1e2aa56e908156b0a7fd5f883a69d5 Mon Sep 17 00:00:00 2001 From: SilentSpike Date: Fri, 7 Aug 2015 01:51:46 +0100 Subject: [PATCH 25/91] Change spectator UI toggle to include help window With new layout of help window the toggle UX also changes. User expects help window to toggle as part of overall UI. --- .../spectator/functions/fnc_toggleInterface.sqf | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/addons/spectator/functions/fnc_toggleInterface.sqf b/addons/spectator/functions/fnc_toggleInterface.sqf index 609c7cd757..4a03de4271 100644 --- a/addons/spectator/functions/fnc_toggleInterface.sqf +++ b/addons/spectator/functions/fnc_toggleInterface.sqf @@ -31,17 +31,8 @@ _map = _display displayCtrl IDC_MAP; _tool = _display displayCtrl IDC_TOOL; _unit = _display displayCtrl IDC_UNIT; -// Map and help operate outside of interface -GVAR(showHelp) = [GVAR(showHelp), !GVAR(showHelp)] select _toggleHelp; +// Map operates outside of interface GVAR(showMap) = [GVAR(showMap), !GVAR(showMap)] select _toggleMap; - -// When help changes with map open, minimise the map -if (GVAR(showMap) && _toggleHelp) then { - GVAR(showHelp) = true; - GVAR(showMap) = false; -}; - -_help ctrlShow GVAR(showHelp); _map ctrlShow GVAR(showMap); if (GVAR(showMap)) then { @@ -62,16 +53,18 @@ if (GVAR(showMap)) then { if (GVAR(showInterface)) then { // Can only toggle interface elements with interface shown GVAR(showComp) = [GVAR(showComp), !GVAR(showComp)] select _toggleComp; + GVAR(showHelp) = [GVAR(showHelp), !GVAR(showHelp)] select _toggleHelp; GVAR(showTool) = [GVAR(showTool), !GVAR(showTool)] select _toggleTool; GVAR(showUnit) = [GVAR(showUnit), !GVAR(showUnit)] select _toggleUnit; _comp ctrlShow GVAR(showComp); + _help ctrlShow GVAR(showHelp); _tool ctrlShow GVAR(showTool); _unit ctrlShow GVAR(showUnit); } else { { _x ctrlShow false; - } forEach [_comp,_tool,_unit]; + } forEach [_comp,_help,_tool,_unit]; }; }; From da97472600fa5f78668e6b855c2f0823133f0414 Mon Sep 17 00:00:00 2001 From: Michael Braun Date: Fri, 7 Aug 2015 12:56:10 +0200 Subject: [PATCH 26/91] Added ace specific logging methods --- addons/main/script_macros.hpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/addons/main/script_macros.hpp b/addons/main/script_macros.hpp index e67c45e675..78205a8d11 100644 --- a/addons/main/script_macros.hpp +++ b/addons/main/script_macros.hpp @@ -97,5 +97,9 @@ // Time functions for accuracy per frame #define ACE_tickTime (ACE_time + (diag_tickTime - ACE_diagTime)) +#define ACE_LOG(module,level,message) diag_log text format [QUOTE([ACE] (%1) %2: %3), module, level, message]; +#define ACE_LOGERROR(message) ACE_LOG(QUOTE(COMPONENT),"ERROR",message) +#define ACE_LOGWARNING(message) ACE_LOG(QUOTE(COMPONENT),"WARNING",message) +#define ACE_LOGINFO(message) ACE_LOG(QUOTE(COMPONENT),"INFO",message) -#include "script_debug.hpp" \ No newline at end of file +#include "script_debug.hpp" From f143db7fc067133e53e81897ff614297a5a25109 Mon Sep 17 00:00:00 2001 From: SilentSpike Date: Fri, 7 Aug 2015 12:07:22 +0100 Subject: [PATCH 27/91] Draw player names on spectator map --- addons/spectator/UI/interface.hpp | 6 +++--- addons/spectator/functions/fnc_handleMap.sqf | 5 +++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/addons/spectator/UI/interface.hpp b/addons/spectator/UI/interface.hpp index 5dbea22273..51105b216b 100644 --- a/addons/spectator/UI/interface.hpp +++ b/addons/spectator/UI/interface.hpp @@ -167,9 +167,9 @@ class GVAR(interface) { colorBorder[] = {COL_FORE}; colorBackground[] = {COL_BACK}; colorSelect[] = { - QUOTE(GETPRVAR(GUI_BCG_RGB_R,0.77)), - QUOTE(GETPRVAR(GUI_BCG_RGB_G,0.51)), - QUOTE(GETPRVAR(GUI_BCG_RGB_B,0.08)), + "profilenamespace getvariable ['GUI_BCG_RGB_R',0.77]", + "profilenamespace getvariable ['GUI_BCG_RGB_G',0.51]", + "profilenamespace getvariable ['GUI_BCG_RGB_B',0.08]", 1 }; multiselectEnabled = 0; diff --git a/addons/spectator/functions/fnc_handleMap.sqf b/addons/spectator/functions/fnc_handleMap.sqf index a0000718bd..4eeb5fd7e1 100644 --- a/addons/spectator/functions/fnc_handleMap.sqf +++ b/addons/spectator/functions/fnc_handleMap.sqf @@ -18,7 +18,7 @@ #include "script_component.hpp" params ["_map"]; -private ["_cachedVehicles","_unit","_color","_icon"]; +private ["_cachedVehicles","_unit","_color","_icon","_txt"]; if (GVAR(camMode) == 0) then { _map drawIcon ["\A3\UI_F\Data\GUI\Rsc\RscDisplayMissionEditor\iconcamera_ca.paa",[0,0,0,1],GVAR(camera),20,20,GVAR(camPan)]; @@ -39,8 +39,9 @@ _cachedVehicles = []; // Function has caching built in _color = [side effectiveCommander _unit] call BIS_fnc_sideColor; _icon = GETVAR(_unit,GVAR(uIcon),""); + _txt = ["", GETVAR(_x,GVAR(uName),"")] select (isPlayer _x); - _map drawIcon [_icon, _color, _unit, 19, 19, getDir _unit]; + _map drawIcon [_icon, _color, _unit, 19, 19, getDir _unit, _txt, 1, 0.03]; }; false } count GVAR(unitList); From 702e50b731fd849c59a1ee1a7e531601ff703b52 Mon Sep 17 00:00:00 2001 From: SilentSpike Date: Fri, 7 Aug 2015 12:30:50 +0100 Subject: [PATCH 28/91] Improve spectator UI respawn counter blending When the BI respawn counter is blended with the spectator UI its colours are also updated to match --- addons/spectator/functions/fnc_handleInterface.sqf | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/addons/spectator/functions/fnc_handleInterface.sqf b/addons/spectator/functions/fnc_handleInterface.sqf index ef3363b72c..db701366b0 100644 --- a/addons/spectator/functions/fnc_handleInterface.sqf +++ b/addons/spectator/functions/fnc_handleInterface.sqf @@ -176,7 +176,11 @@ switch (toLower _mode) do { _back ctrlSetPosition [_x,_y,TOOL_W,TOOL_H]; _timer ctrlSetPosition [_x,_y,TOOL_W,TOOL_H]; _frame ctrlSetPosition [_x,_y,TOOL_W,TOOL_H]; + + _title ctrlSetBackgroundColor [0,0,0,0]; + _back ctrlSetBackgroundColor [COL_BACK]; _timer ctrlSetFontHeight TOOL_H; + _frame ctrlSetTextColor [COL_FORE]; _title ctrlCommit 0; _back ctrlCommit 0; From 1c79c8fa45fc55c85cd90458803879ae22a8e6de Mon Sep 17 00:00:00 2001 From: SilentSpike Date: Fri, 7 Aug 2015 15:15:04 +0100 Subject: [PATCH 29/91] Update spectator UI styling Adds a title to the unit tree to match the help list and enters the title text. --- addons/spectator/UI/interface.hpp | 67 +++++++++++++------ .../spectator/functions/fnc_handleUnits.sqf | 2 +- addons/spectator/script_component.hpp | 5 +- addons/spectator/stringtable.xml | 3 + 4 files changed, 53 insertions(+), 24 deletions(-) diff --git a/addons/spectator/UI/interface.hpp b/addons/spectator/UI/interface.hpp index 51105b216b..a7790d6da0 100644 --- a/addons/spectator/UI/interface.hpp +++ b/addons/spectator/UI/interface.hpp @@ -137,11 +137,11 @@ class GVAR(interface) { idc = -1; style = 64; }; - class fovTool: viewTool { + class zoomTool: viewTool { idc = IDC_TOOL_FOV; x = safeZoneW - TOOL_W * 2 - MARGIN; }; - class fovFrame: fovTool { + class zoomFrame: zoomTool { idc = -1; style = 64; }; @@ -155,25 +155,52 @@ class GVAR(interface) { }; }; }; - class unitTree: RscTree { + class unitTree: RscControlsGroupNoScrollbars { idc = IDC_UNIT; x = safeZoneX; y = safeZoneY + TOOL_H * 6; w = TOOL_W * 2; h = safeZoneH - TOOL_H * 13; - sizeEx = H_PART(0.8); - borderSize = 1; - colorText[] = {COL_FORE}; - colorBorder[] = {COL_FORE}; - colorBackground[] = {COL_BACK}; - colorSelect[] = { - "profilenamespace getvariable ['GUI_BCG_RGB_R',0.77]", - "profilenamespace getvariable ['GUI_BCG_RGB_G',0.51]", - "profilenamespace getvariable ['GUI_BCG_RGB_B',0.08]", - 1 + class controls { + class unitTitle: RscText { + x = 0; + y = 0; + w = TOOL_W * 2; + h = H_PART(1); + style = 2; + colorText[] = {COL_FORE}; + colorBackground[] = {COL_FORE_D}; + sizeEx = H_PART(1); + text = CSTRING(UnitTitle); + }; + class unitTree: RscTree { + idc = IDC_UNIT_TREE; + x = 0; + y = H_PART(1); + w = TOOL_W * 2; + h = safeZoneH - TOOL_H * 14; + sizeEx = H_PART(0.8); + colorText[] = {COL_FORE}; + colorBorder[] = {0,0,0,0}; + colorBackground[] = {COL_BACK}; + colorSelect[] = { + "profilenamespace getvariable ['GUI_BCG_RGB_R',0.77]", + "profilenamespace getvariable ['GUI_BCG_RGB_G',0.51]", + "profilenamespace getvariable ['GUI_BCG_RGB_B',0.08]", + 1 + }; + multiselectEnabled = 0; + onTreeDblClick = QUOTE([ARR_2('onTreeDblClick',_this)] call FUNC(handleInterface)); + }; + class unitFrame: RscFrame { + x = 0; + y = 0; + w = TOOL_W * 2; + h = safeZoneH - TOOL_H * 13; + shadow = 2; + colorText[] = {COL_FORE}; + }; }; - multiselectEnabled = 0; - onTreeDblClick = QUOTE([ARR_2('onTreeDblClick',_this)] call FUNC(handleInterface)); }; class mapOverlay: RscMapControl { idc = IDC_MAP; @@ -191,16 +218,13 @@ class GVAR(interface) { y = safeZoneY + TOOL_H * 6; w = TOOL_W * 2; h = safeZoneH - TOOL_H * 13; - colorText[] = {COL_FORE}; - colorSelectBackground[] = {COL_FORE_D}; - colorSelectBackground2[] = {COL_BACK}; - colorBackground[] = {0,0,0,0}; class controls { class helpTitle: RscText { x = 0; y = 0; w = TOOL_W * 2; h = H_PART(1); + style = 2; colorText[] = {COL_FORE}; colorBackground[] = {COL_FORE_D}; sizeEx = H_PART(1); @@ -213,15 +237,16 @@ class GVAR(interface) { w = TOOL_W * 2; h = safeZoneH - TOOL_H * 14; colorBackground[] = {COL_BACK}; + sizeEx = H_PART(0.8); default = 1; }; - class helpFrame: RscText { + class helpFrame: RscFrame { x = 0; y = 0; w = TOOL_W * 2; h = safeZoneH - TOOL_H * 13; + shadow = 2; colorText[] = {COL_FORE}; - style = 64; }; }; }; diff --git a/addons/spectator/functions/fnc_handleUnits.sqf b/addons/spectator/functions/fnc_handleUnits.sqf index e8cd561da0..c32961024c 100644 --- a/addons/spectator/functions/fnc_handleUnits.sqf +++ b/addons/spectator/functions/fnc_handleUnits.sqf @@ -36,5 +36,5 @@ if !(GVAR(camUnit) in GVAR(unitList)) then { // Reduce overhead when unit tree is hidden if (ctrlShown (_display displayCtrl IDC_UNIT)) then { // Reduce overhead by spreading across frames - [FUNC(handleInterface),["onUnitsUpdate",[_display displayCtrl IDC_UNIT]],1] call EFUNC(common,waitAndExecute); + [FUNC(handleInterface),["onUnitsUpdate",[(_display displayCtrl IDC_UNIT) controlsGroupCtrl IDC_UNIT_TREE]],1] call EFUNC(common,waitAndExecute); }; diff --git a/addons/spectator/script_component.hpp b/addons/spectator/script_component.hpp index a726c6c67f..de2ee22363 100644 --- a/addons/spectator/script_component.hpp +++ b/addons/spectator/script_component.hpp @@ -49,8 +49,9 @@ #define IDC_TOOL_VISION 3004 #define IDC_UNIT 6002 +#define IDC_UNIT_TREE 6005 // UI colours -#define COL_BACK 0.1,0.1,0.1,0.8 +#define COL_BACK 0.1,0.1,0.1,0.7 #define COL_FORE 1,1,1,1 -#define COL_FORE_D 0.1,0.1,0.1,1 +#define COL_FORE_D 0.1,0.1,0.1,0.8 diff --git a/addons/spectator/stringtable.xml b/addons/spectator/stringtable.xml index 4d615d4e1e..30af5d1aa6 100644 --- a/addons/spectator/stringtable.xml +++ b/addons/spectator/stringtable.xml @@ -101,6 +101,9 @@ Termowizja + + Spectator Units + Spectator Controls Sterowanie obserwatorem From c5d9ec5d500a83db1bc3e85c4dc9c005f89f8fb0 Mon Sep 17 00:00:00 2001 From: SilentSpike Date: Fri, 7 Aug 2015 18:59:48 +0100 Subject: [PATCH 30/91] Add speed boost button to spectator free camera Sometimes you just want a burst of speed rather than to adjust it and then adjust it back. Also swapped the speed/zoom scrolling modifier around. --- .../functions/fnc_handleInterface.sqf | 33 ++++++++++--------- addons/spectator/stringtable.xml | 3 ++ 2 files changed, 21 insertions(+), 15 deletions(-) diff --git a/addons/spectator/functions/fnc_handleInterface.sqf b/addons/spectator/functions/fnc_handleInterface.sqf index db701366b0..80d87cf40a 100644 --- a/addons/spectator/functions/fnc_handleInterface.sqf +++ b/addons/spectator/functions/fnc_handleInterface.sqf @@ -114,7 +114,7 @@ switch (toLower _mode) do { // Keep unit list and tree up to date [FUNC(handleUnits), 21, _display] call CBA_fnc_addPerFrameHandler; - // Handle unit icons on map and 3D + // Handle 3D unit icons GVAR(iconHandler) = addMissionEventHandler ["Draw3D",FUNC(handleIcons)]; // Populate the help window @@ -146,8 +146,9 @@ switch (toLower _mode) do { [localize LSTRING(freeCamDown),"Z"], [localize LSTRING(freeCamPan),"RMB (Hold)"], [localize LSTRING(freeCamDolly),"LMB (Hold)"], - [localize LSTRING(freeCamSpeed),"Scrollwheel"], - [localize LSTRING(freeCamZoom),"Ctrl + Scrollwheel"], + [localize LSTRING(freeCamZoom),"Scrollwheel"], + [localize LSTRING(freeCamSpeed),"Ctrl + Scrollwheel"], + [localize LSTRING(freeCamBoost),"Shift (Hold)"], [localize LSTRING(freeCamNextVis),"N"], [localize LSTRING(freeCamPrevVis),"Ctrl + N"], [localize LSTRING(otherControls),""], @@ -220,9 +221,9 @@ switch (toLower _mode) do { // Scroll to change speed, modifier for zoom if (GVAR(ctrlKey)) then { - [nil,nil,nil,nil,nil,nil, GVAR(camZoom) + _zChange * 0.1] call FUNC(setCameraAttributes); - } else { [nil,nil,nil,nil,nil,nil,nil, GVAR(camSpeed) + _zChange * 0.2] call FUNC(setCameraAttributes); + } else { + [nil,nil,nil,nil,nil,nil, GVAR(camZoom) + _zChange * 0.1] call FUNC(setCameraAttributes); }; }; case "onmousemoving": { @@ -268,31 +269,33 @@ switch (toLower _mode) do { [_display,nil,nil,true] call FUNC(toggleInterface); }; case 16: { // Q - GVAR(camBoom) = 0.5 * GVAR(camSpeed); + GVAR(camBoom) = 0.5 * GVAR(camSpeed) * ([1, 2] select _shift); }; case 17: { // W - GVAR(camDolly) set [1, GVAR(camSpeed)]; + GVAR(camDolly) set [1, GVAR(camSpeed) * ([1, 2] select _shift)]; }; case 29: { // Ctrl GVAR(ctrlKey) = true; }; case 30: { // A - GVAR(camDolly) set [0, -GVAR(camSpeed)]; + GVAR(camDolly) set [0, -GVAR(camSpeed) * ([1, 2] select _shift)]; }; case 31: { // S - GVAR(camDolly) set [1, -GVAR(camSpeed)]; + GVAR(camDolly) set [1, -GVAR(camSpeed) * ([1, 2] select _shift)]; }; case 32: { // D - GVAR(camDolly) set [0, GVAR(camSpeed)]; + GVAR(camDolly) set [0, GVAR(camSpeed) * ([1, 2] select _shift)]; }; case 44: { // Z - GVAR(camBoom) = -0.5 * GVAR(camSpeed); + GVAR(camBoom) = -0.5 * GVAR(camSpeed) * ([1, 2] select _shift); }; case 49: { // N - if (_ctrl) then { - [nil,nil,-1] call FUNC(cycleCamera); - } else { - [nil,nil,1] call FUNC(cycleCamera); + if (GVAR(camMode) == 0) then { + if (_ctrl) then { + [nil,nil,-1] call FUNC(cycleCamera); + } else { + [nil,nil,1] call FUNC(cycleCamera); + }; }; }; case 50: { // M diff --git a/addons/spectator/stringtable.xml b/addons/spectator/stringtable.xml index 30af5d1aa6..b174608d03 100644 --- a/addons/spectator/stringtable.xml +++ b/addons/spectator/stringtable.xml @@ -181,6 +181,9 @@ Speed +/- Prędkość +/- + + Speed Boost + Next Vision Mode Następny tryb wizji From 57bda372f0f221f049ecbeebf9d9f0d2ff88ae15 Mon Sep 17 00:00:00 2001 From: SilentSpike Date: Fri, 7 Aug 2015 19:00:31 +0100 Subject: [PATCH 31/91] Adjust spectator free camera speed with zoom --- addons/spectator/functions/fnc_handleCamera.sqf | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/addons/spectator/functions/fnc_handleCamera.sqf b/addons/spectator/functions/fnc_handleCamera.sqf index 7f53b59009..1d1d5bef9e 100644 --- a/addons/spectator/functions/fnc_handleCamera.sqf +++ b/addons/spectator/functions/fnc_handleCamera.sqf @@ -23,9 +23,9 @@ if (isNil QGVAR(camHandler)) exitWith { [_this select 1] call CBA_fnc_removePerF private ["_oldPos","_mX","_mY","_mZ","_pan","_x","_y","_z"]; _oldPos = getPosASL GVAR(camera); -_mX = GVAR(camDolly) select 0; -_mY = GVAR(camDolly) select 1; -_mZ = GVAR(camBoom); +_mX = (GVAR(camDolly) select 0) / ((GVAR(camZoom) * 0.8) max 1); +_mY = (GVAR(camDolly) select 1) / ((GVAR(camZoom) * 0.8) max 1); +_mZ = GVAR(camBoom) / ((GVAR(camZoom) * 0.8) max 1); _pan = (GVAR(camPan) + 360) % 360; _x = (_oldPos select 0) + (_mX * cos(_pan)) + (_mY * sin(_pan)); From e59f0ce822ab64c8a8fd6c330341e16113437282 Mon Sep 17 00:00:00 2001 From: SilentSpike Date: Sat, 8 Aug 2015 12:24:49 +0100 Subject: [PATCH 32/91] Fix spectator respawn template for types 0 and 1 Type 0 worked, but the mission didn't end when all players were killed. Type 1 didn't work because isPlayer isn't true for seagulls. So spectator virtual state is now entirely unassociated from objects in the game. --- .../functions/fnc_handleInterface.sqf | 2 +- .../functions/fnc_respawnTemplate.sqf | 11 +++++--- .../spectator/functions/fnc_setSpectator.sqf | 26 +++++++------------ .../functions/fnc_stageSpectator.sqf | 9 +++---- 4 files changed, 22 insertions(+), 26 deletions(-) diff --git a/addons/spectator/functions/fnc_handleInterface.sqf b/addons/spectator/functions/fnc_handleInterface.sqf index 80d87cf40a..d06c19bd38 100644 --- a/addons/spectator/functions/fnc_handleInterface.sqf +++ b/addons/spectator/functions/fnc_handleInterface.sqf @@ -80,7 +80,7 @@ switch (toLower _mode) do { clearRadio; // Return to player view - _unit switchCamera "internal"; + player switchCamera "internal"; // Enable BI damage effects BIS_fnc_feedback_allowPP = true; diff --git a/addons/spectator/functions/fnc_respawnTemplate.sqf b/addons/spectator/functions/fnc_respawnTemplate.sqf index b03c6dfb06..b808c43eab 100644 --- a/addons/spectator/functions/fnc_respawnTemplate.sqf +++ b/addons/spectator/functions/fnc_respawnTemplate.sqf @@ -21,6 +21,11 @@ params [["_unit",objNull,[objNull]], ["_killer",objNull,[objNull]], ["_respawn",0,[0]], ["_respawnDelay",0,[0]]]; private ["_vision","_pos"]; +// End mission when all are dead with respawn type "None" +if ((_respawn == 0) && {{alive _x} count allPlayers <= 0}) exitWith { + [["endDeath",false],"BIS_fnc_endMission"] call EFUNC(common,execRemoteFnc); +}; + if (isNull _killer) then {_killer = _unit}; _vision = [-2,-1] select (sunOrMoon < 1); _pos = (getPosATL _unit) vectorAdd [0,0,5]; @@ -29,11 +34,11 @@ if (alive _unit) then { if (_respawn == 1) then { [_unit,QGVAR(isSeagull)] call EFUNC(common,hideUnit); [2,_killer,_vision,_pos,getDir _unit] call FUNC(setCameraAttributes); - [_unit] call FUNC(setSpectator); + [true] call FUNC(setSpectator); } else { - [_unit,false] call FUNC(setSpectator); + [false] call FUNC(setSpectator); }; } else { [2,_killer,_vision,_pos,getDir _unit] call FUNC(setCameraAttributes); - [_unit] call FUNC(setSpectator); + [true] call FUNC(setSpectator); }; diff --git a/addons/spectator/functions/fnc_setSpectator.sqf b/addons/spectator/functions/fnc_setSpectator.sqf index 2d5ada415c..4f41e073d7 100644 --- a/addons/spectator/functions/fnc_setSpectator.sqf +++ b/addons/spectator/functions/fnc_setSpectator.sqf @@ -1,48 +1,42 @@ /* * Author: SilentSpike - * Sets target player to the given spectator state (virtually) + * Sets local client to the given spectator state (virtually) * To physically handle a spectator see ace_spectator_fnc_stageSpectator * - * Player will be able to communicate in ACRE/TFAR as appropriate + * Client will be able to communicate in ACRE/TFAR as appropriate * The spectator interface will be opened/closed * * Arguments: - * 0: Unit to put into spectator state - * 1: Spectator state + * 0: Spectator state of local client * * Return Value: * None * * Example: - * [player, true] call ace_spectator_fnc_setSpectator + * [true] call ace_spectator_fnc_setSpectator * * Public: Yes */ #include "script_component.hpp" -params ["_unit", ["_set",true,[true]]]; +params [["_set",true,[true]]]; -// Only run for player units -if !(isPlayer _unit) exitWith {}; - -if !(local _unit) exitwith { - [[_unit, _set], QFUNC(setSpectator), _unit] call EFUNC(common,execRemoteFnc); -}; +// Only clients can be spectators +if !(hasInterface) exitWith {}; // Handle common addon audio if (["ace_hearing"] call EFUNC(common,isModLoaded)) then {EGVAR(hearing,disableVolumeUpdate) = _set}; if (["acre_sys_radio"] call EFUNC(common,isModLoaded)) then {[_set] call acre_api_fnc_setSpectator}; -if (["task_force_radio"] call EFUNC(common,isModLoaded)) then {[_unit, _set] call TFAR_fnc_forceSpectator}; +if (["task_force_radio"] call EFUNC(common,isModLoaded)) then {[player, _set] call TFAR_fnc_forceSpectator}; if (_set) then { ["open"] call FUNC(handleInterface); } else { - ["close",_unit] call FUNC(handleInterface); + ["close"] call FUNC(handleInterface); }; // Mark spectator state for reference -_unit setVariable [QGVAR(isSet), _set, true]; GVAR(isSet) = _set; -["spectatorSet",[_set,_unit]] call EFUNC(common,localEvent); +["spectatorSet",[_set]] call EFUNC(common,localEvent); diff --git a/addons/spectator/functions/fnc_stageSpectator.sqf b/addons/spectator/functions/fnc_stageSpectator.sqf index 3e17235e3e..7f0d862719 100644 --- a/addons/spectator/functions/fnc_stageSpectator.sqf +++ b/addons/spectator/functions/fnc_stageSpectator.sqf @@ -7,7 +7,7 @@ * Upon unstage, units will be moved to the position they were in upon staging * * Arguments: - * 0: Unit to put into spectator stage + * 0: Unit to put into spectator stage * 1: Spectator stage * * Return Value: @@ -21,19 +21,16 @@ #include "script_component.hpp" -params ["_unit", ["_set",true,[true]]]; +params [["_unit",player,[objNull]], ["_set",true,[true]]]; // No change, no service (but allow spectators to be reset) if !(_set || (GETVAR(_unit,GVAR(isStaged),false))) exitWith {}; -// Only run for player units -if !(isPlayer _unit) exitWith {}; - if !(local _unit) exitwith { [[_unit, _set], QFUNC(stageSpectator), _unit] call EFUNC(common,execRemoteFnc); }; -// Prevent player falling into water +// Prevent unit falling into water _unit enableSimulation !_set; // Move to/from group as appropriate From 5b881224c5a231c35fb96d79183f240265915e89 Mon Sep 17 00:00:00 2001 From: SilentSpike Date: Sat, 8 Aug 2015 13:19:07 +0100 Subject: [PATCH 33/91] Allow admins to use chat in the spectator UI --- addons/spectator/functions/fnc_handleInterface.sqf | 3 +++ 1 file changed, 3 insertions(+) diff --git a/addons/spectator/functions/fnc_handleInterface.sqf b/addons/spectator/functions/fnc_handleInterface.sqf index d06c19bd38..21d6266fba 100644 --- a/addons/spectator/functions/fnc_handleInterface.sqf +++ b/addons/spectator/functions/fnc_handleInterface.sqf @@ -238,6 +238,9 @@ switch (toLower _mode) do { if ((alive player) && {_dik in (actionKeys "curatorInterface")} && {!isNull (getAssignedCuratorLogic player)}) exitWith { ["zeus", [_display]] call FUNC(handleInterface); }; + if ((isServer || {serverCommandAvailable "#kick"}) && {_dik in (actionKeys "Chat" + actionKeys "PrevChannel" + actionKeys "NextChannel")}) exitWith { + false + }; // Handle held keys (prevent repeat calling) if (_dik in GVAR(heldKeys)) exitwith {}; From be7b156c49170da938b120cd16d45ec7c6daa245 Mon Sep 17 00:00:00 2001 From: SilentSpike Date: Sat, 8 Aug 2015 15:49:07 +0100 Subject: [PATCH 34/91] Add "focus on unit" to spectator free camera Pressing F will move the free camera to a position viewing the unit currently selected in the list. Fixes map teleporting functionality also. --- addons/spectator/UI/interface.hpp | 23 ++++++++-------- .../functions/fnc_handleInterface.sqf | 26 +++++++++++++++++-- .../functions/fnc_setCameraAttributes.sqf | 9 ++++--- .../functions/fnc_transitionCamera.sqf | 3 +-- addons/spectator/stringtable.xml | 3 +++ 5 files changed, 45 insertions(+), 19 deletions(-) diff --git a/addons/spectator/UI/interface.hpp b/addons/spectator/UI/interface.hpp index a7790d6da0..e8bc6c210f 100644 --- a/addons/spectator/UI/interface.hpp +++ b/addons/spectator/UI/interface.hpp @@ -155,7 +155,7 @@ class GVAR(interface) { }; }; }; - class unitTree: RscControlsGroupNoScrollbars { + class unitWindow: RscControlsGroupNoScrollbars { idc = IDC_UNIT; x = safeZoneX; y = safeZoneY + TOOL_H * 6; @@ -191,6 +191,7 @@ class GVAR(interface) { }; multiselectEnabled = 0; onTreeDblClick = QUOTE([ARR_2('onTreeDblClick',_this)] call FUNC(handleInterface)); + onTreeSelChanged = QUOTE([ARR_2('onTreeSelChanged',_this)] call FUNC(handleInterface)); }; class unitFrame: RscFrame { x = 0; @@ -202,16 +203,6 @@ class GVAR(interface) { }; }; }; - class mapOverlay: RscMapControl { - idc = IDC_MAP; - type = 100; - x = safeZoneX; - y = safeZoneY; - w = safeZoneW; - h = safeZoneH; - onMouseButtonDown = QUOTE([ARR_2('onMapClick',_this)] call FUNC(handleInterface)); - onDraw = QUOTE(_this call FUNC(handleMap)); - }; class helpWindow: RscControlsGroupNoScrollbars { idc = IDC_HELP; x = safeZoneX + safeZoneW - TOOL_W * 2; @@ -250,5 +241,15 @@ class GVAR(interface) { }; }; }; + class mapOverlay: RscMapControl { + idc = IDC_MAP; + type = 100; + x = safeZoneX; + y = safeZoneY; + w = safeZoneW; + h = safeZoneH; + onMouseButtonDown = QUOTE([ARR_2('onMapClick',_this)] call FUNC(handleInterface)); + onDraw = QUOTE(_this call FUNC(handleMap)); + }; }; }; diff --git a/addons/spectator/functions/fnc_handleInterface.sqf b/addons/spectator/functions/fnc_handleInterface.sqf index 21d6266fba..eda24dccf6 100644 --- a/addons/spectator/functions/fnc_handleInterface.sqf +++ b/addons/spectator/functions/fnc_handleInterface.sqf @@ -35,6 +35,7 @@ switch (toLower _mode) do { GVAR(heldKeys) = []; GVAR(mouse) = [false,false]; GVAR(mousePos) = [0.5,0.5]; + GVAR(treeSel) = objNull; // Initalize the camera view GVAR(camera) = "Camera" camCreate (ASLtoATL GVAR(camPos)); @@ -96,6 +97,7 @@ switch (toLower _mode) do { GVAR(heldKeys) = nil; GVAR(mouse) = nil; GVAR(mousePos) = nil; + GVAR(treeSel) = nil; // Reset nametag settings if (["ace_nametags"] call EFUNC(common,isModLoaded)) then { @@ -146,11 +148,12 @@ switch (toLower _mode) do { [localize LSTRING(freeCamDown),"Z"], [localize LSTRING(freeCamPan),"RMB (Hold)"], [localize LSTRING(freeCamDolly),"LMB (Hold)"], + [localize LSTRING(freeCamFocus),"F"], + [localize LSTRING(freeCamNextVis),"N"], + [localize LSTRING(freeCamPrevVis),"Ctrl + N"], [localize LSTRING(freeCamZoom),"Scrollwheel"], [localize LSTRING(freeCamSpeed),"Ctrl + Scrollwheel"], [localize LSTRING(freeCamBoost),"Shift (Hold)"], - [localize LSTRING(freeCamNextVis),"N"], - [localize LSTRING(freeCamPrevVis),"Ctrl + N"], [localize LSTRING(otherControls),""], [localize LSTRING(nextCam),"Up Arrow"], [localize LSTRING(prevCam),"Down Arrow"], @@ -289,6 +292,14 @@ switch (toLower _mode) do { case 32: { // D GVAR(camDolly) set [0, GVAR(camSpeed) * ([1, 2] select _shift)]; }; + case 33: { // F + private ["_sel","_vector"]; + _sel = GVAR(treeSel); + if !((GVAR(camMode) == 0) && {isNull _sel} && {_sel in GVAR(unitList)}) then { + _vector = (positionCameraToWorld [0,0,0]) vectorDiff (positionCameraToWorld [0,0,25]); + [nil,nil,nil,(getPosATL _sel) vectorAdd _vector] call FUNC(setCameraAttributes); + }; + }; case 44: { // Z GVAR(camBoom) = -0.5 * GVAR(camSpeed) * ([1, 2] select _shift); }; @@ -374,6 +385,15 @@ switch (toLower _mode) do { [_newMode,_newUnit] call FUNC(transitionCamera); }; }; + case "ontreeselchanged": { + _args params ["_tree","_sel"]; + + if (count _sel == 3) then { + GVAR(treeSel) = objectFromNetId (_tree tvData _sel); + } else { + GVAR(treeSel) = objNull; + }; + }; case "onunitsupdate": { _args params ["_tree"]; private ["_cachedUnits","_cachedGrps","_cachedSides","_s","_g","_grp","_u","_unit","_side"]; @@ -485,6 +505,7 @@ switch (toLower _mode) do { GVAR(heldKeys) = []; GVAR(mouse) = [false,false]; GVAR(mousePos) = [0.5,0.5]; + GVAR(treeSel) = objNull; createDialog (["RscDisplayInterrupt", "RscDisplayMPInterrupt"] select isMultiplayer); @@ -538,6 +559,7 @@ switch (toLower _mode) do { GVAR(heldKeys) = []; GVAR(mouse) = [false,false]; GVAR(mousePos) = [0.5,0.5]; + GVAR(treeSel) = objNull; openCuratorInterface; diff --git a/addons/spectator/functions/fnc_setCameraAttributes.sqf b/addons/spectator/functions/fnc_setCameraAttributes.sqf index 278a8c4758..8eb6fe51ac 100644 --- a/addons/spectator/functions/fnc_setCameraAttributes.sqf +++ b/addons/spectator/functions/fnc_setCameraAttributes.sqf @@ -51,7 +51,6 @@ if !(_vision in GVAR(availableVisions)) then { }; GVAR(camPan) = _heading % 360; -GVAR(camPos) = (ATLtoASL _position); GVAR(camSpeed) = (_speed max 0.05) min 10; GVAR(camTilt) = (_tilt max -89) min 89; GVAR(camUnit) = _unit; @@ -59,8 +58,10 @@ GVAR(camVision) = _vision; GVAR(camZoom) = (_zoom min 2) max 0.01; // Apply if camera exists -if !(isNil QGVAR(camera)) then { - [_mode,_unit,_vision] call FUNC(transitionCamera); -} else { +if (isNil QGVAR(camera)) then { GVAR(camMode) = _mode; + GVAR(camPos) = (ATLtoASL _position); +} else { + [_mode,_unit,_vision] call FUNC(transitionCamera); + GVAR(camera) setPosATL _position; }; diff --git a/addons/spectator/functions/fnc_transitionCamera.sqf b/addons/spectator/functions/fnc_transitionCamera.sqf index b35b61b311..72cb9f1a45 100644 --- a/addons/spectator/functions/fnc_transitionCamera.sqf +++ b/addons/spectator/functions/fnc_transitionCamera.sqf @@ -53,8 +53,7 @@ if (_newMode == 0) then { // Free GVAR(camera) camSetFov -(linearConversion [0.01,2,GVAR(camZoom),-2,-0.01,true]); GVAR(camera) camCommit 0; - // Agent is switched to in free cam to hide death table and prevent AI chat while allowing icons to draw - // However, map click events don't fire in free cam for some reason... + // Agent is switched to in free cam to hide death table and prevent AI chat while allowing icons to draw (also prevents systemChat and unit HUD) // (Why is so much stuff tied into the current camera unit BI?!) if (isNull GVAR(camAgent)) then { GVAR(camAgent) = createAgent ["VirtualMan_F",markerPos QGVAR(respawn),[],0,""]; diff --git a/addons/spectator/stringtable.xml b/addons/spectator/stringtable.xml index b174608d03..c4b9b6b631 100644 --- a/addons/spectator/stringtable.xml +++ b/addons/spectator/stringtable.xml @@ -184,6 +184,9 @@ Speed Boost + + Focus on Unit + Next Vision Mode Następny tryb wizji From d7730103c98c0cf5d677abeb42128de29e375aaf Mon Sep 17 00:00:00 2001 From: SilentSpike Date: Sat, 8 Aug 2015 17:22:04 +0100 Subject: [PATCH 35/91] Update ace_spectator readme --- addons/spectator/README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/addons/spectator/README.md b/addons/spectator/README.md index b3e586149b..b827bdcc49 100644 --- a/addons/spectator/README.md +++ b/addons/spectator/README.md @@ -1,7 +1,11 @@ ace_spectator ======= -Spectator. Includes features from Splendid Cam, and much more. +A flexible spectator framework for mission makers to use. + +Includes a public API for integration into custom respawn frameworks and a template for use with the vanilla respawn framework. + +For more information, see: http://ace3mod.com/wiki/feature/spectator.html ## Maintainers From 213deeffb405ac85138bd8376b25274922b6af02 Mon Sep 17 00:00:00 2001 From: SilentSpike Date: Sat, 8 Aug 2015 18:31:37 +0100 Subject: [PATCH 36/91] Add keys to adjust spectator camera speed and zoom Allows for finer control of the speed and zoom, as well as a quick way to reset either. --- addons/spectator/XEH_preInit.sqf | 2 +- .../functions/fnc_handleInterface.sqf | 40 ++++++++++---- addons/spectator/stringtable.xml | 53 +++++++++++-------- 3 files changed, 61 insertions(+), 34 deletions(-) diff --git a/addons/spectator/XEH_preInit.sqf b/addons/spectator/XEH_preInit.sqf index 2c29598ebc..a40f4a0dcb 100644 --- a/addons/spectator/XEH_preInit.sqf +++ b/addons/spectator/XEH_preInit.sqf @@ -33,7 +33,7 @@ GVAR(camAgent) = objNull; GVAR(camMode) = 0; GVAR(camPan) = 0; GVAR(camPos) = ATLtoASL [worldSize * 0.5, worldSize * 0.5, 20]; -GVAR(camSpeed) = 1; +GVAR(camSpeed) = 2.5; GVAR(camTilt) = -10; GVAR(camUnit) = objNull; GVAR(camVision) = -2; diff --git a/addons/spectator/functions/fnc_handleInterface.sqf b/addons/spectator/functions/fnc_handleInterface.sqf index eda24dccf6..80ee564ab5 100644 --- a/addons/spectator/functions/fnc_handleInterface.sqf +++ b/addons/spectator/functions/fnc_handleInterface.sqf @@ -148,17 +148,21 @@ switch (toLower _mode) do { [localize LSTRING(freeCamDown),"Z"], [localize LSTRING(freeCamPan),"RMB (Hold)"], [localize LSTRING(freeCamDolly),"LMB (Hold)"], - [localize LSTRING(freeCamFocus),"F"], - [localize LSTRING(freeCamNextVis),"N"], - [localize LSTRING(freeCamPrevVis),"Ctrl + N"], - [localize LSTRING(freeCamZoom),"Scrollwheel"], - [localize LSTRING(freeCamSpeed),"Ctrl + Scrollwheel"], [localize LSTRING(freeCamBoost),"Shift (Hold)"], - [localize LSTRING(otherControls),""], + [localize LSTRING(freeCamFocus),"F"], + [localize LSTRING(attributeControls),""], [localize LSTRING(nextCam),"Up Arrow"], [localize LSTRING(prevCam),"Down Arrow"], [localize LSTRING(nextUnit),"Right Arrow"], - [localize LSTRING(prevUnit),"Left Arrow"] + [localize LSTRING(prevUnit),"Left Arrow"], + [localize LSTRING(nextVis),"N"], + [localize LSTRING(prevVis),"Ctrl + N"], + [localize LSTRING(adjZoom),"Scrollwheel"], + [localize LSTRING(adjSpeed),"Ctrl + Scrollwheel"], + [localize LSTRING(incZoom),"Num-/Num+"], + [localize LSTRING(incSpeed),"Ctrl + Num-/Num+"], + [localize LSTRING(reZoom),"Alt + Num-"], + [localize LSTRING(reSpeed),"Alt + Num+"] ]; // Handle support for BI's respawn counter @@ -247,8 +251,8 @@ switch (toLower _mode) do { // Handle held keys (prevent repeat calling) if (_dik in GVAR(heldKeys)) exitwith {}; - // Exclude movement keys so that speed can be adjusted on fly - if !(_dik in [16,17,30,31,32,44]) then { + // Exclude movement/adjustment keys so that speed can be adjusted on fly + if !(_dik in [16,17,30,31,32,44,74,78]) then { GVAR(heldKeys) pushBack _dik; }; @@ -295,7 +299,7 @@ switch (toLower _mode) do { case 33: { // F private ["_sel","_vector"]; _sel = GVAR(treeSel); - if !((GVAR(camMode) == 0) && {isNull _sel} && {_sel in GVAR(unitList)}) then { + if ((GVAR(camMode) == 0) && {!isNull _sel} && {_sel in GVAR(unitList)}) then { _vector = (positionCameraToWorld [0,0,0]) vectorDiff (positionCameraToWorld [0,0,25]); [nil,nil,nil,(getPosATL _sel) vectorAdd _vector] call FUNC(setCameraAttributes); }; @@ -318,6 +322,22 @@ switch (toLower _mode) do { case 57: { // Spacebar // Freecam attachment here, if in external then set cam pos and attach }; + case 74: { // Num - + if (_alt) exitWith { [nil,nil,nil,nil,nil,nil, 1.25] call FUNC(setCameraAttributes); }; + if (_ctrl) then { + [nil,nil,nil,nil,nil,nil,nil, GVAR(camSpeed) - 0.05] call FUNC(setCameraAttributes); + } else { + [nil,nil,nil,nil,nil,nil, GVAR(camZoom) - 0.01] call FUNC(setCameraAttributes); + }; + }; + case 78: { // Num + + if (_alt) exitWith { [nil,nil,nil,nil,nil,nil,nil, 2.5] call FUNC(setCameraAttributes); }; + if (_ctrl) then { + [nil,nil,nil,nil,nil,nil,nil, GVAR(camSpeed) + 0.05] call FUNC(setCameraAttributes); + } else { + [nil,nil,nil,nil,nil,nil, GVAR(camZoom) + 0.01] call FUNC(setCameraAttributes); + }; + }; case 200: { // Up arrow [-1] call FUNC(cycleCamera); }; diff --git a/addons/spectator/stringtable.xml b/addons/spectator/stringtable.xml index c4b9b6b631..895a279844 100644 --- a/addons/spectator/stringtable.xml +++ b/addons/spectator/stringtable.xml @@ -134,8 +134,7 @@ - Free Camera Controls - Wolne sterowanie kamerą + Free Camera Camera Forward @@ -173,31 +172,14 @@ Lock Camera to Target Zablokuj kamerę na celu - - Zoom +/- - Zoom +/- - - - Speed +/- - Prędkość +/- - Speed Boost Focus on Unit - - Next Vision Mode - Następny tryb wizji - - - Previous Vision Mode - Poprzedni tryb wizji - - Interface Controls - Sterowanie interfejsem + Interface Toggle Interface @@ -227,9 +209,8 @@ Toggle Help Przełącz pomoc - - Other Controls - Pozostałe sterowanie + + Camera Attributes Next Camera @@ -247,5 +228,31 @@ Previous Unit Poprzednia jednostka + + Next Vision Mode + Następny tryb wizji + + + Previous Vision Mode + Poprzedni tryb wizji + + + Adjust Zoom + + + Adjust Speed + + + Increment Zoom + + + Increment Speed + + + Reset Zoom + + + Reset Speed + From 182eef39de65cc53d413df36db6b7286bca20c68 Mon Sep 17 00:00:00 2001 From: SilentSpike Date: Sat, 8 Aug 2015 18:41:38 +0100 Subject: [PATCH 37/91] Adjust spectator camera pan and tilt with zoom --- addons/spectator/functions/fnc_handleCamera.sqf | 11 +++++++---- addons/spectator/functions/fnc_handleMouse.sqf | 9 ++++++--- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/addons/spectator/functions/fnc_handleCamera.sqf b/addons/spectator/functions/fnc_handleCamera.sqf index 1d1d5bef9e..960a20df80 100644 --- a/addons/spectator/functions/fnc_handleCamera.sqf +++ b/addons/spectator/functions/fnc_handleCamera.sqf @@ -20,12 +20,15 @@ // Kill PFH when not in free cam (or display is closed) if (isNil QGVAR(camHandler)) exitWith { [_this select 1] call CBA_fnc_removePerFrameHandler; }; -private ["_oldPos","_mX","_mY","_mZ","_pan","_x","_y","_z"]; +private ["_oldPos","_zoomMod","_mX","_mY","_mZ","_pan","_x","_y","_z"]; _oldPos = getPosASL GVAR(camera); -_mX = (GVAR(camDolly) select 0) / ((GVAR(camZoom) * 0.8) max 1); -_mY = (GVAR(camDolly) select 1) / ((GVAR(camZoom) * 0.8) max 1); -_mZ = GVAR(camBoom) / ((GVAR(camZoom) * 0.8) max 1); + +// Dolly/Boom amount should be influnced by zoom level (it should really be exponential) +_zoomMod = (GVAR(camZoom) * 0.8) max 1; +_mX = (GVAR(camDolly) select 0) / _zoomMod; +_mY = (GVAR(camDolly) select 1) / _zoomMod; +_mZ = GVAR(camBoom) / _zoomMod; _pan = (GVAR(camPan) + 360) % 360; _x = (_oldPos select 0) + (_mX * cos(_pan)) + (_mY * sin(_pan)); diff --git a/addons/spectator/functions/fnc_handleMouse.sqf b/addons/spectator/functions/fnc_handleMouse.sqf index 8158ba95b5..1c2b62798c 100644 --- a/addons/spectator/functions/fnc_handleMouse.sqf +++ b/addons/spectator/functions/fnc_handleMouse.sqf @@ -18,7 +18,7 @@ #include "script_component.hpp" params ["_x","_y"]; -private ["_leftButton","_rightButton","_oldX","_oldY","_deltaX","_deltaY"]; +private ["_leftButton","_rightButton","_oldX","_oldY","_deltaX","_deltaY","_zoomMod"]; _leftButton = GVAR(mouse) select 0; _rightButton = GVAR(mouse) select 1; @@ -35,8 +35,11 @@ if (_leftButton) then { GVAR(camDolly) set [1, _deltaY * 100 * GVAR(camSpeed)]; } else { if (_rightButton) then { - GVAR(camPan) = GVAR(camPan) - (_deltaX * 360); - GVAR(camTilt) = ((GVAR(camTilt) + (_deltaY * 180)) min 89) max -89; + // Pan/Tilt amount should be influnced by zoom level (it should really be exponential) + _zoomMod = (GVAR(camZoom) * 0.8) max 1; + + GVAR(camPan) = GVAR(camPan) - ((_deltaX * 360) / _zoomMod); + GVAR(camTilt) = ((GVAR(camTilt) + ((_deltaY * 180) / _zoomMod)) min 89) max -89; }; }; From a6acff9178bf2a6072d9a67673ca623ccdd2c092 Mon Sep 17 00:00:00 2001 From: PabstMirror Date: Sat, 8 Aug 2015 14:40:19 -0500 Subject: [PATCH 38/91] Setting to disable hearing for zeus RC --- addons/hearing/ACE_Settings.hpp | 6 ++++++ addons/hearing/CfgVehicles.hpp | 6 ++++++ addons/hearing/functions/fnc_earRinging.sqf | 1 + addons/hearing/functions/fnc_moduleHearing.sqf | 2 ++ addons/hearing/stringtable.xml | 8 +++++++- 5 files changed, 22 insertions(+), 1 deletion(-) diff --git a/addons/hearing/ACE_Settings.hpp b/addons/hearing/ACE_Settings.hpp index 867914b857..262c3edc34 100644 --- a/addons/hearing/ACE_Settings.hpp +++ b/addons/hearing/ACE_Settings.hpp @@ -19,4 +19,10 @@ class ACE_Settings { isClientSettable = 1; displayName = CSTRING(DisableEarRinging); }; + class GVAR(enabledForZeusUnits) { + value = 1; + typeName = "BOOL"; + displayName = CSTRING(enabledForZeusUnits_DisplayName); + description = CSTRING(enabledForZeusUnits_Description); + }; }; diff --git a/addons/hearing/CfgVehicles.hpp b/addons/hearing/CfgVehicles.hpp index 44ea8f734f..2273653c3a 100644 --- a/addons/hearing/CfgVehicles.hpp +++ b/addons/hearing/CfgVehicles.hpp @@ -130,6 +130,12 @@ class CfgVehicles { }; }; }; + class enabledForZeusUnits { + displayName = CSTRING(enabledForZeusUnits_DisplayName); + description = CSTRING(enabledForZeusUnits_Description); + typeName = "BOOL"; + defaultValue = 1; + }; }; class ModuleDescription { description = CSTRING(Module_Description); diff --git a/addons/hearing/functions/fnc_earRinging.sqf b/addons/hearing/functions/fnc_earRinging.sqf index 6a896c1820..de70c4f860 100644 --- a/addons/hearing/functions/fnc_earRinging.sqf +++ b/addons/hearing/functions/fnc_earRinging.sqf @@ -21,6 +21,7 @@ PARAMS_2(_unit,_strength); if (_unit != ACE_player) exitWith {}; if (_strength < 0.05) exitWith {}; if (!isNull curatorCamera) exitWith {}; +if ((!GVAR(enabledForZeusUnits)) && {player != ACE_player}) exitWith {}; if (_unit getVariable ["ACE_hasEarPlugsin", false]) then { _strength = _strength / 4; diff --git a/addons/hearing/functions/fnc_moduleHearing.sqf b/addons/hearing/functions/fnc_moduleHearing.sqf index 6ec0af0231..fed6335c07 100644 --- a/addons/hearing/functions/fnc_moduleHearing.sqf +++ b/addons/hearing/functions/fnc_moduleHearing.sqf @@ -21,4 +21,6 @@ if ((_logic getVariable "DisableEarRinging") != -1) then { [_logic, QGVAR(DisableEarRinging), "DisableEarRinging"] call EFUNC(common,readSettingFromModule); }; +[_logic, QGVAR(enabledForZeusUnits), "enabledForZeusUnits"] call EFUNC(common,readSettingFromModule); + diag_log text "[ACE]: Hearing Module Initialized."; diff --git a/addons/hearing/stringtable.xml b/addons/hearing/stringtable.xml index a3af102580..403434cf4f 100644 --- a/addons/hearing/stringtable.xml +++ b/addons/hearing/stringtable.xml @@ -118,7 +118,7 @@ Audição - Enable combat deafness? + Combat Deafness Wł. głuchotę bojową ¿Habilitar sordera de combate? Aktiviere Taubheit im Gefecht? @@ -140,5 +140,11 @@ Ztráta sluchu je možná ve chvíly, kdy se v bezprostřední blízkosti střílí z velkorážní zbraně nebo při bombardování a osoba je bez ochrany sluchu (např. špunty). Tento modul umožňuje tuto věc povolit nebo zakázat. Este módulo ativa / desativa surdez em combate. Quando ativado, os jogadores podem ficar surdos quando uma arma é disparada ao seu redor ou uma explosão ocorre sem proteção auditiva. + + Effect Zeus RC + + + Allow zeus remote controlled units to be able to take hearing damage. + \ No newline at end of file From c30cb45bd63fc40a0f6d8087f82655ac0363227d Mon Sep 17 00:00:00 2001 From: SilentSpike Date: Sun, 9 Aug 2015 20:59:57 +0100 Subject: [PATCH 39/91] Optimize spectator UI held key prevention system --- addons/spectator/functions/fnc_handleInterface.sqf | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/addons/spectator/functions/fnc_handleInterface.sqf b/addons/spectator/functions/fnc_handleInterface.sqf index 80ee564ab5..335b71bbe1 100644 --- a/addons/spectator/functions/fnc_handleInterface.sqf +++ b/addons/spectator/functions/fnc_handleInterface.sqf @@ -33,6 +33,7 @@ switch (toLower _mode) do { // Initalize display variables GVAR(ctrlKey) = false; GVAR(heldKeys) = []; + GVAR(heldKeys) resize 255; GVAR(mouse) = [false,false]; GVAR(mousePos) = [0.5,0.5]; GVAR(treeSel) = objNull; @@ -250,10 +251,10 @@ switch (toLower _mode) do { }; // Handle held keys (prevent repeat calling) - if (_dik in GVAR(heldKeys)) exitwith {}; + if (GVAR(heldKeys) param [_dik,false]) exitwith {}; // Exclude movement/adjustment keys so that speed can be adjusted on fly if !(_dik in [16,17,30,31,32,44,74,78]) then { - GVAR(heldKeys) pushBack _dik; + GVAR(heldKeys) set [_dik,true]; }; switch (_dik) do { @@ -358,7 +359,7 @@ switch (toLower _mode) do { _args params ["_display","_dik","_shift","_ctrl","_alt"]; // No longer being held - GVAR(heldKeys) = GVAR(heldKeys) - [_dik]; + GVAR(heldKeys) set [_dik,nil]; switch (_dik) do { case 16: { // Q @@ -523,6 +524,7 @@ switch (toLower _mode) do { GVAR(ctrlKey) = false; GVAR(heldKeys) = []; + GVAR(heldKeys) resize 255; GVAR(mouse) = [false,false]; GVAR(mousePos) = [0.5,0.5]; GVAR(treeSel) = objNull; @@ -577,6 +579,7 @@ switch (toLower _mode) do { GVAR(ctrlKey) = false; GVAR(heldKeys) = []; + GVAR(heldKeys) resize 255; GVAR(mouse) = [false,false]; GVAR(mousePos) = [0.5,0.5]; GVAR(treeSel) = objNull; From 4cce799ace5fcc1fb73265d8233370cffebac75a Mon Sep 17 00:00:00 2001 From: PabstMirror Date: Mon, 10 Aug 2015 22:08:13 -0500 Subject: [PATCH 40/91] #2045 - Push SDV sub, cleanup push --- addons/interaction/CfgVehicles.hpp | 4 ++-- addons/interaction/XEH_postInit.sqf | 7 +++++++ addons/interaction/functions/fnc_push.sqf | 16 ++++++++-------- 3 files changed, 17 insertions(+), 10 deletions(-) diff --git a/addons/interaction/CfgVehicles.hpp b/addons/interaction/CfgVehicles.hpp index 6a492b14ad..d3260fd577 100644 --- a/addons/interaction/CfgVehicles.hpp +++ b/addons/interaction/CfgVehicles.hpp @@ -501,8 +501,8 @@ class CfgVehicles { class ACE_Push { displayName = CSTRING(Push); distance = 6; - condition = QUOTE(getMass _target < 1000 && {alive _target}); - statement = QUOTE([ARR_2(_target, [ARR_3(2 * (vectorDir _player select 0), 2 * (vectorDir _player select 1), 0.5)])] call DFUNC(push);); + condition = QUOTE(((getMass _target) <= 2600) && {alive _target} && {(vectorMagnitude (velocity _target)) < 3}); + statement = QUOTE(_this call FUNC(push)); showDisabled = 0; priority = -1; }; diff --git a/addons/interaction/XEH_postInit.sqf b/addons/interaction/XEH_postInit.sqf index 7fe151dac1..8db2d34ad1 100644 --- a/addons/interaction/XEH_postInit.sqf +++ b/addons/interaction/XEH_postInit.sqf @@ -10,6 +10,13 @@ ACE_Modifier = 0; _group selectLeader _leader; }] call EFUNC(common,addEventHandler); +//Pushing boats from FUNC(push) +[QGVAR(pushBoat), { + params ["_boat", "_newVelocity"]; + _boat setVelocity _newVelocity; +}] call EFUNC(common,addEventHandler); + + if (!hasInterface) exitWith {}; GVAR(isOpeningDoor) = false; diff --git a/addons/interaction/functions/fnc_push.sqf b/addons/interaction/functions/fnc_push.sqf index 946a5118be..86ad673d9c 100644 --- a/addons/interaction/functions/fnc_push.sqf +++ b/addons/interaction/functions/fnc_push.sqf @@ -4,23 +4,23 @@ * * Arguments: * 0: Boat - * 1: Velocity + * 1: Player * * Return Value: * None * * Example: - * [target, [vector]] call ace_interaction_fnc_push + * [Boats, Jose] call ace_interaction_fnc_push * * Public: No */ - + #include "script_component.hpp" -PARAMS_2(_boat,_velocity); +params ["_boat", "_player"]; -if !(local _boat) exitWith { - [_this, QUOTE(FUNC(push)), _boat] call EFUNC(common,execRemoteFnc); -}; +private ["_newVelocity"]; -_boat setVelocity _velocity; +_newVelocity = [2 * (vectorDir _player select 0), 2 * (vectorDir _player select 1), 0.5]; + +[QGVAR(pushBoat), [_boat], [_boat, _newVelocity]] call EFUNC(common,targetEvent); From 95aa9f604bf83d29ad51267cc1d62ded6eaf2f18 Mon Sep 17 00:00:00 2001 From: SilentSpike Date: Tue, 11 Aug 2015 13:53:55 +0100 Subject: [PATCH 41/91] Fix manual pre-setting of spectator camera unit If the spectator camera unit was set before the camera had ever opened then the unit list wouldn't be populated and as such the camera would automatically abort to free mode since the unit wasn't available to spectate. So now I'm running the updateUnits function before opening the camera to pre-populate the list. --- addons/spectator/functions/fnc_handleInterface.sqf | 3 +++ 1 file changed, 3 insertions(+) diff --git a/addons/spectator/functions/fnc_handleInterface.sqf b/addons/spectator/functions/fnc_handleInterface.sqf index 335b71bbe1..95f05d01ec 100644 --- a/addons/spectator/functions/fnc_handleInterface.sqf +++ b/addons/spectator/functions/fnc_handleInterface.sqf @@ -38,6 +38,9 @@ switch (toLower _mode) do { GVAR(mousePos) = [0.5,0.5]; GVAR(treeSel) = objNull; + // Update units before opening to support pre-set camera unit + [] call FUNC(updateUnits); + // Initalize the camera view GVAR(camera) = "Camera" camCreate (ASLtoATL GVAR(camPos)); [] call FUNC(transitionCamera); From 0656418cd1a6aa5019e2c723d82822cc8169b0d8 Mon Sep 17 00:00:00 2001 From: jokoho48 Date: Fri, 14 Aug 2015 00:00:34 +0200 Subject: [PATCH 42/91] Code cleanup of HuntIR module. --- addons/huntir/functions/fnc_cam.sqf | 19 ++++++++++--------- addons/huntir/functions/fnc_handleFired.sqf | 13 +++++++------ addons/huntir/functions/fnc_huntirCompass.sqf | 15 ++++++++------- 3 files changed, 25 insertions(+), 22 deletions(-) diff --git a/addons/huntir/functions/fnc_cam.sqf b/addons/huntir/functions/fnc_cam.sqf index bcc553fff0..20a9a86f6c 100644 --- a/addons/huntir/functions/fnc_cam.sqf +++ b/addons/huntir/functions/fnc_cam.sqf @@ -13,7 +13,7 @@ */ #include "script_component.hpp" -PARAMS_1(_huntIR); +parama ["_huntIR"]; GVAR(huntIR) = _huntIR; GVAR(pos) = getPosVisual GVAR(huntIR); @@ -73,7 +73,8 @@ GVAR(no_cams) sort true; if (((getPosVisual _x) select 2) > 20 && {!(_x in GVAR(no_cams))} && {_x getHitPointDamage "HitCamera" < 0.25}) then { GVAR(no_cams) pushBack _x; }; - } forEach GVAR(nearHuntIRs); + true + } count GVAR(nearHuntIRs); { if (((getPosVisual _x) select 2) <= 20 || {!(_x in GVAR(nearHuntIRs))} || {_x getHitPointDamage "HitCamera" >= 0.25}) then { GVAR(no_cams) deleteAt _forEachIndex; @@ -82,19 +83,19 @@ GVAR(no_cams) sort true; }; }; } forEach GVAR(no_cams); - + GVAR(cur_cam) = 0 max GVAR(cur_cam) min ((count GVAR(no_cams)) - 1); if (count GVAR(no_cams) > 0) then { GVAR(huntIR) = GVAR(no_cams) select GVAR(cur_cam); }; - + GVAR(pos) = getPosVisual GVAR(huntIR); - + if ((!dialog) || (count GVAR(no_cams) == 0) || ((GVAR(pos) select 2) <= 20)) exitWith { [_this select 1] call cba_fnc_removePerFrameHandler; - + GVAR(stop) = true; - + GVAR(pphandle) ppEffectEnable true; ppEffectDestroy GVAR(pphandle); @@ -108,7 +109,7 @@ GVAR(no_cams) sort true; deleteVehicle GVAR(logic); if (player != ACE_player) then { player remoteControl ACE_player; - }; + }; }; switch (GVAR(ZOOM)) do { @@ -131,7 +132,7 @@ GVAR(no_cams) sort true; }; private ["_cam_coord_y", "_cam_coord_x", "_cam_time", "_cam_pos"]; - + GVAR(logic) setPosATL (GVAR(pos) vectorAdd [0, 0, -5]); GVAR(logic) setDir GVAR(ROTATE); GVAR(logic) setVectorUp [0.0001, 0.0001, 1]; diff --git a/addons/huntir/functions/fnc_handleFired.sqf b/addons/huntir/functions/fnc_handleFired.sqf index 121cd9fd12..4a8f593c5b 100644 --- a/addons/huntir/functions/fnc_handleFired.sqf +++ b/addons/huntir/functions/fnc_handleFired.sqf @@ -19,13 +19,13 @@ */ #include "script_component.hpp" -PARAMS_7(_unit,_weapon,_muzzle,_mode,_ammo,_magazine,_projectile); +params ["_unit", "_weapon", "_muzzle", "_mode", "_ammo", "_magazine", "_projectile"]; if (_ammo != "F_HuntIR") exitWith {}; [{ - PARAMS_1(_projectile); - + params ["_projectile"]; + //If null (deleted or hit water) exit: if (isNull _projectile) exitWith {}; //If it's not spinning (hit ground), bail: @@ -33,15 +33,16 @@ if (_ammo != "F_HuntIR") exitWith {}; "ACE_HuntIR_Propell" createVehicle (getPosATL _projectile); [{ - PARAMS_1(_position); private ["_huntir"]; + params ["_position"]; _huntir = createVehicle ["ACE_HuntIR", _position, [], 0, "FLY"]; _huntir setPosATL _position; _huntir setVariable [QGVAR(startTime), ACE_time, true]; [{ - EXPLODE_1_PVT(_this select 0,_huntir); + params ["_args", "_idPFH"]; + _args params ["_huntir"]; if (isNull _huntir) exitWith { - [_this select 1] call CBA_fnc_removePerFrameHandler; + [_idPFH] call CBA_fnc_removePerFrameHandler; }; private ["_parachuteDamage", "_velocity"]; _parachuteDamage = _huntir getHitPointDamage "HitParachute"; diff --git a/addons/huntir/functions/fnc_huntirCompass.sqf b/addons/huntir/functions/fnc_huntirCompass.sqf index 30fcf45900..2b14878c3b 100644 --- a/addons/huntir/functions/fnc_huntirCompass.sqf +++ b/addons/huntir/functions/fnc_huntirCompass.sqf @@ -32,7 +32,7 @@ disableSerialization; private ["_fnc_correctIt"]; _fnc_correctIt = { - PARAMS_2(_pos,_dir); + params ["_pos", "_dir"]; if (_dir >= 270 || {_dir <= 90}) then { _pos set [1, (_pos select 1) + __OFFSET_Y] }; @@ -51,16 +51,17 @@ _fnc_correctIt = { HUNTIR_CAM_ROSE_LAYER_ID cutRsc ["ace_huntir_cam_rose", "PLAIN"]; [{ - EXPLODE_1_PVT(_this select 0,_fnc_correctIt); - + params ["_args", "_idPFH"]; + _args params ["_fnc_correctIt"]; + if (GVAR(stop)) exitWith { HUNTIR_CAM_ROSE_LAYER_ID cutText ["", "PLAIN"]; - [_this select 1] call CBA_fnc_removePerFrameHandler; + [_idPFH] call CBA_fnc_removePerFrameHandler; }; - + private ["_dir", "_x1", "_y1", "_pos"]; _dir = getDir GVAR(cam); // direction player; - + _x1 = __CENTER_X - (__RADIUS * sin(_dir)); _y1 = __CENTER_Y - (__RADIUS * cos(_dir)); _pos = [[_x1, _y1], _dir] call _fnc_correctIt; @@ -84,5 +85,5 @@ HUNTIR_CAM_ROSE_LAYER_ID cutRsc ["ace_huntir_cam_rose", "PLAIN"]; _pos = [[_x1, _y1], _dir] call _fnc_correctIt; __CHAR_E ctrlSetPosition [_pos select 0, _pos select 1, __WIDTH, __HEIGHT]; __CHAR_E ctrlCommit 0; - + }, 0.01, [_fnc_correctIt]] call CBA_fnc_addPerFrameHandler; From d62f00146ecb75fc74548264ee249f831ca6471f Mon Sep 17 00:00:00 2001 From: jokoho48 Date: Fri, 14 Aug 2015 00:02:19 +0200 Subject: [PATCH 43/91] Comment CleanUp --- addons/huntir/functions/fnc_cam.sqf | 2 +- addons/huntir/functions/fnc_handleFired.sqf | 2 +- addons/huntir/functions/fnc_huntir.sqf | 12 ++++++------ addons/huntir/functions/fnc_huntirCompass.sqf | 4 ++-- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/addons/huntir/functions/fnc_cam.sqf b/addons/huntir/functions/fnc_cam.sqf index 20a9a86f6c..213edfca35 100644 --- a/addons/huntir/functions/fnc_cam.sqf +++ b/addons/huntir/functions/fnc_cam.sqf @@ -7,7 +7,7 @@ * 0: HuntIR * * Return Value: - * Nothing + * None * * Public: No */ diff --git a/addons/huntir/functions/fnc_handleFired.sqf b/addons/huntir/functions/fnc_handleFired.sqf index 4a8f593c5b..1919b4547c 100644 --- a/addons/huntir/functions/fnc_handleFired.sqf +++ b/addons/huntir/functions/fnc_handleFired.sqf @@ -13,7 +13,7 @@ * 6: projectile - Object of the projectile that was shot * * Return Value: - * Nothing + * None * * Public: No */ diff --git a/addons/huntir/functions/fnc_huntir.sqf b/addons/huntir/functions/fnc_huntir.sqf index 27fd5e280b..b1c269533d 100644 --- a/addons/huntir/functions/fnc_huntir.sqf +++ b/addons/huntir/functions/fnc_huntir.sqf @@ -4,10 +4,10 @@ * HuntIR monitor system * * Arguments: - * Nothing + * None * * Return Value: - * Nothing + * None * * Public: No */ @@ -35,21 +35,21 @@ createDialog "ace_huntir_cam_dialog_off"; GVAR(connectionDelay) = 5; GVAR(state) = "searching"; GVAR(message) = []; - GVAR(messageSearching) = toArray "Searching....."; + GVAR(messageSearching) = toArray "Searching....."; GVAR(messageConnecting) = toArray "Connecting....."; [{ //Close monitor if we no longer have item: if ((!([ACE_player, "ACE_HuntIR_monitor"] call EFUNC(common,hasItem))) && {!isNull (uiNameSpace getVariable ["ace_huntir_monitor", displayNull])}) then { closeDialog 0; }; - + private ["_elapsedTime", "_nearestHuntIRs"]; _elapsedTime = ACE_time - GVAR(startTime); _nearestHuntIRs = ACE_player nearEntities ["ACE_HuntIR", HUNTIR_MAX_TRANSMISSION_RANGE]; - + if ((!dialog) || GVAR(done)) exitWith { [_this select 1] call cba_fnc_removePerFrameHandler; - + if (dialog && GVAR(state) == "connected") then { [_nearestHuntIRs select 0] call FUNC(cam); } else { diff --git a/addons/huntir/functions/fnc_huntirCompass.sqf b/addons/huntir/functions/fnc_huntirCompass.sqf index 2b14878c3b..ff06b47df3 100644 --- a/addons/huntir/functions/fnc_huntirCompass.sqf +++ b/addons/huntir/functions/fnc_huntirCompass.sqf @@ -4,10 +4,10 @@ * HuntIR monitor compass * * Arguments: - * Nothing + * None * * Return Value: - * Nothing + * None * * Public: No */ From 8e7e9b9ee3954b8ef62e525f7f687348c1f442f4 Mon Sep 17 00:00:00 2001 From: jokoho48 Date: Fri, 14 Aug 2015 14:57:29 +0200 Subject: [PATCH 44/91] Fix Typo --- addons/huntir/functions/fnc_cam.sqf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/huntir/functions/fnc_cam.sqf b/addons/huntir/functions/fnc_cam.sqf index 213edfca35..9eb22b9fb5 100644 --- a/addons/huntir/functions/fnc_cam.sqf +++ b/addons/huntir/functions/fnc_cam.sqf @@ -13,7 +13,7 @@ */ #include "script_component.hpp" -parama ["_huntIR"]; +params ["_huntIR"]; GVAR(huntIR) = _huntIR; GVAR(pos) = getPosVisual GVAR(huntIR); From ea2dc46d59f57ec0bbe8a824b3b937e12e3fd9c5 Mon Sep 17 00:00:00 2001 From: PabstMirror Date: Sat, 15 Aug 2015 02:56:34 -0500 Subject: [PATCH 45/91] 1.50 realisticnames - ubc --- addons/realisticnames/CfgWeapons.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/addons/realisticnames/CfgWeapons.hpp b/addons/realisticnames/CfgWeapons.hpp index 0a83239047..cd7624e581 100644 --- a/addons/realisticnames/CfgWeapons.hpp +++ b/addons/realisticnames/CfgWeapons.hpp @@ -1,4 +1,4 @@ - +class Mode_SemiAuto; class Mode_FullAuto; class CfgWeapons { @@ -510,14 +510,14 @@ class CfgWeapons { class player: player {}; }; - class cannon_105mm: cannon_120mm { + class cannon_105mm: CannonCore { displayName = "M68"; - class player: player { + class player: Mode_SemiAuto { displayName = "M68"; }; }; - class cannon_125mm: cannon_120mm { + class cannon_125mm: CannonCore { displayName = "2A46"; }; From 9fd155f3ecd5f71bbd7a401c1263369b73630ccd Mon Sep 17 00:00:00 2001 From: jonpas Date: Wed, 19 Aug 2015 17:11:15 +0200 Subject: [PATCH 46/91] Integrated ASDG JR Optional --- addons/laserpointer/CfgJointRails.hpp | 8 +++++ addons/laserpointer/config.cpp | 1 + addons/main/config.cpp | 4 +-- addons/optics/CfgEventHandlers.hpp | 1 - addons/optics/CfgJointRails.hpp | 15 +++++++++ addons/optics/CfgOpticsEffect.hpp | 1 - addons/optics/CfgPreloadTextures.hpp | 1 - addons/optics/CfgRscTitles.hpp | 3 +- addons/optics/CfgVehicles.hpp | 1 - addons/optics/CfgWeapons.hpp | 7 ++-- addons/optics/config.cpp | 1 + optionals/compat_asdg/$PBOPREFIX$ | 1 - optionals/compat_asdg/config.cpp | 38 ---------------------- optionals/compat_asdg/script_component.hpp | 5 --- 14 files changed, 31 insertions(+), 56 deletions(-) create mode 100644 addons/laserpointer/CfgJointRails.hpp create mode 100644 addons/optics/CfgJointRails.hpp delete mode 100644 optionals/compat_asdg/$PBOPREFIX$ delete mode 100644 optionals/compat_asdg/config.cpp delete mode 100644 optionals/compat_asdg/script_component.hpp diff --git a/addons/laserpointer/CfgJointRails.hpp b/addons/laserpointer/CfgJointRails.hpp new file mode 100644 index 0000000000..7583bd03b5 --- /dev/null +++ b/addons/laserpointer/CfgJointRails.hpp @@ -0,0 +1,8 @@ +class asdg_SlotInfo; +class asdg_FrontSideRail: asdg_SlotInfo { + class compatibleItems { + ACE_acc_pointer_red = 1; + ACE_acc_pointer_green = 1; + ACE_acc_pointer_green_IR = 1; + }; +}; diff --git a/addons/laserpointer/config.cpp b/addons/laserpointer/config.cpp index d368512257..cbb3105696 100644 --- a/addons/laserpointer/config.cpp +++ b/addons/laserpointer/config.cpp @@ -16,3 +16,4 @@ class CfgPatches { #include "CfgEventHandlers.hpp" #include "CfgVehicles.hpp" #include "CfgWeapons.hpp" +#include "CfgJointRails.hpp" diff --git a/addons/main/config.cpp b/addons/main/config.cpp index eb136f84cf..f4e9166877 100644 --- a/addons/main/config.cpp +++ b/addons/main/config.cpp @@ -1,4 +1,4 @@ -#include "script_component.hpp" +#include "script_component.hpp" class CfgPatches { class ADDON { @@ -541,7 +541,7 @@ class CfgPatches { "a3_weapons_f_vests", "a3data", "map_vr", - "extended_eventhandlers", "CBA_UI", "CBA_XEH", "CBA_XEH_A3" + "extended_eventhandlers", "cba_ui", "cba_xeh", "cba_xeh_a3", "cba_jr" }; author[] = {"ACE Team"}; authorUrl = ""; diff --git a/addons/optics/CfgEventHandlers.hpp b/addons/optics/CfgEventHandlers.hpp index 6c6e824b16..68962af2c4 100644 --- a/addons/optics/CfgEventHandlers.hpp +++ b/addons/optics/CfgEventHandlers.hpp @@ -1,4 +1,3 @@ - class Extended_PreInit_EventHandlers { class ADDON { init = QUOTE(call COMPILE_FILE(XEH_preInit)); diff --git a/addons/optics/CfgJointRails.hpp b/addons/optics/CfgJointRails.hpp new file mode 100644 index 0000000000..86c962afe5 --- /dev/null +++ b/addons/optics/CfgJointRails.hpp @@ -0,0 +1,15 @@ +class asdg_OpticRail; +class asdg_OpticRail1913: asdg_OpticRail { + class compatibleItems { + ACE_optic_Hamr_2D = 1; + ACE_optic_Hamr_PIP = 1; + ACE_optic_Arco_2D = 1; + ACE_optic_Arco_PIP = 1; + ACE_optic_MRCO_2D = 1; + ACE_optic_MRCO_PIP = 1; + ACE_optic_SOS_2D = 1; + ACE_optic_SOS_PIP = 1; + ACE_optic_LRPS_2D = 1; + ACE_optic_LRPS_PIP = 1; + }; +}; diff --git a/addons/optics/CfgOpticsEffect.hpp b/addons/optics/CfgOpticsEffect.hpp index a1bf62d6e3..8638277732 100644 --- a/addons/optics/CfgOpticsEffect.hpp +++ b/addons/optics/CfgOpticsEffect.hpp @@ -1,4 +1,3 @@ - class CfgOpticsEffect { class ACE_OpticsRadBlur1 { type = "radialblur"; diff --git a/addons/optics/CfgPreloadTextures.hpp b/addons/optics/CfgPreloadTextures.hpp index 57fa2cabf8..1354f91e18 100644 --- a/addons/optics/CfgPreloadTextures.hpp +++ b/addons/optics/CfgPreloadTextures.hpp @@ -1,4 +1,3 @@ - #define MACRO_PRELOAD \ GVAR(BodyDay) = "*"; \ GVAR(BodyNight) = "*"; \ diff --git a/addons/optics/CfgRscTitles.hpp b/addons/optics/CfgRscTitles.hpp index b7d2005d77..3bbd6b62bc 100644 --- a/addons/optics/CfgRscTitles.hpp +++ b/addons/optics/CfgRscTitles.hpp @@ -1,4 +1,3 @@ - class RscOpticsValue; class RscMapControl; class RscText; @@ -111,7 +110,7 @@ class RscInGameUI { idc = 1713011; x = "safeZoneXAbs + safeZoneWAbs - (safezoneX - safeZoneXABS) * ((getResolution select 4)/(16/3))"; colorBackground[] = {0,0,0,1}; - }; + }; }; class ACE_RscWeapon_Hamr: ACE_RscWeapon_base { diff --git a/addons/optics/CfgVehicles.hpp b/addons/optics/CfgVehicles.hpp index 92abeac04f..eda9a3d930 100644 --- a/addons/optics/CfgVehicles.hpp +++ b/addons/optics/CfgVehicles.hpp @@ -1,4 +1,3 @@ - class CfgVehicles { class Box_NATO_Support_F; class ACE_Box_Misc: Box_NATO_Support_F { diff --git a/addons/optics/CfgWeapons.hpp b/addons/optics/CfgWeapons.hpp index 11fdb1f427..7b822efd55 100644 --- a/addons/optics/CfgWeapons.hpp +++ b/addons/optics/CfgWeapons.hpp @@ -1,18 +1,17 @@ - class CfgWeapons { class ItemCore; class InventoryOpticsItem_Base_F; class Default; - + class Binocular: Default { forceOptics = 0; // Allow using compass with Binocular opticsZoomMin = 0.056889; // 5.25x power opticsZoomMax = 0.056889; // 9 px/mil - modelOptics = "\z\ace\addons\optics\models\NWD_M22_5x"; // 7 horizontal field of view + modelOptics = "\z\ace\addons\optics\models\NWD_M22_5x"; // 7� horizontal field of view visionMode[] = {"Normal"}; // Can't use nvgs with binoculars any more than you can with scopes // Fix AI using Binocs on short range - #18737 // minRange = 300; // 300 = uses Rangefinder often (runs a few meters, stops, uses RF, repeats) - minRange = 500; //500 = seem almost never use it..? + minRange = 500; //500 = seem almost never use it..? minRangeProbab = 0.001; midRange = 1000; midRangeProbab = 0.01; diff --git a/addons/optics/config.cpp b/addons/optics/config.cpp index 224410cdec..79f71842ee 100644 --- a/addons/optics/config.cpp +++ b/addons/optics/config.cpp @@ -30,5 +30,6 @@ class CfgPatches { #include "CfgRscTitles.hpp" #include "CfgVehicles.hpp" #include "CfgWeapons.hpp" +#include "CfgJointRails.hpp" #include "CfgPreloadTextures.hpp" diff --git a/optionals/compat_asdg/$PBOPREFIX$ b/optionals/compat_asdg/$PBOPREFIX$ deleted file mode 100644 index 0ba5166c16..0000000000 --- a/optionals/compat_asdg/$PBOPREFIX$ +++ /dev/null @@ -1 +0,0 @@ -z\ace\addons\compat_asdg \ No newline at end of file diff --git a/optionals/compat_asdg/config.cpp b/optionals/compat_asdg/config.cpp deleted file mode 100644 index 40dae32051..0000000000 --- a/optionals/compat_asdg/config.cpp +++ /dev/null @@ -1,38 +0,0 @@ -#include "script_component.hpp" - -class CfgPatches { - class ADDON { - units[] = {}; - weapons[] = {}; - requiredVersion = REQUIRED_VERSION; - requiredAddons[] = {"asdg_jointrails","ace_laserpointer","ace_optics"}; - author[]={"OnkelDisMaster"}; - authorUrl = "http://2.xn--gebirgsjgerkompanie-nwb.de/"; - VERSION_CONFIG; - }; -}; - -class asdg_SlotInfo; -class asdg_FrontSideRail: asdg_SlotInfo { - class compatibleItems { - ACE_acc_pointer_red = 1; - ACE_acc_pointer_green = 1; - ACE_acc_pointer_green_IR = 1; - }; -}; - -class asdg_OpticRail; -class asdg_OpticRail1913: asdg_OpticRail { - class compatibleItems { - ACE_optic_Hamr_2D = 1; - ACE_optic_Hamr_PIP = 1; - ACE_optic_Arco_2D = 1; - ACE_optic_Arco_PIP = 1; - ACE_optic_MRCO_2D = 1; - ACE_optic_MRCO_PIP = 1; - ACE_optic_SOS_2D = 1; - ACE_optic_SOS_PIP = 1; - ACE_optic_LRPS_2D = 1; - ACE_optic_LRPS_PIP = 1; - }; -}; diff --git a/optionals/compat_asdg/script_component.hpp b/optionals/compat_asdg/script_component.hpp deleted file mode 100644 index e67bf3b9e4..0000000000 --- a/optionals/compat_asdg/script_component.hpp +++ /dev/null @@ -1,5 +0,0 @@ -#define COMPONENT asdg_comp - -#include "\z\ace\addons\main\script_mod.hpp" - -#include "\z\ace\addons\main\script_macros.hpp" From d71c43b91c0fccbba183f475923bcfe68337531a Mon Sep 17 00:00:00 2001 From: jonpas Date: Wed, 19 Aug 2015 17:12:39 +0200 Subject: [PATCH 47/91] Fixed unknown char --- addons/optics/CfgWeapons.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/optics/CfgWeapons.hpp b/addons/optics/CfgWeapons.hpp index 7b822efd55..1be66d3aa2 100644 --- a/addons/optics/CfgWeapons.hpp +++ b/addons/optics/CfgWeapons.hpp @@ -7,7 +7,7 @@ class CfgWeapons { forceOptics = 0; // Allow using compass with Binocular opticsZoomMin = 0.056889; // 5.25x power opticsZoomMax = 0.056889; // 9 px/mil - modelOptics = "\z\ace\addons\optics\models\NWD_M22_5x"; // 7� horizontal field of view + modelOptics = "\z\ace\addons\optics\models\NWD_M22_5x"; // 7 degrees horizontal field of view visionMode[] = {"Normal"}; // Can't use nvgs with binoculars any more than you can with scopes // Fix AI using Binocs on short range - #18737 // minRange = 300; // 300 = uses Rangefinder often (runs a few meters, stops, uses RF, repeats) From 21b0ee087a48d55d7b86e901da6eeb6644882967 Mon Sep 17 00:00:00 2001 From: SilentSpike Date: Sat, 22 Aug 2015 00:26:01 +0100 Subject: [PATCH 48/91] Add spectator UI interrupt system A public API system to allow external systems to interrupt and resume the spectator interface. Also made use of it for the escape menu and zeus support. --- addons/spectator/XEH_preInit.sqf | 2 + .../functions/fnc_handleInterface.sqf | 66 +++++++------------ addons/spectator/functions/fnc_interrupt.sqf | 44 +++++++++++++ 3 files changed, 68 insertions(+), 44 deletions(-) create mode 100644 addons/spectator/functions/fnc_interrupt.sqf diff --git a/addons/spectator/XEH_preInit.sqf b/addons/spectator/XEH_preInit.sqf index a40f4a0dcb..d1bf48d106 100644 --- a/addons/spectator/XEH_preInit.sqf +++ b/addons/spectator/XEH_preInit.sqf @@ -12,6 +12,7 @@ PREP(handleMap); PREP(handleMouse); PREP(handleToolbar); PREP(handleUnits); +PREP(interrupt); PREP(moduleSpectatorSettings); PREP(respawnTemplate); PREP(setCameraAttributes); @@ -39,6 +40,7 @@ GVAR(camUnit) = objNull; GVAR(camVision) = -2; GVAR(camZoom) = 1.25; +GVAR(interrupts) = []; GVAR(isSet) = false; GVAR(showComp) = true; diff --git a/addons/spectator/functions/fnc_handleInterface.sqf b/addons/spectator/functions/fnc_handleInterface.sqf index 95f05d01ec..57026fb6fa 100644 --- a/addons/spectator/functions/fnc_handleInterface.sqf +++ b/addons/spectator/functions/fnc_handleInterface.sqf @@ -24,6 +24,7 @@ switch (toLower _mode) do { case "open": { // Prevent reopening if (GVAR(isSet)) exitWith {}; + GVAR(interrupts) = []; // Initalize camera variables GVAR(camBoom) = 0; @@ -68,16 +69,18 @@ switch (toLower _mode) do { }; }; case "close": { - _args params ["_unit"]; - // Can't close a second time if !(GVAR(isSet)) exitWith {}; + GVAR(interrupts) = []; // Terminate interface while {dialog} do { closeDialog 0; }; + // Kill the display + (findDisplay 12249) closeDisplay 0; + // Terminate camera GVAR(camera) cameraEffect ["terminate", "back"]; camDestroy GVAR(camera); @@ -203,11 +206,21 @@ switch (toLower _mode) do { }; case "onunload": { // Kill GUI PFHs + removeMissionEventHandler ["Draw3D",GVAR(iconHandler)]; GVAR(camHandler) = nil; GVAR(compHandler) = nil; - removeMissionEventHandler ["Draw3D",GVAR(iconHandler)]; GVAR(iconHandler) = nil; GVAR(toolHandler) = nil; + + // Reset variables + GVAR(camBoom) = 0; + GVAR(camDolly) = [0,0]; + GVAR(ctrlKey) = false; + GVAR(heldKeys) = []; + GVAR(heldKeys) resize 255; + GVAR(mouse) = [false,false]; + GVAR(mousePos) = [0.5,0.5]; + GVAR(treeSel) = objNull; }; // Mouse events case "onmousebuttondown": { @@ -247,7 +260,8 @@ switch (toLower _mode) do { _args params ["_display","_dik","_shift","_ctrl","_alt"]; if ((alive player) && {_dik in (actionKeys "curatorInterface")} && {!isNull (getAssignedCuratorLogic player)}) exitWith { - ["zeus", [_display]] call FUNC(handleInterface); + [QGVAR(zeus)] call FUNC(interrupt); + ["zeus"] call FUNC(handleInterface); }; if ((isServer || {serverCommandAvailable "#kick"}) && {_dik in (actionKeys "Chat" + actionKeys "PrevChannel" + actionKeys "NextChannel")}) exitWith { false @@ -262,7 +276,8 @@ switch (toLower _mode) do { switch (_dik) do { case 1: { // Esc - ["escape", [_display]] call FUNC(handleInterface); + [QGVAR(escape)] call FUNC(interrupt); + ["escape"] call FUNC(handleInterface); }; case 2: { // 1 [_display,nil,nil,nil,nil,nil,true] call FUNC(toggleInterface); @@ -515,23 +530,8 @@ switch (toLower _mode) do { }; // Break from interface for external events case "escape": { - _args params ["_display"]; private "_dlg"; - // Kill display - _display closeDisplay 0; - - // Reset cam/UI vars - GVAR(camBoom) = 0; - GVAR(camDolly) = [0,0]; - - GVAR(ctrlKey) = false; - GVAR(heldKeys) = []; - GVAR(heldKeys) resize 255; - GVAR(mouse) = [false,false]; - GVAR(mousePos) = [0.5,0.5]; - GVAR(treeSel) = objNull; - createDialog (["RscDisplayInterrupt", "RscDisplayMPInterrupt"] select isMultiplayer); disableSerialization; @@ -562,31 +562,12 @@ switch (toLower _mode) do { if !(isNull (findDisplay 49)) exitWith {}; // If still a spectator then re-enter the interface - if (GVAR(isSet)) then { - createDialog QGVAR(interface); - [] call FUNC(transitionCamera); - }; + [QGVAR(escape),false] call FUNC(interrupt); [_this select 1] call CBA_fnc_removePerFrameHandler; },0] call CBA_fnc_addPerFrameHandler; }; case "zeus": { - _args params ["_display"]; - - // Kill display - _display closeDisplay 0; - - // Reset cam/UI vars - GVAR(camBoom) = 0; - GVAR(camDolly) = [0,0]; - - GVAR(ctrlKey) = false; - GVAR(heldKeys) = []; - GVAR(heldKeys) resize 255; - GVAR(mouse) = [false,false]; - GVAR(mousePos) = [0.5,0.5]; - GVAR(treeSel) = objNull; - openCuratorInterface; [{ @@ -595,10 +576,7 @@ switch (toLower _mode) do { if !((isNull curatorCamera) && {isNull (GETMVAR(bis_fnc_moduleRemoteControl_unit,objNull))}) exitWith {}; // If still a spectator then re-enter the interface - if (GVAR(isSet)) then { - createDialog QGVAR(interface); - [] call FUNC(transitionCamera); - }; + [QGVAR(zeus),false] call FUNC(interrupt) [_this select 1] call CBA_fnc_removePerFrameHandler; },0] call CBA_fnc_addPerFrameHandler; diff --git a/addons/spectator/functions/fnc_interrupt.sqf b/addons/spectator/functions/fnc_interrupt.sqf new file mode 100644 index 0000000000..48cca7d102 --- /dev/null +++ b/addons/spectator/functions/fnc_interrupt.sqf @@ -0,0 +1,44 @@ +/* + * Author: SilentSpike + * Interrupts the spectator interface for external systems + * + * Arguments: + * 0: Reason + * 1: Interrupting + * + * Return Value: + * None + * + * Example: + * ["mySystem"] call ace_spectator_fnc_interrupt + * + * Public: Yes + */ +#include "script_component.hpp" + +params [["_reason", "", [""]], ["_interrupt", true, [true]]]; + +// Nothing to do when spectator is closed +if !(GVAR(isSet)) exitWith {}; + +if (_reason == "") exitWith { ERROR("Invalid Reason"); }; +if (_interrupt) then { + GVAR(interrupts) pushBack _reason; +} else { + GVAR(interrupts) = GVAR(interrupts) - [_reason]; +}; + +if (GVAR(interrupts) isEqualTo []) then { + if (isNull (findDisplay 12249)) then { + createDialog QGVAR(interface); + [] call FUNC(transitionCamera); + }; +} else { + if !(isNull (findDisplay 12249)) then { + while {dialog} do { + closeDialog 0; + }; + + (findDisplay 12249) closeDisplay 0; + }; +}; From e08bf59ac2d85ca0e87abb7a0ca3eb2867815c0d Mon Sep 17 00:00:00 2001 From: jonpas Date: Sun, 23 Aug 2015 21:09:36 +0200 Subject: [PATCH 49/91] Removed 'Repair' word from sub-actions --- addons/repair/functions/fnc_addRepairActions.sqf | 4 ++-- addons/repair/stringtable.xml | 16 ++-------------- 2 files changed, 4 insertions(+), 16 deletions(-) diff --git a/addons/repair/functions/fnc_addRepairActions.sqf b/addons/repair/functions/fnc_addRepairActions.sqf index 3503dff3f0..24ad3605ca 100644 --- a/addons/repair/functions/fnc_addRepairActions.sqf +++ b/addons/repair/functions/fnc_addRepairActions.sqf @@ -90,9 +90,9 @@ _wheelHitPointSelections = _wheelHitPointsWithSelections select 1; _text = format ["STR_ACE_Repair_%1", _x]; if (isLocalized _text) then { - _text = format [localize LSTRING(RepairHitpoint), localize _text]; + _text = localize _text; } else { - _text = format [localize LSTRING(RepairHitpoint), _x]; + _text = _x; }; _icon = "A3\ui_f\data\igui\cfg\actions\repair_ca.paa"; diff --git a/addons/repair/stringtable.xml b/addons/repair/stringtable.xml index 48a40f5b49..0f045c064b 100644 --- a/addons/repair/stringtable.xml +++ b/addons/repair/stringtable.xml @@ -1,4 +1,4 @@ - + @@ -118,18 +118,6 @@ Who can perform a full repair on a vehicle? Kto może przeprowadzić pełną naprawę pojazdu? - - Repair %1 - Reparieren %1 - Reparación %1 - Réparer %1 - Napraw %1 - Opravit %1 - Reparar %1 - Ripara %1 - Szerelés %1 - Ремонт %1 - Repair >> Reparieren >> @@ -696,4 +684,4 @@ Przydziel klasę budynku naprawczego do jednego lub kilku budynków. - \ No newline at end of file + From 0fc9a33d384d3aaea7c128eedaf89800dbbe1db3 Mon Sep 17 00:00:00 2001 From: jonpas Date: Sun, 23 Aug 2015 21:11:45 +0200 Subject: [PATCH 50/91] Shortened sub-action text localization --- addons/repair/functions/fnc_addRepairActions.sqf | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/addons/repair/functions/fnc_addRepairActions.sqf b/addons/repair/functions/fnc_addRepairActions.sqf index 24ad3605ca..8f030d6e7f 100644 --- a/addons/repair/functions/fnc_addRepairActions.sqf +++ b/addons/repair/functions/fnc_addRepairActions.sqf @@ -88,12 +88,7 @@ _wheelHitPointSelections = _wheelHitPointsWithSelections select 1; _name = format ["Repair_%1", _x]; _text = format ["STR_ACE_Repair_%1", _x]; - - if (isLocalized _text) then { - _text = localize _text; - } else { - _text = _x; - }; + _text = if (isLocalized _text) then {localize _text} else {_x}; _icon = "A3\ui_f\data\igui\cfg\actions\repair_ca.paa"; _selection = ""; From 396e01cd6ec6695a6a221a4ce259519e7e92ef5a Mon Sep 17 00:00:00 2001 From: jonpas Date: Mon, 24 Aug 2015 01:04:57 +0200 Subject: [PATCH 51/91] Added string checking for less needed string multiplicates --- .../repair/functions/fnc_addRepairActions.sqf | 62 +++++++++- addons/repair/stringtable.xml | 109 ++++++------------ 2 files changed, 97 insertions(+), 74 deletions(-) diff --git a/addons/repair/functions/fnc_addRepairActions.sqf b/addons/repair/functions/fnc_addRepairActions.sqf index 8f030d6e7f..db18e6f392 100644 --- a/addons/repair/functions/fnc_addRepairActions.sqf +++ b/addons/repair/functions/fnc_addRepairActions.sqf @@ -13,12 +13,15 @@ * * Public: No */ +#define DEBUG_MODE_FULL #include "script_component.hpp" #define TRACK_HITPOINTS ["HitLTrack", "HitRTrack"] params ["_vehicle"]; TRACE_1("params", _vehicle); +if (typeOf _vehicle != "O_Heli_Transport_04_F") exitWith {}; // test + private ["_type", "_initializedClasses"]; _type = typeOf _vehicle; @@ -39,6 +42,11 @@ _wheelHitPointsWithSelections = [_vehicle] call FUNC(getWheelHitPointsWithSelect _wheelHitPoints = _wheelHitPointsWithSelections select 0; _wheelHitPointSelections = _wheelHitPointsWithSelections select 1; +private ["_hitPointsAddedNames", "_hitPointsAddedStrings", "_hitPointsAddedAmount"]; +_hitPointsAddedNames = []; +_hitPointsAddedStrings = []; +_hitPointsAddedAmount = []; + // add repair events to this vehicle class { if (_x in _wheelHitPoints) then { @@ -83,12 +91,60 @@ _wheelHitPointSelections = _wheelHitPointsWithSelections select 1; // add misc repair action - private ["_name", "_text", "_icon", "_selection", "_condition", "_statement"]; + private ["_name", "_text", "_icon", "_selection", "_condition", "_statement", "_toFind", "_hitPointFoundIndex", "_combinedString"]; _name = format ["Repair_%1", _x]; - _text = format ["STR_ACE_Repair_%1", _x]; - _text = if (isLocalized _text) then {localize _text} else {_x}; + // Prepare first part of the string from stringtable + _text = LSTRING(Hit); + + // Remove "Hit" from hitpoint name if one exists + _toFind = if (_x find "Hit" == 0) then { + [_x, 3] call CBA_fnc_substr + } else { + _x + }; + + // Loop through always shorter part of the hitpoint name to find the string from stringtable or use an already found one + for "_i" from 0 to (count _x) do { + // Loop through already added hitpoints and save index + _hitPointFoundIndex = -1; + { + if (_x == _toFind) exitWith { + _hitPointFoundIndex = _forEachIndex; + }; + } forEach _hitPointsAddedNames; + + // Use already added hitpoint if one found above and numerize + if (_hitPointFoundIndex != -1) exitWith { + _text = (_hitPointsAddedNames select _hitPointFoundIndex) + " " + str(_hitPointsAddedAmount select _hitPointFoundIndex); + _hitPointsAddedAmount set [_hitPointFoundIndex, (_hitPointsAddedAmount select _hitPointFoundIndex) + 1]; // Set amount + TRACE_2("Same hitpoint found",_toFind,_hitPointsAddedNames); + }; + + // Localize if localization found and save all variables for possible hitpoints of same type + _combinedString = _text + _toFind; + if (isLocalized _combinedString) exitWith { + // Add hitpoint to the list + _hitPointsAddedNames pushBack _toFind; + _hitPointsAddedStrings pushBack _combinedString; + _hitPointsAddedAmount pushBack 2; + + // Localize text + _text = localize _combinedString; + TRACE_1("Hitpoint localized",_toFind); + }; + + // Cut off one character + _toFind = [_toFind, 0, count _toFind - 1] call CBA_fnc_substr; + }; + + // Display part name directly if no string is found in stringtable + if (_text == LSTRING(Hit)) then { + _text = _x; + }; + + _icon = "A3\ui_f\data\igui\cfg\actions\repair_ca.paa"; _selection = ""; diff --git a/addons/repair/stringtable.xml b/addons/repair/stringtable.xml index 0f045c064b..1f0dc8b394 100644 --- a/addons/repair/stringtable.xml +++ b/addons/repair/stringtable.xml @@ -230,6 +230,15 @@ Motor Двигатель + + Left Horizontal Stabilizer + + + Right Horizontal Stabilizer + + + Vertical Stabilizer + Fuel Tank Tank @@ -242,6 +251,24 @@ Üzemanyagtank Топливный бак + + Transmission + + + Gear + + + Starter + + + Tail + + + Pilot Tube + + + Static Port + Main Turret Turm @@ -451,77 +478,17 @@ Bal szélvédő Стекло (слава) - - Glass 1 - Scheibe 1 - Ventana 1 - Vitre 1 - Szyba 1 - Sklo 1 - Vidro 1 - Vetro 1 - Üveg 1 - Стекло 1 - - - Glass 2 - Scheibe 2 - Ventana 2 - Vitre 2 - Szyba 2 - Sklo 2 - Vidro 2 - Vetro 2 - Üveg 2 - Стекло 2 - - - Glass 3 - Scheibe 3 - Ventana 3 - Vitre 3 - Szyba 3 - Sklo 3 - Vidro 3 - Vetro 3 - Üveg 3 - Стекло 3 - - - Glass 4 - Scheibe 4 - Ventana 4 - Vitre 4 - Szyba 4 - Sklo 4 - Vidro 4 - Vetro 4 - Üveg 4 - Стекло 4 - - - Glass 5 - Scheibe 5 - Ventana 5 - Vitre 5 - Szyba 5 - Sklo 5 - Vidro 5 - Vetro 5 - Üveg 5 - Стекло 5 - - - Glass 6 - Scheibe 6 - Ventana 6 - Vitre 6 - Szyba 6 - Sklo 6 - Vidro 6 - Vetro 6 - Üveg 6 - Стекло 6 + + Glass + Scheibe + Ventana + Vitre + Szyba + Sklo + Vidro + Vetro + Üveg + Стекло Repair Settings From e368ae28f59aa649b174ef490695bff9e9df240b Mon Sep 17 00:00:00 2001 From: jonpas Date: Mon, 24 Aug 2015 01:13:42 +0200 Subject: [PATCH 52/91] Fixed localization on same type hitpoints --- addons/repair/functions/fnc_addRepairActions.sqf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addons/repair/functions/fnc_addRepairActions.sqf b/addons/repair/functions/fnc_addRepairActions.sqf index db18e6f392..299466db60 100644 --- a/addons/repair/functions/fnc_addRepairActions.sqf +++ b/addons/repair/functions/fnc_addRepairActions.sqf @@ -95,6 +95,7 @@ _hitPointsAddedAmount = []; _name = format ["Repair_%1", _x]; + // Prepare first part of the string from stringtable _text = LSTRING(Hit); @@ -117,7 +118,7 @@ _hitPointsAddedAmount = []; // Use already added hitpoint if one found above and numerize if (_hitPointFoundIndex != -1) exitWith { - _text = (_hitPointsAddedNames select _hitPointFoundIndex) + " " + str(_hitPointsAddedAmount select _hitPointFoundIndex); + _text = localize (_hitPointsAddedStrings select _hitPointFoundIndex) + " " + str(_hitPointsAddedAmount select _hitPointFoundIndex); _hitPointsAddedAmount set [_hitPointFoundIndex, (_hitPointsAddedAmount select _hitPointFoundIndex) + 1]; // Set amount TRACE_2("Same hitpoint found",_toFind,_hitPointsAddedNames); }; @@ -145,7 +146,6 @@ _hitPointsAddedAmount = []; }; - _icon = "A3\ui_f\data\igui\cfg\actions\repair_ca.paa"; _selection = ""; _condition = {[_this select 1, _this select 0, _this select 2 select 0, _this select 2 select 1] call DFUNC(canRepair)}; From d33834261f88c8213db9a13ab8267dd7608d43d7 Mon Sep 17 00:00:00 2001 From: jonpas Date: Mon, 24 Aug 2015 01:14:59 +0200 Subject: [PATCH 53/91] Removed debug --- addons/repair/functions/fnc_addRepairActions.sqf | 3 --- 1 file changed, 3 deletions(-) diff --git a/addons/repair/functions/fnc_addRepairActions.sqf b/addons/repair/functions/fnc_addRepairActions.sqf index 299466db60..10eb5ee01d 100644 --- a/addons/repair/functions/fnc_addRepairActions.sqf +++ b/addons/repair/functions/fnc_addRepairActions.sqf @@ -13,15 +13,12 @@ * * Public: No */ -#define DEBUG_MODE_FULL #include "script_component.hpp" #define TRACK_HITPOINTS ["HitLTrack", "HitRTrack"] params ["_vehicle"]; TRACE_1("params", _vehicle); -if (typeOf _vehicle != "O_Heli_Transport_04_F") exitWith {}; // test - private ["_type", "_initializedClasses"]; _type = typeOf _vehicle; From 6a1b8cc359d6d62a1b944f20f4a57df6cbd7bff5 Mon Sep 17 00:00:00 2001 From: jonpas Date: Mon, 24 Aug 2015 01:25:00 +0200 Subject: [PATCH 54/91] Changed to LSTRING --- addons/repair/functions/fnc_addRepairActions.sqf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/repair/functions/fnc_addRepairActions.sqf b/addons/repair/functions/fnc_addRepairActions.sqf index 10eb5ee01d..c330086327 100644 --- a/addons/repair/functions/fnc_addRepairActions.sqf +++ b/addons/repair/functions/fnc_addRepairActions.sqf @@ -60,7 +60,7 @@ _hitPointsAddedAmount = []; // remove wheel action _name = format ["Remove_%1", _x]; - _text = localize "STR_ACE_Repair_RemoveWheel"; + _text = localize LSTRING(RemoveWheel); _condition = {[_this select 1, _this select 0, _this select 2 select 0, "RemoveWheel"] call DFUNC(canRepair)}; _statement = {[_this select 1, _this select 0, _this select 2 select 0, "RemoveWheel"] call DFUNC(repair)}; From 2e1d7344205e39d94cc785e3df3fa27848dc467b Mon Sep 17 00:00:00 2001 From: PabstMirror Date: Sun, 23 Aug 2015 18:39:08 -0500 Subject: [PATCH 55/91] #2238 - use config for fences + cleanup --- addons/concertina_wire/CfgVehicles.hpp | 1 + addons/logistics_wirecutter/CfgVehicles.hpp | 18 ++++++++++++ addons/logistics_wirecutter/CfgWeapons.hpp | 2 +- addons/logistics_wirecutter/XEH_preInit.sqf | 3 -- .../functions/fnc_cutDownFence.sqf | 28 ++++++++++++++----- .../functions/fnc_cutDownFenceAbort.sqf | 18 ------------ .../functions/fnc_cutDownFenceCallback.sqf | 22 --------------- .../functions/fnc_getNearestFence.sqf | 28 ------------------- .../functions/fnc_interactEH.sqf | 19 +++++++------ .../functions/fnc_isFence.sqf | 13 ++++----- .../logistics_wirecutter/script_component.hpp | 6 ++++ 11 files changed, 63 insertions(+), 95 deletions(-) delete mode 100644 addons/logistics_wirecutter/functions/fnc_cutDownFenceAbort.sqf delete mode 100644 addons/logistics_wirecutter/functions/fnc_cutDownFenceCallback.sqf delete mode 100644 addons/logistics_wirecutter/functions/fnc_getNearestFence.sqf diff --git a/addons/concertina_wire/CfgVehicles.hpp b/addons/concertina_wire/CfgVehicles.hpp index d0514aa700..81304da853 100644 --- a/addons/concertina_wire/CfgVehicles.hpp +++ b/addons/concertina_wire/CfgVehicles.hpp @@ -74,6 +74,7 @@ class CfgVehicles { scope = 2; displayName = $STR_ACE_CONCERTINA_WIRE; model = PATHTOF(data\ACE_ConcertinaWire.p3d); + EGVAR(logistics_wirecutter,isFence) = 1; class ACE_Actions { class ACE_MainActions { selection = ""; diff --git a/addons/logistics_wirecutter/CfgVehicles.hpp b/addons/logistics_wirecutter/CfgVehicles.hpp index a31d9c0d99..0b584409d3 100644 --- a/addons/logistics_wirecutter/CfgVehicles.hpp +++ b/addons/logistics_wirecutter/CfgVehicles.hpp @@ -5,4 +5,22 @@ class CfgVehicles { MACRO_ADDITEM(ACE_wirecutter,4); }; }; + + class Wall_F; + class NonStrategic; + + class Land_Net_Fence_4m_F: Wall_F { GVAR(isFence) = 1; }; + class Land_Net_Fence_8m_F: Wall_F { GVAR(isFence) = 1; }; + class Land_Net_FenceD_8m_F: Wall_F { GVAR(isFence) = 1; }; + class Land_New_WiredFence_5m_F: Wall_F { GVAR(isFence) = 1; }; + class Land_New_WiredFence_10m_Dam_F: Wall_F { GVAR(isFence) = 1; }; + class Land_New_WiredFence_10m_F: Wall_F { GVAR(isFence) = 1; }; + class Land_Pipe_fence_4m_F: Wall_F { GVAR(isFence) = 1; }; + class Land_Pipe_fence_4mNoLC_F: Wall_F { GVAR(isFence) = 1; }; + class Land_SportGround_fence_F: Wall_F { GVAR(isFence) = 1; }; + class Land_Wired_Fence_4m_F: Wall_F { GVAR(isFence) = 1; }; + class Land_Wired_Fence_4mD_F: Wall_F { GVAR(isFence) = 1; }; + class Land_Wired_Fence_8m_F: Wall_F { GVAR(isFence) = 1; }; + class Land_Wired_Fence_8mD_F: Wall_F { GVAR(isFence) = 1; }; + class Land_Razorwire_F: NonStrategic { GVAR(isFence) = 1; }; }; diff --git a/addons/logistics_wirecutter/CfgWeapons.hpp b/addons/logistics_wirecutter/CfgWeapons.hpp index 4297cb3b83..2b365cc8e6 100644 --- a/addons/logistics_wirecutter/CfgWeapons.hpp +++ b/addons/logistics_wirecutter/CfgWeapons.hpp @@ -10,7 +10,7 @@ class CfgWeapons { picture = QUOTE(PATHTOF(ui\item_wirecutter_ca.paa)); scope = 2; class ItemInfo: InventoryItem_Base_F { - mass = 100; + mass = 65; }; }; }; diff --git a/addons/logistics_wirecutter/XEH_preInit.sqf b/addons/logistics_wirecutter/XEH_preInit.sqf index 44eb941c16..39620bf35c 100644 --- a/addons/logistics_wirecutter/XEH_preInit.sqf +++ b/addons/logistics_wirecutter/XEH_preInit.sqf @@ -3,9 +3,6 @@ ADDON = false; PREP(cutDownFence); -PREP(cutDownFenceAbort); -PREP(cutDownFenceCallback); -PREP(getNearestFence); PREP(interactEH); PREP(isFence); diff --git a/addons/logistics_wirecutter/functions/fnc_cutDownFence.sqf b/addons/logistics_wirecutter/functions/fnc_cutDownFence.sqf index f45f0c1511..2bf807975f 100644 --- a/addons/logistics_wirecutter/functions/fnc_cutDownFence.sqf +++ b/addons/logistics_wirecutter/functions/fnc_cutDownFence.sqf @@ -16,21 +16,35 @@ */ #include "script_component.hpp" -#define SOUND_CLIP_TIME_SPACEING 1.5 -private ["_timeToCut", "_progressCheck"]; +params ["_unit", "_fenceObject"]; +TRACE_2("params",_unit,_fenceObject); + +private ["_timeToCut", "_progressCheck", "_onCompletion", "_onFail"]; -PARAMS_2(_unit,_fenceObject); if (_unit != ACE_player) exitWith {}; _timeToCut = if ([ACE_player] call EFUNC(common,isEngineer)) then {7.5} else {11}; [ACE_player, "AinvPknlMstpSnonWnonDr_medic5", 0] call EFUNC(common,doAnimation); +_onCompletion = { + TRACE_1("_onCompletion",_this); + (_this select 0) params ["_fenceObject", "", "_unit"]; + _fenceObject setdamage 1; + [_unit, "AmovPknlMstpSrasWrflDnon", 1] call EFUNC(common,doAnimation); +}; + +_onFail = { + TRACE_1("_onFail", _this); + (_this select 0) params ["", "", "_unit"]; + [_unit, "AmovPknlMstpSrasWrflDnon", 1] call EFUNC(common,doAnimation); +}; + _progressCheck = { - PARAMS_2(_args,_passedTime); - EXPLODE_2_PVT(_args,_fenceObject,_lastSoundEffectTime); + params ["_args", "_passedTime"]; + _args params ["_fenceObject", "_lastSoundEffectTime"]; + if (_passedTime > (_lastSoundEffectTime + SOUND_CLIP_TIME_SPACEING)) then { - // playSound "ACE_wirecutter_sound"; playSound3D [QUOTE(PATHTO_R(sound\wirecut.ogg)), objNull, false, (getPosASL ACE_player), 3, 1, 10]; _args set [1, _passedTime]; }; @@ -38,4 +52,4 @@ _progressCheck = { ((!isNull _fenceObject) && {(damage _fenceObject) < 1} && {("ACE_wirecutter" in (items ACE_player))}) }; -[_timeToCut, [_fenceObject,0], {(_this select 0) call FUNC(cutDownFenceCallback)}, {(_this select 0) call FUNC(cutDownFenceAbort)}, localize LSTRING(CuttingFence), _progressCheck] call EFUNC(common,progressBar); +[_timeToCut, [_fenceObject,0,_unit], _onCompletion, _onFail, localize LSTRING(CuttingFence), _progressCheck] call EFUNC(common,progressBar); diff --git a/addons/logistics_wirecutter/functions/fnc_cutDownFenceAbort.sqf b/addons/logistics_wirecutter/functions/fnc_cutDownFenceAbort.sqf deleted file mode 100644 index 20cb092131..0000000000 --- a/addons/logistics_wirecutter/functions/fnc_cutDownFenceAbort.sqf +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Author: commy2 - * Stops cutting down fence (reset animation) - * - * Arguments: - * Nothing - * - * Return Value: - * Nothing - * - * Example: - * [] call ace_logistics_wirecutter_fnc_cutDownFenceAbort - * - * Public: No - */ -#include "script_component.hpp" - -[ACE_player, "AmovPknlMstpSrasWrflDnon", 1] call EFUNC(common,doAnimation); diff --git a/addons/logistics_wirecutter/functions/fnc_cutDownFenceCallback.sqf b/addons/logistics_wirecutter/functions/fnc_cutDownFenceCallback.sqf deleted file mode 100644 index 57495a2a03..0000000000 --- a/addons/logistics_wirecutter/functions/fnc_cutDownFenceCallback.sqf +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Author: PabstMirror - * Once progressbar is done: Fence is cutdown - * - * Arguments: - * 0: Fence Object - * - * Return Value: - * Nothing - * - * Example: - * [aFence] call ace_logistics_wirecutter_fnc_cutDownFenceCallback - * - * Public: No - */ -#include "script_component.hpp" - -PARAMS_1(_fenceObject); - -_fenceObject setdamage 1; -// [localize LSTRING(FenceCut)] call EFUNC(common,displayTextStructured); -[ACE_player, "AmovPknlMstpSrasWrflDnon", 1] call EFUNC(common,doAnimation); diff --git a/addons/logistics_wirecutter/functions/fnc_getNearestFence.sqf b/addons/logistics_wirecutter/functions/fnc_getNearestFence.sqf deleted file mode 100644 index 15bfbdb8ef..0000000000 --- a/addons/logistics_wirecutter/functions/fnc_getNearestFence.sqf +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Author: PabstMirror - * Gets nearest fence object (not actully used, left for utility) - * - * Arguments: - * 0: Unit - * - * Return Value: - * The return value - * - * Example: - * [player] call ace_logistics_wirecutter_fnc_getNearestFence - * - * Public: Yes - */ -#include "script_component.hpp" - -private "_nearestFence"; -PARAMS_1(_unit); - -_nearestFence = objNull; -{ - if ((isNull _nearestFence) && {[_x] call FUNC(isFence)}) then { - _nearestFence = _x; - }; -} forEach nearestObjects [_unit, [], 15]; - -_nearestFence diff --git a/addons/logistics_wirecutter/functions/fnc_interactEH.sqf b/addons/logistics_wirecutter/functions/fnc_interactEH.sqf index 05c47c4454..14cdfb3c2c 100644 --- a/addons/logistics_wirecutter/functions/fnc_interactEH.sqf +++ b/addons/logistics_wirecutter/functions/fnc_interactEH.sqf @@ -15,7 +15,7 @@ */ #include "script_component.hpp" -PARAMS_1(_interactionType); +params ["_interactionType"]; //Ignore self-interaction menu if (_interactionType != 0) exitWith {}; @@ -26,11 +26,11 @@ if (!("ACE_wirecutter" in (items ace_player))) exitWith {}; [{ private ["_fncStatement", "_attachedFence", "_fncCondition", "_helper", "_action"]; - PARAMS_2(_args,_pfID); - EXPLODE_3_PVT(_args,_setPosition,_addedHelpers,_fencesHelped); + params ["_args", "_pfID"]; + _args params ["_setPosition", "_addedHelpers", "_fencesHelped"]; if (!EGVAR(interact_menu,keyDown)) then { - {deleteVehicle _x;} forEach _addedHelpers; + {deleteVehicle _x; nil} count _addedHelpers; [_pfID] call CBA_fnc_removePerFrameHandler; } else { // Prevent Rare Error when ending mission with interact key down: @@ -40,11 +40,12 @@ if (!("ACE_wirecutter" in (items ace_player))) exitWith {}; if (((getPosASL ace_player) distance _setPosition) > 5) then { _fncStatement = { - PARAMS_3(_dummyTarget,_player,_attachedFence); + params ["", "_player", "_attachedFence"]; [_player, _attachedFence] call FUNC(cutDownFence); }; _fncCondition = { - PARAMS_3(_dummyTarget,_player,_attachedFence); + params ["", "_player", "_attachedFence"]; + if (!([_player, _attachedFence, []] call EFUNC(common,canInteractWith))) exitWith {false}; ((!isNull _attachedFence) && {(damage _attachedFence) < 1} && {("ACE_wirecutter" in (items _player))}) }; @@ -52,15 +53,15 @@ if (!("ACE_wirecutter" in (items ace_player))) exitWith {}; if (!(_x in _fencesHelped)) then { if ([_x] call FUNC(isFence)) then { _fencesHelped pushBack _x; - _helper = "Sign_Sphere25cm_F" createVehicleLocal (getpos _x); + _helper = "ACE_LogicDummy" createVehicleLocal (getpos _x); _action = [QGVAR(helperCutFence), (localize LSTRING(CutFence)), QUOTE(PATHTOF(ui\wirecutter_ca.paa)), _fncStatement, _fncCondition, {}, _x, [0,0,0], 5] call EFUNC(interact_menu,createAction); [_helper, 0, [],_action] call EFUNC(interact_menu,addActionToObject); _helper setPosASL ((getPosASL _x) vectorAdd [0,0,1.25]); - _helper hideObject true; _addedHelpers pushBack _helper; }; }; - } forEach nearestObjects [ace_player, [], 15]; + nil + } count nearestObjects [ace_player, [], 15]; _args set [0, (getPosASL ace_player)]; }; diff --git a/addons/logistics_wirecutter/functions/fnc_isFence.sqf b/addons/logistics_wirecutter/functions/fnc_isFence.sqf index 4c247b268a..2a0110e2ab 100644 --- a/addons/logistics_wirecutter/functions/fnc_isFence.sqf +++ b/addons/logistics_wirecutter/functions/fnc_isFence.sqf @@ -16,27 +16,26 @@ */ #include "script_component.hpp" -//find is case sensitive, so keep everything lowercase -#define FENCE_TYPENAMES ["land_net_fence_4m_f", "land_net_fence_8m_f", "land_net_fenced_8m_f", "land_new_wiredfence_5m_f", "land_new_wiredfence_10m_dam_f", "land_new_wiredfence_10m_f", "land_pipe_fence_4m_f", "land_pipe_fence_4mnolc_f", "land_sportground_fence_f", "land_wired_fence_4m_f", "land_wired_fence_4md_f", "land_wired_fence_8m_f", "land_wired_fence_8md_f", "land_razorwire_f", "ace_concertinawire"] - -#define FENCE_P3DS ["mil_wiredfence_f.p3d","wall_indfnc_3.p3d", "wall_indfnc_9.p3d", "wall_indfnc_corner.p3d", "pletivo_wired.p3d", "wall_fen1_5.p3d"] +params ["_object"]; +TRACE_1("params",_object); private ["_typeOf", "_returnValue"]; -PARAMS_1(_object); _typeOf = toLower (typeOf _object); _returnValue = false; if (_typeOf != "") then { //If the fence has configEntry we can check it directly - _returnValue = _typeOf in FENCE_TYPENAMES; + _returnValue = (1 == (getNumber (configFile >> "CfgVehicles" >> _typeOf >> QGVAR(isFence)))); } else { + //TODO: 1.50 use getModelInfo _typeOf = toLower (str _object); //something like "123201: wall_indfnc_9.p3d" { if ((_typeOf find _x) != -1) exitWith { _returnValue = true; }; - } forEach FENCE_P3DS; + nil + } count FENCE_P3DS; }; _returnValue diff --git a/addons/logistics_wirecutter/script_component.hpp b/addons/logistics_wirecutter/script_component.hpp index 6dae60dfd2..cd003ba143 100644 --- a/addons/logistics_wirecutter/script_component.hpp +++ b/addons/logistics_wirecutter/script_component.hpp @@ -10,3 +10,9 @@ #endif #include "\z\ace\addons\main\script_macros.hpp" + + +//find is case sensitive, so keep everything lowercase +#define FENCE_P3DS ["mil_wiredfence_f.p3d","wall_indfnc_3.p3d", "wall_indfnc_9.p3d", "wall_indfnc_corner.p3d", "pletivo_wired.p3d", "wall_fen1_5.p3d"] + +#define SOUND_CLIP_TIME_SPACEING 1.5 From 152faf63886e43e752b8fc53498a5cf1b3b86a58 Mon Sep 17 00:00:00 2001 From: SilentSpike Date: Sun, 23 Aug 2015 17:50:11 +0100 Subject: [PATCH 56/91] Improve spectator interface entry and exit - Use a display rather than a dialog (contextually makes more sense). - Move the entry/exit functionality to the setSpectator function. Preserves the handleInterface function for purely display related events and makes more sense. - Fix missing semi-colon --- .../functions/fnc_handleInterface.sqf | 98 +------------------ .../spectator/functions/fnc_setSpectator.sqf | 88 ++++++++++++++++- 2 files changed, 88 insertions(+), 98 deletions(-) diff --git a/addons/spectator/functions/fnc_handleInterface.sqf b/addons/spectator/functions/fnc_handleInterface.sqf index 57026fb6fa..93c6ca3ddd 100644 --- a/addons/spectator/functions/fnc_handleInterface.sqf +++ b/addons/spectator/functions/fnc_handleInterface.sqf @@ -20,100 +20,6 @@ params ["_mode",["_args",[]]]; switch (toLower _mode) do { - // Safely open/close the interface - case "open": { - // Prevent reopening - if (GVAR(isSet)) exitWith {}; - GVAR(interrupts) = []; - - // Initalize camera variables - GVAR(camBoom) = 0; - GVAR(camDolly) = [0,0]; - GVAR(camGun) = false; - - // Initalize display variables - GVAR(ctrlKey) = false; - GVAR(heldKeys) = []; - GVAR(heldKeys) resize 255; - GVAR(mouse) = [false,false]; - GVAR(mousePos) = [0.5,0.5]; - GVAR(treeSel) = objNull; - - // Update units before opening to support pre-set camera unit - [] call FUNC(updateUnits); - - // Initalize the camera view - GVAR(camera) = "Camera" camCreate (ASLtoATL GVAR(camPos)); - [] call FUNC(transitionCamera); - - // Close map and clear radio - openMap [false,false]; - clearRadio; - - // Disable BI damage effects - BIS_fnc_feedback_allowPP = false; - - // Close all existing dialogs - while {dialog} do { - closeDialog 0; - }; - - // Create the dialog - createDialog QGVAR(interface); - - // Cache and disable nametag settings - if (["ace_nametags"] call EFUNC(common,isModLoaded)) then { - GVAR(nametagSettingCache) = [EGVAR(nametags,showPlayerNames), EGVAR(nametags,showNamesForAI)]; - EGVAR(nametags,showPlayerNames) = 0; - EGVAR(nametags,showNamesForAI) = false; - }; - }; - case "close": { - // Can't close a second time - if !(GVAR(isSet)) exitWith {}; - GVAR(interrupts) = []; - - // Terminate interface - while {dialog} do { - closeDialog 0; - }; - - // Kill the display - (findDisplay 12249) closeDisplay 0; - - // Terminate camera - GVAR(camera) cameraEffect ["terminate", "back"]; - camDestroy GVAR(camera); - - clearRadio; - - // Return to player view - player switchCamera "internal"; - - // Enable BI damage effects - BIS_fnc_feedback_allowPP = true; - - // Cleanup camera variables - GVAR(camera) = nil; - GVAR(camBoom) = nil; - GVAR(camDolly) = nil; - GVAR(camGun) = nil; - - // Cleanup display variables - GVAR(ctrlKey) = nil; - GVAR(heldKeys) = nil; - GVAR(mouse) = nil; - GVAR(mousePos) = nil; - GVAR(treeSel) = nil; - - // Reset nametag settings - if (["ace_nametags"] call EFUNC(common,isModLoaded)) then { - EGVAR(nametags,showPlayerNames) = GVAR(nametagSettingCache) select 0; - EGVAR(nametags,showNamesForAI) = GVAR(nametagSettingCache) select 1; - GVAR(nametagSettingCache) = nil; - }; - }; - // Dialog events case "onload": { _args params ["_display"]; @@ -528,7 +434,7 @@ switch (toLower _mode) do { [nil,nil,nil, _newPos] call FUNC(setCameraAttributes); }; }; - // Break from interface for external events + // Interrupt events case "escape": { private "_dlg"; @@ -576,7 +482,7 @@ switch (toLower _mode) do { if !((isNull curatorCamera) && {isNull (GETMVAR(bis_fnc_moduleRemoteControl_unit,objNull))}) exitWith {}; // If still a spectator then re-enter the interface - [QGVAR(zeus),false] call FUNC(interrupt) + [QGVAR(zeus),false] call FUNC(interrupt); [_this select 1] call CBA_fnc_removePerFrameHandler; },0] call CBA_fnc_addPerFrameHandler; diff --git a/addons/spectator/functions/fnc_setSpectator.sqf b/addons/spectator/functions/fnc_setSpectator.sqf index 4f41e073d7..621100a5ba 100644 --- a/addons/spectator/functions/fnc_setSpectator.sqf +++ b/addons/spectator/functions/fnc_setSpectator.sqf @@ -25,17 +25,101 @@ params [["_set",true,[true]]]; // Only clients can be spectators if !(hasInterface) exitWith {}; +// Exit if no change +if (_set isEqualTo GVAR(isSet)) exitwith {}; + // Handle common addon audio if (["ace_hearing"] call EFUNC(common,isModLoaded)) then {EGVAR(hearing,disableVolumeUpdate) = _set}; if (["acre_sys_radio"] call EFUNC(common,isModLoaded)) then {[_set] call acre_api_fnc_setSpectator}; if (["task_force_radio"] call EFUNC(common,isModLoaded)) then {[player, _set] call TFAR_fnc_forceSpectator}; if (_set) then { - ["open"] call FUNC(handleInterface); + // Initalize camera variables + GVAR(camBoom) = 0; + GVAR(camDolly) = [0,0]; + GVAR(camGun) = false; + + // Initalize display variables + GVAR(ctrlKey) = false; + GVAR(heldKeys) = []; + GVAR(heldKeys) resize 255; + GVAR(mouse) = [false,false]; + GVAR(mousePos) = [0.5,0.5]; + GVAR(treeSel) = objNull; + + // Update units before opening to support pre-set camera unit + [] call FUNC(updateUnits); + + // Initalize the camera view + GVAR(camera) = "Camera" camCreate (ASLtoATL GVAR(camPos)); + [] call FUNC(transitionCamera); + + // Close map and clear radio + openMap [false,false]; + clearRadio; + + // Disable BI damage effects + BIS_fnc_feedback_allowPP = false; + + // Close any open dialogs + while {dialog} do { + closeDialog 0; + }; + + // Create the display + (findDisplay 46) createDisplay QGVAR(interface); + + // Cache and disable nametag settings + if (["ace_nametags"] call EFUNC(common,isModLoaded)) then { + GVAR(nametagSettingCache) = [EGVAR(nametags,showPlayerNames), EGVAR(nametags,showNamesForAI)]; + EGVAR(nametags,showPlayerNames) = 0; + EGVAR(nametags,showNamesForAI) = false; + }; } else { - ["close"] call FUNC(handleInterface); + // Close any open dialogs (could be interrupts) + while {dialog} do { + closeDialog 0; + }; + + // Kill the display + (findDisplay 12249) closeDisplay 0; + + // Terminate camera + GVAR(camera) cameraEffect ["terminate", "back"]; + camDestroy GVAR(camera); + + clearRadio; + + // Return to player view + player switchCamera "internal"; + + // Enable BI damage effects + BIS_fnc_feedback_allowPP = true; + + // Cleanup camera variables + GVAR(camera) = nil; + GVAR(camBoom) = nil; + GVAR(camDolly) = nil; + GVAR(camGun) = nil; + + // Cleanup display variables + GVAR(ctrlKey) = nil; + GVAR(heldKeys) = nil; + GVAR(mouse) = nil; + GVAR(mousePos) = nil; + GVAR(treeSel) = nil; + + // Reset nametag settings + if (["ace_nametags"] call EFUNC(common,isModLoaded)) then { + EGVAR(nametags,showPlayerNames) = GVAR(nametagSettingCache) select 0; + EGVAR(nametags,showNamesForAI) = GVAR(nametagSettingCache) select 1; + GVAR(nametagSettingCache) = nil; + }; }; +// Reset interruptions +GVAR(interrupts) = []; + // Mark spectator state for reference GVAR(isSet) = _set; From f2bda7c434a1f5375f7c7657dec3c946258c087c Mon Sep 17 00:00:00 2001 From: jonpas Date: Mon, 24 Aug 2015 04:17:24 +0200 Subject: [PATCH 57/91] Added hitpoint groups framework --- addons/repair/CfgVehicles.hpp | 14 ++++++++++++-- .../repair/functions/fnc_addRepairActions.sqf | 7 +++++-- addons/repair/functions/fnc_doRepair.sqf | 18 ++++++++++++++++-- addons/repair/script_component.hpp | 4 ---- 4 files changed, 33 insertions(+), 10 deletions(-) diff --git a/addons/repair/CfgVehicles.hpp b/addons/repair/CfgVehicles.hpp index 7c465f50ce..b4196dcf16 100644 --- a/addons/repair/CfgVehicles.hpp +++ b/addons/repair/CfgVehicles.hpp @@ -285,7 +285,10 @@ class CfgVehicles { transportRepair = 0; }; - class Heli_Transport_04_base_F; + class Helicopter_Base_H; + class Heli_Transport_04_base_F: Helicopter_Base_H { + GVAR(hitpointGroup[]) = {"Glass_1_hitpoint", "Glass_2_hitpoint", "Glass_3_hitpoint", "Glass_4_hitpoint", "Glass_5_hitpoint", "Glass_6_hitpoint", "Glass_7_hitpoint", "Glass_8_hitpoint", "Glass_9_hitpoint", "Glass_10_hitpoint", "Glass_11_hitpoint", "Glass_12_hitpoint", "Glass_13_hitpoint", "Glass_14_hitpoint", "Glass_15_hitpoint", "Glass_16_hitpoint", "Glass_17_hitpoint", "Glass_18_hitpoint", "Glass_19_hitpoint", "Glass_20_hitpoint"}; + }; class O_Heli_Transport_04_repair_F: Heli_Transport_04_base_F { GVAR(canRepair) = 1; transportRepair = 0; @@ -303,12 +306,19 @@ class CfgVehicles { transportRepair = 0; }; - class Offroad_01_base_F; + class Car_F; + class Offroad_01_base_F: Car_F { + GVAR(hitpointGroup[]) = {"HitGlass1", "HitGlass2"}; + }; class Offroad_01_repair_base_F: Offroad_01_base_F { GVAR(canRepair) = 1; transportRepair = 0; }; + class MRAP_01_base_F: Car_F { + GVAR(hitpointGroup[]) = {"HitGlass1", "HitGlass2", "HitGlass3", "HitGlass4", "HitGlass5", "HitGlass6"}; + }; + class B_Truck_01_mover_F; class B_Truck_01_Repair_F: B_Truck_01_mover_F { GVAR(canRepair) = 1; diff --git a/addons/repair/functions/fnc_addRepairActions.sqf b/addons/repair/functions/fnc_addRepairActions.sqf index 3503dff3f0..5353986a4b 100644 --- a/addons/repair/functions/fnc_addRepairActions.sqf +++ b/addons/repair/functions/fnc_addRepairActions.sqf @@ -75,8 +75,11 @@ _wheelHitPointSelections = _wheelHitPointsWithSelections select 1; [_type, 0, [], _action] call EFUNC(interact_menu,addActionToClass); } else { - // exit if the hitpoint is in the blacklist, e.g. glasses - if (_x in IGNORED_HITPOINTS) exitWith {}; + private "_hitpointGroup"; + // Exit if the hitpoint is in group and not main group hitpoint (which gets added as group repair action) + _hitpointGroup = configFile >> "CfgVehicles" >> _type >> QGVAR(hitpointGroup); + _hitpointGroup = if (isArray _hitpointGroup) then {getArray _hitpointGroup} else {[]}; + if (count _hitpointGroup > 0 && {_x in _hitpointGroup} && {_x != _hitpointGroup select 0}) exitWith {}; // exit if the hitpoint is virtual if (isText (configFile >> "CfgVehicles" >> _type >> "HitPoints" >> _x >> "depends")) exitWith {}; diff --git a/addons/repair/functions/fnc_doRepair.sqf b/addons/repair/functions/fnc_doRepair.sqf index dfc21830c9..fb53f033a6 100644 --- a/addons/repair/functions/fnc_doRepair.sqf +++ b/addons/repair/functions/fnc_doRepair.sqf @@ -17,11 +17,11 @@ */ #include "script_component.hpp" +private ["_hitPointDamage", "_text", "_hitpointGroup"]; params ["_unit", "_vehicle", "_hitPoint"]; TRACE_3("params",_unit,_vehicle,_hitPoint); // get current hitpoint damage -private "_hitPointDamage"; _hitPointDamage = _vehicle getHitPointDamage _hitPoint; _hitPointDamage = _hitPointDamage - 0.5; @@ -31,9 +31,23 @@ _hitPointDamage = _hitPointDamage max ([_unit] call FUNC(getPostRepairDamage)); // raise event to set the new hitpoint damage ["setVehicleHitPointDamage", _vehicle, [_vehicle, _hitPoint, _hitPointDamage]] call EFUNC(common,targetEvent); +// Repair the rest in the group (don't need to worry about specific damage as it's not checked) +_hitpointGroup = configFile >> "CfgVehicles" >> typeOf _vehicle >> QGVAR(hitpointGroup); +_hitpointGroup = if (isArray _hitpointGroup) then {getArray _hitpointGroup} else {[]}; +if (count _hitpointGroup > 0) then { + ([_vehicle] call EFUNC(common,getHitPointsWithSelections)) params ["_hitpoints"]; + _hitpointGroup deleteAt 0; // Remove main group hitpoint + { + if (_x in _hitpoints) then { + _vehicle setHitPointDamage [_x, 0]; + } else { + diag_log text format ["[ACE] ERROR: Invalid hitpoint %1 in hitpointGroup of %2", _x, _vehicle]; + }; + } forEach _hitpointGroup; +}; + // display text message if enabled if (GVAR(DisplayTextOnRepair)) then { - private "_text"; _text = format ["STR_ACE_Repair_%1", _hitPoint]; if (isLocalized _text) then { diff --git a/addons/repair/script_component.hpp b/addons/repair/script_component.hpp index 23c52bdec8..0714b1a568 100644 --- a/addons/repair/script_component.hpp +++ b/addons/repair/script_component.hpp @@ -10,7 +10,3 @@ #endif #include "\z\ace\addons\main\script_macros.hpp" - - -#define IGNORED_HITPOINTS ["HitGlass1","HitGlass2","HitGlass3","HitGlass4","HitGlass5","HitGlass6","HitGlass7","HitGlass8","HitGlass9","HitGlass10","HitGlass11","HitGlass12","HitGlass13","HitGlass14","HitGlass15","HitRGlass","HitLGlass"] -// #define TRACK_HITPOINTS ["HitLTrack", "HitRTrack"]; From 144af2ed17917ba70dd47d0c11dd3cc76d1f66cb Mon Sep 17 00:00:00 2001 From: jonpas Date: Mon, 24 Aug 2015 05:14:04 +0200 Subject: [PATCH 58/91] Added support for when one of the grouped hitpoints is damaged but not main --- addons/repair/ACE_Repair.hpp | 2 +- addons/repair/XEH_preInit.sqf | 1 + addons/repair/functions/fnc_canMiscRepair.sqf | 40 +++++++++++++++++++ addons/repair/functions/fnc_doRepair.sqf | 2 +- 4 files changed, 43 insertions(+), 2 deletions(-) create mode 100644 addons/repair/functions/fnc_canMiscRepair.sqf diff --git a/addons/repair/ACE_Repair.hpp b/addons/repair/ACE_Repair.hpp index c12566d5b1..a5f9cdfcee 100644 --- a/addons/repair/ACE_Repair.hpp +++ b/addons/repair/ACE_Repair.hpp @@ -31,7 +31,7 @@ class ACE_Repair { class MiscRepair: ReplaceWheel { displayName = CSTRING(Repairing); // let's make empty string an auto generated string displayNameProgress = CSTRING(RepairingHitPoint); - condition = QUOTE((_target getHitPointDamage _hitPoint) > ([_caller] call FUNC(getPostRepairDamage))); + condition = QUOTE(call FUNC(canMiscRepair)); requiredEngineer = 0; repairingTime = 15; callbackSuccess = QUOTE(call FUNC(doRepair)); diff --git a/addons/repair/XEH_preInit.sqf b/addons/repair/XEH_preInit.sqf index ebf4c87537..24244ddba0 100644 --- a/addons/repair/XEH_preInit.sqf +++ b/addons/repair/XEH_preInit.sqf @@ -3,6 +3,7 @@ ADDON = false; PREP(addRepairActions); +PREP(canMiscRepair); PREP(canRemove); PREP(canRepair); PREP(canRepairTrack); diff --git a/addons/repair/functions/fnc_canMiscRepair.sqf b/addons/repair/functions/fnc_canMiscRepair.sqf new file mode 100644 index 0000000000..7c4eb3e1fb --- /dev/null +++ b/addons/repair/functions/fnc_canMiscRepair.sqf @@ -0,0 +1,40 @@ +/* + * Author: Jonpas + * Check if misc repair action can be done, called from callbackSuccess. + * + * Arguments: + * 0: Unit that does the repairing + * 1: Vehicle to repair + * 2: Selected hitpoint + * + * Return Value: + * Can Misc Repair + * + * Example: + * [unit, vehicle, "hitpoint", "classname"] call ace_repair_fnc_canMiscRepair + * + * Public: No + */ +#include "script_component.hpp" + +private ["_hitpointGroup", "_postRepairDamage", "_return"]; +params ["_caller", "_target", "_hitPoint"]; + +// Check hitpoint group +_hitpointGroup = configFile >> "CfgVehicles" >> typeOf _target >> QGVAR(hitpointGroup); +_hitpointGroup = if (isArray _hitpointGroup) then {getArray _hitpointGroup} else {[]}; + +if !(_hitPoint in _hitpointGroup) then { + _hitpointGroup pushBack _hitPoint; +}; + +_postRepairDamage = [_caller] call FUNC(getPostRepairDamage); + +_return = false; +{ + if ((_target getHitPointDamage _x) > _postRepairDamage) exitWith { + _return = true; + }; +} forEach _hitpointGroup; + +_return diff --git a/addons/repair/functions/fnc_doRepair.sqf b/addons/repair/functions/fnc_doRepair.sqf index fb53f033a6..0a5d0a0eae 100644 --- a/addons/repair/functions/fnc_doRepair.sqf +++ b/addons/repair/functions/fnc_doRepair.sqf @@ -31,7 +31,7 @@ _hitPointDamage = _hitPointDamage max ([_unit] call FUNC(getPostRepairDamage)); // raise event to set the new hitpoint damage ["setVehicleHitPointDamage", _vehicle, [_vehicle, _hitPoint, _hitPointDamage]] call EFUNC(common,targetEvent); -// Repair the rest in the group (don't need to worry about specific damage as it's not checked) +// Repair the rest in the group (no specific damage, main hitpoint is enough) _hitpointGroup = configFile >> "CfgVehicles" >> typeOf _vehicle >> QGVAR(hitpointGroup); _hitpointGroup = if (isArray _hitpointGroup) then {getArray _hitpointGroup} else {[]}; if (count _hitpointGroup > 0) then { From 7f175bad5ff16840c6915758e97f3f611de94515 Mon Sep 17 00:00:00 2001 From: jonpas Date: Mon, 24 Aug 2015 05:24:25 +0200 Subject: [PATCH 59/91] Added support for display messages --- addons/repair/functions/fnc_doRepair.sqf | 29 +++++++++++++++++++---- addons/repair/functions/fnc_repair.sqf | 30 ++++++++++++++++++++---- 2 files changed, 51 insertions(+), 8 deletions(-) diff --git a/addons/repair/functions/fnc_doRepair.sqf b/addons/repair/functions/fnc_doRepair.sqf index dfc21830c9..1c1d47d189 100644 --- a/addons/repair/functions/fnc_doRepair.sqf +++ b/addons/repair/functions/fnc_doRepair.sqf @@ -33,14 +33,35 @@ _hitPointDamage = _hitPointDamage max ([_unit] call FUNC(getPostRepairDamage)); // display text message if enabled if (GVAR(DisplayTextOnRepair)) then { - private "_text"; - _text = format ["STR_ACE_Repair_%1", _hitPoint]; + private ["_text", "_toFind", "_combinedString"]; - if (isLocalized _text) then { - _text = format [localize ([LSTRING(RepairedHitPointFully), LSTRING(RepairedHitPointPartially)] select (_hitPointDamage > 0)), localize _text]; + // Prepare first part of the string from stringtable + _text = LSTRING(Hit); + + // Remove "Hit" from hitpoint name if one exists + _toFind = if (_x find "Hit" == 0) then { + [_x, 3] call CBA_fnc_substr } else { + _x + }; + + // Loop through always shorter part of the hitpoint name to find the string from stringtable + for "_i" from 0 to (count _x) do { + // Localize if localization found + _combinedString = _text + _toFind; + if (isLocalized _combinedString) exitWith { + _text = format [localize ([LSTRING(RepairedHitPointFully), LSTRING(RepairedHitPointPartially)] select (_hitPointDamage > 0)), localize _combinedString]; + }; + + // Cut off one character + _toFind = [_toFind, 0, count _toFind - 1] call CBA_fnc_substr; + }; + + // Don't display part name if no string is found in stringtable + if (_text == LSTRING(Hit)) then { _text = localize ([LSTRING(RepairedFully), LSTRING(RepairedPartially)] select (_hitPointDamage > 0)); }; + // Display text [_text] call EFUNC(common,displayTextStructured); }; diff --git a/addons/repair/functions/fnc_repair.sqf b/addons/repair/functions/fnc_repair.sqf index 92af5df80e..45ce756b06 100644 --- a/addons/repair/functions/fnc_repair.sqf +++ b/addons/repair/functions/fnc_repair.sqf @@ -164,15 +164,37 @@ _repairTime = if (isNumber (_config >> "repairingTime")) then { 0; }; -private ["_text", "_processText"]; +private ["_processText", "_text", "_toFind", "_combinedString"]; _processText = getText (_config >> "displayNameProgress"); -_text = format ["STR_ACE_Repair_%1", _hitPoint]; -if (isLocalized _text) then { - _text = format [_processText, localize _text]; + +// Prepare first part of the string from stringtable +_text = LSTRING(Hit); + +// Remove "Hit" from hitpoint name if one exists +_toFind = if (_x find "Hit" == 0) then { + [_x, 3] call CBA_fnc_substr } else { + _x +}; + +// Loop through always shorter part of the hitpoint name to find the string from stringtable +for "_i" from 0 to (count _x) do { + // Localize if localization found + _combinedString = _text + _toFind; + if (isLocalized _combinedString) exitWith { + _text = format [_processText, localize _combinedString]; + }; + + // Cut off one character + _toFind = [_toFind, 0, count _toFind - 1] call CBA_fnc_substr; +}; + +// Don't display part name if no string is found in stringtable +if (_text == LSTRING(Hit)) then { _text = _processText; }; + // Start repair [ _repairTime, From bb616887dc620b25513bb776926e1c98f6936d9d Mon Sep 17 00:00:00 2001 From: PabstMirror Date: Sun, 23 Aug 2015 22:55:43 -0500 Subject: [PATCH 60/91] Don't run when mounted --- addons/logistics_wirecutter/functions/fnc_interactEH.sqf | 6 ++++-- addons/logistics_wirecutter/functions/fnc_isFence.sqf | 2 +- addons/logistics_wirecutter/script_component.hpp | 2 ++ 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/addons/logistics_wirecutter/functions/fnc_interactEH.sqf b/addons/logistics_wirecutter/functions/fnc_interactEH.sqf index 14cdfb3c2c..e93296e44a 100644 --- a/addons/logistics_wirecutter/functions/fnc_interactEH.sqf +++ b/addons/logistics_wirecutter/functions/fnc_interactEH.sqf @@ -17,13 +17,15 @@ params ["_interactionType"]; -//Ignore self-interaction menu -if (_interactionType != 0) exitWith {}; +//Ignore self-interaction menu or mounted vehicle interaction +if ((_interactionType != 0) || {(vehicle ACE_player) != ACE_player}) exitWith {}; //for performance only do stuff it they have a wirecutter item //(if they somehow get one durring keydown they'll just have to reopen) if (!("ACE_wirecutter" in (items ace_player))) exitWith {}; +TRACE_1("Starting wire-cut action PFEH",_interactionType); + [{ private ["_fncStatement", "_attachedFence", "_fncCondition", "_helper", "_action"]; params ["_args", "_pfID"]; diff --git a/addons/logistics_wirecutter/functions/fnc_isFence.sqf b/addons/logistics_wirecutter/functions/fnc_isFence.sqf index 2a0110e2ab..c1e30a7e6f 100644 --- a/addons/logistics_wirecutter/functions/fnc_isFence.sqf +++ b/addons/logistics_wirecutter/functions/fnc_isFence.sqf @@ -21,7 +21,7 @@ TRACE_1("params",_object); private ["_typeOf", "_returnValue"]; -_typeOf = toLower (typeOf _object); +_typeOf = typeOf _object; _returnValue = false; if (_typeOf != "") then { diff --git a/addons/logistics_wirecutter/script_component.hpp b/addons/logistics_wirecutter/script_component.hpp index cd003ba143..a86ace1592 100644 --- a/addons/logistics_wirecutter/script_component.hpp +++ b/addons/logistics_wirecutter/script_component.hpp @@ -1,6 +1,8 @@ #define COMPONENT logistics_wirecutter #include "\z\ace\addons\main\script_mod.hpp" +// #define DEBUG_MODE_FULL + #ifdef DEBUG_ENABLED_LOGISTICS_WIRECUTTER #define DEBUG_MODE_FULL #endif From 0fa10045d2507bf4a42247c5576c28d804a460af Mon Sep 17 00:00:00 2001 From: gienkov Date: Mon, 24 Aug 2015 14:35:15 +0200 Subject: [PATCH 61/91] pl translation of spectator --- addons/spectator/stringtable.xml | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/addons/spectator/stringtable.xml b/addons/spectator/stringtable.xml index 895a279844..e6cf1d7fd4 100644 --- a/addons/spectator/stringtable.xml +++ b/addons/spectator/stringtable.xml @@ -27,6 +27,7 @@ Playable Units + Grywalne jednostki All units @@ -103,6 +104,7 @@ Spectator Units + Obserwatorzy Spectator Controls @@ -135,6 +137,7 @@ Free Camera + Kamera swobodna Camera Forward @@ -174,12 +177,15 @@ Speed Boost + Przyśpieszenie kamery Focus on Unit + Skup na jednostce Interface + Interfejs Toggle Interface @@ -211,6 +217,7 @@ Camera Attributes + Atrybuty kamery Next Camera @@ -238,21 +245,27 @@ Adjust Zoom + Reguluj zoom Adjust Speed + Reguluj prędkość Increment Zoom + Reguluj zoom (krok) Increment Speed + Reguluj prędkość (krok) Reset Zoom + Resetuj zoom Reset Speed + Resetuj prędkość - + \ No newline at end of file From 288457d3665d43125a60ccfff56f6b462205ad8f Mon Sep 17 00:00:00 2001 From: Grzegorz Date: Mon, 24 Aug 2015 17:43:02 +0200 Subject: [PATCH 62/91] fix --- addons/spectator/stringtable.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addons/spectator/stringtable.xml b/addons/spectator/stringtable.xml index e6cf1d7fd4..5c24224b72 100644 --- a/addons/spectator/stringtable.xml +++ b/addons/spectator/stringtable.xml @@ -104,7 +104,7 @@ Spectator Units - Obserwatorzy + Jednostki obserwatora Spectator Controls @@ -268,4 +268,4 @@ Resetuj prędkość - \ No newline at end of file + From 78e7565121b5a4c4d7576e5c41ae9124205808ba Mon Sep 17 00:00:00 2001 From: jonpas Date: Mon, 24 Aug 2015 20:03:11 +0200 Subject: [PATCH 63/91] Added support for multiple groups, Fixed check group damage returning true even if hitpoint not in a group --- addons/repair/CfgVehicles.hpp | 6 ++-- .../repair/functions/fnc_addRepairActions.sqf | 26 ++++++++++++---- addons/repair/functions/fnc_canMiscRepair.sqf | 24 ++++++++++----- addons/repair/functions/fnc_doRepair.sqf | 30 ++++++++++++------- 4 files changed, 60 insertions(+), 26 deletions(-) diff --git a/addons/repair/CfgVehicles.hpp b/addons/repair/CfgVehicles.hpp index b4196dcf16..4b4fd382ad 100644 --- a/addons/repair/CfgVehicles.hpp +++ b/addons/repair/CfgVehicles.hpp @@ -287,7 +287,7 @@ class CfgVehicles { class Helicopter_Base_H; class Heli_Transport_04_base_F: Helicopter_Base_H { - GVAR(hitpointGroup[]) = {"Glass_1_hitpoint", "Glass_2_hitpoint", "Glass_3_hitpoint", "Glass_4_hitpoint", "Glass_5_hitpoint", "Glass_6_hitpoint", "Glass_7_hitpoint", "Glass_8_hitpoint", "Glass_9_hitpoint", "Glass_10_hitpoint", "Glass_11_hitpoint", "Glass_12_hitpoint", "Glass_13_hitpoint", "Glass_14_hitpoint", "Glass_15_hitpoint", "Glass_16_hitpoint", "Glass_17_hitpoint", "Glass_18_hitpoint", "Glass_19_hitpoint", "Glass_20_hitpoint"}; + GVAR(hitpointGroups[]) = { {"HitEngine", {"HitEngine1", "HitEngine2"}}, {"Glass_1_hitpoint", {"Glass_2_hitpoint", "Glass_3_hitpoint", "Glass_4_hitpoint", "Glass_5_hitpoint", "Glass_6_hitpoint", "Glass_7_hitpoint", "Glass_8_hitpoint", "Glass_9_hitpoint", "Glass_10_hitpoint", "Glass_11_hitpoint", "Glass_12_hitpoint", "Glass_13_hitpoint", "Glass_14_hitpoint", "Glass_15_hitpoint", "Glass_16_hitpoint", "Glass_17_hitpoint", "Glass_18_hitpoint", "Glass_19_hitpoint", "Glass_20_hitpoint"}} }; }; class O_Heli_Transport_04_repair_F: Heli_Transport_04_base_F { GVAR(canRepair) = 1; @@ -308,7 +308,7 @@ class CfgVehicles { class Car_F; class Offroad_01_base_F: Car_F { - GVAR(hitpointGroup[]) = {"HitGlass1", "HitGlass2"}; + GVAR(hitpointGroups[]) = { {"HitGlass1", {"HitGlass2"}} }; }; class Offroad_01_repair_base_F: Offroad_01_base_F { GVAR(canRepair) = 1; @@ -316,7 +316,7 @@ class CfgVehicles { }; class MRAP_01_base_F: Car_F { - GVAR(hitpointGroup[]) = {"HitGlass1", "HitGlass2", "HitGlass3", "HitGlass4", "HitGlass5", "HitGlass6"}; + GVAR(hitpointGroups[]) = { {"HitGlass1", {"HitGlass2", "HitGlass3", "HitGlass4", "HitGlass5", "HitGlass6"}} }; }; class B_Truck_01_mover_F; diff --git a/addons/repair/functions/fnc_addRepairActions.sqf b/addons/repair/functions/fnc_addRepairActions.sqf index 5353986a4b..c47a9276f9 100644 --- a/addons/repair/functions/fnc_addRepairActions.sqf +++ b/addons/repair/functions/fnc_addRepairActions.sqf @@ -75,11 +75,27 @@ _wheelHitPointSelections = _wheelHitPointsWithSelections select 1; [_type, 0, [], _action] call EFUNC(interact_menu,addActionToClass); } else { - private "_hitpointGroup"; - // Exit if the hitpoint is in group and not main group hitpoint (which gets added as group repair action) - _hitpointGroup = configFile >> "CfgVehicles" >> _type >> QGVAR(hitpointGroup); - _hitpointGroup = if (isArray _hitpointGroup) then {getArray _hitpointGroup} else {[]}; - if (count _hitpointGroup > 0 && {_x in _hitpointGroup} && {_x != _hitpointGroup select 0}) exitWith {}; + private ["_hitpointGroupConfig", "_inHitpointSubGroup", "_currentHitpoint"]; + + // Get hitpoint groups if available + _hitpointGroupConfig = configFile >> "CfgVehicles" >> _type >> QGVAR(hitpointGroups); + _inHitpointSubGroup = false; + if (isArray _hitpointGroupConfig) then { + // Loop through hitpoint groups + _currentHitpoint = _x; + { + // Loop through sub-group + { + // Current hitpoint is in a sub-group, set it so + if (_x == _currentHitpoint) exitWith { + _inHitpointSubGroup = true; + }; + } forEach (_x select 1); + } forEach (getArray _hitpointGroupConfig); + }; + + // Exit if current hitpoint is not a group leader (only they get actions) + if (_inHitpointSubGroup) exitWith {}; // exit if the hitpoint is virtual if (isText (configFile >> "CfgVehicles" >> _type >> "HitPoints" >> _x >> "depends")) exitWith {}; diff --git a/addons/repair/functions/fnc_canMiscRepair.sqf b/addons/repair/functions/fnc_canMiscRepair.sqf index 7c4eb3e1fb..f52e8b3bfd 100644 --- a/addons/repair/functions/fnc_canMiscRepair.sqf +++ b/addons/repair/functions/fnc_canMiscRepair.sqf @@ -17,19 +17,29 @@ */ #include "script_component.hpp" -private ["_hitpointGroup", "_postRepairDamage", "_return"]; +private ["_hitpointGroupConfig", "_hitpointGroup", "_postRepairDamage", "_return"]; params ["_caller", "_target", "_hitPoint"]; -// Check hitpoint group -_hitpointGroup = configFile >> "CfgVehicles" >> typeOf _target >> QGVAR(hitpointGroup); -_hitpointGroup = if (isArray _hitpointGroup) then {getArray _hitpointGroup} else {[]}; - -if !(_hitPoint in _hitpointGroup) then { - _hitpointGroup pushBack _hitPoint; +// Get hitpoint groups if available +_hitpointGroupConfig = configFile >> "CfgVehicles" >> typeOf _target >> QGVAR(hitpointGroup); +_hitpointGroup = []; +if (isArray _hitpointGroupConfig) then { + // Loop through hitpoint groups + { + // Exit using found hitpoint group if this hitpoint is leader of any + if (_x select 0 == _hitPoint) exitWith { + _hitpointGroup = _x select 1; + }; + } forEach (getArray _hitpointGroupConfig); }; +// Add current hitpoint to the group +_hitpointGroup pushBack _hitPoint; + +// Get post repair damage _postRepairDamage = [_caller] call FUNC(getPostRepairDamage); +// Return true if damage can be repaired on any hitpoint in the group, else false _return = false; { if ((_target getHitPointDamage _x) > _postRepairDamage) exitWith { diff --git a/addons/repair/functions/fnc_doRepair.sqf b/addons/repair/functions/fnc_doRepair.sqf index 0a5d0a0eae..c310ddd2ca 100644 --- a/addons/repair/functions/fnc_doRepair.sqf +++ b/addons/repair/functions/fnc_doRepair.sqf @@ -31,19 +31,27 @@ _hitPointDamage = _hitPointDamage max ([_unit] call FUNC(getPostRepairDamage)); // raise event to set the new hitpoint damage ["setVehicleHitPointDamage", _vehicle, [_vehicle, _hitPoint, _hitPointDamage]] call EFUNC(common,targetEvent); -// Repair the rest in the group (no specific damage, main hitpoint is enough) -_hitpointGroup = configFile >> "CfgVehicles" >> typeOf _vehicle >> QGVAR(hitpointGroup); -_hitpointGroup = if (isArray _hitpointGroup) then {getArray _hitpointGroup} else {[]}; -if (count _hitpointGroup > 0) then { - ([_vehicle] call EFUNC(common,getHitPointsWithSelections)) params ["_hitpoints"]; - _hitpointGroup deleteAt 0; // Remove main group hitpoint +// Get hitpoint groups if available +_hitpointGroupConfig = configFile >> "CfgVehicles" >> typeOf _vehicle >> QGVAR(hitpointGroup); +_hitpointGroup = []; +if (isArray _hitpointGroupConfig) then { + // Loop through hitpoint groups { - if (_x in _hitpoints) then { - _vehicle setHitPointDamage [_x, 0]; - } else { - diag_log text format ["[ACE] ERROR: Invalid hitpoint %1 in hitpointGroup of %2", _x, _vehicle]; + // Exit using found hitpoint group if this hitpoint is leader of any + if (_x select 0 == _hitPoint) exitWith { + ([_vehicle] call EFUNC(common,getHitPointsWithSelections)) params ["_hitpoints"]; + // Loop through the found group + { + // If hitpoint is valid set damage to 0, else print RPT error + if (_x in _hitpoints) then { + ["setVehicleHitPointDamage", _vehicle, [_vehicle, _x, 0]] call EFUNC(common,targetEvent); + } else { + diag_log text format ["[ACE] ERROR: Invalid hitpoint %1 in hitpointGroups of %2", _x, _vehicle]; + }; + + } forEach (_x select 1); }; - } forEach _hitpointGroup; + } forEach (getArray _hitpointGroupConfig); }; // display text message if enabled From 3f0909ddd5113a0f65710a7fdd5bef38f70014dd Mon Sep 17 00:00:00 2001 From: jonpas Date: Mon, 24 Aug 2015 20:12:45 +0200 Subject: [PATCH 64/91] Fixed typo --- addons/repair/functions/fnc_canMiscRepair.sqf | 6 +++++- addons/repair/functions/fnc_doRepair.sqf | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/addons/repair/functions/fnc_canMiscRepair.sqf b/addons/repair/functions/fnc_canMiscRepair.sqf index f52e8b3bfd..105235fa1e 100644 --- a/addons/repair/functions/fnc_canMiscRepair.sqf +++ b/addons/repair/functions/fnc_canMiscRepair.sqf @@ -21,7 +21,7 @@ private ["_hitpointGroupConfig", "_hitpointGroup", "_postRepairDamage", "_return params ["_caller", "_target", "_hitPoint"]; // Get hitpoint groups if available -_hitpointGroupConfig = configFile >> "CfgVehicles" >> typeOf _target >> QGVAR(hitpointGroup); +_hitpointGroupConfig = configFile >> "CfgVehicles" >> typeOf _target >> QGVAR(hitpointGroups); _hitpointGroup = []; if (isArray _hitpointGroupConfig) then { // Loop through hitpoint groups @@ -47,4 +47,8 @@ _return = false; }; } forEach _hitpointGroup; +if (typeOf _target == "B_MRAP_01_F") then { + diag_log format ["%1 - %2", _hitPoint, _hitpointGroup]; +}; + _return diff --git a/addons/repair/functions/fnc_doRepair.sqf b/addons/repair/functions/fnc_doRepair.sqf index c310ddd2ca..14b828a67b 100644 --- a/addons/repair/functions/fnc_doRepair.sqf +++ b/addons/repair/functions/fnc_doRepair.sqf @@ -32,7 +32,7 @@ _hitPointDamage = _hitPointDamage max ([_unit] call FUNC(getPostRepairDamage)); ["setVehicleHitPointDamage", _vehicle, [_vehicle, _hitPoint, _hitPointDamage]] call EFUNC(common,targetEvent); // Get hitpoint groups if available -_hitpointGroupConfig = configFile >> "CfgVehicles" >> typeOf _vehicle >> QGVAR(hitpointGroup); +_hitpointGroupConfig = configFile >> "CfgVehicles" >> typeOf _vehicle >> QGVAR(hitpointGroups); _hitpointGroup = []; if (isArray _hitpointGroupConfig) then { // Loop through hitpoint groups From 97188835998bd182078360e4d8fef5b87ec4c1f6 Mon Sep 17 00:00:00 2001 From: jonpas Date: Mon, 24 Aug 2015 20:58:54 +0200 Subject: [PATCH 65/91] Consolidated into 1 function --- addons/repair/XEH_preInit.sqf | 1 + .../repair/functions/fnc_addRepairActions.sqf | 57 ++---------- addons/repair/functions/fnc_doRepair.sqf | 32 ++----- .../functions/fnc_getHitPointString.sqf | 89 +++++++++++++++++++ addons/repair/functions/fnc_repair.sqf | 32 +------ 5 files changed, 104 insertions(+), 107 deletions(-) create mode 100644 addons/repair/functions/fnc_getHitPointString.sqf diff --git a/addons/repair/XEH_preInit.sqf b/addons/repair/XEH_preInit.sqf index ebf4c87537..91d576c373 100644 --- a/addons/repair/XEH_preInit.sqf +++ b/addons/repair/XEH_preInit.sqf @@ -15,6 +15,7 @@ PREP(doRepair); PREP(doRepairTrack); PREP(doReplaceTrack); PREP(doReplaceWheel); +PREP(getHitPointString); PREP(getPostRepairDamage); PREP(getWheelHitPointsWithSelections); PREP(hasItems); diff --git a/addons/repair/functions/fnc_addRepairActions.sqf b/addons/repair/functions/fnc_addRepairActions.sqf index c330086327..c4c995c0e2 100644 --- a/addons/repair/functions/fnc_addRepairActions.sqf +++ b/addons/repair/functions/fnc_addRepairActions.sqf @@ -88,60 +88,15 @@ _hitPointsAddedAmount = []; // add misc repair action - private ["_name", "_text", "_icon", "_selection", "_condition", "_statement", "_toFind", "_hitPointFoundIndex", "_combinedString"]; + private ["_name", "_icon", "_selection", "_condition", "_statement"]; _name = format ["Repair_%1", _x]; - - // Prepare first part of the string from stringtable - _text = LSTRING(Hit); - - // Remove "Hit" from hitpoint name if one exists - _toFind = if (_x find "Hit" == 0) then { - [_x, 3] call CBA_fnc_substr - } else { - _x - }; - - // Loop through always shorter part of the hitpoint name to find the string from stringtable or use an already found one - for "_i" from 0 to (count _x) do { - // Loop through already added hitpoints and save index - _hitPointFoundIndex = -1; - { - if (_x == _toFind) exitWith { - _hitPointFoundIndex = _forEachIndex; - }; - } forEach _hitPointsAddedNames; - - // Use already added hitpoint if one found above and numerize - if (_hitPointFoundIndex != -1) exitWith { - _text = localize (_hitPointsAddedStrings select _hitPointFoundIndex) + " " + str(_hitPointsAddedAmount select _hitPointFoundIndex); - _hitPointsAddedAmount set [_hitPointFoundIndex, (_hitPointsAddedAmount select _hitPointFoundIndex) + 1]; // Set amount - TRACE_2("Same hitpoint found",_toFind,_hitPointsAddedNames); - }; - - // Localize if localization found and save all variables for possible hitpoints of same type - _combinedString = _text + _toFind; - if (isLocalized _combinedString) exitWith { - // Add hitpoint to the list - _hitPointsAddedNames pushBack _toFind; - _hitPointsAddedStrings pushBack _combinedString; - _hitPointsAddedAmount pushBack 2; - - // Localize text - _text = localize _combinedString; - TRACE_1("Hitpoint localized",_toFind); - }; - - // Cut off one character - _toFind = [_toFind, 0, count _toFind - 1] call CBA_fnc_substr; - }; - - // Display part name directly if no string is found in stringtable - if (_text == LSTRING(Hit)) then { - _text = _x; - }; - + // Find localized string and track those added for numerization + ([_x, "%1", _x, [_hitPointsAddedNames, _hitPointsAddedStrings, _hitPointsAddedAmount]] call FUNC(getHitPointString)) params ["_text", "_trackArray"]; + _hitPointsAddedNames = _trackArray select 0; + _hitPointsAddedStrings = _trackArray select 1; + _hitPointsAddedAmount = _trackArray select 2; _icon = "A3\ui_f\data\igui\cfg\actions\repair_ca.paa"; _selection = ""; diff --git a/addons/repair/functions/fnc_doRepair.sqf b/addons/repair/functions/fnc_doRepair.sqf index 1c1d47d189..b086ab78d1 100644 --- a/addons/repair/functions/fnc_doRepair.sqf +++ b/addons/repair/functions/fnc_doRepair.sqf @@ -33,34 +33,12 @@ _hitPointDamage = _hitPointDamage max ([_unit] call FUNC(getPostRepairDamage)); // display text message if enabled if (GVAR(DisplayTextOnRepair)) then { - private ["_text", "_toFind", "_combinedString"]; + private ["_textLocalized", "_textDefault"]; - // Prepare first part of the string from stringtable - _text = LSTRING(Hit); - - // Remove "Hit" from hitpoint name if one exists - _toFind = if (_x find "Hit" == 0) then { - [_x, 3] call CBA_fnc_substr - } else { - _x - }; - - // Loop through always shorter part of the hitpoint name to find the string from stringtable - for "_i" from 0 to (count _x) do { - // Localize if localization found - _combinedString = _text + _toFind; - if (isLocalized _combinedString) exitWith { - _text = format [localize ([LSTRING(RepairedHitPointFully), LSTRING(RepairedHitPointPartially)] select (_hitPointDamage > 0)), localize _combinedString]; - }; - - // Cut off one character - _toFind = [_toFind, 0, count _toFind - 1] call CBA_fnc_substr; - }; - - // Don't display part name if no string is found in stringtable - if (_text == LSTRING(Hit)) then { - _text = localize ([LSTRING(RepairedFully), LSTRING(RepairedPartially)] select (_hitPointDamage > 0)); - }; + // Find localized string + _textLocalized = localize ([LSTRING(RepairedHitPointFully), LSTRING(RepairedHitPointPartially)] select (_hitPointDamage > 0)); + _textDefault = localize ([LSTRING(RepairedFully), LSTRING(RepairedPartially)] select (_hitPointDamage > 0)); + ([_hitPoint, _textLocalized, _textDefault] call FUNC(getHitPointString)) params ["_text"]; // Display text [_text] call EFUNC(common,displayTextStructured); diff --git a/addons/repair/functions/fnc_getHitPointString.sqf b/addons/repair/functions/fnc_getHitPointString.sqf new file mode 100644 index 0000000000..c6e587db50 --- /dev/null +++ b/addons/repair/functions/fnc_getHitPointString.sqf @@ -0,0 +1,89 @@ +/* + * Author: Jonpas + * Finds the localized string of the given hitpoint name. + * + * Arguments: + * 0: Hitpoint + * 1: Localized Text + * 2: Default Text + * 3: Track Added Hitpoints (default: false) + * + * Return Value: + * 0: Text + * 1: Added Hitpoint (default: []) + * + * Example: + * [unit, vehicle, "hitpoint"] call ace_repair_fnc_getHitPointString + * + * Public: No + */ +#include "script_component.hpp" + +private ["_track", "_trackNames", "_trackStrings", "_trackAmount", "_text", "_toFind", "_trackIndex", "_combinedString"]; +params ["_hitPoint", "_textLocalized", "_textDefault", ["_trackArray", []]]; + +_track = if (count _trackArray > 0) then {true} else {false}; +_trackNames = []; +_trackStrings = []; +_trackAmount = []; + +if (_track) then { + _trackNames = _trackArray select 0; + _trackStrings = _trackArray select 1; + _trackAmount = _trackArray select 2; +}; + +// Prepare first part of the string from stringtable +_text = LSTRING(Hit); + +// Remove "Hit" from hitpoint name if one exists +_toFind = if (_hitPoint find "Hit" == 0) then { + [_hitPoint, 3] call CBA_fnc_substr +} else { + _hitPoint +}; + +// Loop through always shorter part of the hitpoint name to find the string from stringtable +for "_i" from 0 to (count _hitPoint) do { + if (_track) then { + // Loop through already added hitpoints and save index + _trackIndex = -1; + { + if (_x == _toFind) exitWith { + _trackIndex = _forEachIndex; + }; + } forEach _trackNames; + + // Use already added hitpoint if one found above and numerize + if (_trackIndex != -1) exitWith { + _text = localize (_trackStrings select _trackIndex) + " " + str(_trackAmount select _trackIndex); + _trackAmount set [_trackIndex, (_trackAmount select _trackIndex) + 1]; // Set amount + TRACE_2("Same hitpoint found",_toFind,_trackNames); + }; + }; + + + // Localize if localization found + _combinedString = _text + _toFind; + if (isLocalized _combinedString) exitWith { + _text = format [_textLocalized, localize _combinedString]; + TRACE_1("Hitpoint localized",_toFind); + + if (_track) then { + // Add hitpoint to the list + _trackNames pushBack _toFind; + _trackStrings pushBack _combinedString; + _trackAmount pushBack 2; + }; + }; + + // Cut off one character + _toFind = [_toFind, 0, count _toFind - 1] call CBA_fnc_substr; +}; + +// Don't display part name if no string is found in stringtable +if (_text == LSTRING(Hit)) then { + _text = _textDefault; +}; + +[_text, [_trackNames, _trackStrings, _trackAmount]] diff --git a/addons/repair/functions/fnc_repair.sqf b/addons/repair/functions/fnc_repair.sqf index 45ce756b06..8fa7f498bd 100644 --- a/addons/repair/functions/fnc_repair.sqf +++ b/addons/repair/functions/fnc_repair.sqf @@ -164,36 +164,10 @@ _repairTime = if (isNumber (_config >> "repairingTime")) then { 0; }; -private ["_processText", "_text", "_toFind", "_combinedString"]; +private ["_processText"]; +// Find localized string _processText = getText (_config >> "displayNameProgress"); - -// Prepare first part of the string from stringtable -_text = LSTRING(Hit); - -// Remove "Hit" from hitpoint name if one exists -_toFind = if (_x find "Hit" == 0) then { - [_x, 3] call CBA_fnc_substr -} else { - _x -}; - -// Loop through always shorter part of the hitpoint name to find the string from stringtable -for "_i" from 0 to (count _x) do { - // Localize if localization found - _combinedString = _text + _toFind; - if (isLocalized _combinedString) exitWith { - _text = format [_processText, localize _combinedString]; - }; - - // Cut off one character - _toFind = [_toFind, 0, count _toFind - 1] call CBA_fnc_substr; -}; - -// Don't display part name if no string is found in stringtable -if (_text == LSTRING(Hit)) then { - _text = _processText; -}; - +([_hitPoint, _processText, _processText] call FUNC(getHitPointString)) params ["_text"]; // Start repair [ From fe7a02a63d83475a97a3e6091d2f4bb6b6751527 Mon Sep 17 00:00:00 2001 From: jonpas Date: Tue, 25 Aug 2015 20:59:55 +0200 Subject: [PATCH 66/91] Updated make.py with changes from CBA --- tools/make.py | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/tools/make.py b/tools/make.py index 0420b2df92..14031a749c 100644 --- a/tools/make.py +++ b/tools/make.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python3 +#!/usr/bin/env python3 # vim: set fileencoding=utf-8 : # make.py @@ -59,7 +59,7 @@ if sys.platform == "win32": ######## GLOBALS ######### project = "@ace" -ACE_VERSION = "3.0.0" +project_version = "3.0.0" arma3tools_path = "" work_drive = "" module_root = "" @@ -130,7 +130,6 @@ def Fract_Sec(s): return d,h,m,sec #endef Fract_Sec - # Copyright (c) André Burgaud # http://www.burgaud.com/bring-colors-to-the-windows-console-with-python/ if sys.platform == "win32": @@ -387,6 +386,7 @@ def copy_optionals_for_building(mod,pbos): if (os.path.isfile(sig_path)): #print("Moving {} for processing.".format(sig_path)) shutil.move(sig_path, os.path.join(release_dir, project, "addons", sigFile_name)) + except: print_error("Error in moving") raise @@ -450,6 +450,9 @@ def cleanup_optionals(mod): continue shutil.rmtree(destination) + except FileNotFoundError: + print_yellow("{} file not found".format(file_name)) + except: print_error("Cleaning Optionals Failed") raise @@ -556,9 +559,9 @@ def addon_restore(modulePath): return True -def get_ace_version(): - global ACE_VERSION - versionStamp = ACE_VERSION +def get_project_version(): + global project_version + versionStamp = project_version #do the magic based on https://github.com/acemod/ACE3/issues/806#issuecomment-95639048 try: @@ -583,16 +586,16 @@ def get_ace_version(): raise FileNotFoundError("File Not Found: {}".format(scriptModPath)) except Exception as e: - print_error("Get_Ace_Version error: {}".format(e)) + print_error("Get_project_version error: {}".format(e)) print_error("Check the integrity of the file: {}".format(scriptModPath)) - versionStamp = ACE_VERSION + versionStamp = project_version print_error("Resetting to the default version stamp: {}".format(versionStamp)) input("Press Enter to continue...") print("Resuming build...") print_yellow("{} VERSION set to {}".format(project.lstrip("@").upper(),versionStamp)) - ACE_VERSION = versionStamp - return ACE_VERSION + project_version = versionStamp + return project_version def replace_file(filePath, oldSubstring, newSubstring): @@ -610,7 +613,7 @@ def replace_file(filePath, oldSubstring, newSubstring): def set_version_in_files(): - newVersion = ACE_VERSION # MAJOR.MINOR.PATCH.BUILD + newVersion = project_version # MAJOR.MINOR.PATCH.BUILD newVersionShort = newVersion[:-2] # MAJOR.MINOR.PATCH # Regex patterns @@ -692,7 +695,7 @@ def restore_version_files(): def get_private_keyname(commitID,module="main"): global pbo_name_prefix - aceVersion = get_ace_version() + aceVersion = get_project_version() keyName = str("{prefix}{version}-{commit_id}".format(prefix=pbo_name_prefix,version=aceVersion,commit_id=commitID)) return keyName @@ -769,7 +772,7 @@ def main(argv): """Build an Arma addon suite in a directory from rules in a make.cfg file.""" print_blue("\nmake.py for Arma, modified for Advanced Combat Environment v{}".format(__version__)) - global ACE_VERSION + global project_version global arma3tools_path global work_drive global module_root @@ -855,7 +858,7 @@ See the make.cfg file for additional build options. argv.remove("release") else: make_release_zip = False - release_version = ACE_VERSION + release_version = project_version if "target" in argv: make_target = argv[argv.index("target") + 1] From 8498589920345e650aec7b4efeeab67b499e738f Mon Sep 17 00:00:00 2001 From: gienkov Date: Wed, 26 Aug 2015 02:37:51 +0200 Subject: [PATCH 67/91] pulse zero on limb with TQ on --- addons/medical/functions/fnc_actionCheckPulse.sqf | 5 +++-- .../medical/functions/fnc_actionCheckPulseLocal.sqf | 12 ++++++++---- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/addons/medical/functions/fnc_actionCheckPulse.sqf b/addons/medical/functions/fnc_actionCheckPulse.sqf index fd96321e8f..134cf7dd20 100644 --- a/addons/medical/functions/fnc_actionCheckPulse.sqf +++ b/addons/medical/functions/fnc_actionCheckPulse.sqf @@ -14,7 +14,8 @@ #include "script_component.hpp" -private ["_caller","_target"]; +private ["_caller","_target","_selectionName"]; _caller = _this select 0; _target = _this select 1; -[[_caller, _target], QUOTE(DFUNC(actionCheckPulseLocal)), _target] call EFUNC(common,execRemoteFnc); /* TODO Replace by event system */ +_selectionName = _this select 2; +[[_caller, _target, _selectionName], QUOTE(DFUNC(actionCheckPulseLocal)), _target] call EFUNC(common,execRemoteFnc); /* TODO Replace by event system */ \ No newline at end of file diff --git a/addons/medical/functions/fnc_actionCheckPulseLocal.sqf b/addons/medical/functions/fnc_actionCheckPulseLocal.sqf index d759bf1bc8..d79c96549b 100644 --- a/addons/medical/functions/fnc_actionCheckPulseLocal.sqf +++ b/addons/medical/functions/fnc_actionCheckPulseLocal.sqf @@ -14,10 +14,10 @@ #include "script_component.hpp" -private ["_caller", "_unit", "_heartRateOutput", "_heartRate", "_logOutPut"]; +private ["_caller", "_unit", "_selectionName", "_heartRateOutput", "_heartRate", "_logOutPut"]; _caller = _this select 0; _unit = _this select 1; - +_selectionName = _this select 2; _heartRate = _unit getvariable [QGVAR(heartRate), 80]; if (!alive _unit) then { @@ -46,9 +46,13 @@ if (_heartRate > 1.0) then { }; }; +if ([_unit, _selectionName] call FUNC(hasTourniquetAppliedTo)) then { + _heartRateOutput = LSTRING(Check_Pulse_Output_5); + _logOutPut = LSTRING(Check_Pulse_None); + }; + ["displayTextStructured", [_caller], [[_heartRateOutput, [_unit] call EFUNC(common,getName), round(_heartRate)], 1.5, _caller]] call EFUNC(common,targetEvent); if (_logOutPut != "") then { [_unit,"activity", LSTRING(Check_Pulse_Log),[[_caller] call EFUNC(common,getName),_logOutPut]] call FUNC(addToLog); - [_unit,"quick_view", LSTRING(Check_Pulse_Log),[[_caller] call EFUNC(common,getName),_logOutPut]] call FUNC(addToLog); -}; +}; \ No newline at end of file From 5a9817322b1cb5a86c6bfe2b03f60ec802105524 Mon Sep 17 00:00:00 2001 From: gienkov Date: Wed, 26 Aug 2015 02:39:34 +0200 Subject: [PATCH 68/91] remove tabs --- addons/medical/functions/fnc_actionCheckPulseLocal.sqf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/medical/functions/fnc_actionCheckPulseLocal.sqf b/addons/medical/functions/fnc_actionCheckPulseLocal.sqf index d79c96549b..96b1bc698c 100644 --- a/addons/medical/functions/fnc_actionCheckPulseLocal.sqf +++ b/addons/medical/functions/fnc_actionCheckPulseLocal.sqf @@ -49,7 +49,7 @@ if (_heartRate > 1.0) then { if ([_unit, _selectionName] call FUNC(hasTourniquetAppliedTo)) then { _heartRateOutput = LSTRING(Check_Pulse_Output_5); _logOutPut = LSTRING(Check_Pulse_None); - }; +}; ["displayTextStructured", [_caller], [[_heartRateOutput, [_unit] call EFUNC(common,getName), round(_heartRate)], 1.5, _caller]] call EFUNC(common,targetEvent); From c3af5e81e7bff1d707df311883fc2728b35b591b Mon Sep 17 00:00:00 2001 From: gienkov Date: Wed, 26 Aug 2015 02:41:12 +0200 Subject: [PATCH 69/91] fix my error --- addons/medical/functions/fnc_actionCheckPulseLocal.sqf | 1 + 1 file changed, 1 insertion(+) diff --git a/addons/medical/functions/fnc_actionCheckPulseLocal.sqf b/addons/medical/functions/fnc_actionCheckPulseLocal.sqf index 96b1bc698c..54b03ec247 100644 --- a/addons/medical/functions/fnc_actionCheckPulseLocal.sqf +++ b/addons/medical/functions/fnc_actionCheckPulseLocal.sqf @@ -55,4 +55,5 @@ if ([_unit, _selectionName] call FUNC(hasTourniquetAppliedTo)) then { if (_logOutPut != "") then { [_unit,"activity", LSTRING(Check_Pulse_Log),[[_caller] call EFUNC(common,getName),_logOutPut]] call FUNC(addToLog); + [_unit,"quick_view", LSTRING(Check_Pulse_Log),[[_caller] call EFUNC(common,getName),_logOutPut]] call FUNC(addToLog); }; \ No newline at end of file From cae5f828fbb507eada6ae336ee0f2a96cfd89cb7 Mon Sep 17 00:00:00 2001 From: gienkov Date: Wed, 26 Aug 2015 02:51:05 +0200 Subject: [PATCH 70/91] run check only on arms --- addons/medical/functions/fnc_actionCheckPulseLocal.sqf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/medical/functions/fnc_actionCheckPulseLocal.sqf b/addons/medical/functions/fnc_actionCheckPulseLocal.sqf index 54b03ec247..adbafd004f 100644 --- a/addons/medical/functions/fnc_actionCheckPulseLocal.sqf +++ b/addons/medical/functions/fnc_actionCheckPulseLocal.sqf @@ -46,7 +46,7 @@ if (_heartRate > 1.0) then { }; }; -if ([_unit, _selectionName] call FUNC(hasTourniquetAppliedTo)) then { +if (_selectionName in ["hand_l","hand_r"] && [_unit, _selectionName] call FUNC(hasTourniquetAppliedTo)) then { _heartRateOutput = LSTRING(Check_Pulse_Output_5); _logOutPut = LSTRING(Check_Pulse_None); }; From b8a29bfd442aeee64454065c3a0f1c0fdd5c5184 Mon Sep 17 00:00:00 2001 From: Grzegorz Date: Wed, 26 Aug 2015 03:00:43 +0200 Subject: [PATCH 71/91] @jokoho482 suggestion --- addons/medical/functions/fnc_actionCheckPulseLocal.sqf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addons/medical/functions/fnc_actionCheckPulseLocal.sqf b/addons/medical/functions/fnc_actionCheckPulseLocal.sqf index adbafd004f..f719aad2d8 100644 --- a/addons/medical/functions/fnc_actionCheckPulseLocal.sqf +++ b/addons/medical/functions/fnc_actionCheckPulseLocal.sqf @@ -46,7 +46,7 @@ if (_heartRate > 1.0) then { }; }; -if (_selectionName in ["hand_l","hand_r"] && [_unit, _selectionName] call FUNC(hasTourniquetAppliedTo)) then { +if (_selectionName in ["hand_l","hand_r"] && {[_unit, _selectionName] call FUNC(hasTourniquetAppliedTo)}) then { _heartRateOutput = LSTRING(Check_Pulse_Output_5); _logOutPut = LSTRING(Check_Pulse_None); }; @@ -56,4 +56,4 @@ if (_selectionName in ["hand_l","hand_r"] && [_unit, _selectionName] call FUNC(h if (_logOutPut != "") then { [_unit,"activity", LSTRING(Check_Pulse_Log),[[_caller] call EFUNC(common,getName),_logOutPut]] call FUNC(addToLog); [_unit,"quick_view", LSTRING(Check_Pulse_Log),[[_caller] call EFUNC(common,getName),_logOutPut]] call FUNC(addToLog); -}; \ No newline at end of file +}; From ca71dd43e193961200ba8f8a39720cc42b63f138 Mon Sep 17 00:00:00 2001 From: jokoho48 Date: Wed, 26 Aug 2015 05:31:33 +0200 Subject: [PATCH 72/91] Code Cleanup MicroDagr Module --- .../functions/fnc_appMarkKeypadEntry.sqf | 13 +++---- .../fnc_appMenuButtonConnectRangefinder.sqf | 8 ++-- .../functions/fnc_appSettingsLBClick.sqf | 4 +- .../fnc_appWaypointsButtonDeleteWP.sqf | 14 +++---- .../functions/fnc_appWaypointsButtonSetWP.sqf | 6 +-- addons/microdagr/functions/fnc_canShow.sqf | 23 ++++++----- .../functions/fnc_deviceAddWaypoint.sqf | 11 +++--- .../functions/fnc_deviceDeleteWaypoint.sqf | 9 ++--- .../functions/fnc_deviceGetWaypoints.sqf | 4 +- .../functions/fnc_dialogClosedEH.sqf | 6 +-- .../functions/fnc_mapButtonDownEH.sqf | 4 +- .../functions/fnc_mapDoubleTapEH.sqf | 6 +-- .../microdagr/functions/fnc_mapOnDrawEH.sqf | 16 ++++---- .../functions/fnc_modeMapButtons.sqf | 4 +- .../microdagr/functions/fnc_moduleMapFill.sqf | 9 ++--- .../microdagr/functions/fnc_openDisplay.sqf | 16 ++++---- .../functions/fnc_recieveRangefinderData.sqf | 6 +-- .../fnc_saveCurrentAndSetNewMode.sqf | 21 +++++----- .../functions/fnc_showApplicationPage.sqf | 12 ++---- .../microdagr/functions/fnc_updateDisplay.sqf | 38 +++++++++---------- 20 files changed, 104 insertions(+), 126 deletions(-) diff --git a/addons/microdagr/functions/fnc_appMarkKeypadEntry.sqf b/addons/microdagr/functions/fnc_appMarkKeypadEntry.sqf index 0822bdf310..86ace87b3e 100644 --- a/addons/microdagr/functions/fnc_appMarkKeypadEntry.sqf +++ b/addons/microdagr/functions/fnc_appMarkKeypadEntry.sqf @@ -6,7 +6,7 @@ * 0: String version of Keypad entry ["ok","del","1",...] * * Return Value: - * Nothing + * None * * Example: * ["ok"] call ace_microdagr_fnc_appMarkKeypadEntry @@ -16,15 +16,12 @@ #include "script_component.hpp" private ["_display", "_editText", "_actualPos"]; -PARAMS_1(_keypadButton); + +params ["_keypadButton"]; disableSerialization; -_display = displayNull; -if (GVAR(currentShowMode) == DISPLAY_MODE_DIALOG) then { - _display = (uiNamespace getVariable [QGVAR(DialogDisplay), displayNull]); -} else { - _display = (uiNamespace getVariable [QGVAR(RscTitleDisplay), displayNull]); -}; +_display = uiNamespace getVariable [[QGVAR(RscTitleDisplay), QGVAR(DialogDisplay)] select (GVAR(currentShowMode) == DISPLAY_MODE_DIALOG), displayNull]; + if (isNull _display) exitWith {ERROR("No Display");}; if (GVAR(currentApplicationPage) != APP_MODE_MARK) exitWith {}; diff --git a/addons/microdagr/functions/fnc_appMenuButtonConnectRangefinder.sqf b/addons/microdagr/functions/fnc_appMenuButtonConnectRangefinder.sqf index 1cf81963f5..589ec096fb 100644 --- a/addons/microdagr/functions/fnc_appMenuButtonConnectRangefinder.sqf +++ b/addons/microdagr/functions/fnc_appMenuButtonConnectRangefinder.sqf @@ -3,18 +3,18 @@ * Handles the "Connect To" button from the menu application * * Arguments: - * Nothing + * None * * Return Value: - * Nothing + * None * * Example: - * [] call ace_microdagr_fnc_appMenuButtonConnectRangefinder + * call ace_microdagr_fnc_appMenuButtonConnectRangefinder * * Public: No */ #include "script_component.hpp" -GVAR(currentWaypoint) = if (GVAR(currentWaypoint) == -2) then {-1} else {-2}; +GVAR(currentWaypoint) = [-2, -1] select (GVAR(currentWaypoint) == -2); GVAR(rangeFinderPositionASL) = []; [APP_MODE_INFODISPLAY] call FUNC(saveCurrentAndSetNewMode); diff --git a/addons/microdagr/functions/fnc_appSettingsLBClick.sqf b/addons/microdagr/functions/fnc_appSettingsLBClick.sqf index bc6779c10a..04f045171b 100644 --- a/addons/microdagr/functions/fnc_appSettingsLBClick.sqf +++ b/addons/microdagr/functions/fnc_appSettingsLBClick.sqf @@ -7,7 +7,7 @@ * 1: Index * * Return Value: - * Nothing + * None * * Example: * [settingList, 1] call ace_microdagr_fnc_appSettingsLBClick @@ -17,7 +17,7 @@ #include "script_component.hpp" disableSerialization; -PARAMS_2(_control,_itemClicked); +params ["_control", "_itemClicked"]; switch (_itemClicked) do { case (0): { GVAR(settingUseMils) = ! GVAR(settingUseMils)}; diff --git a/addons/microdagr/functions/fnc_appWaypointsButtonDeleteWP.sqf b/addons/microdagr/functions/fnc_appWaypointsButtonDeleteWP.sqf index 1acd936370..956e24c5ba 100644 --- a/addons/microdagr/functions/fnc_appWaypointsButtonDeleteWP.sqf +++ b/addons/microdagr/functions/fnc_appWaypointsButtonDeleteWP.sqf @@ -3,13 +3,13 @@ * Handles clicking the delete button from the waypoint application * * Arguments: - * Nothing + * None * * Return Value: - * Nothing + * None * * Example: - * [] call ace_microdagr_fnc_appWaypointsButtonDeleteWP + * call ace_microdagr_fnc_appWaypointsButtonDeleteWP * * Public: No */ @@ -18,12 +18,8 @@ private ["_display", "_wpIndex"]; disableSerialization; -_display = displayNull; -if (GVAR(currentShowMode) == DISPLAY_MODE_DIALOG) then { - _display = (uiNamespace getVariable [QGVAR(DialogDisplay), displayNull]); -} else { - _display = (uiNamespace getVariable [QGVAR(RscTitleDisplay), displayNull]); -}; +_display = uiNamespace getVariable [[QGVAR(RscTitleDisplay), QGVAR(DialogDisplay)] select GVAR(currentShowMode) == DISPLAY_MODE_DIALOG, displayNull]; + if (isNull _display) exitWith {ERROR("No Display");}; _wpIndex = lbCurSel (_display displayCtrl IDC_MODEWAYPOINTS_LISTOFWAYPOINTS); diff --git a/addons/microdagr/functions/fnc_appWaypointsButtonSetWP.sqf b/addons/microdagr/functions/fnc_appWaypointsButtonSetWP.sqf index 881c0b3b5d..d2b3b0e20c 100644 --- a/addons/microdagr/functions/fnc_appWaypointsButtonSetWP.sqf +++ b/addons/microdagr/functions/fnc_appWaypointsButtonSetWP.sqf @@ -6,10 +6,10 @@ * The "SetWP" button * * Return Value: - * Nothing + * None * * Example: - * [] call ace_microdagr_fnc_appWaypointsButtonSetWP + * [1234] call ace_microdagr_fnc_appWaypointsButtonSetWP * * Public: No */ @@ -18,7 +18,7 @@ private ["_wpListBox", "_newWpIndex", "_waypoints"]; disableSerialization; -PARAMS_1(_wpButton); +params ["_wpButton"]; _wpListBox = (ctrlParent _wpButton) displayCtrl 144501; _newWpIndex = lbCurSel _wpListBox; diff --git a/addons/microdagr/functions/fnc_canShow.sqf b/addons/microdagr/functions/fnc_canShow.sqf index 9e54f927e0..70e8989031 100644 --- a/addons/microdagr/functions/fnc_canShow.sqf +++ b/addons/microdagr/functions/fnc_canShow.sqf @@ -6,32 +6,31 @@ * The display mode to test showing * * Return Value: - * Nothing + * None * * Example: - * [mode] call ace_microdagr_fnc_canShow + * [1] call ace_microdagr_fnc_canShow * * Public: No */ #include "script_component.hpp" - -PARAMS_1(_showType); +params ["_showType"]; private ["_returnValue"]; _returnValue = false; -switch (_showType) do { -case (DISPLAY_MODE_CLOSED): {_returnValue = true}; //Can always close -case (DISPLAY_MODE_HIDDEN): {_returnValue = true}; //Can always hide - -case (DISPLAY_MODE_DIALOG): { - _returnValue = ("ACE_microDAGR" in (items ACE_player)) && {[ACE_player, objNull, ["notOnMap", "isNotInside", "isNotSitting"]] call EFUNC(common,canInteractWith)}; +_returnValue = switch (_showType) do { + case (DISPLAY_MODE_CLOSED): { true }; //Can always close + case (DISPLAY_MODE_HIDDEN): { true }; //Can always hide + case (DISPLAY_MODE_DIALOG): { + ("ACE_microDAGR" in (items ACE_player)) && {[ACE_player, objNull, ["notOnMap", "isNotInside", "isNotSitting"]] call EFUNC(common,canInteractWith)} }; -case (DISPLAY_MODE_DISPLAY): { + case (DISPLAY_MODE_DISPLAY): { //Can't have minimap up while zoomed in - _returnValue = (cameraview != "GUNNER") && {"ACE_microDAGR" in (items ACE_player)} && {[ACE_player, objNull, ["notOnMap", "isNotInside", "isNotSitting"]] call EFUNC(common,canInteractWith)}; + (cameraview != "GUNNER") && {"ACE_microDAGR" in (items ACE_player)} && {[ACE_player, objNull, ["notOnMap", "isNotInside", "isNotSitting"]] call EFUNC(common,canInteractWith)} }; + default { false }; }; _returnValue diff --git a/addons/microdagr/functions/fnc_deviceAddWaypoint.sqf b/addons/microdagr/functions/fnc_deviceAddWaypoint.sqf index c383d0a95e..f99ec78354 100644 --- a/addons/microdagr/functions/fnc_deviceAddWaypoint.sqf +++ b/addons/microdagr/functions/fnc_deviceAddWaypoint.sqf @@ -8,7 +8,7 @@ * 1: Waypoint Position ASL * * Return Value: - * Nothing + * None * * Example: * ["Hill 55", [41,324, 12]] call ace_microdagr_fnc_deviceAddWaypoint @@ -17,10 +17,11 @@ */ #include "script_component.hpp" -PARAMS_2(_waypointName,_waypointPosASL); - private "_waypoints"; +params ["_waypointName","_waypointPosASL"]; -_waypoints = ace_player getVariable [QGVAR(waypoints), []]; + + +_waypoints = ACE_player getVariable [QGVAR(waypoints), []]; _waypoints pushBack [_waypointName, _waypointPosASL]; -ace_player setVariable [QGVAR(waypoints), _waypoints]; +ACE_player setVariable [QGVAR(waypoints), _waypoints]; diff --git a/addons/microdagr/functions/fnc_deviceDeleteWaypoint.sqf b/addons/microdagr/functions/fnc_deviceDeleteWaypoint.sqf index 62ca5a222a..d3681466b4 100644 --- a/addons/microdagr/functions/fnc_deviceDeleteWaypoint.sqf +++ b/addons/microdagr/functions/fnc_deviceDeleteWaypoint.sqf @@ -7,7 +7,7 @@ * 0: Waypoint Index * * Return Value: - * Nothing + * None * * Example: * ["Hill 55", [41,324, 12]] call ace_microdagr_fnc_deviceDeleteWaypoint @@ -16,13 +16,12 @@ */ #include "script_component.hpp" -PARAMS_1(_wpIndex); - private "_waypoints"; +params ["_wpIndex"]; -_waypoints = ace_player getVariable [QGVAR(waypoints), []]; +_waypoints = ACE_player getVariable [QGVAR(waypoints), []]; if ((_wpIndex < 0) || (_wpIndex > ((count _waypoints) - 1))) exitWith {ERROR("out of bounds wp");}; _waypoints deleteAt _wpIndex; -ace_player setVariable [QGVAR(waypoints), _waypoints]; +ACE_player setVariable [QGVAR(waypoints), _waypoints]; diff --git a/addons/microdagr/functions/fnc_deviceGetWaypoints.sqf b/addons/microdagr/functions/fnc_deviceGetWaypoints.sqf index f90ecb06be..da3484ceb0 100644 --- a/addons/microdagr/functions/fnc_deviceGetWaypoints.sqf +++ b/addons/microdagr/functions/fnc_deviceGetWaypoints.sqf @@ -4,7 +4,7 @@ * Device saving not implemented yet, just save to player object * * Arguments: - * Nothing + * None * * Return Value: * Waypoints @@ -16,4 +16,4 @@ */ #include "script_component.hpp" -(ace_player getVariable [QGVAR(waypoints), []]) +(ACE_player getVariable [QGVAR(waypoints), []]) diff --git a/addons/microdagr/functions/fnc_dialogClosedEH.sqf b/addons/microdagr/functions/fnc_dialogClosedEH.sqf index 0a7e5e5115..5180734644 100644 --- a/addons/microdagr/functions/fnc_dialogClosedEH.sqf +++ b/addons/microdagr/functions/fnc_dialogClosedEH.sqf @@ -3,13 +3,13 @@ * Handles the dialog closeing, switches back to display mode * * Arguments: - * Nothing + * None * * Return Value: - * Nothing + * None * * Example: - * [] call ace_microdagr_fnc_dialogClosedEH + * call ace_microdagr_fnc_dialogClosedEH * * Public: No */ diff --git a/addons/microdagr/functions/fnc_mapButtonDownEH.sqf b/addons/microdagr/functions/fnc_mapButtonDownEH.sqf index e7d2618160..8c564a7cfc 100644 --- a/addons/microdagr/functions/fnc_mapButtonDownEH.sqf +++ b/addons/microdagr/functions/fnc_mapButtonDownEH.sqf @@ -10,7 +10,7 @@ * 3: MousePosY * * Return Value: - * Nothing + * None * * Example: * [minimap,0,0.5,0.5] call ace_microdagr_fnc_mapButtonDownEH @@ -19,7 +19,7 @@ */ #include "script_component.hpp" -PARAMS_4(_theMap,_mouseButton,_xPos,_yPos); +params ["_theMap", "_mouseButton", "_xPos", "_yPos"]; //Only handle RMB if (_mouseButton != 1) exitWith {}; diff --git a/addons/microdagr/functions/fnc_mapDoubleTapEH.sqf b/addons/microdagr/functions/fnc_mapDoubleTapEH.sqf index 21a164ff2e..2226011215 100644 --- a/addons/microdagr/functions/fnc_mapDoubleTapEH.sqf +++ b/addons/microdagr/functions/fnc_mapDoubleTapEH.sqf @@ -9,7 +9,7 @@ * 3: MousePosY * * Return Value: - * Nothing + * None * * Example: * [minimap,0,0.5,0.5] call ace_microdagr_fnc_mapDoubleTapEH @@ -18,7 +18,7 @@ */ #include "script_component.hpp" -PARAMS_4(_theMap,_mouseButton,_xPos,_yPos); +params ["_theMap", "_mouseButton", "_xPos", "_yPos"]; private ["_worldPos"]; @@ -26,7 +26,7 @@ private ["_worldPos"]; if (_mouseButton != 0) exitWith {}; _worldPos = _theMap ctrlMapScreenToWorld [_xPos, _yPos]; -_worldPos set [2, (getTerrainHeightASL _worldPos)]; +_worldPos pushBack (getTerrainHeightASL _worldPos); GVAR(newWaypointPosition) = _worldPos; [APP_MODE_MARK] call FUNC(saveCurrentAndSetNewMode); diff --git a/addons/microdagr/functions/fnc_mapOnDrawEH.sqf b/addons/microdagr/functions/fnc_mapOnDrawEH.sqf index 644064d069..a74255601c 100644 --- a/addons/microdagr/functions/fnc_mapOnDrawEH.sqf +++ b/addons/microdagr/functions/fnc_mapOnDrawEH.sqf @@ -6,7 +6,7 @@ * 0: The Map * * Return Value: - * Nothing + * None * * Example: * [compassMap] call ace_microdagr_fnc_mapOnDrawEH @@ -15,10 +15,10 @@ */ #include "script_component.hpp" -PARAMS_1(_theMap); - private ["_mapSize", "_waypoints", "_size", "_targetPos", "_relBearing", "_wpName", "_wpPos", "_alpha"]; +params ["_theMap"]; + _mapSize = (ctrlPosition _theMap) select 3; _waypoints = [] call FUNC(deviceGetWaypoints); @@ -27,7 +27,7 @@ if (GVAR(currentApplicationPage) == 1) then { _theMap ctrlMapAnimAdd [0, DUMMY_ZOOM, DUMMY_POS]; ctrlMapAnimCommit _theMap; _size = 412 * _mapSize; - _theMap drawIcon [QUOTE(PATHTO_R(images\compass_starInverted.paa)), [1,1,1,1], DUMMY_POS, _size, _size, (-1 * (getDir ace_player)), '', 0 ]; + _theMap drawIcon [QUOTE(PATHTO_R(images\compass_starInverted.paa)), [1,1,1,1], DUMMY_POS, _size, _size, (-1 * (getDir ACE_player)), '', 0 ]; _theMap drawIcon [QUOTE(PATHTO_R(images\compass_needle.paa)), [0.533,0.769,0.76,1], DUMMY_POS, _size, _size, 0, '', 0 ]; if (GVAR(currentWaypoint) != -1) then { @@ -42,23 +42,23 @@ if (GVAR(currentApplicationPage) == 1) then { }; }; if ((count _targetPos) == 3) then { - _relBearing = [ace_player, _targetPos] call BIS_fnc_relativeDirTo; + _relBearing = [ACE_player, _targetPos] call BIS_fnc_relativeDirTo; _theMap drawIcon [QUOTE(PATHTO_R(images\compass_needle.paa)), [1,0.564,0.564,1], DUMMY_POS, _size, _size, _relBearing, '', 0 ]; }; }; } else { //Map Mode: if (GVAR(mapAutoTrackPosition)) then { - _theMap ctrlMapAnimAdd [0, (GVAR(mapZoom)/_mapSize), (getPosASL ace_player)]; + _theMap ctrlMapAnimAdd [0, (GVAR(mapZoom)/_mapSize), (getPosASL ACE_player)]; ctrlMapAnimCommit _theMap; }; _size = 48 * _mapSize; - _theMap drawIcon [QUOTE(PATHTO_R(images\icon_self.paa)), [0.533,0.769,0.76,0.75], (getPosASL ace_player), _size, _size, (getDir ace_player), '', 0 ]; + _theMap drawIcon [QUOTE(PATHTO_R(images\icon_self.paa)), [0.533,0.769,0.76,0.75], (getPosASL ACE_player), _size, _size, (getDir ACE_player), '', 0 ]; if (GVAR(settingShowAllWaypointsOnMap)) then { _size = 32 * _mapSize; { - EXPLODE_2_PVT(_x,_wpName,_wpPos); + _x params ["_wpName", "_wpPos"]; _alpha = if (_forEachIndex == GVAR(currentWaypoint)) then {1} else {0.5}; _theMap drawIcon [QUOTE(PATHTO_R(images\icon_mapWaypoints.paa)), [1,1,1,_alpha], _wpPos, _size, _size, 0, '', 0 ]; } forEach _waypoints; diff --git a/addons/microdagr/functions/fnc_modeMapButtons.sqf b/addons/microdagr/functions/fnc_modeMapButtons.sqf index 5de4bf9ca7..a0d74bec49 100644 --- a/addons/microdagr/functions/fnc_modeMapButtons.sqf +++ b/addons/microdagr/functions/fnc_modeMapButtons.sqf @@ -6,7 +6,7 @@ * 0: String of the map button pressed * * Return Value: - * Nothing + * None * * Example: * ["autotrack"] call ace_microdagr_fnc_modeMapButtons @@ -15,7 +15,7 @@ */ #include "script_component.hpp" -PARAMS_1(_mode); +params ["_mode"]; [-1] call FUNC(saveCurrentAndSetNewMode); //backup current draw pos/zoom diff --git a/addons/microdagr/functions/fnc_moduleMapFill.sqf b/addons/microdagr/functions/fnc_moduleMapFill.sqf index d07b0bc518..d88bc56e87 100644 --- a/addons/microdagr/functions/fnc_moduleMapFill.sqf +++ b/addons/microdagr/functions/fnc_moduleMapFill.sqf @@ -8,7 +8,7 @@ * 2: Module Activated * * Return Value: - * Nothing + * None * * Example: * [module, [], true] call ace_microdagr_fnc_moduleMapFill @@ -17,10 +17,7 @@ */ #include "script_component.hpp" -PARAMS_3(_logic,_syncedUnits,_activated); +if !(isServer) exitWith {}; +params ["_logic", "_syncedUnits", "_activated"]; if (!_activated) exitWith {WARNING("Module Placed but not active");}; - -if (isServer) then { - [_logic, QGVAR(MapDataAvailable), "MapDataAvailable"] call EFUNC(common,readSettingFromModule); -}; diff --git a/addons/microdagr/functions/fnc_openDisplay.sqf b/addons/microdagr/functions/fnc_openDisplay.sqf index b4cec0fe46..c619890bf3 100644 --- a/addons/microdagr/functions/fnc_openDisplay.sqf +++ b/addons/microdagr/functions/fnc_openDisplay.sqf @@ -6,7 +6,7 @@ * 0: Display Mode to show the microDAGR in * * Return Value: - * Nothing + * None * * Example: * [1] call ace_microdagr_fnc_openDisplay @@ -17,7 +17,7 @@ private ["_oldShowMode", "_args", "_pfID", "_player"]; -DEFAULT_PARAM(0,_newDisplayShowMode,-1); +params [["_newDisplayShowMode", -1, [-1]]]; _oldShowMode = GVAR(currentShowMode); if (_newDisplayShowMode == -1) then { @@ -34,7 +34,7 @@ if ((_newDisplayShowMode == DISPLAY_MODE_DIALOG) && {!([DISPLAY_MODE_DIALOG] cal //On first-startup if (GVAR(currentApplicationPage) == APP_MODE_NULL) then { GVAR(currentApplicationPage) = APP_MODE_INFODISPLAY; - GVAR(mapPosition) = getPos ace_player; + GVAR(mapPosition) = getPos ACE_player; }; if (_newDisplayShowMode in [DISPLAY_MODE_CLOSED, DISPLAY_MODE_HIDDEN]) then { @@ -74,14 +74,14 @@ if ((_oldShowMode == DISPLAY_MODE_CLOSED) && {GVAR(currentShowMode) != DISPLAY_M //Start a pfeh to update display and handle hiding display [{ - PARAMS_2(_args,_pfID); - EXPLODE_1_PVT(_args,_player); - if ((isNull ace_player) || {!alive ace_player} || {ace_player != _player} || {!("ACE_microDAGR" in (items ace_player))} || {GVAR(currentShowMode) == DISPLAY_MODE_CLOSED}) then { + params ["_args", "_idPFH"]; + _args params ["_player"]; + if ((isNull ACE_player) || {!alive ACE_player} || {ACE_player != _player} || {!("ACE_microDAGR" in (items ACE_player))} || {GVAR(currentShowMode) == DISPLAY_MODE_CLOSED}) then { //Close Display if still open: if (GVAR(currentShowMode) != DISPLAY_MODE_CLOSED) then { [DISPLAY_MODE_CLOSED] call FUNC(openDisplay); }; - [_pfID] call CBA_fnc_removePerFrameHandler; + [_idPFH] call CBA_fnc_removePerFrameHandler; } else { if (GVAR(currentShowMode) == DISPLAY_MODE_HIDDEN) then { //If display is hidden, and we can show, then swithc modes: @@ -96,5 +96,5 @@ if ((_oldShowMode == DISPLAY_MODE_CLOSED) && {GVAR(currentShowMode) != DISPLAY_M }; }; }; - }, 0.1, [ace_player]] call CBA_fnc_addPerFrameHandler; + }, 0.1, [ACE_player]] call CBA_fnc_addPerFrameHandler; }; diff --git a/addons/microdagr/functions/fnc_recieveRangefinderData.sqf b/addons/microdagr/functions/fnc_recieveRangefinderData.sqf index 154dfff94a..8b2c6672a8 100644 --- a/addons/microdagr/functions/fnc_recieveRangefinderData.sqf +++ b/addons/microdagr/functions/fnc_recieveRangefinderData.sqf @@ -8,7 +8,7 @@ * 2: Inclination (Degrees) * * Return Value: - * Nothing + * None * * Example: * [1000, 45, 1] call ace_microdagr_fnc_recieveRangefinderData @@ -19,7 +19,7 @@ private ["_horizontalDistance", "_verticleDistance", "_targetOffset", "_targetPosASL"]; -PARAMS_3(_slopeDistance,_azimuth,_inclination); +params ["_slopeDistance", "_azimuth", "_inclination"]; if (GVAR(currentWaypoint) != -2) exitWith {}; //Only take waypoint when "connected" if (_slopeDistance < 0) exitWith {}; //Bad Data @@ -29,6 +29,6 @@ _verticleDistance = (sin _inclination) * _slopeDistance; _targetOffset = [((sin _azimuth) * _horizontalDistance), ((cos _azimuth) * _horizontalDistance), _verticleDistance]; //This assumes the "rangefinder view" pos is very close to player, at worst the turret should only be a few meters different -_targetPosASL = (getPosASL ace_player) vectorAdd _targetOffset; +_targetPosASL = (getPosASL ACE_player) vectorAdd _targetOffset; GVAR(rangeFinderPositionASL) = _targetPosASL; diff --git a/addons/microdagr/functions/fnc_saveCurrentAndSetNewMode.sqf b/addons/microdagr/functions/fnc_saveCurrentAndSetNewMode.sqf index 64a5cab991..7cbec9f242 100644 --- a/addons/microdagr/functions/fnc_saveCurrentAndSetNewMode.sqf +++ b/addons/microdagr/functions/fnc_saveCurrentAndSetNewMode.sqf @@ -7,7 +7,7 @@ * 0: New Mode * * Return Value: - * Nothing + * None * * Example: * [2] call ace_microdagr_fnc_saveCurrentAndSetNewMode @@ -16,24 +16,21 @@ */ #include "script_component.hpp" -private ["_display", "_theMap", "_mapSize", "_centerPos", "_mapCtrlPos"]; +private ["_display", "_theMap", "_centerPos", "_mapCtrlPos"]; -PARAMS_1(_newMode); +params ["_newMode"]; disableSerialization; -_display = displayNull; -if (GVAR(currentShowMode) == DISPLAY_MODE_DIALOG) then { - _display = (uiNamespace getVariable [QGVAR(DialogDisplay), displayNull]); -} else { - _display = (uiNamespace getVariable [QGVAR(RscTitleDisplay), displayNull]); -}; +_display = uiNamespace getVariable [[QGVAR(RscTitleDisplay), QGVAR(DialogDisplay)] select (GVAR(currentShowMode) == DISPLAY_MODE_DIALOG), displayNull]; + if (isNull _display) exitWith {ERROR("No Display");}; if (GVAR(currentApplicationPage) == 2) then { - _theMap = if (!GVAR(mapShowTexture)) then {_display displayCtrl IDC_MAPPLAIN} else {_display displayCtrl IDC_MAPDETAILS}; + _theMap = [_display displayCtrl IDC_MAPDETAILS, _display displayCtrl IDC_MAPPLAIN] select (!GVAR(mapShowTexture)); _mapCtrlPos = ctrlPosition _theMap; - _mapSize = _mapCtrlPos select 3; - _centerPos = [((_mapCtrlPos select 0) + (_mapCtrlPos select 2) / 2), ((_mapCtrlPos select 1) + (_mapCtrlPos select 3) / 2)]; + + _mapCtrlPos params ["_mapCtrlPosX", "_mapCtrlPosY", "_mapCtrlPosZ", "_mapSize"]; + _centerPos = [(_mapCtrlPosX + _mapCtrlPosZ / 2), (_mapCtrlPosY + _mapSize / 2)]; GVAR(mapPosition) = _theMap ctrlMapScreenToWorld _centerPos; GVAR(mapZoom) = (ctrlMapScale _theMap) * _mapSize; diff --git a/addons/microdagr/functions/fnc_showApplicationPage.sqf b/addons/microdagr/functions/fnc_showApplicationPage.sqf index 3c042fdff3..dba6b54f18 100644 --- a/addons/microdagr/functions/fnc_showApplicationPage.sqf +++ b/addons/microdagr/functions/fnc_showApplicationPage.sqf @@ -3,10 +3,10 @@ * Changes the "application page" shown on the microDAGR * * Arguments: - * Nothing + * None * * Return Value: - * Nothing + * None * * Example: * [] call ace_microdagr_fnc_showApplicationPage @@ -19,12 +19,8 @@ private ["_display", "_theMap", "_mapSize"]; disableSerialization; -_display = displayNull; -if (GVAR(currentShowMode) == DISPLAY_MODE_DIALOG) then { - _display = (uiNamespace getVariable [QGVAR(DialogDisplay), displayNull]); -} else { - _display = (uiNamespace getVariable [QGVAR(RscTitleDisplay), displayNull]); -}; +_display = uiNamespace getVariable [[QGVAR(RscTitleDisplay), QGVAR(DialogDisplay)] select (GVAR(currentShowMode) == DISPLAY_MODE_DIALOG), displayNull]; + if (isNull _display) exitWith {ERROR("No Display");}; //TopBar diff --git a/addons/microdagr/functions/fnc_updateDisplay.sqf b/addons/microdagr/functions/fnc_updateDisplay.sqf index 910f422c75..8ab35bd2e5 100644 --- a/addons/microdagr/functions/fnc_updateDisplay.sqf +++ b/addons/microdagr/functions/fnc_updateDisplay.sqf @@ -3,10 +3,10 @@ * Updates the display (several times a second) called from the pfeh * * Arguments: - * Nothing + * None * * Return Value: - * Nothing + * None * * Example: * [] call ace_microdagr_fnc_updateDisplay @@ -18,12 +18,8 @@ private ["_display", "_waypoints", "_posString", "_eastingText", "_northingText", "_numASL", "_aboveSeaLevelText", "_compassAngleText", "_targetPos", "_targetPosName", "_targetPosLocationASL", "_bearingText", "_rangeText", "_targetName", "_bearing", "_2dDistanceKm", "_SpeedText", "_playerPos2d", "_wpListBox", "_currentIndex", "_wpName", "_wpPos", "_settingListBox", "_yearString", "_monthSring", "_dayString"]; disableSerialization; -_display = displayNull; -if (GVAR(currentShowMode) == DISPLAY_MODE_DIALOG) then { - _display = (uiNamespace getVariable [QGVAR(DialogDisplay), displayNull]); -} else { - _display = (uiNamespace getVariable [QGVAR(RscTitleDisplay), displayNull]); -}; +_display = uiNamespace getVariable [[QGVAR(RscTitleDisplay), QGVAR(DialogDisplay)] select (GVAR(currentShowMode) == DISPLAY_MODE_DIALOG), displayNull]; + if (isNull _display) exitWith {ERROR("No Display");}; //Fade "shell" at night @@ -44,21 +40,21 @@ case (APP_MODE_INFODISPLAY): { (_display displayCtrl IDC_MODEDISPLAY_NORTHING) ctrlSetText _northingText; //Elevation: - _numASL = ((getPosASL ace_player) select 2) + EGVAR(common,mapAltitude); + _numASL = ((getPosASL ACE_player) select 2) + EGVAR(common,mapAltitude); _aboveSeaLevelText = [_numASL, 5, 0] call CBA_fnc_formatNumber; _aboveSeaLevelText = if (_numASL > 0) then {"+" + _aboveSeaLevelText + " MSL"} else {_aboveSeaLevelText + " MSL"}; (_display displayCtrl IDC_MODEDISPLAY_ELEVATIONNUM) ctrlSetText _aboveSeaLevelText; //Heading: _compassAngleText = if (GVAR(settingUseMils)) then { - [(floor ((6400 / 360) * (getDir ace_player))), 4, 0] call CBA_fnc_formatNumber; + [(floor ((6400 / 360) * (getDir ACE_player))), 4, 0] call CBA_fnc_formatNumber; } else { - ([(floor (getDir ace_player)), 3, 1] call CBA_fnc_formatNumber) + "°" //degree symbol is in UTF-8 + ([(floor (getDir ACE_player)), 3, 1] call CBA_fnc_formatNumber) + "°" //degree symbol is in UTF-8 }; (_display displayCtrl IDC_MODEDISPLAY_HEADINGNUM) ctrlSetText _compassAngleText; //Speed: - (_display displayCtrl IDC_MODEDISPLAY_SPEEDNUM) ctrlSetText format ["%1kph", (round (speed (vehicle ace_player)))];; + (_display displayCtrl IDC_MODEDISPLAY_SPEEDNUM) ctrlSetText format ["%1kph", (round (speed (vehicle ACE_player)))];; if (GVAR(currentWaypoint) == -1) then { @@ -89,13 +85,13 @@ case (APP_MODE_INFODISPLAY): { }; if (!(_targetPosLocationASL isEqualTo [])) then { - _bearing = [(getPosASL ace_player), _targetPosLocationASL] call BIS_fnc_dirTo; + _bearing = [(getPosASL ACE_player), _targetPosLocationASL] call BIS_fnc_dirTo; _bearingText = if (GVAR(settingUseMils)) then { [(floor ((6400 / 360) * (_bearing))), 4, 0] call CBA_fnc_formatNumber; } else { ([(floor (_bearing)), 3, 1] call CBA_fnc_formatNumber) + "°" //degree symbol is in UTF-8 }; - _2dDistanceKm = (((getPosASL ace_player) select [0,2]) distance (_targetPosLocationASL select [0,2])) / 1000; + _2dDistanceKm = (((getPosASL ACE_player) select [0,2]) distance (_targetPosLocationASL select [0,2])) / 1000; _rangeText = format ["%1km", ([_2dDistanceKm, 1, 1] call CBA_fnc_formatNumber)]; _numASL = (_targetPosLocationASL select 2) + EGVAR(common,mapAltitude); _aboveSeaLevelText = [_numASL, 5, 0] call CBA_fnc_formatNumber; @@ -111,14 +107,14 @@ case (APP_MODE_INFODISPLAY): { case (APP_MODE_COMPASS): { //Heading: _compassAngleText = if (GVAR(settingUseMils)) then { - [(floor ((6400 / 360) * (getDir ace_player))), 4, 0] call CBA_fnc_formatNumber; + [(floor ((6400 / 360) * (getDir ACE_player))), 4, 0] call CBA_fnc_formatNumber; } else { - ([(floor (getDir ace_player)), 3, 1] call CBA_fnc_formatNumber) + "°" //degree symbol is in UTF-8 + ([(floor (getDir ACE_player)), 3, 1] call CBA_fnc_formatNumber) + "°" //degree symbol is in UTF-8 }; (_display displayCtrl IDC_MODECOMPASS_HEADING) ctrlSetText _compassAngleText; //Speed: - _SpeedText = format ["%1kph", (round (speed (vehicle ace_player)))];; + _SpeedText = format ["%1kph", (round (speed (vehicle ACE_player)))];; (_display displayCtrl IDC_MODECOMPASS_SPEED) ctrlSetText _SpeedText; if (GVAR(currentWaypoint) == -1) then { @@ -126,7 +122,7 @@ case (APP_MODE_COMPASS): { (_display displayCtrl IDC_MODECOMPASS_RANGE) ctrlSetText ""; (_display displayCtrl IDC_MODECOMPASS_TARGET) ctrlSetText ""; } else { - _playerPos2d = (getPosASL ace_player) select [0,2]; + _playerPos2d = (getPosASL ACE_player) select [0,2]; _targetPosName = ""; _targetPosLocationASL = []; @@ -147,13 +143,13 @@ case (APP_MODE_COMPASS): { _rangeText = "---"; if (!(_targetPosLocationASL isEqualTo [])) then { - _bearing = [(getPosASL ace_player), _targetPosLocationASL] call BIS_fnc_dirTo; + _bearing = [(getPosASL ACE_player), _targetPosLocationASL] call BIS_fnc_dirTo; _bearingText = if (GVAR(settingUseMils)) then { [(floor ((6400 / 360) * (_bearing))), 4, 0] call CBA_fnc_formatNumber; } else { ([(floor (_bearing)), 3, 1] call CBA_fnc_formatNumber) + "°" //degree symbol is in UTF-8 }; - _2dDistanceKm = (((getPosASL ace_player) select [0,2]) distance (_targetPosLocationASL select [0,2])) / 1000; + _2dDistanceKm = (((getPosASL ACE_player) select [0,2]) distance (_targetPosLocationASL select [0,2])) / 1000; _rangeText = format ["%1km", ([_2dDistanceKm, 1, 1] call CBA_fnc_formatNumber)]; }; @@ -171,7 +167,7 @@ case (APP_MODE_WAYPOINTS): { { EXPLODE_2_PVT(_x,_wpName,_wpPos); _wpListBox lbAdd _wpName; - _2dDistanceKm = (((getPosASL ace_player) select [0,2]) distance (_wpPos select [0,2])) / 1000; + _2dDistanceKm = (((getPosASL ACE_player) select [0,2]) distance (_wpPos select [0,2])) / 1000; _wpListBox lbSetTextRight [_forEachIndex, (format ["%1km", ([_2dDistanceKm, 1, 1] call CBA_fnc_formatNumber)])]; } forEach _waypoints; From 6a123020d2d32a69f92f0d9c609d4f0db46be9c7 Mon Sep 17 00:00:00 2001 From: gienkov Date: Wed, 26 Aug 2015 08:55:50 +0200 Subject: [PATCH 73/91] fail to find BP on limbs with TQ on --- addons/medical/functions/fnc_actionCheckBloodPressure.sqf | 5 +++-- .../functions/fnc_actionCheckBloodPressureLocal.sqf | 8 +++++++- addons/medical/functions/fnc_actionCheckPulse.sqf | 2 +- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/addons/medical/functions/fnc_actionCheckBloodPressure.sqf b/addons/medical/functions/fnc_actionCheckBloodPressure.sqf index e8e03bb4c0..646e472f70 100644 --- a/addons/medical/functions/fnc_actionCheckBloodPressure.sqf +++ b/addons/medical/functions/fnc_actionCheckBloodPressure.sqf @@ -14,7 +14,8 @@ #include "script_component.hpp" -private ["_caller","_target"]; +private ["_caller","_target","_selectionName"]; _caller = _this select 0; _target = _this select 1; -[[_caller, _target], QUOTE(DFUNC(actionCheckBloodPressureLocal)), _target] call EFUNC(common,execRemoteFnc); /* TODO Replace by event system */ +_selectionName = _this select 2; +[[_caller, _target, _selectionName], QUOTE(DFUNC(actionCheckBloodPressureLocal)), _target] call EFUNC(common,execRemoteFnc); /* TODO Replace by event system */ diff --git a/addons/medical/functions/fnc_actionCheckBloodPressureLocal.sqf b/addons/medical/functions/fnc_actionCheckBloodPressureLocal.sqf index 82edd1749f..92120a280c 100644 --- a/addons/medical/functions/fnc_actionCheckBloodPressureLocal.sqf +++ b/addons/medical/functions/fnc_actionCheckBloodPressureLocal.sqf @@ -14,9 +14,10 @@ #include "script_component.hpp" -private ["_caller","_target","_bloodPressure","_bloodPressureHigh","_bloodPressureLow", "_logOutPut", "_output"]; +private ["_caller","_target","_selectionName","_bloodPressure","_bloodPressureHigh","_bloodPressureLow", "_logOutPut", "_output"]; _caller = _this select 0; _target = _this select 1; +_selectionName = _this select 2; _bloodPressure = [_target] call FUNC(getBloodPressure); if (!alive _target) then { @@ -54,6 +55,11 @@ if ([_caller] call FUNC(isMedic)) then { }; }; +if (_selectionName in ["hand_l","hand_r"] && {[_unit, _selectionName] call FUNC(hasTourniquetAppliedTo)}) then { + _output = LSTRING(Check_Bloodpressure_Output_6); + _logOutPut = ""; +}; + ["displayTextStructured", [_caller], [[_output, [_target] call EFUNC(common,getName), round(_bloodPressureHigh),round(_bloodPressureLow)], 1.75, _caller]] call EFUNC(common,targetEvent); if (_logOutPut != "") then { diff --git a/addons/medical/functions/fnc_actionCheckPulse.sqf b/addons/medical/functions/fnc_actionCheckPulse.sqf index 134cf7dd20..f615c69983 100644 --- a/addons/medical/functions/fnc_actionCheckPulse.sqf +++ b/addons/medical/functions/fnc_actionCheckPulse.sqf @@ -18,4 +18,4 @@ private ["_caller","_target","_selectionName"]; _caller = _this select 0; _target = _this select 1; _selectionName = _this select 2; -[[_caller, _target, _selectionName], QUOTE(DFUNC(actionCheckPulseLocal)), _target] call EFUNC(common,execRemoteFnc); /* TODO Replace by event system */ \ No newline at end of file +[[_caller, _target, _selectionName], QUOTE(DFUNC(actionCheckPulseLocal)), _target] call EFUNC(common,execRemoteFnc); /* TODO Replace by event system */ From 5a0e95dcf0de8b4cd17f2173ad04db09d39931dc Mon Sep 17 00:00:00 2001 From: Michael Braun Date: Wed, 26 Aug 2015 14:04:17 +0200 Subject: [PATCH 74/91] Simplified log macros --- addons/main/script_macros.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/addons/main/script_macros.hpp b/addons/main/script_macros.hpp index 78205a8d11..566ba9ccd6 100644 --- a/addons/main/script_macros.hpp +++ b/addons/main/script_macros.hpp @@ -97,9 +97,9 @@ // Time functions for accuracy per frame #define ACE_tickTime (ACE_time + (diag_tickTime - ACE_diagTime)) -#define ACE_LOG(module,level,message) diag_log text format [QUOTE([ACE] (%1) %2: %3), module, level, message]; -#define ACE_LOGERROR(message) ACE_LOG(QUOTE(COMPONENT),"ERROR",message) -#define ACE_LOGWARNING(message) ACE_LOG(QUOTE(COMPONENT),"WARNING",message) -#define ACE_LOGINFO(message) ACE_LOG(QUOTE(COMPONENT),"INFO",message) +#define ACE_LOG(module,level,message) diag_log text format [QUOTE([ACE] (module) level: %1), message]; +#define ACE_LOGERROR(message) ACE_LOG(COMPONENT,ERROR,message) +#define ACE_LOGWARNING(message) ACE_LOG(COMPONENT,WARNING,message) +#define ACE_LOGINFO(message) ACE_LOG(COMPONENT,INFO,message) #include "script_debug.hpp" From a17d94c213b9c0c99c5f89b6d841cad29d40cbf9 Mon Sep 17 00:00:00 2001 From: Michael Braun Date: Wed, 26 Aug 2015 14:12:17 +0200 Subject: [PATCH 75/91] Removed semicolon of log macro --- addons/main/script_macros.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/main/script_macros.hpp b/addons/main/script_macros.hpp index 566ba9ccd6..a97d1bf29b 100644 --- a/addons/main/script_macros.hpp +++ b/addons/main/script_macros.hpp @@ -97,7 +97,7 @@ // Time functions for accuracy per frame #define ACE_tickTime (ACE_time + (diag_tickTime - ACE_diagTime)) -#define ACE_LOG(module,level,message) diag_log text format [QUOTE([ACE] (module) level: %1), message]; +#define ACE_LOG(module,level,message) diag_log text format [QUOTE([ACE] (module) level: %1), message] #define ACE_LOGERROR(message) ACE_LOG(COMPONENT,ERROR,message) #define ACE_LOGWARNING(message) ACE_LOG(COMPONENT,WARNING,message) #define ACE_LOGINFO(message) ACE_LOG(COMPONENT,INFO,message) From 5f6584ba3fe15aebcfba3fc97a8cc14112fb1e1b Mon Sep 17 00:00:00 2001 From: Michael Braun Date: Wed, 26 Aug 2015 15:53:03 +0200 Subject: [PATCH 76/91] Added Log format macros for use with not printing it to the log. --- addons/main/script_macros.hpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/addons/main/script_macros.hpp b/addons/main/script_macros.hpp index a97d1bf29b..34d9ca7a02 100644 --- a/addons/main/script_macros.hpp +++ b/addons/main/script_macros.hpp @@ -97,9 +97,13 @@ // Time functions for accuracy per frame #define ACE_tickTime (ACE_time + (diag_tickTime - ACE_diagTime)) -#define ACE_LOG(module,level,message) diag_log text format [QUOTE([ACE] (module) level: %1), message] +#define ACE_LOG(module,level,message) diag_log text ACE_LOGFORMAT(module,level,message) +#define ACE_LOGFORMAT(module,level,message) format [QUOTE([ACE] (module) level: %1), message] #define ACE_LOGERROR(message) ACE_LOG(COMPONENT,ERROR,message) +#define ACE_ERRORFORMAT(message) ACE_LOGFORMAT(COMPONENT,ERROR,message) #define ACE_LOGWARNING(message) ACE_LOG(COMPONENT,WARNING,message) +#define ACE_WARNINGFORMAT(message) ACE_LOGFORMAT(COMPONENT,WARNING,message) #define ACE_LOGINFO(message) ACE_LOG(COMPONENT,INFO,message) +#define ACE_INFOFORMAT(message) ACE_LOGFORMAT(COMPONENT,INFO,message) #include "script_debug.hpp" From fd204d972d58e39f7df4494e01d3af608af6a030 Mon Sep 17 00:00:00 2001 From: Michael Braun Date: Wed, 26 Aug 2015 16:45:28 +0200 Subject: [PATCH 77/91] Fixed issue with ERROR conflicting with log level input --- addons/main/script_macros.hpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/addons/main/script_macros.hpp b/addons/main/script_macros.hpp index 34d9ca7a02..9ac5e034d6 100644 --- a/addons/main/script_macros.hpp +++ b/addons/main/script_macros.hpp @@ -98,12 +98,12 @@ #define ACE_tickTime (ACE_time + (diag_tickTime - ACE_diagTime)) #define ACE_LOG(module,level,message) diag_log text ACE_LOGFORMAT(module,level,message) -#define ACE_LOGFORMAT(module,level,message) format [QUOTE([ACE] (module) level: %1), message] -#define ACE_LOGERROR(message) ACE_LOG(COMPONENT,ERROR,message) -#define ACE_ERRORFORMAT(message) ACE_LOGFORMAT(COMPONENT,ERROR,message) -#define ACE_LOGWARNING(message) ACE_LOG(COMPONENT,WARNING,message) -#define ACE_WARNINGFORMAT(message) ACE_LOGFORMAT(COMPONENT,WARNING,message) -#define ACE_LOGINFO(message) ACE_LOG(COMPONENT,INFO,message) -#define ACE_INFOFORMAT(message) ACE_LOGFORMAT(COMPONENT,INFO,message) +#define ACE_LOGFORMAT(module,level,message) format [QUOTE([ACE] (module) %1: %2), level, message] +#define ACE_LOGERROR(message) ACE_LOG(COMPONENT,"ERROR",message) +#define ACE_ERRORFORMAT(message) ACE_LOGFORMAT(COMPONENT,"ERROR",message) +#define ACE_LOGWARNING(message) ACE_LOG(COMPONENT,"WARNING",message) +#define ACE_WARNINGFORMAT(message) ACE_LOGFORMAT(COMPONENT,"WARNING",message) +#define ACE_LOGINFO(message) ACE_LOG(COMPONENT,"INFO",message) +#define ACE_INFOFORMAT(message) ACE_LOGFORMAT(COMPONENT,"INFO",message) #include "script_debug.hpp" From 9ca19def7076b6cd66cefd3ae88a7e368cf3b729 Mon Sep 17 00:00:00 2001 From: Michael Braun Date: Wed, 26 Aug 2015 17:09:31 +0200 Subject: [PATCH 78/91] Added autoformatting variations for log macros --- addons/main/script_macros.hpp | 56 ++++++++++++++++++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) diff --git a/addons/main/script_macros.hpp b/addons/main/script_macros.hpp index 9ac5e034d6..2113161ad7 100644 --- a/addons/main/script_macros.hpp +++ b/addons/main/script_macros.hpp @@ -98,12 +98,66 @@ #define ACE_tickTime (ACE_time + (diag_tickTime - ACE_diagTime)) #define ACE_LOG(module,level,message) diag_log text ACE_LOGFORMAT(module,level,message) -#define ACE_LOGFORMAT(module,level,message) format [QUOTE([ACE] (module) %1: %2), level, message] +#define ACE_LOGFORMAT(module,level,message) FORMAT_2(QUOTE([ACE] (module) %1: %2),level,message) + #define ACE_LOGERROR(message) ACE_LOG(COMPONENT,"ERROR",message) +#define ACE_LOGERROR_1(message,arg1) ACE_LOGERROR(FORMAT_1(message,arg1)) +#define ACE_LOGERROR_2(message,arg1,arg2) ACE_LOGERROR(FORMAT_2(message,arg1,arg2)) +#define ACE_LOGERROR_3(message,arg1,arg2,arg3) ACE_LOGERROR(FORMAT_3(message,arg1,arg2,arg3)) +#define ACE_LOGERROR_4(message,arg1,arg2,arg3,arg4) ACE_LOGERROR(FORMAT_4(message,arg1,arg2,arg3,arg4)) +#define ACE_LOGERROR_5(message,arg1,arg2,arg3,arg4,arg5) ACE_LOGERROR(FORMAT_5(message,arg1,arg2,arg3,arg4,arg5)) +#define ACE_LOGERROR_6(message,arg1,arg2,arg3,arg4,arg5,arg6) ACE_LOGERROR(FORMAT_6(message,arg1,arg2,arg3,arg4,arg5,arg6)) +#define ACE_LOGERROR_7(message,arg1,arg2,arg3,arg4,arg5,arg6,arg7) ACE_LOGERROR(FORMAT_7(message,arg1,arg2,arg3,arg4,arg5,arg6,arg7)) +#define ACE_LOGERROR_8(message,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8) ACE_LOGERROR(FORMAT_8(message,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8)) + #define ACE_ERRORFORMAT(message) ACE_LOGFORMAT(COMPONENT,"ERROR",message) +#define ACE_ERRORFORMAT_1(message,arg1) ACE_ERRORFORMAT(FORMAT_1(message,arg1)) +#define ACE_ERRORFORMAT_2(message,arg1,arg2) ACE_ERRORFORMAT(FORMAT_2(message,arg1,arg2)) +#define ACE_ERRORFORMAT_3(message,arg1,arg2,arg3) ACE_ERRORFORMAT(FORMAT_3(message,arg1,arg2,arg3)) +#define ACE_ERRORFORMAT_4(message,arg1,arg2,arg3,arg4) ACE_ERRORFORMAT(FORMAT_4(message,arg1,arg2,arg3,arg4)) +#define ACE_ERRORFORMAT_5(message,arg1,arg2,arg3,arg4,arg5) ACE_ERRORFORMAT(FORMAT_5(message,arg1,arg2,arg3,arg4,arg5)) +#define ACE_ERRORFORMAT_6(message,arg1,arg2,arg3,arg4,arg5,arg6) ACE_ERRORFORMAT(FORMAT_6(message,arg1,arg2,arg3,arg4,arg5,arg6)) +#define ACE_ERRORFORMAT_7(message,arg1,arg2,arg3,arg4,arg5,arg6,arg7) ACE_ERRORFORMAT(FORMAT_7(message,arg1,arg2,arg3,arg4,arg5,arg6,arg7)) +#define ACE_ERRORFORMAT_8(message,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8) ACE_ERRORFORMAT(FORMAT_8(message,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8)) + #define ACE_LOGWARNING(message) ACE_LOG(COMPONENT,"WARNING",message) +#define ACE_LOGWARNING_1(message,arg1) ACE_LOGWARNING(FORMAT_1(message,arg1)) +#define ACE_LOGWARNING_2(message,arg1,arg2) ACE_LOGWARNING(FORMAT_2(message,arg1,arg2)) +#define ACE_LOGWARNING_3(message,arg1,arg2,arg3) ACE_LOGWARNING(FORMAT_3(message,arg1,arg2,arg3)) +#define ACE_LOGWARNING_4(message,arg1,arg2,arg3,arg4) ACE_LOGWARNING(FORMAT_4(message,arg1,arg2,arg3,arg4)) +#define ACE_LOGWARNING_5(message,arg1,arg2,arg3,arg4,arg5) ACE_LOGWARNING(FORMAT_5(message,arg1,arg2,arg3,arg4,arg5)) +#define ACE_LOGWARNING_6(message,arg1,arg2,arg3,arg4,arg5,arg6) ACE_LOGWARNING(FORMAT_6(message,arg1,arg2,arg3,arg4,arg5,arg6)) +#define ACE_LOGWARNING_7(message,arg1,arg2,arg3,arg4,arg5,arg6,arg7) ACE_LOGWARNING(FORMAT_7(message,arg1,arg2,arg3,arg4,arg5,arg6,arg7)) +#define ACE_LOGWARNING_8(message,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8) ACE_LOGWARNING(FORMAT_8(message,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8)) + #define ACE_WARNINGFORMAT(message) ACE_LOGFORMAT(COMPONENT,"WARNING",message) +#define ACE_WARNINGFORMAT_1(message,arg1) ACE_WARNINGFORMAT(FORMAT_1(message,arg1)) +#define ACE_WARNINGFORMAT_2(message,arg1,arg2) ACE_WARNINGFORMAT(FORMAT_2(message,arg1,arg2)) +#define ACE_WARNINGFORMAT_3(message,arg1,arg2,arg3) ACE_WARNINGFORMAT(FORMAT_3(message,arg1,arg2,arg3)) +#define ACE_WARNINGFORMAT_4(message,arg1,arg2,arg3,arg4) ACE_WARNINGFORMAT(FORMAT_4(message,arg1,arg2,arg3,arg4)) +#define ACE_WARNINGFORMAT_5(message,arg1,arg2,arg3,arg4,arg5) ACE_WARNINGFORMAT(FORMAT_5(message,arg1,arg2,arg3,arg4,arg5)) +#define ACE_WARNINGFORMAT_6(message,arg1,arg2,arg3,arg4,arg5,arg6) ACE_WARNINGFORMAT(FORMAT_6(message,arg1,arg2,arg3,arg4,arg5,arg6)) +#define ACE_WARNINGFORMAT_7(message,arg1,arg2,arg3,arg4,arg5,arg6,arg7) ACE_WARNINGFORMAT(FORMAT_7(message,arg1,arg2,arg3,arg4,arg5,arg6,arg7)) +#define ACE_WARNINGFORMAT_8(message,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8) ACE_WARNINGFORMAT(FORMAT_8(message,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8)) + #define ACE_LOGINFO(message) ACE_LOG(COMPONENT,"INFO",message) +#define ACE_LOGINFO_1(message,arg1) ACE_LOGINFO(FORMAT_1(message,arg1)) +#define ACE_LOGINFO_2(message,arg1,arg2) ACE_LOGINFO(FORMAT_2(message,arg1,arg2)) +#define ACE_LOGINFO_3(message,arg1,arg2,arg3) ACE_LOGINFO(FORMAT_3(message,arg1,arg2,arg3)) +#define ACE_LOGINFO_4(message,arg1,arg2,arg3,arg4) ACE_LOGINFO(FORMAT_4(message,arg1,arg2,arg3,arg4)) +#define ACE_LOGINFO_5(message,arg1,arg2,arg3,arg4,arg5) ACE_LOGINFO(FORMAT_5(message,arg1,arg2,arg3,arg4,arg5)) +#define ACE_LOGINFO_6(message,arg1,arg2,arg3,arg4,arg5,arg6) ACE_LOGINFO(FORMAT_6(message,arg1,arg2,arg3,arg4,arg5,arg6)) +#define ACE_LOGINFO_7(message,arg1,arg2,arg3,arg4,arg5,arg6,arg7) ACE_LOGINFO(FORMAT_7(message,arg1,arg2,arg3,arg4,arg5,arg6,arg7)) +#define ACE_LOGINFO_8(message,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8) ACE_LOGINFO(FORMAT_8(message,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8)) + #define ACE_INFOFORMAT(message) ACE_LOGFORMAT(COMPONENT,"INFO",message) +#define ACE_INFOFORMAT_1(message,arg1) ACE_INFOFORMAT(FORMAT_1(message,arg1)) +#define ACE_INFOFORMAT_2(message,arg1,arg2) ACE_INFOFORMAT(FORMAT_2(message,arg1,arg2)) +#define ACE_INFOFORMAT_3(message,arg1,arg2,arg3) ACE_INFOFORMAT(FORMAT_3(message,arg1,arg2,arg3)) +#define ACE_INFOFORMAT_4(message,arg1,arg2,arg3,arg4) ACE_INFOFORMAT(FORMAT_4(message,arg1,arg2,arg3,arg4)) +#define ACE_INFOFORMAT_5(message,arg1,arg2,arg3,arg4,arg5) ACE_INFOFORMAT(FORMAT_5(message,arg1,arg2,arg3,arg4,arg5)) +#define ACE_INFOFORMAT_6(message,arg1,arg2,arg3,arg4,arg5,arg6) ACE_INFOFORMAT(FORMAT_6(message,arg1,arg2,arg3,arg4,arg5,arg6)) +#define ACE_INFOFORMAT_7(message,arg1,arg2,arg3,arg4,arg5,arg6,arg7) ACE_INFOFORMAT(FORMAT_7(message,arg1,arg2,arg3,arg4,arg5,arg6,arg7)) +#define ACE_INFOFORMAT_8(message,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8) ACE_INFOFORMAT(FORMAT_8(message,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8)) #include "script_debug.hpp" From 4cf81b493a1a2ba2ffbd248d790bc09b3dc120d3 Mon Sep 17 00:00:00 2001 From: PabstMirror Date: Wed, 26 Aug 2015 11:00:59 -0500 Subject: [PATCH 79/91] Fix stringtable and more cleanup --- addons/microdagr/CfgVehicles.hpp | 8 ++++---- .../microdagr/functions/fnc_appSettingsLBClick.sqf | 2 +- addons/microdagr/functions/fnc_mapButtonDownEH.sqf | 2 +- addons/microdagr/functions/fnc_moduleMapFill.sqf | 8 +++----- addons/microdagr/functions/fnc_openDisplay.sqf | 3 +-- addons/microdagr/functions/fnc_updateDisplay.sqf | 12 +++++------- addons/microdagr/stringtable.xml | 6 +++--- 7 files changed, 18 insertions(+), 23 deletions(-) diff --git a/addons/microdagr/CfgVehicles.hpp b/addons/microdagr/CfgVehicles.hpp index 49f7a0e65c..ee16870fe0 100644 --- a/addons/microdagr/CfgVehicles.hpp +++ b/addons/microdagr/CfgVehicles.hpp @@ -37,7 +37,7 @@ class CfgVehicles { displayName = CSTRING(Module_DisplayName); function = QFUNC(moduleMapFill); scope = 2; - isGlobal = 1; + isGlobal = 0; icon = QUOTE(PATHTOF(UI\Icon_Module_microDAGR_ca.paa)); functionPriority = 0; class Arguments { @@ -46,9 +46,9 @@ class CfgVehicles { description = CSTRING(MapDataAvailable_Description); typeName = "NUMBER"; class values { - class None {name = CSTRING(None); value = MAP_DETAIL_SAT; default = 1;}; - class Side {name = CSTRING(Side); value = MAP_DETAIL_TOPOROADS;}; - class Unique {name = CSTRING(Unique); value = MAP_DETAIL_NONE;}; + class Full {name = CSTRING(MapFill_Full); value = MAP_DETAIL_SAT; default = 1;}; + class Roads {name = CSTRING(MapFill_OnlyRoads); value = MAP_DETAIL_TOPOROADS;}; + class Disabled {name = CSTRING(MapFill_None); value = MAP_DETAIL_NONE;}; }; }; }; diff --git a/addons/microdagr/functions/fnc_appSettingsLBClick.sqf b/addons/microdagr/functions/fnc_appSettingsLBClick.sqf index 04f045171b..9e808559b2 100644 --- a/addons/microdagr/functions/fnc_appSettingsLBClick.sqf +++ b/addons/microdagr/functions/fnc_appSettingsLBClick.sqf @@ -17,7 +17,7 @@ #include "script_component.hpp" disableSerialization; -params ["_control", "_itemClicked"]; +params ["", "_itemClicked"]; switch (_itemClicked) do { case (0): { GVAR(settingUseMils) = ! GVAR(settingUseMils)}; diff --git a/addons/microdagr/functions/fnc_mapButtonDownEH.sqf b/addons/microdagr/functions/fnc_mapButtonDownEH.sqf index 8c564a7cfc..566f08dc66 100644 --- a/addons/microdagr/functions/fnc_mapButtonDownEH.sqf +++ b/addons/microdagr/functions/fnc_mapButtonDownEH.sqf @@ -19,7 +19,7 @@ */ #include "script_component.hpp" -params ["_theMap", "_mouseButton", "_xPos", "_yPos"]; +params ["", "_mouseButton"]; //Only handle RMB if (_mouseButton != 1) exitWith {}; diff --git a/addons/microdagr/functions/fnc_moduleMapFill.sqf b/addons/microdagr/functions/fnc_moduleMapFill.sqf index d88bc56e87..03089a4ff4 100644 --- a/addons/microdagr/functions/fnc_moduleMapFill.sqf +++ b/addons/microdagr/functions/fnc_moduleMapFill.sqf @@ -4,20 +4,18 @@ * * Arguments: * 0: logic - * 1: synced units-not used - * 2: Module Activated * * Return Value: * None * * Example: - * [module, [], true] call ace_microdagr_fnc_moduleMapFill + * [module] call ace_microdagr_fnc_moduleMapFill * * Public: No */ #include "script_component.hpp" if !(isServer) exitWith {}; -params ["_logic", "_syncedUnits", "_activated"]; +params ["_logic"]; -if (!_activated) exitWith {WARNING("Module Placed but not active");}; +[_logic, QGVAR(MapDataAvailable), "MapDataAvailable"] call EFUNC(common,readSettingFromModule); diff --git a/addons/microdagr/functions/fnc_openDisplay.sqf b/addons/microdagr/functions/fnc_openDisplay.sqf index c619890bf3..aa2db94827 100644 --- a/addons/microdagr/functions/fnc_openDisplay.sqf +++ b/addons/microdagr/functions/fnc_openDisplay.sqf @@ -15,7 +15,7 @@ */ #include "script_component.hpp" -private ["_oldShowMode", "_args", "_pfID", "_player"]; +private ["_oldShowMode", "_args", "_player"]; params [["_newDisplayShowMode", -1, [-1]]]; _oldShowMode = GVAR(currentShowMode); @@ -30,7 +30,6 @@ if ((_newDisplayShowMode == DISPLAY_MODE_DISPLAY) && {!([DISPLAY_MODE_DISPLAY] c if ((_newDisplayShowMode == DISPLAY_MODE_DIALOG) && {!([DISPLAY_MODE_DIALOG] call FUNC(canShow))}) then {_newDisplayShowMode = DISPLAY_MODE_HIDDEN}; - //On first-startup if (GVAR(currentApplicationPage) == APP_MODE_NULL) then { GVAR(currentApplicationPage) = APP_MODE_INFODISPLAY; diff --git a/addons/microdagr/functions/fnc_updateDisplay.sqf b/addons/microdagr/functions/fnc_updateDisplay.sqf index 8ab35bd2e5..826ea55e6c 100644 --- a/addons/microdagr/functions/fnc_updateDisplay.sqf +++ b/addons/microdagr/functions/fnc_updateDisplay.sqf @@ -15,7 +15,7 @@ */ #include "script_component.hpp" -private ["_display", "_waypoints", "_posString", "_eastingText", "_northingText", "_numASL", "_aboveSeaLevelText", "_compassAngleText", "_targetPos", "_targetPosName", "_targetPosLocationASL", "_bearingText", "_rangeText", "_targetName", "_bearing", "_2dDistanceKm", "_SpeedText", "_playerPos2d", "_wpListBox", "_currentIndex", "_wpName", "_wpPos", "_settingListBox", "_yearString", "_monthSring", "_dayString"]; +private ["_display", "_waypoints", "_posString", "_eastingText", "_northingText", "_numASL", "_aboveSeaLevelText", "_compassAngleText", "_targetPos", "_targetPosName", "_targetPosLocationASL", "_bearingText", "_rangeText", "_targetName", "_bearing", "_2dDistanceKm", "_SpeedText", "_wpListBox", "_currentIndex", "_wpName", "_wpPos", "_settingListBox", "_yearString", "_monthSring", "_dayString", "_daylight"]; disableSerialization; _display = uiNamespace getVariable [[QGVAR(RscTitleDisplay), QGVAR(DialogDisplay)] select (GVAR(currentShowMode) == DISPLAY_MODE_DIALOG), displayNull]; @@ -91,7 +91,7 @@ case (APP_MODE_INFODISPLAY): { } else { ([(floor (_bearing)), 3, 1] call CBA_fnc_formatNumber) + "°" //degree symbol is in UTF-8 }; - _2dDistanceKm = (((getPosASL ACE_player) select [0,2]) distance (_targetPosLocationASL select [0,2])) / 1000; + _2dDistanceKm = ((getPosASL ACE_player) distance2D _targetPosLocationASL) / 1000; _rangeText = format ["%1km", ([_2dDistanceKm, 1, 1] call CBA_fnc_formatNumber)]; _numASL = (_targetPosLocationASL select 2) + EGVAR(common,mapAltitude); _aboveSeaLevelText = [_numASL, 5, 0] call CBA_fnc_formatNumber; @@ -122,8 +122,6 @@ case (APP_MODE_COMPASS): { (_display displayCtrl IDC_MODECOMPASS_RANGE) ctrlSetText ""; (_display displayCtrl IDC_MODECOMPASS_TARGET) ctrlSetText ""; } else { - _playerPos2d = (getPosASL ACE_player) select [0,2]; - _targetPosName = ""; _targetPosLocationASL = []; @@ -149,7 +147,7 @@ case (APP_MODE_COMPASS): { } else { ([(floor (_bearing)), 3, 1] call CBA_fnc_formatNumber) + "°" //degree symbol is in UTF-8 }; - _2dDistanceKm = (((getPosASL ACE_player) select [0,2]) distance (_targetPosLocationASL select [0,2])) / 1000; + _2dDistanceKm = ((getPosASL ACE_player) distance2D _targetPosLocationASL) / 1000; _rangeText = format ["%1km", ([_2dDistanceKm, 1, 1] call CBA_fnc_formatNumber)]; }; @@ -165,9 +163,9 @@ case (APP_MODE_WAYPOINTS): { lbClear _wpListBox; { - EXPLODE_2_PVT(_x,_wpName,_wpPos); + _x params ["_wpName", "_wpPos"]; _wpListBox lbAdd _wpName; - _2dDistanceKm = (((getPosASL ACE_player) select [0,2]) distance (_wpPos select [0,2])) / 1000; + _2dDistanceKm = ((getPosASL ACE_player) distance2D _wpPos) / 1000; _wpListBox lbSetTextRight [_forEachIndex, (format ["%1km", ([_2dDistanceKm, 1, 1] call CBA_fnc_formatNumber)])]; } forEach _waypoints; diff --git a/addons/microdagr/stringtable.xml b/addons/microdagr/stringtable.xml index f28e3397c3..d3a955580a 100644 --- a/addons/microdagr/stringtable.xml +++ b/addons/microdagr/stringtable.xml @@ -325,7 +325,7 @@ Kolik informací je načteno do MicroDAGR? Quanta informação é preenchida no mapa do MicroDAGR - + Full Satellite + Buildings Pełna satelitarna + budynki Satelite completo + Edificios @@ -333,7 +333,7 @@ Satelit + Budovy Satélite completo + Edifícios - + Topographical + Roads Topograficzna + drogi Topografico + Carreteras @@ -341,7 +341,7 @@ Topografické + Cesty Topográfico + Estradas - + None (Cannot use map view) Żadna (wyłącza ekran mapy) Nada (No se puede el mapa) From e4123c97304bcba7e88a0d3afc72f623d4b7ba48 Mon Sep 17 00:00:00 2001 From: jonpas Date: Wed, 26 Aug 2015 22:44:30 +0200 Subject: [PATCH 80/91] Added 2 strings, changed 1 --- .../repair/functions/fnc_getHitPointString.sqf | 2 +- addons/repair/stringtable.xml | 16 +++++++++++----- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/addons/repair/functions/fnc_getHitPointString.sqf b/addons/repair/functions/fnc_getHitPointString.sqf index c6e587db50..1358e99595 100644 --- a/addons/repair/functions/fnc_getHitPointString.sqf +++ b/addons/repair/functions/fnc_getHitPointString.sqf @@ -1,6 +1,6 @@ /* * Author: Jonpas - * Finds the localized string of the given hitpoint name. + * Finds the localized string of the given hitpoint name or uses default text if none found. * * Arguments: * 0: Hitpoint diff --git a/addons/repair/stringtable.xml b/addons/repair/stringtable.xml index 1f0dc8b394..09759344f8 100644 --- a/addons/repair/stringtable.xml +++ b/addons/repair/stringtable.xml @@ -269,15 +269,18 @@ Static Port + + Ammo + - Main Turret + Turret Turm - Torreta príncipal + Torreta Tourelle Wieżyczka - Hlavní Věž - Torre principal - Torretta principale + Věž + Torre + Torretta Lövegtorony Башню @@ -293,6 +296,9 @@ Ágyú Пушку + + Missiles + Left Track Linke Kette From cc70580a93a19f4ebc6642b70ef4a37adcc3ee7d Mon Sep 17 00:00:00 2001 From: jonpas Date: Wed, 26 Aug 2015 22:51:41 +0200 Subject: [PATCH 81/91] Improved comments --- addons/repair/functions/fnc_addRepairActions.sqf | 6 ++---- addons/repair/functions/fnc_canMiscRepair.sqf | 2 +- addons/repair/functions/fnc_doRepair.sqf | 6 ++---- 3 files changed, 5 insertions(+), 9 deletions(-) diff --git a/addons/repair/functions/fnc_addRepairActions.sqf b/addons/repair/functions/fnc_addRepairActions.sqf index c47a9276f9..15cc0de881 100644 --- a/addons/repair/functions/fnc_addRepairActions.sqf +++ b/addons/repair/functions/fnc_addRepairActions.sqf @@ -81,12 +81,10 @@ _wheelHitPointSelections = _wheelHitPointsWithSelections select 1; _hitpointGroupConfig = configFile >> "CfgVehicles" >> _type >> QGVAR(hitpointGroups); _inHitpointSubGroup = false; if (isArray _hitpointGroupConfig) then { - // Loop through hitpoint groups + // Set variable if current hitpoint is in a sub-group (to be excluded from adding action) _currentHitpoint = _x; { - // Loop through sub-group { - // Current hitpoint is in a sub-group, set it so if (_x == _currentHitpoint) exitWith { _inHitpointSubGroup = true; }; @@ -94,7 +92,7 @@ _wheelHitPointSelections = _wheelHitPointsWithSelections select 1; } forEach (getArray _hitpointGroupConfig); }; - // Exit if current hitpoint is not a group leader (only they get actions) + // Exit if current hitpoint is in sub-group (only main hitpoints get actions) if (_inHitpointSubGroup) exitWith {}; // exit if the hitpoint is virtual diff --git a/addons/repair/functions/fnc_canMiscRepair.sqf b/addons/repair/functions/fnc_canMiscRepair.sqf index 105235fa1e..c60e59c840 100644 --- a/addons/repair/functions/fnc_canMiscRepair.sqf +++ b/addons/repair/functions/fnc_canMiscRepair.sqf @@ -24,7 +24,7 @@ params ["_caller", "_target", "_hitPoint"]; _hitpointGroupConfig = configFile >> "CfgVehicles" >> typeOf _target >> QGVAR(hitpointGroups); _hitpointGroup = []; if (isArray _hitpointGroupConfig) then { - // Loop through hitpoint groups + // Retrieve hitpoint subgroup if current hitpoint is main hitpoint of a group { // Exit using found hitpoint group if this hitpoint is leader of any if (_x select 0 == _hitPoint) exitWith { diff --git a/addons/repair/functions/fnc_doRepair.sqf b/addons/repair/functions/fnc_doRepair.sqf index 14b828a67b..3b2b991de2 100644 --- a/addons/repair/functions/fnc_doRepair.sqf +++ b/addons/repair/functions/fnc_doRepair.sqf @@ -35,14 +35,12 @@ _hitPointDamage = _hitPointDamage max ([_unit] call FUNC(getPostRepairDamage)); _hitpointGroupConfig = configFile >> "CfgVehicles" >> typeOf _vehicle >> QGVAR(hitpointGroups); _hitpointGroup = []; if (isArray _hitpointGroupConfig) then { - // Loop through hitpoint groups + // Retrieve group if current hitpoint is leader of any { - // Exit using found hitpoint group if this hitpoint is leader of any if (_x select 0 == _hitPoint) exitWith { ([_vehicle] call EFUNC(common,getHitPointsWithSelections)) params ["_hitpoints"]; - // Loop through the found group + // Set all sub-group hitpoints' damage to 0, if a hitpoint is invalid print RPT error { - // If hitpoint is valid set damage to 0, else print RPT error if (_x in _hitpoints) then { ["setVehicleHitPointDamage", _vehicle, [_vehicle, _x, 0]] call EFUNC(common,targetEvent); } else { From b6d5db9157ada1834f47e8d240ab5a76bfd20401 Mon Sep 17 00:00:00 2001 From: jonpas Date: Wed, 26 Aug 2015 23:09:04 +0200 Subject: [PATCH 82/91] Reverted IGNORED_HITPOINTS, Added Taru glasses to it --- addons/repair/functions/fnc_addRepairActions.sqf | 4 +++- addons/repair/script_component.hpp | 4 ++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/addons/repair/functions/fnc_addRepairActions.sqf b/addons/repair/functions/fnc_addRepairActions.sqf index 15cc0de881..94ad9b204d 100644 --- a/addons/repair/functions/fnc_addRepairActions.sqf +++ b/addons/repair/functions/fnc_addRepairActions.sqf @@ -14,7 +14,6 @@ * Public: No */ #include "script_component.hpp" -#define TRACK_HITPOINTS ["HitLTrack", "HitRTrack"] params ["_vehicle"]; TRACE_1("params", _vehicle); @@ -75,6 +74,9 @@ _wheelHitPointSelections = _wheelHitPointsWithSelections select 1; [_type, 0, [], _action] call EFUNC(interact_menu,addActionToClass); } else { + // exit if the hitpoint is in the blacklist, e.g. glasses + if (_x in IGNORED_HITPOINTS) exitWith {}; + private ["_hitpointGroupConfig", "_inHitpointSubGroup", "_currentHitpoint"]; // Get hitpoint groups if available diff --git a/addons/repair/script_component.hpp b/addons/repair/script_component.hpp index 0714b1a568..89983dd0e8 100644 --- a/addons/repair/script_component.hpp +++ b/addons/repair/script_component.hpp @@ -10,3 +10,7 @@ #endif #include "\z\ace\addons\main\script_macros.hpp" + + +#define IGNORED_HITPOINTS ["HitGlass1", "HitGlass2", "HitGlass3", "HitGlass4", "HitGlass5", "HitGlass6", "HitGlass7", "HitGlass8", "HitGlass9", "HitGlass10", "HitGlass11", "HitGlass12", "HitGlass13", "HitGlass14", "HitGlass15", "HitRGlass", "HitLGlass", "Glass_1_hitpoint", "Glass_2_hitpoint", "Glass_3_hitpoint", "Glass_4_hitpoint", "Glass_5_hitpoint", "Glass_6_hitpoint", "Glass_7_hitpoint", "Glass_8_hitpoint", "Glass_9_hitpoint", "Glass_10_hitpoint", "Glass_11_hitpoint", "Glass_12_hitpoint", "Glass_13_hitpoint", "Glass_14_hitpoint", "Glass_15_hitpoint", "Glass_16_hitpoint", "Glass_17_hitpoint", "Glass_18_hitpoint", "Glass_19_hitpoint", "Glass_20_hitpoint"] +#define TRACK_HITPOINTS ["HitLTrack", "HitRTrack"] From ce8da8d7203259dc99fac4820391a2c517adf588 Mon Sep 17 00:00:00 2001 From: jonpas Date: Wed, 26 Aug 2015 23:09:46 +0200 Subject: [PATCH 83/91] Fixed Full Repair available even when vehicle is already fully repaired --- addons/repair/ACE_Repair.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/repair/ACE_Repair.hpp b/addons/repair/ACE_Repair.hpp index c12566d5b1..4cfbb93e1f 100644 --- a/addons/repair/ACE_Repair.hpp +++ b/addons/repair/ACE_Repair.hpp @@ -63,7 +63,7 @@ class ACE_Repair { requiredEngineer = QGVAR(engineerSetting_fullRepair); repairLocations[] = {QGVAR(fullRepairLocation)}; repairingTime = 30; - condition = "damage (_this select 1) > 0"; + condition = "damage _target > 0"; callbackSuccess = QUOTE(call FUNC(doFullRepair)); }; }; From 9c8e9732edd59b72cd90235ca79ceb2f6070378a Mon Sep 17 00:00:00 2001 From: PabstMirror Date: Wed, 26 Aug 2015 16:26:08 -0500 Subject: [PATCH 84/91] Add canInteractWith checks for cargo --- addons/cargo/functions/fnc_canLoad.sqf | 2 ++ addons/cargo/functions/fnc_initVehicle.sqf | 5 ++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/addons/cargo/functions/fnc_canLoad.sqf b/addons/cargo/functions/fnc_canLoad.sqf index da41d93358..f5d1304a95 100644 --- a/addons/cargo/functions/fnc_canLoad.sqf +++ b/addons/cargo/functions/fnc_canLoad.sqf @@ -18,6 +18,8 @@ params ["_player", "_object"]; +if (!([_player, _object, []] call EFUNC(common,canInteractWith))) exitWith {false}; + private ["_nearestVehicle"]; _nearestVehicle = [_player] call FUNC(findNearestVehicle); diff --git a/addons/cargo/functions/fnc_initVehicle.sqf b/addons/cargo/functions/fnc_initVehicle.sqf index 06f8fbcbbc..b817688336 100644 --- a/addons/cargo/functions/fnc_initVehicle.sqf +++ b/addons/cargo/functions/fnc_initVehicle.sqf @@ -39,7 +39,10 @@ SETMVAR(GVAR(initializedClasses),_initializedClasses); if (getNumber (configFile >> "CfgVehicles" >> _type >> QGVAR(hasCargo)) != 1) exitWith {}; private ["_text", "_condition", "_statement", "_icon", "_action"]; -_condition = {GVAR(enable)}; +_condition = { + params ["_target", "_player"]; + GVAR(enable) && {[_player, _target, []] call EFUNC(common,canInteractWith)} +}; _text = localize LSTRING(openMenu); _statement = {GVAR(interactionVehicle) = _target; createDialog QGVAR(menu);}; _icon = ""; From 1187b7341905d36863dbeb09b4f23c58eff96f9b Mon Sep 17 00:00:00 2001 From: jonpas Date: Thu, 27 Aug 2015 03:23:56 +0200 Subject: [PATCH 85/91] make.py version bump to 0.7 --- tools/make.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/make.py b/tools/make.py index 14031a749c..f8a4c80886 100644 --- a/tools/make.py +++ b/tools/make.py @@ -30,7 +30,7 @@ ############################################################################### -__version__ = "0.6" +__version__ = "0.7" import sys From bc016eac4cbabc09109735619653bfcc6dd3a91e Mon Sep 17 00:00:00 2001 From: PabstMirror Date: Wed, 26 Aug 2015 22:39:27 -0500 Subject: [PATCH 86/91] 1.50 - use new didJip command (Ref #2241) --- addons/common/XEH_postInit.sqf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/common/XEH_postInit.sqf b/addons/common/XEH_postInit.sqf index 6535b79257..1f060c8900 100644 --- a/addons/common/XEH_postInit.sqf +++ b/addons/common/XEH_postInit.sqf @@ -327,7 +327,7 @@ GVAR(OldIsCamera) = false; // Lastly, do JIP events // JIP Detection and event trigger. Run this at the very end, just in case anything uses it -if(isMultiplayer && { ACE_time > 0 || isNull player } ) then { +if (didJip) then { // We are jipping! Get ready and wait, and throw the event [{ if(!(isNull player)) then { From 93106697ab77a1a7e71331f1c9297e076a79e1ab Mon Sep 17 00:00:00 2001 From: Michael Braun Date: Thu, 27 Aug 2015 06:21:02 +0200 Subject: [PATCH 87/91] Added debug log macros --- addons/main/script_macros.hpp | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/addons/main/script_macros.hpp b/addons/main/script_macros.hpp index 2113161ad7..41514e4aaf 100644 --- a/addons/main/script_macros.hpp +++ b/addons/main/script_macros.hpp @@ -160,4 +160,24 @@ #define ACE_INFOFORMAT_7(message,arg1,arg2,arg3,arg4,arg5,arg6,arg7) ACE_INFOFORMAT(FORMAT_7(message,arg1,arg2,arg3,arg4,arg5,arg6,arg7)) #define ACE_INFOFORMAT_8(message,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8) ACE_INFOFORMAT(FORMAT_8(message,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8)) +#define ACE_LOGDEBUG(message) ACE_LOG(COMPONENT,"DEBUG",message) +#define ACE_LOGDEBUG_1(message,arg1) ACE_LOGDEBUG(FORMAT_1(message,arg1)) +#define ACE_LOGDEBUG_2(message,arg1,arg2) ACE_LOGDEBUG(FORMAT_2(message,arg1,arg2)) +#define ACE_LOGDEBUG_3(message,arg1,arg2,arg3) ACE_LOGDEBUG(FORMAT_3(message,arg1,arg2,arg3)) +#define ACE_LOGDEBUG_4(message,arg1,arg2,arg3,arg4) ACE_LOGDEBUG(FORMAT_4(message,arg1,arg2,arg3,arg4)) +#define ACE_LOGDEBUG_5(message,arg1,arg2,arg3,arg4,arg5) ACE_LOGDEBUG(FORMAT_5(message,arg1,arg2,arg3,arg4,arg5)) +#define ACE_LOGDEBUG_6(message,arg1,arg2,arg3,arg4,arg5,arg6) ACE_LOGDEBUG(FORMAT_6(message,arg1,arg2,arg3,arg4,arg5,arg6)) +#define ACE_LOGDEBUG_7(message,arg1,arg2,arg3,arg4,arg5,arg6,arg7) ACE_LOGDEBUG(FORMAT_7(message,arg1,arg2,arg3,arg4,arg5,arg6,arg7)) +#define ACE_LOGDEBUG_8(message,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8) ACE_LOGDEBUG(FORMAT_8(message,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8)) + +#define ACE_DEBUGFORMAT(message) ACE_LOGFORMAT(COMPONENT,"DEBUG",message) +#define ACE_DEBUGFORMAT_1(message,arg1) ACE_DEBUGFORMAT(FORMAT_1(message,arg1)) +#define ACE_DEBUGFORMAT_2(message,arg1,arg2) ACE_DEBUGFORMAT(FORMAT_2(message,arg1,arg2)) +#define ACE_DEBUGFORMAT_3(message,arg1,arg2,arg3) ACE_DEBUGFORMAT(FORMAT_3(message,arg1,arg2,arg3)) +#define ACE_DEBUGFORMAT_4(message,arg1,arg2,arg3,arg4) ACE_DEBUGFORMAT(FORMAT_4(message,arg1,arg2,arg3,arg4)) +#define ACE_DEBUGFORMAT_5(message,arg1,arg2,arg3,arg4,arg5) ACE_DEBUGFORMAT(FORMAT_5(message,arg1,arg2,arg3,arg4,arg5)) +#define ACE_DEBUGFORMAT_6(message,arg1,arg2,arg3,arg4,arg5,arg6) ACE_DEBUGFORMAT(FORMAT_6(message,arg1,arg2,arg3,arg4,arg5,arg6)) +#define ACE_DEBUGFORMAT_7(message,arg1,arg2,arg3,arg4,arg5,arg6,arg7) ACE_DEBUGFORMAT(FORMAT_7(message,arg1,arg2,arg3,arg4,arg5,arg6,arg7)) +#define ACE_DEBUGFORMAT_8(message,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8) ACE_DEBUGFORMAT(FORMAT_8(message,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8)) + #include "script_debug.hpp" From 6fe79c4fe2587ac7093b3839f15bfb5eca6f538b Mon Sep 17 00:00:00 2001 From: commy2 Date: Thu, 27 Aug 2015 22:10:09 +0200 Subject: [PATCH 88/91] remove obsolete compat pbo for BWMod, fix #2293 --- optionals/compat_bwa3/$PBOPREFIX$ | 1 - optionals/compat_bwa3/CfgAmmo.hpp | 142 ----------------- optionals/compat_bwa3/CfgMagazines.hpp | 9 -- optionals/compat_bwa3/CfgWeapons.hpp | 173 --------------------- optionals/compat_bwa3/config.cpp | 16 -- optionals/compat_bwa3/script_component.hpp | 5 - 6 files changed, 346 deletions(-) delete mode 100644 optionals/compat_bwa3/$PBOPREFIX$ delete mode 100644 optionals/compat_bwa3/CfgAmmo.hpp delete mode 100644 optionals/compat_bwa3/CfgMagazines.hpp delete mode 100644 optionals/compat_bwa3/CfgWeapons.hpp delete mode 100644 optionals/compat_bwa3/config.cpp delete mode 100644 optionals/compat_bwa3/script_component.hpp diff --git a/optionals/compat_bwa3/$PBOPREFIX$ b/optionals/compat_bwa3/$PBOPREFIX$ deleted file mode 100644 index 7331009959..0000000000 --- a/optionals/compat_bwa3/$PBOPREFIX$ +++ /dev/null @@ -1 +0,0 @@ -z\ace\addons\compat_bwa3 \ No newline at end of file diff --git a/optionals/compat_bwa3/CfgAmmo.hpp b/optionals/compat_bwa3/CfgAmmo.hpp deleted file mode 100644 index c19e00819a..0000000000 --- a/optionals/compat_bwa3/CfgAmmo.hpp +++ /dev/null @@ -1,142 +0,0 @@ -class CfgAmmo { - class B_9x21_Ball; - class B_556x45_Ball_Tracer_Red; - class B_762x51_Tracer_Red; - class B_127x99_Ball_Tracer_Red; - class GrenadeHand; - class BWA3_B_556x45_Ball: B_556x45_Ball_Tracer_Red { - ACE_caliber=5.69; - ACE_bulletLength=23.012; - ACE_bulletMass=4.0176; - ACE_ammoTempMuzzleVelocityShifts[]={-27.20, -26.44, -23.76, -21.00, -17.54, -13.10, -7.95, -1.62, 6.24, 15.48, 27.75}; - ACE_ballisticCoefficients[]={0.151}; - ACE_velocityBoundaries[]={}; - ACE_standardAtmosphere="ASM"; - ACE_dragModel=7; - ACE_muzzleVelocities[]={723, 764, 796, 825, 843, 866, 878, 892, 906, 915, 922, 900}; - ACE_barrelLengths[]={210.82, 238.76, 269.24, 299.72, 330.2, 360.68, 391.16, 419.1, 449.58, 480.06, 508.0, 609.6}; - }; - class BWA3_B_556x45_Ball_SD: BWA3_B_556x45_Ball { - // Reference? - ACE_ballisticCoefficients[]={}; - ACE_velocityBoundaries[]={}; - ACE_muzzleVelocities[]={}; - ACE_barrelLengths[]={}; - }; - class BWA3_B_556x45_Ball_AP: BWA3_B_556x45_Ball { - ACE_caliber=5.69; - ACE_bulletLength=23.012; - ACE_bulletMass=4.5359237; - ACE_ammoTempMuzzleVelocityShifts[]={-26.55, -25.47, -22.85, -20.12, -16.98, -12.80, -7.64, -1.53, 5.96, 15.17, 26.19}; - ACE_ballisticCoefficients[]={0.310}; - ACE_velocityBoundaries[]={}; - ACE_standardAtmosphere="ASM"; - ACE_dragModel=1; - ACE_muzzleVelocities[]={820, 865, 880}; - ACE_barrelLengths[]={254.0, 393.7, 508.0}; - }; - class BWA3_B_762x51_Ball: B_762x51_Tracer_Red { - ACE_caliber=7.823; - ACE_bulletLength=28.956; - ACE_bulletMass=9.4608; - ACE_ammoTempMuzzleVelocityShifts[]={-26.55, -25.47, -22.85, -20.12, -16.98, -12.80, -7.64, -1.53, 5.96, 15.17, 26.19}; - ACE_ballisticCoefficients[]={0.2}; - ACE_velocityBoundaries[]={}; - ACE_standardAtmosphere="ICAO"; - ACE_dragModel=7; - ACE_muzzleVelocities[]={700, 800, 820, 833, 845}; - ACE_barrelLengths[]={254.0, 406.4, 508.0, 609.6, 660.4}; - }; - class BWA3_B_762x51_Ball_SD: BWA3_B_762x51_Ball { - ACE_caliber=7.823; - ACE_bulletLength=34.036; - ACE_bulletMass=12.96; - ACE_ammoTempMuzzleVelocityShifts[]={-2.655, -2.547, -2.285, -2.012, -1.698, -1.280, -0.764, -0.153, 0.596, 1.517, 2.619}; - ACE_ballisticCoefficients[]={0.235}; - ACE_velocityBoundaries[]={}; - ACE_standardAtmosphere="ICAO"; - ACE_dragModel=7; - ACE_muzzleVelocities[]={305, 325, 335, 340}; - ACE_barrelLengths[]={406.4, 508.0, 609.6, 660.4}; - }; - class BWA3_B_762x51_Ball_AP: BWA3_B_762x51_Ball { - ACE_caliber=7.823; - ACE_bulletLength=31.496; - ACE_bulletMass=8.22946157; - ACE_ammoTempMuzzleVelocityShifts[]={-26.55, -25.47, -22.85, -20.12, -16.98, -12.80, -7.64, -1.53, 5.96, 15.17, 26.19}; - ACE_ballisticCoefficients[]={0.359}; - ACE_velocityBoundaries[]={}; - ACE_standardAtmosphere="ICAO"; - ACE_dragModel=1; - ACE_muzzleVelocities[]={875, 910, 930}; - ACE_barrelLengths[]={330.2, 406.4, 508.0}; - }; - class BWA3_B_762x51_Ball_LR: BWA3_B_762x51_Ball { - ACE_caliber=7.823; - ACE_bulletLength=31.496; - ACE_bulletMass=11.34; - ACE_ammoTempMuzzleVelocityShifts[]={-26.55, -25.47, -22.85, -20.12, -16.98, -12.80, -7.64, -1.53, 5.96, 15.17, 26.19}; - ACE_ballisticCoefficients[]={0.243}; - ACE_velocityBoundaries[]={}; - ACE_standardAtmosphere="ICAO"; - ACE_dragModel=7; - ACE_muzzleVelocities[]={750, 780, 790, 794}; - ACE_barrelLengths[]={406.4, 508.0, 609.6, 660.4}; - }; - class BWA3_B_127x99_Ball: B_127x99_Ball_Tracer_Red { - ACE_caliber=12.954; - ACE_bulletLength=58.674; - ACE_bulletMass=41.9256; - ACE_ammoTempMuzzleVelocityShifts[]={-26.55, -25.47, -22.85, -20.12, -16.98, -12.80, -7.64, -1.53, 5.96, 15.17, 26.19}; - ACE_ballisticCoefficients[]={0.670}; - ACE_velocityBoundaries[]={}; - ACE_standardAtmosphere="ASM"; - ACE_dragModel=1; - ACE_muzzleVelocities[]={900}; - ACE_barrelLengths[]={736.6}; - }; - class BWA3_B_127x99_Ball_SD: BWA3_B_127x99_Ball { - // Reference? - ACE_ballisticCoefficients[]={}; - ACE_velocityBoundaries[]={}; - ACE_muzzleVelocities[]={}; - ACE_barrelLengths[]={}; - }; - class BWA3_B_127x99_Ball_AP: BWA3_B_127x99_Ball { - ACE_caliber=12.954; - ACE_bulletLength=58.674; - ACE_bulletMass=41.9904; - ACE_ammoTempMuzzleVelocityShifts[]={-26.55, -25.47, -22.85, -20.12, -16.98, -12.80, -7.64, -1.53, 5.96, 15.17, 26.19}; - ACE_ballisticCoefficients[]={0.670}; - ACE_velocityBoundaries[]={}; - ACE_standardAtmosphere="ASM"; - ACE_dragModel=1; - ACE_muzzleVelocities[]={900}; - ACE_barrelLengths[]={736.6}; - }; - class BWA3_B_46x30_Ball: B_9x21_Ball { - ACE_caliber=4.902; - ACE_bulletLength=13.005; - ACE_bulletMass=2.0088; - ACE_ammoTempMuzzleVelocityShifts[]={-26.55, -25.47, -22.85, -20.12, -16.98, -12.80, -7.64, -1.53, 5.96, 15.17, 26.19}; - ACE_ballisticCoefficients[]={0.1455}; - ACE_velocityBoundaries[]={}; - ACE_standardAtmosphere="ICAO"; - ACE_dragModel=1; - ACE_muzzleVelocities[]={680, 720, 730, 740}; - ACE_barrelLengths[]={101.6, 177.8, 228.6, 304.8}; - }; - class BWA3_B_46x30_Ball_SD: BWA3_B_46x30_Ball { - // Reference? - ACE_ballisticCoefficients[]={}; - ACE_velocityBoundaries[]={}; - ACE_muzzleVelocities[]={}; - ACE_barrelLengths[]={}; - }; - class BWA3_G_DM51A1: GrenadeHand { - ace_frag_metal = 296; - ace_frag_charge = 180; - ace_frag_gurney_c = 2930; // Gurney velocity constant for PETN - ace_frag_gurney_k = 1/2; // shape factor for a cylinder - }; -}; \ No newline at end of file diff --git a/optionals/compat_bwa3/CfgMagazines.hpp b/optionals/compat_bwa3/CfgMagazines.hpp deleted file mode 100644 index bf43af6426..0000000000 --- a/optionals/compat_bwa3/CfgMagazines.hpp +++ /dev/null @@ -1,9 +0,0 @@ -class CfgMagazines { - class CA_Magazine; - class BWA3_200Rnd_556x45: CA_Magazine { - ACE_isBelt = 1; - }; - class BWA3_120Rnd_762x51: CA_Magazine { - ACE_isBelt = 1; - }; -}; \ No newline at end of file diff --git a/optionals/compat_bwa3/CfgWeapons.hpp b/optionals/compat_bwa3/CfgWeapons.hpp deleted file mode 100644 index c0acea9912..0000000000 --- a/optionals/compat_bwa3/CfgWeapons.hpp +++ /dev/null @@ -1,173 +0,0 @@ -class CfgWeapons { - class Pistol_Base_F; - class Rifle_Base_F; - class Rifle_Long_Base_F; - class UGL_F; - class BWA3_P8: Pistol_Base_F { - ACE_barrelTwist=248.92; - ACE_barrelLength=108; - }; - class BWA3_MP7: Pistol_Base_F { - ACE_barrelTwist=160.02; - ACE_barrelLength=180; - }; - class BWA3_G36: Rifle_Base_F { - ACE_barrelTwist=177.8; - ACE_barrelLength=480; - }; - class BWA3_G36K: BWA3_G36 { - ACE_barrelTwist=177.8; - ACE_barrelLength=318; - }; - class BWA3_G28_Standard: Rifle_Long_Base_F { - ACE_barrelTwist=304.8; - ACE_barrelLength=421; - }; - class BWA3_G28_Assault: BWA3_G28_Standard { - ACE_barrelTwist=304.8; - ACE_barrelLength=421; - }; - class BWA3_G27: BWA3_G28_Standard { - ACE_barrelTwist=304.8; - ACE_barrelLength=406; - }; - class BWA3_G27_AG: BWA3_G27 { - class AG40: UGL_F { - magazines[] += { - "ACE_HuntIR_M203" - }; - }; - }; - class BWA3_MG4: Rifle_Long_Base_F { - ACE_barrelTwist=177.8; - ACE_barrelLength=480; - }; - class BWA3_MG5: Rifle_Long_Base_F { - ACE_barrelTwist=304.8; - ACE_barrelLength=550; - }; - class BWA3_G82: Rifle_Long_Base_F { - ACE_barrelTwist=381.0; - ACE_barrelLength=736.7; - }; - class AG40: UGL_F { - magazines[] += { - "ACE_HuntIR_M203" - }; - }; - class optic_Hamr; - class InventoryOpticsItem_Base_F; - - class BWA3_optic_ZO4x30 : optic_Hamr { - ACE_ScopeAdjust_Vertical[] = { -10, 10 }; - ACE_ScopeAdjust_Horizontal[] = { -10, 10 }; - ACE_ScopeAdjust_VerticalIncrement = 0.2; - ACE_ScopeAdjust_HorizontalIncrement = 0.2; - class ItemInfo : InventoryOpticsItem_Base_F { - class OpticsModes { - class Scope { - discreteDistance[] = { 200 }; - discreteDistanceInitIndex = 0; - }; - }; - }; - }; - class BWA3_optic_ZO4x30_NSV : optic_Hamr { - ACE_ScopeAdjust_Vertical[] = { -10, 10 }; - ACE_ScopeAdjust_Horizontal[] = { -10, 10 }; - ACE_ScopeAdjust_VerticalIncrement = 0.2; - ACE_ScopeAdjust_HorizontalIncrement = 0.2; - class ItemInfo : InventoryOpticsItem_Base_F { - class OpticsModes { - class Scope { - discreteDistance[] = { 200 }; - discreteDistanceInitIndex = 0; - }; - }; - }; - }; - class BWA3_optic_ZO4x30_IRV : optic_Hamr { - ACE_ScopeAdjust_Vertical[] = { -10, 10 }; - ACE_ScopeAdjust_Horizontal[] = { -10, 10 }; - ACE_ScopeAdjust_VerticalIncrement = 0.2; - ACE_ScopeAdjust_HorizontalIncrement = 0.2; - class ItemInfo : InventoryOpticsItem_Base_F { - class OpticsModes { - class Scope { - discreteDistance[] = { 200 }; - discreteDistanceInitIndex = 0; - }; - }; - }; - }; - class BWA3_optic_Shortdot : optic_Hamr { - ACE_ScopeAdjust_Vertical[] = { -0.1, 10.1 }; - ACE_ScopeAdjust_Horizontal[] = { -5.1, 5.1 }; - ACE_ScopeAdjust_VerticalIncrement = 0.1; - ACE_ScopeAdjust_HorizontalIncrement = 0.1; - class ItemInfo : InventoryOpticsItem_Base_F { - class OpticsModes { - class Scope { - discreteDistance[] = { 100 }; - discreteDistanceInitIndex = 0; - }; - }; - }; - }; - class BWA3_optic_20x50 : optic_Hamr { - ACE_ScopeAdjust_Vertical[] = { 0, 26 }; - ACE_ScopeAdjust_Horizontal[] = { -6, 6 }; - ACE_ScopeAdjust_VerticalIncrement = 0.1; - ACE_ScopeAdjust_HorizontalIncrement = 0.1; - class ItemInfo : InventoryOpticsItem_Base_F { - class OpticsModes { - class Scope { - discreteDistance[] = { 100 }; - discreteDistanceInitIndex = 0; - }; - }; - }; - }; - class BWA3_optic_20x50_NSV : BWA3_optic_20x50 { - ACE_ScopeAdjust_Vertical[] = { 0, 26 }; - ACE_ScopeAdjust_Horizontal[] = { -6, 6 }; - ACE_ScopeAdjust_VerticalIncrement = 0.1; - ACE_ScopeAdjust_HorizontalIncrement = 0.1; - class ItemInfo : InventoryOpticsItem_Base_F { - class OpticsModes { - class Scope { - discreteDistance[] = { 100 }; - discreteDistanceInitIndex = 0; - }; - }; - }; - }; - class BWA3_optic_24x72 : optic_Hamr { - ACE_ScopeAdjust_Vertical[] = { 0, 16 }; - ACE_ScopeAdjust_Horizontal[] = { -7, 7 }; - ACE_ScopeAdjust_VerticalIncrement = 0.1; - ACE_ScopeAdjust_HorizontalIncrement = 0.1; - class ItemInfo : InventoryOpticsItem_Base_F { - class OpticsModes { - class Scope { - discreteDistance[] = { 100 }; - discreteDistanceInitIndex = 0; - }; - }; - }; - }; - class BWA3_optic_24x72_NSV : BWA3_optic_20x50 { - ACE_ScopeAdjust_Vertical[] = { 0, 16 }; - ACE_ScopeAdjust_Horizontal[] = { -7, 7 }; - ACE_ScopeAdjust_VerticalIncrement = 0.1; - ACE_ScopeAdjust_HorizontalIncrement = 0.1; - class ItemInfo : InventoryOpticsItem_Base_F { - class OpticsModes { - class Scope { - discreteDistance[] = { 100 }; - discreteDistanceInitIndex = 0; - }; - }; - }; - }; -}; diff --git a/optionals/compat_bwa3/config.cpp b/optionals/compat_bwa3/config.cpp deleted file mode 100644 index efdebaf616..0000000000 --- a/optionals/compat_bwa3/config.cpp +++ /dev/null @@ -1,16 +0,0 @@ -#include "script_component.hpp" - -class CfgPatches { - class ADDON { - units[] = {}; - weapons[] = {}; - requiredVersion = REQUIRED_VERSION; - requiredAddons[] = {"BWA3_Weapons"}; - author[]={"Ruthberg"}; - VERSION_CONFIG; - }; -}; - -#include "CfgAmmo.hpp" -#include "CfgWeapons.hpp" -#include "CfgMagazines.hpp" diff --git a/optionals/compat_bwa3/script_component.hpp b/optionals/compat_bwa3/script_component.hpp deleted file mode 100644 index 86bb669119..0000000000 --- a/optionals/compat_bwa3/script_component.hpp +++ /dev/null @@ -1,5 +0,0 @@ -#define COMPONENT BWA3_Weapons_comp - -#include "\z\ace\addons\main\script_mod.hpp" - -#include "\z\ace\addons\main\script_macros.hpp" From 19a6226ced3e204e1474fea74f24e1fe418f35f2 Mon Sep 17 00:00:00 2001 From: bux578 Date: Fri, 28 Aug 2015 09:05:31 +0200 Subject: [PATCH 89/91] add Hearing Protection to Helmets with Peltors --- addons/hearing/CfgWeapons.hpp | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/addons/hearing/CfgWeapons.hpp b/addons/hearing/CfgWeapons.hpp index 2806ef9970..7c21baaed2 100644 --- a/addons/hearing/CfgWeapons.hpp +++ b/addons/hearing/CfgWeapons.hpp @@ -47,5 +47,16 @@ class CfgWeapons { GVAR(lowerVolume) = 0.60; }; class H_Cap_marshal: H_Cap_headphones {}; -}; + class H_HelmetB_light: H_HelmetB { + GVAR(protection) = 0.8; + GVAR(lowerVolume) = 0.20; + }; + + class H_HelmetB_plain_mcamo; + class H_HelmetSpecB: H_HelmetB_plain_mcamo { + GVAR(protection) = 0.8; + GVAR(lowerVolume) = 0.20; + }; + +}; From 326911486143316fa08938046745a619dca3570f Mon Sep 17 00:00:00 2001 From: jokoho48 Date: Fri, 28 Aug 2015 11:55:32 +0200 Subject: [PATCH 90/91] Fix Tactical Ladder Animation Clipping --- .../data/ace_tacticalladder.p3d | Bin 2100184 -> 2115464 bytes addons/tacticalladder/data/model.cfg | 10 +++++----- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/addons/tacticalladder/data/ace_tacticalladder.p3d b/addons/tacticalladder/data/ace_tacticalladder.p3d index a331f2408498f3c39bdb1aeea28d5433c70f212d..7bb924ff46e4ba8f2e454a9f674878e178f4238e 100644 GIT binary patch delta 211758 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

#e@{9Q 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

o6rqqE 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 TRus90t?imNoHC?h&;kDqf4eg4 diff --git a/addons/tacticalladder/data/model.cfg b/addons/tacticalladder/data/model.cfg index 1fc8840d4f..ba19d58c65 100644 --- a/addons/tacticalladder/data/model.cfg +++ b/addons/tacticalladder/data/model.cfg @@ -1,4 +1,4 @@ -class CfgSkeletons { +class CfgSkeletons { class Default { isDiscrete = 1; skeletonInherit = ""; @@ -21,7 +21,7 @@ class CfgSkeletons { "10","9", "11","10", "step","11" - }; + }; }; class OFP2_ManSkeleton { isDiscrete = 0; @@ -180,7 +180,7 @@ class CfgModels { class ace_tacticalladder { skeletonName = "ace_tacticalladder_skeleton"; sections[] = { "roadway" }; - sectionsInherit = ""; + sectionsInherit = ""; class Animations { class rotate { type = "rotation"; @@ -192,7 +192,7 @@ class CfgModels { maxValue = 90; angle0="rad 0"; angle1="rad +90"; - }; + }; class extract_1 { type = "translation"; source = ""; @@ -280,4 +280,4 @@ class CfgModels { }; class ace_tacticalladder_pack: ArmaMan { }; -}; \ No newline at end of file +}; From 200f44d96336c08eb8f4e1b055de5e052761a808 Mon Sep 17 00:00:00 2001 From: SilentSpike Date: Sat, 29 Aug 2015 16:03:43 +0100 Subject: [PATCH 91/91] Adjust spectator camera speed based on height Slows the camera movement close to the ground as it feels more natural when spectating units up close and such --- .../spectator/functions/fnc_handleCamera.sqf | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/addons/spectator/functions/fnc_handleCamera.sqf b/addons/spectator/functions/fnc_handleCamera.sqf index 960a20df80..db196c8504 100644 --- a/addons/spectator/functions/fnc_handleCamera.sqf +++ b/addons/spectator/functions/fnc_handleCamera.sqf @@ -20,14 +20,18 @@ // Kill PFH when not in free cam (or display is closed) if (isNil QGVAR(camHandler)) exitWith { [_this select 1] call CBA_fnc_removePerFrameHandler; }; -private ["_oldPos","_zoomMod","_mX","_mY","_mZ","_pan","_x","_y","_z"]; +private ["_camera","_oldPos","_altMod","_zoomMod","_mX","_mY","_mZ","_pan","_x","_y","_z"]; -_oldPos = getPosASL GVAR(camera); +_camera = GVAR(camera); +_oldPos = getPosASL _camera; // Dolly/Boom amount should be influnced by zoom level (it should really be exponential) +// Dollying should also slow as the camera gets close to the ground _zoomMod = (GVAR(camZoom) * 0.8) max 1; -_mX = (GVAR(camDolly) select 0) / _zoomMod; -_mY = (GVAR(camDolly) select 1) / _zoomMod; +_altMod = ((((getPos _camera) select 2) * 0.05) max 0.1) min 1; + +_mX = (GVAR(camDolly) select 0) * _altMod / _zoomMod; +_mY = (GVAR(camDolly) select 1) * _altMod / _zoomMod; _mZ = GVAR(camBoom) / _zoomMod; _pan = (GVAR(camPan) + 360) % 360; @@ -39,6 +43,6 @@ _z = (_oldPos select 2) + _mZ; GVAR(camPos) = [_x,_y,_z max (getTerrainHeightASL [_x,_y])]; // Update camera position and rotation -GVAR(camera) setPosASL GVAR(camPos); -GVAR(camera) setDir GVAR(camPan); -[GVAR(camera), GVAR(camTilt), 0] call BIS_fnc_setPitchBank; +_camera setPosASL GVAR(camPos); +_camera setDir GVAR(camPan); +[_camera, GVAR(camTilt), 0] call BIS_fnc_setPitchBank;