Merge pull request #4052 from acemod/fix4049

Mine detector optimization and cleanup
This commit is contained in:
Glowbal 2016-07-11 11:16:16 +02:00 committed by GitHub
commit 02f08939f2
27 changed files with 287 additions and 124 deletions

View File

@ -127,6 +127,7 @@ PREP(numberToString);
PREP(onAnswerRequest);
PREP(owned);
PREP(parseList);
PREP(playConfigSound3D);
PREP(player);
PREP(playerSide);
PREP(positionToASL);

View File

@ -0,0 +1,35 @@
/*
* Author: esteldunedain
* Plays a sound defined in CfgSounds using playSound3D, with global effect
*
* Arguments:
* 0: Sound class <STRING>
* 1: Position ASL <ARRAY>
* 2: Volume <NUMBER>
* 3: Distance <NUMBER>
*
* Return Value:
* None
*
* Public: Yes
*/
#define DEBUG_MODE_FULL
#include "script_component.hpp"
params ["_soundClass", "_posASL", "_volume", "_distance"];
private _cfgSound = configFile >> "CfgSounds" >> _soundClass;
if (!isClass _cfgSound) exitWith {
ACE_LOGERROR_1("CfgSounds class [%1] does not exist", _soundClass);
};
private _args = getArray (_cfgSound >> "sound");
TRACE_1("playConfigSound3D args", _args);
private _pitch = (_args select 2);
// Strip the first \ from the filename
private _fileName = _args select 0;
_fileName = _fileName select [1, count _fileName - 1];
TRACE_1("playConfigSound3D filename", _fileName);
playSound3D [_fileName, objNull, false, _posASL, _volume, _pitch, _distance];

View File

