Merge branch 'master' of https://github.com/acemod/ACE3 into medical-rewrite

This commit is contained in:
commy2 2016-10-10 14:29:50 +02:00
commit 0f43829b63
104 changed files with 1466 additions and 1102 deletions

View File

@ -15,6 +15,12 @@ if (!alive ACE_player) exitWith { // Dead people don't breath, Will also handle
private _currentWork = REE;
private _currentSpeed = (vectorMagnitude (velocity ACE_player)) min 6;
// fix #4481. Diving to the ground is recorded as PRONE stance with running speed velocity. Cap maximum speed to fix.
if (stance ACE_player == "PRONE") then {
_currentSpeed = _currentSpeed min 1.5;
};
if ((vehicle ACE_player == ACE_player) && {_currentSpeed > 0.1} && {isTouchingGround ACE_player || {underwater ACE_player}}) then {
_currentWork = [ACE_player, _currentSpeed] call FUNC(getMetabolicCosts);
_currentWork = _currentWork max REE;

View File

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

View File

@ -6,4 +6,16 @@ class ACE_Settings {
value = 1;
typeName = "BOOL";
};
class GVAR(enableAmmobox) {
displayName = CSTRING(enableBoxCookoff_name);
description = CSTRING(enableBoxCookoff_tooltip);
value = 1;
typeName = "BOOL";
};
class GVAR(enableAmmoCookoff) {
displayName = CSTRING(enableAmmoCookoff_name);
description = CSTRING(enableAmmoCookoff_tooltip);
value = 1;
typeName = "BOOL";
};
};

View File

@ -0,0 +1,33 @@
class CfgAmmo {
class ShellBase;
class ace_ammoExplosion: ShellBase {
hit = 10;
indirectHit = 0.5;
indirectHitRange = 1;
soundHit[] = {"", 1, 1, 0};
typicalSpeed = 100;
explosive = 0;
cost = 300;
model = "\A3\Weapons_F\empty.p3d";
airFriction = 0;
timeToLive = 1;
explosionTime = 0.001;
soundFly[] = {"",1,1};
soundEngine[] = {"",1,4};
explosionEffects = "ExploAmmoExplosion";
};
class SmallSecondary;
class ACE_ammoExplosionLarge: SmallSecondary {
soundHit[] = {"", 1, 1, 0};
model = "\A3\Weapons_F\empty.p3d";
soundFly[] = {"",1,1};
soundEngine[] = {"",1,4};
soundHit1[] = {"",1,1,1};
soundHit2[] = {"",1,1,1};
soundHit3[] = {"",1,1,1};
supersonicCrackFar[] = {"",1,1,1};
supersonicCrackNear[] = {"",1,1,1};
craterEffects = "ImpactEffectsMedium";
};
};

View File

@ -52,3 +52,30 @@ class CfgCloudlets {
destroyOnWaterSurfaceOffset = 0;
};
};
class GVAR(ExploAmmoExplosion) {
class ExploAmmoFlash {
position[] = {0,0,0};
simulation = "particles";
type = "ExploAmmoFlash";
intensity = 1;
interval = 1;
lifeTime = 1;
};
class LightExplosion {
simulation = "light";
type = "SparksLight";
position[] = {0,0,0};
intensity = 1;
interval = 1;
lifeTime = 0.15;
};
class ExploAmmoSmoke {
position[] = {0,0,0};
simulation = "particles";
type = "AutoCannonFired";
intensity = 1.5;
interval = 1.5;
lifeTime = 1.5;
};
};

View File

@ -2,5 +2,7 @@
PREP(handleDamage);
PREP(engineFire);
PREP(cookOff);
PREP(cookOffBox);
PREP(blowOffTurret);
PREP(secondaryExplosions);
PREP(detonateAmmunition);

View File

@ -2,6 +2,7 @@
[QGVAR(engineFire), FUNC(engineFire)] call CBA_fnc_addEventHandler;
[QGVAR(cookOff), FUNC(cookOff)] call CBA_fnc_addEventHandler;
[QGVAR(cookOffBox), FUNC(cookOffBox)] call CBA_fnc_addEventHandler;
GVAR(cacheTankDuplicates) = call CBA_fnc_createNamespace;
@ -52,21 +53,31 @@ GVAR(cacheTankDuplicates) = call CBA_fnc_createNamespace;
}];
}, nil, ["Wheeled_APC_F"], true] call CBA_fnc_addClassEventHandler;
["ReammoBox_F", "init", {
(_this select 0) addEventHandler ["HandleDamage", {
if (GVAR(enableAmmobox)) then {
["box", _this] call FUNC(handleDamage);
};
}];
}, nil, nil, true] call CBA_fnc_addClassEventHandler;
// secondary explosions
["AllVehicles", "killed", {
params ["_vehicle"];
if (_vehicle getVariable [QGVAR(enable), GVAR(enable)]) then {
if (_vehicle getVariable [QGVAR(enable),GVAR(enable)]) then {
_vehicle call FUNC(secondaryExplosions);
if (_vehicle getVariable [QGVAR(enableAmmoCookoff), GVAR(enableAmmoCookoff)]) then {
[_vehicle, magazinesAmmo _vehicle] call FUNC(detonateAmmunition);
};
};
}, nil, ["Man"]] call CBA_fnc_addClassEventHandler;
}, nil, ["Man","StaticWeapon"]] call CBA_fnc_addClassEventHandler;
// blow off turret effect
["Tank", "killed", {
params ["_vehicle"];
if (_vehicle getVariable [QGVAR(enable), GVAR(enable)]) then {
_vehicle call FUNC(blowOffTurret);
if ((_this select 0) getVariable [QGVAR(enable),GVAR(enable)]) then {
if (random 1 < 0.15) then {
(_this select 0) call FUNC(blowOffTurret);
};
};
}] call CBA_fnc_addClassEventHandler;

View File

@ -8,7 +8,7 @@ class CfgPatches {
requiredVersion = REQUIRED_VERSION;
requiredAddons[] = {"ace_common"};
author = ECSTRING(common,ACETeam);
authors[] = {"commy2"};
authors[] = {"commy2", "Glowbal"};
url = ECSTRING(main,URL);
VERSION_CONFIG;
};
@ -18,6 +18,7 @@ class CfgPatches {
#include "CfgEden.hpp"
#include "CfgEventHandlers.hpp"
#include "CfgAmmo.hpp"
#include "CfgCloudlets.hpp"
#include "CfgSFX.hpp"
#include "CfgVehicles.hpp"

View File

@ -129,6 +129,6 @@ if (local _vehicle) then {
if (local _vehicle) then {
_vehicle setDamage 1;
};
}, [_vehicle, _effects], 4 + random 1] call CBA_fnc_waitAndExecute;
}, [_vehicle, _effects, _positions], 3 + random 2] call CBA_fnc_waitAndExecute;
}, _vehicle, 0.5 + random 0.3] call CBA_fnc_waitAndExecute;
}, [_vehicle, _effects], 4 + random 20] call CBA_fnc_waitAndExecute;
}, [_vehicle, _effects, _positions], 3 + random 15] call CBA_fnc_waitAndExecute;
}, _vehicle, 0.5 + random 5] call CBA_fnc_waitAndExecute;

View File

@ -0,0 +1,75 @@
/*
* Author: KoffeinFlummi, commy2, SilentSpike
* Start a cook-off in the given ammo box.
*
* Arguments:
* 0: Ammo box <OBJECT>
*
* Return Value:
* None
*
* Example:
* [_box] call ace_cookoff_fnc_cookOffBox
*
* Public: No
*/
#include "script_component.hpp"
params ["_box"];
if (_box getVariable [QGVAR(isCookingOff), false]) exitWith {};
_box setVariable [QGVAR(isCookingOff), true];
if (local _vehicle) then {
[QGVAR(cookOffBox), _box] call CBA_fnc_remoteEvent;
};
[{
params ["_box"];
// Box will start smoking
private _smoke = "#particlesource" createVehicleLocal [0,0,0];
_smoke setParticleClass "AmmoSmokeParticles2";
_smoke attachTo [_box, [0,0,0]];
private _effects = [_smoke];
if (isServer) then {
private _sound = createSoundSource ["Sound_Fire", position _box, [], 0];
_effects pushBack _sound;
};
[{
params ["_box", "_effects"];
// These functions are smart and do all the cooking off work
if (local _box) then {
_box call FUNC(secondaryExplosions);
if (_box getVariable [QGVAR(enableAmmoCookoff), GVAR(enableAmmoCookoff)]) then {
[_box, magazinesAmmo _box] call FUNC(detonateAmmunition);
};
// This shit is busy being on fire, magazines aren't accessible/usable
clearMagazineCargoGlobal _box;
};
// Light the fire (also handles lighting)
private _fire = "#particlesource" createVehicleLocal [0,0,0];
_fire setParticleClass "AmmoBulletCore";
_fire attachTo [_box, [0,0,0]];
_effects pushBack _fire;
[{
params ["_box", "_effects"];
{
deleteVehicle _x;
} forEach _effects;
if (local _box) then {
_box setDamage 1;
};
}, [_box, _effects], 45 + random 75] call CBA_fnc_waitAndExecute; // Give signifcant time for ammo cookoff to occur (perhaps keep the box alive until all cooked off?)
}, [_box, _effects], 3 + random 15] call CBA_fnc_waitAndExecute;
}, _box, 0.5 + random 5] call CBA_fnc_waitAndExecute;

