2016-05-30 16:37:03 +00:00
//fnc_frago.sqf
// #define DEBUG_MODE_FULL
#include "script_component.hpp"
#define FRAG_VEC_VAR 0.004
#define MAX_FRAG_COUNT 50
2016-10-26 22:16:31 +00:00
if (!isServer) exitWith {};
2016-05-30 16:37:03 +00:00
BEGIN_COUNTER(frago);
2016-06-02 15:02:09 +00:00
// _startTime = diag_tickTime;
2016-05-30 16:37:03 +00:00
2016-10-26 22:16:31 +00:00
params ["_round", "_lastPos", "_lastVel", "_shellType", "_firedFrame", "_gun"];
2016-05-30 16:37:03 +00:00
2016-09-04 14:44:22 +00:00
private _fragTypes = [
QGVAR(tiny), QGVAR(tiny), QGVAR(tiny),
QGVAR(tiny_HD), QGVAR(tiny_HD), QGVAR(tiny_HD),
2016-10-26 22:16:31 +00:00
QGVAR(small), QGVAR(small), QGVAR(small), QGVAR(small),
QGVAR(small_HD), QGVAR(small_HD), QGVAR(small_HD), QGVAR(small_HD),
2016-09-04 14:44:22 +00:00
QGVAR(medium_HD), QGVAR(medium_HD), QGVAR(medium_HD), QGVAR(medium_HD), QGVAR(medium_HD)
];
2016-05-30 16:37:03 +00:00
2016-09-04 14:44:22 +00:00
private _warn = false;
2016-10-26 22:16:31 +00:00
if (isArray (configFile >> "CfgAmmo" >> _shellType >> QGVAR(CLASSES))) then {
2016-07-20 04:15:18 +00:00
_fragTypes = getArray (configFile >> "CfgAmmo" >> _shellType >> QGVAR(CLASSES));
2016-05-30 16:37:03 +00:00
} else {
_warn = true;
};
2016-09-04 14:44:22 +00:00
private _isArmed = true;
2016-10-26 22:16:31 +00:00
if (!isNil "_gun") then {
private _fuseDist = getNumber(configFile >> "CfgAmmo" >> _shellType >> "fuseDistance");
2016-05-30 16:37:03 +00:00
_isArmed = ((getPosASL _gun) distance _lastPos > _fuseDist);
};
2016-10-26 22:16:31 +00:00
private _indirectHitRange = getNumber(configFile >> "CfgAmmo" >> _shellType >> "indirecthitrange");
private _fragRange = 20 * _indirectHitRange * 4;
2016-05-30 16:37:03 +00:00
// _c = 185; // grams of comp-b
// _m = 210; // grams of fragmentating metal
// _k = 3/5; // spherical K factor
// _gC = 2843; // Gurney constant of comp-b in /ms
// _c = 429; // grams of tritonal
// _m = 496; // grams of fragmentating metal
// _k = 1/2; // spherical K factor
// _gC = 2320; // Gurney constant of tritonal in /ms
2016-10-26 22:16:31 +00:00
private _c = getNumber (configFile >> "CfgAmmo" >> _shellType >> QGVAR(CHARGE));
if (_c == 0) then {_c = 1; _warn = true;};
private _m = getNumber (configFile >> "CfgAmmo" >> _shellType >> QGVAR(METAL));
if (_m == 0) then {_m = 2; _warn = true;};
private _k = getNumber (configFile >> "CfgAmmo" >> _shellType >> QGVAR(GURNEY_K));
if (_k == 0) then {_k = 0.5; _warn = true;};
private _gC = getNumber (configFile >> "CfgAmmo" >> _shellType >> QGVAR(GURNEY_C));
if (_gC == 0) then {_gC = 2440; _warn = true;};
2016-05-30 16:37:03 +00:00
2016-10-26 22:16:31 +00:00
if (_warn) then {
2016-12-01 17:01:55 +00:00
INFO_1("Ammo class %1 lacks proper explosive properties definitions for frag!",_shellType);
2016-05-30 16:37:03 +00:00
};
2016-10-26 22:16:31 +00:00
private _fragPower = (((_m / _c) + _k) ^ - (1 / 2)) * _gC;
2017-02-10 18:28:27 +00:00
MUL(_fragPower,0.8); // Gunery equation is for a non-fragmenting metal, imperical value of 80% represents fragmentation
2016-05-30 16:37:03 +00:00
2016-10-26 22:16:31 +00:00
private _atlPos = ASLtoATL _lastPos;
private _fragPowerRandom = _fragPower * 0.5;
if ((_atlPos select 2) < 0.5) then {
2017-02-10 18:28:27 +00:00
_lastPos vectorAdd [0, 0, 0.5];
2016-05-30 16:37:03 +00:00
};
// _manObjects = _atlPos nearEntities ["CaManBase", _fragRange];
// setAccTime 0.01;
//_objects = nearestObjects [_atlPos, ["AllVehicles"], _fragRange]; // Not sure if tracking "ReammoBox" is required, if so revert this change for _objects
2016-10-26 22:16:31 +00:00
private _objects = _atlPos nearEntities [["Car", "Motorcycle", "Tank", "StaticWeapon", "CAManBase", "Air", "Ship"], _fragRange];
2016-05-30 16:37:03 +00:00
// _objects = _manObjects;
2016-10-26 22:16:31 +00:00
// Add unique crews in faster way
2016-05-30 16:37:03 +00:00
{
{
2016-10-26 22:16:31 +00:00
_objects pushBackUnique _x;
2016-05-30 16:37:03 +00:00
} forEach (crew _x);
} forEach _objects;
2016-10-26 22:16:31 +00:00
private _fragCount = 0;
2016-05-30 16:37:03 +00:00
2016-10-26 22:16:31 +00:00
private _fragArcs = [];
_fragArcs set [360, 0];
2016-05-30 16:37:03 +00:00
#ifdef DEBUG_MODE_FULL
2016-10-26 22:16:31 +00:00
ACE_player sideChat format ["_fragRange: %1", _fragRange];
ACE_player sideChat format ["_objects: %1", _objects];
2016-05-30 16:37:03 +00:00
#endif
2016-10-26 22:16:31 +00:00
private _doRandom = true;
if (_isArmed && {!(_objects isEqualTo [])}) then {
2017-02-10 18:28:27 +00:00
if (GVAR(reflectionsEnabled)) then {
2016-05-30 16:37:03 +00:00
[_lastPos, _shellType] call FUNC(doReflections);
};
{
2016-10-26 22:16:31 +00:00
//if (random(1) > 0.5) then {
private _target = _x;
if (alive _target) then {
private _boundingBox = boundingBox _target;
2017-02-10 18:28:27 +00:00
private _cubic = 1;
for "_i" from 0 to 2 do {
MUL(_cubic,(abs ((_boundingBox select 0) select _i)) + ((_boundingBox select 1) select _i));
};
if (_cubic <= 1) exitWith {};
_doRandom = true;
private _targetVel = velocity _target;
2016-10-26 22:16:31 +00:00
private _targetPos = getPosASL _target;
2017-02-10 18:28:27 +00:00
private _distance = _targetPos vectorDistance _lastPos;
2016-10-26 22:16:31 +00:00
private _add = (((_boundingBox select 1) select 2) / 2) + ((((_distance - (_fragpower / 8)) max 0) / _fragPower) * 10);
2017-02-10 18:28:27 +00:00
_targetPos = _targetPos vectorAdd [
(_targetVel select 0) * (_distance / _fragPower),
(_targetVel select 1) * (_distance / _fragPower),
_add
];
private _baseVec = _lastPos vectorFromTo _targetPos;
private _dir = floor (_baseVec call CBA_fnc_vectDir);
private _currentCount = RETDEF(_fragArcs select _dir,0);
if (_currentCount < 20) then {
private _count = ceil (random (sqrt (_m / 1000)));
private _vecVar = FRAG_VEC_VAR;
if (!(_target isKindOf "Man")) then {
ADD(_vecVar,(sqrt _cubic) / 2000);
if ((crew _target) isEqualTo [] && {_count > 0}) then {
_count = 0 max (_count / 2);
2016-05-30 16:37:03 +00:00
};
2017-02-10 18:28:27 +00:00
};
for "_i" from 1 to _count do {
private _vec = _baseVec vectorDiff [
(_vecVar / 2) + (random _vecVar),
(_vecVar / 2) + (random _vecVar),
(_vecVar / 2) + (random _vecVar)
];
private _fp = _fragPower - (random (_fragPowerRandom));
private _vel = _vec vectorMultiply _fp;
private _fragType = round (random ((count _fragTypes) - 1));
private _fragObj = (_fragTypes select _fragType) createVehicleLocal [0,0,10000];
// diag_log text format ["fp: %1 %2", _fp, typeOf _fragObj];
_fragObj setPosASL _lastPos;
_fragObj setVectorDir _vec;
_fragObj setVelocity _vel;
if (GVAR(traceFrags)) then {
INC(GVAR(totalFrags));
[ACE_player, _fragObj, [1,0,0,1]] call FUNC(addTrack);
2016-05-30 16:37:03 +00:00
};
2017-02-10 18:28:27 +00:00
INC(_fragCount);
INC(_currentCount);
2016-05-30 16:37:03 +00:00
};
2017-02-10 18:28:27 +00:00
_fragArcs set [_dir, _currentCount];
2016-05-30 16:37:03 +00:00
};
};
//};
2016-10-26 22:16:31 +00:00
if (_fragCount > MAX_FRAG_COUNT) exitWith {};
2016-05-30 16:37:03 +00:00
} forEach _objects;
2016-10-26 22:16:31 +00:00
if (_fragCount > MAX_FRAG_COUNT) exitWith {};
private _randomCount = ((ceil ((MAX_FRAG_COUNT - _fragCount) * 0.1)) max 0) + 20;
private _sectorSize = 360 / (_randomCount max 1);
2016-05-30 16:37:03 +00:00
// _doRandom = false;
2016-10-26 22:16:31 +00:00
if (_doRandom) then {
2016-05-30 16:37:03 +00:00
for "_i" from 1 to _randomCount do {
// Distribute evenly
2016-10-26 22:16:31 +00:00
private _sectorOffset = 360 * (_i - 1) / (_randomCount max 1);
private _randomDir = random (_sectorSize);
_vec = [cos (_sectorOffset + _randomDir), sin (_sectorOffset + _randomDir), sin (30 - (random 45))];
2016-05-30 16:37:03 +00:00
2016-10-26 22:16:31 +00:00
_fp = (_fragPower - (random (_fragPowerRandom)));
2016-05-30 16:37:03 +00:00
_vel = _vec vectorMultiply _fp;
2016-10-26 22:16:31 +00:00
_fragType = round (random ((count _fragTypes) - 1));
_fragObj = (_fragTypes select _fragType) createVehicleLocal [0, 0, 10000];
2016-05-30 16:37:03 +00:00
_fragObj setPosASL _lastPos;
_fragObj setVectorDir _vec;
_fragObj setVelocity _vel;
2016-10-26 22:16:31 +00:00
if (GVAR(traceFrags)) then {
INC(GVAR(totalFrags));
2016-05-30 16:37:03 +00:00
[ACE_player, _fragObj, [1,0.5,0,1]] call FUNC(addTrack);
};
2016-10-26 22:16:31 +00:00
INC(_fragCount);
2016-05-30 16:37:03 +00:00
};
};
};
// #ifdef DEBUG_MODE_FULL
2016-10-26 22:16:31 +00:00
// ACE_player sideChat format["total frags: %1", GVAR(totalFrags)];
2016-05-30 16:37:03 +00:00
// ACE_player sideChat format["tracks: %1", (count GVAR(trackedObjects))];
// #endif
2016-06-02 15:02:09 +00:00
// _endTime = diag_tickTime;
2016-07-20 04:15:18 +00:00
END_COUNTER(frago);