Skip to content

Commit 99c85e3

Browse files
DrofsehMike-MFLinkIsGrimPabstMirrorjonpas
authored
Overheating - Fix issues from release (#8617)
* move overheating cookoff into separate function * move heatCoef and require mission restart for setting change - move heatCoef to a more sensible place - require mission restart for heatCoef setting change (it gets cached per ammo type) * add exit to ammo temp loop if cookoffCoef is changed to 0 mid-mission - add exit to ammo temp loop if cookoffCoef is changed to 0 mid-mission, this prevents an issue where all weapon cookoff regardless of temp, because required temp gets multiplied by cookoffCoef which has been set to 0. * file end new line * update header for ace_overheating_fnc_cookoffWeapon * use ambientTemperature as floor for weapon and ammo temp * add coolingCoef setting * improve feature documentation * add fnc_cookoffWeapon to XEH_PREP * add type of jam to ace_weaponJammed local event - add type of jam to ace_weaponJammed local event - fix #8637 * fix misspelling Co-authored-by: TyroneMF <[email protected]> * clear all weapon heat on death * Update addons/overheating/functions/fnc_updateTemperature.sqf Co-authored-by: GhostIsSpooky <[email protected]> * deprecate ace_overheating_fnc_getBarrelMass, cache weapon bolt and barrel mass values - cache closed bolt value by moving config look up to ace_overheating_fnc_getWeaponData - cache barrel mass value by moving calculation from ace_overheating_fnc_getBarrelMass to ace_overheating_fnc_getWeaponData - deprecate ace_overheating_fnc_getBarrelMass to be a wrapper for ace_overheating_fnc_getWeaponData that only returns barrel mass * add public functions to get and set weapon and ammo temperature * add `canCoolWeaponWithItem` function, workaround for #8657 * Apply suggestions from code review Co-authored-by: PabstMirror <[email protected]> * add coef setting for addition heat from suppressor * Update fnc_overheat.sqf * improve fnc_canCoolWeaponWithItem * remove extra ( * Move canCoolWeaponWithItem action code to function * Use hashmaps and reset on settings change * Apply suggestions from code review Co-authored-by: jonpas <[email protected]> Co-authored-by: TyroneMF <[email protected]> Co-authored-by: GhostIsSpooky <[email protected]> Co-authored-by: PabstMirror <[email protected]> Co-authored-by: jonpas <[email protected]>
1 parent 5bad689 commit 99c85e3

23 files changed

+323
-100
lines changed

addons/overheating/CfgVehicles.hpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ class CfgVehicles {
3838
};
3939
class GVAR(CoolWeaponWithItem) {
4040
displayName = CSTRING(CoolWeaponWithItem);
41-
condition = QUOTE(GVAR(enabled) && {isClass (configfile >> 'CfgPatches' >> 'acex_field_rations')});
41+
condition = QUOTE(call FUNC(canCoolWeaponWithItem));
4242
exceptions[] = {"isNotInside", "isNotSwimming", "isNotSitting"};
4343
statement = "true";
4444
showDisabled = 0;
@@ -66,7 +66,7 @@ class CfgVehicles {
6666
};
6767
class GVAR(CoolWeaponWithItem) {
6868
displayName = CSTRING(CoolWeaponWithItem);
69-
condition = QUOTE(GVAR(enabled) && {isClass (configfile >> 'CfgPatches' >> 'acex_field_rations')});
69+
condition = QUOTE(call FUNC(canCoolWeaponWithItem));
7070
exceptions[] = {"isNotInside", "isNotSwimming", "isNotSitting"};
7171
statement = "true";
7272
showDisabled = 0;

addons/overheating/XEH_PREP.hpp

+5
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,24 @@ PREP(canCheckSpareBarrelsTemperatures);
66
PREP(checkSpareBarrelsTemperatures);
77
PREP(checkTemperature);
88
PREP(clearJam);
9+
PREP(cookoffWeapon);
910
PREP(coolWeaponWithItem);
1011
PREP(coolWeaponWithWaterSource);
1112
PREP(displayTemperature);
1213
PREP(firedEH);
14+
PREP(getAmmoTemperature);
1315
PREP(getBarrelMass);
1416
PREP(getConsumableChildren);
1517
PREP(getWeaponData);
18+
PREP(getWeaponTemperature);
1619
PREP(handleTakeEH);
1720
PREP(handleRespawn);
1821
PREP(jamWeapon);
1922
PREP(loadCoolestSpareBarrel);
2023
PREP(overheat);
2124
PREP(sendSpareBarrelsTemperaturesHint);
25+
PREP(setAmmoTemperature);
26+
PREP(setWeaponTemperature);
2227
PREP(swapBarrel);
2328
PREP(swapBarrelAssistant);
2429
PREP(swapBarrelCallback);

addons/overheating/XEH_postInit.sqf

+13-4
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,9 @@ if (hasInterface) then {
4444

4545
if !(hasInterface) exitWith {};
4646

47-
GVAR(cacheWeaponData) = call CBA_fnc_createNamespace;
48-
GVAR(cacheAmmoData) = call CBA_fnc_createNamespace;
49-
GVAR(cacheSilencerData) = call CBA_fnc_createNamespace;
47+
GVAR(cacheWeaponData) = createHashMap;
48+
GVAR(cacheAmmoData) = createHashMap;
49+
GVAR(cacheSilencerData) = createHashMap;
5050

5151
//Add Take EH if required
5252
if (GVAR(unJamOnReload) || {GVAR(cookoffCoef) > 0}) then {
@@ -76,8 +76,18 @@ if (hasInterface) then {
7676
}] call CBA_fnc_addClassEventHandler;
7777
};
7878

79+
// Reset all weapon heat to ambient on death to prevent cookoffs when a unit respawns.
80+
["CAManBase", "Killed", {
81+
params ["_unit"];
82+
{
83+
_unit setVariable [_x, ambientTemperature select 0];
84+
} forEach (_unit getVariable [QGVAR(trackedWeapons), []]);
85+
_unit setVariable [QGVAR(trackedWeapons), []];
86+
}] call CBA_fnc_addClassEventHandler;
87+
7988
// Install event handler to display temp when a barrel was swapped
8089
[QGVAR(showWeaponTemperature), DFUNC(displayTemperature)] call CBA_fnc_addEventHandler;
90+
8191
// Install event handler to initiate an assisted barrel swap
8292
[QGVAR(initiateSwapBarrelAssisted), DFUNC(swapBarrel)] call CBA_fnc_addEventHandler;
8393

@@ -107,5 +117,4 @@ if (hasInterface) then {
107117
[]
108118
] call CBA_fnc_waitUntilAndExecute;
109119
};
110-
111120
}] call CBA_fnc_addEventHandler;