@ -1,6 +1,4 @@
class ACE_detector {
class detectableObjects {
};
class detectors {
class ACE_VMM3 {
radius = 2.5;

View File

@ -5,6 +5,6 @@ class Extended_PreInit_EventHandlers {
};
class Extended_PostInit_EventHandlers {
class ADDON {
clientInit = QUOTE( call COMPILE_FILE(XEH_clientInit) );
init = QUOTE( call COMPILE_FILE(XEH_postInit) );
};
};

View File

@ -1,22 +1,22 @@
class CfgSounds {
class ace_detector_1 {
name = "ace_detector_1";
sound[] = {QUOTE(PATHTOF(sounds\metal_detector.wav)), "db+1", 1};
sound[] = {QUOTE(PATHTOF(sounds\metal_detector.wss)), "db+3", 1};
titles[] = {};
};
class ace_detector_2 {
name = "ace_detector_2";
sound[] = {QUOTE(PATHTOF(sounds\metal_detector.wav)), "db+1", 0.9};
sound[] = {QUOTE(PATHTOF(sounds\metal_detector.wss)), "db+3", 0.9};
titles[] = {};
};
class ace_detector_3 {
name = "ace_detector_3";
sound[] = {QUOTE(PATHTOF(sounds\metal_detector.wav)), "db+1", 0.8};
sound[] = {QUOTE(PATHTOF(sounds\metal_detector.wss)), "db+3", 0.8};
titles[] = {};
};
class ace_detector_4 {
name = "ace_detector_4";
sound[] = {QUOTE(PATHTOF(sounds\metal_detector.wav)), "db+1", 0.7};
sound[] = {QUOTE(PATHTOF(sounds\metal_detector.wss)), "db+3", 0.7};
titles[] = {};
};
};

View File

@ -11,23 +11,40 @@ class CfgVehicles {
class CAManBase: Man {
class ACE_SelfActions {
class ACE_Equipment {
class GVAR(activate) {
displayName = CSTRING(ActivateDetector);
condition = QUOTE(call FUNC(canActivateDetector));
statement = QUOTE(call FUNC(activateDetector));
showDisabled = 0;
priority = 0.1;
icon = QPATHTOF(ui\icon_mineDetectorOn.paa);
exceptions[] = {};
};
class GVAR(deactivate) {
displayName = CSTRING(DeactivateDetector);
condition = QUOTE(call FUNC(canDeactivateDetector));
statement = QUOTE(call FUNC(deactivateDetector));
showDisabled = 0;
priority = 0.1;
icon = QPATHTOF(ui\icon_mineDetectorOff.paa);
class GVAR(metalDetector) {
displayName = CSTRING(MetalDetector);
condition = QUOTE([ACE_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));
icon = QPATHTOF(ui\icon_mineDetectorOn.paa);
exceptions[] = {};
};
class GVAR(deactivate) {
displayName = CSTRING(DeactivateDetector);
condition = QUOTE(call FUNC(canDeactivateDetector));
statement = QUOTE(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));
icon = ""; //TODO
exceptions[] = {};
};
class GVAR(disconnectHeadphones) {
displayName = CSTRING(DisconnectHeadphones);
condition = QUOTE(call FUNC(canDisconnectHeadphones));
statement = QUOTE([ARR_2(ACE_player, false)] call FUNC(connectHeadphones));
icon = ""; //TODO
exceptions[] = {};
};
};
};
};

View File

@ -14,6 +14,8 @@ class CfgWeapons {
picture = QUOTE(PATHTOF(data\equip\w_vmm3_ca.paa));
magazines[] = { };
modes[] = { "Single" };
cursor = "EmptyCursor";
cursorAim = "EmptyCursor";
class Single: Mode_SemiAuto {
displayName = "";
sounds[] = {};

View File

@ -1,6 +1,9 @@
PREP(canActivateDetector);
PREP(canConnectHeadphones);
PREP(canDeactivateDetector);
PREP(canDisconnectHeadphones);
PREP(connectHeadphones);
PREP(activateDetector);
PREP(deactivateDetector);
PREP(hasDetector);

View File

@ -1,27 +1,25 @@
#include "script_component.hpp"
// Create a dictionary to store detector configs
GVAR(detectorConfigs) = call CBA_fnc_createNamespace;
[QGVAR(detectorEnabled), {
params ["_unit", "_type"];
private _config = [_type] call FUNC(getDetectorConfig);
private _helperObject = "ACE_LogicDummy" createVehicleLocal (getPos _unit);
_unit setVariable [QGVAR(helperLogic), _helperObject];
[FUNC(detectorLoop), 0.01, [_unit, _type, _config, CBA_missionTime, _helperObject]] call CBA_fnc_addPerFrameHandler;
}] call CBA_fnc_addEventHandler;
[QGVAR(detectorDisabled), {
params ["_unit", "_type"];
private _helperObject = _unit getVariable [QGVAR(helperLogic), objNull];
if !(isNull _helperObject) then {
deleteVehicle _helperObject;
// Create a dictionary of detectable classnames
GVAR(detectableClasses) = call CBA_fnc_createNamespace;
{
if ((getNumber (_x >> QGVAR(detectable))) == 1) then {
GVAR(detectableClasses) setVariable [configName _x, true];
};
}] call CBA_fnc_addEventHandler;
} forEach (configProperties [configFile >> "CfgVehicles", "isClass _x", true]);
{
if ((getNumber (_x >> QGVAR(detectable))) == 1) then {
GVAR(detectableClasses) setVariable [configName _x, true];
};
} forEach (configProperties [configFile >> "CfgAmmo", "isClass _x", true]);
[QGVAR(enableDetector), FUNC(enableDetector)] call CBA_fnc_addEventHandler;
[QGVAR(disableDetector), FUNC(disableDetector)] call CBA_fnc_addEventHandler;
//Shows detector and mine posistions in 3d when debug is on
// Shows detector and mine posistions in 3d when debug is on
#ifdef DEBUG_MODE_FULL
GVAR(debugDetector) = [];
addMissionEventHandler ["Draw3D", {

View File

@ -4,7 +4,4 @@ ADDON = false;
#include "XEH_PREP.hpp"
// TODO load from config instead of hardcoded in sqf
GVAR(ALL_DETECTABLE_TYPES) = ["ACE_Explosive_Object", "ACE_Explosive_Helper", "ACE_Explosives_Place", "ModuleMine_F", "TimeBombCore", "MineBase", "DirectionalBombBase", "BoundingMineBase", "PipeBombBase"];
ADDON = true;

View File

@ -8,7 +8,7 @@ class CfgPatches {
requiredVersion = REQUIRED_VERSION;
requiredAddons[] = {"ace_explosives"};
author = ECSTRING(common,ACETeam);
authors[] = {"Grey", "Glowbal", "Rocko"};
authors[] = {"Grey", "Glowbal", "Rocko", "esteldunedain"};
url = ECSTRING(main,URL);
VERSION_CONFIG;
};

View File

@ -16,4 +16,5 @@
#include "script_component.hpp"
([ACE_player] call FUNC(hasDetector)) && !([ACE_player, currentWeapon ACE_player] call FUNC(isDetectorEnabled));
([ACE_player] call FUNC(hasDetector)) &&
!([ACE_player, currentWeapon ACE_player] call FUNC(isDetectorEnabled));

View File

@ -0,0 +1,20 @@
/*
* Author: esteldunedain
* Check if headphones can be connected to the mine detector
*
* Arguments:
* None
*
* Return Value:
* Can be connected <BOOL>
*
* Example:
* [] call ace_minedetector_fnc_canConnectHeadphones
*
* Public: No
*/
#include "script_component.hpp"
!(ACE_player getVariable [QGVAR(isUsingHeadphones), false]) &&
{[ACE_player] call FUNC(hasDetector)};

View File

@ -16,4 +16,5 @@
#include "script_component.hpp"
([ACE_player] call FUNC(hasDetector)) && {[ACE_player, currentWeapon ACE_player] call FUNC(isDetectorEnabled)};
([ACE_player] call FUNC(hasDetector)) &&
{[ACE_player, currentWeapon ACE_player] call FUNC(isDetectorEnabled)};

View File

@ -0,0 +1,20 @@
/*
* Author: esteldunedain
* Check if headphones can be disconnected from the mine detector
*
* Arguments:
* None
*
* Return Value:
* Can be disconnected <BOOL>
*
* Example:
* [] call ace_minedetector_fnc_canDisconnectHeadphones
*
* Public: No
*/
#include "script_component.hpp"
(ACE_player getVariable [QGVAR(isUsingHeadphones), false]) &&
{[ACE_player] call FUNC(hasDetector)};

View File

@ -0,0 +1,27 @@
/*
* Author: esteldunedain
* Connect/disconnect headphones to the mine detector
*
* Arguments:
* 0: Unit <OBJECT>
* 1: Connect? <BOOLEAN>
*
* Return Value:
* None
*
* Example:
* [_unit, true] call ace_minedetector_fnc_connectHeadphones
*
* Public: No
*/
#include "script_component.hpp"
params ["_unit", "_state"];
_unit setVariable [QGVAR(isUsingHeadphones), _state];
if (_state) then {
[localize LSTRING(HeadphonesConnected)] call EFUNC(common,displayTextStructured);
} else {
[localize LSTRING(HeadphonesDisconnected)] call EFUNC(common,displayTextStructured);
};

View File

@ -17,6 +17,12 @@
params ["_args", "_idPFH"];
_args params ["_unit", "_type", "_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);
@ -32,24 +38,35 @@ if !([_unit, _type] call FUNC(isDetectorEnabled)) exitWith {
[_idPFH] call CBA_fnc_removePerFrameHandler;
};
if (ACE_player == _unit && {currentWeapon _unit == _type}) then {
private _detected = [_unit, _detectorConfig] call FUNC(getDetectedObject);
_detected params ["_hasDetected", "_object", "_distance"];
private _distanceTiming = switch (true) do {
case (_distance >= 2): {1};
case (_distance >= 1.25): {0.85};
case (_distance >= 0.75): {0.7};
default {0.5};
};
if (_hasDetected && {(CBA_missionTime - _lastPlayed > _distanceTiming)}) then {
_args set [3, CBA_missionTime];
_detectorConfig params ["_type", "_radius", "_detectableTypes", "_sounds"];
private _sound = switch (true) do {
case (_distance >= 2): {_sounds select 3};
case (_distance >= 1.25): {_sounds select 2};
case (_distance >= 0.5): {_sounds select 1};
default {_sounds select 0};
};
[_unit, _sound, true] call FUNC(playDetectorSound);
};
if (currentWeapon _unit != _type) exitWith {
[_unit, _type] call FUNC(disableDetector);
[_idPFH] call CBA_fnc_removePerFrameHandler;
};
private _detected = [[_unit, _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;
private _distanceTiming = switch (true) do {
case (_distance >= 2): {1};
case (_distance >= 1.25): {0.85};
case (_distance >= 0.75): {0.7};
default {0.5};
};
if (CBA_missionTime - _lastPlayed < _distanceTiming) 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);

View File

@ -19,6 +19,14 @@
params ["_unit", "_detectorType"];
_unit setVariable [format[QGVAR(enable_%1), _detectorType], false];
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;

View File

@ -19,6 +19,17 @@
params ["_unit", "_detectorType"];
_unit setVariable [format[QGVAR(enable_%1), _detectorType], true];
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);
[FUNC(detectorLoop), 0.05, [_unit, _detectorType, _config, CBA_missionTime - 0.25]] call CBA_fnc_addPerFrameHandler;

View File

@ -1,6 +1,6 @@
/*
* Author: Glowbal
* Enables the mine detector
* Get the distance to the nearest detectable object
*
* Arguments:
* 0: Unit <OBJECT>
@ -15,17 +15,18 @@
* Public: No
*/
#define __DR 1.3
#include "script_component.hpp"
params ["_unit", "_detectorConfig"];
_detectorConfig params ["_type", "_radius", "_detectableTypes", "_sounds"];
_detectorConfig params ["", "_radius"];
private _worldPosition = _unit modelToWorld (_unit selectionPosition "granat");
private _direction = _unit weaponDirection "Put";
private _detectorPointAGL = _worldPosition vectorAdd (_direction vectorMultiply __DR);
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));
private _nearestObjects = nearestObjects [_detectorPointAGL, [], _radius];
@ -38,27 +39,19 @@ private _mine = objNull;
private _distance = -1;
{
private _object = _x;
private _objectType = typeOf _x;
if ({_object isKindOf _x} count _detectableTypes > 0) then {
//Try all unprepared mines in range and use first detectable one:
if ((getNumber (configFile >> "CfgVehicles" >> (typeOf _x) >> QGVAR(detectable))) == 1) exitWith {
_isDetectable = true;
_mine = _x;
_distance = _detectorPointAGL distance _x;
};
//Try all prepared mines in range and use first detectable one:
if ((getNumber (configFile >> "CfgAmmo" >> (typeOf _x) >> QGVAR(detectable))) == 1) exitWith {
_isDetectable = true;
_mine = _x;
_distance = _detectorPointAGL distance _x;
};
_isDetectable = GVAR(detectableClasses) getVariable _objectType;
if (isNil "_isDetectable") then {
_isDetectable = false;
};
if (!isNull _mine) exitWith {};
// If a nun-null object was detected exit the search
if (_isDetectable && {!isNull _x}) exitWith {
_distance = _detectorPointAGL distance _x;
_mine = _x;
TRACE_3("return", _isDetectable, _mine, _distance);
};
} forEach _nearestObjects;
TRACE_3("return",_isDetectable,_mine,_distance);
[_isDetectable, _mine, _distance];

View File

@ -1,6 +1,6 @@
/*
* Author: Glowbal
* Get the mine detector configuration from the config file
* Get the mine detector configuration from the cache or config file
*
* Arguments:
* 0: Detector class name <STRING>
@ -18,14 +18,18 @@
params ["_detectorType"];
private _config = (configFile >> "ACE_detector" >> "detectors" >> _detectorType);
if (isClass _config) then {
[
_detectorType,
getNumber (_config >> "radius"),
GVAR(ALL_DETECTABLE_TYPES), // TODO read from config and use this as a back up value instead
getArray (_config >> "sounds")
];
} else {
[];
private _detectorConfig = GVAR(detectorConfigs) getVariable _detectorType;
if (isNil "_detectorConfig") then {
private _cfgEntry = (configFile >> "ACE_detector" >> "detectors" >> _detectorType);
if (isClass _cfgEntry) then {
_detectorConfig = [
_detectorType,
getNumber (_cfgEntry >> "radius"),
getArray (_cfgEntry >> "sounds")
];
} else {
_detectorConfig = [];
};
GVAR(detectorConfigs) setVariable [_detectorType, _detectorConfig];
};
_detectorConfig

View File

@ -4,20 +4,20 @@
*
* Arguments:
* 0: Unit <OBJECT>
* 1: Sound class name <STRING>
* 1: Sound class <STRING>
*
* Return Value:
* None
*
* Example:
* [player, "ace_buzz_1"] call ace_minedetector_fnc_playDetectorSound
* [player, "ace_buzz_1", 1] call ace_minedetector_fnc_playDetectorSound
*
* Public: No
*/
#include "script_component.hpp"
params ["_unit", "_detectorSound"];
params ["_unit", "_soundClass"];
if (isNull _unit) exitWith {
ACE_LOGERROR_1("unit does not exist [%1]",_unit);
@ -26,17 +26,9 @@ if (!alive _unit) exitWith {
ACE_LOGERROR_1("unit is not alive [%1]",_unit);
};
private _helperObject = _unit getVariable [QGVAR(helperLogic), objNull];
if (!isNull _helperObject) then {
deleteVehicle _helperObject;
};
_helperObject = "ACE_LogicDummy" createVehicleLocal (getPos _unit);
if !(isNull _helperObject) then {
_helperObject attachTo [_unit,[0,0,-3],""];
_unit setVariable [QGVAR(helperLogic), _helperObject];
[_helperObject, _unit] say3D _detectorSound;
if (_unit getVariable [QGVAR(isUsingHeadphones), false] && {_unit == ACE_player}) then {
playSound _soundClass;
} else {
ACE_LOGERROR_1("helper does not exist [%1]",_helperObject);
private _posASL = AGLtoASL (_unit modelToWorld (_unit selectionPosition "granat"));
[_soundClass, _posASL, 3, 15] call EFUNC(common,playConfigSound3D);
};

View File

@ -16,3 +16,5 @@
#endif
#include "\z\ace\addons\main\script_macros.hpp"
#define __DR 1.3

Binary file not shown.

View File

@ -5,13 +5,29 @@
<English>Metal detector</English>
<French>Détecteur de métaux</French>
</Key>
<Key ID="STR_ACE_MineDetector_MetalDetector">
<English>Metal detector</English>
<French>Détecteur de métaux</French>
</Key>
<Key ID="STR_ACE_MineDetector_ActivateDetector">
<English>Activate Detector</English>
<French>Activer le détecteur</French>
<English>Activate</English>
<French>Activer</French>
</Key>
<Key ID="STR_ACE_MineDetector_DeactivateDetector">
<English>Deactivate Detector</English>
<French>Désactiver le détecteur</French>
<English>Deactivate</English>
<French>Désactiver</French>
</Key>
<Key ID="STR_ACE_MineDetector_ConnectHeadphones">
<English>Connect Headphones</English>
</Key>
<Key ID="STR_ACE_MineDetector_DisconnectHeadphones">
<English>Disconnect Headphones</English>
</Key>
<Key ID="STR_ACE_MineDetector_HeadphonesConnected">
<English>Headphones Connected</English>
</Key>
<Key ID="STR_ACE_MineDetector_HeadphonesDisconnected">
<English>Headphones Disconnected</English>
</Key>
</Package>
</Project>

Binary file not shown.