2015-04-05 19:08:55 +00:00
/*
* Author: Glowbal, Ruthberg
2015-04-07 19:46:43 +00:00
*
* Handles advanced ballistics for (BulletBase) projectiles
2015-04-05 19:08:55 +00:00
*
* Arguments:
* 0: unit - Object the event handler is assigned to <OBJECT>
* 1: weapon - Fired weapon <STRING>
* 2: muzzle - Muzzle that was used <STRING>
* 3: mode - Current mode of the fired weapon <STRING>
* 4: ammo - Ammo used <STRING>
* 5: magazine - magazine name which was used <STRING>
* 6: projectile - Object of the projectile that was shot <OBJECT>
*
* Return Value:
* Nothing
*
* Public: No
*/
#include "script_component.hpp"
2015-04-24 09:53:06 +00:00
private ["_unit", "_weapon", "_mode", "_ammo", "_magazine", "_caliber", "_bullet", "_abort", "_index", "_opticsName", "_opticType", "_bulletTraceVisible", "_temperature", "_barometricPressure", "_atmosphereModel", "_bulletMass", "_bulletLength", "_airFriction", "_dragModel", "_muzzleVelocity", "_muzzleVelocityCoef", "_muzzleAccessory", "_initSpeedCoef", "_muzzleVelocityShift", "_bulletVelocity", "_bulletSpeed", "_bulletLength", "_barrelTwist", "_twistDirection", "_stabilityFactor", "_transonicStabilityCoef"];
2015-04-05 19:08:55 +00:00
_unit = _this select 0;
_weapon = _this select 1;
_mode = _this select 3;
_ammo = _this select 4;
_magazine = _this select 5;
_bullet = _this select 6;
2015-04-12 09:48:21 +00:00
_abort = false;
2015-04-09 18:27:10 +00:00
if (!hasInterface) exitWith {};
2015-04-05 19:08:55 +00:00
if (!alive _bullet) exitWith {};
2015-04-09 18:27:10 +00:00
if (!GVAR(enabled)) exitWith {};
2015-04-05 19:08:55 +00:00
if (!([_unit] call EFUNC(common,isPlayer))) exitWith {};
if (underwater _unit) exitWith {};
if (!(_ammo isKindOf "BulletBase")) exitWith {};
2015-04-12 10:09:55 +00:00
if (_unit distance ACE_player > GVAR(simulationRadius)) exitWith {};
2015-04-12 09:48:21 +00:00
if (GVAR(onlyActiveForLocalPlayers) && _unit != ACE_player) then { _abort = true; };
//if (!GVAR(vehicleGunnerEnabled) && !(_unit isKindOf "Man")) then { _abort = true; }; // TODO: We currently do not have firedEHs on vehicles
if (GVAR(disabledInFullAutoMode) && getNumber(configFile >> "cfgWeapons" >> _weapon >> _mode >> "autoFire") == 1) then { _abort = true; };
if (_abort && alwaysSimulateForSnipers) then {
2015-04-09 18:27:10 +00:00
// The shooter is non local
if (currentWeapon _unit == primaryWeapon _unit && count primaryWeaponItems _unit > 2) then {
_opticsName = (primaryWeaponItems _unit) select 2;
_opticType = getNumber(configFile >> "cfgWeapons" >> _opticsName >> "ItemInfo" >> "opticType");
_abort = _opticType != 2; // We only abort if the non local shooter is not a sniper
};
};
2015-04-13 10:56:53 +00:00
if (_abort || !(GVAR(extensionAvailable))) exitWith {
2015-04-09 18:27:10 +00:00
[_bullet, getNumber(configFile >> "cfgAmmo" >> _ammo >> "airFriction")] call EFUNC(winddeflection,updateTrajectoryPFH);
};
2015-04-05 19:08:55 +00:00
_airFriction = getNumber(configFile >> "cfgAmmo" >> _ammo >> "airFriction");
_muzzleVelocity = getNumber(configFile >> "cfgMagazines" >> _magazine >> "initSpeed");
_muzzleVelocityCoef = getNumber(configFile >> "cfgWeapons" >> _weapon >> "initSpeed");
if (_muzzleVelocityCoef > 0) then {
2015-04-07 19:27:04 +00:00
_muzzleVelocity = _muzzleVelocityCoef;
2015-04-05 19:08:55 +00:00
};
if (_muzzleVelocityCoef < 0) then {
2015-04-07 19:27:04 +00:00
_muzzleVelocity = _muzzleVelocity * (-1 * _muzzleVelocityCoef);
2015-04-05 19:08:55 +00:00
};
_muzzleAccessory = "";
switch (currentWeapon _unit) do {
2015-04-07 19:27:04 +00:00
case primaryWeapon _unit: { _muzzleAccessory = (primaryWeaponItems _unit) select 0; };
case handgunWeapon _unit: { _muzzleAccessory = (handgunItems _unit) select 0; };
2015-04-05 19:08:55 +00:00
};
if (_muzzleAccessory != "" && isNumber(configFile >> "cfgWeapons" >> _muzzleAccessory >> "ItemInfo" >> "MagazineCoef" >> "initSpeed")) then {
2015-04-07 19:27:04 +00:00
_initSpeedCoef = getNumber(configFile >> "cfgWeapons" >> _muzzleAccessory >> "ItemInfo" >> "MagazineCoef" >> "initSpeed");
_muzzleVelocity = _muzzleVelocity * _initSpeedCoef;
2015-04-05 19:08:55 +00:00
};
2015-04-12 14:17:49 +00:00
if (GVAR(barrelLengthInfluenceEnabled)) then {
2015-04-07 19:27:04 +00:00
_muzzleVelocityShift = [_ammo, _weapon, _muzzleVelocity] call FUNC(calculateBarrelLengthVelocityShift);
if (_muzzleVelocityShift != 0) then {
_bulletVelocity = velocity _bullet;
_bulletSpeed = vectorMagnitude _bulletVelocity;
_bulletVelocity = _bulletVelocity vectorAdd ((vectorNormalized _bulletVelocity) vectorMultiply (_muzzleVelocityShift * (_bulletSpeed / _muzzleVelocity)));
_bullet setVelocity _bulletVelocity;
_muzzleVelocity = _muzzleVelocity + _muzzleVelocityShift;
};
2015-04-05 19:08:55 +00:00
};
2015-04-12 14:17:49 +00:00
if (GVAR(ammoTemperatureEnabled)) then {
2015-04-07 19:27:04 +00:00
_temperature = GET_TEMPERATURE_AT_HEIGHT((getPosASL _unit) select 2);
_muzzleVelocityShift = [_ammo, _temperature] call FUNC(calculateAmmoTemperatureVelocityShift);
if (_muzzleVelocityShift != 0) then {
_bulletVelocity = velocity _bullet;
_bulletSpeed = vectorMagnitude _bulletVelocity;
_bulletVelocity = _bulletVelocity vectorAdd ((vectorNormalized _bulletVelocity) vectorMultiply (_muzzleVelocityShift * (_bulletSpeed / _muzzleVelocity)));
_bullet setVelocity _bulletVelocity;
_muzzleVelocity = _muzzleVelocity + _muzzleVelocityShift;
};
2015-04-05 19:08:55 +00:00
};
_bulletTraceVisible = false;
2015-04-16 15:52:21 +00:00
if (GVAR(bulletTraceEnabled) && cameraView == "GUNNER" && currentWeapon ACE_player == primaryWeapon ACE_player && count primaryWeaponItems ACE_player > 2) then {
2015-04-07 19:27:04 +00:00
_opticsName = (primaryWeaponItems ACE_player) select 2;
_opticType = getNumber(configFile >> "cfgWeapons" >> _opticsName >> "ItemInfo" >> "opticType");
2015-04-16 15:52:21 +00:00
_bulletTraceVisible = (_opticType == 2 || currentWeapon ACE_player in ["ACE_Vector", "Binocular", "Rangefinder", "Laserdesignator"]);
2015-04-05 19:08:55 +00:00
};
_caliber = getNumber(configFile >> "cfgAmmo" >> _ammo >> "ACE_caliber");
_bulletLength = getNumber(configFile >> "cfgAmmo" >> _ammo >> "ACE_bulletLength");
_bulletMass = getNumber(configFile >> "cfgAmmo" >> _ammo >> "ACE_bulletMass");
_barrelTwist = getNumber(configFile >> "cfgWeapons" >> _weapon >> "ACE_barrelTwist");
_stabilityFactor = 1.5;
if (_caliber > 0 && _bulletLength > 0 && _bulletMass > 0 && _barrelTwist > 0) then {
2015-04-07 19:27:04 +00:00
_temperature = GET_TEMPERATURE_AT_HEIGHT((getPosASL _unit) select 2);
2015-04-20 11:54:22 +00:00
_barometricPressure = ((getPosASL _bullet) select 2) call EFUNC(weather,calculateBarometricPressure);
2015-04-07 19:27:04 +00:00
_stabilityFactor = [_caliber, _bulletLength, _bulletMass, _barrelTwist, _muzzleVelocity, _temperature, _barometricPressure] call FUNC(calculateStabilityFactor);
2015-04-05 19:08:55 +00:00
};
_twistDirection = 1;
if (isNumber(configFile >> "cfgWeapons" >> _weapon >> "ACE_twistDirection")) then {
2015-04-07 19:27:04 +00:00
_twistDirection = getNumber(configFile >> "cfgWeapons" >> _weapon >> "ACE_twistDirection");
if (_twistDirection != -1 && _twistDirection != 0 && _twistDirection != 1) then {
_twistDirection = 1;
};
2015-04-05 19:08:55 +00:00
};
_transonicStabilityCoef = 0.5;
if (isNumber(configFile >> "cfgAmmo" >> _ammo >> "ACE_transonicStabilityCoef")) then {
2015-04-07 19:27:04 +00:00
_transonicStabilityCoef = getNumber(configFile >> "cfgAmmo" >> _ammo >> "ACE_transonicStabilityCoef");
2015-04-05 19:08:55 +00:00
};
_dragModel = 1;
_ballisticCoefficients = [];
_velocityBoundaries = [];
_atmosphereModel = "ICAO";
if (GVAR(AdvancedAirDragEnabled)) then {
2015-04-07 19:27:04 +00:00
if (isNumber(configFile >> "cfgAmmo" >> _ammo >> "ACE_dragModel")) then {
_dragModel = getNumber(configFile >> "cfgAmmo" >> _ammo >> "ACE_dragModel");
if (!(_dragModel in [1, 2, 5, 6, 7, 8])) then {
_dragModel = 1;
};
};
if (isArray(configFile >> "cfgAmmo" >> _ammo >> "ACE_ballisticCoefficients")) then {
_ballisticCoefficients = getArray(configFile >> "cfgAmmo" >> _ammo >> "ACE_ballisticCoefficients");
};
if (isArray(configFile >> "cfgAmmo" >> _ammo >> "ACE_velocityBoundaries")) then {
_velocityBoundaries = getArray(configFile >> "cfgAmmo" >> _ammo >> "ACE_velocityBoundaries");
};
if (isText(configFile >> "cfgAmmo" >> _ammo >> "ACE_standardAtmosphere")) then {
_atmosphereModel = getText(configFile >> "cfgAmmo" >> _ammo >> "ACE_standardAtmosphere");
};
2015-04-05 19:08:55 +00:00
};
2015-04-25 08:59:48 +00:00
GVAR(currentbulletID) = (GVAR(currentbulletID) + 1) % 10000;
"ace_advanced_ballistics" callExtension format["new:%1:%2:%3:%4:%5:%6:%7:%8:%9:%10:%11:%12:%13:%14:%15:%16:%17:%18", GVAR(currentbulletID), _airFriction, _ballisticCoefficients, _velocityBoundaries, _atmosphereModel, _dragModel, _stabilityFactor, _twistDirection, _muzzleVelocity, _transonicStabilityCoef, getPosASL _bullet, EGVAR(weather,Latitude), EGVAR(weather,currentTemperature), EGVAR(weather,Altitude), EGVAR(weather,currentHumidity), overcast, floor(time), time - floor(time)];
[{
private ["_index", "_bullet", "_caliber", "_bulletTraceVisible", "_bulletVelocity", "_bulletPosition"];
EXPLODE_4_PVT(_this select 0,_bullet,_caliber,_bulletTraceVisible,_index);
_bulletVelocity = velocity _bullet;
_bulletPosition = getPosASL _bullet;
_bulletSpeed = vectorMagnitude _bulletVelocity;
if (!alive _bullet || _bulletSpeed < 100) exitWith {
[_this select 1] call cba_fnc_removePerFrameHandler;
};
if (_bulletTraceVisible && _bulletSpeed > 600) then {
drop ["\A3\data_f\ParticleEffects\Universal\Refract","","Billboard",1,0.1,getPos _bullet,[0,0,0],0,1.275,1,0,[0.4*_caliber,0.2*_caliber],[[0,0,0,0.6],[0,0,0,0.4]],[1,0],0,0,"","",""];
2015-04-13 10:56:53 +00:00
};
2015-04-25 08:59:48 +00:00
call compile ("ace_advanced_ballistics" callExtension format["simulate:%1:%2:%3:%4:%5:%6:%7", _index, _bulletVelocity, _bulletPosition, ACE_wind, ASLToATL(_bulletPosition) select 2, floor(time), time - floor(time)]);
2015-04-07 19:22:58 +00:00
2015-04-25 08:59:48 +00:00
}, GVAR(simulationInterval), [_bullet, _caliber, _bulletTraceVisible, GVAR(currentbulletID)]] call CBA_fnc_addPerFrameHandler;