addons/overheating/functions/fnc_calculateCooling.sqf

+8-5
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,12 @@
1919

2020
params ["_temperature", "_barrelMass", "_totalTime"];
2121

22-
if (_temperature < 1) exitWith {0};
22+
// The lowest temperature a weapon can reach is the ambient air temperature.
23+
private _ambientTemperature = ambientTemperature select 0;
24+
2325
// If a long time passed since the last shot, there's no need to calculate anything; the weapon should be cool
24-
if (_totalTime > 1800) exitWith {0};
26+
if (_totalTime > 1800) exitWith {_ambientTemperature};
27+
if (_temperature <= _ambientTemperature) exitWith {_ambientTemperature};
2528

2629
//AR-15 (0.00570m bullet diameter) (barrel diameter usually 0.75" or 0.008255m radius)
2730
//Steel Denisty = 7850 m^3 / kg
@@ -51,15 +54,15 @@ while {true} do {
5154
_convectionRate * _barrelSurface * _temperature
5255
// Radiative cooling
5356
+ 0.4 * 5.67e-8 * _barrelSurface * ((_temperature + 273.15) ^ 4 - 273.15 ^ 4)
54-
) * _deltaTime / (_barrelMass * 466);
57+
) * GVAR(coolingCoef) * _deltaTime / (_barrelMass * 466);
5558