View File

@ -0,0 +1,112 @@
/*
* Author: Glowbal
* Detonates ammunition from a vehicle until no ammo left
*
* Arguments:
* 0: vehicle <OBJECT>
*
* Return Value:
* None
*
* Example:
* [_vehicle, magazinesAmmo _vehicle] call ace_cookoff_fnc_detonateAmmunition
*
* Public: No
*/
#include "script_component.hpp"
#define MAX_TIME_BETWEEN_AMMO_DET 25
params ["_vehicle", "_magazines"];
if (isNull _vehicle) exitWith {}; // vehicle got deleted
if (_magazines isEqualTo []) exitWith {}; // nothing to detonate anymore
if (underwater _vehicle) exitWith {};
private _magazineIndex = floor random(count _magazines);
private _magazine = _magazines select _magazineIndex;
_magazine params ["_magazineClassname", "_amountOfMagazines"];
if (_amountOfMagazines > 0) exitWith {
private _newMagCount = _amountOfMagazines - floor(1 + random(6));
if (_newMagCount <= 0) then {
_magazines deleteAt _magazineIndex;
} else {
_magazine set [1, _newMagCount]; // clear out the magazine
};
private _ammo = getText (configFile >> "CfgMagazines" >> _magazineClassname >> "ammo");
private _timeBetweenAmmoDetonation = (random 7) * (1 / random (_amountOfMagazines)) min MAX_TIME_BETWEEN_AMMO_DET;
_timeBetweenAmmoDetonation = _timeBetweenAmmoDetonation max 0.1;
private _speedOfAmmo = getNumber (configFile >> "CfgMagazines" >> _magazineClassname >> "initSpeed");
private _simulationTime = getNumber (configFile >> "CfgAmmo" >> _ammo >> "simulation");
private _caliber = getNumber (configFile >> "CfgAmmo" >> _ammo >> "caliber");
private _simType = getText (configFile >> "CfgAmmo" >> _ammo >> "simulation");
private _effect2pos = _vehicle selectionPosition "destructionEffect2";
private _spawnProjectile = {
params ["_vehicle", "_ammo", "_speed", "_flyAway"];
private _spawnPos = _vehicle modelToWorld [-0.2 + (random 0.4), -0.2 + (random 0.4), random 3];
if (_spawnPos select 2 < 0) then {
_spawnPos set [2, 0];
};
private _projectile = _ammo createVehicle [0,0,0];
_projectile setPos _spawnPos;
if (_flyAway) then {
private _vectorAmmo = [(-1 + (random 2)), (-1 + (random 2)), -0.2 + (random 1)];
private _velVec = _vectorAmmo vectorMultiply _speed;
_projectile setVectorDir _velVec;
_projectile setVelocity _velVec;
[ACE_player, _projectile, [1,0,0,1]] call EFUNC(frag,addTrack);
} else {
_projectile setDamage 1;
};
_projectile;
};
private _speed = random (_speedOfAmmo / 10) max 1;
if (toLower _simType == "shotbullet") then {
private _sound = selectRandom [QUOTE(PATHTO_R(sounds\light_crack_close.wss)), QUOTE(PATHTO_R(sounds\light_crack_close_filtered.wss)), QUOTE(PATHTO_R(sounds\heavy_crack_close.wss)), QUOTE(PATHTO_R(sounds\heavy_crack_close_filtered.wss))];
playSound3D [_sound, objNull, false, (getPosASL _vehicle), 2, 1, 1250];
if (random 1 < 0.6) then {
[_vehicle, _ammo, _speed, true] call _spawnProjectile;
};
};
if (toLower _simType == "shotshell") then {
private _sound = selectRandom [QUOTE(PATHTO_R(sounds\heavy_crack_close.wss)), QUOTE(PATHTO_R(sounds\heavy_crack_close_filtered.wss))];
playSound3D [_sound, objNull, false, (getPosASL _vehicle), 2, 1, 1300];
if (random 1 < 0.15) then {
[_vehicle, _ammo, _speed, random 1 < 0.15] call _spawnProjectile;
};
};
if (toLower _simType == "shotgrenade") then {
if (random 1 < 0.9) then {
_speed = 0;
};
[_vehicle, _ammo, _speed, random 1 < 0.5] call _spawnProjectile;
};
if (toLower _simType == "shotrocket" || {toLower _simType == "shotmissile"}) then {
if (random 1 < 0.1) then {
private _sound = selectRandom [QUOTE(PATHTO_R(sounds\cannon_crack_close.wss)), QUOTE(PATHTO_R(sounds\cannon_crack_close_filtered.wss))];
playSound3D [_sound, objNull, false, (getPosASL _vehicle), 3, 1, 1600];
[_vehicle, _ammo, _speed, random 1 < 0.3] call _spawnProjectile;
} else {
"ACE_ammoExplosionLarge" createvehicle (_vehicle modelToWorld _effect2pos);
};
};
if (toLower _simType in ["shotdirectionalbomb", "shotilluminating", "shotmine"]) then {
if (random 1 < 0.5) then {
[_vehicle, _ammo, 0, false] call _spawnProjectile;
};
};
[FUNC(detonateAmmunition), [_vehicle, _magazines], _timeBetweenAmmoDetonation] call CBA_fnc_waitAndExecute;
};
[FUNC(detonateAmmunition), [_vehicle, _magazines], random 3] call CBA_fnc_waitAndExecute;

View File

