diff --git a/addons/minedetector/ACE_detector.hpp b/addons/minedetector/ACE_detector.hpp index ee00836edac..f770b952723 100644 --- a/addons/minedetector/ACE_detector.hpp +++ b/addons/minedetector/ACE_detector.hpp @@ -1,10 +1,15 @@ class ACE_detector { class detectors { class ACE_VMM3 { + detectorPosition[] = {1.3, -0.22, 0.4}; radius = 2.5; sounds[] = {"ace_detector_1", "ace_detector_2", "ace_detector_3", "ace_detector_4"}; + soundDistances[] = {0, 0.5, 1.25, 2}; + soundIntervals[] = {0.5, 0.7, 0.85, 1}; + soundIntervalDistances[] = {0, 0.75, 1.25, 2}; }; class ACE_VMH3: ACE_VMM3 { + detectorPosition[] = {1, -0.32, 0.3}; }; }; }; diff --git a/addons/minedetector/CfgAmmo.hpp b/addons/minedetector/CfgAmmo.hpp index bd2a3fdca64..77b571b58da 100644 --- a/addons/minedetector/CfgAmmo.hpp +++ b/addons/minedetector/CfgAmmo.hpp @@ -1,12 +1,11 @@ class CfgAmmo { - - // seems to not get inherited + // Seems to not get inherited class Default; class TimeBombCore: Default { GVAR(detectable) = 1; }; - // these below do get inherited + // These below do get inherited class DirectionalBombCore; class DirectionalBombBase: DirectionalBombCore { GVAR(detectable) = 1; diff --git a/addons/minedetector/CfgEventHandlers.hpp b/addons/minedetector/CfgEventHandlers.hpp index 2a3f71f852d..f6503c2479b 100644 --- a/addons/minedetector/CfgEventHandlers.hpp +++ b/addons/minedetector/CfgEventHandlers.hpp @@ -3,11 +3,13 @@ class Extended_PreStart_EventHandlers { init = QUOTE(call COMPILE_SCRIPT(XEH_preStart)); }; }; + class Extended_PreInit_EventHandlers { class ADDON { init = QUOTE(call COMPILE_SCRIPT(XEH_preInit)); }; }; + class Extended_PostInit_EventHandlers { class ADDON { init = QUOTE(call COMPILE_SCRIPT(XEH_postInit)); diff --git a/addons/minedetector/CfgSounds.hpp b/addons/minedetector/CfgSounds.hpp index 2f9ce91da16..98aa3735846 100644 --- a/addons/minedetector/CfgSounds.hpp +++ b/addons/minedetector/CfgSounds.hpp @@ -1,22 +1,22 @@ class CfgSounds { class ace_detector_1 { name = "ace_detector_1"; - sound[] = {QUOTE(PATHTOF(sounds\metal_detector.wss)), "db+3", 1}; + sound[] = {QPATHTOF(sounds\metal_detector.wss), "db+3", 1}; titles[] = {}; }; class ace_detector_2 { name = "ace_detector_2"; - sound[] = {QUOTE(PATHTOF(sounds\metal_detector.wss)), "db+3", 0.9}; + sound[] = {QPATHTOF(sounds\metal_detector.wss), "db+3", 0.9}; titles[] = {}; }; class ace_detector_3 { name = "ace_detector_3"; - sound[] = {QUOTE(PATHTOF(sounds\metal_detector.wss)), "db+3", 0.8}; + sound[] = {QPATHTOF(sounds\metal_detector.wss), "db+3", 0.8}; titles[] = {}; }; class ace_detector_4 { name = "ace_detector_4"; - sound[] = {QUOTE(PATHTOF(sounds\metal_detector.wss)), "db+3", 0.7}; + sound[] = {QPATHTOF(sounds\metal_detector.wss), "db+3", 0.7}; titles[] = {}; }; }; diff --git a/addons/minedetector/CfgVehicles.hpp b/addons/minedetector/CfgVehicles.hpp index 874fc597f53..59fd392de57 100644 --- a/addons/minedetector/CfgVehicles.hpp +++ b/addons/minedetector/CfgVehicles.hpp @@ -13,35 +13,35 @@ class CfgVehicles { class ACE_Equipment { class GVAR(metalDetector) { displayName = CSTRING(MetalDetector); - condition = QUOTE([ACE_player] call FUNC(hasDetector)); + condition = QUOTE(_player call FUNC(hasDetector)); statement = ""; icon = QPATHTOF(ui\icon_mineDetector.paa); exceptions[] = {}; class GVAR(activate) { displayName = CSTRING(ActivateDetector); - condition = QUOTE(call FUNC(canActivateDetector)); - statement = QUOTE(call FUNC(activateDetector)); + condition = QUOTE(_player call FUNC(canActivateDetector)); + statement = QUOTE(_player call FUNC(activateDetector)); icon = QPATHTOF(ui\icon_mineDetectorOn.paa); exceptions[] = {}; }; class GVAR(deactivate) { displayName = CSTRING(DeactivateDetector); - condition = QUOTE(call FUNC(canDeactivateDetector)); - statement = QUOTE(call FUNC(deactivateDetector)); + condition = QUOTE(_player call FUNC(canDeactivateDetector)); + statement = QUOTE(_player call FUNC(deactivateDetector)); icon = QPATHTOF(ui\icon_mineDetectorOff.paa); exceptions[] = {}; }; class GVAR(connectHeadphones) { displayName = CSTRING(ConnectHeadphones); - condition = QUOTE(call FUNC(canConnectHeadphones)); - statement = QUOTE([ARR_2(ACE_player,true)] call FUNC(connectHeadphones)); + condition = QUOTE(_player call FUNC(canConnectHeadphones)); + statement = QUOTE([ARR_2(_player,true)] call FUNC(connectHeadphones)); icon = ""; //TODO exceptions[] = {}; }; class GVAR(disconnectHeadphones) { displayName = CSTRING(DisconnectHeadphones); - condition = QUOTE(call FUNC(canDisconnectHeadphones)); - statement = QUOTE([ARR_2(ACE_player,false)] call FUNC(connectHeadphones)); + condition = QUOTE(_player call FUNC(canDisconnectHeadphones)); + statement = QUOTE([ARR_2(_player,false)] call FUNC(connectHeadphones)); icon = ""; //TODO exceptions[] = {}; }; @@ -49,6 +49,7 @@ class CfgVehicles { }; }; }; + class Items_base_F; class ACE_Explosives_Place: Items_base_F { GVAR(detectable) = 1; diff --git a/addons/minedetector/CfgWeapons.hpp b/addons/minedetector/CfgWeapons.hpp index fddc3c28685..b06ba6b4d97 100644 --- a/addons/minedetector/CfgWeapons.hpp +++ b/addons/minedetector/CfgWeapons.hpp @@ -10,8 +10,8 @@ class CfgWeapons { author = ECSTRING(common,ACETeam); displayName = "VMM3"; descriptionShort = CSTRING(VMM3_Description); - model = QUOTE(PATHTOF(ace_wallon_vmm3.p3d)); - picture = QUOTE(PATHTOF(data\equip\w_vmm3_ca.paa)); + model = QPATHTOF(ace_wallon_vmm3.p3d); + picture = QPATHTOF(data\equip\w_vmm3_ca.paa); magazines[] = { }; modes[] = { "Single" }; cursor = "EmptyCursor"; @@ -43,8 +43,8 @@ class CfgWeapons { scope = 2; displayName = "VMH3"; author = ECSTRING(common,ACETeam); - model = QUOTE(PATHTOF(ace_wallon_vmh3.p3d)); - picture = QUOTE(PATHTOF(data\equip\w_vmh3_ca.paa)); + model = QPATHTOF(ace_wallon_vmh3.p3d); + picture = QPATHTOF(data\equip\w_vmh3_ca.paa); class WeaponSlotsInfo: WeaponSlotsInfo { mass = 55; }; diff --git a/addons/minedetector/XEH_PREP.hpp b/addons/minedetector/XEH_PREP.hpp index e3d9316bf5d..155d45d1827 100644 --- a/addons/minedetector/XEH_PREP.hpp +++ b/addons/minedetector/XEH_PREP.hpp @@ -1,16 +1,13 @@ - +PREP(activateDetector); PREP(canActivateDetector); PREP(canConnectHeadphones); PREP(canDeactivateDetector); PREP(canDisconnectHeadphones); PREP(connectHeadphones); -PREP(activateDetector); PREP(deactivateDetector); -PREP(hasDetector); PREP(detectorLoop); -PREP(disableDetector); -PREP(enableDetector); PREP(getDetectedObject); +PREP(getDetectorConfig); +PREP(hasDetector); PREP(isDetectorEnabled); PREP(playDetectorSound); -PREP(getDetectorConfig); diff --git a/addons/minedetector/XEH_postInit.sqf b/addons/minedetector/XEH_postInit.sqf index 0671699f9e8..28adf9b166f 100644 --- a/addons/minedetector/XEH_postInit.sqf +++ b/addons/minedetector/XEH_postInit.sqf @@ -3,23 +3,21 @@ // Create a dictionary to store detector configs GVAR(detectorConfigs) = createHashMap; -[QGVAR(enableDetector), LINKFUNC(enableDetector)] call CBA_fnc_addEventHandler; -[QGVAR(disableDetector), LINKFUNC(disableDetector)] call CBA_fnc_addEventHandler; - // Shows detector and mine posistions in 3d when debug is on #ifdef DEBUG_MODE_FULL GVAR(debugDetector) = []; + addMissionEventHandler ["Draw3D", { if (GVAR(debugDetector) isEqualTo []) exitWith {}; + GVAR(debugDetector) params ["_detectorPointAGL", "_mines"]; - drawIcon3D ["\A3\ui_f\data\map\markers\military\dot_CA.paa", [0,0,1,1], _detectorPointAGL, 1, 1, 0, "detector", 1, 0.02, "PuristaMedium"]; + + drawIcon3D ["\A3\ui_f\data\map\markers\military\dot_CA.paa", [0, 0, 1, 1], _detectorPointAGL, 1, 1, 0, "detector", 1, 0.02, "PuristaMedium"]; + { private _name = format ["%1@%2", typeOf _x, (floor ((_x distance _detectorPointAGL) * 10)) / 10]; - if ((getNumber (configOf _x >> QGVAR(detectable))) == 1) then { - drawIcon3D ["\A3\ui_f\data\map\markers\military\dot_CA.paa", [1,0,0,1], (ASLToAGL (getPosASL _x)), 1, 1, 0, _name, 1, 0.02, "PuristaMedium"]; - } else { - drawIcon3D ["\A3\ui_f\data\map\markers\military\dot_CA.paa", [1,1,0,1], (ASLToAGL (getPosASL _x)), 1, 1, 0, _name, 1, 0.02, "PuristaMedium"]; - }; + + drawIcon3D ["\A3\ui_f\data\map\markers\military\dot_CA.paa", [[1, 1, 0, 1], [1, 0, 0, 1]] select (getNumber (configOf _x >> QGVAR(detectable)) == 1), ASLtoAGL (getPosASL _x), 1, 1, 0, _name, 1, 0.02, "PuristaMedium"]; } forEach _mines; }]; #endif diff --git a/addons/minedetector/XEH_preStart.sqf b/addons/minedetector/XEH_preStart.sqf index 046c0373640..8e1a04d0379 100644 --- a/addons/minedetector/XEH_preStart.sqf +++ b/addons/minedetector/XEH_preStart.sqf @@ -2,13 +2,15 @@ #include "XEH_PREP.hpp" -// Cache detectable classes, see XEH_postInit.sqf +// Cache detectable classes private _detectableClasses = []; + { if ((getNumber (_x >> QGVAR(detectable))) == 1) then { _detectableClasses pushBackUnique configName _x; }; } forEach (configProperties [configFile >> "CfgVehicles", "isClass _x", true]); + { if ((getNumber (_x >> QGVAR(detectable))) == 1) then { _detectableClasses pushBackUnique configName _x; diff --git a/addons/minedetector/config.cpp b/addons/minedetector/config.cpp index 7a48e0e2a06..6899c18237a 100644 --- a/addons/minedetector/config.cpp +++ b/addons/minedetector/config.cpp @@ -4,7 +4,7 @@ class CfgPatches { class ADDON { name = COMPONENT_NAME; units[] = {}; - weapons[] = {"ACE_VMH3","ACE_VMM3"}; + weapons[] = {"ACE_VMH3", "ACE_VMM3"}; requiredVersion = REQUIRED_VERSION; requiredAddons[] = {"ace_explosives"}; author = ECSTRING(common,ACETeam); diff --git a/addons/minedetector/functions/fnc_activateDetector.sqf b/addons/minedetector/functions/fnc_activateDetector.sqf index 7899899d4b4..681b5aa6877 100644 --- a/addons/minedetector/functions/fnc_activateDetector.sqf +++ b/addons/minedetector/functions/fnc_activateDetector.sqf @@ -1,20 +1,48 @@ #include "..\script_component.hpp" /* * Author: Glowbal - * Activate the mine detector + * Activates the mine detector. Selects the mine detector if not selected. * * Arguments: - * None + * 0: Unit + * 1: Detector type (default: currentWeapon Unit) * * Return Value: - * None + * If the detector was activated * * Example: - * [] call ace_minedetector_fnc_activateDetector + * [player, currentWeapon player] call ace_minedetector_fnc_activateDetector * - * Public: No + * Public: Yes */ -if (call FUNC(canActivateDetector)) then { - [ACE_player, currentWeapon ACE_player] call FUNC(enableDetector); +params [["_unit", objNull, [objNull]]]; + +if (!local _unit || {!alive _unit}) exitWith { + false // return +}; + +private _currentWeapon = currentWeapon _unit; +private _detectorType = param [1, _currentWeapon, [""]]; + +if (_detectorType == "" || {!([_unit, _detectorType] call FUNC(canActivateDetector))}) exitWith {false}; + +// Select mine detector if not already selected +if (_currentWeapon != _detectorType) then { + _unit selectWeapon _detectorType; }; + +// This prevents multiple PFH for the same weapon +_unit setVariable [format [QGVAR(enable_%1), _detectorType], true, true]; + +if (_unit == ACE_player) then { + playSoundUI ["ACE_Sound_Click"]; +}; + +// API +[QGVAR(detectorEnabled), [_unit, _detectorType]] call CBA_fnc_localEvent; + +// Start monitoring +[LINKFUNC(detectorLoop), 0.05, [_unit, _detectorType, _detectorType call FUNC(getDetectorConfig), CBA_missionTime - 0.25]] call CBA_fnc_addPerFrameHandler; + +true // return diff --git a/addons/minedetector/functions/fnc_canActivateDetector.sqf b/addons/minedetector/functions/fnc_canActivateDetector.sqf index 7b1de093e9f..676c8accf17 100644 --- a/addons/minedetector/functions/fnc_canActivateDetector.sqf +++ b/addons/minedetector/functions/fnc_canActivateDetector.sqf @@ -1,19 +1,27 @@ #include "..\script_component.hpp" /* * Author: Glowbal - * Check if the mine detector can be activated + * Checks if the mine detector can be activated. * * Arguments: - * None + * 0: Unit + * 1: Detector type (default: currentWeapon Unit) * * Return Value: * Can be activated * * Example: - * [] call ace_minedetector_fnc_canActivateDetector + * [player, currentWeapon player] call ace_minedetector_fnc_canActivateDetector * * Public: No */ -([ACE_player] call FUNC(hasDetector)) && -!([ACE_player, currentWeapon ACE_player] call FUNC(isDetectorEnabled)); +params ["_unit"]; + +if (!local _unit || {!alive _unit}) exitWith { + false // return +}; + +private _detectorType = param [1, currentWeapon _unit, [""]]; + +[_unit, _detectorType] call FUNC(hasDetector) && {!([_unit, _detectorType] call FUNC(isDetectorEnabled))} // return diff --git a/addons/minedetector/functions/fnc_canConnectHeadphones.sqf b/addons/minedetector/functions/fnc_canConnectHeadphones.sqf index cc83271d03c..b7d91083d03 100644 --- a/addons/minedetector/functions/fnc_canConnectHeadphones.sqf +++ b/addons/minedetector/functions/fnc_canConnectHeadphones.sqf @@ -1,19 +1,20 @@ #include "..\script_component.hpp" /* * Author: esteldunedain - * Check if headphones can be connected to the mine detector + * Checks if headphones can be connected to the mine detector. * * Arguments: - * None + * 0: Unit * * Return Value: * Can be connected * * Example: - * [] call ace_minedetector_fnc_canConnectHeadphones + * player call ace_minedetector_fnc_canConnectHeadphones * * Public: No */ -!(ACE_player getVariable [QGVAR(isUsingHeadphones), false]) && -{[ACE_player] call FUNC(hasDetector)}; +params ["_unit"]; + +!(_unit getVariable [QGVAR(isUsingHeadphones), false]) && {_unit call FUNC(hasDetector)} // return diff --git a/addons/minedetector/functions/fnc_canDeactivateDetector.sqf b/addons/minedetector/functions/fnc_canDeactivateDetector.sqf index 06eeab62e1b..01e37dc00f8 100644 --- a/addons/minedetector/functions/fnc_canDeactivateDetector.sqf +++ b/addons/minedetector/functions/fnc_canDeactivateDetector.sqf @@ -1,19 +1,23 @@ #include "..\script_component.hpp" /* * Author: Glowbal - * Check if the mine detector can be deactivated + * Checks if the mine detector can be deactivated. * * Arguments: - * None + * 0: Unit + * 1: Detector type (default: currentWeapon Unit) * * Return Value: * Can be deactivated * * Example: - * [] call ace_minedetector_fnc_canDeactivateDetector + * call ace_minedetector_fnc_canDeactivateDetector * * Public: No */ -([ACE_player] call FUNC(hasDetector)) && -{[ACE_player, currentWeapon ACE_player] call FUNC(isDetectorEnabled)}; +params ["_unit"]; + +private _detectorType = param [1, currentWeapon _unit, [""]]; + +[_unit, _detectorType] call FUNC(hasDetector) && {[_unit, _detectorType] call FUNC(isDetectorEnabled)} // return diff --git a/addons/minedetector/functions/fnc_canDisconnectHeadphones.sqf b/addons/minedetector/functions/fnc_canDisconnectHeadphones.sqf index 733d1a9ff22..aa5adc0befd 100644 --- a/addons/minedetector/functions/fnc_canDisconnectHeadphones.sqf +++ b/addons/minedetector/functions/fnc_canDisconnectHeadphones.sqf @@ -1,19 +1,20 @@ #include "..\script_component.hpp" /* * Author: esteldunedain - * Check if headphones can be disconnected from the mine detector + * Checks if headphones can be disconnected from the mine detector. * * Arguments: - * None + * 0: Unit * * Return Value: * Can be disconnected * * Example: - * [] call ace_minedetector_fnc_canDisconnectHeadphones + * player call ace_minedetector_fnc_canDisconnectHeadphones * * Public: No */ -(ACE_player getVariable [QGVAR(isUsingHeadphones), false]) && -{[ACE_player] call FUNC(hasDetector)}; +params ["_unit"]; + +(_unit getVariable [QGVAR(isUsingHeadphones), false]) && {_unit call FUNC(hasDetector)} // return diff --git a/addons/minedetector/functions/fnc_connectHeadphones.sqf b/addons/minedetector/functions/fnc_connectHeadphones.sqf index 88b6b298461..0ad760ce2b9 100644 --- a/addons/minedetector/functions/fnc_connectHeadphones.sqf +++ b/addons/minedetector/functions/fnc_connectHeadphones.sqf @@ -1,7 +1,7 @@ #include "..\script_component.hpp" /* * Author: esteldunedain - * Connect/disconnect headphones to the mine detector + * Connects/disconnects headphones to the mine detector. * * Arguments: * 0: Unit @@ -11,16 +11,19 @@ * None * * Example: - * [_unit, true] call ace_minedetector_fnc_connectHeadphones + * [player, true] call ace_minedetector_fnc_connectHeadphones * * Public: No */ params ["_unit", "_state"]; -_unit setVariable [QGVAR(isUsingHeadphones), _state]; + +_unit setVariable [QGVAR(isUsingHeadphones), _state, true]; + +if (_unit != ACE_player) exitWith {}; if (_state) then { - [localize LSTRING(HeadphonesConnected)] call EFUNC(common,displayTextStructured); + [LLSTRING(HeadphonesConnected)] call EFUNC(common,displayTextStructured); } else { - [localize LSTRING(HeadphonesDisconnected)] call EFUNC(common,displayTextStructured); + [LLSTRING(HeadphonesDisconnected)] call EFUNC(common,displayTextStructured); }; diff --git a/addons/minedetector/functions/fnc_deactivateDetector.sqf b/addons/minedetector/functions/fnc_deactivateDetector.sqf index 7403250ad69..a1258a34ea3 100644 --- a/addons/minedetector/functions/fnc_deactivateDetector.sqf +++ b/addons/minedetector/functions/fnc_deactivateDetector.sqf @@ -1,20 +1,38 @@ #include "..\script_component.hpp" /* * Author: Glowbal - * Deactivate the mine detector + * Deactivates the mine detector. * * Arguments: - * None + * 0: Unit + * 1: Detector type (default: currentWeapon Unit) * * Return Value: - * None + * If the detector was deactivated * * Example: - * [] call ace_minedetector_fnc_deactivateDetector + * [player, currentWeapon player] call ace_minedetector_fnc_deactivateDetector * - * Public: No + * Public: Yes */ -if (call FUNC(canDeactivateDetector)) then { - [ACE_player, currentWeapon ACE_player] call FUNC(disableDetector); +params [["_unit", objNull, [objNull]], ["_detectorType", "", [""]]]; + +if (!local _unit) exitWith { + false // return +}; + +private _detectorType = param [1, currentWeapon _unit, [""]]; + +if (_detectorType == "" || {!([_unit, _detectorType] call FUNC(canDeactivateDetector))}) exitWith {false}; + +_unit setVariable [format [QGVAR(enable_%1), _detectorType], false, true]; + +if (alive _unit && {_unit == ACE_player}) then { + playSoundUI ["ACE_Sound_Click"]; }; + +// API +[QGVAR(detectorDisabled), [_unit, _detectorType]] call CBA_fnc_localEvent; + +true // return diff --git a/addons/minedetector/functions/fnc_detectorLoop.sqf b/addons/minedetector/functions/fnc_detectorLoop.sqf index 1ede6c74227..9d466e46be4 100644 --- a/addons/minedetector/functions/fnc_detectorLoop.sqf +++ b/addons/minedetector/functions/fnc_detectorLoop.sqf @@ -1,74 +1,54 @@ #include "..\script_component.hpp" /* * Author: Glowbal - * Handle mine detection in a PFH loop + * Handles mine detection in a PFH loop. * * Arguments: - * 0: args - * 1: PHD Id + * 0: Args + * 1: PFH Id * * Return Value: * None * * Example: - * [[args], 2] call ACE_minedetector_fnc_detectorLoop + * [[args], 2] call ace_minedetector_fnc_detectorLoop * * Public: No */ -params ["_args", "_idPFH"]; -_args params ["_unit", "_type", "_detectorConfig", "_lastPlayed"]; +params ["_args", "_pfhID"]; +_args params ["_unit", "_detectorType", "_detectorConfig", "_lastPlayed"]; -// If locality switched just turn off the detector -if !(local _unit) exitWith { - [QGVAR(disableDetector), [_unit, _type], _unit] call CBA_fnc_targetEvent; - [_idPFH] call CBA_fnc_removePerFrameHandler; -}; - -if !([_unit, _type] call FUNC(hasDetector)) exitWith { - // disable detector type - [_unit, _type] call FUNC(disableDetector); - [_idPFH] call CBA_fnc_removePerFrameHandler; -}; - -if (!alive _unit) exitWith { - [_unit, _type] call FUNC(disableDetector); - [_idPFH] call CBA_fnc_removePerFrameHandler; -}; +// Check that the unis is in a valid state and if the unit hasn't switched weapons +if (!alive _unit || {_unit != ACE_player} || {currentWeapon _unit != _detectorType}) exitWith { + [_unit, _detectorType] call FUNC(deactivateDetector); -if !([_unit, _type] call FUNC(isDetectorEnabled)) exitWith { - [_idPFH] call CBA_fnc_removePerFrameHandler; + _pfhID call CBA_fnc_removePerFrameHandler; }; -if (currentWeapon _unit != _type) exitWith { - [_unit, _type] call FUNC(disableDetector); - [_idPFH] call CBA_fnc_removePerFrameHandler; +if !([_unit, _detectorType] call FUNC(isDetectorEnabled)) exitWith { + _pfhID call CBA_fnc_removePerFrameHandler; }; -private _detected = [[_unit, _detectorConfig], FUNC(getDetectedObject), _unit, QGVAR(detectedObjects), 0.15] call EFUNC(common,cachedCall); +private _detected = [[_unit, _detectorType, _detectorConfig], FUNC(getDetectedObject), _unit, QGVAR(detectedObjects), 0.15] call EFUNC(common,cachedCall); _detected params ["_hasDetected", "_mine", "_distance"]; if (!_hasDetected) exitWith {}; -// Launch a local event stating which mine was detected for mission purposes -[QGVAR(mineDetected), [_unit, _mine, _distance]] call CBA_fnc_localEvent; +// API +[QGVAR(mineDetected), [_unit, _mine, _distance, _detectorType]] call CBA_fnc_localEvent; -private _distanceTiming = switch (true) do { - case (_distance >= 2): {1}; - case (_distance >= 1.25): {0.85}; - case (_distance >= 0.75): {0.7}; - default {0.5}; -}; +_detectorConfig params ["", "", "_sounds", "_soundDistances", "_soundIntervals", "_soundIntervalDistances"]; + +private _index = _soundIntervalDistances findIf {_distance >= _x}; -if (CBA_missionTime - _lastPlayed < _distanceTiming) exitWith {}; +if (_index == -1 || {CBA_missionTime - _lastPlayed < _soundIntervals select _index}) exitWith {}; _args set [3, CBA_missionTime]; -_detectorConfig params ["", "", "_soundClasses"]; -private _soundClass = switch (true) do { - case (_distance >= 2): {_soundClasses select 3}; - case (_distance >= 1.25): {_soundClasses select 2}; - case (_distance >= 0.5): {_soundClasses select 1}; - default {_soundClasses select 0}; -}; -[_unit, _soundClass] call FUNC(playDetectorSound); +// Find the sound class to play that matches with distance +_index = _soundDistances findIf {_distance >= _x}; + +if (_index == -1) exitWith {}; + +[_unit, _sounds select _index] call FUNC(playDetectorSound); diff --git a/addons/minedetector/functions/fnc_disableDetector.sqf b/addons/minedetector/functions/fnc_disableDetector.sqf deleted file mode 100644 index 33106b4c452..00000000000 --- a/addons/minedetector/functions/fnc_disableDetector.sqf +++ /dev/null @@ -1,31 +0,0 @@ -#include "..\script_component.hpp" -/* - * Author: Glowbal - * Disables the mine detector - * - * Arguments: - * 0: Unit - * 1: detecter type - * - * Return Value: - * None - * - * Example: - * [UNIT, DETECTOR_CLASS_NAME] call ace_minedetector_fnc_disableDetector - * - * Public: No - */ - -params ["_unit", "_detectorType"]; - -if !(local _unit) then { - [QGVAR(disableDetector), [_unit, _detectorType], _unit] call CBA_fnc_targetEvent; -}; - -_unit setVariable [format[QGVAR(enable_%1), _detectorType], false, true]; - -if (_unit == ACE_player && {alive _unit}) then { - playSound "ACE_Sound_Click"; -}; - -[QGVAR(detectorDisabled), [_unit, _detectorType]] call CBA_fnc_localEvent; diff --git a/addons/minedetector/functions/fnc_enableDetector.sqf b/addons/minedetector/functions/fnc_enableDetector.sqf deleted file mode 100644 index 55b58dcf3a6..00000000000 --- a/addons/minedetector/functions/fnc_enableDetector.sqf +++ /dev/null @@ -1,34 +0,0 @@ -#include "..\script_component.hpp" -/* - * Author: Glowbal - * Enables the mine detector - * - * Arguments: - * 0: Unit - * 1: detecter type - * - * Return Value: - * None - * - * Example: - * [UNIT, DETECTOR_CLASS_NAME] call ace_minedetector_fnc_enableDetector - * - * Public: No - */ - -params ["_unit", "_detectorType"]; - -if !(local _unit) then { - [QGVAR(enableDetector), [_unit, _detectorType], _unit] call CBA_fnc_targetEvent; -}; - -_unit setVariable [format[QGVAR(enable_%1), _detectorType], true, true]; - -if (_unit == ACE_player) then { - playSound "ACE_Sound_Click"; -}; - -[QGVAR(detectorEnabled), [_unit, _detectorType]] call CBA_fnc_localEvent; - -private _config = [_detectorType] call FUNC(getDetectorConfig); -[LINKFUNC(detectorLoop), 0.05, [_unit, _detectorType, _config, CBA_missionTime - 0.25]] call CBA_fnc_addPerFrameHandler; diff --git a/addons/minedetector/functions/fnc_getDetectedObject.sqf b/addons/minedetector/functions/fnc_getDetectedObject.sqf index 8cc95ac4226..1d68af9aeb6 100644 --- a/addons/minedetector/functions/fnc_getDetectedObject.sqf +++ b/addons/minedetector/functions/fnc_getDetectedObject.sqf @@ -1,54 +1,47 @@ #include "..\script_component.hpp" /* * Author: Glowbal - * Get the distance to the nearest detectable object + * Gets the distance to the nearest detectable object. * * Arguments: * 0: Unit - * 1: Configuration + * 1: Mine detector + * 2: Mine detector config * * Return Value: - * [isDetected , mine , distance ] + * + * 0: If mine was detected + * 1: Detected mine + * 2: Distance to mine * * Example: - * [ace_player, DETECTOR_CONFIG] call ace_minedetector_fnc_getDetectedObject + * [player, currentWeapon player, (currentWeapon player) call ace_minedetector_fnc_getDetectorConfig] call ace_minedetector_fnc_getDetectedObject * * Public: No */ -params ["_unit", "_detectorConfig"]; -_detectorConfig params ["", "_radius"]; +params ["_unit", "_detectorType", "_detectorConfig"]; +_detectorConfig params ["_detectorPosition", "_radius"]; private _worldPosition = _unit modelToWorld (_unit selectionPosition "granat"); -private _ref = (_unit weaponDirection currentWeapon _unit) call EFUNC(common,createOrthonormalReference); -_ref params ["_v1", "_v2", "_v3"]; -private _detectorPointAGL = _worldPosition vectorAdd - (_v1 vectorMultiply ( 0.9 * __DR)) vectorAdd - (_v2 vectorMultiply (-0.2 * __DR)) vectorAdd - (_v3 vectorMultiply ( 0.4 * __DR)); +// Move _detectorPosition along the direction vector of the unit's weapon +private _detectorPointAGL = _worldPosition vectorAdd (([_detectorPosition] matrixMultiply ((_unit weaponDirection _detectorType) call EFUNC(common,createOrthonormalReference))) select 0); private _nearestObjects = nearestObjects [_detectorPointAGL, [], _radius]; #ifdef DEBUG_MODE_FULL GVAR(debugDetector) = [_detectorPointAGL, _nearestObjects]; #endif -private _isDetectable = false; -private _mine = objNull; -private _distance = -1; +private _detectableClasses = uiNamespace getVariable QGVAR(detectableClasses); +private _index = _nearestObjects findIf {(typeOf _x) in _detectableClasses && {(getModelInfo _x) select 0 != "empty.p3d"}}; -{ - if ((getModelInfo _x) select 0 == "empty.p3d") then { - continue; - }; +// Not found +if (_index == -1) then { + [false, objNull, -1] // return +} else { + private _mine = _nearestObjects select _index; - // If an object was detected, exit the search - if ((typeOf _x) in GVAR(detectableClasses)) exitWith { - _isDetectable = true; - _distance = _detectorPointAGL distance _x; - _mine = _x; - TRACE_3("return",_isDetectable,_mine,_distance); - }; -} forEach _nearestObjects; - -[_isDetectable, _mine, _distance]; + // Found + [true, _mine, _detectorPointAGL distance _mine] // return +}; diff --git a/addons/minedetector/functions/fnc_getDetectorConfig.sqf b/addons/minedetector/functions/fnc_getDetectorConfig.sqf index a5566cbfbfc..2d386509571 100644 --- a/addons/minedetector/functions/fnc_getDetectorConfig.sqf +++ b/addons/minedetector/functions/fnc_getDetectorConfig.sqf @@ -1,33 +1,54 @@ #include "..\script_component.hpp" /* * Author: Glowbal - * Get the mine detector configuration from the cache or config file + * Gets the mine detector configuration from the cache or config file. * * Arguments: - * 0: Detector class name + * 0: Detector type * * Return Value: * Detector configuration or empty array if invalid * * Example: - * ["my_detector"] call ace_minedetector_fnc_getDetectorConfig + * (currentWeapon player) call ace_minedetector_fnc_getDetectorConfig * * Public: No */ params ["_detectorType"]; -if (_detectorType isEqualTo "") exitWith {[]}; +if (_detectorType == "") exitWith { + [] // return +}; + +GVAR(detectorConfigs) getOrDefaultCall [toLowerANSI _detectorType, { + private _cfgEntry = configFile >> "ACE_detector" >> "detectors" >> _detectorType; -GVAR(detectorConfigs) getOrDefaultCall [_detectorType, { - private _cfgEntry = (configFile >> "ACE_detector" >> "detectors" >> _detectorType); if (isClass _cfgEntry) then { + private _detectorPosition = getArray (_cfgEntry >> "detectorPosition"); + private _sounds = getArray (_cfgEntry >> "sounds"); + private _soundDistances = getArray (_cfgEntry >> "soundDistances"); + private _soundIntervals = getArray (_cfgEntry >> "soundIntervals"); + private _soundIntervalDistances = getArray (_cfgEntry >> "soundIntervalDistances"); + + reverse _sounds; + reverse _soundDistances; + reverse _soundIntervals; + reverse _soundIntervalDistances; + + if (_detectorPosition isEqualTo [] || {_sounds isEqualTo []} || {_soundIntervals isEqualTo []} || {count _sounds != count _soundDistances} || {count _soundIntervals != count _soundIntervalDistances}) then { + ERROR_1("Mine detector %1 is configured badly",_detectorType); + }; + [ - _detectorType, + _detectorPosition, getNumber (_cfgEntry >> "radius"), - getArray (_cfgEntry >> "sounds") - ]; + _sounds, + _soundDistances, + _soundIntervals, + _soundIntervalDistances + ] } else { [] }; -}, true] +}, true] // return diff --git a/addons/minedetector/functions/fnc_hasDetector.sqf b/addons/minedetector/functions/fnc_hasDetector.sqf index 05ac7e412ee..96910b0aa6b 100644 --- a/addons/minedetector/functions/fnc_hasDetector.sqf +++ b/addons/minedetector/functions/fnc_hasDetector.sqf @@ -1,20 +1,21 @@ #include "..\script_component.hpp" /* * Author: Glowbal - * Check if unit has a mine detector in hands + * Checks if the unit has a mine detector. * * Arguments: * 0: Unit + * 1: Detector type (default: currentWeapon Unit) * * Return Value: - * Current weapon is a mine detector + * Current weapon is a mine detector * * Example: - * [ace_player] call ace_minedetector_fnc_hasDetector + * player call ace_minedetector_fnc_hasDetector * - * Public: No + * Public: Yes */ -params ["_unit"]; +params [["_unit", objNull, [objNull]]]; -([currentWeapon _unit] call FUNC(getDetectorConfig)) isNotEqualTo []; +((param [1, currentWeapon _unit, [""]]) call FUNC(getDetectorConfig)) isNotEqualTo [] // return diff --git a/addons/minedetector/functions/fnc_isDetectorEnabled.sqf b/addons/minedetector/functions/fnc_isDetectorEnabled.sqf index 6b94e4bc110..8ef839bb9c3 100644 --- a/addons/minedetector/functions/fnc_isDetectorEnabled.sqf +++ b/addons/minedetector/functions/fnc_isDetectorEnabled.sqf @@ -1,20 +1,27 @@ #include "..\script_component.hpp" /* * Author: Glowbal - * Check if the mine detector is enabled + * Checks if the mine detector is enabled. * * Arguments: - * 0: detecter type + * 0: Unit + * 1: Detector type (default: currentWeapon Unit) * * Return Value: * None * * Example: - * ["example"] call ace_minedetector_fnc_isDetectorEnabled + * [player, currentWeapon player] call ace_minedetector_fnc_isDetectorEnabled * - * Public: No + * Public: Yes */ -params ["_unit", "_detectorType"]; +params [["_unit", objNull, [objNull]]]; -alive _unit && {(_unit getVariable [format[QGVAR(enable_%1), _detectorType], false])}; +if (!alive _unit) exitWith { + false // return +}; + +private _detectorType = param [1, currentWeapon _unit, [""]]; + +_detectorType != "" && {_unit getVariable [format [QGVAR(enable_%1), _detectorType], false]} // return diff --git a/addons/minedetector/functions/fnc_playDetectorSound.sqf b/addons/minedetector/functions/fnc_playDetectorSound.sqf index cfd5dc38224..e19b37f4bc2 100644 --- a/addons/minedetector/functions/fnc_playDetectorSound.sqf +++ b/addons/minedetector/functions/fnc_playDetectorSound.sqf @@ -1,7 +1,7 @@ #include "..\script_component.hpp" /* * Author: Glowbal - * Play the detector sound + * Plays the detector sound. * * Arguments: * 0: Unit @@ -11,23 +11,19 @@ * None * * Example: - * [player, "ace_buzz_1", 1] call ace_minedetector_fnc_playDetectorSound + * [player, "ace_buzz_1"] call ace_minedetector_fnc_playDetectorSound * * Public: No */ params ["_unit", "_soundClass"]; -if (isNull _unit) exitWith { - ERROR_1("unit does not exist [%1]",_unit); -}; -if (!alive _unit) exitWith { - ERROR_1("unit is not alive [%1]",_unit); -}; - -if (_unit getVariable [QGVAR(isUsingHeadphones), false] && {_unit == ACE_player}) then { - playSound _soundClass; +if (_unit getVariable [QGVAR(isUsingHeadphones), false]) then { + if (alive _unit && {_unit == ACE_player}) then { + playSoundUI [_soundClass]; + }; } else { private _posASL = _unit modelToWorldWorld (_unit selectionPosition "granat"); + [_soundClass, _posASL, 3, 15] call EFUNC(common,playConfigSound3D); }; diff --git a/addons/minedetector/script_component.hpp b/addons/minedetector/script_component.hpp index 154f1a05e2e..ed6be44d853 100644 --- a/addons/minedetector/script_component.hpp +++ b/addons/minedetector/script_component.hpp @@ -15,5 +15,3 @@ #endif #include "\z\ace\addons\main\script_macros.hpp" - -#define __DR 1.3 diff --git a/docs/wiki/framework/events-framework.md b/docs/wiki/framework/events-framework.md index 8569f41a9aa..c5d90729bd0 100644 --- a/docs/wiki/framework/events-framework.md +++ b/docs/wiki/framework/events-framework.md @@ -193,6 +193,14 @@ MenuType: 0 = Interaction, 1 = Self Interaction | `ace_huntir_monitorConnected` | [_unit, _huntir] | Local | Listen | Called when the monitor is connected | `ace_huntir_monitorNoGDS` | [_unit] | Local | Listen | Called when the monitor found no GDS +### 2.20 Mine detector (`ace_minedetector`) + +| Event Key | Parameters | Locality | Type | Description | +|---------- |------------|----------|------|-------------| +| `ace_minedetector_detectorEnabled` | [_unit, _detectorType] | Local | Listen | Called when local unit turned on their mine detector +| `ace_minedetector_detectorDisabled` | [_unit, _detectorType] | Local | Listen | Called when local unit turned off their mine detector +| `ace_minedetector_mineDetected` | [_unit, _mine, _distance, _detectorType] | Local | Listen | Called when local unit has detected a mine + ## 3. Usage Also Reference [CBA Events System](https://github.com/CBATeam/CBA_A3/wiki/Custom-Events-System){:target="_blank"} documentation. diff --git a/docs/wiki/framework/minedetector-framework.md b/docs/wiki/framework/minedetector-framework.md new file mode 100644 index 00000000000..a6a89b08495 --- /dev/null +++ b/docs/wiki/framework/minedetector-framework.md @@ -0,0 +1,78 @@ +--- +layout: wiki +title: Mine Detector Framework +description: Explains how to add custom mine detectors, as well as making objects detectable. +group: framework +order: 5 +parent: wiki +mod: ace +version: + major: 3 + minor: 19 + patch: 0 +--- + +## 1. Making objects detectable + +Objects defined in `CfgVehicles` or `CfgAmmo` can be detected if their `ace_minedetector_detectable` attribute is set to `1`. + + +## 2. Adding custom mine detectors + +Adding a custom mine detector requires you to create an addon containing specific classes and properties in the config. + +### 2.1 Add the item + +Create your weapon. + +```cpp +class CfgWeapons { + class Pistol; + class Pistol_Base_F: Pistol { + class WeaponSlotsInfo; + }; + class MyMineDetector: Pistol_Base_F { + displayName = "My Mine Detector"; + model = "path/to/myMineDetectorModel.p3d" + }; +}; +``` + +### 2.2 Add the mine detector config + +Add a new config entry in `"ACE_detector" >> "detectors"` with the same name as the weapon created above. + +```cpp +class ACE_detector { + class detectors { + class MyMineDetector { + detectorPosition = {1.3, -0.22, 0.4}; // Position from which the mine detector will search for mines (= position of the mine detector head) + radius = 2.5; // Maximum distance the mine detector can detect a mine + sounds[] = {"ace_detector_1", "ace_detector_2", "ace_detector_3, "ace_detector_4"}; // Sounds + soundDistances[] = {0, 0.5, 1.25, 2}; // Distances defining the sounds to be played when a mine is detected + soundIntervals[] = {0.5, 0.7, 0.85, 1}; // Interval values + soundIntervalDistances[] = {0, 0.75, 1.25, 2}; // Distances defining at what intervals the sounds should be played + }; + }; +}; +``` + +In the example above, the sound `ace_detector_1` will be played between 0 and 0.5 m, `ace_detector_2` 0.5 - 1.25 m, `ace_detector_3` 1.25 - 2 m and `ace_detector_4` 2 - 2.5 m. All of these numbers are defined in `soundDistances`, except the maximum, which is defined in `radius.` The last distance defined in `soundDistances` must therefore be either equal or smaller than `radius.`. + +`soundIntervals` is done is the same manner as `sounds`, except it uses `soundIntervalDistances` instead of `soundDistances`. + +`detectorPosition` defines an offset from the selection `"granat"` on a person. The following piece of code allows you visualize the position in game: + +```sqf +private _unit = player; +private _detectorType = currentWeapon player; +private _detectorPosition = (_detectorType call ace_minedetector_fnc_getDetectorConfig) select 0; + +private _worldPosition = _unit modelToWorld (_unit selectionPosition "granat"); +private _detectorPointAGL = _worldPosition vectorAdd (([_detectorPosition] matrixMultiply ((_unit weaponDirection _detectorType) call ace_common_fnc_createOrthonormalReference)) select 0); + +// Create an arrow at the place where the mine detector head is +private _arrow = createVehicle ["Sign_Arrow_Blue_F", _detectorPointAGL, [], 0, "CAN_COLLIDE"]; + +[{deleteVehicle _this}, _arrow, 2] call CBA_fnc_waitAndExecute; +```