56-
if (_temperature < 1) exitWith {0};
59+
if (_temperature <= _ambientTemperature) exitWith {_ambientTemperature};
5760

5861
if (isNil "_temperature") exitWith {
5962
diag_log text format ["[ACE] ERROR: _totalTime = %1; _time = %2; _deltaTime = %3;", _totalTime, _time, _deltaTime];
6063
0
6164
};
6265

6366
_time = _time + _deltaTime;
64-
if (_time >= _totalTime) exitWith { _temperature max 0 };
67+
if (_time >= _totalTime) exitWith {_temperature max _ambientTemperature};
6568
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
#include "script_component.hpp"
2+
/*
3+
* Author: drofseh
4+
* Return true if the target's weapon can be cooled with an item in the player's inventory
5+
*
6+
* Arguments:
7+
* 0: Target <OBJECT>
8+
* 1: Player <OBJECT>
9+
*
10+
* Return Value:
11+
* Bool <BOOL>
12+
*
13+
* Example:
14+
* [cursorObject, player] call ace_overheating_fnc_canCoolWeaponWithItem
15+
*
16+
* Public: No
17+
*/
18+
19+
params ["_unit", "_player"];
20+
TRACE_2("canCoolWeaponWithItem",_unit,_player);
21+
22+
GVAR(enabled)
23+
&& {isClass (configfile >> "CfgPatches" >> "acex_field_rations")}
24+
&& {!(_unit getVariable [QEGVAR(captives,isSurrendering), false])} // interaction point will overlap with ace_captives
25+
&& {!(_unit getVariable [QEGVAR(captives,isHandcuffed), false])}
26+
&& {[_unit, currentWeapon _unit] call FUNC(getWeaponTemperature) > (ambientTemperature select 0)}
27+
&& {((_player call EFUNC(common,uniqueItems)) findIf {getNumber (configFile >> "CfgWeapons" >> _x >> QEXGVAR(field_rations,thirstQuenched)) > 0}) != -1}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
#include "script_component.hpp"
2+
/*
3+
* Author: drofseh
4+
* Cookoff loaded round.
5+
*
6+
* Arguments:
7+
* 0: Unit <OBJECT>
8+
* 1: Weapon <STRING>
9+
* 2: Is Weapon Jammed <BOOL>
10+
* 3: Type of Jam <STRING>
11+
*
12+
* Return Value:
13+
* None
14+
*
15+
* Example:
16+
* [player, currentWeapon player, true, "Fire"] call ace_overheating_fnc_cookoffWeapon
17+
*
18+
* Public: No
19+
*/
20+
21+
params ["_unit", "_weapon", "_canUnjam", "_jamType"];
22+
TRACE_4("params",_unit,_weapon,_canUnjam,_jamType);
23+
24+
// a weapon with a failure to fire or dud type jam will be unjammed from cooking off
25+
// this is first so that the fired event from the cookoff can also cause a jam
26+
if (_canUnjam && {_jamType in ["Fire","Dud"]}) then {
27+
[_unit, currentMuzzle _unit, true] call FUNC(clearJam);
28+
29+
// clearJam will remove a dud round, but so will the forced fire, so give back the lost round and shoot it
30+
if (_jamType isEqualTo "Dud") then {
31+
_unit setAmmo [_weapon, (_unit ammo _weapon) + 1];
32+
};
33+
};
34+
35+
// get valid mode and muzzle for the main weapon, we don't want the cookoff to come from an underbarrel launcher
36+
([_weapon] call FUNC(getWeaponData)) params ["", "", "", "_modes", "_muzzle", "_reloadTime"];
37+
38+
// get an appropriate firemode and muzzle, cache the current muzzle
39+
// trying to match firemodes and switching back to the cached muzzle will hide the change from the player and prevent unexpected mode/muzzle changes (going from full auto to semi auto, or from underbarrel GL to rifle for example)
40+
private _muzzleCache = currentMuzzle _unit;
41+
private _mode = currentWeaponMode _unit;
42+
if !(_mode in _modes) then {
43+
_mode = _modes select 0;
44+
};
45+
46+
// delay cookoff to ensure any previous animation from a fired event is finished
47+
[
48+
{
49+
params ["_unit", "_mode", "_muzzle", "_muzzleCache"];
50+
51+
// fire the cookoff
52+
_unit forceWeaponFire [_muzzle, _mode];
53+
54+
// switch back to the cached muzzle if required
55+
if (_muzzle != _muzzleCache) then {
56+
_unit selectWeapon _muzzleCache;
57+
};
58+
59+
[
60+
[localize LSTRING(WeaponCookedOff)],
61+
true // allows the hint to be overwritten by another hint, such as a jam or another cookoff
62+
] call CBA_fnc_notify;
63+
},
64+
[_unit, _mode, _muzzle, _muzzleCache],
65+
_reloadTime
66+
] call CBA_fnc_waitAndExecute;

