diff --git a/addons/frag/XEH_postInit.sqf b/addons/frag/XEH_postInit.sqf index b8b6e39f10..f0cbd532de 100644 --- a/addons/frag/XEH_postInit.sqf +++ b/addons/frag/XEH_postInit.sqf @@ -10,8 +10,8 @@ #ifdef DEBUG_MODE_DRAW if (hasInterface) then { - private _h = [LINKFUNC(dev_drawTrace), 0] call CBA_fnc_addPerFrameHandler; - missionNamespace setVariable [QGVAR(dev_drawPFEH), _h]; + private _handle = [LINKFUNC(dev_drawTrace), 0] call CBA_fnc_addPerFrameHandler; + missionNamespace setVariable [QGVAR(dev_drawPFEH), _handle]; ["unit", LINKFUNC(dev_switchUnitHandle), true] call CBA_fnc_addPlayerEventHandler; [objNull, ace_player] call FUNC(dev_switchUnitHandle); }; diff --git a/addons/frag/functions/fnc_addBlackList.sqf b/addons/frag/functions/fnc_addBlackList.sqf index 3766df13e8..ecb6af71e2 100644 --- a/addons/frag/functions/fnc_addBlackList.sqf +++ b/addons/frag/functions/fnc_addBlackList.sqf @@ -15,15 +15,15 @@ * Public: No */ -params ["_proj"]; +params ["_projectile"]; TRACE_1("addBlackList",_round); -switch (typeName _proj) do { +switch (typeName _projectile) do { case "OBJECT": { - GVAR(shouldFragCache) set [typeOf _proj, false]; + GVAR(shouldFragCache) set [typeOf _projectile, false]; }; case "STRING": { - GVAR(shouldFragCache) set [_proj, false]; + GVAR(shouldFragCache) set [_projectile, false]; }; default { }; -}; \ No newline at end of file +}; diff --git a/addons/frag/functions/fnc_doFrag.sqf b/addons/frag/functions/fnc_doFrag.sqf index e66349a8df..41d97f4a53 100644 --- a/addons/frag/functions/fnc_doFrag.sqf +++ b/addons/frag/functions/fnc_doFrag.sqf @@ -15,15 +15,15 @@ * None * * Example: - * [[_proj, getPosASL _proj, velocity _proj]] call ace_frag_fnc_doFrag; + * [_projectile, getPosASL _projectile, velocity _projectile, typeOf _projectile, getShotParents _projectile] call ace_frag_fnc_doFrag; * * Public: No */ TRACE_1("begin doFrag",_this); params [ - ["_proj", objNull, [objNull]], + "", ["_posASL", [0, 0, 0], [[]], [3]], - ["_vel", [0, 0, 0] , [[]], [3]], + ["_velocity", [0, 0, 0] , [[]], [3]], ["_ammo", "", [""]], ["_shotParents", [objNull, objNull], [[]]] ]; @@ -65,5 +65,5 @@ if (_fragRange > 3 && _timeSince > ACE_FRAG_HOLDOFF*1.5 && GVAR(fragSimComplexit }; if (_timeSince > 0.2 && {GVAR(fragSimComplexity) > 0}) then { - [_posASL, _vel, _heightAGL, _fragTypes, _maxFrags, _shotParents] call FUNC(doFragRandom); -}; \ No newline at end of file + [_posASL, _velocity, _heightAGL, _fragTypes, _maxFrags, _shotParents] call FUNC(doFragRandom); +}; diff --git a/addons/frag/functions/fnc_doFragRandom.sqf b/addons/frag/functions/fnc_doFragRandom.sqf index 2f5b53ff80..b956bc36cc 100644 --- a/addons/frag/functions/fnc_doFragRandom.sqf +++ b/addons/frag/functions/fnc_doFragRandom.sqf @@ -8,28 +8,27 @@ * 0: Position of fragmenting projectile ASL * 1: Velocity of the fragmenting projectile * 2: Height (AGL) of the fragmenting projectile - * 3: Type of fragments to generate + * 3: Type of fragments to generate * 4: Remaining fragment budget - * 5: Shot parent + * 5: Shot parents * * Return Value: * None * * Example: - * [getPosASL _proj, velocity _proj, 50, 50, [], 1, [player, player]] call ace_frag_fnc_doFragRandom; + * [getPosASL _proj, 800, 50, 50, [], 1, [player, player]] call ace_frag_fnc_doFragRandom; * * Public: No */ - params [ "_posASL", - ["_projVel", [0,0,0]], + ["_fragVelocity", [0,0,0]], ["_heightAGL", 2, [123]], ["_fragType", [], [[]]], ["_fragCnt", 10, [123]], - ["_shotPrnt", [objNull, objNull], [[]], [2]] + ["_shotParents", [objNull, objNull], [[]], [2]] ]; -TRACE_5("fnc_doFragRandom", _posASL, _projVel, _heightAGL, _fragType, _fragCnt); +TRACE_5("fnc_doFragRandom", _posASL, _fragVelocity, _heightAGL, _fragType, _fragCnt); // See cfgAmmoFragSpawner for different frag types private _hMode = switch (true) do { @@ -54,7 +53,7 @@ _fragCnt = switch (true) do { // Spawn the fragment spawner private _fragSpawner = createVehicle [_type + _fragCnt + _hMode, ASLToATL _posASL, [], 0, "CAN_COLLIDE"]; _fragSpawner setVectorDirandUp [[0,0,1], [1,0,0]]; -_fragSpawner setVelocity _projVel; +_fragSpawner setVelocity _fragVelocity; _fragSpawner setShotParents _shotParents; #ifdef DEBUG_MODE_FULL @@ -71,4 +70,4 @@ _fragSpawner addEventHandler [ if (GVAR(dbgSphere)) then { [_posASL] call FUNC(dev_sphereDraw); }; -#endif \ No newline at end of file +#endif diff --git a/addons/frag/functions/fnc_doFragTargeted.sqf b/addons/frag/functions/fnc_doFragTargeted.sqf index 29241f469f..a46ee65ed3 100644 --- a/addons/frag/functions/fnc_doFragTargeted.sqf +++ b/addons/frag/functions/fnc_doFragTargeted.sqf @@ -24,14 +24,14 @@ params [ "_posASL", - ["_fragVel", 800, [123]], + ["_fragVelocity", 800, [123]], ["_fragRange", 50, [123]], ["_maxFrags", 20, [123]], ["_fragTypes", [], [[]]], ["_modFragCount", 1, [123]], - ["_shotPrnt", [objNull, objNull], [[]], [2]] + ["_shotParents", [objNull, objNull], [[]], [2]] ]; -TRACE_5("fnc_doFragTargeted", _posASL, _fragRange, _maxFrags, _fragTypes, _modFragCount); +TRACE_5("fnc_doFragTargeted",_posASL,_fragRange,_maxFrags,_fragTypes,_modFragCount); if (_fragTypes isEqualTo []) then { _fragTypes = [ @@ -45,14 +45,14 @@ if (_fragTypes isEqualTo []) then { private _objects = (ASLToATL _posASL) nearEntities [["Car", "Motorcycle", "Tank", "StaticWeapon", "CAManBase", "Air", "Ship"], _fragRange]; if (_objects isEqualTo []) exitWith { - TRACE_2("No nearby targets", _posASL, _fragRange); + TRACE_2("No nearby targets",_posASL,_fragRange); 0; }; // grab crews and add them in so that targets stay approx. sorted by distance { - private _crew = (crew _x); + private _crew = crew _x; if (count _crew > 1) then { private _arr = [_x]; { @@ -63,11 +63,11 @@ if (_objects isEqualTo []) exitWith { }; } forEach _objects; _objects = flatten _objects; -TRACE_3("Targets found", _posASL, _fragRange, count _objects); +TRACE_3("Targets found",_posASL,_fragRange,count _objects); // limit number of fragments per direction (2D) to 10 using _fragArcs private _fragArcs = createHashMap; -private _fragCount = 0; +private _totalFragCount = 0; { // Begin of forEach iterating on _objects if (!alive _x) then {continue}; private _target = _x; @@ -103,16 +103,15 @@ private _fragCount = 0; // calculate chance to be hit by a fragment private _fragChance = _crossSectionArea * _modFragCount / _distance^2; - private _count = if (_fragChance > 1) then { + private _fragCount = if (_fragChance > 1) then { 3 min (floor _fragChance); } else { [0, 1] select (GVAR(atLeastOne) || {random 1 < _fragChance}); }; - if (_count == 0) then {TRACE_2("fragments",_fragChance,_count); continue}; - - // Approximate offset to hit including speed & gravity - private _locFragVel = _fragVel * (1 - random 0.5); - private _tof = _distance / _locFragVel; + if (_fragCount == 0) then { + TRACE_2("fragments",_fragChance,_fragCount); + continue + }; // handle limiting fragments per degree arc private _dir = floor (_posASL getDir _target); @@ -120,11 +119,15 @@ private _fragCount = 0; if (_fragPerArc > 10) then { continue; } else { - _fragArcs set [_dir, _fragPerArc + _count]; + _fragArcs set [_dir, _fragPerArc + _fragCount]; }; + // Approximate offset to hit including speed & gravity + private _locFragVel = _fragVelocity * (1 - random 0.5); + private _timeOfFlight = _distance / _locFragVel; + // target pos for fragment to hit - private _targetPos = (velocity _target vectorMultiply _tof) vectorAdd [0, 0, 9.81 / 2 * _tof ^ 2]; + private _targetPos = (velocity _target vectorMultiply _timeOfFlight) vectorAdd [0, 0, ACE_FRAG_HALF_GRAVITY_APPROX * _timeOfFlight ^ 2]; if _isPerson then { private _hitPoint = selectRandom ACE_FRAG_HITPOINTS; private _hitPointPos = _target selectionPosition [_hitPoint, "HitPoints", "AveragePoint"]; @@ -139,8 +142,8 @@ private _fragCount = 0; // select a fragment / submunition frag spawner private _fragSpawner = selectRandom _fragTypes; - if (_count > 1) then { - _fragSpawner = _fragSpawner + "_spawner_" + str _count + (switch (true) do { + if (_fragCount > 1) then { + _fragSpawner = _fragSpawner + "_spawner_" + str _fragCount + (switch (true) do { case (_distance < 10): {"_short"}; case (_distance < 20): {"_mid"}; default {"_far"}; @@ -149,11 +152,11 @@ private _fragCount = 0; TRACE_4("fragments",_fragSpawner,_fragChance,_distance,_locFragVel); // Create fragment - private _vecDir = _posASL vectorFromTo _targetPos; + private _vectorDir = _posASL vectorFromTo _targetPos; private _fragObj = createVehicle [_fragSpawner, ASLtoATL _posASL, [], 0, "CAN_COLLIDE"]; - _fragObj setVectorDir _vecDir; - _fragObj setVelocity (_vecDir vectorMultiply _locFragVel); - _fragObj setShotParents _shotPrnt; + _fragObj setVectorDir _vectorDir; + _fragObj setVelocity (_vectorDir vectorMultiply _locFragVel); + _fragObj setShotParents _shotParents; #ifdef DEBUG_MODE_DRAW [_fragObj, "purple", true] call FUNC(dev_trackObj); if (GVAR(dbgSphere)) then { @@ -161,15 +164,15 @@ private _fragCount = 0; }; #endif - _fragCount = _fragCount + _count; - if (_fragCount >= _maxFrags) then { - TRACE_2("maxFrags", _fragCount, _maxFrags); + _totalFragCount = _totalFragCount + _fragCount; + if (_totalFragCount >= _maxFrags) then { + TRACE_2("maxFrags", _totalFragCount, _maxFrags); break }; } forEach _objects; #ifdef DEBUG_MODE_FULL -systemChat ("fragCount cnt: " + str _fragCount); -TRACE_1("fragCount",_fragCount); +systemChat ("fragCount cnt: " + str _totalFragCount); +TRACE_1("fragCount",_totalFragCount); #endif -_fragCount \ No newline at end of file +_totalFragCount diff --git a/addons/frag/functions/fnc_doSpall.sqf b/addons/frag/functions/fnc_doSpall.sqf index a12e0b47c9..8a65e60e8b 100644 --- a/addons/frag/functions/fnc_doSpall.sqf +++ b/addons/frag/functions/fnc_doSpall.sqf @@ -18,21 +18,21 @@ TRACE_1("doSpall",_this); params [ "_projectile", - ["_hitObj", objNull], - ["_lPosASL", [0, 0, 0]], - ["_lVel", [0, 0, 0]], - ["_sNorm", [0, 0, 0]], + ["_objectHit", objNull], + ["_lastPosASL", [0, 0, 0]], + ["_lastVelocity", [0, 0, 0]], + ["_surfaceNorm", [0, 0, 0]], ["_surfaceType", ""], ["_ammo", "", [""]], ["_shotParents", [objNull, objNull], [[]]], - ["_vUp", [0,0,1]] + ["_vectorUp", [0,0,1]] ]; if (CBA_missionTime - GVAR(lastSpallTime) < ACE_FRAG_SPALL_HOLDOFF || - _lPosASL isEqualTo [0,0,0] || - {isNull _hitObj || {_hitObj isKindOf "man" || + _lastPosASL isEqualTo [0,0,0] || + {isNull _objectHit || {_objectHit isKindOf "man" || {_ammo isEqualTo ""}}}) exitWith { - TRACE_4("time/invldHit",CBA_missionTime,GVAR(lastSpallTime),_hitObj,_lPosASL); + TRACE_4("time/invldHit",CBA_missionTime,GVAR(lastSpallTime),_objectHit,_lastPosASL); }; private _material = [_surfaceType] call FUNC(getMaterialInfo); @@ -45,21 +45,21 @@ if (_material isEqualTo "ground") then { // Find spall speed / fragment info [_ammo] call FUNC(getSpallInfo) params ["_caliber", "_explosive", "_indirectHit"]; private _vel = if (alive _projectile) then { - _explosive = 0; // didn't explode + _explosive = 0; // didn't explode since it's alive a frame later velocity _projectile } else { [0, 0, 0]; }; -private _dV = vectorMagnitude _lVel - vectorMagnitude _vel; +private _velocityChange = vectorMagnitude _lastVelocity - vectorMagnitude _vel; /* * This is all fudge factor since real spalling is too complex for calculation. * There are two terms. The first is from round impact, taking a quasi scale * of sqrt(2)/50 * round caliber * srqt(change in speed). The second term is * explosive * indirect hit, for any explosive contribution */ -private _spallPower = (ACE_FRAG_ROUND_COEF * _caliber * sqrt _dV + _explosive * _indirectHit) * GVAR(spallIntensity); -TRACE_3("found speed",_dV,_caliber,_spallPower); +private _spallPower = (ACE_FRAG_ROUND_COEF * _caliber * sqrt _velocityChange + _explosive * _indirectHit) * GVAR(spallIntensity); +TRACE_3("found speed",_velocityChange,_caliber,_spallPower); if (_spallPower < 2) exitWith { @@ -67,49 +67,49 @@ if (_spallPower < 2) exitWith { }; -private _lVelUnit = vectorNormalized _lVel; -private _unitStep = _lVelUnit vectorMultiply 0.05; +private _lastVelocityUnit = vectorNormalized _lastVelocity; +private _deltaStep = _lastVelocityUnit vectorMultiply 0.05; -if (terrainIntersectASL [_lPosASL vectorAdd _unitStep, _lPosASL]) exitWith { - TRACE_3("terrainIntersect",_lPosASL,_unitStep,_lPosASL); +if (terrainIntersectASL [_lastPosASL vectorAdd _deltaStep, _lastPosASL]) exitWith { + TRACE_2("terrainIntersect",_lastPosASL,_deltaStep); }; #ifdef DEBUG_MODE_DRAW if GVAR(dbgSphere) then { - [_lPosASL vectorAdd _lVelUnit, "orange"] call FUNC(dev_sphereDraw); - [_lPosASL, "yellow"] call FUNC(dev_sphereDraw); + [_lastPosASL vectorAdd _lastVelocityUnit, "orange"] call FUNC(dev_sphereDraw); + [_lastPosASL, "yellow"] call FUNC(dev_sphereDraw); }; #endif /* * Improve performance of finding otherside of object on shallow angle - * impacts. 120 degrees due to 90 degree offset with _lVelUnit into object. + * impacts. 120 degrees due to 90 degree offset with _lastVelocityUnit into object. */ -private _spallPos = _lPosASL vectorAdd _unitStep; -if (120 > acos ( _lVelUnit vectorDotProduct _sNorm)) then { - _spallPos = _spallPos vectorAdd (_unitStep vectorMultiply 5); +private _spallPosASL = _lastPosASL vectorAdd _deltaStep; +if (120 > acos ( _lastVelocityUnit vectorDotProduct _surfaceNorm)) then { + _spallPosASL = _spallPosASL vectorAdd (_deltaStep vectorMultiply 5); }; private _insideObject = true; for "_i" from 2 to 21 do { - private _nPos = _spallPos vectorAdd _unitStep; - if (!lineIntersects [_spallPos, _nPos]) then { - _spallPos = _nPos vectorAdd (_unitStep vectorMultiply 2); + private _nPos = _spallPosASL vectorAdd _deltaStep; + if (!lineIntersects [_spallPosASL, _nPos]) then { + _spallPosASL = _nPos vectorAdd (_deltaStep vectorMultiply 2); _insideObject = false; break }; - _spallPos = _nPos; + _spallPosASL = _nPos; }; if (_insideObject) exitWith { - TRACE_3("insideObj",_lPosASL,_spallPos,alive _projectile); + TRACE_3("insideObj",_lastPosASL,_spallPosASL,alive _projectile); }; // Passed all exitWiths GVAR(lastSpallTime) = CBA_missionTime; #ifdef DEBUG_MODE_DRAW if GVAR(dbgSphere) then { - [_spallPos, "green"] call FUNC(dev_sphereDraw); + [_spallPosASL, "green"] call FUNC(dev_sphereDraw); }; #endif @@ -124,17 +124,17 @@ private _spawnSize = switch (true) do private _spallSpawner = createVehicle [ "ace_frag_" + _material + _spawnSize, - ASLToATL _spallPos, + ASLToATL _spallPosASL, [], 0, "CAN_COLLIDE" ]; -_spallSpawner setVectorDirandUp [_lVelUnit, _vUp]; -_spallSpawner setVelocity (_lVelUnit vectorMultiply (_dV/2)); +_spallSpawner setVectorDirandUp [_lastVelocityUnit, _vectorUp]; +_spallSpawner setVelocity (_lastVelocityUnit vectorMultiply (_velocityChange/ACE_FRAG_SPALL_VELOCITY_INHERIT_COEFF)); _spallSpawner setShotParents _shotParents; #ifdef DEBUG_MODE_FULL -systemChat ("bSpd: " + str speed _spallSpawner + ", frag: " + _fragSpawnType + ", dm: " + str _spallPower); +systemChat ("spd: " + str speed _spallSpawner + ", spawner: " + _fragSpawnType + ", spallPow: " + str _spallPower); #endif #ifdef DEBUG_MODE_DRAW _spallSpawner addEventHandler [ @@ -144,4 +144,4 @@ _spallSpawner addEventHandler [ [_subProj] call FUNC(dev_addRound); } ]; -#endif \ No newline at end of file +#endif diff --git a/addons/frag/functions/fnc_getFragInfo.sqf b/addons/frag/functions/fnc_getFragInfo.sqf index 6bcde43713..088e19f967 100644 --- a/addons/frag/functions/fnc_getFragInfo.sqf +++ b/addons/frag/functions/fnc_getFragInfo.sqf @@ -9,11 +9,11 @@ * * Return Value: * _ammoInfo - * 0: _fragRange - search range for fragments - * 1: _fragVel - gurney equation calculated velocity - * 2: _fragTypes - array of fragment types + * 0: _fragRange - search range for fragments + * 1: _fragVel - gurney equation calculated velocity + * 2: _fragTypes - array of fragment types * 3: _fragCount - modified frag count used under assumptions - * of spherical fragmentation +* of spherical fragmentation * * Example: * ["B_556x45_Ball"] call ace_frag_fnc_getFragInfo; @@ -38,31 +38,31 @@ if (isArray (configFile >> "cfgAmmo" >> _ammo >> QGVAR(CLASSES))) then { /************ Gurney equation notes *****************//* * see https://en.wikipedia.org/wiki/Gurney_equations * - * GURNEY_K is the constant added to _m/_c + * GURNEY_K is the geometry constant added to _metalMass/_chargeMass * GURNEY_C = sqrt(2E) * - * _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 + * _chargeMass = 185; - grams of comp-b + * _metalMass = 210; - grams of fragmentating metal + * _geometryCoefficient = 3/5; - spherical K factor + * _gurneyConstant = 2843; - Gurney constant of comp-b in /ms * - * _c = 429; - grams of tritonal - * _m = 496; - grams of fragmentating metal - * _k = 1/2; - cylindrical K factor - * _gC = 2320; - Gurney constant of tritonal in m/s + * _chargeMass = 429; - grams of tritonal + * _metalMass = 496; - grams of fragmentating metal + * _geometryCoefficient = 1/2; - cylindrical K factor + * _gurneyConstant = 2320; - Gurney constant of tritonal in m/s * Equation - 0.8 for empirical 80% speed - * 0.8 * (((_m / _c) + _k) ^ - (1 / 2)) * _gC; - * or 0.8 * _gC * sqrt (_c /(_m + _c * _k)); (slightly faster to compute) + * 0.8 * (((_metalMass / _chargeMass) + _geometryCoefficient) ^ - (1 / 2)) * _gurneyConstant; + * or 0.8 * _gurneyConstant * sqrt (_chargeMass /(_metalMass + _chargeMass * _geometryCoefficient)); (slightly faster to compute) */ -private _c = getNumber (configFile >> "cfgAmmo" >> _ammo >> QGVAR(CHARGE)); -if (_c == 0) then {_c = 1; _warn = true;}; -private _m = getNumber (configFile >> "cfgAmmo" >> _ammo >> QGVAR(METAL)); -if (_m == 0) then {_m = 2; _warn = true;}; -private _k = getNumber (configFile >> "cfgAmmo" >> _ammo >> QGVAR(GURNEY_K)); -if (_k == 0) then {_k = 0.8; _warn = true;}; -private _gC = getNumber (configFile >> "cfgAmmo" >> _ammo >> QGVAR(GURNEY_C)); -if (_gC == 0) then {_gC = 2440; _warn = true;}; +private _chargeMass = getNumber (configFile >> "cfgAmmo" >> _ammo >> QGVAR(CHARGE)); +if (_chargeMass == 0) then {_chargeMass = 1; _warn = true;}; +private _metalMass = getNumber (configFile >> "cfgAmmo" >> _ammo >> QGVAR(METAL)); +if (_metalMass == 0) then {_metalMass = 2; _warn = true;}; +private _geometryCoefficient = getNumber (configFile >> "cfgAmmo" >> _ammo >> QGVAR(GURNEY_K)); +if (_geometryCoefficient == 0) then {_geometryCoefficient = 0.8; _warn = true;}; +private _gurneyConstant = getNumber (configFile >> "cfgAmmo" >> _ammo >> QGVAR(GURNEY_C)); +if (_gurneyConstant == 0) then {_gurneyConstant = 2440; _warn = true;}; private _fragCount = getNumber (configFile >> "cfgAmmo" >> _ammo >> QGVAR(fragCount)); if (_fragCount == 0) then {_fragCount = 400; _warn = true;}; @@ -79,11 +79,11 @@ if (_warn) then { * of spherical fragmentation */ _ammoInfo = [ - sqrt (_fragCount / (4 * pi * 0.005)), - 0.8 * _gC * sqrt (_c / (_m + _c * _k)), + sqrt (_fragCount / (4 * pi * ACE_FRAG_MIN_FRAG_HIT_CHANCE)), + 0.8 * _gurneyConstant * sqrt (_chargeMass / (_metalMass + _chargeMass * _geometryCoefficient)), _fragTypes, _fragCount / 4 / pi ]; GVAR(fragInfoCache) set [_ammo, _ammoInfo]; -_ammoInfo \ No newline at end of file +_ammoInfo diff --git a/addons/frag/script_component.hpp b/addons/frag/script_component.hpp index f9006a249e..f435581690 100644 --- a/addons/frag/script_component.hpp +++ b/addons/frag/script_component.hpp @@ -27,7 +27,8 @@ #define ACE_FRAG_HITPOINTS_WEIGHTS // sqrt(2)/50 #define ACE_FRAG_ROUND_COEF 0.02828427 - -#ifndef GLUE -#define GLUE(g1,g2) g1##g2 -#endif \ No newline at end of file +// half of gravity approx 9.81/2 +#define ACE_FRAG_HALF_GRAVITY_APPROX 4.905 +// stop searching at 0.5% chance to hit +#define ACE_FRAG_MIN_FRAG_HIT_CHANCE 0.005 +#define ACE_FRAG_SPALL_VELOCITY_INHERIT_COEFF 2