mirror of
https://github.com/acemod/ACE3.git
synced 2024-08-30 18:23:18 +00:00
Merge pull request #3438 from acemod/spareBarrelSimulation
AAR actions + track temperatures of spare barrels
This commit is contained in:
commit
5ff91484ed
@ -38,4 +38,10 @@ class ACE_Settings {
|
||||
displayName = CSTRING(unJamFailChance_displayName);
|
||||
description = CSTRING(unJamFailChance_description);
|
||||
};
|
||||
class GVAR(enabled) {
|
||||
typeName = "BOOL";
|
||||
value = 1;
|
||||
displayName = CSTRING(enabled_displayName);
|
||||
description = CSTRING(enabled_description);
|
||||
};
|
||||
};
|
||||
|
@ -16,11 +16,3 @@ class Extended_PostInit_EventHandlers {
|
||||
init = QUOTE( call COMPILE_FILE(XEH_postInit) );
|
||||
};
|
||||
};
|
||||
|
||||
class Extended_Take_EventHandlers {
|
||||
class CAManBase {
|
||||
class GVAR(UnjamReload) {
|
||||
clientTake = QUOTE( _this call FUNC(handleTakeEH) );
|
||||
};
|
||||
};
|
||||
};
|
||||
|
11
addons/overheating/CfgMagazines.hpp
Normal file
11
addons/overheating/CfgMagazines.hpp
Normal file
@ -0,0 +1,11 @@
|
||||
class CfgMagazines {
|
||||
class CA_Magazine;
|
||||
class ACE_SpareBarrel: CA_Magazine {
|
||||
displayName = CSTRING(SpareBarrelName);
|
||||
descriptionshort = CSTRING(SpareBarrelDescription);
|
||||
picture = QUOTE(PATHTOF(UI\spare_barrel_ca.paa));
|
||||
count = 1;
|
||||
mass = 60;
|
||||
ACE_isUnique = 1;
|
||||
};
|
||||
};
|
@ -4,32 +4,59 @@ class CfgVehicles {
|
||||
class CAManBase: Man {
|
||||
class ACE_SelfActions {
|
||||
class ACE_Equipment {
|
||||
class ACE_UnJam {
|
||||
class GVAR(UnJam) {
|
||||
displayName = CSTRING(UnjamWeapon);
|
||||
condition = QUOTE( [_player] call FUNC(canUnjam) );
|
||||
condition = QUOTE( GVAR(enabled) && {[_player] call FUNC(canUnjam)} );
|
||||
exceptions[] = {"isNotInside", "isNotSitting"};
|
||||
statement = QUOTE( [ARR_2(_player, currentMuzzle _player)] call FUNC(clearJam); );
|
||||
showDisabled = 0;
|
||||
priority = 4;
|
||||
icon = QUOTE(PATHTOF(UI\unjam_ca.paa));
|
||||
};
|
||||
class ACE_SwapBarrel {
|
||||
class GVAR(SwapBarrel) {
|
||||
displayName = CSTRING(SwapBarrel);
|
||||
condition = QUOTE( 'ACE_SpareBarrel' in items _player && {getNumber (configFile >> 'CfgWeapons' >> currentWeapon _player >> 'ACE_Overheating_allowSwapBarrel') == 1} );
|
||||
statement = QUOTE( [ARR_2(_player, currentWeapon _player)] call FUNC(swapBarrel); );
|
||||
condition = QUOTE( GVAR(enabled) && {'ACE_SpareBarrel' in magazines _player} && {getNumber (configFile >> 'CfgWeapons' >> currentWeapon _player >> 'ACE_Overheating_allowSwapBarrel') == 1} );
|
||||
statement = QUOTE( [ARR_3(_player, _player, currentWeapon _player)] call FUNC(swapBarrel); );
|
||||
showDisabled = 0;
|
||||
priority = 3;
|
||||
icon = QUOTE(PATHTOF(UI\spare_barrel_ca.paa));
|
||||
};
|
||||
class ACE_CheckTemperature {
|
||||
class GVAR(CheckTemperature) {
|
||||
displayName = CSTRING(CheckTemperatureShort);
|
||||
condition = "switch (currentWeapon _player) do {case (''): {false}; case (primaryWeapon _player); case (secondaryWeapon _player); case (handgunWeapon _player): {true}; default {false}}";
|
||||
condition = "ace_overheating_enabled && {switch (currentWeapon _player) do {case (''): {false}; case (primaryWeapon _player); case (handgunWeapon _player): {true}; default {false}}}";
|
||||
exceptions[] = {"isNotInside", "isNotSitting"};
|
||||
statement = QUOTE( [ARR_2(_player, currentWeapon _player)] call FUNC(CheckTemperature); );
|
||||
statement = QUOTE( [ARR_3(_player, _player, currentWeapon _player)] call FUNC(checkTemperature); );
|
||||
showDisabled = 0;
|
||||
priority = 2.9;
|
||||
icon = QUOTE(PATHTOF(UI\temp_ca.paa));
|
||||
};
|
||||
class GVAR(CheckTemperatureSpareBarrels) {
|
||||
displayName = CSTRING(CheckTemperatureSpareBarrelsShort);
|
||||
condition = QUOTE( GVAR(enabled) && {'ACE_SpareBarrel' in magazines _player});
|
||||
exceptions[] = {"isNotInside", "isNotSitting"};
|
||||
statement = QUOTE( [_player] call FUNC(checkSpareBarrelsTemperatures); );
|
||||
showDisabled = 0;
|
||||
priority = 2.8;
|
||||
icon = QUOTE(PATHTOF(UI\temp_ca.paa));
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
class ACE_Actions {
|
||||
class ACE_Weapon {
|
||||
class GVAR(SwapBarrel) {
|
||||
displayName = CSTRING(SwapBarrel);
|
||||
condition = QUOTE( GVAR(enabled) && {'ACE_SpareBarrel' in magazines _player} && {getNumber (configFile >> 'CfgWeapons' >> currentWeapon _target >> 'ACE_Overheating_allowSwapBarrel') == 1} );
|
||||
statement = QUOTE([ARR_3(_player, _target, currentWeapon _target)] call FUNC(swapBarrelAssistant););
|
||||
icon = QUOTE(PATHTOF(UI\spare_barrel_ca.paa));
|
||||
};
|
||||
class GVAR(CheckTemperature) {
|
||||
displayName = CSTRING(CheckTemperatureShort);
|
||||
condition = "ace_overheating_enabled && {switch (currentWeapon _target) do {case (''): {false}; case (primaryWeapon _target); case (handgunWeapon _target): {true}; default {false}}}";
|
||||
exceptions[] = {"isNotInside", "isNotSitting"};
|
||||
statement = QUOTE( [ARR_3(_player, _target, currentWeapon _target)] call FUNC(checkTemperature); );
|
||||
icon = QUOTE(PATHTOF(UI\temp_ca.paa));
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
@ -2,17 +2,6 @@ class CfgWeapons {
|
||||
class ACE_ItemCore;
|
||||
class InventoryItem_Base_F;
|
||||
|
||||
class ACE_SpareBarrel: ACE_ItemCore {
|
||||
displayname = CSTRING(SpareBarrelName);
|
||||
descriptionshort = CSTRING(SpareBarrelDescription);
|
||||
//model = "";
|
||||
picture = QUOTE(PATHTOF(UI\spare_barrel_ca.paa));
|
||||
scope = 2;
|
||||
class ItemInfo: InventoryItem_Base_F {
|
||||
mass = 30;
|
||||
};
|
||||
};
|
||||
|
||||
class RifleCore;
|
||||
class Rifle: RifleCore {
|
||||
//Mean Rounds Between Stoppages (this will be scaled based on the barrel temp)
|
||||
|
@ -1,5 +1,7 @@
|
||||
|
||||
PREP(calculateCooling);
|
||||
PREP(canUnjam);
|
||||
PREP(checkSpareBarrelsTemperatures);
|
||||
PREP(checkTemperature);
|
||||
PREP(clearJam);
|
||||
PREP(displayTemperature);
|
||||
@ -7,8 +9,12 @@ PREP(firedEH);
|
||||
PREP(getWeaponData);
|
||||
PREP(handleTakeEH);
|
||||
PREP(jamWeapon);
|
||||
PREP(loadCoolestSpareBarrel);
|
||||
PREP(overheat);
|
||||
PREP(sendSpareBarrelsTemperaturesHint);
|
||||
PREP(swapBarrel);
|
||||
PREP(swapBarrelAssistant);
|
||||
PREP(swapBarrelCallback);
|
||||
PREP(updateSpareBarrelsTemperaturesThread);
|
||||
PREP(updateTemperature);
|
||||
PREP(updateTemperatureThread);
|
||||
|
@ -1,47 +1,69 @@
|
||||
// by esteldunedain
|
||||
#include "script_component.hpp"
|
||||
|
||||
if (isServer) then {
|
||||
GVAR(pseudoRandomList) = [];
|
||||
// Construct a list of pseudo random 2D vectors
|
||||
for "_i" from 0 to 30 do {
|
||||
GVAR(pseudoRandomList) pushBack [-1 + random 2, -1 + random 2];
|
||||
};
|
||||
publicVariable QGVAR(pseudoRandomList);
|
||||
if (hasInterface) then {
|
||||
// Add keybinds
|
||||
["ACE3 Weapons", QGVAR(unjamWeapon), localize LSTRING(UnjamWeapon),
|
||||
{
|
||||
// Conditions: canInteract
|
||||
if !([ACE_player, objNull, ["isNotInside"]] call EFUNC(common,canInteractWith)) exitWith {false};
|
||||
// Conditions: specific
|
||||
|
||||
if !(GVAR(enabled) && {[ACE_player] call FUNC(canUnjam)}) exitWith {false};
|
||||
|
||||
// Statement
|
||||
[ACE_player, currentMuzzle ACE_player, false] call FUNC(clearJam);
|
||||
true
|
||||
},
|
||||
{false},
|
||||
[19, [true, false, false]], false] call CBA_fnc_addKeybind; //SHIFT + R Key
|
||||
};
|
||||
|
||||
|
||||
if !(hasInterface) exitWith {};
|
||||
|
||||
GVAR(cacheWeaponData) = call CBA_fnc_createNamespace;
|
||||
GVAR(cacheAmmoData) = call CBA_fnc_createNamespace;
|
||||
GVAR(cacheSilencerData) = call CBA_fnc_createNamespace;
|
||||
|
||||
// Add keybinds
|
||||
["ACE3 Weapons", QGVAR(unjamWeapon), localize LSTRING(UnjamWeapon),
|
||||
{
|
||||
// Conditions: canInteract
|
||||
if !([ACE_player, objNull, ["isNotInside"]] call EFUNC(common,canInteractWith)) exitWith {false};
|
||||
// Conditions: specific
|
||||
|
||||
if !([ACE_player] call FUNC(canUnjam)) exitWith {false};
|
||||
|
||||
// Statement
|
||||
[ACE_player, currentMuzzle ACE_player, false] call FUNC(clearJam);
|
||||
true
|
||||
},
|
||||
{false},
|
||||
[19, [true, false, false]], false] call CBA_fnc_addKeybind; //SHIFT + R Key
|
||||
|
||||
|
||||
// Schedule cool down calculation of player weapons at (infrequent) regular intervals
|
||||
[] call FUNC(updateTemperatureThread);
|
||||
|
||||
["SettingsInitialized", {
|
||||
TRACE_1("SettingsInitialized eh", GVAR(enabled));
|
||||
if (!GVAR(enabled)) exitWith {};
|
||||
|
||||
if (isServer) then {
|
||||
GVAR(pseudoRandomList) = [];
|
||||
// Construct a list of pseudo random 2D vectors
|
||||
for "_i" from 0 to 30 do {
|
||||
GVAR(pseudoRandomList) pushBack [-1 + random 2, -1 + random 2];
|
||||
};
|
||||
publicVariable QGVAR(pseudoRandomList);
|
||||
|
||||
// Keep track of the temperature of stored spare barrels
|
||||
GVAR(storedSpareBarrels) = [] call CBA_fnc_hashCreate;
|
||||
|
||||
// Install event handlers for spare barrels
|
||||
["spareBarrelsSendTemperatureHint", FUNC(sendSpareBarrelsTemperaturesHint)] call EFUNC(common,addEventHandler);
|
||||
["spareBarrelsLoadCoolest", FUNC(loadCoolestSpareBarrel)] call EFUNC(common,addEventHandler);
|
||||
|
||||
// Schedule cool down calculation of stored spare barrels
|
||||
[] call FUNC(updateSpareBarrelsTemperaturesThread);
|
||||
};
|
||||
|
||||
if !(hasInterface) exitWith {};
|
||||
|
||||
GVAR(cacheWeaponData) = call CBA_fnc_createNamespace;
|
||||
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;
|
||||
|
||||
// Register fire event handler
|
||||
["firedPlayer", DFUNC(firedEH)] call EFUNC(common,addEventHandler);
|
||||
// Only add eh to non local players if dispersion is enabled
|
||||
if (GVAR(overheatingDispersion)) then {
|
||||
["firedPlayerNonLocal", DFUNC(firedEH)] call EFUNC(common,addEventHandler);
|
||||
};
|
||||
|
||||
// Schedule cool down calculation of player weapons at (infrequent) regular intervals
|
||||
[] call FUNC(updateTemperatureThread);
|
||||
|
||||
// Install event handler to display temp when a barrel was swapped
|
||||
["showWeaponTemperature", DFUNC(displayTemperature)] call EFUNC(common,addEventHandler);
|
||||
// Install event handler to initiate an assisted barrel swap
|
||||
["initiateSwapBarrelAssisted", DFUNC(swapBarrel)] call EFUNC(common,addEventHandler);
|
||||
|
||||
}] call EFUNC(common,addEventHandler);
|
||||
|
@ -4,4 +4,16 @@ ADDON = false;
|
||||
|
||||
#include "XEH_PREP.hpp"
|
||||
|
||||
if (isNil "CBA_fnc_getMagazineIndex") then {
|
||||
CBA_fnc_getMagazineIndex = {
|
||||
params [["_unit", objNull, [objNull]], ["_magazine", "", [""]]];
|
||||
|
||||
private _displayName = getText (configFile >> "CfgMagazines" >> _magazine >> "displayName");
|
||||
|
||||
if (_displayName isEqualTo "") exitWith {[]};
|
||||
|
||||
(magazinesDetail _unit select {_x find _displayName == 0}) apply {_x = _x splitString "[:]"; _x select (count _x - 1)};
|
||||
};
|
||||
};
|
||||
|
||||
ADDON = true;
|
||||
|
@ -18,6 +18,8 @@ class CfgPatches {
|
||||
|
||||
#include "CfgVehicles.hpp"
|
||||
|
||||
#include "CfgMagazines.hpp"
|
||||
|
||||
#include "CfgWeapons.hpp"
|
||||
|
||||
#include "ACE_Settings.hpp"
|
||||
|
58
addons/overheating/functions/fnc_calculateCooling.sqf
Normal file
58
addons/overheating/functions/fnc_calculateCooling.sqf
Normal file
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Author: esteldunedain
|
||||
* Calculate the cooling down of a weapon over a time interval.
|
||||
*
|
||||
* Argument:
|
||||
* 0: Initial temperature <NUMBER>
|
||||
* 1: Barrel mass <NUMBER>
|
||||
* 2: Time interval <NUMBER>
|
||||
*
|
||||
* Return value:
|
||||
* Final temperature <NUMBER>
|
||||
*
|
||||
* Example:
|
||||
* [_temperature, _barrelMass, _totalTime] call ace_overheating_fnc_calculateCooling
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
#include "script_component.hpp"
|
||||
|
||||
params ["_temperature", "_barrelMass", "_totalTime"];
|
||||
|
||||
// If a long time passed since the last shot, there's no need to calculate anything; the weapon should be cool
|
||||
if (_totalTime > 1800) exitWith {0};
|
||||
|
||||
//AR-15 (0.00570m bullet diameter) (barrel diameter usually 0.75" or 0.008255m radius)
|
||||
//Steel Denisty = 7850 m^3 / kg
|
||||
//Area of a cylinder (2/r)*(Pi * r^3 + V) - for a 0.008255m radius barrel -> Area = 210(1/meters) * Volume
|
||||
//Adjusted volume for being hollowed out is ~1.1x
|
||||
//So Area = 210 * 1.1 * (mass / 7850) = mass * 0.029427 (for steel near that diameter)
|
||||
|
||||
private _barrelSurface = _barrelMass * 0.029427;
|
||||
|
||||
TRACE_4("cooling",_temperature,_totalTime,_barrelMass,_barrelSurface);
|
||||
|
||||
private _time = 0;
|
||||
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 )
|
||||
) * _deltaTime / (_barrelMass * 466);
|
||||
|
||||
if (_temperature < 1) exitWith {0};
|
||||
|
||||
if (isNil "_temperature") exitWith {
|
||||
diag_log text format ["[ACE] ERROR: _totalTime = %1; _time = %2; _deltaTime = %3;", _totalTime, _time, _deltaTime];
|
||||
0
|
||||
};
|
||||
|
||||
_time = _time + _deltaTime;
|
||||
if (_time >= _totalTime) exitWith { _temperature max 0 };
|
||||
};
|
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Author: esteldunedain
|
||||
* Make the player check the temperature of his spare barrels
|
||||
*
|
||||
* Arguments:
|
||||
* 0: Player <OBJECT>
|
||||
*
|
||||
* Return Value:
|
||||
* None
|
||||
*
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
#include "script_component.hpp"
|
||||
|
||||
params ["_player"];
|
||||
|
||||
// Check canInteractWith:
|
||||
if (!([_player, objNull, ["isNotInside", "isNotSitting"]] call EFUNC(common,canInteractWith))) exitWith {};
|
||||
|
||||
// Make the unit go kneeling
|
||||
[_player] call EFUNC(common,goKneeling);
|
||||
|
||||
// Spawn a progress bar
|
||||
[
|
||||
5.0,
|
||||
[_player],
|
||||
{
|
||||
params ["_args", "_elapsedTime", "_totalTime", "_errorCode"];
|
||||
_args params ["_player"];
|
||||
// Time has enlapsed, ask the server to send the hint
|
||||
['spareBarrelsSendTemperatureHint', [_player, _player]] call EFUNC(common,serverEvent);
|
||||
},
|
||||
{},
|
||||
(localize LSTRING(CheckingSpareBarrelsTemperatures)),
|
||||
{true},
|
||||
["isNotInside", "isNotSitting"]
|
||||
] call EFUNC(common,progressBar);
|
@ -3,8 +3,9 @@
|
||||
* Make the player check the temperature of his weapon
|
||||
*
|
||||
* Arguments:
|
||||
* 0: Player <OBJECT>
|
||||
* 1: Weapon <STRING>
|
||||
* 0: Unit checking <OBJECT>
|
||||
* 1: Unit that has the weapon <OBJECT>
|
||||
* 2: Weapon <STRING>
|
||||
*
|
||||
* Return Value:
|
||||
* None
|
||||
@ -16,17 +17,18 @@
|
||||
*/
|
||||
#include "script_component.hpp"
|
||||
|
||||
params ["_player", "_weapon"];
|
||||
TRACE_2("params",_player,_weapon);
|
||||
params ["_assistant", "_gunner", "_weapon"];
|
||||
TRACE_3("params",_assistant,_gunner,_weapon);
|
||||
|
||||
// Play animation and report temperature
|
||||
private _action = getText (configFile >> "CfgWeapons" >> _weapon >> "ACE_checkTemperatureAction");
|
||||
|
||||
if (_action == "") then {
|
||||
_action = "Gear";
|
||||
private _action = "PutDown";
|
||||
if (_assistant isEqualTo _gunner) then {
|
||||
_action = getText (configFile >> "CfgWeapons" >> _weapon >> "ACE_checkTemperatureAction");
|
||||
if (_action == "") then {
|
||||
_action = "Gear";
|
||||
};
|
||||
};
|
||||
|
||||
_player playActionNow _action;
|
||||
_assistant playActionNow _action;
|
||||
|
||||
// Waits a sec before displaying the temperature
|
||||
[FUNC(displayTemperature), [_player, _weapon], 1.0] call EFUNC(common,waitAndExecute);
|
||||
[FUNC(displayTemperature), [_gunner, _weapon], 1.0] call EFUNC(common,waitAndExecute);
|
||||
|
53
addons/overheating/functions/fnc_loadCoolestSpareBarrel.sqf
Normal file
53
addons/overheating/functions/fnc_loadCoolestSpareBarrel.sqf
Normal file
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Author: esteldunedain
|
||||
* Collect the temperature of all the spare barrels a unit has and load the
|
||||
* coolest on the unit weapon. Runs on the server.
|
||||
*
|
||||
* Argument:
|
||||
* 0: Unit that has the spare barrels <OBJECT>
|
||||
* 1: Unit that has the weapon <OBJECT>
|
||||
* 2: Weapon <STRING>
|
||||
* 3: Weapon temp before switching <NUMBER>
|
||||
* 4: Mass of the removed barrel <NUMBER>
|
||||
*
|
||||
* Return value:
|
||||
* None
|
||||
*
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
#include "script_component.hpp"
|
||||
|
||||
params ["_assistant", "_gunner", "_weapon", "_weaponTemp", "_barrelMass"];
|
||||
TRACE_5("loadCoolestSpareBarrel1",_assistant,_gunner,_weapon,_weaponTemp,_barrelMass);
|
||||
|
||||
// Find all spare barrel the player has
|
||||
private _allBarrels = [_assistant, "ACE_SpareBarrel"] call CBA_fnc_getMagazineIndex;
|
||||
TRACE_1("_allBarrels",_allBarrels);
|
||||
if ((count _allBarrels) < 1) exitWith {};
|
||||
|
||||
// Determine which on is coolest
|
||||
private _coolestTemp = 10000;
|
||||
private _coolestMag = _allBarrels select 0;
|
||||
{
|
||||
private _temp = 0;
|
||||
if ([GVAR(storedSpareBarrels), _x] call CBA_fnc_hashHasKey) then {
|
||||
_temp = ([GVAR(storedSpareBarrels), _x] call CBA_fnc_hashGet) select 0;
|
||||
};
|
||||
TRACE_2("loadCoolestSpareBarrel4",_x,_temp);
|
||||
if (_temp < _coolestTemp) then {
|
||||
_coolestTemp = _temp;
|
||||
_coolestMag = _x;
|
||||
};
|
||||
} forEach _allBarrels;
|
||||
TRACE_3("loadCoolestSpareBarrel5",_coolestTemp,_coolestMag,_weaponTemp);
|
||||
|
||||
// The new weapon temperature is similar to the coolest barrel
|
||||
// Publish the new temperature value
|
||||
_gunner setVariable [format [QGVAR(%1_temp), _weapon], _coolestTemp, true];
|
||||
|
||||
// Heat up the coolest barrel to the former weapon temperature
|
||||
[GVAR(storedSpareBarrels), _coolestMag, [_weaponTemp, ACE_Time, _barrelMass]] call CBA_fnc_hashSet;
|
||||
|
||||
// Send an event so the machines of the assistant and gunner can show the hint
|
||||
["showWeaponTemperature", [_assistant, _gunner], [_gunner, _weapon]] call EFUNC(common,targetEvent);
|
@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Author: esteldunedain
|
||||
* Collect the temperature of all the spare barrels a unit has and send a hint
|
||||
* to a client. Runs on the server.
|
||||
*
|
||||
* Argument:
|
||||
* 0: Target unit of the hint <OBJECT>
|
||||
* 1: Unit that has the spare barrels <STRING>
|
||||
*
|
||||
* Return value:
|
||||
* None
|
||||
*
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
#include "script_component.hpp"
|
||||
|
||||
params ["_player","_unit"];
|
||||
|
||||
// Find all spare barrel the player has
|
||||
TRACE_2("sendSpareBarrelsTemperatureHunt",_player,_unit);
|
||||
private _allBarrels = [_unit, "ACE_SpareBarrel"] call CBA_fnc_getMagazineIndex;
|
||||
TRACE_1("_allBarrels",_allBarrels);
|
||||
if ((count _allBarrels) < 1) exitWith {};
|
||||
|
||||
// Determine the temp of each barrel
|
||||
private _temps = [];
|
||||
{
|
||||
private _temp = 0;
|
||||
if ([GVAR(storedSpareBarrels), _x] call CBA_fnc_hashHasKey) then {
|
||||
_temp = ([GVAR(storedSpareBarrels), _x] call CBA_fnc_hashGet) select 0;
|
||||
};
|
||||
_temps pushBack _temp;
|
||||
} forEach _allBarrels;
|
||||
TRACE_1("_temps",_temps);
|
||||
|
||||
// Count cool
|
||||
private _countCool = {_x < 20} count _temps;
|
||||
private _countWarm = {(_x >= 20) && (_x < 100)} count _temps;
|
||||
private _countHot = {(_x >= 100) && (_x < 200)} count _temps;
|
||||
private _countVeryHot = {(_x >= 200) && (_x < 600)} count _temps;
|
||||
private _countExtremelyHot = {_x >= 600} count _temps;
|
||||
private _output = ["%1 %2%3%4 %5%6%7 %8%9%10 %11%12%13 %14"];
|
||||
private _size = 1.0;
|
||||
if (_countCool > 0) then {
|
||||
_output pushBack _countCool;
|
||||
_output pushBack LSTRING(BarrelCool);
|
||||
_output pushBack "<br/>";
|
||||
_size = _size + 0.5;
|
||||
};
|
||||
if (_countWarm > 0) then {
|
||||
_output pushBack _countWarm;
|
||||
_output pushBack LSTRING(BarrelWarm);
|
||||
_output pushBack "<br/>";
|
||||
_size = _size + 0.5;
|
||||
};
|
||||
if (_countHot > 0) then {
|
||||
_output pushBack _countHot;
|
||||
_output pushBack LSTRING(BarrelHot);
|
||||
_output pushBack "<br/>";
|
||||
_size = _size + 0.5;
|
||||
};
|
||||
if (_countVeryHot > 0) then {
|
||||
_output pushBack _countVeryHot;
|
||||
_output pushBack LSTRING(BarrelVeryHot);
|
||||
_output pushBack "<br/>";
|
||||
_size = _size + 0.5;
|
||||
};
|
||||
if (_countExtremelyHot > 0) then {
|
||||
_output pushBack _countExtremelyHot;
|
||||
_output pushBack LSTRING(BarrelExtremelyHot);
|
||||
_size = _size + 0.5;
|
||||
};
|
||||
|
||||
TRACE_1("_output",_output);
|
||||
["displayTextStructured", [_player], [_output, _size, _player]] call EFUNC(common,targetEvent);
|
@ -3,29 +3,35 @@
|
||||
* Make a unit start swapping it's barrel
|
||||
*
|
||||
* Argument:
|
||||
* 0: Unit <OBJECT>
|
||||
* 1: Weapon <STRING>
|
||||
* 0: Unit initiating the action <OBJECT>
|
||||
* 1: Unit that has the weapon <OBJECT>
|
||||
* 2: Weapon <STRING>
|
||||
*
|
||||
* Return value:
|
||||
* None
|
||||
*
|
||||
* Example:
|
||||
* [player, currentWeapon player] call ace_overheating_fnc_swapBarrel
|
||||
* [cursorTarget, player, currentWeapon player] call ace_overheating_fnc_swapBarrel
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
#include "script_component.hpp"
|
||||
|
||||
params ["_player", "_weapon"];
|
||||
TRACE_2("params",_player,_weapon);
|
||||
params ["_assistant", "_gunner", "_weapon"];
|
||||
TRACE_3("params",_assistant,_gunner,_weapon);
|
||||
|
||||
// Make the standing player kneel down
|
||||
if (stance _player != "PRONE") then {
|
||||
[_player, "amovpknlmstpsraswrfldnon", 1] call EFUNC(common,doAnimation);
|
||||
if (stance _gunner != "PRONE") then {
|
||||
[_gunner, "amovpknlmstpsraswrfldnon", 1] call EFUNC(common,doAnimation);
|
||||
};
|
||||
|
||||
// Barrel dismount gesture
|
||||
_player playActionNow QGVAR(GestureDismountMuzzle);
|
||||
_gunner playActionNow QGVAR(GestureDismountMuzzle);
|
||||
playSound "ACE_BarrelSwap";
|
||||
|
||||
[5, [_player, _weapon], {(_this select 0) call FUNC(swapBarrelCallback)}, {}, (localize LSTRING(SwappingBarrel))] call EFUNC(common,progressBar);
|
||||
private _duration = 3.0;
|
||||
if (_assistant isEqualTo _gunner) then {
|
||||
_duration = 5.0;
|
||||
};
|
||||
|
||||
[_duration, [_assistant,_gunner,_weapon], {(_this select 0) call FUNC(swapBarrelCallback)}, {}, (localize LSTRING(SwappingBarrel))] call EFUNC(common,progressBar);
|
||||
|
33
addons/overheating/functions/fnc_swapBarrelAssistant.sqf
Normal file
33
addons/overheating/functions/fnc_swapBarrelAssistant.sqf
Normal file
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Author: esteldunedain, Commy2
|
||||
* Make a unit start swapping the barrel of another unit
|
||||
*
|
||||
* Argument:
|
||||
* 0: Unit initiating the action <OBJECT>
|
||||
* 1: Unit that has the weapon <OBJECT>
|
||||
* 2: Weapon <STRING>
|
||||
*
|
||||
* Return value:
|
||||
* None
|
||||
*
|
||||
* Example:
|
||||
* [player, cursorTarget, currentWeapon cursorTarget] call ace_overheating_fnc_swapBarrelAssistant
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
#include "script_component.hpp"
|
||||
|
||||
params ["_assistant", "_gunner", "_weapon"];
|
||||
TRACE_3("params",_assistant,_gunner,_weapon);
|
||||
|
||||
// Make the standing player kneel down
|
||||
if (stance _assistant != "PRONE") then {
|
||||
[_assistant, "amovpknlmstpsraswrfldnon", 1] call EFUNC(common,doAnimation);
|
||||
};
|
||||
|
||||
// Barrel dismount gesture
|
||||
playSound "ACE_BarrelSwap";
|
||||
|
||||
[3, [_assistant, _gunner, _weapon], {}, {}, (localize LSTRING(SwappingBarrel))] call EFUNC(common,progressBar);
|
||||
|
||||
["initiateSwapBarrelAssisted", _gunner, [_assistant, _gunner, _weapon]] call EFUNC(common,objectEvent);
|
@ -1,10 +1,11 @@
|
||||
/*
|
||||
* Author: Commy2
|
||||
* Author: Commy2, esteldunedain
|
||||
* Swap barrel callback
|
||||
*
|
||||
* Argument:
|
||||
* 0: Unit <OBJECT>
|
||||
* 1: Weapon <STRING>
|
||||
* 0: Unit initiating the action <OBJECT>
|
||||
* 1: Unit that has the weapon <OBJECT>
|
||||
* 2: Weapon <STRING>
|
||||
*
|
||||
* Return value:
|
||||
* None
|
||||
@ -14,19 +15,26 @@
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
// #define DEBUG_MODE_FULL
|
||||
#include "script_component.hpp"
|
||||
|
||||
params ["_player", "_weapon"];
|
||||
TRACE_2("params",_player,_weapon);
|
||||
params ["_assistant", "_gunner", "_weapon"];
|
||||
TRACE_3("params",_assistant,_gunner,_weapon);
|
||||
|
||||
// Barrel mount gesture
|
||||
_player playAction QGVAR(GestureMountMuzzle);
|
||||
playSound "ACE_BarrelSwap";
|
||||
if (_assistant isEqualTo _gunner) then {
|
||||
// Barrel mount gesture
|
||||
_gunner playAction QGVAR(GestureMountMuzzle);
|
||||
playSound "ACE_BarrelSwap";
|
||||
};
|
||||
|
||||
// don't consume the barrel, but rotate through them.
|
||||
[localize LSTRING(SwappedBarrel), QUOTE(PATHTOF(UI\spare_barrel_ca.paa))] call EFUNC(common,displayTextPicture);
|
||||
private _temp = _gunner getVariable [format [QGVAR(%1_temp), _weapon], 0];
|
||||
private _barrelMass = 0.50 * (getNumber (configFile >> "CfgWeapons" >> _weapon >> "WeaponSlotsInfo" >> "mass") / 22.0) max 1.0;
|
||||
|
||||
// Instruct the server to load the coolest spare barrel into the weapon and
|
||||
// store the removed barrel with the former weapon temperature. The server
|
||||
// also updates the current weapon temperature to match that of the new
|
||||
// loaded barrel.
|
||||
["spareBarrelsLoadCoolest", [_assistant, _gunner, _weapon, _temp, _barrelMass]] call EFUNC(common,serverEvent);
|
||||
|
||||
// Publish the temperature variable
|
||||
_player setVariable [format [QGVAR(%1_temp), _weapon], 0, true];
|
||||
// Store the update time
|
||||
_player setVariable [format [QGVAR(%1_time), _weapon], ACE_time];
|
||||
_gunner setVariable [format [QGVAR(%1_time), _weapon], ACE_time];
|
||||
|
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Author: esteldunedain
|
||||
* Calculate cooldown of all the stored spare barrels.
|
||||
*
|
||||
* Argument:
|
||||
* None
|
||||
*
|
||||
* Return value:
|
||||
* None
|
||||
*
|
||||
* Example:
|
||||
* [] call ace_overheating_fnc_updateSpareBarrelsTemperaturesThread
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
// #define DEBUG_MODE_FULL
|
||||
#include "script_component.hpp"
|
||||
|
||||
private _pairs = [];
|
||||
TRACE_1("updateSpareBarrelsTemperaturesThread1",GVAR(storedSpareBarrels));
|
||||
[GVAR(storedSpareBarrels), {_pairs pushBack [_key, _value];}] call CBA_fnc_hashEachPair;
|
||||
TRACE_1("updateSpareBarrelsTemperaturesThread2",_pairs);
|
||||
{
|
||||
_x params ["_barrelMagazineID","_value"];
|
||||
_value params ["_initialTemp","_initialTime", "_barrelMass"];
|
||||
|
||||
// Calculate cooling
|
||||
private _finalTemp = [_initialTemp, _barrelMass, ACE_time - _initialTime] call FUNC(calculateCooling);
|
||||
TRACE_4("updateSpareBarrelsTemperaturesThread3",_barrelMagazineID,_initialTemp,_finalTemp,_barrelMass);
|
||||
if (_finalTemp < 5) then {
|
||||
// The barrel is cool enough to keep calculating. Remove it from the hash
|
||||
[GVAR(storedSpareBarrels), _barrelMagazineID] call CBA_fnc_hashRem;
|
||||
} else {
|
||||
// Store the new temp
|
||||
[GVAR(storedSpareBarrels), _barrelMagazineID, [_finalTemp, ACE_time, _barrelMass]] call CBA_fnc_hashSet;
|
||||
};
|
||||
} forEach _pairs;
|
||||
|
||||
// Schedule for execution again after 10 seconds
|
||||
[DFUNC(updateSpareBarrelsTemperaturesThread), [], 10] call EFUNC(common,waitAndExecute);
|
@ -29,50 +29,8 @@ private _lastTime = _unit getVariable [_timeVarName, 0];
|
||||
|
||||
private _barrelMass = 0.50 * (getNumber (configFile >> "CfgWeapons" >> _weapon >> "WeaponSlotsInfo" >> "mass") / 22.0) max 1.0;
|
||||
|
||||
_fnc_cooling = {
|
||||
params ["_temperature", "_barrelMass", "_totalTime"];
|
||||
|
||||
// If a long time passed since the last shot, there's no need to calculate anything; the weapon should be cool
|
||||
if (_totalTime > 1800) exitWith {0};
|
||||
|
||||
//AR-15 (0.00570m bullet diameter) (barrel diameter usually 0.75" or 0.008255m radius)
|
||||
//Steel Denisty = 7850 m^3 / kg
|
||||
//Area of a cylinder (2/r)*(Pi * r^3 + V) - for a 0.008255m radius barrel -> Area = 210(1/meters) * Volume
|
||||
//Adjusted volume for being hollowed out is ~1.1x
|
||||
//So Area = 210 * 1.1 * (mass / 7850) = mass * 0.029427 (for steel near that diameter)
|
||||
|
||||
private _barrelSurface = _barrelMass * 0.029427;
|
||||
|
||||
TRACE_4("cooling",_temperature,_totalTime,_barrelMass,_barrelSurface);
|
||||
|
||||
private _time = 0;
|
||||
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 )
|
||||
) * _deltaTime / (_barrelMass * 466);
|
||||
|
||||
if (_temperature < 1) exitWith {0};
|
||||
|
||||
if (isNil "_temperature") exitWith {
|
||||
diag_log text format ["[ACE] ERROR: _totalTime = %1; _time = %2; _deltaTime = %3;", _totalTime, _time, _deltaTime];
|
||||
0
|
||||
};
|
||||
|
||||
_time = _time + _deltaTime;
|
||||
if (_time >= _totalTime) exitWith { _temperature max 0 };
|
||||
};
|
||||
};
|
||||
|
||||
// Calculate cooling
|
||||
_temperature = [_temperature, _barrelMass, ACE_time - _lastTime] call _fnc_cooling;
|
||||
_temperature = [_temperature, _barrelMass, ACE_time - _lastTime] call FUNC(calculateCooling);
|
||||
TRACE_1("cooledTo",_temperature);
|
||||
// Calculate heating
|
||||
// Steel Heat Capacity = 466 J/(Kg.K)
|
||||
|
@ -251,6 +251,12 @@
|
||||
<Italian>Sto controllando la temperatura...</Italian>
|
||||
<Russian>Проверка температуры...</Russian>
|
||||
</Key>
|
||||
<Key ID="STR_ACE_Overheating_CheckTemperatureSpareBarrelsShort">
|
||||
<English>Check spare barrels temperatures</English>
|
||||
</Key>
|
||||
<Key ID="STR_ACE_Overheating_CheckingSpareBarrelsTemperatures">
|
||||
<English>Checking spare barrels temperatures...</English>
|
||||
</Key>
|
||||
<Key ID="STR_ACE_Overheating_Temperature">
|
||||
<English>Temperature</English>
|
||||
<German>Temperatur</German>
|
||||
@ -263,5 +269,28 @@
|
||||
<Italian>Temperatura</Italian>
|
||||
<Russian>Температура</Russian>
|
||||
</Key>
|
||||
<Key ID="STR_ACE_Overheating_BarrelCool">
|
||||
<English>Cool Spare Barrel/s</English>
|
||||
</Key>
|
||||
<Key ID="STR_ACE_Overheating_BarrelWarm">
|
||||
<English>Warm Spare Barrel/s</English>
|
||||
</Key>
|
||||
<Key ID="STR_ACE_Overheating_BarrelHot">
|
||||
<English>Hot Spare Barrel/s</English>
|
||||
</Key>
|
||||
<Key ID="STR_ACE_Overheating_BarrelVeryHot">
|
||||
<English>Very Hot Spare Barrel/s</English>
|
||||
</Key>
|
||||
<Key ID="STR_ACE_Overheating_BarrelExtremelyHot">
|
||||
<English>Extremely Hot Spare Barrel/s</English>
|
||||
</Key>
|
||||
<Key ID="STR_ACE_Overheating_enabled_displayName">
|
||||
<English>Overheating Enabled</English>
|
||||
<German>Überhitzen Aktiviert</German>
|
||||
<Spanish>Activada Sobrecalentamiento</Spanish>
|
||||
</Key>
|
||||
<Key ID="STR_ACE_Overheating_enabled_description">
|
||||
<English>Master enable for the overheating/jamming module</English>
|
||||
</Key>
|
||||
</Package>
|
||||
</Project>
|
Loading…
Reference in New Issue
Block a user