addons/overheating/functions/fnc_coolWeaponWithItem.sqf

+1-1
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ private _fnc_onSuccess = {
6161
};
6262

6363
// cool the weapon
64-
private _barrelMass = _weapon call FUNC(getBarrelMass);
64+
([_weapon] call FUNC(getWeaponData)) params ["", "", "", "", "", "", "", "_barrelMass"];
6565
_temperature = [_temperature, _barrelMass, _liquidAmount * 10] call FUNC(calculateCooling);
6666
[_target, _tempVarName, _temperature, TEMP_TOLERANCE] call EFUNC(common,setApproximateVariablePublic);
6767
};

addons/overheating/functions/fnc_coolWeaponWithWaterSource.sqf

+1-1
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ private _fnc_condition = {
5959
};
6060

6161
//Cool the weapon down
62-
private _barrelMass = _weapon call FUNC(getBarrelMass);
62+
([_weapon] call FUNC(getWeaponData)) params ["", "", "", "", "", "", "", "_barrelMass"];
6363
_temperature = [_temperature, _barrelMass, 20] call FUNC(calculateCooling);
6464
[_player, _tempVarName, _temperature, TEMP_TOLERANCE] call EFUNC(common,setApproximateVariablePublic);
6565

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
#include "script_component.hpp"
2+
/*
3+
* Author: drofseh
4+
* Get current temperature of weapon's ammo.
5+
*
6+
* Arguments:
7+
* 0: Unit <OBJECT>
8+
* 1: Weapon <STRING>
9+
*
10+
* Return Value:
11+
* Current ammunition temperature <NUMBER>
12+
*
13+
* Example:
14+
* [player, currentWeapon player] call ace_overheating_fnc_getAmmoTemperature
15+
*
16+
* Public: Yes
17+
*/
18+
19+
params ["_unit", "_weapon"];
20+
21+
private _ammoTempVarName = format [QGVAR(%1_ammoTemp), _weapon];
22+
23+
_unit getVariable [_ammoTempVarName, ambientTemperature select 0]

addons/overheating/functions/fnc_getBarrelMass.sqf

+3-1
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,6 @@
1717

1818
params ["_weapon"];
1919

20-
METAL_MASS_RATIO * (getNumber (configFile >> "CfgWeapons" >> _weapon >> "WeaponSlotsInfo" >> "mass") / 22.0) max 1.0;
20+
([_weapon] call FUNC(getWeaponData)) params ["", "", "", "", "", "", "", "_barrelMass"];
21+
22+
_barrelMass

addons/overheating/functions/fnc_getWeaponData.sqf

