2023-09-12 18:58:10 +00:00
|
|
|
#include "..\script_component.hpp"
|
2016-10-06 20:37:38 +00:00
|
|
|
/*
|
|
|
|
* Author: Glowbal
|
2024-01-27 08:14:10 +00:00
|
|
|
* Detonates ammunition from an object (e.g. vehicle or crate) until no ammo is left.
|
2016-10-06 20:37:38 +00:00
|
|
|
*
|
|
|
|
* Arguments:
|
2024-01-27 08:14:10 +00:00
|
|
|
* 0: Object <OBJECT>
|
|
|
|
* 1: Magazine array <ARRAY>
|
|
|
|
* - 0: Magazine classname <STRING>
|
|
|
|
* - 1: Ammo count <NUMBER>
|
|
|
|
* 2: Total ammo count <NUMBER>
|
|
|
|
* 3: Destroy when finished <BOOL> (default: false)
|
|
|
|
* 4: Killer <OBJECT> (default: objNull)
|
|
|
|
* 5: Instigator <OBJECT> (default: objNull)
|
|
|
|
* 6: Initial delay <NUMBER> (default: 0)
|
2016-10-06 20:37:38 +00:00
|
|
|
*
|
|
|
|
* Return Value:
|
2024-01-27 08:14:10 +00:00
|
|
|
* Nothing Useful
|
2016-10-06 20:37:38 +00:00
|
|
|
*
|
|
|
|
* Example:
|
2024-01-27 08:14:10 +00:00
|
|
|
* [cursorObject, magazinesAmmo vehicle player, 1000] call ace_cookoff_fnc_detonateAmmunition
|
2016-10-06 20:37:38 +00:00
|
|
|
*
|
|
|
|
* Public: No
|
|
|
|
*/
|
|
|
|
|
2024-01-27 08:14:10 +00:00
|
|
|
if (!isServer) exitWith {};
|
2016-10-06 20:37:38 +00:00
|
|
|
|
2024-01-27 08:14:10 +00:00
|
|
|
params ["_object", "_magazines", "_totalAmmo", ["_destroyWhenFinished", false], ["_killer", objNull], ["_instigator", objNull], ["_initialDelay", 0]];
|
2021-10-14 15:49:27 +00:00
|
|
|
|
2024-01-27 08:14:10 +00:00
|
|
|
if (isNull _object) exitWith {};
|
2016-10-06 20:37:38 +00:00
|
|
|
|
2024-01-27 08:14:10 +00:00
|
|
|
// If the cook-off has finished, clean up the effects and destroy the object
|
|
|
|
if (_magazines isEqualTo [] || {_totalAmmo <= 0}) exitWith {
|
|
|
|
[QGVAR(cleanupEffects), _object] call CBA_fnc_globalEvent;
|
2016-10-06 20:37:38 +00:00
|
|
|
|
2024-01-27 08:14:10 +00:00
|
|
|
if (_destroyWhenFinished) then {
|
|
|
|
_object setDamage [1, true, _killer, _instigator];
|
|
|
|
};
|
|
|
|
};
|
2017-01-04 21:35:54 +00:00
|
|
|
|
2024-01-27 08:14:10 +00:00
|
|
|
// If the cook-off is interrupted or disabled, clean up the effects
|
|
|
|
if (underwater _object || {
|
|
|
|
if (GVAR(ammoCookoffDuration) == 0) exitWith {true};
|
|
|
|
|
|
|
|
if (_object isKindOf "ReammoBox_F") exitWith {
|
|
|
|
!(GVAR(enableAmmobox) && {_object getVariable [QGVAR(enableAmmoCookoff), true]})
|
2016-10-06 20:37:38 +00:00
|
|
|
};
|
|
|
|
|
2024-01-27 08:14:10 +00:00
|
|
|
!(GVAR(enableAmmoCookoff) && {_object getVariable [QGVAR(enableAmmoCookoff), true]})
|
|
|
|
}) exitWith {
|
|
|
|
[QGVAR(cleanupEffects), _object] call CBA_fnc_globalEvent;
|
|
|
|
};
|
|
|
|
|
|
|
|
// Initial delay allows for a delay for the first time this function runs in its cycle
|
|
|
|
if (_initialDelay > 0) exitWith {
|
|
|
|
[FUNC(detonateAmmunition), [_object, _magazines, _totalAmmo, _destroyWhenFinished, _killer, _instigator], _initialDelay] call CBA_fnc_waitAndExecute;
|
|
|
|
};
|
2016-11-05 14:20:48 +00:00
|
|
|
|
2024-01-27 08:14:10 +00:00
|
|
|
private _magazineIndex = floor random (count _magazines);
|
|
|
|
private _magazine = _magazines select _magazineIndex;
|
|
|
|
_magazine params ["_magazineClassname", "_ammoCount"];
|
2016-10-06 20:37:38 +00:00
|
|
|
|
2024-01-27 08:14:10 +00:00
|
|
|
// Make sure ammo is at least 0
|
|
|
|
_ammoCount = _ammoCount max 0;
|
2016-10-06 20:37:38 +00:00
|
|
|
|
2024-01-27 08:14:10 +00:00
|
|
|
// Remove some ammo, which will be detonated
|
|
|
|
private _removed = _ammoCount min floor (1 + random (6 / GVAR(ammoCookoffDuration)));
|
2016-10-06 20:37:38 +00:00
|
|
|
|
2024-01-27 08:14:10 +00:00
|
|
|
_ammoCount = _ammoCount - _removed;
|
2016-11-06 12:24:00 +00:00
|
|
|
|
2024-01-27 08:14:10 +00:00
|
|
|
if (_ammoCount <= 0) then {
|
|
|
|
_magazines deleteAt _magazineIndex;
|
|
|
|
} else {
|
|
|
|
_magazine set [1, _ammoCount]; // remove ammo that was detonated
|
|
|
|
};
|
|
|
|
|
|
|
|
private _timeBetweenAmmoDetonation = ((random 10 / sqrt _totalAmmo) min MAX_TIME_BETWEEN_AMMO_DET) max 0.1;
|
|
|
|
TRACE_2("",_totalAmmo,_timeBetweenAmmoDetonation);
|
|
|
|
_totalAmmo = _totalAmmo - _removed;
|
2016-10-06 20:37:38 +00:00
|
|
|
|
2024-01-27 08:14:10 +00:00
|
|
|
// Detonate the remaining ammo after a delay
|
|
|
|
[FUNC(detonateAmmunition), [_object, _magazines, _totalAmmo, _destroyWhenFinished, _killer, _instigator], _timeBetweenAmmoDetonation] call CBA_fnc_waitAndExecute;
|
|
|
|
|
|
|
|
// Get magazine info, which is used to spawn projectiles
|
|
|
|
private _configMagazine = configFile >> "CfgMagazines" >> _magazineClassname;
|
|
|
|
private _ammo = getText (_configMagazine >> "ammo");
|
|
|
|
private _configAmmo = configFile >> "CfgAmmo" >> _ammo;
|
|
|
|
|
|
|
|
private _simType = toLower getText (_configAmmo >> "simulation");
|
|
|
|
private _speed = random (getNumber (_configMagazine >> "initSpeed") / 10) max 1;
|
|
|
|
|
|
|
|
private _effect2pos = _object selectionPosition "destructionEffect2";
|
|
|
|
|
|
|
|
// Spawns the projectiles, making them either fly in random directions or explode
|
|
|
|
private _fnc_spawnProjectile = {
|
|
|
|
params ["_object", "_ammo", "_speed", "_flyAway"];
|
|
|
|
|
|
|
|
private _spawnPos = _object modelToWorld [-0.2 + random 0.4, -0.2 + random 0.4, random 3];
|
|
|
|
|
|
|
|
if (_spawnPos select 2 < 0) then {
|
|
|
|
_spawnPos set [2, 0];
|
2016-10-06 20:37:38 +00:00
|
|
|
};
|
|
|
|
|
2024-01-27 08:14:10 +00:00
|
|
|
private _projectile = createVehicle [_ammo, _spawnPos, [], 0, "CAN_COLLIDE"];
|
2016-10-06 20:37:38 +00:00
|
|
|
|
2024-01-27 08:14:10 +00:00
|
|
|
if (_flyAway) then {
|
|
|
|
private _vectorAmmo = [-1 + random 2, -1 + random 2, -0.2 + random 1];
|
|
|
|
private _vectorVelocity = _vectorAmmo vectorMultiply _speed;
|
|
|
|
|
|
|
|
_projectile setVectorDir _vectorVelocity;
|
|
|
|
_projectile setVelocity _vectorVelocity;
|
|
|
|
} else {
|
|
|
|
_projectile setDamage 1;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
switch (_simType) do {
|
|
|
|
case "shotbullet": {
|
|
|
|
private _sound = selectRandom [QPATHTO_R(sounds\light_crack_close.wss), QPATHTO_R(sounds\light_crack_close_filtered.wss), QPATHTO_R(sounds\heavy_crack_close.wss), QPATHTO_R(sounds\heavy_crack_close_filtered.wss)];
|
|
|
|
playSound3D [_sound, objNull, false, getPosASL _object, 2, 1, 1250];
|
2016-10-06 20:37:38 +00:00
|
|
|
|
|
|
|
if (random 1 < 0.6) then {
|
2024-01-27 08:14:10 +00:00
|
|
|
[_object, _ammo, _speed, true] call _fnc_spawnProjectile;
|
2016-10-06 20:37:38 +00:00
|
|
|
};
|
|
|
|
};
|
2024-01-27 08:14:10 +00:00
|
|
|
case "shotshell": {
|
|
|
|
private _sound = selectRandom [QPATHTO_R(sounds\heavy_crack_close.wss), QPATHTO_R(sounds\heavy_crack_close_filtered.wss)];
|
|
|
|
playSound3D [_sound, objNull, false, getPosASL _object, 2, 1, 1300];
|
2016-10-06 20:37:38 +00:00
|
|
|
|
|
|
|
if (random 1 < 0.15) then {
|
2024-01-27 08:14:10 +00:00
|
|
|
[_object, _ammo, _speed, true] call _fnc_spawnProjectile;
|
2016-10-06 20:37:38 +00:00
|
|
|
};
|
|
|
|
};
|
2024-01-27 08:14:10 +00:00
|
|
|
case "shotgrenade": {
|
2016-10-06 20:37:38 +00:00
|
|
|
if (random 1 < 0.9) then {
|
|
|
|
_speed = 0;
|
|
|
|
};
|
2024-01-27 08:14:10 +00:00
|
|
|
|
|
|
|
[_object, _ammo, _speed, random 1 < 0.5] call _fnc_spawnProjectile;
|
2016-10-06 20:37:38 +00:00
|
|
|
};
|
2024-01-27 08:14:10 +00:00
|
|
|
case "shotrocket";
|
|
|
|
case "shotmissile";
|
|
|
|
case "shotsubmunitions": {
|
2016-10-06 20:37:38 +00:00
|
|
|
if (random 1 < 0.1) then {
|
2024-01-27 08:14:10 +00:00
|
|
|
private _sound = selectRandom [QPATHTO_R(sounds\cannon_crack_close.wss), QPATHTO_R(sounds\cannon_crack_close_filtered.wss)];
|
|
|
|
playSound3D [_sound, objNull, false, getPosASL _object, 3, 1, 1600];
|
2016-10-06 20:37:38 +00:00
|
|
|
|
2024-01-27 08:14:10 +00:00
|
|
|
[_object, _ammo, _speed, random 1 < 0.3] call _fnc_spawnProjectile;
|
2016-10-06 20:37:38 +00:00
|
|
|
} else {
|
2024-01-27 08:14:10 +00:00
|
|
|
createVehicle ["ACE_ammoExplosionLarge", _object modelToWorld _effect2pos, [], 0 , "CAN_COLLIDE"];
|
2016-10-06 20:37:38 +00:00
|
|
|
};
|
|
|
|
};
|
2024-01-27 08:14:10 +00:00
|
|
|
case "shotdirectionalbomb";
|
|
|
|
case "shotmine": {
|
2016-10-06 20:37:38 +00:00
|
|
|
if (random 1 < 0.5) then {
|
2016-11-05 14:20:48 +00:00
|
|
|
// Not all explosives detonate on destruction, some have scripted alternatives
|
2024-01-27 08:14:10 +00:00
|
|
|
if (getNumber (_configAmmo >> "triggerWhenDestroyed") != 1) then {
|
|
|
|
_ammo = getText (_configAmmo >> QEGVAR(explosives,explosive));
|
2016-11-05 14:20:48 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
// If a scripted alternative doesn't exist use generic explosion
|
|
|
|
if (_ammo != "") then {
|
2024-01-27 08:14:10 +00:00
|
|
|
[_object, _ammo, 0, false] call _fnc_spawnProjectile;
|
2016-11-05 14:20:48 +00:00
|
|
|
} else {
|
2024-01-27 08:14:10 +00:00
|
|
|
createVehicle ["SmallSecondary", _object modelToWorld _effect2pos, [], 0 , "CAN_COLLIDE"];
|
2016-11-05 14:20:48 +00:00
|
|
|
};
|
|
|
|
};
|
|
|
|
};
|
2024-01-27 08:14:10 +00:00
|
|
|
case "shotilluminating": {
|
2016-11-05 14:20:48 +00:00
|
|
|
if (random 1 < 0.15) then {
|
2024-01-27 08:14:10 +00:00
|
|
|
[_object, _ammo, _speed, random 1 < 0.3] call _fnc_spawnProjectile;
|
2016-10-06 20:37:38 +00:00
|
|
|
};
|
|
|
|
};
|
|
|
|
};
|