mirror of
https://github.com/acemod/ACE3.git
synced 2024-08-30 18:23:18 +00:00
Initial commit:
- Added new ammo cfg types - Added new caching functions - Added dev functions - Transfered core system to vanilla projectile EHs - Added stringtable sub categories - Reworked fragmenting and spalling to us submunitions - Frag - Implemented system around chance to hit - Switched from hitbox estimation to hitting specific HPs - Updated chance to miss method based on solid angle hit chance - Split random & targeted frag to their own subfunctions - Spall - Uses a system of estimated momentum changes to generate spall
This commit is contained in:
parent
6c212ca377
commit
3c1e912787
File diff suppressed because it is too large
Load Diff
@ -1,23 +1,33 @@
|
||||
// dev
|
||||
PREP(dev_fragCalcDump);
|
||||
PREP(dev_debugAmmo);
|
||||
PREP(dev_trackHitBox);
|
||||
PREP(dev_fadeRound);
|
||||
PREP(dev_sphereDraw);
|
||||
PREP(dev_addRound);
|
||||
PREP(dev_trackObj);
|
||||
PREP(dev_drawTrace);
|
||||
PREP(dev_clearTraces);
|
||||
PREP(dev_switchUnitHandle);
|
||||
|
||||
PREP(doSpall);
|
||||
// Frag
|
||||
PREP(addBlackList);
|
||||
PREP(initBlackList);
|
||||
PREP(fired);
|
||||
PREP(frago);
|
||||
PREP(spallTrack);
|
||||
PREP(submunition);
|
||||
PREP(shouldFrag);
|
||||
PREP(fragInfo);
|
||||
PREP(doFrag);
|
||||
PREP(doFragTargeted);
|
||||
PREP(doFragRandom);
|
||||
|
||||
// Spall
|
||||
PREP(shouldSpall);
|
||||
PREP(doSpall);
|
||||
PREP(doSpallMomentum);
|
||||
|
||||
// * Other */
|
||||
PREP(addBlackList);
|
||||
PREP(dev_addTrack);
|
||||
PREP(dev_drawTraces);
|
||||
PREP(spallHP);
|
||||
PREP(dev_startTracing);
|
||||
PREP(dev_stopTracing);
|
||||
PREP(dev_trackTrace);
|
||||
|
||||
// New tracking mechanisms
|
||||
PREP(masterPFH);
|
||||
PREP(pfhRound);
|
||||
PREP(addPfhRound);
|
||||
//PREP(spallHP); Look at me !*!
|
||||
|
||||
// Explosive Reflection
|
||||
PREP(findReflections);
|
||||
|
@ -1,32 +1,39 @@
|
||||
#include "script_component.hpp"
|
||||
|
||||
if (isServer) then {
|
||||
GVAR(lastFragTime) = -1;
|
||||
[QGVAR(frag_eh), {_this call FUNC(frago);}] call CBA_fnc_addEventHandler;
|
||||
};
|
||||
|
||||
["CBA_settingsInitialized", {
|
||||
if (!GVAR(enabled)) exitWith {};
|
||||
if (isServer) then {
|
||||
[QGVAR(frag_eh), LINKFUNC(doFrag)] call CBA_fnc_addEventHandler;
|
||||
[QGVAR(spall_eh), LINKFUNC(doFragMomentum)] call CBA_fnc_addEventHandler;
|
||||
[] call FUNC(initBlackList);
|
||||
};
|
||||
|
||||
if (hasInterface) then {
|
||||
["ace_firedPlayer", LINKFUNC(fired)] call CBA_fnc_addEventHandler;
|
||||
["ace_firedPlayerVehicle", LINKFUNC(fired)] call CBA_fnc_addEventHandler;
|
||||
};
|
||||
|
||||
// Register fire event handler
|
||||
["ace_firedPlayer", LINKFUNC(fired)] call CBA_fnc_addEventHandler;
|
||||
["ace_firedNonPlayer", LINKFUNC(fired)] call CBA_fnc_addEventHandler;
|
||||
["ace_firedPlayerVehicle", LINKFUNC(fired)] call CBA_fnc_addEventHandler;
|
||||
["ace_firedNonPlayerVehicle", LINKFUNC(fired)] call CBA_fnc_addEventHandler;
|
||||
["ace_firedNonPlayer", LINKFUNC(fired)] call CBA_fnc_addEventHandler;
|
||||
["ace_firedNonPlayerVehicle", LINKFUNC(fired)] call CBA_fnc_addEventHandler;
|
||||
|
||||
addMissionEventHandler ["EachFrame", {call FUNC(masterPFH)}];
|
||||
// Debug info
|
||||
#ifdef DEBUG_MODE_FULL
|
||||
if (hasInterface && GVAR(debugOptions)) then
|
||||
{
|
||||
private _h = [LINKFUNC(dev_drawTrace), 0] call CBA_fnc_addPerFrameHandler;
|
||||
missionNamespace setVariable [QGVAR(dev_drawPFEH), _h];
|
||||
["unit", LINKFUNC(dev_switchUnitHandle), true] call CBA_fnc_addPlayerEventHandler;
|
||||
[objNull, ace_player] call FUNC(dev_switchUnitHandle);
|
||||
["ace_firedPlayer", LINKFUNC(fired)] call CBA_fnc_addEventHandler;
|
||||
["ace_firedNonPlayer", LINKFUNC(fired)] call CBA_fnc_addEventHandler;
|
||||
["ace_firedPlayerVehicle", LINKFUNC(fired)] call CBA_fnc_addEventHandler;
|
||||
["ace_firedNonPlayerVehicle", LINKFUNC(fired)] call CBA_fnc_addEventHandler;
|
||||
};
|
||||
#endif
|
||||
}] call CBA_fnc_addEventHandler;
|
||||
|
||||
// Cache for ammo type configs
|
||||
GVAR(cacheRoundsTypesToTrack) = [false] call CBA_fnc_createNamespace;
|
||||
|
||||
|
||||
// Debug stuff:
|
||||
|
||||
#ifdef DRAW_FRAG_INFO
|
||||
[] call FUNC(dev_startTracing);
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG_MODE_FULL
|
||||
#ifdef LOG_FRAG_INFO
|
||||
[true, true, 30] call FUNC(dev_debugAmmo);
|
||||
#endif
|
||||
|
@ -6,20 +6,24 @@ PREP_RECOMPILE_START;
|
||||
#include "XEH_PREP.hpp"
|
||||
PREP_RECOMPILE_END;
|
||||
|
||||
GVAR(blackList) = [];
|
||||
GVAR(traceFrags) = false;
|
||||
|
||||
GVAR(spallHPData) = [];
|
||||
GVAR(spallIsTrackingCount) = 0;
|
||||
GVAR(materialSpallCache) = createHashMap;
|
||||
GVAR(spallRoundCache) = createHashMap;
|
||||
|
||||
GVAR(traceID) = -1;
|
||||
GVAR(traces) = [];
|
||||
GVAR(tracesStarted) = false;
|
||||
GVAR(shouldFragCache) = createHashMap;
|
||||
GVAR(fragInfoCache) = createHashMap;
|
||||
GVAR(lastFragTime) = -2;
|
||||
|
||||
GVAR(lastIterationIndex) = 0;
|
||||
GVAR(objects) = [];
|
||||
GVAR(arguments) = [];
|
||||
|
||||
#include "initSettings.inc.sqf"
|
||||
|
||||
#ifdef DEBUG_MODE_FULL
|
||||
GVAR(dev_trackLines) = createHashMap;
|
||||
GVAR(dev_hitBoxes) = createHashMap;
|
||||
GVAR(dev_failedToDelete) = 0;
|
||||
GVAR(dev_eventSpheres) = [];
|
||||
#include "initSettingsDebug.inc.sqf"
|
||||
#endif
|
||||
|
||||
|
||||
ADDON = true;
|
||||
|
@ -1,6 +1,6 @@
|
||||
#include "..\script_component.hpp"
|
||||
#include "script_component.hpp"
|
||||
/*
|
||||
* Author: Jaynus, NouberNou
|
||||
* Author: Jaynus, NouberNou, Lambda.Tiger
|
||||
* Adds a round to the blacklist (will be ignored).
|
||||
*
|
||||
* Arguments:
|
||||
@ -10,12 +10,12 @@
|
||||
* None
|
||||
*
|
||||
* Example:
|
||||
* [bullet] call ace_frag_fnc_addBlackList
|
||||
* [projectile] call ace_frag_fnc_addBlackList
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
|
||||
params ["_round"];
|
||||
params ["_proj"];
|
||||
TRACE_1("addBlackList",_round);
|
||||
|
||||
GVAR(blackList) pushBack _round;
|
||||
GVAR(shouldFragCache) set [typeOf _ammo, [false, false]];
|
||||
|
@ -1,77 +0,0 @@
|
||||
#include "..\script_component.hpp"
|
||||
/*
|
||||
* Author: Jaynus, NouberNou
|
||||
* Starts tracking a round that will frag.
|
||||
* Should only be called once per round.
|
||||
*
|
||||
* Arguments:
|
||||
* 0: Shooter <OBJECT>
|
||||
* 1: Ammo classname <STRING>
|
||||
* 2: Projectile <OBJECT>
|
||||
*
|
||||
* Return Value:
|
||||
* None
|
||||
*
|
||||
* Example:
|
||||
* [player, "handGrenade", bullet] call ace_frag_fnc_addPfhRound
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
|
||||
params ["_gun", "_type", "_round"];
|
||||
TRACE_3("addPfhRound",_gun,_type,_round);
|
||||
|
||||
if (!GVAR(enabled)) exitWith {TRACE_1("setting disabled",_this);};
|
||||
|
||||
if (!alive _round) exitWith {TRACE_1("round dead?",_this);};
|
||||
|
||||
if (_round in GVAR(blackList)) exitWith {
|
||||
TRACE_1("round in blackList",_this);
|
||||
REM(GVAR(blackList),_round);
|
||||
};
|
||||
|
||||
// Exit on max track
|
||||
if ((count GVAR(objects)) >= GVAR(maxTrack)) exitWith {TRACE_1("maxTrack limit",count GVAR(objects));};
|
||||
|
||||
private _doSpall = false;
|
||||
if (GVAR(SpallEnabled)) then {
|
||||
if (GVAR(spallIsTrackingCount) <= 0) then {
|
||||
GVAR(spallHPData) = [];
|
||||
};
|
||||
if (GVAR(spallIsTrackingCount) > 5) then {
|
||||
TRACE_1("At Spall Limit",GVAR(spallIsTrackingCount));
|
||||
} else {
|
||||
_doSpall = true;
|
||||
INC(GVAR(spallIsTrackingCount));
|
||||
};
|
||||
TRACE_2("",_doSpall,GVAR(spallIsTrackingCount));
|
||||
};
|
||||
|
||||
#ifdef DRAW_FRAG_INFO
|
||||
[ACE_player, _round, [0, 1, 0, 1]] call FUNC(dev_addTrack);
|
||||
#endif
|
||||
|
||||
// We only do the single track object check here.
|
||||
// We should do an {!(_round in GVAR(objects))}
|
||||
// But we leave that out here for optimization. So this cannot be a framework function
|
||||
// Otherwise, it should only be added once and from the FiredEH
|
||||
if (alive _round) then {
|
||||
private _spallTrack = [];
|
||||
private _spallTrackID = [];
|
||||
|
||||
private _args = [
|
||||
_round, getPosASL _round, velocity _round, _type, diag_frameno, getPosASL _round, _doSpall, _spallTrack, _spallTrackID,
|
||||
getNumber (configFile >> "CfgAmmo" >> _type >> QGVAR(skip)),
|
||||
getNumber (configFile >> "CfgAmmo" >> _type >> "explosive"),
|
||||
getNumber (configFile >> "CfgAmmo" >> _type >> "indirectHitRange"),
|
||||
getNumber (configFile >> "CfgAmmo" >> _type >> QGVAR(force)),
|
||||
getNumber (configFile >> "CfgAmmo" >> _type >> "indirecthit") * (sqrt (getNumber (configFile >> "CfgAmmo" >> _type >> "indirectHitRange")))
|
||||
];
|
||||
TRACE_1("Initializing track", _round);
|
||||
GVAR(objects) pushBack _round;
|
||||
GVAR(arguments) pushBack _args;
|
||||
|
||||
if (_doSpall) then {
|
||||
[_round, 1, _spallTrack, _spallTrackID] call FUNC(spallTrack);
|
||||
};
|
||||
};
|
114
addons/frag/functions/fnc_dev_addRound.sqf
Normal file
114
addons/frag/functions/fnc_dev_addRound.sqf
Normal file
@ -0,0 +1,114 @@
|
||||
#include "script_component.hpp"
|
||||
/*
|
||||
* Author: Lambda.Tiger
|
||||
* This function adds a round to be traced
|
||||
*
|
||||
* Arguments:
|
||||
* 0: Projectile <OBJECT>
|
||||
* 1: Add projectile event handlers <BOOL>
|
||||
* 2: Is the round blue <BOOL>
|
||||
*
|
||||
* Return Value:
|
||||
* None
|
||||
*
|
||||
* Example:
|
||||
* [_proj, false, false] call ace_frag_dev_addRound;
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
params [
|
||||
"_proj",
|
||||
["_addEHs", true, [false]],
|
||||
["_sidePlayer", true, [false]]
|
||||
];
|
||||
|
||||
/// track round on each frame
|
||||
// Create entry in position array from hashmap
|
||||
private _pID = getObjectID _proj;
|
||||
if (GVAR(fadeRounds)) then
|
||||
{
|
||||
if (_sidePlayer) then
|
||||
{
|
||||
GVAR(dev_trackLines) set [_pID, [__FADE_INIT, [getposATL _proj], [0, 0, 1, __FADE_INIT]]];
|
||||
} else
|
||||
{
|
||||
GVAR(dev_trackLines) set [_pID, [__FADE_INIT, [getposATL _proj], [1, 0.5, 0, __FADE_INIT]]];
|
||||
};
|
||||
|
||||
// add fading factor
|
||||
[LINKFUNC(dev_fadeRound), __FADE_INTERVAL, [_pID]] call CBA_fnc_addPerFrameHandler;
|
||||
} else
|
||||
{
|
||||
if (_sidePlayer) then
|
||||
{
|
||||
GVAR(dev_trackLines) set [_pID, [1, [getposATL _proj], [0, 0, 1, 1]]];
|
||||
} else
|
||||
{
|
||||
GVAR(dev_trackLines) set [_pID, [1, [getposATL _proj], [1, 0, 0, 1]]];
|
||||
};
|
||||
};
|
||||
// eventhandler to track round and cleanup when round is "dead"
|
||||
[
|
||||
{
|
||||
if (isGamePaused) exitWith {};
|
||||
params ["_par", "_h"];
|
||||
_par params ["_proj"];
|
||||
if (!alive _proj) exitWith
|
||||
{
|
||||
[_h] call CBA_fnc_removePerFrameHandler;
|
||||
};
|
||||
private _arr = GVAR(dev_trackLines) getOrDefault [(getObjectID _proj), -1];
|
||||
if (typeName _arr == "SCALAR") exitWith {};
|
||||
(_arr#1) pushBack getPosATL _proj;
|
||||
if (_arr#0 <= 0) exitWith
|
||||
{
|
||||
[_h] call CBA_fnc_removePerFrameHandler;
|
||||
};
|
||||
},
|
||||
0,
|
||||
[_proj]
|
||||
] call CBA_fnc_addPerFrameHandler;
|
||||
|
||||
if (!_addEHs) exitWith {};
|
||||
|
||||
// Add hitpart eventHandler
|
||||
_proj addEventHandler [
|
||||
"HitPart",
|
||||
{
|
||||
params ["_proj", "", "", "_posASL"];
|
||||
private _arr = (GVAR(dev_trackLines) get (getObjectID _proj))#1;
|
||||
_arr pushBack ASLtoATL _posASL;
|
||||
if (GVAR(dbgSphere)) then
|
||||
{
|
||||
[_posASL, "green"] call FUNC(dev_sphereDraw);
|
||||
};
|
||||
}
|
||||
];
|
||||
|
||||
// Add explode eventHandler
|
||||
_proj addEventHandler [
|
||||
"Explode",
|
||||
{
|
||||
params ["_proj", "_posASL"];
|
||||
private _arr = (GVAR(dev_trackLines) get (getObjectID _proj))#1;
|
||||
_arr pushBack ASLtoATL _posASL;
|
||||
if (GVAR(dbgSphere)) then
|
||||
{
|
||||
[_posASL, "red"] call FUNC(dev_sphereDraw);
|
||||
};
|
||||
}
|
||||
];
|
||||
|
||||
// Add deflected eventHandler
|
||||
_proj addEventHandler [
|
||||
"Deflected",
|
||||
{
|
||||
params ["_proj", "_posASL"];
|
||||
private _arr = (GVAR(dev_trackLines) get (getObjectID _proj))#1;
|
||||
_arr pushBack ASLtoATL _posASL;
|
||||
if (GVAR(dbgSphere)) then
|
||||
{
|
||||
[_posASL, "blue"] call FUNC(dev_sphereDraw);
|
||||
};
|
||||
}
|
||||
];
|
@ -1,26 +0,0 @@
|
||||
#include "..\script_component.hpp"
|
||||
/*
|
||||
* Author: ACE-Team
|
||||
*
|
||||
*
|
||||
* Arguments:
|
||||
* None
|
||||
*
|
||||
* Return Value:
|
||||
* None
|
||||
*
|
||||
* Example:
|
||||
* call ace_frag_fnc_dev_addTrack
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
|
||||
params ["_origin", "_obj", ["_color", [1, 0, 0, 1]]];
|
||||
|
||||
private _positions = [];
|
||||
private _objSpd = vectorMagnitude (velocity _obj);
|
||||
_positions pushBack [getPos _obj, _objSpd];
|
||||
private _data = [_origin, typeOf _origin, typeOf _obj, _objSpd, _positions, _color];
|
||||
|
||||
private _index = GVAR(traces) pushBack _data;
|
||||
[DFUNC(dev_trackTrace), 0, [_obj, _index, CBA_missionTime]] call CBA_fnc_addPerFrameHandler;
|
24
addons/frag/functions/fnc_dev_clearTraces.sqf
Normal file
24
addons/frag/functions/fnc_dev_clearTraces.sqf
Normal file
@ -0,0 +1,24 @@
|
||||
#include "script_component.hpp"
|
||||
/*
|
||||
* Author: Lambda.Tiger
|
||||
* Cleares all dev spheres and traces
|
||||
*
|
||||
* Arguments:
|
||||
* None
|
||||
*
|
||||
* Return Value:
|
||||
* None
|
||||
*
|
||||
* Example:
|
||||
* [] call ace_frag_fnc_dev_clearTraces;
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
GVAR(dev_trackLines) = createHashMap;
|
||||
for "_i" from 0 to count GVAR(dev_eventSpheres) - 1 do
|
||||
{
|
||||
deleteVehicle (GVAR(dev_eventSpheres)#_i);
|
||||
};
|
||||
GVAR(dev_eventSpheres) = +[];
|
||||
|
||||
GVAR(dev_hitBoxes) = createHashMap;
|
75
addons/frag/functions/fnc_dev_drawTrace.sqf
Normal file
75
addons/frag/functions/fnc_dev_drawTrace.sqf
Normal file
@ -0,0 +1,75 @@
|
||||
#include "script_component.hpp"
|
||||
/*
|
||||
* Author: Lambda.Tiger
|
||||
* Per frame function to draw all dev traces
|
||||
*
|
||||
* Arguments:
|
||||
* none
|
||||
*
|
||||
* Return Value:
|
||||
* None
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
|
||||
private _deleteArr = [];
|
||||
{
|
||||
private _alpha = _y#0;
|
||||
// leave if trace is not to be drawn
|
||||
if (GVAR(dltTrace) && _alpha <= 0) then
|
||||
{
|
||||
_deleteArr pushBack _x;
|
||||
continue;
|
||||
};
|
||||
|
||||
if (count (_y#1) > 1) then
|
||||
{
|
||||
private _color = _y#2;
|
||||
for "_j" from 1 to count (_y#1) - 1 do
|
||||
{
|
||||
drawLine3D [_y#1#(_j-1), _y#1#_j, _color];
|
||||
};
|
||||
};
|
||||
} forEach GVAR(dev_trackLines);
|
||||
|
||||
if (GVAR(dltTrace)) then
|
||||
{
|
||||
for "_i" from 0 to count _deleteArr - 1 do
|
||||
{
|
||||
GVAR(dev_trackLines) deleteAt (_deleteArr#_i);
|
||||
};
|
||||
};
|
||||
|
||||
if (GVAR(drawHitBox)) then {
|
||||
|
||||
#define HB_DRAW_ARRS [[3,2,1,5,6,7,3,0,4,5],[0,1],[2,6],[7,4]]
|
||||
_deleteArr = [];
|
||||
{
|
||||
_y params ["_obj", "_pts", "_color"];
|
||||
if (!alive _obj) then
|
||||
{
|
||||
_deleteArr pushBack _x;
|
||||
continue;
|
||||
};
|
||||
|
||||
{
|
||||
for "_i" from 1 to count _x -1 do
|
||||
{
|
||||
drawLine3D [_obj modelToWorld (_pts#(_x#_i)), _obj modelToWorld (_pts#(_x#(_i-1))), _color];
|
||||
};
|
||||
} forEach HB_DRAW_ARRS;
|
||||
|
||||
} forEach GVAR(dev_hitBoxes);
|
||||
|
||||
for "_i" from 0 to count _deleteArr - 1 do
|
||||
{
|
||||
GVAR(dev_hitBoxes) deleteAt (_deleteArr#_i);
|
||||
};
|
||||
};
|
||||
|
||||
if (GVAR(frameHint)) then
|
||||
{
|
||||
hintsilent str (1/diag_deltaTime);
|
||||
};
|
@ -1,37 +0,0 @@
|
||||
#include "..\script_component.hpp"
|
||||
/*
|
||||
* Author: ACE-Team
|
||||
*
|
||||
*
|
||||
* Arguments:
|
||||
* None
|
||||
*
|
||||
* Return Value:
|
||||
* None
|
||||
*
|
||||
* Example:
|
||||
* call ace_frag_fnc_dev_drawTraces
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
|
||||
{
|
||||
_x params ["", "", "", "", "_positions", "_color"];
|
||||
private _index = 0;
|
||||
private _max = count _positions;
|
||||
// private _lastSpd = [];
|
||||
private _lastPos = [];
|
||||
while {_index < _max} do {
|
||||
_data1 = _positions select _index;
|
||||
_data2 = _positions select ([_index + ACE_TRACE_DRAW_INC, _max - 1] select (_index + ACE_TRACE_DRAW_INC >= _max));
|
||||
|
||||
_pos1 = _data1 select 0;
|
||||
_pos2 = _data2 select 0;
|
||||
ADD(_index,ACE_TRACE_DRAW_INC);
|
||||
|
||||
drawLine3D [_pos1, _pos2, _color];
|
||||
_lastPos = _pos2;
|
||||
// _lastSpd = _data1 select 1;
|
||||
};
|
||||
// drawIcon3D ["", [1,0,0,1], _lastPos, 0, 0, 0, format ["%1m/s", _lastSpd], 1, 0.05, "RobotoCondensed"];
|
||||
} forEach GVAR(traces);
|
34
addons/frag/functions/fnc_dev_fadeRound.sqf
Normal file
34
addons/frag/functions/fnc_dev_fadeRound.sqf
Normal file
@ -0,0 +1,34 @@
|
||||
#include "script_component.hpp"
|
||||
/*
|
||||
* Author: Lambda.Tiger
|
||||
* Fades a trace over time based on given parameters
|
||||
*
|
||||
* Arguments:
|
||||
* 0: PFEH arguments <ARRAY>
|
||||
* 1: PHEH handle <SCALAR>
|
||||
*
|
||||
* Return Value:
|
||||
* None
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
params ["_args", "_h"];
|
||||
|
||||
private _arr = GVAR(dev_trackLines) getOrDefault [(_args#0), []];
|
||||
if (count _arr < 3) exitWith
|
||||
{
|
||||
[_h] call CBA_fnc_removePerFrameHandler;
|
||||
};
|
||||
|
||||
private _alpha = _arr#0;
|
||||
private _color = _arr#2;
|
||||
_alpha = (_alpha - __FADE_RATE) min 1;
|
||||
_arr set [0, _alpha];
|
||||
_color set [3, _alpha];
|
||||
_color set [1, (0.5 - _alpha/2) max 0];
|
||||
if (_alpha <= 0 ) then
|
||||
{
|
||||
[_h] call CBA_fnc_removePerFrameHandler;
|
||||
};
|
90
addons/frag/functions/fnc_dev_fragCalcDump.sqf
Normal file
90
addons/frag/functions/fnc_dev_fragCalcDump.sqf
Normal file
@ -0,0 +1,90 @@
|
||||
#include "script_component.hpp"
|
||||
/*
|
||||
* Author: Lambda.Tiger, based on fnc_dev_debugAmmo by "ACE-Team"
|
||||
* Dumps all ammo types to see if there's any reason to spawn fragments
|
||||
* given power, distance, and lifetime of each fragement
|
||||
*
|
||||
* Arguments:
|
||||
* 0: _dispAll <BOOL> - Display rounds that will never frag (power < 5).
|
||||
* Default value false
|
||||
* 1: _minFrgPowRng <FLOAT> - minimum range for sqrt power calculation
|
||||
*
|
||||
* Return Value:
|
||||
* None
|
||||
*
|
||||
* Example:
|
||||
* [false, 10] call ace_frag_fnc_fragoCalcDump
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
|
||||
params [["_dispAll", false, [false]], ["_minFrgPowRng", 35, [123]]];
|
||||
|
||||
#define DT 0.01
|
||||
|
||||
private _allMagsConfigs = configProperties [configFile >> "cfgAmmo", "isClass _x && !('ace' in configName _x)", true];
|
||||
private _processedCfgAmmos = [];
|
||||
|
||||
|
||||
|
||||
private _nPrinted = 0;
|
||||
|
||||
diag_log text "//****************** fragCalcDump Beg ******************//";
|
||||
// Processing ammo types
|
||||
{
|
||||
private _ammo = toLower configName _x;
|
||||
|
||||
if (_ammo == "" || {_ammo in _processedCfgAmmos} ) then {continue};
|
||||
|
||||
|
||||
// calculating hit range
|
||||
|
||||
private _skip = getNumber (configFile >> "cfgAmmo" >> _ammo >> QGVAR(skip));
|
||||
private _force = getNumber (configFile >> "cfgAmmo" >> _ammo >> QGVAR(force));
|
||||
private _explosive = getNumber (configFile >> "cfgAmmo" >> _ammo >> "explosive");
|
||||
private _indirectHit = getNumber(configFile >> "cfgAmmo" >> _ammo >> "indirectHit");
|
||||
private _indirectRange = getNumber(configFile >> "cfgAmmo" >> _ammo >> "indirectHitRange");
|
||||
|
||||
_shouldFrag = if (_skip == 1 || (_force == 0 && {_explosive < 0.5 || {_indirectHit < 3
|
||||
|| {_indirectRange < 5 && _indirectHit < _indirectRange}}})) then {
|
||||
false;
|
||||
} else {
|
||||
true;
|
||||
};
|
||||
|
||||
// Gunery equation from frago
|
||||
private _c = getNumber (configFile >> "cfgAmmo" >> _ammo >> QGVAR(CHARGE));
|
||||
if (_c == 0) then {_c = 1;};
|
||||
private _m = getNumber (configFile >> "cfgAmmo" >> _ammo >> QGVAR(METAL));
|
||||
if (_m == 0) then {_m = 2;};
|
||||
private _k = getNumber (configFile >> "cfgAmmo" >> _ammo >> QGVAR(GURNEY_K));
|
||||
if (_k == 0) then {_k = 0.8;};
|
||||
private _gC = getNumber (configFile >> "cfgAmmo" >> _ammo >> QGVAR(GURNEY_C));
|
||||
if (_gC == 0) then {_gC = 2440;};
|
||||
private _fragCount = getNumber (configFile >> "cfgAmmo" >> _ammo >> QGVAR(fragCount));
|
||||
if (_fragCount == 0) then {_fragCount = 200; _warn = true};
|
||||
profilerLog (str (sqrt (_fragCount / (4 * pi * 0.005))));
|
||||
private _velocity = 0.8 * _gC * sqrt (_c /(_m + _c * _k));
|
||||
// number of shrapnel to send a direction
|
||||
private _count = ceil (random (sqrt (_m / 1000)));
|
||||
private _fragPowerSpeedRange = [0.5, 1] vectorMultiply _fragPower;
|
||||
|
||||
if (_nSkip || _dispALl) then
|
||||
{
|
||||
diag_log text format ["Ammo type: %1", _ammo];
|
||||
diag_log text format [" Indirect hit range: %1", _indirectHitRange];
|
||||
diag_log text format [" Frag sqrtPower: %1", _fragPowerSqrt];
|
||||
diag_log text format [" Frag range: %1", _fragRange];
|
||||
diag_log text format [" Frag speed range: %1", _fragPowerSpeedRange];
|
||||
diag_log text format [" Number frags: %1", _count];
|
||||
diag_log text " ~~~ Fragments ~~~";
|
||||
|
||||
|
||||
INC(_nPrinted);
|
||||
};
|
||||
|
||||
_processedCfgAmmos pushBack _ammo;
|
||||
} forEach _allMagsConfigs;
|
||||
|
||||
diag_log text "//****************** fragCalcDump End ******************//";
|
||||
diag_log text format ["//********************** printed %1 *********************//", _nPrinted];
|
52
addons/frag/functions/fnc_dev_sphereDraw.sqf
Normal file
52
addons/frag/functions/fnc_dev_sphereDraw.sqf
Normal file
@ -0,0 +1,52 @@
|
||||
#include "script_component.hpp"
|
||||
/*
|
||||
* Author: Lambda.Tiger
|
||||
* Add a colored sphere at a specified point
|
||||
*
|
||||
* Arguments:
|
||||
* 0: ASL position to add sphere <ARRAY>
|
||||
* 1: Color of sphere <STRING>
|
||||
*
|
||||
* Return Value:
|
||||
* None
|
||||
*
|
||||
* Example:
|
||||
* [unit0, player] call ace_frag_fnc_dev_switchUnitHandle;
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
params [
|
||||
["_posASL", [0,0,0], [[]], [2,3]],
|
||||
["_color", "(1,0,0,0.5)", [""]]
|
||||
];
|
||||
|
||||
if (count _posASL < 3) then
|
||||
{
|
||||
_posASL pushBack 0;
|
||||
_posASL = ASLtoATL _posASL;
|
||||
_posASL set [2, 0];
|
||||
_posASL = ATLtoASL _posASL;
|
||||
};
|
||||
|
||||
if (_color select [0,1] != "(") then
|
||||
{
|
||||
switch (toLower _color) do
|
||||
{
|
||||
case "blue": { _color = "(0,0,0.8,0.5)"; };
|
||||
case "black": { _color = "(1,1,1,0.5)"; };
|
||||
case "white": { _color = "(0,0,0,0.5)"; };
|
||||
case "red": { _color = "(0.8,0,0,0.5)"; };
|
||||
case "green": { _color = "(0,0.8,0,0.5)"; };
|
||||
case "yellow": { _color = "(0.8,0.8,0,0.5)"; };
|
||||
case "orange": { _color = "(0.8,0.518,0,0.5)"; };
|
||||
default { _color = "(0.8,0.8,0,0.5)";};
|
||||
};
|
||||
};
|
||||
private _clrStr = "#(argb,8,8,3)color" + _color;
|
||||
|
||||
private _sphere = "Sign_Sphere25cm_F" createVehicle [1,2,34];
|
||||
_sphere setObjectTexture [0, _clrStr];
|
||||
_sphere setPosASL _posASL;
|
||||
GVAR(dev_eventSpheres) pushBack _sphere;
|
||||
|
||||
_sphere;
|
@ -1,23 +0,0 @@
|
||||
#include "..\script_component.hpp"
|
||||
/*
|
||||
* Author: ACE-Team
|
||||
*
|
||||
*
|
||||
* Arguments:
|
||||
* None
|
||||
*
|
||||
* Return Value:
|
||||
* None
|
||||
*
|
||||
* Example:
|
||||
* call ace_frag_fnc_dev_startTracing
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
|
||||
if (GVAR(tracesStarted)) exitWith {};
|
||||
|
||||
INFO("Starting Trace Drawing");
|
||||
|
||||
GVAR(tracesStarted) = true;
|
||||
GVAR(traceID) = [LINKFUNC(dev_drawTraces), 0, []] call CBA_fnc_addPerFrameHandler;
|
@ -1,23 +0,0 @@
|
||||
#include "..\script_component.hpp"
|
||||
/*
|
||||
* Author: ACE-Team
|
||||
* Dev things
|
||||
*
|
||||
* Arguments:
|
||||
* None
|
||||
*
|
||||
* Return Value:
|
||||
* None
|
||||
*
|
||||
* Example:
|
||||
* None
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
|
||||
if (!GVAR(tracesStarted)) exitWith {};
|
||||
|
||||
INFO("Ending Trace Drawing");
|
||||
|
||||
GVAR(tracesStarted) = false;
|
||||
[GVAR(traceID)] call CBA_fnc_removePerFrameHandler;
|
43
addons/frag/functions/fnc_dev_switchUnitHandle.sqf
Normal file
43
addons/frag/functions/fnc_dev_switchUnitHandle.sqf
Normal file
@ -0,0 +1,43 @@
|
||||
#include "script_component.hpp"
|
||||
/*
|
||||
* Author: Lambda.Tiger
|
||||
* Handle for debug actions when switching units
|
||||
*
|
||||
* Arguments:
|
||||
* 0: Last unit <OBJECT>
|
||||
* 1: Current unit <OBJECT>
|
||||
*
|
||||
* Return Value:
|
||||
* None
|
||||
*
|
||||
* Example:
|
||||
* [unit0, player] call ace_frag_fnc_dev_switchUnitHandle;
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
params ["_lVic", "_cVic"];
|
||||
|
||||
|
||||
if (_cVic isEqualTo objNull || {!local _cVic || _lVic isEqualTo _cVic}) exitWith {};
|
||||
|
||||
|
||||
private _aID = missionNamespace getVariable [QGVAR(dev_clearTraceAction), -1];
|
||||
if (_aID > -1 && {_lVic isNotEqualTo objNull}) then
|
||||
{
|
||||
_lVic removeAction _aID;
|
||||
};
|
||||
|
||||
_aID = _cVic addAction
|
||||
[
|
||||
"Reset Lines",
|
||||
FUNC(dev_clearTraces),
|
||||
nil, // arguments
|
||||
1.5, // priority
|
||||
true, // showWindow
|
||||
false, // hideOnUse
|
||||
"", // shortcut
|
||||
"true", // condition
|
||||
8
|
||||
];
|
||||
|
||||
missionNamespace getVariable [QGVAR(dev_clearTraceAction), _aID];
|
71
addons/frag/functions/fnc_dev_trackHitBox.sqf
Normal file
71
addons/frag/functions/fnc_dev_trackHitBox.sqf
Normal file
@ -0,0 +1,71 @@
|
||||
#include "script_component.hpp"
|
||||
/*
|
||||
* Author: Lambda.Tiger
|
||||
* Add a hitbox outline to an object
|
||||
*
|
||||
* Arguments:
|
||||
* 0: Object to draw hitbox <OBJECT>
|
||||
* 1: Add center sphere <BOOL>
|
||||
*
|
||||
* Return Value:
|
||||
* None
|
||||
*
|
||||
* Example:
|
||||
* [player] call ace_frag_fnc_dev_trackHitBox;
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
params [
|
||||
["_obj", objNull, [objNull]],
|
||||
["_addSphere", true, [false]]
|
||||
];
|
||||
|
||||
if (isNull _obj) exitWith {};
|
||||
|
||||
private _box = [];
|
||||
if (_obj isKindOf "CAManBase") then {
|
||||
if (vehicle _obj == _obj) then {
|
||||
_box = 0 boundingBox _obj;
|
||||
} else {
|
||||
_box = boundingBoxReal [_obj, "Geometry"];
|
||||
};
|
||||
} else {
|
||||
_box = boundingBoxReal [_obj, "FireGeometry"];
|
||||
};
|
||||
_box params ["_lowP","_upP"];
|
||||
|
||||
private _stance = stance _obj;
|
||||
switch (true) do {
|
||||
case (_stance isEqualTo "STAND"): {_upP set [2, 1.9];};
|
||||
case (_stance isEqualTo "CROUCH"): {_upP set [2, 1.3];};
|
||||
case (_stance isEqualTo "PRONE"): {_upP set [2, 0.8];};
|
||||
};
|
||||
private _centerPoint = ASLToAGL getPosASL _obj;
|
||||
|
||||
if (_addSphere && vehicle _obj isEqualTo _obj) then {
|
||||
private _centerSphere = [getPosASL _obj, "yellow"] call FUNC(dev_sphereDraw);
|
||||
_centerSphere disableCollisionWith vehicle _obj;
|
||||
_centerSphere attachTo [_obj, _obj worldToModel _centerPoint];
|
||||
};
|
||||
private _p1 = _upP;
|
||||
private _p7 = _lowP;
|
||||
|
||||
private _points =[
|
||||
_upP,
|
||||
[_p1#0,_p7#1,_p1#2],
|
||||
[_p7#0,_p7#1,_p1#2],
|
||||
[_p7#0,_p1#1,_p1#2],
|
||||
[_p1#0,_p1#1,_p7#2],
|
||||
[_p1#0,_p7#1,_p7#2],
|
||||
_lowP,
|
||||
[_p7#0,_p1#1,_p7#2]
|
||||
];
|
||||
|
||||
_color = switch (side _obj) do {
|
||||
case east: {[1, 0, 0, 1]};
|
||||
case resistance: {[0, 1, 0, 1]};
|
||||
default {[0, 0, 1, 1]};
|
||||
};
|
||||
//TRACE_3("box params", _obj, _points, _color);
|
||||
|
||||
GVAR(dev_hitBoxes) set [getObjectID _obj, [_obj, _points, _color]];
|
123
addons/frag/functions/fnc_dev_trackObj.sqf
Normal file
123
addons/frag/functions/fnc_dev_trackObj.sqf
Normal file
@ -0,0 +1,123 @@
|
||||
#include "script_component.hpp"
|
||||
/*
|
||||
* Author: Lambda.Tiger
|
||||
* This function adds an object to have it's course tracked (every frame).
|
||||
*
|
||||
* Arguments:
|
||||
* 0: Object to draw hitbox <OBJECT>
|
||||
* 1: Color of trace <STRING>
|
||||
* 2: Whether the object is a projectile <BOOL>
|
||||
*
|
||||
* Return Value:
|
||||
* None
|
||||
*
|
||||
* Example:
|
||||
* [player] call ace_frag_fnc_dev_trackObj;
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
params ["_obj", ["_color", "blue", [""]], ["_isProj", false, [false]]];
|
||||
|
||||
/// track round on each frame
|
||||
// Create entry in position array from hashmap
|
||||
private _pID = getObjectID _obj;
|
||||
if (GVAR(fadeRounds)) then
|
||||
{
|
||||
private _colorArray = switch (toLower _color) do {
|
||||
case "purple": {[0.8, 0, 0.8, __FADE_INIT]};
|
||||
case "blue": {[0, 0, 0.8, __FADE_INIT]};
|
||||
case "green": {[0, 0.8, 0, __FADE_INIT]};
|
||||
case "orange": {[0.8, 0.518, 0, __FADE_INIT]};
|
||||
case "yellow": {[0.8, 0.8, 0, __FADE_INIT] };
|
||||
case "red": {[0.8, 0, 0, __FADE_INIT]};
|
||||
case "black": {[1, 1, 1, __FADE_INIT]};
|
||||
case "white": {[0, 0, 0, __FADE_INIT]};
|
||||
default {[0, 0.8, 0.8, __FADE_INIT]};
|
||||
};
|
||||
|
||||
GVAR(dev_trackLines) set [_pID, [__FADE_INIT, [getposATL _obj], _colorArray]];
|
||||
// add fading factor
|
||||
[LINKFUNC(dev_fadeRound), __FADE_INTERVAL, [_pID]] call CBA_fnc_addPerFrameHandler;
|
||||
} else
|
||||
{
|
||||
private _colorArray = switch (toLower _color) do {
|
||||
case "purple": {[0.8, 0, 0.8, 1]};
|
||||
case "blue": {[0, 0, 0.8, 1]};
|
||||
case "green": {[0, 0.8, 0, 1]};
|
||||
case "orange": {[0.8, 0.518, 0, 1]};
|
||||
case "yellow": {[0.8, 0.8, 0, 1] };
|
||||
case "red": {[0.8, 0, 0, 1]};
|
||||
case "black": {[1, 1, 1, 1]};
|
||||
case "white": {[0, 0, 0, 1]};
|
||||
default {[0, 0.8, 0.8, 1]};
|
||||
};
|
||||
GVAR(dev_trackLines) set [_pID, [1, [getposATL _obj], _colorArray]];
|
||||
};
|
||||
// eventhandler to track round and cleanup when round is "dead"
|
||||
[
|
||||
{
|
||||
if (isGamePaused) exitWith {};
|
||||
params ["_par", "_h"];
|
||||
_par params ["_obj"];
|
||||
if (!alive _obj) exitWith {
|
||||
[_h] call CBA_fnc_removePerFrameHandler;
|
||||
};
|
||||
private _arr = GVAR(dev_trackLines) getOrDefault [(getObjectID _obj), -1];
|
||||
|
||||
if (typeName _arr isEqualTo "SCALAR") exitWith {
|
||||
[_h] call CBA_fnc_removePerFrameHandler;
|
||||
};
|
||||
|
||||
(_arr#1) pushBack getPosATL _obj;
|
||||
if (_arr#0 <= 0) exitWith {
|
||||
[_h] call CBA_fnc_removePerFrameHandler;
|
||||
};
|
||||
},
|
||||
0,
|
||||
[_obj]
|
||||
] call CBA_fnc_addPerFrameHandler;
|
||||
|
||||
if (!_isProj) exitWith {};
|
||||
|
||||
|
||||
// Add hitpart eventHandler
|
||||
_obj addEventHandler [
|
||||
"HitPart",
|
||||
{
|
||||
params ["_proj", "", "", "_posASL"];
|
||||
private _arr = (GVAR(dev_trackLines) get (getObjectID _proj))#1;
|
||||
_arr pushBack ASLtoATL _posASL;
|
||||
if (GVAR(dbgSphere)) then
|
||||
{
|
||||
[_posASL, "green"] call FUNC(dev_sphereDraw);
|
||||
};
|
||||
}
|
||||
];
|
||||
|
||||
// Add explode eventHandler
|
||||
_obj addEventHandler [
|
||||
"Explode",
|
||||
{
|
||||
params ["_proj", "_posASL"];
|
||||
private _arr = (GVAR(dev_trackLines) get (getObjectID _proj))#1;
|
||||
_arr pushBack ASLtoATL _posASL;
|
||||
if (GVAR(dbgSphere)) then
|
||||
{
|
||||
[_posASL, "red"] call FUNC(dev_sphereDraw);
|
||||
};
|
||||
}
|
||||
];
|
||||
|
||||
// Add deflected eventHandler
|
||||
_proj addEventHandler [
|
||||
"Deflected",
|
||||
{
|
||||
params ["_proj", "_posASL"];
|
||||
private _arr = (GVAR(dev_trackLines) get (getObjectID _proj))#1;
|
||||
_arr pushBack ASLtoATL _posASL;
|
||||
if (GVAR(dbgSphere)) then
|
||||
{
|
||||
[_posASL, "blue"] call FUNC(dev_sphereDraw);
|
||||
};
|
||||
}
|
||||
];
|
@ -1,27 +0,0 @@
|
||||
#include "..\script_component.hpp"
|
||||
/*
|
||||
* Author: ACE-Team
|
||||
* Dev things
|
||||
*
|
||||
* Arguments:
|
||||
* None
|
||||
*
|
||||
* Return Value:
|
||||
* None
|
||||
*
|
||||
* Example:
|
||||
* call ace_frag_fnc_dev_trackTrace
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
|
||||
params ["_args", "_pfhID"];
|
||||
_args params ["_tracerObj", "_index"];
|
||||
|
||||
if (alive _tracerObj && {GVAR(traces) isNotEqualTo []}) then {
|
||||
private _data = GVAR(traces) select _index;
|
||||
private _positions = _data select 4;
|
||||
_positions pushBack [getPos _tracerObj, vectorMagnitude (velocity _tracerObj)];
|
||||
} else {
|
||||
[_pfhID] call CBA_fnc_removePerFrameHandler;
|
||||
};
|
59
addons/frag/functions/fnc_doFrag.sqf
Normal file
59
addons/frag/functions/fnc_doFrag.sqf
Normal file
@ -0,0 +1,59 @@
|
||||
#include "script_component.hpp"
|
||||
/*
|
||||
* Author: Lambda.Tiger
|
||||
* This function handles creating both random and targeted fragments as well
|
||||
* as handling some of the performance optimizations.
|
||||
*
|
||||
* Arguments:
|
||||
* 0: Array of argumentse
|
||||
* 0.0: projectile that's fragmenting <OBJECT>
|
||||
* 0.1: ASL position of projectile <ARRAY>
|
||||
* 0.2: velocity of projectile <ARRAY>
|
||||
* 1: Whether the projectile is a submunition <BOOL>
|
||||
*
|
||||
* Return Value:
|
||||
* None
|
||||
*
|
||||
* Example:
|
||||
* [[_proj, getPosASL _proj, velocity _proj]] call ace_frag_fnc_doFrag;
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
|
||||
params ["_args", ["_isSubMunit", false, [false]]];
|
||||
_args params [
|
||||
["_proj", objNull, [objNull]],
|
||||
["_posASL", [0,0,0], [[]], [3]],
|
||||
["_vel", [0,0,0] , [[]], [3]]
|
||||
];
|
||||
|
||||
private _timeSince = CBA_missionTime - GVAR(lastFragTime);
|
||||
if (isNull _proj || {_posASL isEqualTo [0,0,0] || _timeSince < 0.2}) exitWith {};
|
||||
GVAR(lastFragTime) = CBA_missionTime;
|
||||
private _maxFrags = round (linearConversion [0.1, 1.5, _timeSince, MAX_FRAG_COUNT_MIN, MAX_FRAG_COUNT_MAX, true]);
|
||||
|
||||
private _ammo = typeOf _proj;
|
||||
private _ammoArr = [_ammo] call FUNC(fragInfo);
|
||||
_ammoArr params ["_fragRange", "_fragVel", "_fragTypes", "_modFragCount"];
|
||||
|
||||
private _shotParents = getShotParents _proj;
|
||||
|
||||
private _heightAGL = (ASLToAGL _posASL)#2;
|
||||
if (_heightAGL < 0.25) then {
|
||||
_posASL = _posASL vectorAdd [0, 0, 0.25];
|
||||
};
|
||||
|
||||
// make timesince a gvar?
|
||||
TRACE_4("fnc_doFragTargeted IF", _fragRange, _timeSince, _isSubMunit, GVAR(enSubMunit));
|
||||
if (_fragRange > 3 && _timeSince > 0.3 && {!_isSubMunit || {GVAR(enSubMunit) == 2}}) then {
|
||||
_maxFrags = _maxFrags - ([_posASL, _fragVel, _fragRange, _maxFrags, _fragTypes, _modFragCount, _shotParents] call FUNC(doFragTargeted));
|
||||
};
|
||||
|
||||
// make a gvar?
|
||||
if (_timeSince > 0.2 && {GVAR(enSubMunit) != 0}) then {
|
||||
[_posASL, _vel, _heightAGL, _fragTypes, _maxFrags, _shotParents] call FUNC(doFragRandom);
|
||||
};
|
||||
|
||||
if (GVAR(reflectionsEnabled)) then {
|
||||
[_posASL, _shellType] call FUNC(doReflections);
|
||||
};
|
71
addons/frag/functions/fnc_doFragRandom.sqf
Normal file
71
addons/frag/functions/fnc_doFragRandom.sqf
Normal file
@ -0,0 +1,71 @@
|
||||
#include "script_component.hpp"
|
||||
/*
|
||||
* Author: Lambda.Tiger
|
||||
* This function creates fragments randomly spreading out from an explosion to
|
||||
* a maximum of 15
|
||||
*
|
||||
* Arguments:
|
||||
* 0: Position of fragmenting projectile ASL <ARRAY>
|
||||
* 1: Velocity of the fragmenting projectile <ARRAY>
|
||||
* 2: Height (AGL) of the fragmenting projectile <SCALAR>
|
||||
* 3: Type of fragments to generate
|
||||
* 4: Remaining fragment budget <SCALAR>
|
||||
* 5: Shot parent <ARRAY>
|
||||
*
|
||||
* Return Value:
|
||||
* None
|
||||
*
|
||||
* Example:
|
||||
* [getPosASL _proj, velocity _proj, 50, 50, [], 1, [player, player]] call ace_frag_fnc_doFragRandom;
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
|
||||
params [
|
||||
"_posASL",
|
||||
["_projVel", [0,0,0]],
|
||||
["_heightAGL", 2, [123]],
|
||||
["_fragType", [], [[]]],
|
||||
["_fragCnt", 10, [123]],
|
||||
["_shotPrnt", [objNull, objNull], [[]], [2]]
|
||||
];
|
||||
TRACE_5("fnc_doFragRandom", _posASL, _projVel, _heightAGL, _fragType, _fragCnt);
|
||||
|
||||
// See CfgAmmo for different frag types
|
||||
private _hMode = switch (true) do {
|
||||
case (_heightAGL > 10): {"_top"};
|
||||
case (_heightAGL > 5): {"_hi"};
|
||||
case (_heightAGL > 1.5): {"_mid"};
|
||||
default {"_mid"};
|
||||
};
|
||||
|
||||
// Select the cfgAmmo type
|
||||
private _type = if (count _fragType > 0 &&
|
||||
{"ace_frag_tiny" isEqualTo (_fragType#0)}) then {
|
||||
QGVAR(def_tiny_)
|
||||
} else {
|
||||
QGVAR(def_small_)
|
||||
};
|
||||
|
||||
_fragCnt = switch (true) do {
|
||||
case (_fragCnt <= 5): {"5"};
|
||||
case (_fragCnt <= 10): {"10"};
|
||||
default {"15"};
|
||||
};
|
||||
|
||||
// Spawn the fragment spawner
|
||||
private _fragSpawner = createVehicle [_type + _fragCnt + _hMode, ASLToATL _posASL, [], 0, "CAN_COLLIDE"];
|
||||
_fragSpawner setVelocity _projVel;
|
||||
_fragSpawner setShotParents _shotParents;
|
||||
|
||||
#ifdef DEBUG_MODE_FULL
|
||||
systemChat ("fragging, id: " + getObjectID _proj);
|
||||
_fragSpawner addEventHandler [
|
||||
"SubmunitionCreated",
|
||||
{
|
||||
params ["","_proj","_posASL"];
|
||||
[_posASL] call FUNC(dev_sphereDraw);
|
||||
[_proj, "green", true] call FUNC(dev_trackObj);
|
||||
}
|
||||
];
|
||||
#endif
|
175
addons/frag/functions/fnc_doFragTargeted.sqf
Normal file
175
addons/frag/functions/fnc_doFragTargeted.sqf
Normal file
@ -0,0 +1,175 @@
|
||||
#include "script_component.hpp"
|
||||
/*
|
||||
* Author: Lambda.Tiger
|
||||
* This function creates fragments targeted at specific entities, up to
|
||||
* a configured maximum
|
||||
*
|
||||
* Arguments:
|
||||
* 0: Position of fragmenting projectile ASL <ARRAY>
|
||||
* 1: Velocity of the fragmenting projectile <ARRAY>
|
||||
* 2: Maximum range of fragments to calculate <SCALAR>
|
||||
* 3: Maximum number of fragments to produce <SCALAR>
|
||||
* 4: Types of fragments <ARRAY>
|
||||
* 5: A modified parameter used to calulate whether a framgent hits <SCALAR>
|
||||
* 6: Shot parent <ARRAY>
|
||||
*
|
||||
* Return Value:
|
||||
* None
|
||||
*
|
||||
* Example:
|
||||
* [getPosASL _proj, velocity _proj, 50, 50, [], 1, [player, player]] call ace_frag_fnc_doFragTargeted;
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
|
||||
params [
|
||||
"_posASL",
|
||||
["_fragVel", 800, [123]],
|
||||
["_fragRange", 50, [123]],
|
||||
["_maxFrags", 20, [123]],
|
||||
["_fragTypes", [], [[]]],
|
||||
["_modFragCount", 1, [123]],
|
||||
["_shotPrnt", [objNull, objNull], [[]], [2]]
|
||||
];
|
||||
TRACE_5("fnc_doFragTargeted", _posASL, _fragRange, _maxFrags, _fragTypes, _modFragCount);
|
||||
|
||||
if (_fragTypes isEqualTo []) then {
|
||||
_fragTypes = [
|
||||
QGVAR(tiny), QGVAR(tiny), QGVAR(tiny),
|
||||
QGVAR(tiny_HD), QGVAR(tiny_HD), QGVAR(tiny_HD),
|
||||
QGVAR(small), QGVAR(small), QGVAR(small), QGVAR(small),
|
||||
QGVAR(small_HD), QGVAR(small_HD), QGVAR(small_HD), QGVAR(small_HD),
|
||||
QGVAR(medium_HD), QGVAR(medium_HD), QGVAR(medium_HD), QGVAR(medium_HD), QGVAR(medium_HD)
|
||||
];
|
||||
};
|
||||
|
||||
private _objects = (ASLToATL _posASL) nearEntities [["Car", "Motorcycle", "Tank", "StaticWeapon", "CAManBase", "Air", "Ship"], _fragRange];
|
||||
if (_objects isEqualTo []) exitWith {
|
||||
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);
|
||||
if (count _crew > 1) then {
|
||||
private _arr = [_x];
|
||||
{
|
||||
_arr pushBackUnique _x;
|
||||
} forEach _crew;
|
||||
|
||||
_objects set [_forEachIndex, _arr];
|
||||
};
|
||||
} forEach _objects;
|
||||
_objects = flatten _objects; // flatten out sub arrays
|
||||
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; // limit of # of fragments to _maxFrags
|
||||
{
|
||||
if (!alive _x) then {continue};
|
||||
private _target = _x;
|
||||
|
||||
#ifdef DEBUG_MODE_DRAWFRAG
|
||||
[_target, false] call FUNC(dev_trackHitBox);
|
||||
#endif
|
||||
|
||||
// Calculate volume and height of target
|
||||
private _vol = 1.5;
|
||||
private _height = 0;
|
||||
private _crossSectionArea = 1;
|
||||
private _isPerson = _target isKindOf "CAManBase";
|
||||
if (_isPerson) then {
|
||||
private _stance = stance _target;
|
||||
switch (true) do {
|
||||
case (_stance isEqualTo "STAND"): {_height = 1.9; _crossSectionArea = 1.5;};
|
||||
case (_stance isEqualTo "CROUCH"): {_height = 1.2; _crossSectionArea = 1;};
|
||||
default {_height = 0.5; _crossSectionArea = 0.75;};
|
||||
};
|
||||
} else {
|
||||
private _boxParams = boundingBoxReal [_target, "FireGeometry"];
|
||||
_boxParams params ["_pointA", "_pointB"];
|
||||
private _dims = _pointB vectorDiff _pointA;
|
||||
_vol = (_dims#0) * (_dims#1) * (_dims#2);
|
||||
_crossSectionArea = (_dims#1)*(_dims#2);
|
||||
_height = _dims#2;
|
||||
};
|
||||
|
||||
if (_vol <= 0.5) then {continue}; // too small => exit
|
||||
|
||||
|
||||
private _distance = _target distance _posASL;
|
||||
|
||||
// calculate chance to be hit by a fragment
|
||||
private _fragChance = _crossSectionArea*_modFragCount/(_distance^2);
|
||||
private _count = 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;
|
||||
private _targetPos = (velocity _target vectorMultiply _tof) vectorAdd [0, 0, 9.81 / 2 * _tof ^ 2];
|
||||
|
||||
// handle limiting fragments per dewgree arc
|
||||
private _dir = floor (_posASL getDir _target);
|
||||
private _fragPerArc = _fragArcs getOrDefault [_dir, 0];
|
||||
if (_fragPerArc > 10) then {
|
||||
continue;
|
||||
} else {
|
||||
_fragArcs set [_dir, _fragPerArc + _count];
|
||||
};
|
||||
|
||||
// actual target pos for fragment to hit
|
||||
if _isPerson then {
|
||||
private _hitPoint = selectRandom _FRAG_HITPOINTS;
|
||||
private _hitPointPos = _target selectionPosition [_hitPoint, "HitPoints", "AveragePoint"];
|
||||
_targetPos = _target modelToWorldWorld _hitPointPos;
|
||||
} else {
|
||||
_targetPos = getPosASL _target vectorAdd [
|
||||
-0.5 + random 1,
|
||||
-0.5 + random 1,
|
||||
(0.1 + random 0.4) * _height
|
||||
];
|
||||
};
|
||||
|
||||
// select a fragment / submunition frag spawner
|
||||
private _fragSpawner = selectRandom _fragTypes;
|
||||
if (_count > 1) then {
|
||||
_fragSpawner = _fragSpawner + "_spawner_" + str _count + (switch (true) do {
|
||||
case (_distance < 10): {"_short"};
|
||||
case (_distance < 20): {"_mid"};
|
||||
default {"_far"};
|
||||
});
|
||||
};
|
||||
|
||||
TRACE_4("fragments",_fragSpawner,_fragChance,_distance,_locFragVel);
|
||||
|
||||
// Create fragment
|
||||
private _vecDir = _posASL vectorFromTo _targetPos;
|
||||
private _fragObj = createVehicle [_fragSpawner, ASLtoATL _posASL, [], 0, "CAN_COLLIDE"];
|
||||
_fragObj setVectorDir _vecDir;
|
||||
_fragObj setVelocity (_vecDir vectorMultiply _locFragVel);
|
||||
_fragObj setShotParents _shotPrnt;
|
||||
#ifdef DEBUG_MODE_DRAWFRAG
|
||||
[_fragObj, "purple", true] call FUNC(dev_trackObj);
|
||||
[_targetPos, "orange"] call FUNC(dev_sphereDraw);
|
||||
#endif
|
||||
|
||||
_fragCount = _fragCount + _count;
|
||||
if (_fragCount >= _maxFrags) then {
|
||||
TRACE_2("maxFrags", _fragCount, _maxFrags);
|
||||
break
|
||||
};
|
||||
} forEach _objects;
|
||||
#ifdef DEBUG_MODE_FULL
|
||||
systemChat ("fragCount cnt: " + str _fragCount);
|
||||
TRACE_1("fragCount",_fragCount);
|
||||
#endif
|
||||
|
||||
_fragCount
|
@ -1,4 +1,4 @@
|
||||
#include "..\script_component.hpp"
|
||||
#include "script_component.hpp"
|
||||
/*
|
||||
* Author: ACE-Team
|
||||
* Dev things
|
||||
|
@ -1,4 +1,4 @@
|
||||
#include "..\script_component.hpp"
|
||||
#include "script_component.hpp"
|
||||
/*
|
||||
* Author: ACE-Team
|
||||
* Dev things
|
||||
@ -14,126 +14,97 @@
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
params ["_projectile", "_hitObj", "", "_lPosASL", "_lVel", "", "", "" ,"_surfaceType"];
|
||||
|
||||
#define WEIGHTED_SIZE [QGVAR(spall_small), 4, QGVAR(spall_medium), 3, QGVAR(spall_large), 2, QGVAR(spall_huge), 1]
|
||||
if (!isNil "_hitObj" && {_hitObj isKindOf "man"}) exitWith {};
|
||||
|
||||
params ["_hitData", "_hitPartDataIndex"];
|
||||
private _initialData = GVAR(spallHPData) select (_hitData select 0);
|
||||
_initialData params ["_hpId", "_object", "_roundType", "_round", "_curPos", "_velocity"];
|
||||
if ((isNil "_lPosASL") || {!(_lPosASL isEqualTypeArray [0,0,0])}) exitWith {WARNING_1("Problem with hitPart data - bad pos [%1]",_lPosASL);};
|
||||
|
||||
private _hpData = (_hitData select 1) select _hitPartDataIndex;
|
||||
private _objectHit = _hpData param [0, objNull];
|
||||
TRACE_1("",_objectHit);
|
||||
if ((isNil "_objectHit") || {isNull _objectHit}) exitWith {WARNING_1("Problem with hitPart data - bad object [%1]",_objectHit);};
|
||||
_objectHit removeEventHandler ["hitPart", _hpId];
|
||||
|
||||
private _caliber = getNumber (configFile >> "CfgAmmo" >> _roundType >> "caliber");
|
||||
private _explosive = getNumber (configFile >> "CfgAmmo" >> _roundType >> "explosive");
|
||||
private _idh = getNumber (configFile >> "CfgAmmo" >> _roundType >> "indirectHitRange");
|
||||
|
||||
if !(_caliber >= 2.5 || {(_explosive > 0 && {_idh >= 1})}) exitWith {};
|
||||
// ACE_player sideChat format ["BBBB"];
|
||||
private _exit = false;
|
||||
private _vm = 1;
|
||||
|
||||
private _oldVelocity = vectorMagnitude _velocity;
|
||||
private _curVelocity = vectorMagnitude (velocity _round);
|
||||
|
||||
if (alive _round) then {
|
||||
private _diff = _velocity vectorDiff (velocity _round);
|
||||
private _polar = _diff call CBA_fnc_vect2polar;
|
||||
// ACE_player sideChat format ["polar: %1", _polar];
|
||||
if (abs (_polar select 1) > 45 || {abs (_polar select 2) > 45}) then {
|
||||
if (_caliber < 2.5) then {
|
||||
// ACE_player sideChat format ["exit!"];
|
||||
_exit = true;
|
||||
} else {
|
||||
SUB(_vm,_curVelocity / _oldVelocity);
|
||||
};
|
||||
private _posASL = _lPosASL;
|
||||
private _vel = [0, 0, 0];
|
||||
private _lVelUnit = vectorNormalized _lVel;
|
||||
private _velMod = 1;
|
||||
if (alive _projectile) then {
|
||||
_vel = velocity _projectile;
|
||||
_posASL = getPosASL _projectile;
|
||||
// Dot product math
|
||||
private _diffAngle = acos (_lVelUnit vectorDotProduct vectorNormalized _vel);
|
||||
|
||||
if (abs _diffAngle > 45) then {
|
||||
SUB(_velMod, (vectorMagnitude _vel) / (vectorMagnitude _lVel));
|
||||
};
|
||||
_projectile setVariable [QGVAR(lastSpallTime), diag_tickTime ];
|
||||
};
|
||||
if (_exit) exitWith {};
|
||||
|
||||
private _unitDir = vectorNormalized _velocity;
|
||||
private _pos = _hpData select 3;
|
||||
private _spallPos = [];
|
||||
if ((isNil "_pos") || {!(_pos isEqualTypeArray [0,0,0])}) exitWith {WARNING_1("Problem with hitPart data - bad pos [%1]",_pos);};
|
||||
for "_i" from 0 to 100 do {
|
||||
private _pos1 = _pos vectorAdd (_unitDir vectorMultiply (0.01 * _i));
|
||||
private _pos2 = _pos vectorAdd (_unitDir vectorMultiply (0.01 * (_i + 1)));
|
||||
// _data = [nil, nil, nil, 1, [[ASLtoATL _pos1, 1], [ASLtoATL _pos2, 1]]];
|
||||
// NOU_TRACES pushBack _data;
|
||||
|
||||
if (!lineIntersects [_pos1, _pos2]) exitWith {
|
||||
// ACE_player sideChat format ["FOUND!"];
|
||||
_spallPos = _pos2;
|
||||
};
|
||||
//** start calculating where the spalling should come **//
|
||||
private _unitStep = _lVelUnit vectorMultiply 0.05;
|
||||
private _spallPos = +_lPosASL;
|
||||
// exit if we hit the ground
|
||||
if (terrainIntersectASL [_lPosASL vectorAdd _unitStep, _lPosASL]) exitWith {};
|
||||
// step through
|
||||
for "_i" from 1 to 20 do
|
||||
{
|
||||
private _nPos = _spallPos vectorAdd _unitStep;
|
||||
if (!lineIntersects [_spallPos, _nPos]) then {break};
|
||||
_spallPos = +_nPos;
|
||||
};
|
||||
if (_spallPos isEqualTo []) exitWith {};
|
||||
private _spallPolar = _velocity call CBA_fnc_vect2polar;
|
||||
#ifdef DEBUG_MODE_FULL
|
||||
[_spallPos, "orange"] call FUNC(dev_sphereDraw);
|
||||
[_lPosASL, "orange"] call FUNC(dev_sphereDraw);
|
||||
#endif
|
||||
// find last intersect with the object
|
||||
|
||||
private _ammo = typeOf _projectile;
|
||||
private _explosive = getNumber (configFile >> "CfgAmmo" >> _ammo >> "explosive");
|
||||
|
||||
#ifdef DEBUG_MODE_FULL
|
||||
private _dv = vectorMagnitude _lVel - vectorMagnitude _vel;
|
||||
private _caliber = getNumber (configFile >> "cfgAmmo" >> _ammo >> "caliber");
|
||||
systemChat ("dV: " + str _dv + ", caliber: " + str _caliber + ", product: " + str (_caliber*_dv));
|
||||
#endif
|
||||
|
||||
if (_explosive > 0) then {
|
||||
// ACE_player sideChat format ["EXPLOSIVE!"];
|
||||
private _warn = false;
|
||||
private _c = getNumber (configFile >> "CfgAmmo" >> _roundType >> QGVAR(CHARGE));
|
||||
if (_c == 0) then {_c = 1; _warn = true;};
|
||||
private _m = getNumber (configFile >> "CfgAmmo" >> _roundType >> QGVAR(METAL));
|
||||
if (_m == 0) then {_m = 2; _warn = true;};
|
||||
private _k = getNumber (configFile >> "CfgAmmo" >> _roundType >> QGVAR(GURNEY_K));
|
||||
if (_k == 0) then {_k = 1 / 2; _warn = true;};
|
||||
private _gC = getNumber (configFile >> "CfgAmmo" >> _roundType >> QGVAR(GURNEY_C));
|
||||
if (_gC == 0) then {_gC = 2440; _warn = true;};
|
||||
//private _warn = false;
|
||||
private _c = getNumber (configFile >> "CfgAmmo" >> _ammo >> "ace_frag_CHARGE");
|
||||
if (_c == 0) then {_c = 1}; //; _warn = true;};
|
||||
private _m = getNumber (configFile >> "CfgAmmo" >> _ammo >> "ace_frag_METAL");
|
||||
if (_m == 0) then {_m = 2;};// _warn = true;};
|
||||
private _k = getNumber (configFile >> "CfgAmmo" >> _ammo >> "ace_frag_GURNEY_K");
|
||||
if (_k == 0) then {_k = 1 / 2;};// _warn = true;};
|
||||
private _gC = getNumber (configFile >> "CfgAmmo" >> _ammo >> "ace_frag_GURNEY_C");
|
||||
if (_gC == 0) then {_gC = 2440};// _warn = true;};
|
||||
|
||||
// if (_warn) then {
|
||||
// WARNING_1("Ammo class %1 lacks proper explosive properties definitions for frag!",_roundType); //TODO: turn this off when we get closer to release
|
||||
// };
|
||||
|
||||
private _fragPower = (((_m / _c) + _k) ^ - (1 / 2)) * _gC;
|
||||
_spallPolar set [0, _fragPower * 0.66];
|
||||
_velMod = (((_m / _c) + _k) ^ - (1 / 2)) * _gC * 0.66 * _velMod;
|
||||
};
|
||||
|
||||
// diag_log text format ["SPALL POWER: %1", _spallPolar select 0];
|
||||
private _spread = 15 + (random 25);
|
||||
private _spallCount = 5 + (random 10);
|
||||
TRACE_1("",_spallCount);
|
||||
for "_i" from 1 to _spallCount do {
|
||||
private _elev = ((_spallPolar select 2) - _spread) + (random (_spread * 2));
|
||||
private _dir = ((_spallPolar select 1) - _spread) + (random (_spread * 2));
|
||||
if (abs _elev > 90) then {
|
||||
ADD(_dir,180);
|
||||
};
|
||||
_dir = _dir % 360;
|
||||
private _vel = (_spallPolar select 0) * 0.33 * _vm;
|
||||
_vel = (_vel - (_vel * 0.25)) + (random (_vel * 0.5));
|
||||
// range of spread 15-40
|
||||
// N rounds 5-15
|
||||
// speed from 0.75-1.5
|
||||
// range of spread 5-10
|
||||
// N rounds 3-8
|
||||
// speed from 0.75-1.5
|
||||
private _velScalar = 0.33 * _velMod;
|
||||
|
||||
private _spallFragVect = [_vel, _dir, _elev] call CBA_fnc_polar2vect;
|
||||
private _fragment = (selectRandomWeighted WEIGHTED_SIZE) createVehicleLocal [0,0,10000];
|
||||
_fragment setPosASL _spallPos;
|
||||
_fragment setVelocity _spallFragVect;
|
||||
private _fragSpawner = QGVAR(base) createVehicleLocal [0,0,12345];
|
||||
_fragSpawner setPosASL _spallPos;
|
||||
_fragSpawner setVectorDirandUp [vectorDir _projectile, vectorUp _projectile];
|
||||
_fragSpawner setVelocity (_lVelUnit vectorMultiply _velScalar);
|
||||
|
||||
#ifdef DRAW_FRAG_INFO
|
||||
[ACE_player, _fragment, [1, 0.5, 0, 1]] call FUNC(dev_addTrack);
|
||||
#endif
|
||||
};
|
||||
|
||||
_spread = 5 + (random 5);
|
||||
_spallCount = 3 + (random 5);
|
||||
for "_i" from 1 to _spallCount do {
|
||||
private _elev = ((_spallPolar select 2) - _spread) + (random (_spread * 2));
|
||||
private _dir = ((_spallPolar select 1) - _spread) + (random (_spread * 2));
|
||||
if (abs _elev > 90) then {
|
||||
ADD(_dir,180);
|
||||
};
|
||||
_dir = _dir % 360;
|
||||
private _vel = (_spallPolar select 0) * 0.55 * _vm;
|
||||
_vel = (_vel - (_vel * 0.25)) + (random (_vel * 0.5));
|
||||
|
||||
private _spallFragVect = [_vel, _dir, _elev] call CBA_fnc_polar2vect;
|
||||
private _fragment = (selectRandomWeighted WEIGHTED_SIZE) createVehicleLocal [0, 0, 10000];
|
||||
_fragment setPosASL _spallPos;
|
||||
_fragment setVelocity _spallFragVect;
|
||||
|
||||
#ifdef DRAW_FRAG_INFO
|
||||
[ACE_player, _fragment, [1, 0, 0, 1]] call FUNC(dev_addTrack);
|
||||
#endif
|
||||
};
|
||||
#ifdef DEBUG_MODE_FULL
|
||||
_fragSpawner addEventHandler [
|
||||
"SubmunitionCreated",
|
||||
{
|
||||
params ["", "_subProj"];
|
||||
[_subProj] call FUNC(dev_addRound);
|
||||
}
|
||||
];
|
||||
#endif
|
109
addons/frag/functions/fnc_doSpallMomentum.sqf
Normal file
109
addons/frag/functions/fnc_doSpallMomentum.sqf
Normal file
@ -0,0 +1,109 @@
|
||||
#include "script_component.hpp"
|
||||
/*
|
||||
* Author: Lambda.Tiger
|
||||
* This function creates spalling if the hit slowed the speed down enough.
|
||||
*
|
||||
* Arguments:
|
||||
* Arguments are the same as BI's "HitPart" EH:
|
||||
* https://community.bistudio.com/wiki/Arma_3:_Event_Handlers#HitPart
|
||||
*
|
||||
* Return Value:
|
||||
* None
|
||||
*
|
||||
* Example:
|
||||
* [BIS_HITPART_EH_ARGS] call ace_frag_fnc_doSpallMomentum;
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
params ["_projectile", "_hitObj", "", "_lPosASL", "_lVel", "", "", "" ,"_surfaceType"];
|
||||
|
||||
if (CBA_missionTime - GVAR(lastHitTick) < ACE_FRAG_SPALL_HOLDOFF) exitWith {};
|
||||
|
||||
if (_hitObj isNotEqualTo objNull && {_hitObj isKindOf "man"}) exitWith {};
|
||||
if ((isNil "_lPosASL") || {!(_lPosASL isEqualTypeArray [0,0,0])}) exitWith {
|
||||
TRACE_1("Problem with hitPart data - bad pos",_lPosASL);
|
||||
};
|
||||
|
||||
private _vel = if (alive _projectile) then {
|
||||
_velocity _projectile;
|
||||
} else {
|
||||
[0, 0, 0]
|
||||
};
|
||||
private _lVelUnit = vectorNormalized _lVel;
|
||||
|
||||
|
||||
// Find spall speed / fragment
|
||||
private _ammo = typeOf _projectile;
|
||||
private _dV = vectorMagnitude _lVel - vectorMagnitude _vel;
|
||||
private _caliber = getNumber (configFile >> "cfgAmmo" >> _ammo >> "caliber"); // !*! optimize this later?
|
||||
private _deltaMomentum = 0.4 * _caliber * sqrt( _dV * 0.032 );
|
||||
|
||||
TRACE_3("found speed",_dV,_caliber,_deltaMomentum);
|
||||
|
||||
if (_deltaMomentum < 1) exitWith {
|
||||
TRACE_1("lowImpulse",_ammo);
|
||||
};
|
||||
|
||||
//** start calculating where the spalling should come !*! could be better **//
|
||||
private _unitStep = _lVelUnit vectorMultiply 0.05;
|
||||
private _spallPos = +_lPosASL;
|
||||
// exit if we hit the ground
|
||||
if (terrainIntersectASL [_lPosASL vectorAdd _unitStep, _lPosASL]) exitWith {
|
||||
TRACE_3("terrainIntersect",_lPosASL,_unitStep,_lPosASL);
|
||||
};
|
||||
// step through
|
||||
for "_i" from 1 to 20 do
|
||||
{
|
||||
private _nPos = _spallPos vectorAdd _unitStep;
|
||||
if (!lineIntersects [_spallPos, _nPos]) then { _spallPos = _nPos; break};
|
||||
_spallPos = +_nPos;
|
||||
};
|
||||
|
||||
#ifdef DEBUG_MODE_FULL
|
||||
[_spallPos, "green"] call FUNC(dev_sphereDraw);
|
||||
[_lPosASL vectorAdd _lVelUnit, "orange"] call FUNC(dev_sphereDraw);
|
||||
[_lPosASL, "orange"] call FUNC(dev_sphereDraw);
|
||||
private _str = GVAR(hitLog) getOrDefault [str _surfaceType, "["];
|
||||
_str =_str + str [_dV, _caliber, abs vectorMagnitude (_lPosASL vectorDiff _spallPos)] + ";";
|
||||
GVAR(hitLog) set [str _surfaceType, _str];
|
||||
if (_deltaMomentum < 2) exitWith {};
|
||||
#endif
|
||||
|
||||
//***** Passed all other exit withs, performance o'clock */
|
||||
GVAR(lastHitTick) = CBA_missionTime;
|
||||
|
||||
//***** Select spalled fragments **//
|
||||
// diag_log text format ["SPALL POWER: %1", _spallPolar select 0];
|
||||
// range of spread 15-40
|
||||
// N rounds 5-15
|
||||
// speed from 0.75-1.5
|
||||
// range of spread 5-10
|
||||
// N rounds 3-8
|
||||
// speed from 0.75-1.5
|
||||
|
||||
private _fragSpawnType = switch (true) do
|
||||
{
|
||||
case (_deltaMomentum < 3): { QGVAR(spall_tiny) };
|
||||
case (_deltaMomentum < 5): { QGVAR(spall_small) };
|
||||
case (_deltaMomentum < 8): { QGVAR(spall_medium) };
|
||||
case (_deltaMomentum < 11): { QGVAR(spall_large) };
|
||||
default { QGVAR(spall_huge) };
|
||||
};
|
||||
|
||||
|
||||
//***** Spawn spalled fragments
|
||||
private _fragSpawner = createVehicleLocal [_fragSpawnType, ASLToATL _spallPos, [], 0, "CAN_COLLIDE"];
|
||||
_fragSpawner setVectorDirandUp [vectorDir _projectile, vectorUp _projectile];
|
||||
_fragSpawner setVelocity _lVelUnit;
|
||||
|
||||
|
||||
#ifdef DEBUG_MODE_FULL
|
||||
systemChat ("bSpd: " + str speed _fragSpawner + ", frag: " + _fragSpawnType + ", dm: " + str _deltaMomentum);
|
||||
_fragSpawner addEventHandler [
|
||||
"SubmunitionCreated",
|
||||
{
|
||||
params ["", "_subProj"];
|
||||
[_subProj] call FUNC(dev_addRound);
|
||||
}
|
||||
];
|
||||
#endif
|
@ -1,6 +1,6 @@
|
||||
#include "..\script_component.hpp"
|
||||
#include "script_component.hpp"
|
||||
/*
|
||||
* Author: nou, jaynus, PabstMirror
|
||||
* Author: nou, jaynus, PabstMirror, Lambda.Tiger
|
||||
* Called from the unified fired EH for all.
|
||||
* If spall is not enabled (default), then cache and only track those that will actually trigger fragmentation.
|
||||
*
|
||||
@ -17,42 +17,44 @@
|
||||
*/
|
||||
|
||||
//IGNORE_PRIVATE_WARNING ["_unit", "_weapon", "_muzzle", "_mode", "_ammo", "_magazine", "_projectile", "_vehicle", "_gunner", "_turret"];
|
||||
TRACE_10("firedEH:",_unit, _weapon, _muzzle, _mode, _ammo, _magazine, _projectile, _vehicle, _gunner, _turret);
|
||||
|
||||
private _shouldAdd = GVAR(cacheRoundsTypesToTrack) getVariable _ammo;
|
||||
if (isNil "_shouldAdd") then {
|
||||
TRACE_1("no cache for round",_ammo);
|
||||
|
||||
//Read configs and test if it would actually cause a frag, using same logic as FUNC(pfhRound)
|
||||
private _skip = getNumber (configFile >> "CfgAmmo" >> _ammo >> QGVAR(skip));
|
||||
private _explosive = getNumber (configFile >> "CfgAmmo" >> _ammo >> "explosive");
|
||||
private _indirectRange = getNumber (configFile >> "CfgAmmo" >> _ammo >> "indirectHitRange");
|
||||
private _force = getNumber (configFile >> "CfgAmmo" >> _ammo >> QGVAR(force));
|
||||
private _fragPower = getNumber (configFile >> "CfgAmmo" >> _ammo >> "indirecthit") * (sqrt (getNumber (configFile >> "CfgAmmo" >> _ammo >> "indirectHitRange")));
|
||||
|
||||
_shouldAdd = (_skip == 0) && {(_force == 1) || {_explosive > 0.5 && {_indirectRange >= 4.5} && {_fragPower >= 35}}};
|
||||
|
||||
if (GVAR(spallEnabled) && {!_shouldAdd}) then {
|
||||
private _caliber = getNumber (configFile >> "CfgAmmo" >> _ammo >> "caliber");
|
||||
if !(_caliber >= 2.5 || {(_explosive > 0 && {_indirectRange >= 1})}) exitWith {}; // from check in doSpall: line 34
|
||||
TRACE_1("Won't frag, but will spall",_caliber);
|
||||
_shouldAdd = true;
|
||||
};
|
||||
|
||||
TRACE_6("Setting Cache",_skip,_explosive,_indirectRange,_force,_fragPower,_shouldAdd);
|
||||
GVAR(cacheRoundsTypesToTrack) setVariable [_ammo, _shouldAdd];
|
||||
if (isNil "_ammo" ||
|
||||
{_ammo isEqualTo "" ||
|
||||
{isNil "_projectile" ||
|
||||
{isNull _projectile}}}) exitWith {
|
||||
WARNING("bad ammo or projectile");
|
||||
};
|
||||
|
||||
if (_shouldAdd) then {
|
||||
// firedMan will have nil "_gunner", so just check _unit; for firedVehicle we want to check _gunner
|
||||
private _localShooter = if (isNil "_gunner") then {local _unit} else {local _gunner};
|
||||
TRACE_4("",_localShooter,_unit,_ammo,_projectile);
|
||||
if (!_localShooter) exitWith {};
|
||||
if (_weapon == "Put") exitWith {}; // Ignore explosives placed without ace_explosives
|
||||
/******* _shouldFrag format *****/
|
||||
// 0: doFragmnent - will the piece fragment
|
||||
// 1: hasSubmuntion - will the round create submunitions
|
||||
private _shouldFrag = _ammo call FUNC(shouldFrag);
|
||||
_shouldFrag params ["_doFrag", "_doSubmunit"];
|
||||
|
||||
// Skip if less than 0.5 second from last shot
|
||||
if ((CBA_missionTime - (_unit getVariable [QGVAR(lastTrack), -1])) < 0.5) exitWith {};
|
||||
_unit setVariable [QGVAR(lastTrack), CBA_missionTime];
|
||||
|
||||
[_unit, _ammo, _projectile] call FUNC(addPfhRound);
|
||||
if (_doFrag) then {
|
||||
// wait for frag damage to kill units before spawning fragments
|
||||
_projectile addEventHandler ["Explode", {
|
||||
if (isServer) then {
|
||||
[FUNC(doFrag), [_this]] call CBA_fnc_execNextFrame;
|
||||
} else {
|
||||
[QGVAR(frag_eh), [_this]] call CBA_fnc_serverEvent;
|
||||
};
|
||||
}
|
||||
];
|
||||
};
|
||||
|
||||
if (_doSubmunit && {GVAR(enSubMunit)> 0}) then {
|
||||
_projectile addEventHandler ["SubmunitionCreated", {_this call FUNC(submunition)}];
|
||||
};
|
||||
|
||||
private _shouldSpall = _ammo call FUNC(shouldSpall);
|
||||
|
||||
if (GVAR(spallEnabled) && {_shouldSpall}) then
|
||||
{_projectile addEventHandler [
|
||||
"HitPart",
|
||||
{
|
||||
[LINKFUNC(doSpallMomentum), _this] call CBA_fnc_execNextFrame;
|
||||
[QGVAR(spall_eh), [_this]] call CBA_fnc_serverEvent;
|
||||
}
|
||||
];
|
||||
};
|
86
addons/frag/functions/fnc_fragInfo.sqf
Normal file
86
addons/frag/functions/fnc_fragInfo.sqf
Normal file
@ -0,0 +1,86 @@
|
||||
#include "script_component.hpp"
|
||||
/*
|
||||
* Author: Lambda.Tiger
|
||||
* This function returns fragmentation parameters for a specific
|
||||
* ammo type.
|
||||
*
|
||||
* Arguments:
|
||||
* 0: _ammo <STRING> - cfgAmmo type of ammo to check
|
||||
*
|
||||
* Return Value:
|
||||
* _ammoInfo <ARRAY>
|
||||
* 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
|
||||
*
|
||||
* Example:
|
||||
* ["B_556x45_Ball"] call ace_frag_fnc_fragInfo;
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
|
||||
params ["_ammo"];
|
||||
|
||||
private _ammoInfo = GVAR(fragInfoCache) get _ammo;
|
||||
|
||||
if !(isNil "_ammoInfo") exitWith {_ammoInfo};
|
||||
|
||||
private _fragTypes = [];
|
||||
private _warn = false;
|
||||
if (isArray (configFile >> "cfgAmmo" >> _ammo >> QGVAR(CLASSES))) then {
|
||||
_fragTypes = getArray (configFile >> "cfgAmmo" >> _ammo >> QGVAR(CLASSES));
|
||||
} else {
|
||||
_warn = true;
|
||||
};
|
||||
|
||||
/************ Gurney equation notes *****************/
|
||||
// see https://en.wikipedia.org/wiki/Gurney_equations
|
||||
//
|
||||
// GURNEY_K is the constant added to _m/_c
|
||||
// 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
|
||||
|
||||
// _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
|
||||
// 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)
|
||||
|
||||
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 _fragCount = getNumber (configFile >> "cfgAmmo" >> _ammo >> QGVAR(fragCount));
|
||||
if (_fragCount == 0) then {_fragCount = 200; _warn = true;};
|
||||
|
||||
if (_warn) then {
|
||||
INFO_1("Ammo class %1 lacks proper explosive properties definitions for frag!",_ammo);
|
||||
};
|
||||
|
||||
/********************** _ammoInfo format *************************/
|
||||
// 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
|
||||
_ammoInfo = [
|
||||
sqrt (_fragCount / (4 * pi * 0.005)),
|
||||
0.8 * _gC * sqrt (_c / (_m + _c * _k)),
|
||||
_fragTypes,
|
||||
_fragCount / 4 / pi
|
||||
];
|
||||
|
||||
GVAR(fragInfoCache) set [_ammo, _ammoInfo];
|
||||
_ammoInfo
|
@ -1,194 +0,0 @@
|
||||
#include "..\script_component.hpp"
|
||||
/*
|
||||
* Author: Jaynus, NouberNou
|
||||
* Server func to create the fragmentation for a round.
|
||||
*
|
||||
* Arguments:
|
||||
* 0: Last Position (ASL) <ARRAY>
|
||||
* 1: Velocity <ARRAY>
|
||||
* 2: Ammo Classname <STRING>
|
||||
*
|
||||
* Return Value:
|
||||
* None
|
||||
*
|
||||
* Example:
|
||||
* [[], [], "handGrenade"] call ace_frag_fnc_frago
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
|
||||
#define FRAG_VEC_VAR 0.004
|
||||
#define MAX_FRAG_COUNT 50
|
||||
|
||||
BEGIN_COUNTER(frago);
|
||||
|
||||
params ["_lastPos", "_lastVel", "_shellType"];
|
||||
TRACE_3("frago",_lastPos,_lastVel,_shellType);
|
||||
|
||||
// Limit max frag count if there was a recent frag
|
||||
private _maxFrags = round (MAX_FRAG_COUNT * linearConversion [0.1, 1.5, (CBA_missionTime - GVAR(lastFragTime)), 0.1, 1, true]);
|
||||
TRACE_2("",_maxFrags,CBA_missionTime - GVAR(lastFragTime));
|
||||
GVAR(lastFragTime) = CBA_missionTime;
|
||||
|
||||
private _fragTypes = [
|
||||
QGVAR(tiny), QGVAR(tiny), QGVAR(tiny),
|
||||
QGVAR(tiny_HD), QGVAR(tiny_HD), QGVAR(tiny_HD),
|
||||
QGVAR(small), QGVAR(small), QGVAR(small), QGVAR(small),
|
||||
QGVAR(small_HD), QGVAR(small_HD), QGVAR(small_HD), QGVAR(small_HD),
|
||||
QGVAR(medium_HD), QGVAR(medium_HD), QGVAR(medium_HD), QGVAR(medium_HD), QGVAR(medium_HD)
|
||||
];
|
||||
|
||||
private _warn = false;
|
||||
if (isArray (configFile >> "CfgAmmo" >> _shellType >> QGVAR(CLASSES))) then {
|
||||
_fragTypes = getArray (configFile >> "CfgAmmo" >> _shellType >> QGVAR(CLASSES));
|
||||
} else {
|
||||
_warn = true;
|
||||
};
|
||||
|
||||
private _indirectHitRange = getNumber(configFile >> "CfgAmmo" >> _shellType >> "indirecthitrange");
|
||||
private _fragRange = 20 * _indirectHitRange * 4;
|
||||
// _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
|
||||
|
||||
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;};
|
||||
|
||||
if (_warn) then {
|
||||
INFO_1("Ammo class %1 lacks proper explosive properties definitions for frag!",_shellType);
|
||||
};
|
||||
|
||||
// Gunery equation is for a non-fragmenting metal, imperical value of 80% represents fragmentation
|
||||
private _fragPower = 0.8 * (((_m / _c) + _k) ^ - (1 / 2)) * _gC;
|
||||
|
||||
private _atlPos = ASLtoATL _lastPos;
|
||||
|
||||
private _fragPowerRandom = _fragPower * 0.5;
|
||||
if ((_atlPos select 2) < 0.5) then {
|
||||
_lastPos vectorAdd [0, 0, 0.5];
|
||||
};
|
||||
|
||||
private _objects = _atlPos nearEntities [["Car", "Motorcycle", "Tank", "StaticWeapon", "CAManBase", "Air", "Ship"], _fragRange];
|
||||
// Add unique crews in faster way
|
||||
{
|
||||
{
|
||||
_objects pushBackUnique _x;
|
||||
} forEach (crew _x);
|
||||
} forEach _objects;
|
||||
TRACE_2("",_fragRange,count _objects);
|
||||
|
||||
private _fragCount = 0;
|
||||
|
||||
private _fragArcs = [];
|
||||
_fragArcs set [360, 0];
|
||||
|
||||
private _doRandom = true;
|
||||
if (_objects isNotEqualTo []) then {
|
||||
if (GVAR(reflectionsEnabled)) then {
|
||||
[_lastPos, _shellType] call FUNC(doReflections);
|
||||
};
|
||||
{
|
||||
private _target = _x;
|
||||
if (alive _target) then {
|
||||
(boundingBox _target) params ["_boundingBoxA", "_boundingBoxB"];
|
||||
|
||||
private _cubic = ((abs (_boundingBoxA select 0)) + (_boundingBoxB select 0)) * ((abs (_boundingBoxA select 1)) + (_boundingBoxB select 1)) * ((abs (_boundingBoxA select 2)) + (_boundingBoxB select 2));
|
||||
|
||||
if (_cubic <= 1) exitWith {};
|
||||
// _doRandom = true;
|
||||
|
||||
private _targetVel = velocity _target;
|
||||
private _targetPos = getPosASL _target;
|
||||
private _distance = _targetPos vectorDistance _lastPos;
|
||||
private _add = ((_boundingBoxB select 2) / 2) + ((((_distance - (_fragpower / 8)) max 0) / _fragPower) * 10);
|
||||
|
||||
_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 < 10) 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);
|
||||
};
|
||||
};
|
||||
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 _fragObj = (selectRandom _fragTypes) createVehicleLocal [0,0,10000];
|
||||
// TRACE_4("targeted",_fp, typeOf _fragObj,_lastPos vectorDistance _targetPos,typeOf _x);
|
||||
_fragObj setPosASL _lastPos;
|
||||
_fragObj setVectorDir _vec;
|
||||
_fragObj setVelocity _vel;
|
||||
#ifdef DRAW_FRAG_INFO
|
||||
[ACE_player, _fragObj, [1,0,0,1]] call FUNC(dev_addTrack);
|
||||
#endif
|
||||
INC(_fragCount);
|
||||
INC(_currentCount);
|
||||
};
|
||||
_fragArcs set [_dir, _currentCount];
|
||||
};
|
||||
};
|
||||
if (_fragCount > _maxFrags) exitWith {};
|
||||
} forEach _objects;
|
||||
TRACE_1("targeted",_fragCount);
|
||||
if (_fragCount > _maxFrags) exitWith {};
|
||||
private _randomCount = ceil ((_maxFrags - _fragCount) * 0.35);
|
||||
TRACE_1("",_randomCount);
|
||||
private _sectorSize = 360 / (_randomCount max 1);
|
||||
|
||||
if (_doRandom) then {
|
||||
for "_i" from 1 to _randomCount do {
|
||||
// Distribute evenly
|
||||
private _sectorOffset = 360 * (_i - 1) / (_randomCount max 1);
|
||||
private _randomDir = random (_sectorSize);
|
||||
_vec = [cos (_sectorOffset + _randomDir), sin (_sectorOffset + _randomDir), sin (30 - (random 45))];
|
||||
|
||||
_fp = (_fragPower - (random (_fragPowerRandom)));
|
||||
|
||||
_vel = _vec vectorMultiply _fp;
|
||||
|
||||
_fragObj = (selectRandom _fragTypes) createVehicleLocal [0, 0, 10000];
|
||||
_fragObj setPosASL _lastPos;
|
||||
_fragObj setVectorDir _vec;
|
||||
_fragObj setVelocity _vel;
|
||||
|
||||
#ifdef DRAW_FRAG_INFO
|
||||
[ACE_player, _fragObj, [1,0.5,0,1]] call FUNC(dev_addTrack);
|
||||
#endif
|
||||
INC(_fragCount);
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
TRACE_1("total created",_fragCount);
|
||||
|
||||
END_COUNTER(frago);
|
51
addons/frag/functions/fnc_initBlackList.sqf
Normal file
51
addons/frag/functions/fnc_initBlackList.sqf
Normal file
@ -0,0 +1,51 @@
|
||||
#include "script_component.hpp"
|
||||
/*
|
||||
* Author: Lambda.Tiger
|
||||
* Adds setting defined blacklisted rounds to blacklist
|
||||
*
|
||||
* Arguments:
|
||||
* Mne
|
||||
*
|
||||
* Return Value:
|
||||
* None
|
||||
*
|
||||
* Example:
|
||||
* [] call ace_frag_fnc_addBlackList
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
|
||||
TRACE_1("Beginning blacklist init", GVAR(BlackList));
|
||||
|
||||
if (!ADDON) then {
|
||||
[FUNC(initBlackList), [], 1] call CBA_fnc_waitAndExecute;
|
||||
};
|
||||
|
||||
// could improve text parsing
|
||||
private _convArray = parseSimpleArray GVAR(BlackList);
|
||||
|
||||
if (count _convArray == 0 ) exitWith {
|
||||
TRACE_1("Empty blacklist", _convArray);
|
||||
};
|
||||
|
||||
private _errors = 0;
|
||||
private _items = count _convArray;
|
||||
for "_i" from 0 to _items - 1 do {
|
||||
private _ammo = _convArray#_i;
|
||||
if (typeName _ammo isNotEqualTo "STRING") then {
|
||||
INFO_1("Improper ammo string at index %1", _i);
|
||||
INC(_errors);
|
||||
continue;
|
||||
};
|
||||
|
||||
if (!isClass (configFile >> "cfgAmmo" >> _ammo)) then {
|
||||
INFO_1("Ammo class: %1 does not exist", str _ammo);
|
||||
INC(_errors);
|
||||
continue;
|
||||
};
|
||||
|
||||
GVAR(shouldFragCache) set [_convArray#_i, [false, false]];
|
||||
};
|
||||
|
||||
|
||||
INFO_2("Initialized blacklist. Total items found: %1, number of items failed: %2", _items, _errors);
|
@ -1,56 +0,0 @@
|
||||
#include "..\script_component.hpp"
|
||||
/*
|
||||
* Author: jaynus
|
||||
* Master single PFH abstraction for all rounds being tracked by frag/spall.
|
||||
*
|
||||
* Arguments:
|
||||
* None
|
||||
*
|
||||
* Return Value:
|
||||
* None
|
||||
*
|
||||
* Example:
|
||||
* call ace_frag_fnc_masterPFH
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
|
||||
BEGIN_COUNTER(PFH);
|
||||
|
||||
// Fast exit if nothing to do
|
||||
if (GVAR(objects) isEqualTo []) exitWith {END_COUNTER(PFH);};
|
||||
|
||||
private _gcIndex = [];
|
||||
|
||||
private _iter = 0;
|
||||
private _objectCount = count GVAR(objects);
|
||||
while {_objectCount > 0 && {_iter < (GVAR(maxTrackPerFrame) min _objectCount)}} do {
|
||||
|
||||
if (GVAR(lastIterationIndex) >= _objectCount) then {
|
||||
GVAR(lastIterationIndex) = 0;
|
||||
};
|
||||
private _object = GVAR(objects) select GVAR(lastIterationIndex);
|
||||
|
||||
if (!isNil "_object") then {
|
||||
private _args = GVAR(arguments) select GVAR(lastIterationIndex);
|
||||
|
||||
if (!(_args call FUNC(pfhRound))) then {
|
||||
_gcIndex pushBack GVAR(lastIterationIndex); // Add it to the GC if it returns false
|
||||
};
|
||||
};
|
||||
INC(_iter);
|
||||
INC(GVAR(lastIterationIndex));
|
||||
};
|
||||
|
||||
// Clean up dead object references
|
||||
private _deletionCount = 0;
|
||||
{
|
||||
TRACE_1("GC Projectile", _x);
|
||||
private _deleteIndex = _x - _deletionCount;
|
||||
GVAR(objects) deleteAt _deleteIndex;
|
||||
GVAR(arguments) deleteAt _deleteIndex;
|
||||
|
||||
INC(_deletionCount);
|
||||
} forEach _gcIndex;
|
||||
|
||||
END_COUNTER(PFH);
|
@ -1,59 +0,0 @@
|
||||
#include "..\script_component.hpp"
|
||||
/*
|
||||
* Author: ACE-Team
|
||||
*
|
||||
*
|
||||
* Arguments:
|
||||
* None
|
||||
*
|
||||
* Return Value:
|
||||
* None
|
||||
*
|
||||
* Example:
|
||||
* call ace_frag_fnc_pfhRound
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
|
||||
params ["_round", "_lastPos", "_lastVel", "_shellType", "_firedFrame", "_firedPos", "_doSpall", "_spallTrack", "_foundObjectHPIds", "_skip", "_explosive", "_indirectRange", "_force", "_fragPower"];
|
||||
|
||||
if (_round in GVAR(blackList)) exitWith {
|
||||
false
|
||||
};
|
||||
|
||||
if (!alive _round) exitWith {
|
||||
if ((diag_frameno - _firedFrame) > 1) then { //skip if deleted within a single frame
|
||||
if (_skip == 0) then {
|
||||
if ((_explosive > 0.5 && {_indirectRange >= 4.5} && {_fragPower >= 35}) || {_force == 1}) then {
|
||||
// shotbullet, shotShell don't seem to explode when touching water, so don't create frags
|
||||
if ((surfaceIsWater _lastPos) && {(toLower getText (configFile >> "CfgAmmo" >> _shellType >> "simulation")) in ["shotbullet", "shotshell"]}) exitWith {};
|
||||
private _fuseDist = getNumber(configFile >> "CfgAmmo" >> _shellType >> "fuseDistance");
|
||||
private _isArmed = _firedPos vectorDistance _lastPos >= _fuseDist; // rounds explode at exactly fuseDistance, so check inclusive
|
||||
TRACE_2("",_fuseDist,_isArmed);
|
||||
if (!_isArmed) exitWith {TRACE_1("round not armed",_this);};
|
||||
TRACE_3("Sending frag event to server",_lastPos,_lastVel,_shellType);
|
||||
[QGVAR(frag_eh), [_lastPos,_lastVel,_shellType]] call CBA_fnc_serverEvent;
|
||||
};
|
||||
};
|
||||
};
|
||||
if (_doSpall) then {
|
||||
DEC(GVAR(spallIsTrackingCount));
|
||||
TRACE_1("doSpall",_foundObjectHPIds);
|
||||
{
|
||||
if (!isNil "_x") then {
|
||||
_x removeEventHandler ["hitPart", _foundObjectHPIds select _forEachIndex];
|
||||
};
|
||||
} forEach _spallTrack;
|
||||
};
|
||||
false
|
||||
};
|
||||
|
||||
_this set [1, getPosASL _round];
|
||||
_this set [2, velocity _round];
|
||||
|
||||
if (_doSpall) then {
|
||||
private _scale = ((count GVAR(objects)) / GVAR(maxTrackPerFrame)) max 0.1;
|
||||
[_round, _scale, _spallTrack, _foundObjectHPIds] call FUNC(spallTrack);
|
||||
};
|
||||
|
||||
true
|
55
addons/frag/functions/fnc_shouldFrag.sqf
Normal file
55
addons/frag/functions/fnc_shouldFrag.sqf
Normal file
@ -0,0 +1,55 @@
|
||||
#include "script_component.hpp"
|
||||
/*
|
||||
* Author: Lambda.Tiger
|
||||
* This function checks whether an ammunition type should cause fragmentation
|
||||
* and whether any submunitions exist
|
||||
*
|
||||
* Arguments:
|
||||
* 0: _ammo <STRING> - cfgAmmo type of ammo to check
|
||||
*
|
||||
* Return Value:
|
||||
* _shouldFrag <ARRAY>
|
||||
* 0 - Should the specific round fragment
|
||||
* 1 - Does the munition have a child submunition
|
||||
*
|
||||
* Example:
|
||||
* ["B_556x45_Ball"] call ace_frag_fnc_shouldFrag;
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
|
||||
params ["_ammo"];
|
||||
|
||||
private _shouldFrag = GVAR(shouldFragCache) get _ammo;
|
||||
|
||||
if !(isNil "_shouldFrag") exitWith {_shouldFrag};
|
||||
// two arguments, 1st for munition should frag, 2nd for
|
||||
_shouldFrag = [true, false];
|
||||
|
||||
private _skip = getNumber (configFile >> "cfgAmmo" >> _ammo >> QGVAR(skip));
|
||||
private _force = getNumber (configFile >> "cfgAmmo" >> _ammo >> QGVAR(force));
|
||||
private _explosive = getNumber (configFile >> "cfgAmmo" >> _ammo >> "explosive");
|
||||
private _indirectHit = getNumber(configFile >> "cfgAmmo" >> _ammo >> "indirectHit");
|
||||
private _indirectRange = getNumber(configFile >> "cfgAmmo" >> _ammo >> "indirectHitRange");
|
||||
|
||||
if (_skip == 1 || (_force == 0 && {_explosive < 0.5 || {_indirectHit < 3
|
||||
|| {_indirectRange < 5 && _indirectHit < _indirectRange}}})) then {
|
||||
TRACE_4("No frag" ,_skip, _explosive, _indirectRange, _indirectHit);
|
||||
_shouldFrag set [0, false];
|
||||
};
|
||||
|
||||
if (GVAR(enSubMunit) > 0) then {
|
||||
private _hasSubmunit = if (isText (configFile >> "cfgAmmo" >> _ammo >> "submunitionAmmo")) then {
|
||||
"" isNotEqualTo getText (configFile >> "cfgAmmo" >> _ammo >> "submunitionAmmo");
|
||||
} else
|
||||
{
|
||||
[] isNotEqualTo getArray (configFile >> "cfgAmmo" >> _ammo >> "submunitionAmmo");
|
||||
};
|
||||
|
||||
_shouldFrag set [1, _hasSubmunit];
|
||||
TRACE_2("Submunition" ,_ammo, _hasSubmunit);
|
||||
};
|
||||
|
||||
GVAR(shouldFragCache) set [_ammo, _shouldFrag];
|
||||
|
||||
_shouldFrag
|
31
addons/frag/functions/fnc_shouldSpall.sqf
Normal file
31
addons/frag/functions/fnc_shouldSpall.sqf
Normal file
@ -0,0 +1,31 @@
|
||||
#include "script_component.hpp"
|
||||
/*
|
||||
* Author: Lambda.Tiger
|
||||
* This function checks whether an ammunition type should cause spalling
|
||||
*
|
||||
*
|
||||
* Arguments:
|
||||
* 0: _ammo <STRING> - cfgAmmo type of ammo to check
|
||||
*
|
||||
* Return Value:
|
||||
* Whether the round type would spall when hitting an object <BOOL>
|
||||
*
|
||||
* Example:
|
||||
* ["B_556x45_Ball"] call ace_frag_fnc_shouldSpall;
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
|
||||
params ["_ammo"];
|
||||
|
||||
private _shouldSpall = GVAR(spallCahche) get _ammo;
|
||||
|
||||
if !(isNil "_shouldSpall") exitWith {_shouldSpall};
|
||||
|
||||
private _caliber = getNumber (configFile >> "CfgAmmo" >> _ammo >> "caliber");
|
||||
private _explosive = getNumber (configFile >> "CfgAmmo" >> _ammo >> "explosive");
|
||||
private _idH = getNumber (configFile >> "CfgAmmo" >> _ammo >> "indirectHitRange");
|
||||
|
||||
_shouldSpall = (_caliber >= 2.5 || _explosive > 0 && _idh >= 1);
|
||||
|
||||
_shouldSpall
|
@ -1,42 +0,0 @@
|
||||
#include "..\script_component.hpp"
|
||||
/*
|
||||
* Author: ACE-Team
|
||||
* Handles the HitPart event
|
||||
*
|
||||
* Arguments:
|
||||
* None
|
||||
*
|
||||
* Return Value:
|
||||
* None
|
||||
*
|
||||
* Example:
|
||||
* call ace_frag_fnc_spallHP
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
|
||||
//player sideChat format ["f: %1 c: %2", (_this select 0), (count GVAR(spallHPData))];
|
||||
|
||||
params ["_index", "_hitPartData"];
|
||||
|
||||
private _initialData = GVAR(spallHPData) param [_index, []];
|
||||
if (_initialData isEqualTo []) exitWith {};
|
||||
|
||||
private _hpRound = (_hitPartData select 0) select 2;
|
||||
private _round = _initialData select 3;
|
||||
private _hpDirect = (_hitPartData select 0) select 10;
|
||||
|
||||
if (_hpDirect && {_round == _hpRound}) then {
|
||||
{
|
||||
// diag_log text format ["HPDUMP-------------------------------------"];
|
||||
// {
|
||||
// _hp = _x;
|
||||
// diag_log text format ["%1 --", _forEachIndex];
|
||||
// {
|
||||
// diag_log text format ["%1: %2", _forEachIndex, _x];
|
||||
// } forEach _hp;
|
||||
// } forEach (_this select 1);
|
||||
[DFUNC(doSpall), [_this, _forEachIndex]] call CBA_fnc_execNextFrame;
|
||||
// player sideChat "WEEE";
|
||||
} forEach _hitPartData;
|
||||
};
|
@ -1,39 +0,0 @@
|
||||
#include "..\script_component.hpp"
|
||||
/*
|
||||
* Author: ACE-Team
|
||||
* Add HitPart EventHandler to objects in the projectile's path
|
||||
*
|
||||
* Arguments:
|
||||
* None
|
||||
*
|
||||
* Return Value:
|
||||
* None
|
||||
*
|
||||
* Example:
|
||||
* call ace_frag_fnc_spallTrack
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
|
||||
params ["_round", "_multiplier", "_foundObjects", "_foundObjectHPIds"];
|
||||
|
||||
private _delta = (1 / diag_fps) * _multiplier;
|
||||
private _curPos = getPosASL _round;
|
||||
private _velocity = velocity _round;
|
||||
|
||||
private _velocityStep = _velocity vectorMultiply _delta;
|
||||
private _forwardPos = _curPos vectorAdd _velocityStep;
|
||||
|
||||
|
||||
private _intersectsWith = lineIntersectsWith [_curPos, _forwardPos];
|
||||
|
||||
if (_intersectsWith isEqualTo []) exitWith {};
|
||||
{
|
||||
// diag_log text format ["Adding HP: %1", _x];
|
||||
private _index = count GVAR(spallHPData);
|
||||
private _hpId = _x addEventHandler ["hitPart", compile format ["[%1, _this] call " + QFUNC(spallHP), _index]];
|
||||
_foundObjects pushBack _x;
|
||||
_foundObjectHPIds pushBack _hpId;
|
||||
private _data = [_hpId, _x, typeOf _round, _round, _curPos, _velocity, 0, _foundObjects, _foundObjectHPIds];
|
||||
GVAR(spallHPData) pushBack _data;
|
||||
} forEach (_intersectsWith select {!(_x in _foundObjects)});
|
40
addons/frag/functions/fnc_submunition.sqf
Normal file
40
addons/frag/functions/fnc_submunition.sqf
Normal file
@ -0,0 +1,40 @@
|
||||
#include "script_component.hpp"
|
||||
/*
|
||||
* Author: Lambda.Tiger
|
||||
* This function adds event handlers for submunition fragmentation.
|
||||
* It begins by confirming fragmentation and submunition fragmentation is
|
||||
* enabled, requests cached (or live calculated) ammo information array.
|
||||
* and uses that information to add event handlers as needed to the given
|
||||
* submunition.
|
||||
*
|
||||
* Arguments:
|
||||
* Inherits from BI SubmunitionCraeted EH
|
||||
*
|
||||
* Return Value:
|
||||
* none
|
||||
*
|
||||
* Example:
|
||||
* ["", _submunitionProjectile] call ace_frag_submunition
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
|
||||
if (!GVAR(enabled) || {GVAR(enSubMunit) == 0}) exitWith {};
|
||||
// params ["_projectile", "_submunitionProjectile", "_pos", "_velocity"];
|
||||
params ["", "_submunitionProjectile"];
|
||||
|
||||
private _shouldFrag = GVAR(shouldFragCache) getOrDefaultCall [typeOf _submunitionProjectile, FUNC(shouldFrag), true];
|
||||
_shouldFrag params ["_doFrag", "_doSubmunit"];
|
||||
|
||||
|
||||
if (_doFrag) then {
|
||||
_submunitionProjectile addEventHandler ["Explode", {[_this, true] call FUNC(doFrag)}];
|
||||
};
|
||||
|
||||
if (_doSubmunit) then {
|
||||
_submunitionProjectile addEventHandler ["SubmunitionCreated", {_this call FUNC(submunition)}];
|
||||
};
|
||||
|
||||
#ifdef DEBUG_MODE_FULL
|
||||
[_submunitionProjectile] call UNC(dev_addRound);
|
||||
#endif
|
1
addons/frag/functions/script_component.hpp
Normal file
1
addons/frag/functions/script_component.hpp
Normal file
@ -0,0 +1 @@
|
||||
#include "\z\ace\addons\frag\script_component.hpp"
|
@ -26,29 +26,29 @@ private _category = format ["ACE %1", localize LSTRING(Module_DisplayName)];
|
||||
|
||||
/// !*! TODO: add stringtable entries
|
||||
[
|
||||
QGVAR(enSubMunit), "LIST",
|
||||
["Enable submunition fragmentation", "Enables submunition fragmentation when fragmentation is enabled"],
|
||||
QGVAR(enSubMunit), "LIST",
|
||||
["Enable submunition fragmentation", "Enables submunition fragmentation when fragmentation is enabled"],
|
||||
[_category, LSTRING(Frag)],
|
||||
[[2, 1, 0], ["complex fragementation","simple fragmentation","no fragmentation"], 2]
|
||||
[[2, 1, 0], ["complex fragementation","simple fragmentation","no fragmentation"], 2]
|
||||
] call CBA_fnc_addSetting;
|
||||
|
||||
[
|
||||
QGVAR(reflectionsEnabled), "CHECKBOX",
|
||||
"Enable reflections",
|
||||
QGVAR(reflectionsEnabled), "CHECKBOX",
|
||||
"Enable reflections",
|
||||
[_category, LSTRING(Frag)],
|
||||
false
|
||||
false
|
||||
] call CBA_fnc_addSetting;
|
||||
|
||||
[
|
||||
QGVAR(atLeastOne), "CHECKBOX",
|
||||
"At least one round hit",
|
||||
QGVAR(atLeastOne), "CHECKBOX",
|
||||
"At least one round hit",
|
||||
[_category, LSTRING(Frag)],
|
||||
true
|
||||
true
|
||||
] call CBA_fnc_addSetting;
|
||||
|
||||
[
|
||||
QGVAR(BlackList), "EDITBOX",
|
||||
["Default BlackList", "Array of ammo classnames strings to blackist fragmentation for."],
|
||||
QGVAR(BlackList), "EDITBOX",
|
||||
["Default BlackList", "Array of ammo classnames strings to blackist fragmentation for."],
|
||||
[_category, LSTRING(Frag)],
|
||||
QUOTE(['B_556x45_Ball'])
|
||||
QUOTE(['B_556x45_Ball'])
|
||||
] call CBA_fnc_addSetting;
|
||||
|
@ -1,54 +1,54 @@
|
||||
private _category = format ["ACE %1", localize LSTRING(Module_DisplayName)];
|
||||
|
||||
[
|
||||
QGVAR(debugOptions),
|
||||
"CHECKBOX",
|
||||
"Enable debug mode",
|
||||
[_category, LSTRING(Debug)],
|
||||
true // [min, max, default, trailing decimals]
|
||||
QGVAR(debugOptions),
|
||||
"CHECKBOX",
|
||||
"Enable debug mode",
|
||||
[_category, LSTRING(Debug)],
|
||||
true // [min, max, default, trailing decimals]
|
||||
] call CBA_fnc_addSetting;
|
||||
|
||||
// debug options
|
||||
[
|
||||
QGVAR(dbgSphere),
|
||||
"CHECKBOX",
|
||||
"Enable debug impact spheres",
|
||||
[_category, LSTRING(Debug)],
|
||||
false,
|
||||
0,
|
||||
{},
|
||||
true
|
||||
QGVAR(dbgSphere),
|
||||
"CHECKBOX",
|
||||
"Enable debug impact spheres",
|
||||
[_category, LSTRING(Debug)],
|
||||
false,
|
||||
0,
|
||||
{},
|
||||
true
|
||||
] call CBA_fnc_addSetting;
|
||||
|
||||
[
|
||||
QGVAR(frameHint),
|
||||
"CHECKBOX",
|
||||
"Show framerate hint",
|
||||
[_category, LSTRING(Debug)],
|
||||
true
|
||||
QGVAR(frameHint),
|
||||
"CHECKBOX",
|
||||
"Show framerate hint",
|
||||
[_category, LSTRING(Debug)],
|
||||
true
|
||||
] call CBA_fnc_addSetting;
|
||||
|
||||
[
|
||||
QGVAR(fadeRounds),
|
||||
"CHECKBOX",
|
||||
"Fade round traces over time",
|
||||
[_category, LSTRING(Debug)],
|
||||
true
|
||||
QGVAR(fadeRounds),
|
||||
"CHECKBOX",
|
||||
"Fade round traces over time",
|
||||
[_category, LSTRING(Debug)],
|
||||
true
|
||||
] call CBA_fnc_addSetting;
|
||||
|
||||
[
|
||||
QGVAR(dltTrace),
|
||||
"CHECKBOX",
|
||||
"Delete fire trace on fade",
|
||||
[_category, LSTRING(Debug)],
|
||||
true
|
||||
QGVAR(dltTrace),
|
||||
"CHECKBOX",
|
||||
"Delete fire trace on fade",
|
||||
[_category, LSTRING(Debug)],
|
||||
true
|
||||
] call CBA_fnc_addSetting;
|
||||
|
||||
[
|
||||
QGVAR(drawHitBox),
|
||||
"CHECKBOX",
|
||||
"Draw unit hitboxes",
|
||||
[_category, LSTRING(Debug)],
|
||||
true
|
||||
QGVAR(drawHitBox),
|
||||
"CHECKBOX",
|
||||
"Draw unit hitboxes",
|
||||
[_category, LSTRING(Debug)],
|
||||
true
|
||||
] call CBA_fnc_addSetting;
|
||||
|
||||
|
@ -17,4 +17,4 @@
|
||||
|
||||
#include "\z\ace\addons\main\script_macros.hpp"
|
||||
|
||||
#define ACE_TRACE_DRAW_INC 1
|
||||
#define ACE_FRAG_SPALL_HOLDOFF 0.1
|
||||
|
Loading…
Reference in New Issue
Block a user