mirror of
https://github.com/acemod/ACE3.git
synced 2024-08-30 18:23:18 +00:00
Overheating - Add cook off and rate of fire features and additional customization settings (#8064)
* Add jamming coef to change or disable jamming. * change max to 5 * add setting for overheating effects distance, unjaming on barrel swap, increase rate of fire with heat - add setting for overheating effects distance - add unjaming on barrel swap, with setting - add increase rate of fire with heat, with setting - fix some formatting * little tweaks * add overheating cookoff feature - add overheating cookoff feature - add documentation - bugfixes/improvements * Update ace3-config-entries.md * Update overheating-framework.md * Update addons/overheating/XEH_postInit.sqf Co-authored-by: jonpas <jonpas33@gmail.com> * Update addons/overheating/XEH_postInit.sqf Co-authored-by: jonpas <jonpas33@gmail.com> * Update addons/overheating/functions/fnc_firedEH.sqf Co-authored-by: jonpas <jonpas33@gmail.com> * Update addons/overheating/stringtable.xml Co-authored-by: jonpas <jonpas33@gmail.com> * Update docs/wiki/feature/overheating.md Co-authored-by: jonpas <jonpas33@gmail.com> * Update addons/overheating/stringtable.xml Co-authored-by: jonpas <jonpas33@gmail.com> * Update addons/overheating/functions/fnc_jamWeapon.sqf Co-authored-by: jonpas <jonpas33@gmail.com> * Update addons/overheating/functions/fnc_jamWeapon.sqf Co-authored-by: jonpas <jonpas33@gmail.com> * remove extra underwater cooling, make cookoffCoef enable cookoff - add coef setting for heat generation per shot - merge cookoff setting into cookoff coef setting - remove check for water that increased cooling - change max rof increase from heat to 10% - change ammo heating to a less linear formula - change cookoffCoef to effect inginition tempurature instead of heat amount - delay cookoff shot until any firing animation is done - update strings based on feedback * Update stringtable.xml * add cookoff notification * improvements from play testing - move ammo heat loop into seperate function with a tighter loop - factor rain into cooling calculation - handle cooling while swimming - merge cookoff take event handler into fnc_handleTakeEH - fix case where cookoff could potentially come from underbarrel weapon muzzle - only add TakeEH if required by enabled settings - improve cookoff muzzle/mode handling * fix missing semi that I swear I already fixed before pushing * Update overheating-framework.md * Update fnc_updateAmmoTemperature.sqf * include wind speed in cooling calculation * cool with X - add ace interactions to allow cooling with water sources when Ace X is loaded - add documentation for cooling - move getting barrel mass to a function * documentation formatting * Add config array for weapon jam types, as not all weapon can get all types IRL. * remove variable that's not required * add some compat entries for RHS * fix merge conflict * fix a happy little accident * move to CBA settings, minor styling. * Update error message in fnc_jamWeapon.sqf Co-authored-by: jonpas <jonpas33@gmail.com> * Apply suggestions from code review Co-authored-by: TyroneMF <TyroneMF@hotmail.com> Co-authored-by: jonpas <jonpas33@gmail.com> Co-authored-by: TyroneMF <TyroneMF@hotmail.com>
This commit is contained in:
parent
b06d6fc0f8
commit
f83c605958
@ -2,6 +2,9 @@ class ACE_Settings {
|
||||
class GVAR(enabled) {
|
||||
movedToSQF = 1;
|
||||
};
|
||||
class GVAR(heatCoef) {
|
||||
movedToSQF = 1;
|
||||
};
|
||||
class GVAR(showParticleEffects) {
|
||||
movedToSQF = 1;
|
||||
};
|
||||
@ -11,13 +14,28 @@ class ACE_Settings {
|
||||
class GVAR(overheatingDispersion) {
|
||||
movedToSQF = 1;
|
||||
};
|
||||
class GVAR(particleEffectsAndDispersionDistance) {
|
||||
movedToSQF = 1;
|
||||
};
|
||||
class GVAR(overheatingRateOfFire) {
|
||||
movedToSQF = 1;
|
||||
};
|
||||
class GVAR(displayTextOnJam) {
|
||||
movedToSQF = 1;
|
||||
};
|
||||
class GVAR(unJamOnreload) {
|
||||
class GVAR(jamChanceCoef) {
|
||||
movedToSQF = 1;
|
||||
};
|
||||
class GVAR(unJamOnReload) {
|
||||
movedToSQF = 1;
|
||||
};
|
||||
class GVAR(unJamOnSwapBarrel) {
|
||||
movedToSQF = 1;
|
||||
};
|
||||
class GVAR(unJamFailChance) {
|
||||
movedToSQF = 1;
|
||||
};
|
||||
class GVAR(cookoffCoef) {
|
||||
movedToSQF = 1;
|
||||
};
|
||||
};
|
||||
|
@ -23,4 +23,26 @@ class CfgSounds {
|
||||
sound[]={QPATHTOF(sounds\fixing_pistol.wav),1,1};
|
||||
titles[]={};
|
||||
};
|
||||
/* // to be added when licence compatible audio can be found or recorded
|
||||
class GVAR(pouring_long) {
|
||||
name= QGVAR(pouring_long);
|
||||
sound[]={QPATHTOF(sounds\pouring_long.ogg),5,1};
|
||||
titles[]={};
|
||||
};
|
||||
class GVAR(pouring_short) {
|
||||
name= QGVAR(pouring_short);
|
||||
sound[]={QPATHTOF(sounds\pouring_short.ogg),5,1};
|
||||
titles[]={};
|
||||
};
|
||||
class GVAR(sizzling_long) {
|
||||
name= QGVAR(sizzling_long);
|
||||
sound[]={QPATHTOF(sounds\sizzling_long.ogg),5,1};
|
||||
titles[]={};
|
||||
};
|
||||
class GVAR(sizzling_short) {
|
||||
name= QGVAR(sizzling_short);
|
||||
sound[]={QPATHTOF(sounds\sizzling_short.ogg),5,1};
|
||||
titles[]={};
|
||||
};
|
||||
*/
|
||||
};
|
||||
|
@ -36,6 +36,15 @@ class CfgVehicles {
|
||||
showDisabled = 0;
|
||||
icon = QUOTE(PATHTOF(UI\temp_ca.paa));
|
||||
};
|
||||
class GVAR(CoolWeaponWithItem) {
|
||||
displayName = CSTRING(CoolWeaponWithItem);
|
||||
condition = QUOTE(GVAR(enabled) && {isClass(configfile >> 'CfgPatches' >> 'acex_field_rations')});
|
||||
exceptions[] = {"isNotInside", "isNotSwimming", "isNotSitting"};
|
||||
statement = "true";
|
||||
showDisabled = 0;
|
||||
insertChildren = QUOTE(_player call FUNC(getConsumableChildren));
|
||||
icon = QPATHTOF(UI\pour_water_ca.paa);
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
@ -55,6 +64,15 @@ class CfgVehicles {
|
||||
statement = QUOTE( [ARR_3(_player, _target, currentWeapon _target)] call FUNC(checkTemperature); );
|
||||
icon = QUOTE(PATHTOF(UI\temp_ca.paa));
|
||||
};
|
||||
class GVAR(CoolWeaponWithItem) {
|
||||
displayName = CSTRING(CoolWeaponWithItem);
|
||||
condition = QUOTE(GVAR(enabled) && {isClass(configfile >> 'CfgPatches' >> 'acex_field_rations')});
|
||||
exceptions[] = {"isNotInside", "isNotSwimming", "isNotSitting"};
|
||||
statement = "true";
|
||||
showDisabled = 0;
|
||||
insertChildren = QUOTE(_player call FUNC(getConsumableChildren));
|
||||
icon = QPATHTOF(UI\pour_water_ca.paa);
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
@ -1,4 +1,19 @@
|
||||
class CfgWeapons {
|
||||
class PistolCore;
|
||||
class Pistol : PistolCore {
|
||||
//Closed Bolt (Closed Bolt will cook off if too hot)
|
||||
//Pistols are nearly universally closed bolt.
|
||||
GVAR(closedBolt) = 1;
|
||||
};
|
||||
|
||||
class Pistol_Base_F : Pistol {};
|
||||
class hgun_Pistol_heavy_02_F : Pistol_Base_F {
|
||||
GVAR(jamTypesAllowed) = ["Fire","Dud"];
|
||||
};
|
||||
class hgun_Pistol_Signal_F : Pistol_Base_F {
|
||||
GVAR(jamTypesAllowed) = ["Fire","Dud"];
|
||||
};
|
||||
|
||||
class RifleCore;
|
||||
class Rifle: RifleCore {
|
||||
//Mean Rounds Between Stoppages (this will be scaled based on the barrel temp)
|
||||
@ -9,10 +24,17 @@ class CfgWeapons {
|
||||
|
||||
//Slowdown Factor (this will be scaled based on the barrel temp)
|
||||
GVAR(slowdownFactor) = 1;
|
||||
|
||||
//Closed Bolt, most weapons are closed bolt
|
||||
GVAR(closedBolt) = 1;
|
||||
};
|
||||
class Rifle_Base_F;
|
||||
class Rifle_Long_Base_F: Rifle_Base_F {
|
||||
GVAR(dispersion) = 0.75;
|
||||
|
||||
// Open Bolt, most machine guns are open bolt, which cannot normally cook off, and use this as a parent class
|
||||
// A lot of sniper rifles also use this as a parent class, they will need to be indivisually set to closed bolt, but it's probably not an issue as they are unlikely to overheat
|
||||
GVAR(closedBolt) = 0;
|
||||
};
|
||||
|
||||
class arifle_MX_Base_F: Rifle_Base_F {
|
||||
@ -26,6 +48,36 @@ class CfgWeapons {
|
||||
GVAR(allowSwapBarrel) = 1;
|
||||
GVAR(dispersion) = 0.75;
|
||||
};
|
||||
class DMR_01_base_F : Rifle_Long_Base_F {
|
||||
GVAR(closedBolt) = 1;
|
||||
};
|
||||
class DMR_02_base_F : Rifle_Long_Base_F {
|
||||
GVAR(closedBolt) = 1;
|
||||
};
|
||||
class DMR_03_base_F : Rifle_Long_Base_F {
|
||||
GVAR(closedBolt) = 1;
|
||||
};
|
||||
class DMR_04_base_F : Rifle_Long_Base_F {
|
||||
GVAR(closedBolt) = 1;
|
||||
};
|
||||
class DMR_05_base_F : Rifle_Long_Base_F {
|
||||
GVAR(closedBolt) = 1;
|
||||
};
|
||||
class DMR_06_base_F : Rifle_Long_Base_F {
|
||||
GVAR(closedBolt) = 1;
|
||||
};
|
||||
class DMR_07_base_F : Rifle_Long_Base_F {
|
||||
GVAR(closedBolt) = 1;
|
||||
};
|
||||
class EBR_base_F : Rifle_Long_Base_F {
|
||||
GVAR(closedBolt) = 1;
|
||||
};
|
||||
class GM6_base_F : Rifle_Long_Base_F {
|
||||
GVAR(closedBolt) = 1;
|
||||
};
|
||||
class LRR_base_F : Rifle_Long_Base_F {
|
||||
GVAR(closedBolt) = 1;
|
||||
};
|
||||
class MMG_01_base_F: Rifle_Long_Base_F {
|
||||
GVAR(allowSwapBarrel) = 1;
|
||||
};
|
||||
@ -41,6 +93,10 @@ class CfgWeapons {
|
||||
class LMG_03_Base_F: Rifle_Long_Base_F {
|
||||
GVAR(allowSwapBarrel) = 1;
|
||||
};
|
||||
class sgun_HunterShotgun_01_base_F : Rifle_Long_Base_F {
|
||||
GVAR(closedBolt) = 1;
|
||||
GVAR(jamTypesAllowed) = ["Fire","Dud"];
|
||||
};
|
||||
class ACE_ItemCore;
|
||||
class CBA_MiscItem_ItemInfo;
|
||||
class ACE_SpareBarrel_Item: ACE_ItemCore {
|
||||
|
BIN
addons/overheating/UI/pour_water_ca.paa
Normal file
BIN
addons/overheating/UI/pour_water_ca.paa
Normal file
Binary file not shown.
@ -6,8 +6,12 @@ PREP(canCheckSpareBarrelsTemperatures);
|
||||
PREP(checkSpareBarrelsTemperatures);
|
||||
PREP(checkTemperature);
|
||||
PREP(clearJam);
|
||||
PREP(coolWeaponWithItem);
|
||||
PREP(coolWeaponWithWaterSource);
|
||||
PREP(displayTemperature);
|
||||
PREP(firedEH);
|
||||
PREP(getBarrelMass);
|
||||
PREP(getConsumableChildren);
|
||||
PREP(getWeaponData);
|
||||
PREP(handleTakeEH);
|
||||
PREP(handleRespawn);
|
||||
@ -18,6 +22,8 @@ PREP(sendSpareBarrelsTemperaturesHint);
|
||||
PREP(swapBarrel);
|
||||
PREP(swapBarrelAssistant);
|
||||
PREP(swapBarrelCallback);
|
||||
PREP(updateAmmoTemperature);
|
||||
PREP(updateAmmoTemperatureThread);
|
||||
PREP(updateSpareBarrelsTemperaturesThread);
|
||||
PREP(updateTemperature);
|
||||
PREP(updateTemperatureThread);
|
||||
|
@ -48,22 +48,64 @@ if (hasInterface) then {
|
||||
GVAR(cacheAmmoData) = call CBA_fnc_createNamespace;
|
||||
GVAR(cacheSilencerData) = call CBA_fnc_createNamespace;
|
||||
|
||||
//Add Take EH (for reload)
|
||||
["CAManBase", "Take", {_this call FUNC(handleTakeEH);}] call CBA_fnc_addClassEventHandler;
|
||||
//Add Take EH if required
|
||||
if (GVAR(unJamOnReload) || {GVAR(cookoffCoef) > 0}) then {
|
||||
["CAManBase", "Take", {_this call FUNC(handleTakeEH);}] call CBA_fnc_addClassEventHandler;
|
||||
};
|
||||
|
||||
// Register fire event handler
|
||||
["ace_firedPlayer", DFUNC(firedEH)] call CBA_fnc_addEventHandler;
|
||||
// Only add eh to non local players if dispersion is enabled
|
||||
if (GVAR(overheatingDispersion)) then {
|
||||
if (GVAR(overheatingDispersion) || {GVAR(showParticleEffectsForEveryone)}) then {
|
||||
["ace_firedPlayerNonLocal", DFUNC(firedEH)] call CBA_fnc_addEventHandler;
|
||||
};
|
||||
|
||||
// Schedule cool down calculation of player weapons at (infrequent) regular intervals
|
||||
[] call FUNC(updateTemperatureThread);
|
||||
|
||||
//Add event handlers and start ammo heating loop for cookoff
|
||||
if (GVAR(cookoffCoef) > 0) then {
|
||||
[] call FUNC(updateAmmoTemperatureThread);
|
||||
|
||||
// Reset ammo temperature on reload, unless the reload is a second muzzle.
|
||||
["CAManBase", "Reloaded", {
|
||||
params ["_unit", "_weapon", "_muzzle"];
|
||||
if (_muzzle == _weapon) then {
|
||||
_unit setVariable [format [QGVAR(%1_ammoTemp), _weapon], 0];
|
||||
};
|
||||
}] call CBA_fnc_addClassEventHandler;
|
||||
};
|
||||
|
||||
// Install event handler to display temp when a barrel was swapped
|
||||
[QGVAR(showWeaponTemperature), DFUNC(displayTemperature)] call CBA_fnc_addEventHandler;
|
||||
// Install event handler to initiate an assisted barrel swap
|
||||
[QGVAR(initiateSwapBarrelAssisted), DFUNC(swapBarrel)] call CBA_fnc_addEventHandler;
|
||||
|
||||
// Add an action to allow hot weapons to be cooled off in AceX Field Rations water sources
|
||||
if (isClass(configfile >> "CfgPatches" >> "acex_field_rations")) then {
|
||||
[
|
||||
{acex_field_rations_enabled || CBA_missionTime > 1},
|
||||
{
|
||||
if (!acex_field_rations_enabled) exitWith {};
|
||||
|
||||
_CoolWeaponWithWaterSourceAction = [
|
||||
QGVAR(CoolWeaponWithWaterSource),
|
||||
LLSTRING(CoolWeaponWithWaterSource),
|
||||
"\z\acex\addons\field_rations\ui\icon_water_tap.paa",
|
||||
{
|
||||
private _waterSource = _target getVariable ["acex_field_rations_waterSource", objNull];
|
||||
[_player, _waterSource] call FUNC(coolWeaponWithWaterSource);
|
||||
},
|
||||
{
|
||||
private _waterSource = _target getVariable ["acex_field_rations_waterSource", objNull];
|
||||
[_player, _waterSource] call acex_field_rations_fnc_canDrinkFromSource;
|
||||
}
|
||||
] call EFUNC(interact_menu,createAction);
|
||||
|
||||
["acex_field_rations_helper", 0, ["acex_field_rations_waterSource"], _CoolWeaponWithWaterSourceAction] call EFUNC(interact_menu,addActionToClass);
|
||||
},
|
||||
[]
|
||||
] call CBA_fnc_waitUntilAndExecute;
|
||||
};
|
||||
|
||||
}] call CBA_fnc_addEventHandler;
|
||||
|
@ -30,6 +30,15 @@ if (_totalTime > 1800) exitWith {0};
|
||||
//So Area = 210 * 1.1 * (mass / 7850) = mass * 0.029427 (for steel near that diameter)
|
||||
|
||||
private _barrelSurface = _barrelMass * 0.029427;
|
||||
private _convectionRate = 25;
|
||||
|
||||
//provide additional cooling if swimming or raining or windy
|
||||
if (ACE_player call EFUNC(common,isSwimming)) then {
|
||||
_convectionRate = 500;
|
||||
} else {
|
||||
// this will give a convection rate between 25 (no wind or rain) and 125 (max rain and >=50 m/s wind)
|
||||
_convectionRate = _convectionRate * ((linearConversion [0,1,rain,1,5,true] + (5 min (vectorMagnitude wind / 10))) / 2);
|
||||
};
|
||||
|
||||
TRACE_4("cooling",_temperature,_totalTime,_barrelMass,_barrelSurface);
|
||||
|
||||
@ -38,13 +47,10 @@ while {true} do {
|
||||
private _deltaTime = (_totalTime - _time) min 20;
|
||||
|
||||
_temperature = _temperature - (
|
||||
// Convective cooling
|
||||
25 * _barrelSurface * _temperature
|
||||
// Radiative cooling
|
||||
+ 0.4 * 5.67e-8 * _barrelSurface *
|
||||
( (_temperature + 273.15)*(_temperature + 273.15)
|
||||
* (_temperature + 273.15)*(_temperature + 273.15)
|
||||
- 273.15 * 273.15 * 273.15 *273.15 )
|
||||
// Convective cooling
|
||||
_convectionRate * _barrelSurface * _temperature
|
||||
// Radiative cooling
|
||||
+ 0.4 * 5.67e-8 * _barrelSurface * ((_temperature + 273.15) ^ 4 - 273.15 ^ 4)
|
||||
) * _deltaTime / (_barrelMass * 466);
|
||||
|
||||
if (_temperature < 1) exitWith {0};
|
||||
|
@ -20,7 +20,7 @@ params ["_player"];
|
||||
//Get the classname of the spare barrel for the weapon
|
||||
private _weaponBarrelClass = getText (configFile >> 'CfgWeapons' >> currentWeapon _player >> QGVAR(barrelClassname));
|
||||
//If the weapon has no defined classname then use the ACE one
|
||||
if(_weaponBarrelClass == "") then {
|
||||
if (_weaponBarrelClass == "") then {
|
||||
_weaponBarrelClass = "ACE_SpareBarrel";
|
||||
};
|
||||
//Check if the player has the barrel and the weapon can have its barrel swapped
|
||||
|
@ -18,12 +18,12 @@
|
||||
params ["_unit","_weapon"];
|
||||
|
||||
//Check if weapon can have its barrel swapped. If not exit out of function
|
||||
if( !GVAR(enabled) || {getNumber (configFile >> 'CfgWeapons' >> _weapon >> QGVAR(allowSwapBarrel)) != 1}) exitWith{false};
|
||||
if ( !GVAR(enabled) || {getNumber (configFile >> 'CfgWeapons' >> _weapon >> QGVAR(allowSwapBarrel)) != 1}) exitWith{false};
|
||||
|
||||
//Get the classname of the spare barrel for the weapon
|
||||
private _weaponBarrelClass = getText (configFile >> 'CfgWeapons' >> _weapon >> QGVAR(barrelClassname));
|
||||
//If the weapon has no defined classname then use the ACE one
|
||||
if(_weaponBarrelClass == "") then {
|
||||
if (_weaponBarrelClass == "") then {
|
||||
_weaponBarrelClass = "ACE_SpareBarrel";
|
||||
};
|
||||
//If the player has the spare barrel then it can be swapped
|
||||
|
@ -12,7 +12,7 @@
|
||||
* None
|
||||
*
|
||||
* Example:
|
||||
* [player, currentWeapon player] call ace_overheating_fnc_checkTemperature
|
||||
* [player, player, currentWeapon player] call ace_overheating_fnc_checkTemperature
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
|
@ -33,6 +33,7 @@ if (_weapon in _jammedWeapons) then {
|
||||
};
|
||||
|
||||
[_unit, _clearJamAction, 1] call EFUNC(common,doGesture);
|
||||
|
||||
if (_weapon == primaryWeapon _unit) then {
|
||||
playSound QGVAR(fixing_rifle);
|
||||
} else {
|
||||
@ -42,21 +43,33 @@ if (_weapon in _jammedWeapons) then {
|
||||
};
|
||||
};
|
||||
|
||||
// Check if the jam will be successfull
|
||||
// Check if the jam clearing will be successfull
|
||||
if (random 1 > GVAR(unJamFailChance)) then {
|
||||
// Success
|
||||
_jammedWeapons = _jammedWeapons - [_weapon];
|
||||
_unit setVariable [QGVAR(jammedWeapons), _jammedWeapons];
|
||||
if (_jammedWeapons isEqualTo []) then {
|
||||
private _id = _unit getVariable [QGVAR(JammingActionID), -1];
|
||||
[_unit, "DefaultAction", _id] call EFUNC(common,removeActionEventHandler);
|
||||
_unit setVariable [QGVAR(JammingActionID), -1];
|
||||
};
|
||||
if (GVAR(DisplayTextOnJam)) then {
|
||||
[{
|
||||
|
||||
[{
|
||||
params ["_unit", "_weapon", "_jammedWeapons"];
|
||||
_jammedWeapons = _jammedWeapons - [_weapon];
|
||||
_unit setVariable [QGVAR(jammedWeapons), _jammedWeapons];
|
||||
|
||||
// If the round is a dud eject the round
|
||||
if (_unit getVariable [format [QGVAR(%1_jamType), _weapon], "None"] isEqualTo "Dud") then {
|
||||
private _ammo = _unit ammo _weapon;
|
||||
_unit setAmmo [_weapon, _ammo - 1];
|
||||
};
|
||||
|
||||
_unit setVariable [format [QGVAR(%1_jamType), _weapon], "None"];
|
||||
|
||||
if (_jammedWeapons isEqualTo []) then {
|
||||
private _id = _unit getVariable [QGVAR(JammingActionID), -1];
|
||||
[_unit, "DefaultAction", _id] call EFUNC(common,removeActionEventHandler);
|
||||
_unit setVariable [QGVAR(JammingActionID), -1];
|
||||
};
|
||||
|
||||
if (GVAR(DisplayTextOnJam)) then {
|
||||
[localize LSTRING(WeaponUnjammed)] call EFUNC(common,displayTextStructured);
|
||||
}, [], _delay] call CBA_fnc_waitAndExecute;
|
||||
};
|
||||
};
|
||||
}, [_unit, _weapon, _jammedWeapons], _delay] call CBA_fnc_waitAndExecute;
|
||||
} else {
|
||||
// Failure
|
||||
if (GVAR(DisplayTextOnJam)) then {
|
||||
|
98
addons/overheating/functions/fnc_coolWeaponWithItem.sqf
Normal file
98
addons/overheating/functions/fnc_coolWeaponWithItem.sqf
Normal file
@ -0,0 +1,98 @@
|
||||
#include "script_component.hpp"
|
||||
/*
|
||||
* Author: mharis001, Glowbal, PabstMirror, drofseh
|
||||
* Cool a weapon with an item and consume the item being used to cool it.
|
||||
*
|
||||
* Arguments:
|
||||
* 0: Target <OBJECT>
|
||||
* 1: Player <OBJECT>
|
||||
* 2: Item <STRING>
|
||||
*
|
||||
* Return Value:
|
||||
* None
|
||||
*
|
||||
* Example:
|
||||
* [ACE_player, ACE_player, "ACE_WaterBottle"] call ace_overheating_fnc_coolWeaponWithItem
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
|
||||
params ["_target", "_unit", "_item"];
|
||||
|
||||
private _config = configFile >> "CfgWeapons" >> _item;
|
||||
|
||||
// Get values
|
||||
private _weapon = currentWeapon _target;
|
||||
private _tempVarName = format [QGVAR(%1_temp), _weapon];
|
||||
private _temperature = _target getVariable [_tempVarName, 0];
|
||||
private _replacementItem = getText (_config >> "acex_field_rations_replacementItem");
|
||||
private _liquidAmount = getNumber (_config >> "acex_field_rations_thirstQuenched");
|
||||
private _consumeText = format [LLSTRING(CoolingWeaponWithItem), getText (configFile >> "CfgWeapons" >> _weapon >> "displayName"), getText (_config >> "displayName")];
|
||||
|
||||
/* // to be added when licence compatible audio can be found or recorded
|
||||
private _pouringSound = QPATHTO_R(sounds\sizzling_short.ogg);
|
||||
|
||||
if (_temperature < 100) then {
|
||||
if (_liquidAmount > 5) then {
|
||||
_pouringSound = QPATHTO_R(sounds\pouring_long.ogg);
|
||||
} else {
|
||||
_pouringSound = QPATHTO_R(sounds\pouring_short.ogg);
|
||||
};
|
||||
} else {
|
||||
if (_liquidAmount > 5) then {
|
||||
_pouringSound = QPATHTO_R(sounds\sizzling_long.ogg);
|
||||
};
|
||||
};
|
||||
|
||||
playSound3D [_pouringSound, _target, false, AGLToASL (_target modelToWorld (_target selectionPosition "RightHand")), 5, 1, 10];
|
||||
*/
|
||||
|
||||
private _fnc_onSuccess = {
|
||||
params ["_args"];
|
||||
_args params ["_target", "_unit", "_item", "_weapon", "_tempVarName", "_temperature", "_replacementItem", "_liquidAmount"];
|
||||
TRACE_1("Cool weapon with item successful",_args);
|
||||
|
||||
// remove the item
|
||||
_unit removeItem _item;
|
||||
|
||||
// Add replacement item if needed
|
||||
if (_replacementItem != "") then {
|
||||
[_unit, _replacementItem] call EFUNC(common,addToInventory);
|
||||
};
|
||||
|
||||
// cool the weapon
|
||||
private _barrelMass = _weapon call FUNC(getBarrelMass);
|
||||
_temperature = [_temperature, _barrelMass, _liquidAmount * 10] call FUNC(calculateCooling);
|
||||
[_target, _tempVarName, _temperature, TEMP_TOLERANCE] call EFUNC(common,setApproximateVariablePublic);
|
||||
};
|
||||
|
||||
/*
|
||||
private _fnc_onFailure = {
|
||||
params ["_args","_elapsedTime"];
|
||||
_args params ["_target", "_unit"];
|
||||
};
|
||||
*/
|
||||
|
||||
private _fnc_condition = {
|
||||
params ["_args"];
|
||||
_args params ["", "_unit", "_item"];
|
||||
_item in (_unit call EFUNC(common,uniqueItems))
|
||||
};
|
||||
|
||||
[
|
||||
_liquidAmount,
|
||||
[
|
||||
_target,
|
||||
_unit,
|
||||
_item,
|
||||
_weapon,
|
||||
_tempVarName,
|
||||
_temperature,
|
||||
_replacementItem,
|
||||
_liquidAmount
|
||||
],
|
||||
_fnc_onSuccess,
|
||||
{}, //_fnc_onFailure,
|
||||
_consumeText,
|
||||
_fnc_condition
|
||||
] call EFUNC(common,progressBar);
|
117
addons/overheating/functions/fnc_coolWeaponWithWaterSource.sqf
Normal file
117
addons/overheating/functions/fnc_coolWeaponWithWaterSource.sqf
Normal file
@ -0,0 +1,117 @@
|
||||
#include "script_component.hpp"
|
||||
/*
|
||||
* Author: mharis001, Glowbal, PabstMirror, drofseh
|
||||
* Cool a weapon with an AceX water source.
|
||||
*
|
||||
* Arguments:
|
||||
* 0: Target <OBJECT>
|
||||
* 1: Player <OBJECT>
|
||||
*
|
||||
* Return Value:
|
||||
* None
|
||||
*
|
||||
* Example:
|
||||
* [ACE_player, WaterTank] call ace_overheating_fnc_coolWeaponWithWaterSource
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
|
||||
params ["_player", "_target"];
|
||||
|
||||
private _weapon = currentWeapon _player;
|
||||
private _tempVarName = format [QGVAR(%1_temp), _weapon];
|
||||
private _temperature = _player getVariable [_tempVarName, 0];
|
||||
private _consumeText = LLSTRING(CoolingWeaponWithWaterSource);
|
||||
GVAR(coolingWeaponWithWaterSource) = false;
|
||||
|
||||
private _fnc_onFinish = {
|
||||
params ["_args"];
|
||||
_args params ["_player", "_target", "_weapon", "_tempVarName"];
|
||||
|
||||
private _water = _target call acex_field_rations_fnc_getRemainingWater;
|
||||
|
||||
if (_water <= 0 && {_water != -10}) exitWith {
|
||||
[
|
||||
[LLSTRING(CoolWeaponNotEnoughWater)],
|
||||
true
|
||||
] call CBA_fnc_notify;
|
||||
};
|
||||
|
||||
[_player, _player, currentWeapon _player] call ace_overheating_fnc_checkTemperature;
|
||||
GVAR(coolingWeaponWithWaterSource) = false;
|
||||
};
|
||||
|
||||
private _fnc_condition = {
|
||||
params ["_args"];
|
||||
_args params ["_player", "_target", "_weapon", "_tempVarName"];
|
||||
|
||||
private _temperature = _player getVariable [_tempVarName, 0];
|
||||
private _water = _target call acex_field_rations_fnc_getRemainingWater;
|
||||
|
||||
if (_water <= 0 && {_water != -10}) exitWith {false};
|
||||
|
||||
if !(GVAR(coolingWeaponWithWaterSource)) then {
|
||||
GVAR(coolingWeaponWithWaterSource) = true;
|
||||
|
||||
//Remove water from the source, unless it's unlimited
|
||||
if (_water != -10) then {
|
||||
[_target, _water - 1] call acex_field_rations_fnc_setRemainingWater;
|
||||
};
|
||||
|
||||
//Cool the weapon down
|
||||
private _barrelMass = _weapon call FUNC(getBarrelMass);
|
||||
_temperature = [_temperature, _barrelMass, 20] call FUNC(calculateCooling);
|
||||
[_player, _tempVarName, _temperature, TEMP_TOLERANCE] call EFUNC(common,setApproximateVariablePublic);
|
||||
|
||||
/* // to be added when licence compatible audio can be found or recorded
|
||||
// water sound, either boiling or not
|
||||
if (_temperature < 100) then {
|
||||
[
|
||||
[LLSTRING(CoolWeaponIsCool)],
|
||||
true // allows the hint to be overwritten by another hint, such as a jam or another cookoff
|
||||
] call CBA_fnc_notify;
|
||||
|
||||
playSound3D [
|
||||
QPATHTO_R(sounds\pouring_short.ogg),
|
||||
_player,
|
||||
false,
|
||||
AGLToASL (_player modelToWorld (_player selectionPosition "RightHand")),
|
||||
5, 1, 10
|
||||
];
|
||||
} else {
|
||||
playSound3D [
|
||||
QPATHTO_R(sounds\sizzling_short.ogg),
|
||||
_player,
|
||||
false,
|
||||
AGLToASL (_player modelToWorld (_player selectionPosition "RightHand")),
|
||||
5, 1, 10
|
||||
];
|
||||
};
|
||||
*/
|
||||
|
||||
// wait 1 second before allowing cooling to happen again
|
||||
[
|
||||
{
|
||||
GVAR(coolingWeaponWithWaterSource) = false;
|
||||
},
|
||||
[],
|
||||
1
|
||||
] call CBA_fnc_waitAndExecute;
|
||||
};
|
||||
|
||||
true
|
||||
};
|
||||
|
||||
[
|
||||
1 max (_temperature / 10),
|
||||
[
|
||||
_player,
|
||||
_target,
|
||||
_weapon,
|
||||
_tempVarName
|
||||
],
|
||||
_fnc_onFinish,
|
||||
_fnc_onFinish,
|
||||
_consumeText,
|
||||
_fnc_condition
|
||||
] call EFUNC(common,progressBar);
|
@ -20,7 +20,7 @@ TRACE_10("firedEH:",_unit, _weapon, _muzzle, _mode, _ammo, _magazine, _projectil
|
||||
|
||||
BEGIN_COUNTER(firedEH);
|
||||
|
||||
if ((_unit distance ACE_player) > 3000
|
||||
if ((_unit distance ACE_player) > GVAR(particleEffectsAndDispersionDistance)
|
||||
|| {(_muzzle != (primaryWeapon _unit)) && {_muzzle != (handgunWeapon _unit)}}) exitWith { // Only rifle or pistol muzzles (ignore grenades / GLs)
|
||||
END_COUNTER(firedEH);
|
||||
};
|
||||
@ -94,9 +94,24 @@ if ((_unit ammo _weapon) % 3 == 0) then {
|
||||
_this call FUNC(overheat);
|
||||
};
|
||||
|
||||
// reset cookoff heat
|
||||
if (GVAR(cookoffCoef) > 0) then {
|
||||
_unit setVariable [format [QGVAR(%1_ammoTemp), _weapon], 0];
|
||||
[_unit, _weapon, _temperature] call FUNC(updateAmmoTemperature);
|
||||
};
|
||||
|
||||
// decrease time to next shot as heat increases, value is a coef where 1 is unchanged and 0 is instant, 0.8 is a 25% faster ROF.
|
||||
// this could be filtered by weapon type, but I think the heat gain and rate of fire on non-automatic weapons is low enough not to bother
|
||||
if (GVAR(overheatingRateOfFire)) then {
|
||||
_unit setWeaponReloadingTime [_unit, _muzzle, linearConversion [0, 0.5, _scaledTemperature, 1, 0.909, true]];
|
||||
};
|
||||
|
||||
// Don't bother with jamming if coef makes the chance 0.
|
||||
if (GVAR(jamChanceCoef) == 0) exitWith {END_COUNTER(firedEH);};
|
||||
|
||||
private _value = 5 * _scaledTemperature;
|
||||
private _array = [0.5, 1, 2, 8, 20, 150];
|
||||
_jamChance = _jamChance * linearConversion [0, 1, _value % 1, _array select floor _value, _array select ceil _value];
|
||||
_jamChance = _jamChance * GVAR(jamChanceCoef) * linearConversion [0, 1, _value % 1, _array select floor _value, _array select ceil _value];
|
||||
|
||||
TRACE_3("check for random jam",_unit,_weapon,_jamChance);
|
||||
|
||||
|
20
addons/overheating/functions/fnc_getBarrelMass.sqf
Normal file
20
addons/overheating/functions/fnc_getBarrelMass.sqf
Normal file
@ -0,0 +1,20 @@
|
||||
#include "script_component.hpp"
|
||||
/*
|
||||
* Author: mharis001, Glowbal, PabstMirror, drofseh
|
||||
* Get the mass of the weapons barrel.
|
||||
*
|
||||
* Arguments:
|
||||
* 0: Weapon <STRING>
|
||||
*
|
||||
* Return Value:
|
||||
* Barrel Mass <NUMBER>
|
||||
*
|
||||
* Example:
|
||||
* [currentWeapon ACE_player] call ace_overheating_fnc_getBarrelMass
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
|
||||
params ["_weapon"];
|
||||
|
||||
METAL_MASS_RATIO * (getNumber (configFile >> "CfgWeapons" >> _weapon >> "WeaponSlotsInfo" >> "mass") / 22.0) max 1.0;
|
41
addons/overheating/functions/fnc_getConsumableChildren.sqf
Normal file
41
addons/overheating/functions/fnc_getConsumableChildren.sqf
Normal file
@ -0,0 +1,41 @@
|
||||
#include "script_component.hpp"
|
||||
/*
|
||||
* Author: mharis001, Glowbal, PabstMirror
|
||||
* Returns children actions for consumable items in player's inventory.
|
||||
*
|
||||
* Arguments:
|
||||
* 0: Player <OBJECT>
|
||||
*
|
||||
* Return Value:
|
||||
* Actions <ARRAY>
|
||||
*
|
||||
* Example:
|
||||
* [_unit] call ace_overheating_fnc_getConsumableChildren
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
|
||||
params ["_unit"];
|
||||
|
||||
private _fnc_getActions = {
|
||||
TRACE_1("Creating overheating consumable item actions",_unit);
|
||||
|
||||
private _actions = [];
|
||||
private _cfgWeapons = configFile >> "CfgWeapons";
|
||||
|
||||
{
|
||||
private _config = _cfgWeapons >> _x;
|
||||
if (getNumber (_config >> "acex_field_rations_thirstQuenched") > 0) then {
|
||||
private _displayName = getText (_config >> "displayName");
|
||||
private _picture = getText (_config >> "picture");
|
||||
|
||||
// Exec next frame so closing interaction menu doesn't block progressBar
|
||||
private _action = [_x, _displayName, _picture, {[FUNC(coolWeaponWithItem), _this] call CBA_fnc_execNextFrame}, {true}, {}, _x] call EFUNC(interact_menu,createAction);
|
||||
_actions pushBack [_action, [], _unit];
|
||||
};
|
||||
} forEach (_unit call EFUNC(common,uniqueItems));
|
||||
|
||||
_actions
|
||||
};
|
||||
|
||||
[[], _fnc_getActions, _unit, QGVAR(overheatingConsumableActionsCache), 9999, "cba_events_loadoutEvent"] call EFUNC(common,cachedCall);
|
@ -65,8 +65,16 @@ if (isArray _property) then {
|
||||
};
|
||||
};
|
||||
|
||||
// for cookoff
|
||||
private _modes = getArray (configFile >> "CfgWeapons" >> _weapon >> "modes");
|
||||
private _muzzle = getArray (configFile >> "CfgWeapons" >> _weapon >> "muzzles") select 0;
|
||||
if (_muzzle == "this") then {
|
||||
_muzzle = _weapon;
|
||||
};
|
||||
private _reloadTime = getNumber (configfile >> "CfgWeapons" >> _weapon >> (_modes select 0) >> "reloadTime");
|
||||
|
||||
// Cache the values
|
||||
_weaponData = [_dispersion, _slowdownFactor, _jamChance];
|
||||
_weaponData = [_dispersion, _slowdownFactor, _jamChance, _modes, _muzzle, _reloadTime];
|
||||
TRACE_2("building cache",_weapon,_weaponData);
|
||||
GVAR(cacheWeaponData) setVariable [_weapon, _weaponData];
|
||||
|
||||
|
@ -18,16 +18,20 @@
|
||||
* Public: No
|
||||
*/
|
||||
|
||||
if !(GVAR(unJamOnreload)) exitWith {};
|
||||
|
||||
params ["_unit", "_container", "_item"];
|
||||
TRACE_3("params",_unit,_container,_item);
|
||||
|
||||
if ((_unit == ACE_player)
|
||||
&& {_container in [uniformContainer _unit, vestContainer _unit, backpackContainer _unit]}
|
||||
&& {_item == currentMagazine _unit}) then { //Todo: should this be any valid magazine for any jammed gun?
|
||||
&& {_container in [uniformContainer _unit, vestContainer _unit, backpackContainer _unit]}
|
||||
&& {_item == currentMagazine _unit}
|
||||
) then { //Todo: should this be any valid magazine for any jammed gun?
|
||||
|
||||
TRACE_1("clearing jam",currentWeapon _unit);
|
||||
[_unit, currentWeapon _unit, true] call FUNC(clearJam)
|
||||
if (GVAR(unJamOnReload)) then {
|
||||
TRACE_1("clearing jam",currentWeapon _unit);
|
||||
[_unit, currentWeapon _unit, true] call FUNC(clearJam);
|
||||
};
|
||||
|
||||
if (GVAR(cookoffCoef) > 0) then {
|
||||
_unit setVariable [format [QGVAR(%1_ammoTemp), currentWeapon _unit], 0];
|
||||
};
|
||||
};
|
||||
|
@ -21,24 +21,45 @@ TRACE_2("params",_unit,_weapon);
|
||||
|
||||
// don't jam a weapon with no rounds left
|
||||
private _ammo = _unit ammo _weapon;
|
||||
if (_ammo == 0) exitWith {};
|
||||
if (_ammo < 1) exitWith {};
|
||||
|
||||
private _jammedWeapons = _unit getVariable [QGVAR(jammedWeapons), []];
|
||||
_jammedWeapons pushBack _weapon;
|
||||
|
||||
_unit setVariable [QGVAR(jammedWeapons), _jammedWeapons];
|
||||
|
||||
// Get jam types, select one from available types
|
||||
// Cookoffs only happen on Fire and Dud, dud rounds are lost on jam clear.
|
||||
// Reduce chance of duds as temp increases (functionally increasing the chance of the others but with fewer commands)
|
||||
private _temp = 1 max (_unit getVariable [format [QGVAR(%1_temp), _weapon], 0]);
|
||||
private _jamTypesAllowed = getArray (configFile >> 'CfgWeapons' >> currentWeapon _player >> QGVAR(jamTypesAllowed));
|
||||
|
||||
if (_jamTypesAllowed == []) then {
|
||||
_jamTypesAllowed = ["Eject", 1, "Extract", 1, "Feed", 1, "Fire", 1, "Dud", (5 / (_temp / 5))];
|
||||
} else {
|
||||
for "_i" from count _jamTypesAllowed to 1 step -1 do {
|
||||
private _jamCurretType = _jamTypesAllowed select _i;
|
||||
if !(_jamCurretType in ["Eject", "Extract", "Feed", "Fire", "Dud"]) exitWith { // check config values and switch to default values if unusual value found
|
||||
ERROR_2("Weapon '%1' has unexpected value %2 in QQGVAR(jamTypesAllowed). Expected values are 'Eject', 'Extract', 'Feed', 'Fire', 'Dud'.",_weapon,_jamCurretType);
|
||||
_jamTypesAllowed = ["Eject", 1, "Extract", 1, "Feed", 1, "Fire", 1, "Dud", (5 / (_temp / 5))];
|
||||
};
|
||||
if (_jamCurretType == "Dud") then {
|
||||
_jamTypesAllowed insert [_i, [5 / (_temp / 5)]];
|
||||
} else {
|
||||
_jamTypesAllowed insert [_i, [1]];
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
_unit setVariable [format [QGVAR(%1_jamType), _weapon], selectRandomWeighted _jamTypesAllowed];
|
||||
|
||||
// Stop current burst
|
||||
if (_ammo > 0) then {
|
||||
_unit setAmmo [_weapon, 0];
|
||||
// this is to re-activate the 'DefaultAction', so you can jam a weapon while full auto shootin
|
||||
[{
|
||||
params ["_unit", "_weapon", "_ammo"];
|
||||
_unit setAmmo [_weapon, _ammo];
|
||||
}, [_unit, _weapon, _ammo]] call CBA_fnc_execNextFrame;
|
||||
};
|
||||
_unit setAmmo [_weapon, 0];
|
||||
// this is to re-activate the 'DefaultAction', so you can jam a weapon while full auto shooting
|
||||
[{
|
||||
params ["_unit", "_weapon", "_ammo"];
|
||||
_unit setAmmo [_weapon, _ammo];
|
||||
}, [_unit, _weapon, _ammo]] call CBA_fnc_execNextFrame;
|
||||
|
||||
if (_weapon == primaryWeapon _unit) then {
|
||||
playSound QGVAR(jamming_rifle);
|
||||
@ -53,20 +74,32 @@ GVAR(knowAboutJam) = false;
|
||||
|
||||
["ace_weaponJammed", [_unit,_weapon]] call CBA_fnc_localEvent;
|
||||
|
||||
|
||||
if (_unit getVariable [QGVAR(JammingActionID), -1] == -1) then {
|
||||
|
||||
private _condition = {
|
||||
[_this select 1] call CBA_fnc_canUseWeapon
|
||||
&& {currentMuzzle (_this select 1) in ((_this select 1) getVariable [QGVAR(jammedWeapons), []])}
|
||||
&& {!(currentMuzzle (_this select 1) in ((_this select 1) getVariable [QEGVAR(safemode,safedWeapons), []]))}
|
||||
private _unit = _this select 1;
|
||||
[_unit] call CBA_fnc_canUseWeapon
|
||||
&& {currentMuzzle _unit in (_unit getVariable [QGVAR(jammedWeapons), []])}
|
||||
&& {!(currentMuzzle _unit in (_unit getVariable [QEGVAR(safemode,safedWeapons), []]))}
|
||||
};
|
||||
|
||||
private _statement = {
|
||||
playSound3D ["a3\sounds_f\weapons\Other\dry9.wss", _this select 0, false, eyePos (_this select 0), 1, 1, 15];
|
||||
params ["_zero","_one"];
|
||||
|
||||
if (!(missionNamespace getVariable [QGVAR(knowAboutJam), false]) && {(_this select 1) ammo currentWeapon (_this select 1) > 0} && {GVAR(DisplayTextOnJam)}) then {
|
||||
[localize LSTRING(WeaponJammed)] call EFUNC(common,displayTextStructured);
|
||||
playSound3D ["a3\sounds_f\weapons\Other\dry9.wss", _zero, false, eyePos _zero, 1, 1, 15];
|
||||
|
||||
if (!(missionNamespace getVariable [QGVAR(knowAboutJam), false]) && {_one ammo currentWeapon _one > 0} && {GVAR(DisplayTextOnJam)}) then {
|
||||
private _jamType = _one getVariable [format [QGVAR(%1_jamType), currentWeapon _one], "None"];
|
||||
private _jamMessage = localize LSTRING(FailureToFire);
|
||||
switch true do {
|
||||
case (_jamType isEqualTo "Eject"): {_jamMessage = localize LSTRING(FailureToEject)};
|
||||
case (_jamType isEqualTo "Extract"): {_jamMessage = localize LSTRING(FailureToExtract)};
|
||||
case (_jamType isEqualTo "Feed"): {_jamMessage = localize LSTRING(FailureToFeed)};
|
||||
};
|
||||
[
|
||||
[localize LSTRING(WeaponJammed)],
|
||||
[_jamMessage]
|
||||
] call CBA_fnc_notify;
|
||||
GVAR(knowAboutJam) = true;
|
||||
};
|
||||
};
|
||||
|
@ -25,7 +25,7 @@ params ["_assistant", "_gunner", "_weapon", "_weaponTemp", "_barrelMass"];
|
||||
TRACE_5("loadCoolestSpareBarrel1",_assistant,_gunner,_weapon,_weaponTemp,_barrelMass);
|
||||
private _weaponBarrelClass = getText (configFile >> 'CfgWeapons' >> _weapon >> QGVAR(barrelClassname));
|
||||
//If the weapon has no defined classname then use the ACE one
|
||||
if(_weaponBarrelClass == "") then {
|
||||
if (_weaponBarrelClass == "") then {
|
||||
_weaponBarrelClass = "ACE_SpareBarrel";
|
||||
};
|
||||
// Find all spare barrel the player has
|
||||
|
@ -27,7 +27,7 @@ private _weapon = currentWeapon _player;
|
||||
//Get the classname of the spare barrel of that weapon
|
||||
private _weaponBarrelClass = getText (configFile >> 'CfgWeapons' >> _weapon >> QGVAR(barrelClassname));
|
||||
//If the weapon has no defined classname then use the ACE one
|
||||
if(_weaponBarrelClass == "") then {
|
||||
if (_weaponBarrelClass == "") then {
|
||||
_weaponBarrelClass = "ACE_SpareBarrel";
|
||||
};
|
||||
private _allBarrels = [_unit, _weaponBarrelClass] call CBA_fnc_getMagazineIndex;
|
||||
|
@ -26,11 +26,15 @@ if (_assistant isEqualTo _gunner) then {
|
||||
playSound "ACE_BarrelSwap";
|
||||
};
|
||||
|
||||
if (GVAR(unJamOnSwapBarrel) && {[_gunner] call FUNC(canUnjam)}) then {
|
||||
[_gunner, currentMuzzle _gunner, true] call FUNC(clearJam);
|
||||
};
|
||||
|
||||
// don't consume the barrel, but rotate through them.
|
||||
[localize LSTRING(SwappedBarrel), QPATHTOF(UI\spare_barrel_ca.paa)] call EFUNC(common,displayTextPicture);
|
||||
|
||||
private _temp = _gunner getVariable [format [QGVAR(%1_temp), _weapon], 0];
|
||||
private _barrelMass = METAL_MASS_RATIO * (getNumber (configFile >> "CfgWeapons" >> _weapon >> "WeaponSlotsInfo" >> "mass") / 22.0) max 1.0;
|
||||
private _barrelMass = _weapon call FUNC(getBarrelMass);
|
||||
|
||||
// Instruct the server to load the coolest spare barrel into the weapon and
|
||||
// store the removed barrel with the former weapon temperature. The server
|
||||
|
106
addons/overheating/functions/fnc_updateAmmoTemperature.sqf
Normal file
106
addons/overheating/functions/fnc_updateAmmoTemperature.sqf
Normal file
@ -0,0 +1,106 @@
|
||||
#include "script_component.hpp"
|
||||
/*
|
||||
* Author: drofseh
|
||||
* Update temperature of the round in the chamber and determine if a cookoff should occur.
|
||||
*
|
||||
* Arguments:
|
||||
* 0: Unit <OBJECT>
|
||||
* 1: Weapon <STRING>
|
||||
* 2: Barrel Temperature <STRING>
|
||||
*
|
||||
* Return Value:
|
||||
* Current ammunition temperature <NUMBER>
|
||||
*
|
||||
* Example:
|
||||
* [player, currentWeapon player, 600] call ace_overheating_fnc_updateAmmoTemperature
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
|
||||
params ["_unit", "_weapon", "_barrelTemperature"];
|
||||
TRACE_3("params",_unit,_weapon,_barrelTemperature);
|
||||
|
||||
private _closedBolt = getNumber (configFile >> "CfgWeapons" >> _weapon >> QGVAR(closedBolt));
|
||||
private _canUnjam = [_unit] call FUNC(canUnjam);
|
||||
|
||||
// Skip if no ammo in chamber
|
||||
if (
|
||||
_unit ammo _weapon < 1
|
||||
// closed bolt, and jammed and type not failure to fire
|
||||
|| {_closedBolt == 1 && {_canUnjam} && {!(_unit getVariable [format [QGVAR(%1_jamType), _weapon], "None"] in ["Fire","Dud"])}}
|
||||
// open bolt, and not jammed, or jammed and type not failure to fire
|
||||
|| {_closedBolt == 0 && {!_canUnjam || {_canUnjam && {!(_unit getVariable [format [QGVAR(%1_jamType), _weapon], "None"] in ["Fire","Dud"])}}}}
|
||||
) exitWith {
|
||||
_unit setVariable [format [QGVAR(%1_ammoTemp), _weapon], 0];
|
||||
0
|
||||
};
|
||||
|
||||
private _ammoTempVarName = format [QGVAR(%1_ammoTemp), _weapon];
|
||||
private _ammoTemperature = _unit getVariable [_ammoTempVarName, 0];
|
||||
|
||||
// heat or cool the ammo
|
||||
if (_ammoTemperature < _barrelTemperature) then {
|
||||
// this is functional and feels ok, but someone please do better heat transfer math here, my head hurts.
|
||||
private _temperatureDifference = _barrelTemperature - _ammoTemperature;
|
||||
_ammoTemperature = _ammoTemperature + (1 max ((_temperatureDifference / 2.75) - 100));
|
||||
} else {
|
||||
_ammoTemperature = _barrelTemperature;
|
||||
};
|
||||
|
||||
// check for cook off
|
||||
if (_ammoTemperature > (GUNPOWDER_IGNITION_TEMP * GVAR(cookoffCoef))) then {
|
||||
|
||||
// a weapon with a failure to fire or dud type jam will be unjammed from cooking off
|
||||
// this is first so that the fired event from the cookoff can also cause a jam
|
||||
private _jamType = _unit getVariable [format [QGVAR(%1_jamType), _weapon], "None"];
|
||||
if (_canUnjam && {_jamType in ["Fire","Dud"]}) then {
|
||||
|
||||
[_unit, currentMuzzle _unit, true] call FUNC(clearJam);
|
||||
|
||||
// clearJam will remove a dud round, but so will the forced fire, so give back the lost round and shoot it
|
||||
if (_jamType isEqualTo "Dud") then {
|
||||
private _ammo = _unit ammo _weapon;
|
||||
_unit setAmmo [_weapon, _ammo + 1];
|
||||
};
|
||||
};
|
||||
|
||||
// get valid mode and muzzle for the main weapon, we don't want the cookoff to come from an underbarrel launcher
|
||||
([_weapon] call FUNC(getWeaponData)) params ["", "", "", "_modes", "_muzzle", "_reloadTime"];
|
||||
|
||||
// get an appropriate firemode and muzzle, cache the current muzzle
|
||||
// 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)
|
||||
private _muzzleCache = currentMuzzle _unit;
|
||||
private _mode = currentWeaponMode _unit;
|
||||
if !(_mode in _modes) then {
|
||||
_mode = _modes select 0;
|
||||
};
|
||||
|
||||
// delay cookoff to ensure any previous animation from a fired event is finished
|
||||
[
|
||||
{
|
||||
params ["_unit", "_muzzleCache", "_mode", "_muzzle"];
|
||||
|
||||
// fire the cookoff
|
||||
_unit forceWeaponFire [_muzzle, _mode];
|
||||
|
||||
// switch back to the cached muzzle if required
|
||||
if (_muzzle != _muzzleCache) then {
|
||||
_unit selectWeapon _muzzleCache;
|
||||
};
|
||||
|
||||
[
|
||||
[localize LSTRING(WeaponCookedOff)],
|
||||
true // allows the hint to be overwritten by another hint, such as a jam or another cookoff
|
||||
] call CBA_fnc_notify;
|
||||
},
|
||||
[_unit, _muzzleCache, _mode, _muzzle],
|
||||
_reloadTime
|
||||
] call CBA_fnc_waitAndExecute;
|
||||
|
||||
// if the cookoff happened then the next round should start at 0
|
||||
_ammoTemperature = 0;
|
||||
};
|
||||
|
||||
_unit setVariable [_ammoTempVarName, _ammoTemperature];
|
||||
|
||||
_ammoTemperature
|
@ -0,0 +1,25 @@
|
||||
#include "script_component.hpp"
|
||||
/*
|
||||
* Author: esteldunedain & drofseh
|
||||
* Update .
|
||||
*
|
||||
* Arguments:
|
||||
* None
|
||||
*
|
||||
* Return Value:
|
||||
* None
|
||||
*
|
||||
* Example:
|
||||
* [] call ace_overheating_fnc_updateAmmoTemperatureThread
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
|
||||
private _currentWeapon = currentWeapon ACE_player;
|
||||
if ((_currentWeapon != "") && {_currentWeapon == primaryWeapon ACE_player || {_currentWeapon == handgunWeapon ACE_player}}) then {
|
||||
private _temperature = ACE_player getVariable [format [QGVAR(%1_temp), _currentWeapon], 0];
|
||||
[ACE_player, _currentWeapon, _temperature] call FUNC(updateAmmoTemperature);
|
||||
};
|
||||
|
||||
// Schedule for execution again after 1 seconds. A quick loop is needed for ammo temperature in order to have faster cookoffs at higher barrel temps
|
||||
[DFUNC(updateAmmoTemperatureThread), [], 1] call CBA_fnc_waitAndExecute;
|
@ -27,7 +27,7 @@ private _timeVarName = format [QGVAR(%1_time), _weapon];
|
||||
private _temperature = _unit getVariable [_tempVarName, 0];
|
||||
private _lastTime = _unit getVariable [_timeVarName, 0];
|
||||
|
||||
private _barrelMass = METAL_MASS_RATIO * (getNumber (configFile >> "CfgWeapons" >> _weapon >> "WeaponSlotsInfo" >> "mass") / 22.0) max 1.0;
|
||||
private _barrelMass = _weapon call FUNC(getBarrelMass);
|
||||
|
||||
// Calculate cooling
|
||||
_temperature = [_temperature, _barrelMass, CBA_missionTime - _lastTime] call FUNC(calculateCooling);
|
||||
@ -35,7 +35,7 @@ _temperature = [_temperature, _barrelMass, CBA_missionTime - _lastTime] call FUN
|
||||
TRACE_1("cooledTo",_temperature);
|
||||
// Calculate heating
|
||||
// Steel Heat Capacity = 466 J/(Kg.K)
|
||||
_temperature = _temperature + _heatIncrement / (_barrelMass * 466);
|
||||
_temperature = _temperature + _heatIncrement * GVAR(heatCoef) / (_barrelMass * 466);
|
||||
|
||||
// Publish the temperature variable
|
||||
[_unit, _tempVarName, _temperature, TEMP_TOLERANCE] call EFUNC(common,setApproximateVariablePublic);
|
||||
|
@ -15,9 +15,20 @@
|
||||
* Public: No
|
||||
*/
|
||||
|
||||
private _currentWeapon = currentWeapon ACE_player;
|
||||
if ((_currentWeapon != "") && {_currentWeapon == primaryWeapon ACE_player || {_currentWeapon == handgunWeapon ACE_player}}) then {
|
||||
[ACE_player, _currentWeapon, 0] call FUNC(updateTemperature);
|
||||
if (ACE_player call EFUNC(common,isSwimming)) then { // cool off both weapons while swimming because currentWeapon == ""
|
||||
private _primaryWeapon = primaryWeapon ACE_player;
|
||||
private _handgunWeapon = handgunWeapon ACE_player;
|
||||
if (_primaryWeapon != "") then {
|
||||
[ACE_player, _primaryWeapon, 0] call FUNC(updateTemperature);
|
||||
};
|
||||
if (_handgunWeapon != "") then {
|
||||
[ACE_player, _handgunWeapon, 0] call FUNC(updateTemperature);
|
||||
};
|
||||
} else {
|
||||
private _currentWeapon = currentWeapon ACE_player;
|
||||
if ((_currentWeapon != "") && {_currentWeapon == primaryWeapon ACE_player || {_currentWeapon == handgunWeapon ACE_player}}) then {
|
||||
[ACE_player, _currentWeapon, 0] call FUNC(updateTemperature);
|
||||
};
|
||||
};
|
||||
|
||||
// Schedule for execution again after 5 seconds
|
||||
|
@ -5,6 +5,16 @@ private _category = format ["ACE %1", localize LSTRING(DisplayName)];
|
||||
[LSTRING(enabled_displayName), LSTRING(enabled_description)],
|
||||
_category,
|
||||
true,
|
||||
1,
|
||||
{},
|
||||
true
|
||||
] call CBA_fnc_addSetting;
|
||||
|
||||
[
|
||||
QGVAR(heatCoef), "SLIDER",
|
||||
[LSTRING(heatCoef_displayName), LSTRING(heatCoef_description)],
|
||||
_category,
|
||||
[0, 5, 1, 2],
|
||||
1
|
||||
] call CBA_fnc_addSetting;
|
||||
|
||||
@ -21,7 +31,9 @@ private _category = format ["ACE %1", localize LSTRING(DisplayName)];
|
||||
[LSTRING(showParticleEffectsForEveryone_displayName), LSTRING(showParticleEffectsForEveryone_description)],
|
||||
_category,
|
||||
false,
|
||||
0
|
||||
0,
|
||||
{},
|
||||
true
|
||||
] call CBA_fnc_addSetting;
|
||||
|
||||
[
|
||||
@ -29,6 +41,24 @@ private _category = format ["ACE %1", localize LSTRING(DisplayName)];
|
||||
[LSTRING(overheatingDispersion_displayName), LSTRING(overheatingDispersion_description)],
|
||||
_category,
|
||||
true,
|
||||
1,
|
||||
{},
|
||||
true
|
||||
] call CBA_fnc_addSetting;
|
||||
|
||||
[
|
||||
QGVAR(particleEffectsAndDispersionDistance), "SLIDER",
|
||||
[LSTRING(particleEffectsAndDispersionDistance_displayName), LSTRING(particleEffectsAndDispersionDistance_description)],
|
||||
_category,
|
||||
[1, 5000, 3000, 0],
|
||||
0
|
||||
] call CBA_fnc_addSetting;
|
||||
|
||||
[
|
||||
QGVAR(overheatingRateOfFire), "CHECKBOX",
|
||||
[LSTRING(overheatingRateOfFire_displayName), LSTRING(overheatingRateOfFire_description)],
|
||||
_category,
|
||||
true,
|
||||
1
|
||||
] call CBA_fnc_addSetting;
|
||||
|
||||
@ -40,11 +70,29 @@ private _category = format ["ACE %1", localize LSTRING(DisplayName)];
|
||||
0
|
||||
] call CBA_fnc_addSetting;
|
||||
|
||||
[
|
||||
QGVAR(jamChanceCoef), "SLIDER",
|
||||
[LSTRING(jamChanceCoef_displayName), LSTRING(jamChanceCoef_description)],
|
||||
_category,
|
||||
[0, 5, 1, 2],
|
||||
0
|
||||
] call CBA_fnc_addSetting;
|
||||
|
||||
[
|
||||
QGVAR(unJamOnreload), "CHECKBOX",
|
||||
[LSTRING(unJamOnreload_displayName), LSTRING(unJamOnreload_description)],
|
||||
_category,
|
||||
false,
|
||||
1,
|
||||
{},
|
||||
true
|
||||
] call CBA_fnc_addSetting;
|
||||
|
||||
[
|
||||
QGVAR(unJamOnSwapBarrel), "CHECKBOX",
|
||||
[LSTRING(unJamOnSwapBarrel_displayName), LSTRING(unJamOnSwapBarrel_description)],
|
||||
_category,
|
||||
false,
|
||||
1
|
||||
] call CBA_fnc_addSetting;
|
||||
|
||||
@ -55,3 +103,13 @@ private _category = format ["ACE %1", localize LSTRING(DisplayName)];
|
||||
[0, 1, 0.1, 2],
|
||||
1
|
||||
] call CBA_fnc_addSetting;
|
||||
|
||||
[
|
||||
QGVAR(cookoffCoef), "SLIDER",
|
||||
[LSTRING(cookoffCoef_displayName), LSTRING(cookoffCoef_description)],
|
||||
_category,
|
||||
[0, 5, 1, 2],
|
||||
1,
|
||||
{},
|
||||
true
|
||||
] call CBA_fnc_addSetting;
|
||||
|
@ -18,6 +18,7 @@
|
||||
|
||||
#define TEMP_TOLERANCE 50
|
||||
#define METAL_MASS_RATIO 0.55
|
||||
#define GUNPOWDER_IGNITION_TEMP 180
|
||||
|
||||
#ifdef DEBUG_MODE_FULL
|
||||
#define TRACE_PROJECTILE_INFO(BULLET) _vdir = vectorNormalized velocity BULLET; _dir = (_vdir select 0) atan2 (_vdir select 1); _up = asin (_vdir select 2); _mv = vectorMagnitude velocity BULLET; TRACE_3("adjusted projectile",_dir,_up,_mv);
|
||||
|
@ -16,8 +16,44 @@
|
||||
<French>Surchauffe</French>
|
||||
<Czech>Přehřívání</Czech>
|
||||
</Key>
|
||||
<Key ID="STR_ACE_Overheating_enabled_displayName">
|
||||
<English>Overheating Enabled</English>
|
||||
<German>Überhitzung aktiviert</German>
|
||||
<Spanish>Activado Sobrecalentamiento</Spanish>
|
||||
<Portuguese>Superaquecimento ativado</Portuguese>
|
||||
<French>Surchauffe activée</French>
|
||||
<Russian>Перегрев включен</Russian>
|
||||
<Czech>Přehřívání povoleno</Czech>
|
||||
<Japanese>過熱を有効化</Japanese>
|
||||
<Polish>Przegrzewanie włączone</Polish>
|
||||
<Korean>과열 활성화</Korean>
|
||||
<Italian>Surriscaldamento Abilitato</Italian>
|
||||
<Chinesesimp>启用过热</Chinesesimp>
|
||||
<Chinese>啟用過熱</Chinese>
|
||||
</Key>
|
||||
<Key ID="STR_ACE_Overheating_enabled_description">
|
||||
<English>Master enable for the overheating/jamming module</English>
|
||||
<Spanish>Activación maestra para Sobrecalentamiento</Spanish>
|
||||
<Portuguese>Chave mestra para o módulo de superaquecimento/emperramento</Portuguese>
|
||||
<French>Active le module de surchauffe/d'enrayement.</French>
|
||||
<Russian>Главный включатель для модуля перегрева/заклинивания</Russian>
|
||||
<Japanese>過熱と弾詰まりモジュールを全て有効化します</Japanese>
|
||||
<Polish>Główny włącznik modułu przegrzewania/zacinania się broni</Polish>
|
||||
<German>Hauptschalter, um die Überhitzung-/Ladehemmung-Module zu aktivieren</German>
|
||||
<Korean>과열/탄걸림 최종 활성화</Korean>
|
||||
<Italian>Abilitazione master per il modulo di surriscaldamento / inceppamento</Italian>
|
||||
<Chinesesimp>启用枪管过热/干扰模块</Chinesesimp>
|
||||
<Chinese>啟用槍管過熱/干擾模塊</Chinese>
|
||||
<Czech>Hlavní přepínač pro modul přehřívání/zasekávání</Czech>
|
||||
</Key>
|
||||
<Key ID="STR_ACE_Overheating_heatCoef_displayName">
|
||||
<English>Heating Coefficient</English>
|
||||
</Key>
|
||||
<Key ID="STR_ACE_Overheating_heatCoef_description">
|
||||
<English>Coefficient for the amount of heat a weapon generates per shot.\nHigher value increases heat.</English>
|
||||
</Key>
|
||||
<Key ID="STR_ACE_Overheating_DisplayTextOnJam_displayName">
|
||||
<English>Display text on jam</English>
|
||||
<English>Display Text on Jam</English>
|
||||
<German>Zeige Text bei Ladehemmung</German>
|
||||
<Spanish>Mostrar texto al encasquillarse</Spanish>
|
||||
<Russian>Показывать текст, когда клинит оружие</Russian>
|
||||
@ -81,7 +117,7 @@
|
||||
<Hungarian>Fegyvertúlmelegedést okozó részecskehatások mutatása</Hungarian>
|
||||
</Key>
|
||||
<Key ID="STR_ACE_Overheating_showParticleEffectsForEveryone_displayName">
|
||||
<English>Overheating Particle Effects for everyone</English>
|
||||
<English>Overheating Particle Effects for Everyone</English>
|
||||
<German>Zeige Partikeleffekt bei Überhitzung für jeden</German>
|
||||
<Polish>Pokaż efekty cząsteczkowe dla wszystkich</Polish>
|
||||
<Italian>Effetti Particellari Surriscaldamento per tutti</Italian>
|
||||
@ -144,8 +180,26 @@
|
||||
<Chinese>過熱的武器將會有打不準和減少射擊初速的情況。適用於所有玩家</Chinese>
|
||||
<Hungarian>A túlmelegedett fegyverek kevésbé lesznek pontosak és csökkent a lövés sebessége. Minden játékosra vonatkozik.</Hungarian>
|
||||
</Key>
|
||||
<Key ID="STR_ACE_Overheating_unJamOnreload_displayName">
|
||||
<English>Unjam weapon on reload</English>
|
||||
<Key ID="STR_ACE_Overheating_particleEffectsAndDispersionDistance_displayName">
|
||||
<English>Distance for Effects and Dispersion</English>
|
||||
</Key>
|
||||
<Key ID="STR_ACE_Overheating_particleEffectsAndDispersionDistance_description">
|
||||
<English>The distance, in meters, from the player within which overheating particle effects and dispersion are visible.</English>
|
||||
</Key>
|
||||
<Key ID="STR_ACE_Overheating_overheatingRateOfFire_displayName">
|
||||
<English>Heat Increases Fire Rate</English>
|
||||
</Key>
|
||||
<Key ID="STR_ACE_Overheating_overheatingRateOfFire_description">
|
||||
<English>As weapons heat up, their rate of fire increases by up to 10%.</English>
|
||||
</Key>
|
||||
<Key ID="STR_ACE_Overheating_jamChanceCoef_displayName">
|
||||
<English>Jam Chance Coefficient</English>
|
||||
</Key>
|
||||
<Key ID="STR_ACE_Overheating_jamChanceCoef_description">
|
||||
<English>Coefficient for the chance that a weapon will jam from overheating.\nHigher value make jams more likely.\nSet to 0 to disable jamming.</English>
|
||||
</Key>
|
||||
<Key ID="STR_ACE_Overheating_unJamOnReload_displayName">
|
||||
<English>Unjam Weapon on Reload</English>
|
||||
<German>Behebt Ladehemmung beim Nachladen</German>
|
||||
<Spanish>Desencasquillar el arma al recargar.</Spanish>
|
||||
<Polish>Usuń zacięcie przy przeładowaniu</Polish>
|
||||
@ -160,7 +214,7 @@
|
||||
<Chinese>重裝彈匣以解決卡彈</Chinese>
|
||||
<Hungarian>Távolítsa el az akadályt újratöltéskor</Hungarian>
|
||||
</Key>
|
||||
<Key ID="STR_ACE_Overheating_unJamOnreload_description">
|
||||
<Key ID="STR_ACE_Overheating_unJamOnReload_description">
|
||||
<English>Reloading clears a weapon jam.</English>
|
||||
<German>Nachladen behebt eine Ladehemmung.</German>
|
||||
<Spanish>Recargar el arma la desencasquilla.</Spanish>
|
||||
@ -176,8 +230,14 @@
|
||||
<Chinese>利用重裝彈匣來解決卡彈</Chinese>
|
||||
<Hungarian>Az újratöltés megszünteti a fegyver elakadását.</Hungarian>
|
||||
</Key>
|
||||
<Key ID="STR_ACE_Overheating_unJamOnSwapBarrel_displayName">
|
||||
<English>Unjam on Barrel Swap</English>
|
||||
</Key>
|
||||
<Key ID="STR_ACE_Overheating_unJamOnSwapBarrel_description">
|
||||
<English>Controls whether swapping barrels clears a weapon jam.</English>
|
||||
</Key>
|
||||
<Key ID="STR_ACE_Overheating_unJamFailChance_displayName">
|
||||
<English>Chance of unjam failing</English>
|
||||
<English>Chance of Unjam Failing</English>
|
||||
<German>Wahrscheinlichkeit, dass Ladehemmung nicht behoben wird</German>
|
||||
<Spanish>Probabilidad de falla al desencasquillar.</Spanish>
|
||||
<Polish>Szansa na porażkę usuw. zacięcia</Polish>
|
||||
@ -208,6 +268,12 @@
|
||||
<Chinese>清除卡彈時有可能會失敗,需要反覆進行清槍。</Chinese>
|
||||
<Hungarian>Valószínűsége annak, hogy egy akadály eltávolítás művelet kudarcot vall, megismétlést igényel.</Hungarian>
|
||||
</Key>
|
||||
<Key ID="STR_ACE_Overheating_cookoffCoef_displayName">
|
||||
<English>Overheating Cookoff Coefficient</English>
|
||||
</Key>
|
||||
<Key ID="STR_ACE_Overheating_cookoffCoef_description">
|
||||
<English>Coefficient for the heat required for cookoffs to occur.\nHigher values require more heat to cookoff.\nSet to 0 to disable cookoff.</English>
|
||||
</Key>
|
||||
<Key ID="STR_ACE_Overheating_SpareBarrelName">
|
||||
<English>Spare barrel</English>
|
||||
<German>Ersatzlauf</German>
|
||||
@ -256,6 +322,21 @@
|
||||
<Chinesesimp>武器卡弹!</Chinesesimp>
|
||||
<Chinese>武器卡彈!</Chinese>
|
||||
</Key>
|
||||
<Key ID="STR_ACE_Overheating_WeaponCookedOff">
|
||||
<English>Weapon cooked off!</English>
|
||||
</Key>
|
||||
<Key ID="STR_ACE_Overheating_FailureToEject">
|
||||
<English>Failure to eject.</English>
|
||||
</Key>
|
||||
<Key ID="STR_ACE_Overheating_FailureToExtract">
|
||||
<English>Failure to extract.</English>
|
||||
</Key>
|
||||
<Key ID="STR_ACE_Overheating_FailureToFeed">
|
||||
<English>Failure to feed.</English>
|
||||
</Key>
|
||||
<Key ID="STR_ACE_Overheating_FailureToFire">
|
||||
<English>Failure to fire.</English>
|
||||
</Key>
|
||||
<Key ID="STR_ACE_Overheating_UnjamWeapon">
|
||||
<English>Clear jam</English>
|
||||
<German>Ladehemmung beheben</German>
|
||||
@ -429,6 +510,24 @@
|
||||
<Chinesesimp>正在检查枪管温度...</Chinesesimp>
|
||||
<Chinese>檢查槍管溫度中...</Chinese>
|
||||
</Key>
|
||||
<Key ID="STR_ACE_Overheating_CoolWeaponWithItem">
|
||||
<English>Cool weapon with...</English>
|
||||
</Key>
|
||||
<Key ID="STR_ACE_Overheating_CoolingWeaponWithItem">
|
||||
<English>Cooling %1 with %2.</English>
|
||||
</Key>
|
||||
<Key ID="STR_ACE_Overheating_CoolWeaponWithWaterSource">
|
||||
<English>Cool weapon in water source.</English>
|
||||
</Key>
|
||||
<Key ID="STR_ACE_Overheating_CoolingWeaponWithWaterSource">
|
||||
<English>Cooling weapon in water source.</English>
|
||||
</Key>
|
||||
<Key ID="STR_ACE_Overheating_CoolWeaponNotEnoughWater">
|
||||
<English>Container doesn't have enough water.</English>
|
||||
</Key>
|
||||
<Key ID="STR_ACE_Overheating_CoolWeaponIsCool">
|
||||
<English>Weapon is cool enough the water has stopped boiling.</English>
|
||||
</Key>
|
||||
<Key ID="STR_ACE_Overheating_Temperature">
|
||||
<English>Temperature</English>
|
||||
<German>Temperatur</German>
|
||||
@ -520,35 +619,5 @@
|
||||
<Chinesesimp>备用枪管温度超级热</Chinesesimp>
|
||||
<Chinese>備用槍管溫度超級熱</Chinese>
|
||||
</Key>
|
||||
<Key ID="STR_ACE_Overheating_enabled_displayName">
|
||||
<English>Overheating Enabled</English>
|
||||
<German>Überhitzung aktiviert</German>
|
||||
<Spanish>Activado Sobrecalentamiento</Spanish>
|
||||
<Portuguese>Superaquecimento ativado</Portuguese>
|
||||
<French>Surchauffe activée</French>
|
||||
<Russian>Перегрев включен</Russian>
|
||||
<Czech>Přehřívání povoleno</Czech>
|
||||
<Japanese>過熱を有効化</Japanese>
|
||||
<Polish>Przegrzewanie włączone</Polish>
|
||||
<Korean>과열 활성화</Korean>
|
||||
<Italian>Surriscaldamento Abilitato</Italian>
|
||||
<Chinesesimp>启用过热</Chinesesimp>
|
||||
<Chinese>啟用過熱</Chinese>
|
||||
</Key>
|
||||
<Key ID="STR_ACE_Overheating_enabled_description">
|
||||
<English>Master enable for the overheating/jamming module</English>
|
||||
<Spanish>Activación maestra para Sobrecalentamiento</Spanish>
|
||||
<Portuguese>Chave mestra para o módulo de superaquecimento/emperramento</Portuguese>
|
||||
<French>Active le module de surchauffe/d'enrayement.</French>
|
||||
<Russian>Главный включатель для модуля перегрева/заклинивания</Russian>
|
||||
<Japanese>過熱と弾詰まりモジュールを全て有効化します</Japanese>
|
||||
<Polish>Główny włącznik modułu przegrzewania/zacinania się broni</Polish>
|
||||
<German>Hauptschalter, um die Überhitzung-/Ladehemmung-Module zu aktivieren</German>
|
||||
<Korean>과열/탄걸림 최종 활성화</Korean>
|
||||
<Italian>Abilitazione master per il modulo di surriscaldamento / inceppamento</Italian>
|
||||
<Chinesesimp>启用枪管过热/干扰模块</Chinesesimp>
|
||||
<Chinese>啟用槍管過熱/干擾模塊</Chinese>
|
||||
<Czech>Hlavní přepínač pro modul přehřívání/zasekávání</Czech>
|
||||
</Key>
|
||||
</Package>
|
||||
</Project>
|
||||
|
@ -49,6 +49,7 @@ ace_recoil_shakemultiplier
|
||||
ace_overpressure_angle
|
||||
ace_overpressure_range
|
||||
ace_overpressure_damage
|
||||
ace_overheating_closedbolt
|
||||
ace_overheating_dispersion
|
||||
ace_overheating_slowdownfactor
|
||||
ace_overheating_jamchance
|
||||
|
@ -15,27 +15,36 @@ version:
|
||||
## 1. Overview
|
||||
|
||||
### 1.1 Weapon Jamming
|
||||
Adds a probability to jam a weapon when firing. Jams can be cleared by reloading or by using the clear jam-key.
|
||||
|
||||
Adds a probability to jam a weapon when firing. Jams can be cleared by reloading, using the clear jam-key, or using the self interaction menu.
|
||||
|
||||
### 1.2 Temperature simulation
|
||||
Introduces weapon temperature simulation depending on weapon and bullet mass. Hot weapons are more prone to jamming. Depending on weapon type the accuracy and in extreme cases the muzzle velocity might be reduced on high temperatures. Adds smoke puff and heat refraction effects to indicate this.
|
||||
|
||||
### 1.3 Spare barrels
|
||||
Adds the ability to changes barrels on machine guns to compensate for those effects.
|
||||
Introduces weapon temperature simulation depending on weapon and bullet mass. Hot weapons are more prone to jamming and will have an increase in their cyclic rate of fire. Depending on weapon type the accuracy and in extreme cases the muzzle velocity might be reduced on high temperatures. Adds smoke puff and heat refraction effects to indicate this.
|
||||
|
||||
### 1.3 Cookoff
|
||||
|
||||
Hot weapons can also cause chambered ammunition to spontaneously ignite. The higher the temperature of the weapon the sooner a cookoff can happen. Open bolt weapons (most machineguns) cannot cookoff unless jammed. Jammed weapons will not cookoff unless the jam is a failure to fire.
|
||||
|
||||
### 1.4 Spare barrels
|
||||
|
||||
Adds the ability to changes barrels on machine guns to compensate for those effects. Changing the barrel can also unjam the gun.
|
||||
|
||||
## 2. Usage
|
||||
|
||||
### 2.1 Clearing a jammed weapon
|
||||
|
||||
- To clear a jammed weapon, press <kbd>SHIFT</kbd> + <kbd>R</kbd> (ACE3 default key bind `Clear jam`).
|
||||
|
||||
### 2.2 Swapping barrels
|
||||
|
||||
- For this you need a `Spare barrel` and a compatible weapon.
|
||||
- Press self interaction <kbd>Ctrl</kbd> + <kbd>⊞ Win</kbd> (ACE3 default key bind `Self Interaction Key`).
|
||||
- Select `Equipment`.
|
||||
- Select `Swap barrel`.
|
||||
|
||||
### 2.3 Checking your barrel temperature
|
||||
|
||||
- Press self interaction <kbd>Ctrl</kbd> + <kbd>⊞ Win</kbd>.
|
||||
- Select `Equipment`.
|
||||
- Select `Check weapon temperature`.
|
||||
@ -43,6 +52,18 @@ Adds the ability to changes barrels on machine guns to compensate for those effe
|
||||
**NOTE** When the bar is half full (yellow) it means the barrel is around 500°c.
|
||||
Your weapon will be even more prone to jams, and it'll get worse if you don't let the barrel cool down or swap it.
|
||||
|
||||
### 2.4 Cooling your weapon
|
||||
|
||||
- Weapons and spare barrels will cool off over time.
|
||||
- Cooling speed of weapons in increased in windy or rainy weather, and when swimming.
|
||||
- If AceX Field Rations is loaded then weapons can be cooled with canteens, water bottles, or other beverage items. This does not require the Field Rations system to be enabled.
|
||||
- If AceX Field Rations is enabled then weapons can also be cooled with the same water sources used to refill canteens and water bottles.
|
||||
|
||||
### 2.5 Avoiding cookoffs
|
||||
|
||||
- After a firefight unload closed bolt firearms (most rifles) until the barrel temperature has gone down to less than 180°C (two sections or less on the bar).
|
||||
- Clear failure to fire jams quickly
|
||||
|
||||
## 3. Dependencies
|
||||
|
||||
{% include dependencies_list.md component="overheating" %}
|
||||
|
@ -27,7 +27,16 @@ class CfgWeapons {
|
||||
};
|
||||
```
|
||||
|
||||
### 1.2 Custom jam clearing animation
|
||||
### 1.2 Custom jam types
|
||||
|
||||
```cpp
|
||||
class CfgWeapons {
|
||||
class Pistol_Base_F;
|
||||
class MyRevolver : Pistol_Base_F {
|
||||
ace_overheating_jamTypesAllowed = ["Fire","Dud"]; //Allowed and default values are ["Eject", "Extract", "Feed", "Fire", "Dud"]. In the example here a revolver does not eject, extract, or feed on each shot to those values are removed.
|
||||
};
|
||||
```
|
||||
### 1.3 Custom jam clearing animation
|
||||
|
||||
```cpp
|
||||
class CfgWeapons {
|
||||
@ -36,3 +45,19 @@ class CfgWeapons {
|
||||
};
|
||||
};
|
||||
```
|
||||
|
||||
### 1.4 Cook Off
|
||||
|
||||
```cpp
|
||||
class CfgWeapons {
|
||||
class Rifle_Long_Base_F ;
|
||||
|
||||
class MySniper : Rifle_Long_Base_F {
|
||||
ace_overheating_closedBolt = 1; // Closed bolt, can cook off from barrel heat.
|
||||
};
|
||||
|
||||
class MyMG : Rifle_Long_Base_F {
|
||||
ace_overheating_closedBolt = 0; // Open bolt, can only cook off on failure to fire type jams.
|
||||
};
|
||||
};
|
||||
```
|
||||
|
@ -107,6 +107,14 @@ class CfgWeapons {
|
||||
ACE_barrelLength = 610.0;
|
||||
};
|
||||
|
||||
class rhs_weap_Izh18 : Rifle_Base_F {
|
||||
ace_overheating_jamTypesAllowed = ["Fire","Dud"];
|
||||
};
|
||||
|
||||
class rhs_weap_m79 : Rifle_Base_F {
|
||||
ace_overheating_jamTypesAllowed = ["Fire","Dud"];
|
||||
};
|
||||
|
||||
CREATE_CSW_PROXY(rhs_weap_DSHKM);
|
||||
|
||||
class Launcher;
|
||||
|
@ -157,6 +157,9 @@ class CfgWeapons {
|
||||
ACE_twistDirection = 0;
|
||||
ACE_barrelLength = 508.0;
|
||||
};
|
||||
class rhs_weap_m32_Base_F : Rifle_Base_F {
|
||||
ace_overheating_jamTypesAllowed = ["Fire","Dud"];
|
||||
};
|
||||
class SMG_02_base_F;
|
||||
class rhsusf_weap_MP7A1_base_f: SMG_02_base_F {
|
||||
ACE_barrelLength = 180;
|
||||
@ -180,6 +183,10 @@ class CfgWeapons {
|
||||
ACE_barrelTwist = 248.92;
|
||||
ACE_barrelLength = 124.46;
|
||||
};
|
||||
class rhs_weap_M320_Base_F: Pistol_Base_F {
|
||||
ace_overheating_jamTypesAllowed = ["Fire","Dud"];
|
||||
};
|
||||
|
||||
// RHS sniper scopes
|
||||
class ItemCore;
|
||||
class InventoryOpticsItem_Base_F;
|
||||
|
Loading…
Reference in New Issue
Block a user