Laser guidance for all designators (#3308)

* Fix laser and missileguidance over water

* Return a normalized vector in EFUNC(common,getTurretDirection)

* Make laser dispersion simulation optional, default off

* Prototype for ace_laser_designate

* Remove vanilla laser handling from ace_laser in favor of the new code on ace_laser_designate

* Simplify laser into one module

Rewrite large parts of laser
Merge laser_designate
Delete lase_selfDesignate

* Cleanup missile guidance

* Headers, fix laser over water

* Cleanup

* Test

* Change setting to scalar, more cleanup

* Add seeker debug drawing
This commit is contained in:
Nicolás Badano 2016-10-08 03:55:30 -07:00 committed by Glowbal
parent 74dfa6ca33
commit ab6fc8efca
64 changed files with 740 additions and 1040 deletions

View File

@ -38,5 +38,5 @@ if (_pov == "pip0_pos") then {
_povDir = _gunBeginPos vectorDiff _gunEndPos; _povDir = _gunBeginPos vectorDiff _gunEndPos;
}; };
_povDir = vectorNormalized _povDir;
[_povPos, _povDir] [_povPos, _povDir]

View File

@ -0,0 +1,7 @@
class ACE_Settings {
class GVAR(dispersionCount) {
value = 2;
typeName = "SCALAR";
displayName = CSTRING(dispersionCount_displayName);
};
};

View File