+14-4
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,14 @@
77
* 0: weapon type <STRING>
88
*
99
* Return Value:
10-
* 0: dispresion <NUMBER>
10+
* 0: dispersion <NUMBER>
1111
* 1: slowdownFactor <NUMBER>
1212
* 2: jamChance <NUMBER>
13+
* 3: modes <ARRAY>
14+
* 4: muzzle <STRING>
15+
* 5: reloadTime <NUMBER>
16+
* 6: closedBolt <NUMBER>
17+
* 7: barrelMass <NUMBER>
1318
*
1419
* Example:
1520
* ["gun"] call ace_overheating_fnc_getWeaponData
@@ -20,7 +25,7 @@
2025
params ["_weapon"];
2126

2227
// Look in the cache first
23-
private _weaponData = GVAR(cacheWeaponData) getVariable _weapon;
28+
private _weaponData = GVAR(cacheWeaponData) get _weapon;
2429
if (!isNil "_weaponData") exitWith {_weaponData};
2530

2631
// Search the config
@@ -71,11 +76,16 @@ private _muzzle = getArray (configFile >> "CfgWeapons" >> _weapon >> "muzzles")
7176
if (_muzzle == "this") then {
7277
_muzzle = _weapon;
7378
};
79+
7480
private _reloadTime = getNumber (configfile >> "CfgWeapons" >> _weapon >> (_modes select 0) >> "reloadTime");
7581

82+
private _closedBolt = getNumber (configFile >> "CfgWeapons" >> _weapon >> QGVAR(closedBolt));
83+
84+
private _barrelMass = METAL_MASS_RATIO * (getNumber (configFile >> "CfgWeapons" >> _weapon >> "WeaponSlotsInfo" >> "mass") / 22.0) max 1.0;
85+
7686
// Cache the values
77-
_weaponData = [_dispersion, _slowdownFactor, _jamChance, _modes, _muzzle, _reloadTime];
87+
_weaponData = [_dispersion, _slowdownFactor, _jamChance, _modes, _muzzle, _reloadTime, _closedBolt, _barrelMass];
7888
TRACE_2("building cache",_weapon,_weaponData);
79-
GVAR(cacheWeaponData) setVariable [_weapon, _weaponData];
89+
GVAR(cacheWeaponData) set [_weapon, _weaponData];
8090

8191
_weaponData
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
#include "script_component.hpp"
2+
/*
3+
* Author: drofseh
4+
* Get current temperature of weapon.
5+
*
6+
* Arguments:
7+
* 0: Unit <OBJECT>
8+
* 1: Weapon <STRING>
9+
*
10+
* Return Value:
11+
* Current ammunition temperature <NUMBER>
12+
*
13+
* Example:
14+
* [player, currentWeapon player] call ace_overheating_fnc_getWeaponTemperature
15+
*
16+
* Public: Yes
17+
*/
18+
19+
params ["_unit", "_weapon"];
20+
21+
private _weaponTempVarName = format [QGVAR(%1_temp), _weapon];
22+
23+
_unit getVariable [_weaponTempVarName, ambientTemperature select 0];

addons/overheating/functions/fnc_jamWeapon.sqf

+4-2
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,9 @@ if (_jamTypesAllowed isEqualTo []) then {
5151
};
5252
};
5353

54-
_unit setVariable [format [QGVAR(%1_jamType), _weapon], selectRandomWeighted _jamTypesAllowed];
54+
private _jamType = selectRandomWeighted _jamTypesAllowed;
55+
_unit setVariable [format [QGVAR(%1_jamType), _weapon], _jamType];
56+
5557