@ -16,7 +16,7 @@
#include "script_component.hpp"
params ["_simulationType", "_thisHandleDamage"];
_thisHandleDamage params ["_vehicle", "", "_damage", "", "_ammo", "_hitIndex"];
_thisHandleDamage params ["_vehicle", "", "_damage", "_source", "_ammo", "_hitIndex", "_shooter"];
// it's already dead, who cares?
if (damage _vehicle >= 1) exitWith {};
@ -58,12 +58,12 @@ if (_simulationType == "car") exitWith {
if (_simulationType == "tank") exitWith {
// determine ammo storage location
private _ammoLocationHitpoint = getText (_vehicle call CBA_fnc_getObjectConfig >> QGVAR(ammoLocation));
private _ammoLocationHitpoint = getText (_vehicle call CBA_fnc_getObjectConfig >> QGVAR(ammoLocation));
if (_hitIndex in (GVAR(cacheTankDuplicates) getVariable (typeOf _vehicle))) then {
_hitpoint = "#subturret";
};
// ammo was hit, high chance for cook-off
if (_hitpoint == _ammoLocationHitpoint) then {
if (_damage > 0.5 && {random 1 < 0.7}) then {
@ -82,3 +82,37 @@ if (_simulationType == "tank") exitWith {
_damage
};
};
if (_simulationType == "box") exitWith {
if (_hitpoint == "#structural" && _damage > 0.5) then {
// Almost always catch fire when hit by an explosive
if (IS_EXPLOSIVE_AMMO(_ammo)) then {
_vehicle call FUNC(cookOffBox);
} else {
// Need magazine to check for tracers
private _mag = "";
if (_source == _shooter) then {
_mag = currentMagazine _source;
} else {
_mag = _source currentMagazineTurret ([_shooter] call CBA_fnc_turretPath);
};
private _magCfg = configFile >> "CfgMagazines" >> _mag;
// Magazine could have changed during flight time (just ignore if so)
if (getText (_magCfg >> "ammo") == _ammo) then {
// If magazine's tracer density is high enough then low chance for cook off
private _tracers = getNumber (_magCfg >> "tracersEvery");
if (_tracers >= 1 && {_tracers <= 4}) then {
if (random 1 < _oldDamage*0.05) then {
_vehicle call FUNC(cookOffBox);
};
};
};
};
// prevent destruction, let cook-off handle it if necessary
_damage min 0.89
} else {
_damage
};
};

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<Project name="ACE">
<Package name="CookOff">
<Key ID="STR_ACE_CookOff_enable_name">
@ -31,5 +31,17 @@
<Korean>잔해(포탑)</Korean>
<Japanese>残骸(タレット)</Japanese>
</Key>
<Key ID="STR_ACE_CookOff_enable_name">
<English>Enable ammo box cook off</English>
</Key>
<Key ID="STR_ACE_CookOff_enable_tooltip">
<English>Enables cooking off of ammo boxes.</English>
</Key>
<Key ID="STR_ACE_CookOff_enableAmmoCookoff_name">
<English>Enable Ammunition cook off</English>
</Key>
<Key ID="STR_ACE_CookOff_enableAmmoCookoff_tooltip">
<English>Enables Ammunition cook off. Fires ammunition projectiles while vehicle is on fire and has ammunition.</English>
</Key>
</Package>
</Project>

View File

@ -217,7 +217,7 @@ class CfgVehicles {
GVAR(enabled) = 2;
GVAR(ropeOrigins)[] = {"ropeOriginRight", "ropeOriginLeft"};
GVAR(friesType) = "ACE_friesGantry";
GVAR(friesAttachmentPoint)[] = {-1.07, 3.26, -0.5};
GVAR(friesAttachmentPoint)[] = {1.07, 2.5, -0.5};
EQUIP_FRIES_ATTRIBUTE;
};
class Heli_Transport_04_base_F: Helicopter_Base_H {

View File

@ -146,9 +146,16 @@ if (isServer) then {
//systemChat format ["burn: %1", _x];
// --- destroy nearby static weapons and ammo boxes
if (_x isKindOf "StaticWeapon" || {_x isKindOf "ReammoBox_F"} || {_x isKindOf "ACE_RepairItem_Base"}) then {
if (_x isKindOf "StaticWeapon" || {_x isKindOf "ACE_RepairItem_Base"}) then {
_x setDamage 1;
};
if (_x isKindOf "ReammoBox_F") then {
if ("ace_cookoff" call EFUNC(common,isModLoaded) && {EGVAR(cookoff,enable)}) then {
_x call EFUNC(cookoff,cookOffBox);
} else {
_x setDamage 1;
};
};
// --- delete nearby ground weapon holders
if (_x isKindOf "WeaponHolder" || {_x isKindOf "WeaponHolderSimulated"}) then {

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 ADDON {
init = QUOTE(call COMPILE_FILE(XEH_preStart));
@ -7,20 +6,13 @@ class Extended_PreStart_EventHandlers {
class Extended_PreInit_EventHandlers {
class ADDON {
init = QUOTE(call COMPILE_FILE(XEH_pre_init));
init = QUOTE(call COMPILE_FILE(XEH_preInit));
};
};
class Extended_PostInit_EventHandlers {
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 All;
class LaserTarget: All {
// @TODO: Changing the model and simulation hides it, but THEN IT DOESNT SPAWN WTF!?
model = "\A3\Weapons_F\empty.p3d";
destrType = "DestructNo";
simulation = "LaserTarget";
// model = "\A3\Weapons_F\empty.p3d";
class EventHandlers {
init = QUOTE(_this call FUNC(laser_init));
class ADDON {
init = QUOTE(_this call FUNC(handleLaserTargetCreation));
};
};
};
// Visual laserTarget override
class ACE_LaserTarget_Visual : LaserTarget {
simulation = "LaserTarget";
model = "\A3\Weapons_f\laserTgt.p3d";
// laserTarget fails if the turret does not have "primaryGunner" config
// This only effects the indfor strider who's commander is not the primaryGunner
class LandVehicle;
class Car: LandVehicle {
class NewTurret;
};
// Vehicle lockable configurations
class AllVehicles;
class Air: AllVehicles {
class Turrets;
};
class Helicopter: Air {
class Car_F: Car {
class Turrets {
class MainTurret;
class MainTurret: NewTurret {};
};
};
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 MRAP_03_base_F: Car_F {
class Turrets: Turrets {
class MainTurret: MainTurret {
GVAR(CanLockLaser) = 1; // Enable laser locking selection
class CommanderTurret: MainTurret {
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)
- [NouberNou](https://github.com/NouberNou)
- [esteldunedain](https://github.com/esteldunedain)
- [PabstMirror](https://github.com/PabstMirror)

View File

@ -1,26 +1,15 @@
PREP(rotateVectLineGetMap);
PREP(rotateVectLine);
PREP(shootRay);
PREP(shootCone);
PREP(checkLos);
PREP(findStrongestRay);
PREP(onLaserDesignatorDraw);
PREP(seekerFindLaserSpot);
PREP(laserOn);
PREP(addLaserTarget);
PREP(dev_drawVisibleLaserTargets);
PREP(findLaserSource);
PREP(handleLaserTargetCreation);
PREP(keyLaserCodeChange);
PREP(laserOff);
PREP(handleLaserOn);
PREP(handleLaserOff);
PREP(drawVisibleLaserTargets);
PREP(laser_init);
PREP(vanillaLaserSeekerHandler);
PREP(laserOn);
PREP(laserTargetPFH);
PREP(unitTurretCanLockLaser);
PREP(keyLaserCodeUp);
PREP(keyLaserCodeDown);
PREP(onLaserDesignatorDraw);
PREP(rotateVectLine);
PREP(rotateVectLineGetMap);
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"
GVAR(VanillaLasers) = [];
// Laser default variables
ACE_DEFAULT_LASER_CODE = 1001;
ACE_DEFAULT_LASER_CODE = 1111;
ACE_DEFAULT_LASER_WAVELENGTH = 1550;
ACE_DEFAULT_LASER_BEAMSPREAD = 1;
GVAR(laserEmitters) = [] call CBA_fnc_hashCreate;
GVAR(trackedLaserTargets) = [];
GVAR(pfehID) = -1;
ADDON = true;

View File

@ -13,6 +13,7 @@ class CfgPatches {
};
};
#include "ACE_Settings.hpp"
#include "CfgEventhandlers.hpp"
#include "CfgVehicles.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.
*
* Arguments:
* 0: UUID (from laserOn) <string>
* 0: UUID (from laserOn) <STRING>
*
* Return Value:
* Return value:
* None
*
* Example:
* ["yourLaserUID"] call ace_laser_fnc_laserOff;
*
* Public: No
*/
#include "script_component.hpp"
params ["_uuid"];
TRACE_1("Sending Global Laser Off Event",_uuid);
["ace_laserOff", [_uuid]] call CBA_fnc_globalEvent;

View File

@ -3,20 +3,33 @@
* Turn a laser designator on.
*
* Arguments:
* 0: Emitter <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.
* 3: Wavelength (1550nm is common eye safe) <number>
* 4: Laser code <number>
* 5: Beam divergence (in mils off beam center).
* 0: Emitter <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. <STRING><CODE><ARRAY>
* 3: Wavelength (1550nm is common eye safe) <NUMBER>
* 4: Laser code <NUMBER>
* 5: Beam divergence (in mils off beam center). <NUMBER>
* 6: Method Args <OPTIONAL><ANY>
*
* 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"
// 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 _args = [_uuid, _this];
TRACE_2("Sending Global Laser On Event",_uuid,_this);
["ace_laserOn", _args] call CBA_fnc_globalEvent;
_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"
TRACE_1("enter", _this);
//TRACE_1("enter", _this);
params ["_args"];
_args params ["_laserTarget", "_shooter", "_uuid"];
params ["", "_pfhuid"];
if(isNull _laserTarget || !alive _shooter) exitWith {
[(_this select 1)] call CBA_fnc_removePerFrameHandler;
REM(GVAR(VanillaLasers), _laserTarget);
GVAR(trackedLaserTargets) = GVAR(trackedLaserTargets) select {
_x params ["_targetObject", "_owner", "_laserUuid"];
if ((isNull _targetObject) ||
{!(alive _targetObject)} ||
{isNull _owner} ||
{!(alive _owner)}) then {
// Remove laseron
[_uuid] call FUNC(laserOff);
// Turn off the laser in ace_laser
[_laserUuid] call FUNC(laserOff);
TRACE_1("Laser off:", _laserUuid);
false
} else {
true
};
};
#ifdef DEBUG_MODE_FULL
// Iconize the location of the actual laserTarget
_pos = getPosASL _laserTarget;
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"];
{
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
if (GVAR(trackedLaserTargets) isEqualTo []) then {
TRACE_1("ending pfeh",count GVAR(trackedLaserTargets));
[_pfhuid] call CBA_fnc_removePerFrameHandler;
GVAR(pfehID) = -1;
};

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"
private ["_laserCode"];
_laserCode = ACE_player getVariable[QGVAR(code), ACE_DEFAULT_LASER_CODE];
if(!isNil "_laserCode") then {
private _laserCode = ACE_player getVariable[QGVAR(code), ACE_DEFAULT_LASER_CODE];
if (!isNil "_laserCode") then {
__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
__LaserDesignatorIGUI_ACE_Distance ctrlSetText "----";
} else {
__LaserDesignatorIGUI_ACE_Distance ctrlSetText (ctrlText __LaserDesignatorIGUI_CA_Distance);
};
};

View File

@ -1,16 +1,9 @@
#include "script_component.hpp"
private ["_d", "_map", "_p", "_theta", "_u"];
_map = _this select 0;
_theta = _this select 1;
_p = _map select 0;
_p1 = _map select 1;
_p2 = _map select 2;
_q1 = +(_map select 3);
_q2 = +(_map select 4);
_u = _map select 5;
_d = _map select 6;
params ["_map", "_theta"];
_map params ["_p", "_p1", "_p2", "_q1", "_q2", "_u", "_d"];
_q1 = +_q1;
_q2 = +_q2;
/* Step 4 */
_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 */
_q1 = _q2 vectorAdd _p1;
_q1;
_q1;

View File

@ -1,17 +1,14 @@
#include "script_component.hpp"
private ["_p", "_theta", "_p1", "_p2", "_q1", "_q2", "_u", "_d"];
_p = _this select 0;
_p1 = _this select 1;
_p2 = _this select 2;
params ["_p", "_p1", "_p2"];
_q2 = [];
private _q2 = [];
/* Step 1 */
_q1 = _p vectorDiff _p1;
_u = _p2 vectorDiff _p1;
private _q1 = _p vectorDiff _p1;
private _u = _p2 vectorDiff _p1;
_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 */
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[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
* Turn a laser designator on.
* Searches for a laser spot given a seekers params.
* Provides the interface for Missile Guidance
*
* Arguments:
* 0: Position of seeker (ASL) <position>
* 1: Direction vector (will be normalized) <vector>
* 2: Seeker FOV in degrees <number>
* 3: Seeker wavelength sensitivity range, [1550,1550] is common eye safe. <array>
* 4: Seeker laser code. <number>
* 0: Position of seeker (ASL) <ARRAY>
* 1: Direction vector (will be normalized) <ARRAY>
* 2: Seeker FOV in degrees <NUMBER>
* 3: Seeker wavelength sensitivity range, [1550,1550] is common eye safe. <ARRAY>
* 4: Seeker laser code. <NUMBER>
* 5: Ignore 1 (e.g. Player's vehicle) <OPTIONAL><OBJECT>
*
* Return Value:
* 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"
private ["_pos", "_seekerWavelengths", "_seekerCode", "_spots", "_buckets", "_excludes", "_bucketIndex", "_finalPos", "_owner", "_obj", "_x", "_method"];
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"];
BEGIN_COUNTER(seekerFindLaserSpot);
_pos = _this select 0;
_dir = vectorNormalized (_this select 1);
_seekerFov = _this select 2;
_seekerWavelengths = _this select 3;
_seekerCode = _this select 4;
params ["_posASL", "_dir", "_seekerFov", "_seekerWavelengths", "_seekerCode", ["_ignoreObj1", objNull]];
_dir = vectorNormalized _dir;
_seekerWavelengths params ["_seekerWavelengthMin", "_seekerWavelengthMax"];
private _seekerCos = cos _seekerFov;
_seekerCos = cos _seekerFov;
TRACE_5("",_posASL,_dir,_seekerFov,_seekerWavelengths,_seekerCode);
_spots = [];
_buckets = [];
_excludes = [];
_bucketIndex = 0;
_finalPos = nil;
_finalOwner = nil;
private _spots = [];
private _finalPos = nil;
private _finalOwner = objNull;
// Go through all lasers in GVAR(laserEmitters)
{
_obj = _x select 0;
_owner = _x select 1;
_method = _x select 2;
_emitterWavelength = _x select 3;
_laserCode = _x select 4;
_divergence = _x select 5;
if(alive _obj && {_emitterWavelength >= (_seekerWavelengths select 0)} && {_emitterWavelength <= (_seekerWavelengths select 1)} && {_laserCode == _seekerCode}) then {
_laser = [];
if(IS_CODE(_method)) then {
_laser = _x call _method;
_x params ["_obj", "_owner", "_laserMethod", "_emitterWavelength", "_laserCode", "_divergence"];
TRACE_6("laser",_obj,_owner,_laserMethod,_emitterWavelength,_laserCode,_divergence);
if (alive _obj && {_emitterWavelength >= _seekerWavelengthMin} && {_emitterWavelength <= _seekerWavelengthMax} && {_laserCode == _seekerCode}) then {
private _laser = [];
// Find laser pos and dir of the laser depending on type
if (IS_STRING(_laserMethod)) then {
_laser = _x call (missionNamespace getVariable [_laserMethod, []]);
} else {
if(IS_STRING(_method)) then {
_laser = _x call (missionNamespace getVariable [_method, {}]);
if (IS_CODE(_laserMethod)) then {
_laser = _x call _laserMethod;
} else {
if(IS_ARRAY(_method)) then {
if(count _method == 2) then {
_laser = [ATLtoASL (_obj modelToWorldVisual (_method select 0)), _obj weaponDirection (_method select 1)];
if (IS_ARRAY(_laserMethod)) then {
if (count _laserMethod == 2) then { // [modelPosition, weaponName] for _obj
_laser = [AGLtoASL (_obj modelToWorldVisual (_laserMethod select 0)), _obj weaponDirection (_laserMethod select 1)];
} else {
if(count _method == 3) then {
_laser = [ATLtoASL (_obj modelToWorldVisual (_method select 0)), (ATLtoASL (_obj modelToWorldVisual (_method select 1))) vectorFromTo (ATLtoASL (_obj modelToWorldVisual (_method select 2)))];
if (count _laserMethod == 3) then {
_laser = [AGLtoASL (_obj modelToWorldVisual (_laserMethod select 0)), (AGLtoASL (_obj modelToWorldVisual (_laserMethod select 1))) vectorFromTo (AGLtoASL (_obj modelToWorldVisual (_laserMethod select 2)))];
};
};
};
};
};
//Handle Weird Data Return
if (_laser params [["_laserPos", [], [[]], 3], ["_laserDir", [], [[]], 3]]) then {
_res = [_laserPos, _laserDir, _divergence] call FUNC(shootCone);
TRACE_1("",_laser);
//Handle Weird Data Return - skips over this laser in the for loop
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;
_testPointVector = vectorNormalized (_testPoint vectorDiff _pos);
_testDotProduct = _dir vectorDotProduct _testPointVector;
if(_testDotProduct > _seekerCos) then {
private _testPointVector = _posASL vectorFromTo _testPoint;
private _testDotProduct = _dir vectorDotProduct _testPointVector;
if (_testDotProduct > _seekerCos) then {
_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 {
_bucketPos = nil;
_bucketList = nil;
_c = 0;
TRACE_2("",count _spots, _spots);
if ((count _spots) > 0) then {
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 {
scopeName "mainSearch";
{
if(!(_forEachIndex in _excludes)) then {
_index = _buckets pushBack [_x, [_x]];
if (!(_forEachIndex in _excludes)) then {
private _index = _buckets pushBack [_x, [_x]];
_excludes pushBack _forEachIndex;
_bucketPos = _x select 0;
_bucketList = (_buckets select _index) select 1;
@ -94,9 +118,9 @@ if((count _spots) > 0) then {
};
} forEach _spots;
{
if(!(_forEachIndex in _excludes)) then {
_testPos = (_x select 0);
if(_testPos vectorDistanceSqr _bucketPos <= 100) then {
if (!(_forEachIndex in _excludes)) then {
private _testPos = (_x select 0);
if ((_testPos vectorDistanceSqr _bucketPos) <= 100) then {
_bucketList pushBack _x;
_excludes pushBack _forEachIndex;
};
@ -104,55 +128,71 @@ if((count _spots) > 0) then {
} forEach _spots;
_c = _c + 1;
};
_finalBuckets = [];
_largest = -1;
_largestIndex = 0;
TRACE_1("",_buckets);
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;
{
_testPos = (_x select 0);
if(!terrainIntersectASL [_pos, _testPos] && {!lineIntersects [_pos, _testPos]}) then {
private _testPos = (_x select 0) vectorAdd [0,0,0.05];
private _testIntersections = lineIntersectsSurfaces [_posASL, _testPos, _ignoreObj1];
if ([] isEqualTo _testIntersections) then {
_bucketList pushBack _x;
};
} forEach (_x select 1);
if((count _bucketList) > _largest) then {
if ((count _bucketList) > _largest) then {
_largest = (count _bucketList);
_largestIndex = _index;
};
} forEach _buckets;
_finalBucket = _finalBuckets select _largestIndex;
_owners = [] call CBA_fnc_hashCreate;
private _finalBucket = _finalBuckets select _largestIndex;
private _ownersHash = [] call CBA_fnc_hashCreate;
if(count _finalBucket > 0) then {
_avgX = 0;
_avgY = 0;
_avgZ = 0;
TRACE_2("",_finalBucket,_finalBuckets);
if (count _finalBucket > 0) then {
// 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];
_avgX = _avgX + ((_x select 0) select 0);
_avgY = _avgY + ((_x select 0) select 1);
_avgZ = _avgZ + ((_x select 0) select 2);
_owner = _x select 1;
if ([_owners, _owner] call CBA_fnc_hashHasKey) then {
private _count = [_owners, _owner] call CBA_fnc_hashGet;
[_owners, _owner, _count + 1] call CBA_fnc_hashSet;
_x params ["_xPos", "_owner"];
_finalPos = _finalPos vectorAdd _xPos;
if ([_ownersHash, _owner] call CBA_fnc_hashHasKey) then {
private _count = [_ownersHash, _owner] call CBA_fnc_hashGet;
[_ownersHash, _owner, _count + 1] call CBA_fnc_hashSet;
} else {
[_owners, _owner, 1] call CBA_fnc_hashSet;
[_ownersHash, _owner, 1] call CBA_fnc_hashSet;
};
} forEach _finalBucket;
_count = count _finalBucket;
_finalPos = [_avgX/_count, _avgY/_count, _avgZ/_count];
_maxOwner = -1;
_maxOwnerIndex = 0;
{
if((_owners select 1) select _forEachIndex > _maxOwner) then {
_maxOwner = (_owners select 1) select _forEachIndex;
_maxOwnerIndex = _forEachIndex;
_finalPos = _finalPos vectorMultiply (1 / (count _finalBucket));
private _maxOwnerCount = -1;
[_ownersHash, {
if (_value > _maxOwnerCount) then {
_finalOwner = _key;
};
} forEach (_owners select 0);
_finalOwner = (_owners select 0) select _maxOwnerIndex;
}] call CBA_fnc_hashEachPair;
};
};
[_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
private ["_i", "_divergence","_pos","_vec","_longestReturn","_shortestReturn","_resultPositions","_p1","_p2","_p","_v","_cp","_vecRotateMap","_result", "_resultPos","_distance","_count","_pos2","_radOffset","_offset","_offsetPos","_offsetVector"];
_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;
#include "script_component.hpp"
_vecRotateMap = [_cp, _p1, _p2] call FUNC(rotateVectLineGetMap);
BEGIN_COUNTER(shootCone);
_result = [_pos, _vec] call FUNC(shootRay);
_resultPos = _result select 0;
if(!isNil "_resultPos") then {
_distance = _result select 1;
if(_distance < _shortestReturn) then {
_shortestReturn = _distance;
};
if(_distance > _longestReturn) then {
_longestReturn = _distance;
};
params ["_pos", "_vec", ["_divergence", 0.3], ["_count", 3], ["_ignoreObj1", objNull]];
private _longestReturn = -1000000000;
private _shortestReturn = 1000000000;
private _resultPositions = [];
private _p1 = [0,0,0];
private _p2 = +_vec;
private _p = (_vec call CBA_fnc_vect2polar);
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;
#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
};
_pos2 = _pos vectorAdd (_vec vectorMultiply 1000);
private _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 {
_radOffset = random 360;
_offset = [_vecRotateMap, (((360/_count)*_i)+_radOffset) mod 360] call FUNC(rotateVectLine);
_offsetPos = _pos2 vectorAdd (_offset vectorMultiply (_divergence*_x));
_offsetVector = _pos vectorFromTo _offsetPos;
_result = [_pos, _offsetVector] call FUNC(shootRay);
private _radOffset = random 360;
for "_i" from 1 to ceil(_count*_x) do { // Will always do at least 1
private _offset = [_vecRotateMap, (((360/_count)*_i)+_radOffset) mod 360] call FUNC(rotateVectLine);
private _offsetPos = _pos2 vectorAdd (_offset vectorMultiply (_divergence*_x));
private _offsetVector = _pos vectorFromTo _offsetPos;
_result = [_pos, _offsetVector, _ignoreObj1] call FUNC(shootRay);
_resultPos = _result select 0;
if(!isNil "_resultPos") then {
_distance = _result select 1;
if(_distance < _shortestReturn) then {
_shortestReturn = _distance;
};
if(_distance > _longestReturn) then {
_longestReturn = _distance;
};
if (!isNil "_resultPos") then {
private _distance = _result select 1;
if (_distance < _shortestReturn) then { _shortestReturn = _distance; };
if (_distance > _longestReturn) then { _longestReturn = _distance; };
_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];
[_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"
private ["_pos", "_vec", "_distance", "_resultPos", "_fidelity", "_lastPos", "_i", "_nextPos"];
scopeName "main";
_pos = _this select 0;
_vec = _this select 1;
_distance = 0;
_resultPos = nil;
_fidelity = [1000,100,10,1,0.1];
_lastPos = +_pos;
{
scopeName "mainSearch";
for "_i" from 1 to 10 do {
_nextPos = _lastPos vectorAdd (_vec vectorMultiply _x);
if(terrainIntersectASL [_lastPos, _nextPos] || {lineIntersects [_lastPos, _nextPos]}) then {
_resultPos = _lastPos;
breakTo "mainSearch";
} else {
_distance = _distance + _x;
_lastPos = _nextPos;
};
};
} forEach _fidelity;
[_resultPos, _distance];
BEGIN_COUNTER(shootRay);
params ["_posASL", "_dir", ["_ignoreVehicle1", objNull], ["_ignoreVehicle2", objNull]];
// TRACE_2("ray origin:", _posASL, _dir);
private _distance = 0;
private _resultPos = nil;
private _farPoint = _posASL vectorAdd (_dir vectorMultiply 10000);
private _intersects = lineIntersectsSurfaces [_posASL, _farPoint, _ignoreVehicle1, _ignoreVehicle2];
if (!(_intersects isEqualTo [])) then {
(_intersects select 0) params ["_intersectPosASL", "", "_intersectObject"];
// Move back slightly to prevents issues with it going below terrain
_distance = (_posASL vectorDistance _intersectPosASL) - 0.005;
_resultPos = _posASL vectorAdd (_dir vectorMultiply _distance);
};
TRACE_3("", _resultPos, _distance, _intersects);
#ifdef DRAW_LASER_INFO
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),
{
if( EGVAR(laser_selfdesignate,active)
||
{ (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);
};
[1] call FUNC(keyLaserCodeChange);
},
{false},
[16, [false, true, true]], false, 0] call CBA_fnc_addKeybind; // (ALT+CTRL+Q)
["ACE3 Equipment", QGVAR(LaserCodeDown), localize LSTRING(laserCodeDown),
{
if( EGVAR(laser_selfdesignate,active)
||
{ (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);
};
[-1] call FUNC(keyLaserCodeChange);
},
{false},
[18, [false, true, true]], false, 0] call CBA_fnc_addKeybind; // (ALT+CTRL+E)

View File

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

View File

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

@ -16,13 +16,17 @@ GVAR(nearUnits) = [];
// @todo. Maybe move to common?
[{
// handle RHS / bugged vehicle slots
private _camPosAGL = positionCameraToWorld [0,0,0];
if !((_camPosAGL select 0) isEqualType 0) exitWith {};
private _nearUnits = [];
{
_nearUnits append crew _x;
if (count _nearUnits > 10) exitWith {
_nearUnits resize 10;
};
} forEach nearestObjects [positionCameraToWorld [0,0,0], ["AllVehicles"], 50]; // when moving this, search also for units inside vehicles. currently breaks the laser in FFV
} forEach nearestObjects [_camPosAGL, ["AllVehicles"], 50]; // when moving this, search also for units inside vehicles. currently breaks the laser in FFV
GVAR(nearUnits) = _nearUnits;

View File

@ -7,4 +7,11 @@ class ACE_Settings {
description = CSTRING(rotateModifierKey_description);
values[] = {"$STR_A3_OPTIONS_DISABLED", "ALT", "CTRL", "SHIFT"};
};
class GVAR(drawStaightLines) {
value = 1;
typeName = "BOOL";
isClientSettable = 1;
displayName = CSTRING(drawStaightLines_displayName);
description = CSTRING(drawStaightLines_description);
};
};

View File

@ -1,6 +1,7 @@
PREP(calculateMapScale);
PREP(canUseMapGPS);
PREP(canUseMapTools);
PREP(drawLinesOnRoamer);
PREP(handleMouseButton);
PREP(handleMouseMove);
PREP(isInsideMapTool);

View File

@ -30,5 +30,13 @@ GVAR(mapTool_isRotating) = false;
} else {
// Hide GPS
[false] call FUNC(openMapGps);
// Handle closing map in middle of line drawing (it's never created)
GVAR(freedrawing) = false;
};
}] call CBA_fnc_addPlayerEventHandler;
GVAR(freeDrawingData) = [];
GVAR(freedrawing) = false;

View File

@ -0,0 +1,144 @@
/*
* Author: PabstMirror
* Prevents the cursor from entering the roamer when drawing lines and records the positions
*
* Arguments:
* 0: The Map <CONTROL>
* 1: Roamer Width <NUMBER>
*
* Return Value:
* Nothing
*
* Example:
* [map, 300] call ace_maptools_fnc_drawLinesOnRoamer
*
* Public: No
*/
#include "script_component.hpp"
if (!GVAR(drawStaightLines)) exitWith {};
params ["_theMap", "_roamerWidth"];
GVAR(mapTool_pos) params ["_roamerPosX", "_roamerPosY"];
private _posCenter = [_roamerPosX, _roamerPosY, 0];
private _posTopRight = [
_roamerPosX + (cos GVAR(mapTool_angle)) * DIST_LEFT_TO_CENTER_PERC * _roamerWidth + (sin GVAR(mapTool_angle)) * DIST_TOP_TO_CENTER_PERC * _roamerWidth,
_roamerPosY + (-sin GVAR(mapTool_angle)) * DIST_LEFT_TO_CENTER_PERC * _roamerWidth + (cos GVAR(mapTool_angle)) * DIST_TOP_TO_CENTER_PERC * _roamerWidth,
0];
private _posTopLeft = [
_roamerPosX + (-cos GVAR(mapTool_angle)) * DIST_LEFT_TO_CENTER_PERC * _roamerWidth + (sin GVAR(mapTool_angle)) * DIST_TOP_TO_CENTER_PERC * _roamerWidth,
_roamerPosY + (sin GVAR(mapTool_angle)) * DIST_LEFT_TO_CENTER_PERC * _roamerWidth + (cos GVAR(mapTool_angle)) * DIST_TOP_TO_CENTER_PERC * _roamerWidth,
0];
private _posBottomLeft = [
_roamerPosX + (-cos GVAR(mapTool_angle)) * DIST_LEFT_TO_CENTER_PERC * _roamerWidth + (sin GVAR(mapTool_angle)) * DIST_BOTTOM_TO_CENTER_PERC * _roamerWidth,
_roamerPosY + (sin GVAR(mapTool_angle)) * DIST_LEFT_TO_CENTER_PERC * _roamerWidth + (cos GVAR(mapTool_angle)) * DIST_BOTTOM_TO_CENTER_PERC * _roamerWidth,
0];
private _posBottomRight = [
_roamerPosX + (cos GVAR(mapTool_angle)) * DIST_LEFT_TO_CENTER_PERC * _roamerWidth + (sin GVAR(mapTool_angle)) * DIST_BOTTOM_TO_CENTER_PERC * _roamerWidth,
_roamerPosY + (-sin GVAR(mapTool_angle)) * DIST_LEFT_TO_CENTER_PERC * _roamerWidth + (cos GVAR(mapTool_angle)) * DIST_BOTTOM_TO_CENTER_PERC * _roamerWidth,
0];
private _fnc_Distance = { // Get distance point _p is from a line made from _a to _b (uses 3d array commands, but z should be 0)
// Ref: https://en.wikipedia.org/wiki/Distance_from_a_point_to_a_line#Vector_formulation
params ["_a", "_b", "_p"];
private _n = _b vectorDiff _a;
private _pa = _a vectorDiff _p;
private _c = _n vectorMultiply ((_pa vectorDotProduct _n) / (_n vectorDotProduct _n));
private _d = _pa vectorDiff _c;
sqrt (_d vectorDotProduct _d);
};
private _currentMousePos = _theMap ctrlMapScreenToWorld getMousePosition;
_currentMousePos set [2, 0];
// Break the roamer rectangle into 4 triangle, one for each side
switch (true) do {
case (_currentMousePos inPolygon [_posCenter, _posTopLeft, _posBottomLeft]): { // Left
private _distanceToRoamerLine = ([_posTopLeft, _posBottomLeft, _currentMousePos] call _fnc_Distance);
_currentMousePos = _currentMousePos vectorAdd ([_distanceToRoamerLine, (GVAR(mapTool_angle) - 90) ,0] call CBA_fnc_polar2vect);
if (GVAR(freeDrawingData) isEqualTo []) then { // We start drawing on the line
GVAR(freeDrawingData) = ["left", _currentMousePos, _currentMousePos];
} else {
if ((GVAR(freeDrawingData) select 0) == "left") then { // We are already drawing on this line, find best spot
if ((_currentMousePos distance2d _posTopLeft) < ((GVAR(freeDrawingData) select 1) distance2d _posTopLeft)) then {
GVAR(freeDrawingData) set [1, _currentMousePos];
};
if ((_currentMousePos distance2d _posBottomLeft) < ((GVAR(freeDrawingData) select 2) distance2d _posBottomLeft)) then {
GVAR(freeDrawingData) set [2, _currentMousePos];
};
};
};
private _screenPosOfCorrectedPos = _theMap ctrlMapWorldToScreen _currentMousePos;
setMousePosition _screenPosOfCorrectedPos;
};
case (_currentMousePos inPolygon [_posCenter, _posTopLeft, _posTopRight]): { // Top
private _distanceToRoamerLine = ([_posTopLeft, _posTopRight, _currentMousePos] call _fnc_Distance);
_currentMousePos = _currentMousePos vectorAdd ([_distanceToRoamerLine, (GVAR(mapTool_angle) + 0) ,0] call CBA_fnc_polar2vect);
if (GVAR(freeDrawingData) isEqualTo []) then { // We start drawing on the line
GVAR(freeDrawingData) = ["top", _currentMousePos, _currentMousePos];
} else {
if ((GVAR(freeDrawingData) select 0) == "top") then { // We are already drawing on this line, find best spot
if ((_currentMousePos distance2d _posTopLeft) < ((GVAR(freeDrawingData) select 1) distance2d _posTopLeft)) then {
GVAR(freeDrawingData) set [1, _currentMousePos];
};
if ((_currentMousePos distance2d _posTopRight) < ((GVAR(freeDrawingData) select 2) distance2d _posTopRight)) then {
GVAR(freeDrawingData) set [2, _currentMousePos];
};
};
};
private _screenPosOfCorrectedPos = _theMap ctrlMapWorldToScreen _currentMousePos;
setMousePosition _screenPosOfCorrectedPos;
};
case (_currentMousePos inPolygon [_posCenter, _posTopRight, _posBottomRight]): { // Right
private _distanceToRoamerLine = ([_posTopRight, _posBottomRight, _currentMousePos] call _fnc_Distance);
_currentMousePos = _currentMousePos vectorAdd ([_distanceToRoamerLine, (GVAR(mapTool_angle) + 90) ,0] call CBA_fnc_polar2vect);
if (GVAR(freeDrawingData) isEqualTo []) then { // We start drawing on the line
GVAR(freeDrawingData) = ["right", _currentMousePos, _currentMousePos];
} else {
if ((GVAR(freeDrawingData) select 0) == "right") then { // We are already drawing on this line, find best spot
if ((_currentMousePos distance2d _posTopRight) < ((GVAR(freeDrawingData) select 1) distance2d _posTopRight)) then {
GVAR(freeDrawingData) set [1, _currentMousePos];
};
if ((_currentMousePos distance2d _posBottomRight) < ((GVAR(freeDrawingData) select 2) distance2d _posBottomRight)) then {
GVAR(freeDrawingData) set [2, _currentMousePos];
};
};
};
private _screenPosOfCorrectedPos = _theMap ctrlMapWorldToScreen _currentMousePos;
setMousePosition _screenPosOfCorrectedPos;
};
case (_currentMousePos inPolygon [_posCenter, _posBottomLeft, _posBottomRight]): { // Bottom
private _distanceToRoamerLine = ([_posBottomLeft, _posBottomRight, _currentMousePos] call _fnc_Distance);
_currentMousePos = _currentMousePos vectorAdd ([_distanceToRoamerLine, (GVAR(mapTool_angle) + 180) ,0] call CBA_fnc_polar2vect);
if (GVAR(freeDrawingData) isEqualTo []) then { // We start drawing on the line
GVAR(freeDrawingData) = ["bottom", _currentMousePos, _currentMousePos];
} else {
if ((GVAR(freeDrawingData) select 0) == "bottom") then { // We are already drawing on this line, find best spot
if ((_currentMousePos distance2d _posBottomLeft) < ((GVAR(freeDrawingData) select 1) distance2d _posBottomLeft)) then {
GVAR(freeDrawingData) set [1, _currentMousePos];
};
if ((_currentMousePos distance2d _posBottomRight) < ((GVAR(freeDrawingData) select 2) distance2d _posBottomRight)) then {
GVAR(freeDrawingData) set [2, _currentMousePos];
};
};
};
private _screenPosOfCorrectedPos = _theMap ctrlMapWorldToScreen _currentMousePos;
setMousePosition _screenPosOfCorrectedPos;
};
};
#ifdef DEBUG_MODE_FULL
_theMap drawIcon ['iconStaticMG',[1,0,0,1],_posTopRight,24,24,getDir player,'1,1',1,0.03,'TahomaB','right'];
_theMap drawIcon ['iconStaticMG',[1,0,0,1],_posTopLeft,24,24,getDir player,'-1,1',1,0.03,'TahomaB','right'];
_theMap drawIcon ['iconStaticMG',[1,0,0,1],_posBottomLeft,24,24,getDir player,'-1,-1',1,0.03,'TahomaB','right'];
_theMap drawIcon ['iconStaticMG',[1,0,0,1],_posBottomRight,24,24,getDir player,'1,-1',1,0.03,'TahomaB','right'];
if !(GVAR(freeDrawingData) isEqualTo []) then {
_theMap drawIcon ['iconStaticMG',[0,0,1,1],GVAR(freeDrawingData) select 1,24,24,getDir player,'1,-1',1,0.03,'TahomaB','right'];
_theMap drawIcon ['iconStaticMG',[0,0,1,1],GVAR(freeDrawingData) select 2,24,24,getDir player,'1,-1',1,0.03,'TahomaB','right'];
};
#endif

View File

@ -15,6 +15,51 @@ params ["_dir", "_params"];
_params params ["_control", "_button", "_screenPosX", "_screenPosY", "_shiftKey", "_ctrlKey", "_altKey"];
TRACE_2("params",_dir,_params);
// Using line drawing
if ((_button == 0) && {GVAR(freedrawing) || _ctrlKey}) exitWith {
if (GVAR(freedrawing) && {_dir == 0}) then {
GVAR(freedrawing) = false;
GVAR(drawPosEnd) = _control ctrlMapScreenToWorld [_screenPosX, _screenPosY];
TRACE_1("Ending Line",GVAR(freedrawing),GVAR(drawPosEnd));
[{
if (allMapMarkers isEqualTo []) exitWith {};
private _markerName = allMapMarkers select (count allMapMarkers - 1);
private _markerPos = getMarkerPos _markerName;
private _distanceCheck = _markerPos distance2d GVAR(drawPosStart);
TRACE_3("Line Drawn",_markerName,_markerPos,_distanceCheck);
if (_distanceCheck > 1) exitWith {WARNING("Wrong Marker!");};
if ((count GVAR(freeDrawingData)) != 3) exitWith {TRACE_1("never touched roamer",GVAR(freeDrawingData));};
GVAR(freeDrawingData) params ["", "_startStraightPos", "_endStraightPos"];
_startStraightPos set [2, 0];
_endStraightPos set [2, 0];
// Convert marker to rectangle and change it's pos/size/dir
_markerName setMarkerShape "RECTANGLE";
private _difPos = _endStraightPos vectorDiff _startStraightPos;
private _mag = vectorMagnitude _difPos;
_markerName setMarkerPos (_startStraightPos vectorAdd (_difPos vectorMultiply 0.5));
_markerName setMarkerSize [10, _mag / 2];
_markerName setMarkerDir (_difPos call CBA_fnc_vectDir);
}, []] call CBA_fnc_execNextFrame;
} else {
if (_ctrlKey && {_dir == 1}) then {
GVAR(freeDrawingData) = [];
GVAR(freedrawing) = true;
GVAR(drawPosStart) = _control ctrlMapScreenToWorld [_screenPosX, _screenPosY];
TRACE_2("Starting Line",GVAR(freedrawing),GVAR(drawPosStart));
} else {
GVAR(freedrawing) = false;
TRACE_1("weird - reseting",GVAR(freedrawing));
};
};
false
};
private _handled = false;
// If it's not a left button event, exit

View File

@ -11,11 +11,6 @@
*/
#include "script_component.hpp"
#define TEXTURE_WIDTH_IN_M 6205
#define DIST_BOTTOM_TO_CENTER_PERC -0.33
#define DIST_TOP_TO_CENTER_PERC 0.65
#define DIST_LEFT_TO_CENTER_PERC 0.30
if (GVAR(mapTool_Shown) == 0) exitWith {false};
private _textureWidth = [TEXTURE_WIDTH_IN_M, TEXTURE_WIDTH_IN_M / 2] select (GVAR(mapTool_Shown) - 1);

View File

@ -12,10 +12,6 @@
*/
#include "script_component.hpp"
#define TEXTURE_WIDTH_IN_M 6205
#define CENTER_OFFSET_Y_PERC 0.1606
#define CONSTANT_SCALE 0.2
params ["_theMap"];
if ((GVAR(mapTool_Shown) == 0) || {!("ACE_MapTools" in items ACE_player)}) exitWith {};
@ -30,6 +26,8 @@ if (GVAR(mapTool_Shown) == 1) then {
_textureWidth = TEXTURE_WIDTH_IN_M / 2;
};
if (GVAR(freedrawing)) then {[_theMap, _textureWidth] call FUNC(drawLinesOnRoamer);};
// Update scale of both parts
getResolution params ["_resWidth", "_resHeight", "", "", "_aspectRatio"];
private _scaleX = 32 * _textureWidth * CONSTANT_SCALE * (call FUNC(calculateMapScale));

View File

@ -15,3 +15,10 @@
#endif
#include "\z\ace\addons\main\script_macros.hpp"
#define TEXTURE_WIDTH_IN_M 6205
#define CENTER_OFFSET_Y_PERC 0.1606
#define CONSTANT_SCALE 0.2
#define DIST_BOTTOM_TO_CENTER_PERC -0.33
#define DIST_TOP_TO_CENTER_PERC 0.65
#define DIST_LEFT_TO_CENTER_PERC 0.30

View File

@ -158,5 +158,11 @@
<Japanese>マップ ツールを回転させるキーを編集できます。</Japanese>
<Polish>Modyfikator pozwalający na obracanie narzędzi nawigacyjnych</Polish>
</Key>
<Key ID="STR_ACE_MapTools_drawStaightLines_displayName">
<English>Draw straight lines with maptools</English>
</Key>
<Key ID="STR_ACE_MapTools_drawStaightLines_description">
<English>Draw on the edge of maptools to draw straight lines. Note: Must hover at midpoint to delete.</English>
</Key>
</Package>
</Project>

View File

@ -1,44 +1,7 @@
enum {
ACE_LOBL = 1,
ACE_LOAL = 2
};
class CfgAmmo {
class 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 M_PG_AT: MissileBase {};
class ACE_Hydra70_DAGR: M_PG_AT {
displayName = CSTRING(Hydra70_DAGR);
@ -47,13 +10,18 @@ class CfgAmmo {
description = CSTRING(Hydra70_DAGR_Desc);
descriptionShort = CSTRING(Hydra70_DAGR_Desc);
irLock = 0;
laserLock = 0;
manualControl = 0;
maxSpeed = 300;
EGVAR(rearm,caliber) = 70;
class ADDON {
enabled = 1;
minDeflection = 0.00025; // Minium flap deflection for guidance
maxDeflection = 0.001; // Maximum flap deflection for guidance
minDeflection = 0.0005; // Minium flap deflection for guidance
maxDeflection = 0.0025; // Maximum flap deflection for guidance
incDeflection = 0.0005; // The incrmeent in which deflection adjusts.
canVanillaLock = 0; // Can this default vanilla lock? Only applicable to non-cadet mode

View File

@ -1,24 +1,20 @@
class CfgVehicles {
class AllVehicles;
class Air: AllVehicles {
class Air;
class Helicopter: Air {
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 Helicopter_Base_F: Helicopter {
class Turrets: Turrets {
class MainTurret;
};
};
class ACE_Comanche_Test : B_Heli_Attack_01_F {
class Heli_Attack_01_base_F: Helicopter_Base_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;
scopeCurator = 0;
displayName = "ACE_Comanche_Test";
@ -28,9 +24,9 @@ class CfgVehicles {
};
class Turrets: Turrets {
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 CannonCore;
class LauncherCore;
class missiles_DAGR;
class RocketPods: LauncherCore {
// canLock = 1;
};
class missiles_DAGR : RocketPods {
canLock = 2;
class GVAR(dagr): missiles_DAGR {
canLock = 0;
magazines[] = {"6Rnd_ACE_Hydra70_DAGR","12Rnd_ACE_Hydra70_DAGR","24Rnd_ACE_Hydra70_DAGR"};
lockingTargetSound[] = {"",0,1};
lockedTargetSound[] = {"",0,1};
};
};

View File

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

View File

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

View File

@ -2,8 +2,8 @@
#include "script_component.hpp"
EXPLODE_7_PVT(((_this select 1) select 0),_shooter,_weapon,_muzzle,_mode,_ammo,_magazine,_projectile);
private ["_targetPos", "_projectilePos", "_target", "_seekerTargetPos", "_launchParams", "_targetLaunchParams"];
private ["_distanceToTarget", "_distanceToShooter", "_addHeight", "_returnTargetPos", "_shooterPos"];
private["_targetPos", "_projectilePos", "_target", "_seekerTargetPos", "_launchParams", "_targetLaunchParams"];
private["_distanceToTarget", "_distanceToShooter", "_addHeight", "_returnTargetPos", "_shooterPos"];
_seekerTargetPos = _this select 0;
_launchParams = _this select 1;
@ -13,7 +13,7 @@ _targetLaunchParams = _launchParams select 1;
_shooterPos = getPosASL _shooter;
_projectilePos = getPosASL _projectile;
_distanceToTarget = _projectilePos vectorDistance _seekerTargetPos;
_distanceToTarget = _projectilePos vectorDistance _seekerTargetPos;
_distanceToShooter = _projectilePos vectorDistance _shooterPos;
TRACE_3("", _distanceToTarget, _distanceToShooter, _seekerTargetPos);
@ -22,7 +22,7 @@ TRACE_3("", _distanceToTarget, _distanceToShooter, _seekerTargetPos);
_addHeight = [0,0,0];
// 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];
} else {
// 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;
#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
TRACE_1("Adjusted target position", _returnTargetPos);
_returnTargetPos;
_returnTargetPos;

View File

@ -58,7 +58,7 @@ _adjustVector = _targetVector vectorDiff (vectorDir _projectile);
_yaw = 0;
_pitch = 0;
_roll = 0;
_roll = 0;
if((_adjustVector select 0) < 0) then {
_yaw = - ( (_minDeflection max (abs(_adjustVector select 0) min _maxDeflection) ) );
} else {
@ -90,17 +90,17 @@ if(accTime > 0) then {
};
#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"];
drawLine3D [ASLtoATL _projectilePos, ASLtoATL _profileAdjustedTargetPos, [1,0,0,1]];
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 [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 setDropInterval 3.0;
hintSilent format["d: %1", _distanceToTarget];
//hintSilent format["d: %1", _distanceToTarget];
#endif
_stateParams set[0, diag_tickTime];
_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"
EXPLODE_7_PVT(((_this select 1) select 0),_shooter,_weapon,_muzzle,_mode,_ammo,_magazine,_projectile);
private ["_angleFov", "_canSeeTarget", "_foundTargetPos", "_laserResult", "_launchParams", "_seekerParams", "_laserCode", "_laserParams", "_seekerTargetPos", "_sensorPos", "_target"];
_seekerTargetPos = _this select 0;
_launchParams = _this select 1;
_seekerParams = _launchParams select 3;
_angleFov = _seekerParams select 0;
params ["_lastSeekTargetPos", "_args"];
_args params ["_firedEH", "_launchParams", "_flightParams", "_seekerParams", "_stateParams"];
_firedEH params ["_shooter","_weapon","_muzzle","_mode","_ammo","_magazine","_projectile"];
_launchParams params ["","","","","","_laserParams"];
_seekerParams params ["_seekerAngle", "", "_seekerMaxRange"];
_laserParams params ["_code", "_wavelengthMin", "_wavelengthMax"];
_laserParams = (_launchParams select 1) select 5;
TRACE_2("", _launchParams, _laserParams);
if(!isNil "_target") then {
private "_foundTargetPos";
if (!isNil "_target") then {
// Handle AI or moving vanilla lasers
_foundTargetPos = getPosASL _target;
} 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;
TRACE_1("Search", _laserResult);
};
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(!_canSeeTarget) then {
_foundTargetPos = _sensorPos vectorAdd ((velocity _projectile) vectorMultiply 5);
};
};
_foundTargetPos;
_foundTargetPos;

View File

@ -46,8 +46,8 @@ if (_lastFireMode != -1) then {
[{
private ["_chargeText", "_currentChargeMode", "_currentFireMode", "_display", "_elevDeg", "_elevationDiff", "_lookVector", "_notGunnerView", "_realAzimuth", "_realElevation", "_upVectorDir", "_useMils", "_weaponDir"];
PARAMS_2(_args,_pfID);
EXPLODE_2_PVT(_args,_mortarVeh,_fireModes);
params ["_args", "_pfID"];
_args params ["_mortarVeh", "_fireModes"];
if ((vehicle ACE_player) != _mortarVeh) then {
[_pfID] call CBA_fnc_removePerFrameHandler;
@ -80,7 +80,19 @@ if (_lastFireMode != -1) then {
//(looking at the sky VS looking at ground will radicaly change fire direction because BIS)
_realAzimuth = -1;
_realElevation = -1;
if ((ctrlText (_display displayCtrl 173)) == "--") then {
private _useRealWeaponDir = (ctrlText (_display displayCtrl 173)) == "--";
if (_useRealWeaponDir && {(_mortarVeh ammo (currentWeapon _mortarVeh)) == 0}) then {
// With no ammo, distance display will be empty, but gun will still fire at wonky angle if aimed at ground
private _testSeekerPosASL = AGLtoASL (positionCameraToWorld [0,0,0]);
private _testSeekerDir = _testSeekerPosASL vectorFromTo (AGLtoASL (positionCameraToWorld [0,0,1]));
private _laserRange = [_testSeekerPosASL, _testSeekerDir, _mortarVeh] call EFUNC(laser,shootRay);
_laserRange params ["", ["_rayDistance", -5]]; // ToDo: move shootRay to common
TRACE_2("",_rayDistance,viewDistance);
_useRealWeaponDir = _rayDistance > viewDistance; // If we are looking at infinity (based on viewDistance)
};
if (_useRealWeaponDir) then {
//No range (looking at sky), it will follow weaponDir:
_weaponDir = _mortarVeh weaponDirection (currentWeapon _mortarVeh);
_realAzimuth = (_weaponDir select 0) atan2 (_weaponDir select 1);

View File

@ -68,6 +68,8 @@ private _ambientBrightness = ((([] call EFUNC(common,ambientBrightness)) + ([0,
private _maxDistance = _ambientBrightness * GVAR(PlayerNamesViewDistance);
private _camPosAGL = positionCameraToWorld [0, 0, 0];
if !((_camPosAGL select 0) isEqualType 0) exitWith {}; // handle RHS / bugged vehicle slots
private _camPosASL = AGLtoASL _camPosAGL;
private _vecy = (AGLtoASL positionCameraToWorld [0, 0, 1]) vectorDiff _camPosASL;

View File

@ -377,9 +377,10 @@ class CfgVehicles {
class HitBody {
armor = 0.6;
material = -1;
name = "zbytek";
name = "mat_rim";
visual = "mat_rim";
passThrough = 1;
radius = 0.1;
explosionShielding = 1;
};
};

Binary file not shown.

Binary file not shown.

View File

@ -6,15 +6,11 @@ class CfgSkeletons {
};
class ace_wheel: Default {
skeletonBones[] = {
"zbytek", ""
};
skeletonBones[] = {};
};
class ace_track: Default {
skeletonBones[] = {
"zbytek", ""
};
skeletonBones[] = {};
};
};

View File

@ -33,7 +33,7 @@ GVAR(distanceIndex) = -1;
[_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 = _distance - 1 + (random 2);

Some files were not shown because too many files have changed in this diff Show More