@ -1,4 +1,3 @@
class Extended_PreStart_EventHandlers { class Extended_PreStart_EventHandlers {
class ADDON { class ADDON {
init = QUOTE(call COMPILE_FILE(XEH_preStart)); init = QUOTE(call COMPILE_FILE(XEH_preStart));
@ -7,20 +6,13 @@ class Extended_PreStart_EventHandlers {
class Extended_PreInit_EventHandlers { class Extended_PreInit_EventHandlers {
class ADDON { class ADDON {
init = QUOTE(call COMPILE_FILE(XEH_pre_init)); init = QUOTE(call COMPILE_FILE(XEH_preInit));
}; };
}; };
class Extended_PostInit_EventHandlers { class Extended_PostInit_EventHandlers {
class ADDON { class ADDON {
init = QUOTE(call COMPILE_FILE(XEH_post_init)); init = QUOTE(call COMPILE_FILE(XEH_postInit));
}; };
}; };
class Extended_Init_EventHandlers {
class LaserTargetBase {
class ADDON {
init = QUOTE(_this call DFUNC(laser_init));
};
};
};

View File

@ -1,44 +1,31 @@
class CfgVehicles { class CfgVehicles {
class All; class All;
class LaserTarget: All { class LaserTarget: All {
// @TODO: Changing the model and simulation hides it, but THEN IT DOESNT SPAWN WTF!? // @TODO: Changing the model and simulation hides it, but THEN IT DOESNT SPAWN WTF!?
model = "\A3\Weapons_F\empty.p3d"; // model = "\A3\Weapons_F\empty.p3d";
destrType = "DestructNo";
simulation = "LaserTarget";
class EventHandlers { class EventHandlers {
init = QUOTE(_this call FUNC(laser_init)); class ADDON {
init = QUOTE(_this call FUNC(handleLaserTargetCreation));
};
}; };
}; };
// Visual laserTarget override // laserTarget fails if the turret does not have "primaryGunner" config
class ACE_LaserTarget_Visual : LaserTarget { // This only effects the indfor strider who's commander is not the primaryGunner
simulation = "LaserTarget"; class LandVehicle;
model = "\A3\Weapons_f\laserTgt.p3d"; class Car: LandVehicle {
class NewTurret;
}; };
class Car_F: Car {
// Vehicle lockable configurations
class AllVehicles;
class Air: AllVehicles {
class Turrets;
};
class Helicopter: Air {
class Turrets { class Turrets {
class MainTurret; class MainTurret: NewTurret {};
}; };
}; };
class MRAP_03_base_F: Car_F {
class Helicopter_Base_F: Helicopter {};
class Heli_Attack_01_base_F: Helicopter_Base_F {};
class B_Heli_Attack_01_F: Heli_Attack_01_base_F {
class Turrets: Turrets { class Turrets: Turrets {
class MainTurret: MainTurret { class CommanderTurret: MainTurret {
GVAR(CanLockLaser) = 1; // Enable laser locking selection primaryGunner = 1;
}; };
}; };
}; };

View File

@ -10,3 +10,5 @@ The people responsible for merging changes to this component or answering potent
- [walterpearce](https://github.com/walterpearce) - [walterpearce](https://github.com/walterpearce)
- [NouberNou](https://github.com/NouberNou) - [NouberNou](https://github.com/NouberNou)
- [esteldunedain](https://github.com/esteldunedain)
- [PabstMirror](https://github.com/PabstMirror)

View File

@ -1,26 +1,15 @@
PREP(rotateVectLineGetMap); PREP(addLaserTarget);
PREP(rotateVectLine); PREP(dev_drawVisibleLaserTargets);
PREP(shootRay); PREP(findLaserSource);
PREP(shootCone); PREP(handleLaserTargetCreation);
PREP(checkLos); PREP(keyLaserCodeChange);
PREP(findStrongestRay);
PREP(onLaserDesignatorDraw);
PREP(seekerFindLaserSpot);
PREP(laserOn);
PREP(laserOff); PREP(laserOff);
PREP(handleLaserOn); PREP(laserOn);
PREP(handleLaserOff);
PREP(drawVisibleLaserTargets);
PREP(laser_init);
PREP(vanillaLaserSeekerHandler);
PREP(laserTargetPFH); PREP(laserTargetPFH);
PREP(onLaserDesignatorDraw);
PREP(unitTurretCanLockLaser); PREP(rotateVectLine);
PREP(keyLaserCodeUp); PREP(rotateVectLineGetMap);
PREP(keyLaserCodeDown); PREP(seekerFindLaserSpot);
PREP(shootCone);
PREP(shootRay);

View File

@ -0,0 +1,23 @@
#include "script_component.hpp"
#include "initKeybinds.sqf"
// Global Laser EHs
["ace_laserOn", {
params ["_uuid", "_args"];
TRACE_2("ace_laserOn eh",_uuid,_args);
[GVAR(laserEmitters), _uuid, _args] call CBA_fnc_hashSet;
}] call CBA_fnc_addEventHandler;
["ace_laserOff", {
params ["_uuid"];
TRACE_1("ace_laserOn eh",_uuid);
if ([GVAR(laserEmitters), _uuid] call CBA_fnc_hashHasKey) then {
[GVAR(laserEmitters), _uuid] call CBA_fnc_hashRem;
};
}] call CBA_fnc_addEventHandler;
// Shows detector and mine posistions in 3d when debug is on
#ifdef DRAW_LASER_INFO
addMissionEventHandler ["Draw3D", {_this call FUNC(dev_drawVisibleLaserTargets)}];
#endif

View File

@ -1,7 +0,0 @@
#include "script_component.hpp"
#include "initKeybinds.sqf"
["ace_laserOn", {_this call DFUNC(handleLaserOn)}] call CBA_fnc_addEventHandler;
["ace_laserOff", {_this call DFUNC(handleLaserOff)}] call CBA_fnc_addEventHandler;

View File

@ -4,13 +4,13 @@ ADDON = false;
#include "XEH_PREP.hpp" #include "XEH_PREP.hpp"
GVAR(VanillaLasers) = [];
// Laser default variables // Laser default variables
ACE_DEFAULT_LASER_CODE = 1001; ACE_DEFAULT_LASER_CODE = 1111;
ACE_DEFAULT_LASER_WAVELENGTH = 1550; ACE_DEFAULT_LASER_WAVELENGTH = 1550;
ACE_DEFAULT_LASER_BEAMSPREAD = 1; ACE_DEFAULT_LASER_BEAMSPREAD = 1;
GVAR(laserEmitters) = [] call CBA_fnc_hashCreate; GVAR(laserEmitters) = [] call CBA_fnc_hashCreate;
GVAR(trackedLaserTargets) = [];
GVAR(pfehID) = -1;
ADDON = true; ADDON = true;

View File

@ -13,6 +13,7 @@ class CfgPatches {
}; };
}; };
#include "ACE_Settings.hpp"
#include "CfgEventhandlers.hpp" #include "CfgEventhandlers.hpp"
#include "CfgVehicles.hpp" #include "CfgVehicles.hpp"
#include "CfgWeapons.hpp" #include "CfgWeapons.hpp"

View File

@ -0,0 +1,59 @@
/*
* Author: esteldunedain
* Adds a vanilla laser target to the tracker PFH and globaly turns it on
*
* Argument:
* 0: TargetObject (vanilla laser) <OBJECT>
* 1: Vehicle <OBJECT>
*
* Return value:
* None
*
* Example:
* [laserTarget player, player] call ace_laser_fnc_addLaserTarget;
*
* Public: No
*/
#include "script_component.hpp"
params ["_targetObject", "_vehicle"];
TRACE_2("params",_targetObject,_vehicle);
// Get the designator variables, or use defaults
private _waveLength = _vehicle getVariable [QEGVAR(laser,waveLength), ACE_DEFAULT_LASER_WAVELENGTH];
private _laserCode = _vehicle getVariable [QEGVAR(laser,code), ACE_DEFAULT_LASER_CODE];
private _beamSpread = _vehicle getVariable [QEGVAR(laser,beamSpread), ACE_DEFAULT_LASER_BEAMSPREAD];
TRACE_3("codes",_waveLength,_laserCode,_beamSpread);
// Laser method is the method ACE_Laser will use to determine from where to where it should project the designator cone
_vehicle setVariable [QGVAR(targetObject), _targetObject, true];
private _laserMethod = QFUNC(findLaserSource);
private _vehicleSourceSelection = "";
if (_vehicle isKindOf "CaManBase") then {
_vehicleSourceSelection = "pilot";
} else {
{ // Go through turrets on vehicle and find the laser
private _turretPath = _x;
{
if ((getNumber (configFile >> "CfgWeapons" >> _x >> "laser")) > 0) exitWith {
_vehicleSourceSelection = getText (([_vehicle, _turretPath] call CBA_fnc_getTurret) >> "memoryPointGunnerOptics");
TRACE_3("",_turretPath,_x,_vehicleSourceSelection);
};
} forEach (_vehicle weaponsTurret _turretPath);
} forEach (allTurrets [_vehicle, true]);
};
private _methodArgs = [_vehicleSourceSelection];
TRACE_6("Laser on:",_vehicle,_laserMethod,_waveLength,_laserCode,_beamSpread,_methodArgs);
private _laserUuid = [_vehicle, _vehicle, _laserMethod, _waveLength, _laserCode, _beamSpread, _methodArgs] call FUNC(laserOn);
GVAR(trackedLaserTargets) pushBack [_targetObject, _vehicle, _laserUuid];
TRACE_1("",GVAR(trackedLaserTargets));
if (GVAR(pfehID) == -1) then {
TRACE_1("starting pfeh",count GVAR(trackedLaserTargets));
GVAR(pfehID) = [DFUNC(laserTargetPFH), 0, []] call CBA_fnc_addPerFrameHandler;
};

View File

@ -1,28 +0,0 @@
#include "script_component.hpp"
params ["_pos1", "_pos2", "_designator", "_seeker"];
private _spacing = 100;
if((count _this) > 4) then {
_spacing = _this select 4;
};
private _return = true;
private _vectorTo = [_pos2, _pos1] call BIS_fnc_vectorFromXToY;
private _x = (_vectorTo select 0)*0.25;
private _y = (_vectorTo select 1)*0.25;
private _z = (_vectorTo select 2)*0.25;
_pos2 = [(_pos2 select 0) + _x, (_pos2 select 1) + _y, (_pos2 select 2) + _z];
// player sideChat format["new los check"];
if(terrainIntersect [_pos2, _pos1]) then {
_return = false;
} else {
if(lineIntersects [_pos2, _pos1]) then { // should take as arguments and add to this command objects to exclude - target and observer
// player sideChat format["with: %1", lineIntersectsWith [_pos1, _pos2]];
_return = false;
};
};
_return;

View File

@ -0,0 +1,61 @@
// Dev Debug Function
// Displays lasers and attempts to lock on to codes 1111 and 1112 from a target vehicle's view
// On Screen Debug:
// Red - Vanilla Laser Targets
// Yellow - Array (vehicle pos/weapon) Laser Targets
// Green - Rays
// Blue - Seeker Locks
#include "script_component.hpp"
// Try searching for lasers from a given vehicle position [BLUE]:
private _seekerVehicle = vehicle ace_player;
private _testSeekerPosASL = AGLtoASL (_seekerVehicle modelToWorldVisual [0,0,1]);
private _testSeekerDir = vectorDirVisual _seekerVehicle;
{
private _code = _x;
private _results = [_testSeekerPosASL, _testSeekerDir, 45, [1550,1550], _code, _seekerVehicle] call FUNC(seekerFindLaserSpot);
private _resultPos = _results select 0;
if (!isNil "_resultPos") then {
// Draw lock results
drawLine3D [ASLtoAGL _testSeekerPosASL, ASLtoAGL _resultPos, [0,0,1,1]];
drawIcon3D ["\a3\ui_f\data\IGUI\Cfg\Cursors\select_target_ca.paa", [0,0,1,1], (ASLtoAGL _resultPos), 1.5, 1.5, 45, format ["%1 from %2", _code, _results select 1], 0.5, 0.025, "TahomaB"];
};
} forEach [1111, 1112]; // Scan at codes 1111 and 1112
// Draw all lasers
[GVAR(laserEmitters), {
// TRACE_2("",_key,_value);
_value params ["_obj", "_owner", "_laserMethod", "_waveLength", "_laserCode", "_beamSpread"];
// Draw vanila lasers [RED]
if (_laserMethod isEqualTo QFUNC(findLaserSource)) then { // Normal vanilla laserTarget func
private _targetObject = _obj getVariable [QGVAR(targetObject), objNull];
private _targetPosASL = getPosASL _targetObject;
drawIcon3D ["\a3\ui_f\data\IGUI\Cfg\Cursors\select_target_ca.paa", [1,0,0,1], (ASLtoAGL _targetPosASL), 0.5, 0.5, 0, "", 0.5, 0.025, "TahomaB"];
(_value call FUNC(findLaserSource)) params ["_laserPosASL", "_laserDir"];
private _resultsRay = [_laserPosASL, _laserDir, _obj] call FUNC(shootRay);
private _rayPos = _resultsRay select 0;
if (isNil "_rayPos") then {
drawIcon3D ["\a3\ui_f\data\IGUI\Cfg\Cursors\select_target_ca.paa", [1,0,0,1], (ASLtoAGL _targetPosASL), 2, 2, 0, "Nil Ray", 0.5, 0.025, "TahomaB"];
} else {
private _diff = _rayPos vectorDistance (getPosASL _targetObject); // Diff from ray position compared to actual
drawIcon3D ["\a3\ui_f\data\IGUI\Cfg\Cursors\select_target_ca.paa", [1,0,0,1], (ASLtoAGL _rayPos), 2, 2, 0, format ["Diff %1",_diff], 0.5, 0.025, "TahomaB"];
};
};
// Draw array weapon lasers [YELLOW]
if ((_laserMethod isEqualType []) && {(count _laserMethod) == 2}) then {
_laserMethod params ["_modelPosition", "_weaponName"];
private _laserPosASL = AGLtoASL (_obj modelToWorldVisual _modelPosition);
drawIcon3D ["\a3\ui_f\data\IGUI\Cfg\Cursors\select_target_ca.paa", [1,1,0,1], (ASLtoAGL _laserPosASL), 0.5, 0.5, 0, _weaponName, 0.5, 0.025, "TahomaB"];
private _laserDir = _obj weaponDirection _weaponName;
private _resultsRay = [_laserPosASL, _laserDir, _obj] call FUNC(shootRay);
private _rayPos = _resultsRay select 0;
if (!isNil "_rayPos") then {
drawIcon3D ["\a3\ui_f\data\IGUI\Cfg\Cursors\select_target_ca.paa", [1,1,0,1], (ASLtoAGL _rayPos), 2, 2, 0, _weaponName, 0.5, 0.025, "TahomaB"];
};
};
}] call CBA_fnc_hashEachPair;

View File

@ -1,9 +0,0 @@
// This is a debug function for displaying visible lasers for ourselves
#include "script_component.hpp"
INFO("Laser Emitter Dump");
{
INFO_1(" %1", _x);
INFO_1(" %1",[ARR_2(GVAR(laserEmitters),_x)] call CBA_fnc_hashGet);
} forEach (GVAR(laserEmitters) select 1);

View File

@ -0,0 +1,41 @@
/*
* Author: esteldunedain
* Handler function for finding position and direction of a vanilla laser.
*
* Argument:
* 0: Vehicle (shooter of laser) <OBJECT>
* 6: Method Args <ARRAY>
* 0: Laser Source selection on Vehicle
*
* Return value:
* [position, direction]
*
* Example:
* [player, x,x,x,x,x, ["pilot"]] call ace_laser_fnc_findLaserSource;
*
* Public: No
*/
#include "script_component.hpp"
params ["_vehicle", "", "", "", "", "", "_methodArgs"];
_methodArgs params ["_ownerSelection"];
// Get the laser target object stored in the unit
private _targetObject = _vehicle getVariable [QGVAR(targetObject), objNull];
private _targetPos = getPosASL _targetObject;
if (surfaceIsWater _targetPos && {(_targetPos select 2) < 0}) then {
// Vanilla lasers seem to give position at ocean floor heigh, even though the x and y are correct??
_targetPos set [2, 0.25];
};
private _povPos = AGLtoASL (_vehicle modelToWorldVisual (_vehicle selectionPosition _ownerSelection));
private _povDir = _povPos vectorFromTo _targetPos;
TRACE_4("",_vehicle,_targetObject,_povPos,_povDir);
if(isNil "_povPos" || isNil "_povDir") exitWith {
WARNING_2("bad data [%1][%2]",_povPos,_povDir);
[-1,-1]
};
[_povPos, _povDir]

View File

@ -1,48 +0,0 @@
#include "script_component.hpp"
params ["_list", "_checkPos"];
private _spots = [];
private _outliers = [];
private _spot = [];
(_list select 0) params ["_testPos"];
{
_x params ["_samplePos"];
if(!lineIntersects [_samplePos, _checkPos] && {!terrainIntersectASL [_samplePos, _checkPos]}) then {
if(_samplePos distance _testPos < 2) then {
_spot pushBack _samplePos;
} else {
_outliers pushBack _samplePos;
};
};
} forEach _list;
_spots pushBack _spot;
if(count _outliers > 0) then {
for "_i" from 1 to 3 do {
private _remainingSpots = _outliers;
_outliers = [];
_spot = [];
_testPos = (_remainingSpots select 0);
{
private _samplePos = _x;
if(!lineIntersects [_samplePos, _checkPos] && {!terrainIntersectASL [_samplePos, _checkPos]}) then {
if(_samplePos distance _testPos < 2) then {
_spot pushBack _samplePos;
} else {
_outliers pushBack _samplePos;
};
};
} forEach _remainingSpots;
_spots pushBack _spot;
};
};
private _largest = 0;
private _largestSpot = [];
{
if(count _x > _largest) then {
_largest = count _x;
_largestSpot = _x;
};
} forEach _spots;
// player sideChat format["g: %1", _spots];
_largestSpot select (random (floor(count _largestSpot)));

View File

@ -1,7 +0,0 @@
//fnc_handleLaserOff.sqf
#include "script_component.hpp"
params ["_uuid"];
if ([GVAR(laserEmitters), _uuid] call CBA_fnc_hashHasKey) then {
[GVAR(laserEmitters), _uuid] call CBA_fnc_hashRem;
};

View File

@ -1,5 +0,0 @@
//fnc_handleLaserOn.sqf
#include "script_component.hpp"
params ["_uuid", "_args"];
[GVAR(laserEmitters), _uuid, _args] call CBA_fnc_hashSet;

View File

@ -0,0 +1,41 @@
/*
* Author: esteldunedain
* Associates a newly created laser target to it's owner
*
* Argument:
* 0: Vanilla Laser (base type LaserTarget) <OBJECT>
*
* Return value:
* None
*
* Return value:
* None
*
* Example:
* [laserTarget player] call ace_laser_fnc_handleLaserTargetCreation;
*
* Public: No
*/
#include "script_component.hpp"
TRACE_1("params",_this);
[{
params ["_targetObject"];
// Only handle locally created lasers
if(!(local _targetObject)) exitWith {TRACE_1("not local",_targetObject);};
private _owners = allUnits select {(lasertarget _x) == _targetObject};
if (count _owners == 1) exitWith {
TRACE_2("Laser target owner [allUnits]", _targetObject, _owners select 0);
[_targetObject, _owners select 0] call FUNC(addLaserTarget);
};
_owners = vehicles select {(lasertarget _x) == _targetObject};
if (count _owners == 1) exitWith {
TRACE_2("Laser target owner [vehicles]", _targetObject, _owners select 0);
[_targetObject, _owners select 0] call FUNC(addLaserTarget);
};
TRACE_1("Laser target doesn't have owner", _targetObject);
}, _this] call CBA_fnc_execNextFrame;

View File

@ -0,0 +1,59 @@
/*
* Author: PabstMirror
* Change the laser key code (both seeker and transmitter)
*
* Argument:
* 0: Change in code <NUMBER>
*
* Return value:
* Key Handled <BOOL>
* Example:
* [1] call ace_laser_fnc_keyLaserCodeChange;
*
* Public: No
*/
#include "script_component.hpp"
params [["_codeChange", 0, [0]]];
TRACE_1("params",_codeChange);
if ((!alive ACE_player) || {!([ACE_player, vehicle ACE_player, []] call EFUNC(common,canInteractWith))}) exitWith {false};
private _currentShooter = objNull;
private _currentWeapon = "";
if (ACE_player call CBA_fnc_canUseWeapon) then {
_currentShooter = ACE_player;
_currentWeapon = currentWeapon ACE_player;
} else {
_currentShooter = vehicle ACE_player;
private _turret = [ACE_player] call ace_common_fnc_getTurretIndex;
_currentWeapon = _currentShooter currentWeaponTurret _turret;
};
TRACE_2("",_currentShooter,_currentWeapon);
if ((getNumber (configFile >> "CfgWeapons" >> _currentWeapon >> "laser")) == 0) exitWith {false};
private _oldLaserCode = _currentShooter getVariable [QGVAR(code), ACE_DEFAULT_LASER_CODE];
private _newLaserCode = _oldLaserCode;
// "Four-digit code equipment settings range from 1111 to 1788"
// While there is a 0 or 9 in code, keep adding change
if (((_codeChange < 0) && {_oldLaserCode > ACE_DEFAULT_LASER_CODE}) || {(_codeChange > 0) && {_oldLaserCode < 1788}}) then {
_newLaserCode = _oldLaserCode + _codeChange;
while {(((str _newLaserCode) find "0") >= 0) || {((str _newLaserCode) find "9") >= 0}} do {
_newLaserCode = _newLaserCode + _codeChange;
};
};
TRACE_2("",_oldLaserCode,_newLaserCode);
if (_oldLaserCode != _newLaserCode) then {
_currentShooter setVariable [QGVAR(code), _newLaserCode, false];
};
[format ["%1: %2", localize LSTRING(laserCode), _newLaserCode]] call EFUNC(common,displayTextStructured);
true

View File

@ -1,12 +0,0 @@
//#define DEBUG_MODE_FULL
#include "script_component.hpp"
private ["_oldLaserCode", "_laserCode"];
_oldLaserCode = ACE_player getVariable [QGVAR(code), ACE_DEFAULT_LASER_CODE];
if(_oldLaserCode > ACE_DEFAULT_LASER_CODE) then {
_laserCode = _oldLaserCode - 1;
ACE_player setVariable [QGVAR(code), _laserCode, false];
};
if(_laserCode != _oldLaserCode) then {
[format ["%1: %2", localize LSTRING(laserCode), _laserCode]] call EFUNC(common,displayTextStructured);
};

View File

@ -1,10 +0,0 @@
//#define DEBUG_MODE_FULL
#include "script_component.hpp"
private ["_oldLaserCode", "_laserCode"];
_oldLaserCode = ACE_player getVariable [QGVAR(code), ACE_DEFAULT_LASER_CODE];
_laserCode = _oldLaserCode + 1;
ACE_player setVariable [QGVAR(code), _laserCode, false];
if(_laserCode != _oldLaserCode) then {
[format ["%1: %2", localize LSTRING(laserCode), _laserCode]] call EFUNC(common,displayTextStructured);
};

View File

@ -3,13 +3,20 @@
* Turn a laser designator off. * Turn a laser designator off.
* *
* Arguments: * Arguments:
* 0: UUID (from laserOn) <string> * 0: UUID (from laserOn) <STRING>
* *
* Return Value: * Return value:
* None * None
*
* Example:
* ["yourLaserUID"] call ace_laser_fnc_laserOff;
*
* Public: No
*/ */
#include "script_component.hpp" #include "script_component.hpp"
params ["_uuid"]; params ["_uuid"];
TRACE_1("Sending Global Laser Off Event",_uuid);
["ace_laserOff", [_uuid]] call CBA_fnc_globalEvent; ["ace_laserOff", [_uuid]] call CBA_fnc_globalEvent;

View File

@ -3,20 +3,33 @@
* Turn a laser designator on. * Turn a laser designator on.
* *
* Arguments: * Arguments:
* 0: Emitter <object> * 0: Emitter <OBJECT>
* 1: Owner <object> * 1: Owner <OBJECT>
* 2: Method, can be code, which emitter and owner are passed to, a string function name, an array with a position memory point and weapon name, or an array with a position memory point, a vector begining memory point, and vector ending memory point. * 2: Method, can be code, which emitter and owner are passed to, a string function name, an array with a position memory point and weapon name, or an array with a position memory point, a vector begining memory point, and vector ending memory point. <STRING><CODE><ARRAY>
* 3: Wavelength (1550nm is common eye safe) <number> * 3: Wavelength (1550nm is common eye safe) <NUMBER>
* 4: Laser code <number> * 4: Laser code <NUMBER>
* 5: Beam divergence (in mils off beam center). * 5: Beam divergence (in mils off beam center). <NUMBER>
* 6: Method Args <OPTIONAL><ANY>
* *
* Return Value: * Return Value:
* String, UUID for sending to laserOff function. * <String> UUID for sending to laserOff function.
*
* Example:
* [hmg, hmg, [[0,0,1], "HMG_static"], 1550, 1111, 1] call ace_laser_fnc_laserOn;
* [player, player, "ace_laser_fnc_findLaserSource", 1550, 1111, 1, ["pilot"]] call ace_laser_fnc_laserOn;
*
* Public: No
*/ */
#include "script_component.hpp" #include "script_component.hpp"
// params [["_emitter", objNull, [objNull]],["_owner", objNull, [objNull]],["_method", "", ["", {}, []]],["_wavelength", 0, [0]],["_code", 0, [0]],["_beamSpread", 0, [0]],"_methodArgs"];
private _uuid = format["%1%2%3", floor diag_tickTime, floor random 1000, floor random 10000]; private _uuid = format["%1%2%3", floor diag_tickTime, floor random 1000, floor random 10000];
private _args = [_uuid, _this]; private _args = [_uuid, _this];
TRACE_2("Sending Global Laser On Event",_uuid,_this);
["ace_laserOn", _args] call CBA_fnc_globalEvent; ["ace_laserOn", _args] call CBA_fnc_globalEvent;
_uuid; _uuid;

View File

@ -1,27 +1,40 @@
//#define DEBUG_MODE_FULL /*
* Author: esteldunedain
* Maintains the tracked lasers, deleting any laser that is turned off
*
* Argument:
* PFEH Args
*
* Return value:
* None
*
* Example:
* [[], 1]] call ace_laser_fnc_laserTargetPFH;
*
* Public: No
*/
#include "script_component.hpp" #include "script_component.hpp"
TRACE_1("enter", _this);
//TRACE_1("enter", _this); params ["", "_pfhuid"];
params ["_args"];
_args params ["_laserTarget", "_shooter", "_uuid"];
if(isNull _laserTarget || !alive _shooter) exitWith { GVAR(trackedLaserTargets) = GVAR(trackedLaserTargets) select {
[(_this select 1)] call CBA_fnc_removePerFrameHandler; _x params ["_targetObject", "_owner", "_laserUuid"];
REM(GVAR(VanillaLasers), _laserTarget); if ((isNull _targetObject) ||
{!(alive _targetObject)} ||
{isNull _owner} ||
{!(alive _owner)}) then {
// Remove laseron // Turn off the laser in ace_laser
[_uuid] call FUNC(laserOff); [_laserUuid] call FUNC(laserOff);
TRACE_1("Laser off:", _laserUuid);
false
} else {
true
};
}; };
#ifdef DEBUG_MODE_FULL if (GVAR(trackedLaserTargets) isEqualTo []) then {
// Iconize the location of the actual laserTarget TRACE_1("ending pfeh",count GVAR(trackedLaserTargets));
_pos = getPosASL _laserTarget; [_pfhuid] call CBA_fnc_removePerFrameHandler;
drawIcon3D ["\a3\ui_f\data\IGUI\Cfg\Cursors\select_target_ca.paa", [1,0,0,1], (ASLtoATL _pos), 0.75, 0.75, 0, "", 0.5, 0.025, "TahomaB"]; GVAR(pfehID) = -1;
};
{
drawLine3D [ASLtoATL (_x select 0), ASLtoATL (_x select 1), (_x select 2)];
drawIcon3D ["\a3\ui_f\data\IGUI\Cfg\Cursors\selectover_ca.paa", (_x select 2), ASLtoATL (_x select 1), 0.75, 0.75, 0, "", 0.5, 0.025, "TahomaB"];
} forEach DRAW_LINES;
DRAW_LINES = [];
#endif

View File

@ -1,33 +0,0 @@
//#define DEBUG_MODE_FULL
#include "script_component.hpp"
TRACE_1("enter", _this);
PARAMS_1(_laserTarget);
private ["_uuid"];
// Add the target to the global targets array
// Everyone tracks them
// Add the laser localized to the laser array, and give it the default localized code
PUSH(GVAR(VanillaLasers), _laserTarget);
// Check the vehicle, otherwise use the default
_laserTarget setVariable [QGVAR(code), ACE_DEFAULT_LASER_CODE, false];
_laserTarget setVariable [QGVAR(beamSpread), ACE_DEFAULT_LASER_BEAMSPREAD, false];
_laserTarget setVariable [QGVAR(waveLength), ACE_DEFAULT_LASER_WAVELENGTH, false];
// Clean the lasers of any null objects while we are here
REM(GVAR(VanillaLasers), objNull);
if(!(local _laserTarget)) exitWith { };
// The target is local, so its on this client
if(!isDedicated) then {
// @TODO: Get ownership variables and set them on the vehicle
_uuid = [(vehicle ACE_player), ACE_player, QFUNC(vanillaLaserSeekerHandler), ACE_DEFAULT_LASER_WAVELENGTH, ACE_DEFAULT_LASER_CODE, ACE_DEFAULT_LASER_BEAMSPREAD] call FUNC(laserOn);
_laserTarget setVariable [QGVAR(uuid), _uuid, false];
[FUNC(laserTargetPFH), 0, [_laserTarget, ACE_player, _uuid]] call CBA_fnc_addPerFrameHandler;
} else {
// server side ownership of laser
_laserTarget setVariable [QGVAR(owner), nil, true];
};

View File

@ -1,15 +1,28 @@
//#define DEBUG_MODE_FULL /*
* Author: Nou
* Update distance when rangefinder laser is on
*
* Arguments:
* None
*
* Return Value:
* None
*
* Example:
* [] call ace_laser_fnc_onLaserDesignatorDraw
*
* Public: No
*/
#include "script_component.hpp" #include "script_component.hpp"
private ["_laserCode"];
_laserCode = ACE_player getVariable[QGVAR(code), ACE_DEFAULT_LASER_CODE]; private _laserCode = ACE_player getVariable[QGVAR(code), ACE_DEFAULT_LASER_CODE];
if(!isNil "_laserCode") then { if (!isNil "_laserCode") then {
__LaserDesignatorIGUI_LaserCode ctrlSetText format["Code: %1", [_laserCode, 4, 0, false] call CBA_fnc_formatNumber]; __LaserDesignatorIGUI_LaserCode ctrlSetText format["Code: %1", [_laserCode, 4, 0, false] call CBA_fnc_formatNumber];
}; };
if(! (ctrlShown __LaserDesignatorIGUI_LaserOn) ) then { if (! (ctrlShown __LaserDesignatorIGUI_LaserOn) ) then {
// TODO: hide distance // TODO: hide distance
__LaserDesignatorIGUI_ACE_Distance ctrlSetText "----"; __LaserDesignatorIGUI_ACE_Distance ctrlSetText "----";
} else { } else {
__LaserDesignatorIGUI_ACE_Distance ctrlSetText (ctrlText __LaserDesignatorIGUI_CA_Distance); __LaserDesignatorIGUI_ACE_Distance ctrlSetText (ctrlText __LaserDesignatorIGUI_CA_Distance);
}; };

View File

@ -1,16 +1,9 @@
#include "script_component.hpp" #include "script_component.hpp"
private ["_d", "_map", "_p", "_theta", "_u"];
_map = _this select 0;
_theta = _this select 1;
_p = _map select 0; params ["_map", "_theta"];
_p1 = _map select 1; _map params ["_p", "_p1", "_p2", "_q1", "_q2", "_u", "_d"];
_p2 = _map select 2; _q1 = +_q1;
_q2 = +_q2;
_q1 = +(_map select 3);
_q2 = +(_map select 4);
_u = _map select 5;
_d = _map select 6;
/* Step 4 */ /* Step 4 */
_q2 set[0, (_q1 select 0) * cos(_theta) - (_q1 select 1) * sin(_theta)]; _q2 set[0, (_q1 select 0) * cos(_theta) - (_q1 select 1) * sin(_theta)];
@ -33,4 +26,4 @@ if (_d != 0) then {
/* Inverse of step 1 */ /* Inverse of step 1 */
_q1 = _q2 vectorAdd _p1; _q1 = _q2 vectorAdd _p1;
_q1; _q1;

View File

@ -1,17 +1,14 @@
#include "script_component.hpp" #include "script_component.hpp"
private ["_p", "_theta", "_p1", "_p2", "_q1", "_q2", "_u", "_d"]; params ["_p", "_p1", "_p2"];
_p = _this select 0;
_p1 = _this select 1;
_p2 = _this select 2;
_q2 = []; private _q2 = [];
/* Step 1 */ /* Step 1 */
_q1 = _p vectorDiff _p1; private _q1 = _p vectorDiff _p1;
_u = _p2 vectorDiff _p1; private _u = _p2 vectorDiff _p1;
_u = vectorNormalized _u; _u = vectorNormalized _u;
_d = sqrt((_u select 1)*(_u select 1) + (_u select 2)*(_u select 2)); private _d = sqrt((_u select 1)*(_u select 1) + (_u select 2)*(_u select 2));
/* Step 2 */ /* Step 2 */
if (_d != 0) then { if (_d != 0) then {
@ -27,4 +24,4 @@ _q1 set[0, (_q2 select 0) * _d - (_q2 select 2) * (_u select 0)];
_q1 set[1, (_q2 select 1)]; _q1 set[1, (_q2 select 1)];
_q1 set[2, (_q2 select 0) * (_u select 0) + (_q2 select 2) * _d]; _q1 set[2, (_q2 select 0) * (_u select 0) + (_q2 select 2) * _d];
[_p, _p1, _p2, _q1, _q2, _u, _d] [_p, _p1, _p2, _q1, _q2, _u, _d]

View File

@ -1,92 +1,116 @@
/* /*
* Author: Nou * Author: Nou
* Turn a laser designator on. * Searches for a laser spot given a seekers params.
* Provides the interface for Missile Guidance
* *
* Arguments: * Arguments:
* 0: Position of seeker (ASL) <position> * 0: Position of seeker (ASL) <ARRAY>
* 1: Direction vector (will be normalized) <vector> * 1: Direction vector (will be normalized) <ARRAY>
* 2: Seeker FOV in degrees <number> * 2: Seeker FOV in degrees <NUMBER>
* 3: Seeker wavelength sensitivity range, [1550,1550] is common eye safe. <array> * 3: Seeker wavelength sensitivity range, [1550,1550] is common eye safe. <ARRAY>
* 4: Seeker laser code. <number> * 4: Seeker laser code. <NUMBER>
* 5: Ignore 1 (e.g. Player's vehicle) <OPTIONAL><OBJECT>
* *
* Return Value: * Return Value:
* Array, [Strongest compatible laser spot ASL pos, owner object] Nil array values if nothing found. * Array, [Strongest compatible laser spot ASL pos, owner object] Nil array values if nothing found.
*
* Example:
* [getPosASL player, [0,1,0], 90, [1500, 1500], 1111, player] call ace_laser_fnc_seekerFindLaserSpot;
*
* Public: No
*/ */
// #define DEBUG_MODE_FULL
#include "script_component.hpp" #include "script_component.hpp"
private ["_pos", "_seekerWavelengths", "_seekerCode", "_spots", "_buckets", "_excludes", "_bucketIndex", "_finalPos", "_owner", "_obj", "_x", "_method"]; BEGIN_COUNTER(seekerFindLaserSpot);
private ["_emitterWavelength", "_laserCode", "_divergence", "_laser", "_res", "_bucketPos", "_bucketList", "_c", "_forEachIndex", "_index"];
private ["_testPos", "_finalBuckets", "_largest", "_largestIndex", "_finalBucket", "_owners", "_avgX", "_avgY", "_avgZ", "_count", "_maxOwner", "_maxOwnerIndex", "_finalOwner"];
private ["_dir", "_seekerCos", "_seekerFov", "_testDotProduct", "_testPoint", "_testPointVector"];
_pos = _this select 0; params ["_posASL", "_dir", "_seekerFov", "_seekerWavelengths", "_seekerCode", ["_ignoreObj1", objNull]];
_dir = vectorNormalized (_this select 1);
_seekerFov = _this select 2;
_seekerWavelengths = _this select 3;
_seekerCode = _this select 4;
_dir = vectorNormalized _dir;
_seekerWavelengths params ["_seekerWavelengthMin", "_seekerWavelengthMax"];
private _seekerCos = cos _seekerFov;
_seekerCos = cos _seekerFov; TRACE_5("",_posASL,_dir,_seekerFov,_seekerWavelengths,_seekerCode);
_spots = []; private _spots = [];
_buckets = []; private _finalPos = nil;
_excludes = []; private _finalOwner = objNull;
_bucketIndex = 0;
_finalPos = nil;
_finalOwner = nil;
// Go through all lasers in GVAR(laserEmitters)
{ {
_obj = _x select 0; _x params ["_obj", "_owner", "_laserMethod", "_emitterWavelength", "_laserCode", "_divergence"];
_owner = _x select 1; TRACE_6("laser",_obj,_owner,_laserMethod,_emitterWavelength,_laserCode,_divergence);
_method = _x select 2;
_emitterWavelength = _x select 3; if (alive _obj && {_emitterWavelength >= _seekerWavelengthMin} && {_emitterWavelength <= _seekerWavelengthMax} && {_laserCode == _seekerCode}) then {
_laserCode = _x select 4;
_divergence = _x select 5; private _laser = [];
if(alive _obj && {_emitterWavelength >= (_seekerWavelengths select 0)} && {_emitterWavelength <= (_seekerWavelengths select 1)} && {_laserCode == _seekerCode}) then { // Find laser pos and dir of the laser depending on type
_laser = []; if (IS_STRING(_laserMethod)) then {
if(IS_CODE(_method)) then { _laser = _x call (missionNamespace getVariable [_laserMethod, []]);
_laser = _x call _method;
} else { } else {
if(IS_STRING(_method)) then { if (IS_CODE(_laserMethod)) then {
_laser = _x call (missionNamespace getVariable [_method, {}]); _laser = _x call _laserMethod;
} else { } else {
if(IS_ARRAY(_method)) then {
if(count _method == 2) then { if (IS_ARRAY(_laserMethod)) then {
_laser = [ATLtoASL (_obj modelToWorldVisual (_method select 0)), _obj weaponDirection (_method select 1)]; if (count _laserMethod == 2) then { // [modelPosition, weaponName] for _obj
_laser = [AGLtoASL (_obj modelToWorldVisual (_laserMethod select 0)), _obj weaponDirection (_laserMethod select 1)];
} else { } else {
if(count _method == 3) then { if (count _laserMethod == 3) then {
_laser = [ATLtoASL (_obj modelToWorldVisual (_method select 0)), (ATLtoASL (_obj modelToWorldVisual (_method select 1))) vectorFromTo (ATLtoASL (_obj modelToWorldVisual (_method select 2)))]; _laser = [AGLtoASL (_obj modelToWorldVisual (_laserMethod select 0)), (AGLtoASL (_obj modelToWorldVisual (_laserMethod select 1))) vectorFromTo (AGLtoASL (_obj modelToWorldVisual (_laserMethod select 2)))];
}; };
}; };
}; };
}; };
}; };
//Handle Weird Data Return TRACE_1("",_laser);
if (_laser params [["_laserPos", [], [[]], 3], ["_laserDir", [], [[]], 3]]) then { //Handle Weird Data Return - skips over this laser in the for loop
_res = [_laserPos, _laserDir, _divergence] call FUNC(shootCone); if ((_laser isEqualTo []) || {_laser isEqualTo [-1, -1]}) exitWith {WARNING_1("Bad Laser Return",_laser);};
_laser params [["_laserPos", [], [[]], 3], ["_laserDir", [], [[]], 3]];
if (GVAR(dispersionCount) > 0) then {
// Shoot a cone with dispersion
([_laserPos, _laserDir, _divergence, GVAR(dispersionCount), _obj] call FUNC(shootCone)) params ["", "", "_resultPositions"];
{ {
_testPoint = _x select 0; _testPoint = _x select 0;
_testPointVector = vectorNormalized (_testPoint vectorDiff _pos); private _testPointVector = _posASL vectorFromTo _testPoint;
_testDotProduct = _dir vectorDotProduct _testPointVector; private _testDotProduct = _dir vectorDotProduct _testPointVector;
if(_testDotProduct > _seekerCos) then { if (_testDotProduct > _seekerCos) then {
_spots pushBack [_testPoint, _owner]; _spots pushBack [_testPoint, _owner];
}; };
} forEach (_res select 2); } forEach _resultPositions;
} else {
// Shoot a single perfect ray from source to target (note, increased chance to "miss" on weird objects like bushes / rocks)
([_laserPos, _laserDir, _obj] call FUNC(shootRay)) params ["_resultPos", "_distance"];
TRACE_2("spot",_resultPos,_distance);
if (_distance > 0) then {
private _testPointVector = _posASL vectorFromTo _resultPos;
private _testDotProduct = _dir vectorDotProduct _testPointVector;
if (_testDotProduct > _seekerCos) then {
_spots pushBack [_resultPos, _owner];
};
};
}; };
}; };
} forEach (GVAR(laserEmitters) select 2); } forEach (GVAR(laserEmitters) select 2); // Go through all values in hash
if((count _spots) > 0) then { TRACE_2("",count _spots, _spots);
_bucketPos = nil;
_bucketList = nil; if ((count _spots) > 0) then {
_c = 0; private _bucketList = nil;
private _bucketPos = nil;
private _c = 0;
private _buckets = [];
private _excludes = [];
private _bucketIndex = 0;
// Put close points together into buckets
while { count(_spots) != count(_excludes) && _c < (count _spots) } do { while { count(_spots) != count(_excludes) && _c < (count _spots) } do {
scopeName "mainSearch"; scopeName "mainSearch";
{ {
if(!(_forEachIndex in _excludes)) then { if (!(_forEachIndex in _excludes)) then {
_index = _buckets pushBack [_x, [_x]]; private _index = _buckets pushBack [_x, [_x]];
_excludes pushBack _forEachIndex; _excludes pushBack _forEachIndex;
_bucketPos = _x select 0; _bucketPos = _x select 0;
_bucketList = (_buckets select _index) select 1; _bucketList = (_buckets select _index) select 1;
@ -94,9 +118,9 @@ if((count _spots) > 0) then {
}; };
} forEach _spots; } forEach _spots;
{ {
if(!(_forEachIndex in _excludes)) then { if (!(_forEachIndex in _excludes)) then {
_testPos = (_x select 0); private _testPos = (_x select 0);
if(_testPos vectorDistanceSqr _bucketPos <= 100) then { if ((_testPos vectorDistanceSqr _bucketPos) <= 100) then {
_bucketList pushBack _x; _bucketList pushBack _x;
_excludes pushBack _forEachIndex; _excludes pushBack _forEachIndex;
}; };
@ -104,55 +128,71 @@ if((count _spots) > 0) then {
} forEach _spots; } forEach _spots;
_c = _c + 1; _c = _c + 1;
}; };
_finalBuckets = [];
_largest = -1; TRACE_1("",_buckets);
_largestIndex = 0;
private _finalBuckets = [];
private _largest = -1;
private _largestIndex = 0;
{ {
_index = _finalBuckets pushBack []; // find bucket with largest number of points we can see
private _index = _finalBuckets pushBack [];
_bucketList = _finalBuckets select _index; _bucketList = _finalBuckets select _index;
{ {
_testPos = (_x select 0); private _testPos = (_x select 0) vectorAdd [0,0,0.05];
if(!terrainIntersectASL [_pos, _testPos] && {!lineIntersects [_pos, _testPos]}) then { private _testIntersections = lineIntersectsSurfaces [_posASL, _testPos, _ignoreObj1];
if ([] isEqualTo _testIntersections) then {
_bucketList pushBack _x; _bucketList pushBack _x;
}; };
} forEach (_x select 1); } forEach (_x select 1);
if((count _bucketList) > _largest) then { if ((count _bucketList) > _largest) then {
_largest = (count _bucketList); _largest = (count _bucketList);
_largestIndex = _index; _largestIndex = _index;
}; };
} forEach _buckets; } forEach _buckets;
_finalBucket = _finalBuckets select _largestIndex; private _finalBucket = _finalBuckets select _largestIndex;
_owners = [] call CBA_fnc_hashCreate; private _ownersHash = [] call CBA_fnc_hashCreate;
if(count _finalBucket > 0) then { TRACE_2("",_finalBucket,_finalBuckets);
_avgX = 0;
_avgY = 0; if (count _finalBucket > 0) then {
_avgZ = 0; // merge all points in the best bucket into an average point and find effective owner
_finalPos = [0,0,0];
{ {
//player sideChat format["x: %1", _x]; _x params ["_xPos", "_owner"];
_avgX = _avgX + ((_x select 0) select 0); _finalPos = _finalPos vectorAdd _xPos;
_avgY = _avgY + ((_x select 0) select 1); if ([_ownersHash, _owner] call CBA_fnc_hashHasKey) then {
_avgZ = _avgZ + ((_x select 0) select 2); private _count = [_ownersHash, _owner] call CBA_fnc_hashGet;
_owner = _x select 1; [_ownersHash, _owner, _count + 1] call CBA_fnc_hashSet;
if ([_owners, _owner] call CBA_fnc_hashHasKey) then {
private _count = [_owners, _owner] call CBA_fnc_hashGet;
[_owners, _owner, _count + 1] call CBA_fnc_hashSet;
} else { } else {
[_owners, _owner, 1] call CBA_fnc_hashSet; [_ownersHash, _owner, 1] call CBA_fnc_hashSet;
}; };
} forEach _finalBucket; } forEach _finalBucket;
_count = count _finalBucket;
_finalPos = [_avgX/_count, _avgY/_count, _avgZ/_count]; _finalPos = _finalPos vectorMultiply (1 / (count _finalBucket));
_maxOwner = -1;
_maxOwnerIndex = 0; private _maxOwnerCount = -1;
{
if((_owners select 1) select _forEachIndex > _maxOwner) then { [_ownersHash, {
_maxOwner = (_owners select 1) select _forEachIndex; if (_value > _maxOwnerCount) then {
_maxOwnerIndex = _forEachIndex; _finalOwner = _key;
}; };
} forEach (_owners select 0); }] call CBA_fnc_hashEachPair;
_finalOwner = (_owners select 0) select _maxOwnerIndex;
}; };
}; };
[_finalPos, _owner];
END_COUNTER(seekerFindLaserSpot);
#ifdef DRAW_LASER_INFO
if (isNil "_finalPos") then {
drawIcon3D ["\A3\ui_f\data\map\vehicleicons\iconMan_ca.paa", [0.9,1,0,1], (ASLtoAGL _posASL), 1, 1, 0, format ["Seeker: %1", _code], 0.5, 0.025, "TahomaB"];
} else {
drawIcon3D ["\A3\ui_f\data\map\vehicleicons\iconManAT_ca.paa", [0.5,1,0,1], (ASLtoAGL _posASL), 1, 1, 0, format ["Seeker: %1", _code], 0.5, 0.025, "TahomaB"];
drawLine3D [ASLtoAGL _posASL, ASLtoAGL _finalPos, [0.5,1,0,1]];
};
#endif
TRACE_2("return",_finalPos,_finalOwner);
if (isNil "_finalPos") exitWith {[nil, _finalOwner]};
[_finalPos, _finalOwner];

View File

@ -1,68 +1,71 @@
#include "script_component.hpp" /*
* Author: Nou
* Shoots multiple rays in a dispersion pattern
*
* Arguments:
* 0: Origin position ASL <ARRAY>
* 1: Direction (normalized) <ARRAY>
* 2: Divergence (mils) <OPTIONAL><NUMBER>
* 3: Count at each divergence level <OPTIONAL><NUMBER>
* 4: Ignore vehicle 1 (e.g. Player's vehicle) <OPTIONAL><OBJECT>
*
* Return value:
* <ARRAY> [_longestReturn, _shortestReturn, _resultPositions]
*
* Example:
* [getPosASL player, [0,1,0]] call ace_laser_fnc_shootCone;
*
* Public: No
*/
//#define DEBUG_MODE_FULL //#define DEBUG_MODE_FULL
private ["_i", "_divergence","_pos","_vec","_longestReturn","_shortestReturn","_resultPositions","_p1","_p2","_p","_v","_cp","_vecRotateMap","_result", "_resultPos","_distance","_count","_pos2","_radOffset","_offset","_offsetPos","_offsetVector"]; #include "script_component.hpp"
_divergence = 0.3;
_pos = _this select 0;
_vec = _this select 1;
if(count _this > 2) then {
_divergence = _this select 2;
};
_count = 3;
if(count _this > 3) then {
_count = _this select 3;
};
_longestReturn = -1000000000;
_shortestReturn = 1000000000;
_resultPositions = [];
_p1 = [0,0,0];
_p2 = +_vec;
_p = (_vec call CBA_fnc_vect2polar);
_v = [(_p select 0), (_p select 1), (_p select 2)+90] call CBA_fnc_polar2vect;
_cp = _vec vectorCrossProduct _v;
_vecRotateMap = [_cp, _p1, _p2] call FUNC(rotateVectLineGetMap); BEGIN_COUNTER(shootCone);
_result = [_pos, _vec] call FUNC(shootRay); params ["_pos", "_vec", ["_divergence", 0.3], ["_count", 3], ["_ignoreObj1", objNull]];
_resultPos = _result select 0;
if(!isNil "_resultPos") then { private _longestReturn = -1000000000;
_distance = _result select 1; private _shortestReturn = 1000000000;
if(_distance < _shortestReturn) then { private _resultPositions = [];
_shortestReturn = _distance; private _p1 = [0,0,0];
}; private _p2 = +_vec;
if(_distance > _longestReturn) then { private _p = (_vec call CBA_fnc_vect2polar);
_longestReturn = _distance; private _v = [(_p select 0), (_p select 1), (_p select 2)+90] call CBA_fnc_polar2vect;
}; private _cp = _vec vectorCrossProduct _v;
private _vecRotateMap = [_cp, _p1, _p2] call FUNC(rotateVectLineGetMap);
// Check first with a perfect ray to the center
private _result = [_pos, _vec, _ignoreObj1] call FUNC(shootRay);
private _resultPos = _result select 0;
if (!isNil "_resultPos") then {
private _distance = _result select 1;
if (_distance < _shortestReturn) then { _shortestReturn = _distance; };
if (_distance > _longestReturn) then { _longestReturn = _distance; };
_resultPositions pushBack _result; _resultPositions pushBack _result;
#ifdef DEBUG_MODE_FULL
// DRAW_LINES set[(count DRAW_LINES), [_pos, _resultPos, [0, 1, 0, 1]]];
drawLine3D [ASLtoATL _pos, ASLtoATL _resultPos, [1,0,0,1]];
#endif
}; };
private _pos2 = _pos vectorAdd (_vec vectorMultiply 1000);
_pos2 = _pos vectorAdd (_vec vectorMultiply 1000); // Try at 3 radius (full, half, quarter of specified divergence)
{ {
for "_i" from 0 to ceil(_count*_x) do { private _radOffset = random 360;
_radOffset = random 360; for "_i" from 1 to ceil(_count*_x) do { // Will always do at least 1
_offset = [_vecRotateMap, (((360/_count)*_i)+_radOffset) mod 360] call FUNC(rotateVectLine); private _offset = [_vecRotateMap, (((360/_count)*_i)+_radOffset) mod 360] call FUNC(rotateVectLine);
_offsetPos = _pos2 vectorAdd (_offset vectorMultiply (_divergence*_x)); private _offsetPos = _pos2 vectorAdd (_offset vectorMultiply (_divergence*_x));
_offsetVector = _pos vectorFromTo _offsetPos;
_result = [_pos, _offsetVector] call FUNC(shootRay); private _offsetVector = _pos vectorFromTo _offsetPos;
_result = [_pos, _offsetVector, _ignoreObj1] call FUNC(shootRay);
_resultPos = _result select 0; _resultPos = _result select 0;
if(!isNil "_resultPos") then { if (!isNil "_resultPos") then {
_distance = _result select 1; private _distance = _result select 1;
if(_distance < _shortestReturn) then { if (_distance < _shortestReturn) then { _shortestReturn = _distance; };
_shortestReturn = _distance; if (_distance > _longestReturn) then { _longestReturn = _distance; };
};
if(_distance > _longestReturn) then {
_longestReturn = _distance;
};
_resultPositions pushBack _result; _resultPositions pushBack _result;
#ifdef DEBUG_MODE_FULL
// DRAW_LINES set[(count DRAW_LINES), [_pos, _resultPos, [0, 1, 0, 1]]];
drawLine3D [ASLtoATL _pos, ASLtoATL _resultPos, [1,0,0,1]];
#endif
}; };
}; };
} forEach [1,0.5,0.25]; } forEach [1,0.5,0.25];
[_longestReturn, _shortestReturn, _resultPositions];
END_COUNTER(shootCone);
[_longestReturn, _shortestReturn, _resultPositions];

View File

@ -1,24 +1,50 @@
/*
* Author: Nou, PabstMirror
* Shoots a ray from a source to a direction and finds first intersction and distance
*
* Arguments:
* 0: Origin position ASL <ARRAY>
* 1: Direction (normalized) <ARRAY>
* 2: Ignore 1 (e.g. Player's vehicle) <OPTIONAL><OBJECT>
* 2: Ignore 2 (e.g. Player's vehicle) <OPTIONAL><OBJECT>
*
* Return value:
* <ARRAY> [posASL, distance] - pos will be nil if no intersection
*
* Example:
* [getPosASL player, [0,1,0], player] call ace_laser_fnc_shootRay;
*
* Public: No
*/
#include "script_component.hpp" #include "script_component.hpp"
private ["_pos", "_vec", "_distance", "_resultPos", "_fidelity", "_lastPos", "_i", "_nextPos"]; BEGIN_COUNTER(shootRay);
scopeName "main";
_pos = _this select 0; params ["_posASL", "_dir", ["_ignoreVehicle1", objNull], ["_ignoreVehicle2", objNull]];
_vec = _this select 1; // TRACE_2("ray origin:", _posASL, _dir);
_distance = 0;
_resultPos = nil; private _distance = 0;
_fidelity = [1000,100,10,1,0.1]; private _resultPos = nil;
_lastPos = +_pos;
{ private _farPoint = _posASL vectorAdd (_dir vectorMultiply 10000);
scopeName "mainSearch"; private _intersects = lineIntersectsSurfaces [_posASL, _farPoint, _ignoreVehicle1, _ignoreVehicle2];
for "_i" from 1 to 10 do {
_nextPos = _lastPos vectorAdd (_vec vectorMultiply _x); if (!(_intersects isEqualTo [])) then {
if(terrainIntersectASL [_lastPos, _nextPos] || {lineIntersects [_lastPos, _nextPos]}) then { (_intersects select 0) params ["_intersectPosASL", "", "_intersectObject"];
_resultPos = _lastPos; // Move back slightly to prevents issues with it going below terrain
breakTo "mainSearch"; _distance = (_posASL vectorDistance _intersectPosASL) - 0.005;
} else { _resultPos = _posASL vectorAdd (_dir vectorMultiply _distance);
_distance = _distance + _x; };
_lastPos = _nextPos;
}; TRACE_3("", _resultPos, _distance, _intersects);
};
} forEach _fidelity; #ifdef DRAW_LASER_INFO
[_resultPos, _distance]; if !(isNil "_resultPos") then {
private _text = [_distance, 4, 0] call CBA_fnc_formatNumber;
drawIcon3D ["\a3\ui_f\data\IGUI\Cfg\Cursors\selectover_ca.paa", [0, 1, 0, 1], ASLtoAGL _resultPos, 0.5, 0.5, 0, _text, 0.4, 0.025, "TahomaB"];
drawLine3D [ASLtoAGL _posASL, ASLtoAGL _resultPos, [0,1,0,1]];
};
#endif
END_COUNTER(shootRay);
[_resultPos, _distance];

View File

@ -1,21 +0,0 @@
/*
* Author: jaynus
* Checks if the turret occupied by the given unit can lock a laser designator and select laser code.
*
* Arguments:
* 0: Unit <OBJECT>
*
* Return Value:
* Has designator? <BOOL>
*/
#include "script_component.hpp"
EXPLODE_1_PVT(_this,_unit);
// Get the player turret path
private ["_turret","_config","_turretConfig"];
_turret = [_unit] call EFUNC(common,getTurretIndex);
_config = configFile >> "CfgVehicles" >> typeOf vehicle _unit;
_turretConfig = [_config, _turret] call EFUNC(common,getTurretConfigPath);
getNumber (_turretConfig >> QGVAR(CanLockLaser)) > 0

View File

@ -1,26 +0,0 @@
/*
* Author: jaynus
* Handler function for laser network code.
*
* Arguments:
* 0: Emitter
* 1: Owner
*
* Return Value:
* [position, direction]
*/
//#define DEBUG_MODE_FULL
#include "script_component.hpp"
private ["_emmiter", "_owner", "_gunnerInfo", "_turretInfo", "_povPos", "_povDir"];
_emmiter = _this select 0;
_owner = _this select 1;
// Not in a vehicle....
// @TODO: handle lasering from turrets
if( (vehicle _emmiter) == _emmiter && alive _emmiter && (currentWeapon _emmiter) == "LaserDesignator") exitWith {
[(eyePos _emmiter), (eyeDirection _emmiter)]
};
[-1,-1]

View File

@ -1,27 +1,16 @@
["ACE3 Equipment", QGVAR(LaserCodeUp), localize LSTRING(laserCodeUp), ["ACE3 Equipment", QGVAR(LaserCodeUp), localize LSTRING(laserCodeUp),
{ {
if( EGVAR(laser_selfdesignate,active) [1] call FUNC(keyLaserCodeChange);
||
{ (currentWeapon ACE_player) == "Laserdesignator" && (call CBA_fnc_getFoV) select 1 > 5 } // If laserdesignator & FOV, we are in scope.
||
{ [ACE_player] call FUNC(unitTurretCanLockLaser) }
) then {
[] call FUNC(keyLaserCodeUp);
};
}, },
{false}, {false},
[16, [false, true, true]], false, 0] call CBA_fnc_addKeybind; // (ALT+CTRL+Q) [16, [false, true, true]], false, 0] call CBA_fnc_addKeybind; // (ALT+CTRL+Q)
["ACE3 Equipment", QGVAR(LaserCodeDown), localize LSTRING(laserCodeDown), ["ACE3 Equipment", QGVAR(LaserCodeDown), localize LSTRING(laserCodeDown),
{ {
if( EGVAR(laser_selfdesignate,active)
|| [-1] call FUNC(keyLaserCodeChange);
{ (currentWeapon ACE_player) == "Laserdesignator" && (call CBA_fnc_getFoV) select 1 > 5 } // If laserdesignator & FOV, we are in scope.
||
{ [ACE_player] call FUNC(unitTurretCanLockLaser) }
) then {
[] call FUNC(keyLaserCodeDown);
};
}, },
{false}, {false},
[18, [false, true, true]], false, 0] call CBA_fnc_addKeybind; // (ALT+CTRL+E) [18, [false, true, true]], false, 0] call CBA_fnc_addKeybind; // (ALT+CTRL+E)

View File

@ -2,6 +2,7 @@
#define COMPONENT_BEAUTIFIED Laser #define COMPONENT_BEAUTIFIED Laser
#include "\z\ace\addons\main\script_mod.hpp" #include "\z\ace\addons\main\script_mod.hpp"
// #define DRAW_LASER_INFO
// #define DEBUG_MODE_FULL // #define DEBUG_MODE_FULL
// #define DISABLE_COMPILE_CACHE // #define DISABLE_COMPILE_CACHE
// #define ENABLE_PERFORMANCE_COUNTERS // #define ENABLE_PERFORMANCE_COUNTERS
@ -17,9 +18,6 @@
#include "\z\ace\addons\main\script_macros.hpp" #include "\z\ace\addons\main\script_macros.hpp"
#define FIREMODE_DIRECT_LOAL 1
#define __LaserDesignatorIGUI (uiNamespace getVariable ["ACE_RscOptics_LaserDesignator", nil]) #define __LaserDesignatorIGUI (uiNamespace getVariable ["ACE_RscOptics_LaserDesignator", nil])
#define __LaserDesignatorIGUI_LaserCode (__LaserDesignatorIGUI displayCtrl 123001) #define __LaserDesignatorIGUI_LaserCode (__LaserDesignatorIGUI displayCtrl 123001)
#define __LaserDesignatorIGUI_ACE_Distance (__LaserDesignatorIGUI displayCtrl 123002) #define __LaserDesignatorIGUI_ACE_Distance (__LaserDesignatorIGUI displayCtrl 123002)

View File

@ -1,6 +1,9 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<Project name="ACE"> <Project name="ACE">
<Package name="Laser"> <Package name="Laser">
<Key ID="STR_ACE_Laser_dispersionCount_displayName">
<English>Laser Dispersion Simulation Count</English>
</Key>
<Key ID="STR_ACE_Laser_laserCode"> <Key ID="STR_ACE_Laser_laserCode">
<English>Laser Code</English> <English>Laser Code</English>
<German>Lasercode</German> <German>Lasercode</German>

View File

@ -1 +0,0 @@
z\ace\addons\laser_selfdesignate

View File

@ -1,26 +0,0 @@
class Extended_PreStart_EventHandlers {
class ADDON {
init = QUOTE(call COMPILE_FILE(XEH_preStart));
};
};
class Extended_PreInit_EventHandlers {
class ADDON {
init = QUOTE(call COMPILE_FILE(XEH_pre_init));
};
};
class Extended_PostInit_EventHandlers {
class ADDON {
init = QUOTE(call COMPILE_FILE(XEH_post_init));
};
};
class Extended_Init_EventHandlers {
class Helicopter {
class ADDON {
init = QUOTE(_this call DFUNC(initDesignatorActions));
};
};
};

View File

@ -1,49 +0,0 @@
class CfgVehicles {
class AllVehicles;
class Air: AllVehicles {
class Turrets;
};
class Helicopter: Air {
class Turrets {
class MainTurret;
};
};
class Helicopter_Base_F: Helicopter {};
class Heli_Attack_01_base_F: Helicopter_Base_F {};
class B_Heli_Attack_01_F: Heli_Attack_01_base_F {
class Turrets: Turrets {
class MainTurret: MainTurret {
GVAR(Enabled) = 0; // Enable laser self-designation
};
};
};
class Plane: Air {};
class Plane_Base_F: Plane {
class Turrets {
class CopilotTurret;
};
};
/* @TODO: LGB GBU
class Plane_CAS_01_base_F: Plane_Base_F {
class Turrets: Turrets {
class MainTurret: MainTurret {
GVAR(Enabled) = 1; // Enable laser self-designation
};
};
};
class Plane_CAS_02_base_F: Plane_Base_F {
class Turrets: Turrets {
class MainTurret: MainTurret {
GVAR(Enabled) = 1; // Enable laser self-designation
};
};
};
*/
};

View File

@ -1,11 +0,0 @@
class CfgWeapons {
// Disable locking unless newb mode
class LauncherCore;
class RocketPods: LauncherCore {
// canLock = 1;
};
class missiles_DAGR: RocketPods {
//canLock = 1;
};
};

View File

@ -1,12 +0,0 @@
ace_laser_selfdesignate
=======================
Allows gunners to lase their own targets.
## Maintainers
The people responsible for merging changes to this component or answering potential questions.
- [walterpearce](https://github.com/walterpearce)
- [NouberNou](https://github.com/NouberNou)

View File

@ -1,7 +0,0 @@
PREP(initDesignatorActions);
PREP(laserHudDesignateOn);
PREP(laserHudDesignateOff);
PREP(unitTurretHasDesignator);
PREP(findLaserSource);

View File

@ -1,2 +0,0 @@
#include "script_component.hpp"

View File

@ -1,3 +0,0 @@
#include "script_component.hpp"
#include "XEH_PREP.hpp"

View File

@ -1,11 +0,0 @@
#include "script_component.hpp"
ADDON = false;
#include "XEH_PREP.hpp"
GVAR(active) = false;
FUNC(getPosASL) = {visiblePositionASL (_this select 0)};
ADDON = true;

View File

@ -1,18 +0,0 @@
#include "script_component.hpp"
class CfgPatches {
class ADDON {
name = COMPONENT_NAME;
units[] = {};
weapons[] = {};
requiredVersion = REQUIRED_VERSION;
requiredAddons[] = {"ace_laser"};
author = ECSTRING(common,ACETeam);
url = ECSTRING(main,URL);
VERSION_CONFIG;
};
};
#include "CfgEventhandlers.hpp"
#include "CfgWeapons.hpp"
#include "CfgVehicles.hpp"

View File

@ -1,23 +0,0 @@
/*
* Author: jaynus
* Handler function for laser network code.
*
* Arguments:
* 0: Emitter <OBJECT>
*
* Return Value:
* 0: position <ARRAY>
* 1: direction <ARRAY>
*
* Public: No
*/
#include "script_component.hpp"
private ["_gunnerInfo", "_turretInfo"];
params ["_emmiter"];
_gunnerInfo = [_emmiter, (currentWeapon _emmiter)] call CBA_fnc_getFirer;
_turretInfo = [_emmiter, _gunnerInfo select 1] call EFUNC(common,getTurretDirection);
_turretInfo params [["_povPos", -1], ["_povDir", -1]];
[_povPos, _povDir]

View File

@ -1,59 +0,0 @@
/*
* Author: esteldunedain
* Initializes the actions for turning on/off the laser for vehicles that have them
*
* Arguments:
* 0: Vehicle <OBJECT>
*
* Return Value:
* None
*
* Public: No
*/
#include "script_component.hpp"
params ["_vehicle"];
// Add action to class if it is not already done
private ["_type", "_initializedClasses"];
_type = typeOf _vehicle;
_initializedClasses = GETGVAR(initializedClasses,[]);
// do nothing if the class is already initialized
if (_type in _initializedClasses) exitWith {};
_initializedClasses pushBack _type;
GVAR(initializedClasses) = _initializedClasses;
{
private ["_turretConfig","_onAction","_offAction"];
_turretConfig = [configFile >> "CfgVehicles" >> _type, _x] call EFUNC(common,getTurretConfigPath);
if (getNumber (_turretConfig >> QGVAR(Enabled)) == 1) exitWith {
// @todo: Add the state variables to the vehicle, instead of to the client
// e.g.: _vehicle setVariable [format ["%1_%2", QGVAR(active), _x], false];
// Add actions
_onAction = [QGVAR(LaserOn), localize LSTRING(DesignatorOn), "",
{
// Statement
_this call FUNC(laserHudDesignateOn)
},
{
// Condition
!GVAR(active) && {[ACE_player] call FUNC(unitTurretHasDesignator)}
}] call EFUNC(interact_menu,createAction);
_offAction = [QGVAR(LaserOff), localize LSTRING(DesignatorOff), "",
{
// Statement
_this call FUNC(laserHudDesignateOff)
},
{
// Condition
GVAR(active) && {[ACE_player] call FUNC(unitTurretHasDesignator)}
}] call EFUNC(interact_menu,createAction);
[_type, 1, ["ACE_SelfActions"], _onAction] call EFUNC(interact_menu,addActionToClass);
[_type, 1, ["ACE_SelfActions"], _offAction] call EFUNC(interact_menu,addActionToClass);
};
} forEach allTurrets _vehicle;

View File

@ -1,29 +0,0 @@
/*
* Author: jaynus
* Turns off passed laser self designation.
*
* Arguments:
* 0: Shooter, player shooting the laser
* 1: LaserUUID, the UUID of the laser returned by EFUNC(laser,laserOn)
* 2: Local laser target, unused.
*
* Return Value:
* True <BOOL>
*/
#include "script_component.hpp"
if( (count _this) > 2) then {
params ["", "_laserUuid"];
[_laserUuid] call EFUNC(laser,laserOff);
// @TODO: Nou gets to field all tickets about missing lasers.
//deleteVehicle _localLaserTarget;
};
GVAR(active) = false;
if(!isNil QGVAR(selfDesignateHandle)) then {
[GVAR(selfDesignateHandle)] call CBA_fnc_removePerFrameHandler;
GVAR(selfDesignateHandle) = nil;
};
true

View File

@ -1,90 +0,0 @@
/*
* Author: jaynus
* Turns on laser self designation from this vehicle based on the turret.
* There are no arguments, because it is all strictly based on the users vehicle.
*
* Arguments:
* None
*
* Return Value:
* None
*
* Public: No
*/
#include "script_component.hpp"
TRACE_1("enter", _this);
#define FCS_UPDATE_DELAY 1
FUNC(laserHudDesignatePFH) = {
private ["_strongestResultPos", "_args", "_localLaserTarget", "_laserResultPosition", "_laserResult", "_shooter", "_vehicle", "_weapon", "_gunnerInfo", "_turretInfo", "_pov", "_gunBeg", "_gunEnd", "_povPos", "_povDir", "_result", "_resultPositions", "_firstResult", "_forceUpdateTime"];
params ["_args"];
_args params ["_shooter", "_localLaserTarget"];
_vehicle = vehicle _shooter;
TRACE_1("", _args);
if((vehicle _shooter) == _shooter || {!alive _shooter} || {isNull _vehicle} || {!GVAR(active)} ) exitWith {
_args call FUNC(laserHudDesignateOff);
};
if(!([_shooter] call FUNC(unitTurretHasDesignator)) ) exitWith {
_args call FUNC(laserHudDesignateOff);
};
if( (count _args) < 4) then {
_args set[3, diag_tickTime + FCS_UPDATE_DELAY];
};
_forceUpdateTime = _args select 3;
// @TODO: We don't have anything here we need to do the calculations for right now
/*
_gunnerInfo = [_vehicle, (currentWeapon _vehicle)] call CBA_fnc_getFirer;
_turretInfo = [_vehicle, _gunnerInfo select 1] call EFUNC(common,getTurretDirection);
_povPos = _turretInfo select 0;
_laserCode = (vehicle ACE_player) getVariable["ace_laser_code", ACE_DEFAULT_LASER_CODE];
_waveLength = (vehicle ACE_player) getVariable["ace_laser_waveLength", ACE_DEFAULT_LASER_WAVELENGTH];
_laserResult = [_povPos, [_waveLength,_waveLength], _laserCode] call EFUNC(laser,seekerFindLaserSpot);
_laserResultPosition = _laserResult select 0;
TRACE_1("Search", _laserResult);
if((count _laserResult) > 0) then {
// @TODO: Nou gets to field all tickets about missing lasers.
//_localLaserTarget setPosASL _laserResultPosition;
};
*/
if(diag_tickTime > _forceUpdateTime) then {
["ace_fcs_forceUpdate", []] call ace_common_fnc_localEvent;
_args set[3, diag_tickTime + FCS_UPDATE_DELAY];
};
_this set[0, _args];
};
private ["_laserTarget", "_handle", "_vehicle", "_laserUuid", "_waveLength", "_beamSpread", "_laserCode"];
if(!GVAR(active)) then {
GVAR(active) = true;
TRACE_1("Activating laser", "");
// Get the self-designation variables, or use defaults
_laserCode = (vehicle ACE_player) getVariable["ace_laser_code", ACE_DEFAULT_LASER_CODE];
_waveLength = (vehicle ACE_player) getVariable["ace_laser_waveLength", ACE_DEFAULT_LASER_WAVELENGTH];
_beamSpread = (vehicle ACE_player) getVariable["ace_laser_beamSpread", ACE_DEFAULT_LASER_BEAMSPREAD];
_laserUuid = [(vehicle ACE_player), ACE_player, QFUNC(findLaserSource), _waveLength, _laserCode, _beamSpread] call EFUNC(laser,laserOn);
// @TODO: Create the local target for the players side
// @TODO: Nou gets to field all tickets about missing lasers.
//_localLaserTarget = "LaserTargetW" createVehicleLocal (getpos ACE_player);
GVAR(selfDesignateHandle) = [FUNC(laserHudDesignatePFH), 0.1, [ACE_player, _laserUuid, nil]] call CBA_fnc_addPerFrameHandler;
} else {
[] call FUNC(laserHudDesignateOff);
[] call FUNC(laserHudDesignateOn);
};

View File

@ -1,23 +0,0 @@
/*
* Author: esteldunedain
* Checks if the turret occupied by the given unit has a laser designator
*
* Arguments:
* 0: Unit <OBJECT>
*
* Return Value:
* Has unit designator <BOOL>
*
* Public: No
*/
#include "script_component.hpp"
params ["_unit"];
// Get the player turret path
private ["_turret","_config","_turretConfig"];
_turret = [_unit] call EFUNC(common,getTurretIndex);
_config = configFile >> "CfgVehicles" >> typeOf vehicle _unit;
_turretConfig = [_config, _turret] call EFUNC(common,getTurretConfigPath);
getNumber (_turretConfig >> QGVAR(Enabled)) > 0

View File

@ -1 +0,0 @@
#include "\z\ace\addons\laser_selfdesignate\script_component.hpp"

View File

@ -1,17 +0,0 @@
#define COMPONENT laser_selfdesignate
#define COMPONENT_BEAUTIFIED Laser Selfdesignate
#include "\z\ace\addons\main\script_mod.hpp"
// #define DEBUG_MODE_FULL
// #define DISABLE_COMPILE_CACHE
// #define ENABLE_PERFORMANCE_COUNTERS
#ifdef DEBUG_ENABLED_LASER_SELFDESIGNATE
#define DEBUG_MODE_FULL
#endif
#ifdef DEBUG_SETTINGS_LASER_SELFDESIGNATE
#define DEBUG_SETTINGS DEBUG_SETTINGS_LASER_SELFDESIGNATE
#endif
#include "\z\ace\addons\main\script_macros.hpp"

View File

@ -1,31 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project name="ACE">
<Package name="Laser_SelfDesignate">
<Key ID="STR_ACE_Laser_SelfDesignate_DesignatorOn">
<English>Laser Designator On</English>
<German>Lasermarkierer an</German>
<Spanish>Designador láser encendido</Spanish>
<Russian>ЛЦУ ВКЛ</Russian>
<Czech>Laserový značkovač zapnut</Czech>
<Polish>Desygnator laserowy wł.</Polish>
<French>Désignateur laser allumé</French>
<Hungarian>Lézeres Megjelölő Be</Hungarian>
<Italian>Designatore laser acceso</Italian>
<Portuguese>Designador Laser Ligado</Portuguese>
<Japanese>レーザー指示を起動</Japanese>
</Key>
<Key ID="STR_ACE_Laser_SelfDesignate_DesignatorOff">
<English>Laser Designator Off</English>
<German>Lasermarkierer aus</German>
<Spanish>Designador láser apagado</Spanish>
<Russian>ЛЦУ ВЫКЛ</Russian>
<Czech>Laserový značkovat vypnut</Czech>
<Polish>Desygnator laserowy wył.</Polish>
<French>Désignateur laser éteint</French>
<Hungarian>Lézeres Megjelölő Ki</Hungarian>
<Italian>Designatore laser spento</Italian>
<Portuguese>Designador Laser Desligado</Portuguese>
<Japanese>レーザー指示を停止</Japanese>
</Key>
</Package>
</Project>

View File

@ -1,44 +1,7 @@
enum {
ACE_LOBL = 1,
ACE_LOAL = 2
};
class CfgAmmo { class CfgAmmo {
class MissileBase; class MissileBase;
class M_PG_AT: MissileBase { class M_PG_AT: MissileBase {};
model = "\A3\Weapons_F\Ammo\Rocket_01_fly_F";
proxyShape = "\A3\Weapons_F\Ammo\Rocket_01_F";
// Reenable this settings when ACE laser targeting and missile guidance is reenabled
//laserLock = 1;
//airLock = 0;
//irLock = 0;
//weaponLockSystem = "4 + 16";
//fuseDistance = 2;
//timeToLive = 60;
// Turn off arma crosshair-guidance
//manualControl = 0;
// ACE uses these values
//trackOversteer = 1;
//trackLead = 0;
maxSpeed = 720;
maxControlRange = 5000;
maneuvrability = 8;
simulationStep = 0.01;
airFriction = 0.1;
sideAirFriction = 0.16;
initTime = 0.002;
thrustTime = 1.07;
thrust = 530;
effectsMissileInit = "MissileDAR1";
effectsMissile = "missile2";
whistleDist = 4;
muzzleEffect = "";
};
class ACE_Hydra70_DAGR: M_PG_AT { class ACE_Hydra70_DAGR: M_PG_AT {
displayName = CSTRING(Hydra70_DAGR); displayName = CSTRING(Hydra70_DAGR);
@ -47,13 +10,18 @@ class CfgAmmo {
description = CSTRING(Hydra70_DAGR_Desc); description = CSTRING(Hydra70_DAGR_Desc);
descriptionShort = CSTRING(Hydra70_DAGR_Desc); descriptionShort = CSTRING(Hydra70_DAGR_Desc);
irLock = 0;
laserLock = 0;
manualControl = 0;
maxSpeed = 300;
EGVAR(rearm,caliber) = 70; EGVAR(rearm,caliber) = 70;
class ADDON { class ADDON {
enabled = 1; enabled = 1;
minDeflection = 0.00025; // Minium flap deflection for guidance minDeflection = 0.0005; // Minium flap deflection for guidance
maxDeflection = 0.001; // Maximum flap deflection for guidance maxDeflection = 0.0025; // Maximum flap deflection for guidance
incDeflection = 0.0005; // The incrmeent in which deflection adjusts. incDeflection = 0.0005; // The incrmeent in which deflection adjusts.
canVanillaLock = 0; // Can this default vanilla lock? Only applicable to non-cadet mode canVanillaLock = 0; // Can this default vanilla lock? Only applicable to non-cadet mode

View File

@ -1,24 +1,20 @@
class CfgVehicles { class CfgVehicles {
class Air;
class AllVehicles; class Helicopter: Air {
class Air: AllVehicles {
class Turrets; class Turrets;
}; };
class Helicopter_Base_F: Helicopter {
class Helicopter: Air {
class Turrets {
class MainTurret;
};
};
class Helicopter_Base_F: Helicopter {};
class Heli_Attack_01_base_F: Helicopter_Base_F {};
class B_Heli_Attack_01_F : Heli_Attack_01_base_F {
class Turrets: Turrets { class Turrets: Turrets {
class MainTurret; class MainTurret;
}; };
}; };
class Heli_Attack_01_base_F: Helicopter_Base_F {
class ACE_Comanche_Test : B_Heli_Attack_01_F { class Turrets: Turrets {
class MainTurret: MainTurret {};
};
};
class B_Heli_Attack_01_F: Heli_Attack_01_base_F {};
class ACE_Comanche_Test : B_Heli_Attack_01_F { // Comanche testbed (Hidden: Scope=1)
scope = 1; scope = 1;
scopeCurator = 0; scopeCurator = 0;
displayName = "ACE_Comanche_Test"; displayName = "ACE_Comanche_Test";
@ -28,9 +24,9 @@ class CfgVehicles {
}; };
class Turrets: Turrets { class Turrets: Turrets {
class MainTurret: MainTurret { class MainTurret: MainTurret {
magazines[] = {"ACE_500Rnd_20mm_shells_Comanche", "24Rnd_ACE_Hellfire_AGM114K"}; weapons[] = {"gatling_20mm", "ace_missileguidance_dagr", "Laserdesignator_mounted"};
magazines[] = {"ACE_500Rnd_20mm_shells_Comanche", "6Rnd_ACE_Hydra70_DAGR", "Laserbatteries"};
}; };
}; };
}; };
}; };

View File

@ -1,12 +1,10 @@
class Mode_SemiAuto;
class CfgWeapons { class CfgWeapons {
class CannonCore; class missiles_DAGR;
class LauncherCore;
class RocketPods: LauncherCore { class GVAR(dagr): missiles_DAGR {
// canLock = 1; canLock = 0;
}; magazines[] = {"6Rnd_ACE_Hydra70_DAGR","12Rnd_ACE_Hydra70_DAGR","24Rnd_ACE_Hydra70_DAGR"};
class missiles_DAGR : RocketPods { lockingTargetSound[] = {"",0,1};
canLock = 2; lockedTargetSound[] = {"",0,1};
}; };
}; };

View File

@ -7,9 +7,9 @@
#define STAGE_TERMINAL 4 #define STAGE_TERMINAL 4
EXPLODE_7_PVT(((_this select 1) select 0),_shooter,_weapon,_muzzle,_mode,_ammo,_magazine,_projectile); EXPLODE_7_PVT(((_this select 1) select 0),_shooter,_weapon,_muzzle,_mode,_ammo,_magazine,_projectile);
private ["_targetPos", "_projectilePos", "_target", "_seekerTargetPos", "_launchParams", "_targetLaunchParams"]; private["_targetPos", "_projectilePos", "_target", "_seekerTargetPos", "_launchParams", "_targetLaunchParams"];
private ["_distanceToTarget", "_distanceToShooter", "_addHeight", "_returnTargetPos", "_state"]; private["_distanceToTarget", "_distanceToShooter", "_addHeight", "_returnTargetPos", "_state"];
private ["_cruisAlt", "_distanceShooterToTarget", "_shooterPos"]; private["_cruisAlt", "_distanceShooterToTarget", "_shooterPos"];
_seekerTargetPos = _this select 0; _seekerTargetPos = _this select 0;
_launchParams = _this select 1; _launchParams = _this select 1;
@ -37,19 +37,19 @@ switch( (_state select 0) ) do {
case STAGE_LAUNCH: { case STAGE_LAUNCH: {
TRACE_1("STAGE_LAUNCH",""); TRACE_1("STAGE_LAUNCH","");
if(_distanceToShooter < 10) then { if(_distanceToShooter < 10) then {
_returnTargetPos = _seekerTargetPos vectorAdd [0,0,_distanceToTarget * 2]; _returnTargetPos = _seekerTargetPos vectorAdd [0,0,_distanceToTarget*2];
} else { } else {
_state set [0, STAGE_CLIMB]; _state set[0, STAGE_CLIMB];
}; };
}; };
case STAGE_CLIMB: { case STAGE_CLIMB: {
TRACE_1("STAGE_CLIMB",""); TRACE_1("STAGE_CLIMB","");
_cruisAlt = 60 * (_distanceShooterToTarget/2000); _cruisAlt = 60 * (_distanceShooterToTarget/2000);
if( ((ASLToATL _projectilePos) select 2) - ((ASLToATL _seekerTargetPos) select 2) >= _cruisAlt) then { if( ((ASLToAGL _projectilePos) select 2) - ((ASLToAGL _seekerTargetPos) select 2) >= _cruisAlt) then {
_state set [0, STAGE_TERMINAL]; _state set[0, STAGE_TERMINAL];
} else { } else {
_returnTargetPos = _seekerTargetPos vectorAdd [0,0,_distanceToTarget * 1.5]; _returnTargetPos = _seekerTargetPos vectorAdd [0,0,_distanceToTarget*1.5];
}; };
}; };
case STAGE_TERMINAL: { case STAGE_TERMINAL: {
@ -59,7 +59,7 @@ switch( (_state select 0) ) do {
}; };
#ifdef DEBUG_MODE_FULL #ifdef DEBUG_MODE_FULL
drawLine3D [(ASLtoATL _returnTargetPos), (ASLtoATL _seekerTargetPos), [0, 1, 0, 1]]; drawLine3D [(ASLtoAGL _returnTargetPos), (ASLtoAGL _seekerTargetPos), [0,1,0,1]];
#endif #endif
TRACE_1("Adjusted target position", _returnTargetPos); TRACE_1("Adjusted target position", _returnTargetPos);

View File

@ -7,9 +7,9 @@
#define STAGE_TERMINAL 4 #define STAGE_TERMINAL 4
EXPLODE_7_PVT(((_this select 1) select 0),_shooter,_weapon,_muzzle,_mode,_ammo,_magazine,_projectile); EXPLODE_7_PVT(((_this select 1) select 0),_shooter,_weapon,_muzzle,_mode,_ammo,_magazine,_projectile);
private ["_targetPos", "_projectilePos", "_target", "_seekerTargetPos", "_launchParams", "_targetLaunchParams"]; private["_targetPos", "_projectilePos", "_target", "_seekerTargetPos", "_launchParams", "_targetLaunchParams"];
private ["_distanceToTarget", "_distanceToShooter", "_addHeight", "_returnTargetPos", "_state"]; private["_distanceToTarget", "_distanceToShooter", "_addHeight", "_returnTargetPos", "_state"];
private ["_cruisAlt", "_distanceShooterToTarget", "_shooterPos"]; private["_cruisAlt", "_distanceShooterToTarget", "_shooterPos"];
_seekerTargetPos = _this select 0; _seekerTargetPos = _this select 0;
_launchParams = _this select 1; _launchParams = _this select 1;
@ -38,7 +38,7 @@ switch( (_state select 0) ) do {
case STAGE_LAUNCH: { case STAGE_LAUNCH: {
TRACE_1("STAGE_LAUNCH",""); TRACE_1("STAGE_LAUNCH","");
if(_distanceToShooter < 10) then { if(_distanceToShooter < 10) then {
_returnTargetPos = _seekerTargetPos vectorAdd [0,0,_distanceToTarget * 2]; _returnTargetPos = _seekerTargetPos vectorAdd [0,0,_distanceToTarget*2];
} else { } else {
_state set[0, STAGE_CLIMB]; _state set[0, STAGE_CLIMB];
}; };
@ -50,34 +50,34 @@ switch( (_state select 0) ) do {
_cruisAlt = 140 * (_distanceShooterToTarget/1250); _cruisAlt = 140 * (_distanceShooterToTarget/1250);
TRACE_1("_cruisAlt", _cruisAlt); TRACE_1("_cruisAlt", _cruisAlt);
}; };
if(((ASLToATL _projectilePos) select 2) - ((ASLToATL _seekerTargetPos) select 2) >= _cruisAlt) then { if( ((ASLToAGL _projectilePos) select 2) - ((ASLToAGL _seekerTargetPos) select 2) >= _cruisAlt) then {
if(_cruisAlt < 140) then { if(_cruisAlt < 140) then {
_state set[0, STAGE_TERMINAL]; _state set[0, STAGE_TERMINAL];
} else { } else {
_state set[0, STAGE_COAST]; _state set[0, STAGE_COAST];
}; };
} else { } else {
_returnTargetPos = _seekerTargetPos vectorAdd [0, 0, _distanceToTarget * 1.5]; _returnTargetPos = _seekerTargetPos vectorAdd [0,0,_distanceToTarget*1.5];
}; };
}; };
case STAGE_COAST: { case STAGE_COAST: {
TRACE_1("STAGE_COAST",""); TRACE_1("STAGE_COAST","");
TRACE_1("", ((ASLToATL _projectilePos) select 2) - (( ASLToATL _seekerTargetPos) select 2) ); TRACE_1("", ((ASLToAGL _projectilePos) select 2) - (( ASLToAGL _seekerTargetPos) select 2) );
if(_distanceToTarget < (((ASLToATL _projectilePos) select 2) - (( ASLToATL _seekerTargetPos) select 2)) * 1.5) then { if(_distanceToTarget < ( ((ASLToAGL _projectilePos) select 2) - (( ASLToAGL _seekerTargetPos) select 2) ) * 1.5) then {
_state set[0, STAGE_TERMINAL]; _state set[0, STAGE_TERMINAL];
} else { } else {
_returnTargetPos = _seekerTargetPos vectorAdd [0, 0, (_projectilePos select 2)]; _returnTargetPos = _seekerTargetPos vectorAdd [0,0,(_projectilePos select 2)];
}; };
}; };
case STAGE_TERMINAL: { case STAGE_TERMINAL: {
TRACE_1("STAGE_TERMINAL",""); TRACE_1("STAGE_TERMINAL","");
//_returnTargetPos = _seekerTargetPos vectorAdd [0, 0, _distanceToTarget * 0.02]; //_returnTargetPos = _seekerTargetPos vectorAdd [0,0,_distanceToTarget * 0.02];
_returnTargetPos = _seekerTargetPos; _returnTargetPos = _seekerTargetPos;
}; };
}; };
#ifdef DEBUG_MODE_FULL #ifdef DEBUG_MODE_FULL
drawLine3D [(ASLtoATL _returnTargetPos), (ASLtoATL _seekerTargetPos), [0, 1, 0, 1]]; drawLine3D [(ASLtoAGL _returnTargetPos), (ASLtoAGL _seekerTargetPos), [0,1,0,1]];
#endif #endif
TRACE_1("Adjusted target position", _returnTargetPos); TRACE_1("Adjusted target position", _returnTargetPos);

View File

@ -2,8 +2,8 @@
#include "script_component.hpp" #include "script_component.hpp"
EXPLODE_7_PVT(((_this select 1) select 0),_shooter,_weapon,_muzzle,_mode,_ammo,_magazine,_projectile); EXPLODE_7_PVT(((_this select 1) select 0),_shooter,_weapon,_muzzle,_mode,_ammo,_magazine,_projectile);
private ["_targetPos", "_projectilePos", "_target", "_seekerTargetPos", "_launchParams", "_targetLaunchParams"]; private["_targetPos", "_projectilePos", "_target", "_seekerTargetPos", "_launchParams", "_targetLaunchParams"];
private ["_distanceToTarget", "_distanceToShooter", "_addHeight", "_returnTargetPos", "_shooterPos"]; private["_distanceToTarget", "_distanceToShooter", "_addHeight", "_returnTargetPos", "_shooterPos"];
_seekerTargetPos = _this select 0; _seekerTargetPos = _this select 0;
_launchParams = _this select 1; _launchParams = _this select 1;
@ -13,7 +13,7 @@ _targetLaunchParams = _launchParams select 1;
_shooterPos = getPosASL _shooter; _shooterPos = getPosASL _shooter;
_projectilePos = getPosASL _projectile; _projectilePos = getPosASL _projectile;
_distanceToTarget = _projectilePos vectorDistance _seekerTargetPos; _distanceToTarget = _projectilePos vectorDistance _seekerTargetPos;
_distanceToShooter = _projectilePos vectorDistance _shooterPos; _distanceToShooter = _projectilePos vectorDistance _shooterPos;
TRACE_3("", _distanceToTarget, _distanceToShooter, _seekerTargetPos); TRACE_3("", _distanceToTarget, _distanceToShooter, _seekerTargetPos);
@ -22,7 +22,7 @@ TRACE_3("", _distanceToTarget, _distanceToShooter, _seekerTargetPos);
_addHeight = [0,0,0]; _addHeight = [0,0,0];
// Always climb an arc on initial launch if we are close to the round // Always climb an arc on initial launch if we are close to the round
if( ((ASLtoATL _projectilePos) select 2) < 5 && _distanceToShooter < 15) then { if( ((ASLtoAGL _projectilePos) select 2) < 5 && _distanceToShooter < 15) then {
_addHeight = _addHeight vectorAdd [0,0,_distanceToTarget]; _addHeight = _addHeight vectorAdd [0,0,_distanceToTarget];
} else { } else {
// If we are below the target, increase the climbing arc // If we are below the target, increase the climbing arc
@ -43,8 +43,8 @@ if( (_projectilePos select 2) > (_seekerTargetPos select 2) && _distanceToTarget
_returnTargetPos = _seekerTargetPos vectorAdd _addHeight; _returnTargetPos = _seekerTargetPos vectorAdd _addHeight;
#ifdef DEBUG_MODE_FULL #ifdef DEBUG_MODE_FULL
drawLine3D [(ASLtoATL _returnTargetPos) vectorAdd _addHeight, ASLtoATL _returnTargetPos, [0,1,0,1]]; drawLine3D [(ASLtoAGL _returnTargetPos) vectorAdd _addHeight, ASLtoAGL _returnTargetPos, [0,1,0,1]];
#endif #endif
TRACE_1("Adjusted target position", _returnTargetPos); TRACE_1("Adjusted target position", _returnTargetPos);
_returnTargetPos; _returnTargetPos;

View File

@ -58,7 +58,7 @@ _adjustVector = _targetVector vectorDiff (vectorDir _projectile);
_yaw = 0; _yaw = 0;
_pitch = 0; _pitch = 0;
_roll = 0; _roll = 0;
if((_adjustVector select 0) < 0) then { if((_adjustVector select 0) < 0) then {
_yaw = - ( (_minDeflection max (abs(_adjustVector select 0) min _maxDeflection) ) ); _yaw = - ( (_minDeflection max (abs(_adjustVector select 0) min _maxDeflection) ) );
} else { } else {
@ -90,17 +90,17 @@ if(accTime > 0) then {
}; };
#ifdef DEBUG_MODE_FULL #ifdef DEBUG_MODE_FULL
drawIcon3D ["\a3\ui_f\data\IGUI\Cfg\Cursors\selectover_ca.paa", [1,1,1,1], ASLtoATL _projectilePos, 0.75, 0.75, 0, str _vectorTo, 1, 0.025, "TahomaB"]; drawIcon3D ["\a3\ui_f\data\IGUI\Cfg\Cursors\selectover_ca.paa", [1,1,1,1], ASLtoAGL _projectilePos, 0.75, 0.75, 0, str _vectorTo, 1, 0.025, "TahomaB"];
drawLine3D [ASLtoATL _projectilePos, ASLtoATL _profileAdjustedTargetPos, [1,0,0,1]]; drawLine3D [ASLtoAGL _projectilePos, ASLtoAGL _profileAdjustedTargetPos, [1,0,0,1]];
_ps = "#particlesource" createVehicleLocal (ASLtoATL _projectilePos); _ps = "#particlesource" createVehicleLocal (ASLtoAGL _projectilePos);
_PS setParticleParams [["\A3\Data_f\cl_basic", 8, 3, 1], "", "Billboard", 1, 3.0141, [0, 0, 2], [0, 0, 0], 1, 1.275, 1, 0, [1, 1], [[1, 0, 0, 1], [1, 0, 0, 1], [1, 0, 0, 1]], [1], 1, 0, "", "", nil]; _PS setParticleParams [["\A3\Data_f\cl_basic", 8, 3, 1], "", "Billboard", 1, 3.0141, [0, 0, 2], [0, 0, 0], 1, 1.275, 1, 0, [1, 1], [[1, 0, 0, 1], [1, 0, 0, 1], [1, 0, 0, 1]], [1], 1, 0, "", "", nil];
_PS setDropInterval 3.0; _PS setDropInterval 3.0;
hintSilent format["d: %1", _distanceToTarget]; //hintSilent format["d: %1", _distanceToTarget];
#endif #endif
_stateParams set[0, diag_tickTime]; _stateParams set[0, diag_tickTime];
_args set[4, _stateParams]; _args set[4, _stateParams];
_this set[0, _args]; _this set[0, _args];

View File

@ -1,32 +1,32 @@
//#define DEBUG_MODE_FULL // #define DEBUG_MODE_FULL
#include "script_component.hpp" #include "script_component.hpp"
EXPLODE_7_PVT(((_this select 1) select 0),_shooter,_weapon,_muzzle,_mode,_ammo,_magazine,_projectile); params ["_lastSeekTargetPos", "_args"];
private ["_angleFov", "_canSeeTarget", "_foundTargetPos", "_laserResult", "_launchParams", "_seekerParams", "_laserCode", "_laserParams", "_seekerTargetPos", "_sensorPos", "_target"]; _args params ["_firedEH", "_launchParams", "_flightParams", "_seekerParams", "_stateParams"];
_seekerTargetPos = _this select 0; _firedEH params ["_shooter","_weapon","_muzzle","_mode","_ammo","_magazine","_projectile"];
_launchParams = _this select 1; _launchParams params ["","","","","","_laserParams"];
_seekerParams = _launchParams select 3; _seekerParams params ["_seekerAngle", "", "_seekerMaxRange"];
_angleFov = _seekerParams select 0; _laserParams params ["_code", "_wavelengthMin", "_wavelengthMax"];
_laserParams = (_launchParams select 1) select 5; private "_foundTargetPos";
TRACE_2("", _launchParams, _laserParams);
if(!isNil "_target") then { if (!isNil "_target") then {
// Handle AI or moving vanilla lasers // Handle AI or moving vanilla lasers
_foundTargetPos = getPosASL _target; _foundTargetPos = getPosASL _target;
} else { } else {
_laserResult = [(getPosASL _projectile), (velocity _projectile), _angleFov, [(_laserParams select 1),(_laserParams select 2)], (_laserParams select 0)] call EFUNC(laser,seekerFindLaserSpot); private _laserResult = [(getPosASL _projectile), (velocity _projectile), _seekerAngle, [_wavelengthMin, _wavelengthMax], _code, _projectile] call EFUNC(laser,seekerFindLaserSpot);
_foundTargetPos = _laserResult select 0; _foundTargetPos = _laserResult select 0;
TRACE_1("Search", _laserResult); TRACE_1("Search", _laserResult);
}; };
if(!isNil "_foundTargetPos") then { if(!isNil "_foundTargetPos") then {
//_canSeeTarget = [_projectile, _foundTargetPos, _angleFov] call FUNC(checkSeekerAngle); // Fov is already checked by laser func, check if distance
private _canSeeTarget = _seekerMaxRange >= (_foundTargetPos vectorDistance (getPosASL _projectile));
// If we got here, it was an invalid target, just return a spot 5m in front of the missile // If we got here, it was an invalid target, just return a spot 5m in front of the missile
if(!_canSeeTarget) then { if(!_canSeeTarget) then {
_foundTargetPos = _sensorPos vectorAdd ((velocity _projectile) vectorMultiply 5); _foundTargetPos = _sensorPos vectorAdd ((velocity _projectile) vectorMultiply 5);
}; };
}; };
_foundTargetPos; _foundTargetPos;

View File

@ -33,7 +33,7 @@ GVAR(distanceIndex) = -1;
[_this select 1] call CBA_fnc_removePerFrameHandler; [_this select 1] call CBA_fnc_removePerFrameHandler;
}; };
_result = [eyePos ACE_player, ACE_player weaponDirection (currentWeapon ACE_player)] call EFUNC(laser,shootRay); _result = [eyePos ACE_player, ACE_player weaponDirection (currentWeapon ACE_player), ACE_player] call EFUNC(laser,shootRay);
_distance = _result select 1; _distance = _result select 1;
_distance = _distance - 1 + (random 2); _distance = _distance - 1 + (random 2);