5658
// Stop current burst
5759
_unit setAmmo [_weapon, 0];
@@ -72,7 +74,7 @@ if (_weapon == primaryWeapon _unit) then {
7274
// only display the hint once, after you try to shoot an already jammed weapon
7375
GVAR(knowAboutJam) = false;
7476

75-
["ace_weaponJammed", [_unit,_weapon]] call CBA_fnc_localEvent;
77+
["ace_weaponJammed", [_unit, _weapon, _jamType]] call CBA_fnc_localEvent;
7678

7779
if (_unit getVariable [QGVAR(JammingActionID), -1] == -1) then {
7880

addons/overheating/functions/fnc_overheat.sqf

+12-13
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,9 @@ TRACE_4("params",_unit,_weapon,_ammo,_projectile);
2626
BEGIN_COUNTER(overheat);
2727

2828
// Get bullet parameters
29-
private _energyIncrement = GVAR(cacheAmmoData) getVariable _ammo;
29+
private _energyIncrement = GVAR(cacheAmmoData) get _ammo;
3030
if (isNil "_energyIncrement") then {
31-
_bulletMass = getNumber (configFile >> "CfgAmmo" >> _ammo >> "ACE_BulletMass");
31+
private _bulletMass = getNumber (configFile >> "CfgAmmo" >> _ammo >> "ACE_BulletMass");
3232
if (_bulletMass == 0) then {
3333
// If the bullet mass is not configured, estimate it
3434
_bulletMass = 3.4334 + 0.5171 * (getNumber (configFile >> "CfgAmmo" >> _ammo >> "hit") + getNumber (configFile >> "CfgAmmo" >> _ammo >> "caliber"));
@@ -38,28 +38,27 @@ if (isNil "_energyIncrement") then {
3838
// Ref: https://en.wikipedia.org/wiki/Physics_of_firearms
3939
// Muzzle Engergy = 1/2 * m * v^2 = (1/2 * 0.001 g/kg * bulletMass (grams) * v^2)
4040
// Multiple by 3 becase we only calc every 3rd bullet: (3 * 1/2 * 0.001) = 0.0015
41-
_energyIncrement = 0.0015 * _bulletMass * (vectorMagnitudeSqr velocity _projectile);
41+
_energyIncrement = GVAR(heatCoef) * 0.0015 * _bulletMass * (vectorMagnitudeSqr velocity _projectile);
4242

43-
GVAR(cacheAmmoData) setVariable [_ammo, _energyIncrement];
43+
GVAR(cacheAmmoData) set [_ammo, _energyIncrement];
4444
};
4545

4646
// Increase overheating depending on how obstrusive is the current supressor,
4747
// if any. Typical arma supressors have visibleFire=0.5 and audibleFire=0.3,
4848
// so they produce x2.1 overheating
49-
private _silencer = switch (_weapon) do {
49+
private _suppressor = switch (_weapon) do {
5050
case (primaryWeapon _unit) : {(primaryWeaponItems _unit) select 0};
5151
case (handgunWeapon _unit) : {(handgunItems _unit) select 0};
5252
default {""};
5353
};
54-
if (_silencer != "") then {
55-
private _silencerCoef = GVAR(cacheSilencerData) getVariable _silencer;
56-
if (isNil "_silencerCoef") then {
57-
_silencerCoef = 1 +
58-
(1 - getNumber (configFile >> "CfgWeapons" >> _silencer >> "ItemInfo" >> "AmmoCoef" >> "audibleFire")) +
59-
(1 - getNumber (configFile >> "CfgWeapons" >> _silencer >> "ItemInfo" >> "AmmoCoef" >> "visibleFire"));
60-
GVAR(cacheSilencerData) setVariable [_silencer, _silencerCoef];
54+
if (_suppressor != "" && {GVAR(suppressorCoef) > 0}) then {
55+
private _suppressorCoef = GVAR(cacheSilencerData) get _suppressor;
56+
if (isNil "_suppressorCoef") then {
57+
private _config = configFile >> "CfgWeapons" >> _suppressor >> "ItemInfo" >> "AmmoCoef";
58+
_suppressorCoef = GVAR(suppressorCoef) * (1 + (1 - getNumber (_config >> "audibleFire")) + (1 - getNumber (_config >> "visibleFire")));
59+
GVAR(cacheSilencerData) set [_suppressor, _suppressorCoef];
6160
};
62-
_energyIncrement = _energyIncrement * _silencerCoef;
61+
_energyIncrement = _energyIncrement * _suppressorCoef;
6362
};
6463

6564
TRACE_1("heat",_energyIncrement);

0 commit comments

Comments
 (0)