Added cse_sys_weaponheat source.

This commit is contained in:
Thomas Kooi 2015-01-12 23:31:53 +01:00
parent 592e40ff0c
commit c8f832bdca
44 changed files with 971 additions and 0 deletions

View File

@ -0,0 +1,27 @@
class CfgFunctions {
class CSE {
class WeaponHeat {
file = "cse\cse_sys_weaponheat\functions";
class canSwapBarrel_wh { recompile = 1; };
class clearMalfunction_wh { recompile = 1; };
class generateMalfunctions_wh { recompile = 1; };
class generateHeatHaze_wh { recompile = 1; };
class generateSmoke_wh { recompile = 1; };
class getBarrelMass_wh { recompile = 1; };
class getBarrelTemperature_wh { recompile = 1; };
class getBulletMass_wh { recompile = 1; };
class getIn_wh { recompile = 1; };
class getOut_wh { recompile = 1; };
class handleWeaponHeat_wh { recompile = 1; };
class jamWeapon_wh { recompile = 1; };
class put_wh { recompile = 1; };
class registerBarrelExchangeActions_wh { recompile = 1; };
class setBarrelTemperature_wh { recompile = 1; };
class swapBarrel_wh { recompile = 1; };
class take_wh { recompile = 1; };
class removeParticleEffectHeat_WH { recompile = 1; };
class addParticleEffectHeat_WH { recompile = 1; };
class setParticleEffectHeat_WH { recompile = 1; };
};
};
};

View File

@ -0,0 +1,33 @@
class CfgSounds
{
class cse_weaponheat_barrel_exchange
{
name="cse_weaponheat_barrel_exchange";
sound[]={"\cse\cse_sys_weaponheat\sound\barrel_exchange.wav",1,1};
titles[]={};
};
class cse_jamming_rifle
{
name="cse_jamming_rifle";
sound[]={"\cse\cse_sys_weaponheat\sound\jamming_rifle.wav",1,1};
titles[]={};
};
class cse_jamming_pistol
{
name="cse_jamming_pistol";
sound[]={"\cse\cse_sys_weaponheat\sound\jamming_pistol.wav",1,1};
titles[]={};
};
class cse_fixing_rifle
{
name="cse_fixing_rifle";
sound[]={"\cse\cse_sys_weaponheat\sound\fixing_rifle.wav",1,1};
titles[]={};
};
class cse_fixing_pistol
{
name="cse_fixing_pistol";
sound[]={"\cse\cse_sys_weaponheat\sound\fixing_pistol.wav",1,1};
titles[]={};
};
};

View File

@ -0,0 +1,46 @@
class CfgVehicles {
class Logic;
class Module_F: Logic {
class ArgumentsBaseUnits {
};
};
class cse_sys_weaponheat: Module_F {
scope = 2;
displayName = "Weapon Heat [CSE]";
icon = "\cse\cse_main\data\cse_rifle_module.paa";
category = "cseModules";
function = "cse_fnc_initalizeModule_F";
functionPriority = 1;
isGlobal = 1;
isTriggerActivated = 0;
class Arguments {
class genericSpareBarrel {
displayName = "Generic Spare Barrel";
description = "Allow players to use a generic spare barrel that fits all weapons.";
typeName = "BOOL";
defaultValue = true;
};
};
class ModuleDescription {
description = "Weapon heating";
};
};
class Item_Base_F;
class cse_sparebarrelbagItem: Item_Base_F
{
scope = 2;
scopeCurator = 2;
displayName = "Spare Barrel Bag";
author = "Combat Space Enhancement";
vehicleClass = "Items";
class TransportItems
{
class cse_sparebarrelbag
{
name = "cse_sparebarrelbag";
count = 1;
};
};
};
};

View File

@ -0,0 +1,49 @@
class CfgWeapons {
class ItemCore;
class InventoryItem_Base_F;
class cse_sparebarrelbag: ItemCore
{
scope=2;
displayName="Spare Barrel Bag";
// TODO: Replace the place holders
model="\cse\cse_sys_weaponheat\equipment\barrel_m16.p3d";
picture="\cse\cse_sys_weaponheat\equipment\img\barrel_m16.paa";
descriptionShort="Spare Barrel Bag";
class ItemInfo: InventoryItem_Base_F
{
mass=40;
type=201;
};
};
class cse_barrel_m16: cse_sparebarrelbag
{
displayName="M16 Spare Barrel";
descriptionShort="M16 Spare Barrel";
model="\cse\cse_sys_weaponheat\equipment\barrel_m16.p3d";
picture="\cse\cse_sys_weaponheat\equipment\img\barrel_m16.paa";
};
class cse_barrel_ak74: cse_sparebarrelbag
{
displayName="AK Spare Barrel";
descriptionShort="AK Spare Barrel";
model="\cse\cse_sys_weaponheat\equipment\barrel_ak74.p3d";
picture="\cse\cse_sys_weaponheat\equipment\img\barrel_ak74.paa";
};
class Rifle_Base_F;
class arifle_MX_Base_F;
class arifle_MX_SW_F: arifle_MX_Base_F
{
cse_exchangeableBarrel = 1;
};
class LMG_Zafir_F: Rifle_Base_F
{
cse_exchangeableBarrel = 1;
};
class LMG_Mk200_F: Rifle_Base_F
{
cse_exchangeableBarrel = 1;
};
};

View File

@ -0,0 +1,18 @@
class Combat_Space_Enhancement {
class CfgModules {
class cse_sys_weaponheat {
init = "call compile preprocessFile 'cse\cse_sys_weaponheat\init_sys_weaponheat.sqf';";
name = "Weapon Heating";
class EventHandlers {
class AllVehicles {
GetIn = "call cse_fnc_getIn_wh; false";
GetOut = "call cse_fnc_getOut_wh; false";
};
class CAManBase {
killed = "[_this select 1] call cse_fnc_removeParticleEffectHeat_WH;";
};
};
};
};
};

View File

@ -0,0 +1,25 @@
class CfgPatches {
class cse_sys_weaponheat {
units[] = {"cse_sparebarrelbagItem"};
weapons[] = {};
requiredVersion = 1.0;
requiredAddons[] = {"cse_f_eh","cse_main", "A3_Weapons_F", "A3_Weapons_F_Rifles_MX"};
version = "0.10.0_rc";
author[] = {"Combat Space Enhancement"};
authorUrl = "http://csemod.com";
};
};
class cse_sys_weaponheat {
class PreloadAddons {
class cse_sys_weaponheat {
list[] = {"cse_sys_weaponheat"};
};
};
};
#include "CfgVehicles.h"
#include "CfgWeapons.h"
#include "CfgSounds.h"
#include "CfgFunctions.h"
#include "Combat_Space_Enhancement.h"

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,22 @@
ambient[]={0.80000001,0.80000001,0.80000001,0};
diffuse[]={0.80000001,0.80000001,0.80000001,0};
forcedDiffuse[]={0,0,0,0};
emmisive[]={0,0,0,0};
specular[]={0.2,0.2,0.2,0};
specularPower=10.6;
renderFlags[]=
{
"NoAlphaWrite"
};
PixelShaderID="Glass";
VertexShaderID="Glass";
class Stage1
{
texture="#(argb,8,8,3)color(1,1,1,0.9)";
uvSource="none";
};
class Stage2
{
texture="a3\data_f\env_chrome_co.paa";
uvSource="none";
};

View File

@ -0,0 +1,92 @@
ambient[]={1.000000,1.000000,1.000000,1.000000};
diffuse[]={1.000000,1.000000,1.000000,1.000000};
forcedDiffuse[]={0.000000,0.000000,0.000000,0.000000};
emmisive[]={0.000000,0.000000,0.000000,1.000000};
specular[]={0.703999,0.703999,0.703999,0.000000};
specularPower=70.000000;
PixelShaderID="Super";
VertexShaderID="Super";
class Stage1
{
texture="cse\cse_sys_weaponheat\equipment\data\barrel_m16_nohq.paa";
uvSource="tex";
class uvTransform
{
aside[]={1.000000,0.000000,0.000000};
up[]={0.000000,1.000000,0.000000};
dir[]={0.000000,0.000000,0.000000};
pos[]={0.000000,0.000000,0.000000};
};
};
class Stage2
{
texture="#(argb,8,8,3)color(0.5,0.5,0.5,1,DT)";
uvSource="tex";
class uvTransform
{
aside[]={1.000000,0.000000,0.000000};
up[]={0.000000,1.000000,0.000000};
dir[]={0.000000,0.000000,0.000000};
pos[]={0.000000,0.000000,0.000000};
};
};
class Stage3
{
texture="#(argb,8,8,3)color(0,0,0,0,MC)";
uvSource="tex";
class uvTransform
{
aside[]={1.000000,0.000000,0.000000};
up[]={0.000000,1.000000,0.000000};
dir[]={0.000000,0.000000,0.000000};
pos[]={0.000000,0.000000,0.000000};
};
};
class Stage4
{
texture="#(argb,8,8,3)color(1,1,1,1,AS)";
uvSource="tex";
class uvTransform
{
aside[]={1.000000,0.000000,0.000000};
up[]={0.000000,1.000000,0.000000};
dir[]={0.000000,0.000000,0.000000};
pos[]={0.000000,0.000000,0.000000};
};
};
class Stage5
{
texture="#(argb,8,8,3)color(0,0.05,1,1,SMDI)";
uvSource="tex";
class uvTransform
{
aside[]={1.000000,0.000000,0.000000};
up[]={0.000000,1.000000,0.000000};
dir[]={0.000000,0.000000,0.000000};
pos[]={0.000000,0.000000,0.000000};
};
};
class Stage6
{
texture="#(ai,32,128,1)fresnel(0.98,1.02)";
uvSource="tex";
class uvTransform
{
aside[]={1.000000,0.000000,0.000000};
up[]={0.000000,1.000000,0.000000};
dir[]={0.000000,0.000000,0.000000};
pos[]={0.000000,0.000000,0.000000};
};
};
class Stage7
{
texture="cse\cse_sys_weaponheat\equipment\data\env_co.tga";
uvSource="tex";
class uvTransform
{
aside[]={1.000000,0.000000,0.000000};
up[]={0.000000,1.000000,0.000000};
dir[]={0.000000,0.000000,0.000000};
pos[]={0.000000,0.000000,0.000000};
};
};

Binary file not shown.

View File

@ -0,0 +1,16 @@
#define PI 3.14159265
#define ABSOLUTE_ZERO_IN_CELSIUS -273.15
#define KELVIN(t) (t - ABSOLUTE_ZERO_IN_CELSIUS)
#define CELSIUS(t) (t + ABSOLUTE_ZERO_IN_CELSIUS)
#define CENTIMETER(i) (i * 2.54)
#define STEFAN_BOLTZMANN_CONSTANT 0.00000005670373 // W / (m^2 * K^4)
#define HEAT_TRANSFER_COEFFICIENT_STEEL 25.0 // W / (m^2 * K)
#define HEAT_CAPACITY_STEEL 0.466 // J / (g * K)
// Source: http://www.engineeringtoolbox.com/emissivity-coefficients-d_447.html
#define EMISSIVITY_STAINLESS_STEEL 0.54
// Source http://www.azom.com/properties.aspx?ArticleID=965
// We have taken the average density for this
// (7.85 + 8.06 / 2) min + max / 2
#define DENSITY_STAINLESS_STEEL 7.955 // g / cm^3

View File

@ -0,0 +1,31 @@
/**
* fn_addParticleEffectsHeat_wh.sqf
* @Descr: Adds a heat effect for the units weapon.
* @Author: Glowbal
*
* @Arguments: [unit OBJECT]
* @Return: PARTICLE The particleeffect object
* @PublicAPI: false
*/
private ["_unit", "_currentParticleEffect", "_weaponDirection", "_particleEffect", "_rightHandPosition"];
_unit = _this select 0;
_currentParticleEffect = _unit getvariable "cse_particleEffect_Heat_WH";
if (!isnil "_currentParticleEffect") exitwith {_currentParticleEffect};
_rightHandPosition = ATLtoASL (_unit modelToWorld (_unit selectionPosition "RightHand"));
_weaponDirection = _unit weaponDirection _weapon;
_dummyObj = "cse_LogicDummy" createVehicleLocal [0,0,0];
_dummyObj attachTo [_unit, _weaponDirection vectorMultiply 0.2, "LeftHand"];
_particleEffect = "#particlesource" createVehicle (getPos _dummyObj);
_particleEffect setParticleCircle [0, [0, 0, 0]];
_particleEffect setParticleRandom [0.2, [0, 0, 0], [0.0, 0.0, 0], 0.1, 0.1, [0, 0, 0, 0], 0, 0];
_particleEffect setParticleParams [["\A3\data_f\ParticleEffects\Universal\Refract",1, 0, 1, 0], "", "Billboard", 3, 0.1, [0, 0, 0], [0, 0, 0.0], 0, 0.5, 0.5, 0.1, [1.0], [[1, 0.7, 0.7, 0.0]], [1], 0, 0, "", "", _dummyObj];
_particleEffect setDropInterval 0.04;
_unit setvariable ["cse_particleEffect_Heat_WH", _particleEffect];
_unit setvariable ["cse_particleEffect_Heat_dummyObj_WH", _dummyObj];
_particleEffect;

View File

@ -0,0 +1,10 @@
private ["_unit", "_weapon"];
_unit = _this select 0;
_weapon = _this select 1;
if (getNumber(configFile >> "CfgWeapons" >> _weapon >> "cse_exchangeableBarrel") != 1) exitWith { false };
if ([_unit, getText(configFile >> "CfgWeapons" >> _weapon >> "cse_spareBarrel")] call cse_fnc_hasItem) exitWith { true };
if (cse_genericSpareBarrel_wh && [_unit, "cse_sparebarrelbag"] call cse_fnc_hasItem) exitWith { true };
false

View File

@ -0,0 +1,32 @@
/**
* fn_jamWeapon_wh.sqf
* @Descr: Clears the malfunction of a given unit/weapon/muzzle combination
* @Author: Ruthberg
*
* @Arguments: [unit OBJECT, weapon STRING, muzzle STRING]
* @Return: nil
* @PublicAPI: true
*/
#define SUCCESS_RATE 0.9
private ["_unit", "_weapon", "_muzzle"];
_unit = _this select 0;
_weapon = _this select 1;
_muzzle = _this select 2;
if ((currentMuzzle _unit) != _muzzle) exitWith {};
if (_unit getVariable["CSE_ClearingMalfunction", false]) exitWith {};
if (!(_unit getVariable[format["CSE_Malfunction_%1_%2", _weapon, _muzzle], false])) exitWith {};
// Beginning of the procedure to clear the malfunction
_unit setVariable["CSE_ClearingMalfunction", true, false];
_unit playActionNow "reloadMagazine";
sleep 2; // TODO: This should depend on the weapon type (maybe consider the weapon mass)
if (SUCCESS_RATE > random 1) then {
_unit setVariable [format["CSE_Malfunction_%1_%2", _weapon, _muzzle], false, !(_unit isKindOf "Man")];
};
// End of the procedure to clear the malfunction
_unit setVariable["CSE_ClearingMalfunction", false, false];

View File

@ -0,0 +1,35 @@
#define MAX_TEMP_HEAT_EFFECT 1000
private ["_unit", "_weapon", "_muzzle", "_ammo", "_malfunctionRate"];
_unit = _this select 0;
_weapon = _this select 1;
_muzzle = _this select 2;
_ammo = _this select 3;
_barrelTemperature = _this select 4;
if (_unit getVariable[format["cse_weaponHeat_TemperatureEffects_%1_%2", _weapon, _muzzle], false]) exitWith {};
if (_barrelTemperature >= 100) then {
_unit setvariable [format["cse_weaponHeat_TemperatureEffects_%1_%2", _weapon, _muzzle], true];
[_unit, _weapon, _muzzle, _ammo] spawn {
_unit = _this select 0;
_weapon = _this select 1;
_muzzle = _this select 2;
_ammo = _this select 3;
_particleEffect = [_unit] call cse_fnc_addParticleEffectHeat_WH;
_currentTemp = [_unit, _weapon, _muzzle, _ammo] call cse_fnc_getBarrelTemperature_wh;
while {_currentTemp >= 100 && alive _unit} do {
_currentTemp = [_unit, _weapon, _muzzle, _ammo] call cse_fnc_getBarrelTemperature_wh;
if (currentWeapon _unit == _weapon) then {
_percentage = 0 max (_currentTemp / MAX_TEMP_HEAT_EFFECT) min 1;
[_unit, _percentage] call cse_fnc_setParticleEffectHeat_WH;
} else {
[_unit, 0] call cse_fnc_setParticleEffectHeat_WH;
};
sleep 1;
};
[_unit] call cse_fnc_removeParticleEffectHeat_WH;
};
};

View File

@ -0,0 +1,53 @@
/**
* fn_generateMalfunctions_wh.sqf
* @Descr: Generates weapon malfunctions based on barrel temperature and weapon cleanness
* @Author: Ruthberg
*
* @Arguments: [unit OBJECT, weapon STRING, muzzle STRING, barrelTemperature NUMBER]
* @Return: nil
* @PublicAPI: false
*/
#define MALFUNCTION_BASE_RATE 0.0001 // Base rate 1 : 10000
private ["_unit", "_weapon", "_muzzle", "_malfunctionRate"];
_unit = _this select 0;
_weapon = _this select 1;
_muzzle = _this select 2;
_barrelTemperature = _this select 3;
if (_unit getVariable[format["CSE_Malfunction_%1_%2", _weapon, _muzzle], false]) exitWith {
switch (getNumber (configFile >> "CfgWeapons" >> _weapon >> "type")) do {
case 1: {
playSound3d["\cse\cse_sys_weaponheat\sound\jamming_rifle.wav", _unit, false, getPos _unit, 1.5, 1, 10];
};
case 2: {
playSound3d["\cse\cse_sys_weaponheat\sound\jamming_pistol.wav", _unit, false, getPos _unit, 1.5, 1, 10];
};
default {
};
};
};
_malfunctionRate = MALFUNCTION_BASE_RATE max (_barrelTemperature / 1500)^4;
// TODO: Add consideration of weapon cleanness
if (_malfunctionRate > random 1) then {
[_unit, _weapon, _muzzle] call cse_fnc_jamWeapon_wh;
switch (getNumber (configFile >> "CfgWeapons" >> _weapon >> "type")) do {
case 1: {
playSound3d["\cse\cse_sys_weaponheat\sound\jamming_rifle.wav", _unit, false, getPos _unit, 15, 1, 10];
};
case 2: {
playSound3d["\cse\cse_sys_weaponheat\sound\jamming_pistol.wav", _unit, false, getPos _unit, 15, 1, 10];
};
default {
};
};
};

View File

@ -0,0 +1,29 @@
/**
* fn_generateSmoke_wh.sqf
* @Descr: Generates a smoke effect based on barrel temperature
* @Author: Ruthberg
*
* @Arguments: [unit OBJECT, weapon STRING, muzzle STRING, _bullet OBJECT, barrelTemperature NUMBER]
* @Return: nil
* @PublicAPI: false
*/
private ["_unit", "_weapon", "_muzzle", "_bullet", "_bulletPosition", "_weaponDirection", "_intensity", "_particlePosition", "_distance"];
_unit = _this select 0;
_weapon = _this select 1;
_muzzle = _this select 2;
_bullet = _this select 3;
_barrelTemperature = _this select 4;
if (_barrelTemperature < 80) exitWith {};
_bulletPosition = getPosATL _bullet;
_weaponDirection = _unit weaponDirection _weapon;
_intensity = (_barrelTemperature / 2000) min 0.3;
{
_distance = 0.05 + random 0.27;
_particlePosition = _bulletPosition vectorAdd (_weaponDirection vectorMultiply _distance);
drop ["\A3\data_f\missileSmoke", "", "Billboard", 1, 1.5,_particlePosition, [0, 0, 0], 1, 7.0, 5.5, 0.075,[0.28, 0.33, 0.37], [[.5, .5, .5, _intensity], [.6, .6, .6,_intensity*0.2]], [random 1,random 1,random 1], 0, 0, "", "", ""];
} forEach [0, 1];

View File

@ -0,0 +1,31 @@
/**
* fn_getBarrelMass_wh.sqf
* @Descr: Calculates the mass of the barrel
* @Author: Ruthberg
*
* @Arguments: [unit OBJECT, weapon STRING, muzzle STRING]
* @Return: barrel mass in gramm
* @PublicAPI: false
*/
private ["_unit", "_weapon", "_muzzle", "_barrelMass"];
_unit = _this select 0;
_weapon = _this select 1;
_muzzle = _this select 2;
_barrelMass = 0.40 * (getNumber (configFile >> "CfgWeapons" >> _weapon >> "WeaponSlotsInfo" >> "mass")) * 50; // estimated barrel mass in gramm
if (_barrelMass == 0) then {
// TODO: Find a way to estimate the barrel mass in this case
_barrelMass = 4000;
if (!(_unit isKindOf "Man")) then {
_barrelMass = _barrelMass * 10;
};
};
switch (_weapon) do {
case (primaryWeapon _unit) : { _barrelMass = 1000 max _barrelMass };
case (secondaryWeapon _unit) : { _barrelMass = 2000 max _barrelMass };
case (handgunWeapon _unit) : { _barrelMass = 400 max _barrelMass };
};
_barrelMass

View File

@ -0,0 +1,62 @@
/**
* fn_getBarrelTemperature_wh.sqf
* @Descr: Calculates the current barrel temperature
* @Author: Ruthberg
*
* @Arguments: [unit OBJECT, weapon STRING, muzzle STRING, ammo STRING]
* @Return: barrel temperature in degree celsius
* @PublicAPI: true
*/
#include "defines.h"
private ["_unit", "_weapon", "_muzzle", "_ammo", "_barrelMass", "_barrelLength", "_barrelCaliber", "_area", "_barrelDiameter", "_ambientTemperature", "_barrelTemperature", "_lastUpdateTime", "_deltaTime", "_simulationStep", "_fluidVelocity", "_dynamicHeatTransferCoefficient"];
_unit = _this select 0;
_weapon = _this select 1;
_muzzle = _this select 2;
_ammo = _this select 3;
_barrelMass = [_unit, _weapon, _muzzle] call cse_fnc_getBarrelMass_wh;
_barrelSurface = _barrelMass * 0.00015; // Rough estimation based on barrel mass only
_barrelLength = getNumber(configFile >> "CfgWeapons" >> _weapon >> "AB_barrelLength");
_barrelCaliber = getNumber(configFile >> "CfgAmmo" >> _ammo >> "AB_caliber");
if (_barrelLength > 0 && _barrelCaliber > 0) then {
// Estimate barrel surface based on barrel mass and barrel length and barrel caliber
_area = _barrelMass / (DENSITY_STAINLESS_STEEL * PI * CENTIMETER(_barrelLength));
_barrelDiameter = sqrt(CENTIMETER(_barrelCaliber)^2 + 4 * _area);
_barrelSurface = _barrelDiameter * PI * CENTIMETER(_barrelLength);
_barrelSurface = _barrelSurface / 10000; // convert from m^2 to cm^2
};
_ambientTemperature = 15;
if (["cse_AB_moduleAdvancedBallistics"] call cse_fnc_isModuleEnabled_F) then {
_ambientTemperature = ((getPosASL _unit) select 2) call cse_ab_ballistics_fnc_get_temperature_at_height;
};
_barrelTemperature = _unit getVariable [format["CSE_BarrelTemperature_%1", _weapon], _ambientTemperature];
_lastUpdateTime = _unit getVariable [format["CSE_BarrelUpdateTime_%1", _weapon], diag_tickTime];
_deltaTime = diag_tickTime - _lastUpdateTime;
while {_deltaTime > 0} do {
_simulationStep = (_deltaTime min 1); // max step size 1 second
// TODO: Do we want conductive heat transfer from the barrel to other parts of the weapon?
// Source: https://de.wikipedia.org/wiki/W%C3%A4rme%C3%BCbergangskoeffizient
// Source: https://en.wikipedia.org/wiki/Combined_forced_and_natural_convection
_fluidVelocity = vectorMagnitude (wind vectorDiff (velocity _unit));
_dynamicHeatTransferCoefficient = 12 * sqrt(_fluidVelocity) + 2;
// Source: https://en.wikipedia.org/wiki/Convective_heat_transfer
_barrelTemperature = _barrelTemperature - (HEAT_TRANSFER_COEFFICIENT_STEEL + _dynamicHeatTransferCoefficient) * _barrelSurface * (_barrelTemperature - _ambientTemperature) / (HEAT_CAPACITY_STEEL * _barrelMass) * _simulationStep;
// Source: https://en.wikipedia.org/wiki/Thermal_radiation
_barrelTemperature = _barrelTemperature - EMISSIVITY_STAINLESS_STEEL * STEFAN_BOLTZMANN_CONSTANT * _barrelSurface * (KELVIN(_barrelTemperature)^4 - KELVIN(_ambientTemperature)^4) / (HEAT_CAPACITY_STEEL * _barrelMass) * _simulationStep;
_deltaTime = _deltaTime - _simulationStep;
};
_barrelTemperature

View File

@ -0,0 +1,25 @@
/**
* fn_getBulletMass_wh.sqf
* @Descr: Calculates the mass of the bullet
* @Author: Ruthberg
*
* @Arguments: ammo STRING
* @Return: bullet mass in gramm
* @PublicAPI: false
*/
private ["_ammo", "_bulletMass", "_caliber"];
_ammo = _this;
_bulletMass = getNumber(configFile >> "CfgAmmo" >> _ammo >> "AB_bulletMass");
if (_bulletMass == 0) then {
// Try to estimate the mass based on BIS caliber
// B_762x51_Ball: caliber 1.0 <--> 7.62 NATO M80: bullet mass 147 grain (9.46064086 g)
_caliber = getNumber(configFile >> "CfgAmmo" >> _ammo >> "caliber");
_bulletMass = _muzzleVelocity / 850 * _caliber * 9.46064086;
} else {
_bulletMass = _bulletMass * 0.06479891;
};
_bulletMass

View File

@ -0,0 +1,9 @@
private ["_vehicle", "_position", "_unit", "_handle"];
_vehicle = _this select 0;
_position = _this select 1;
_unit = _this select 2;
if (_unit != player) exitWith {};
_handle = _vehicle addEventHandler ["Fired", {_this call cse_fnc_handleWeaponHeat_wh}];
_vehicle setVariable ["cse_weapon_heat_fired_event_handler", _handle];

View File

@ -0,0 +1,12 @@
private ["_vehicle", "_position", "_unit", "_handle"];
_vehicle = _this select 0;
_position = _this select 1;
_unit = _this select 2;
if (_unit != player) exitWith {};
_handle = _vehicle getVariable "cse_weapon_heat_fired_event_handler";
if (!isNil "_handle") then {
_vehicle removeEventHandler ["Fired", _handle];
_vehicle setVariable ["cse_weapon_heat_fired_event_handler", nil];
};

View File

@ -0,0 +1,54 @@
/**
* fn_handleWeaponHeat_wh.sqf
* @Descr: Is expected to be triggered by the fired eventhandler from BI.
* @Author: Ruthberg
*
* @Arguments: []
* @Return:
* @PublicAPI: false
*
* Params:
* 1. unit: Object - Object the event handler is assigned to
* 2. weapon: String - Fired weapon
* 3. muzzle: String - Muzzle that was used
* 4. mode: String - Current mode of the fired weapon
* 5. ammo: String - Ammo used
* 6. magazine: String - magazine name which was used
* 7. projectile: Object - Object of the projectile that was shot (Arma 2: OA and onwards)
*/
#include "defines.h"
private ["_unit", "_weapon", "_muzzle", "_mode", "_ammo", "_bullet", "_barrelTemperature", "_muzzleVelocity", "_barrelMass", "_bulletMass", "_caliber", "_kineticEnergy"];
_unit = _this select 0;
_weapon = _this select 1;
_muzzle = _this select 2;
_mode = _this select 3;
_ammo = _this select 4;
_magazine = _this select 5;
_bullet = _this select 6;
if (!(isPlayer _unit) || !local _unit) exitWith {};
if (!(_bullet isKindOf "BulletBase")) exitWith {};
_barrelTemperature = [_unit, _weapon, _muzzle, _ammo] call cse_fnc_getBarrelTemperature_wh;
_muzzleVelocity = getNumber(configFile >> "CfgMagazines" >> _magazine >> "initSpeed");
_barrelMass = [_unit, _weapon, _muzzle] call cse_fnc_getBarrelMass_wh;
_bulletMass = _ammo call cse_fnc_getBulletMass_wh;
_kineticEnergy = 0.5 * (_bulletMass / 1000) * _muzzleVelocity^2; // in J
if (_kineticEnergy > 0 && _barrelMass > 0) then {
_barrelTemperature = _barrelTemperature + _kineticEnergy / (HEAT_CAPACITY_STEEL * _barrelMass);
[_unit, _weapon, _muzzle, _barrelTemperature] call cse_fnc_setBarrelTemperature_wh;
};
[_unit, _weapon, _muzzle, _barrelTemperature] call cse_fnc_generateMalfunctions_wh;
[_unit, _weapon, _muzzle, _ammo, _barrelTemperature] call cse_fnc_generateHeatHaze_wh;
[_unit, _weapon, _muzzle, _bullet, _barrelTemperature] call cse_fnc_generateSmoke_wh;
// TODO: High barrel temperature side effects
// cooking off?
// fire (particle effects)?
// glowing barrel at very high temperatures?

View File

@ -0,0 +1,38 @@
/**
* fn_jamWeapon_wh.sqf
* @Descr: Adds a malfunction to the given unit/weapon/muzzle combination
* @Author: Ruthberg
*
* @Arguments: [unit OBJECT, weapon STRING, muzzle STRING]
* @Return: nil
* @PublicAPI: true
*/
private ["_unit", "_weapon", "_muzzle", "_ID"];
_unit = _this select 0;
_weapon = _this select 1;
_muzzle = _this select 2;
_unit setVariable[format["CSE_Malfunction_%1_%2", _weapon, _muzzle], true, !(_unit isKindOf "CaManBase")];
_ID = format["CSE_Malfunction_ID_%1_%2_%3", _unit, _weapon, _muzzle];
[_ID, [_unit, _weapon, _muzzle, _ID], {
private ["_unit", "_weapon", "_muzzle", "_ID"];
_unit = _this select 0;
// necessary to prefent weapon jam from resetting when jumping in and out of vehicles.
if (vehicle _unit == _unit) then {
_weapon = _this select 1;
_muzzle = _this select 2;
_ID = _this select 3;
if (!(_unit getVariable[format["CSE_Malfunction_%1_%2", _weapon, _muzzle], false]) || !(_weapon in (weapons (vehicle _unit)))) exitWith {
_unit setVariable[format["CSE_Malfunction_%1_%2", _weapon, _muzzle], nil, !(_unit isKindOf "CaManBase")]; // clean up the malfunction variable.
[_ID] call cse_fnc_removeTaskFromPool_F;
};
if (currentWeapon _unit == _weapon && currentMuzzle _unit == _muzzle) then {
(vehicle _unit) setWeaponReloadingTime [_unit, _muzzle, 1];
};
};
}] call cse_fnc_addTaskToPool_f;

View File

@ -0,0 +1,19 @@
private ["_unit", "_container", "_item", "_itemCargo", "_ambientTemperature", "_spareBarrelTemperature", "_spareBarrelUpdateTime"];
_unit = _this select 0;
_container = _this select 1;
_item = _this select 2;
if (_unit != player) exitWith {};
if (!([configFile >> "CfgWeapons" >> _item, "cse_sparebarrelbag"] call cse_fnc_inheritsFrom)) exitWith {};
if (_container == uniformContainer player || _container == vestContainer player || _container == backpackContainer player) exitWith {};
_ambientTemperature = 15;
if (["cse_AB_moduleAdvancedBallistics"] call cse_fnc_isModuleEnabled_F) then {
_ambientTemperature = ((getPosASL _unit) select 2) call cse_ab_ballistics_fnc_get_temperature_at_height;
};
_spareBarrelTemperature = _unit getVariable [format["CSE_BarrelTemperature_%1", _item], _ambientTemperature];
_spareBarrelUpdateTime = _unit getVariable [format["CSE_BarrelUpdateTime_%1", _item], diag_tickTime];
_container setVariable [format["CSE_BarrelTemperature_%1", _item], _spareBarrelTemperature, true];
_container setVariable [format["CSE_BarrelUpdateTime_%1", _item], _spareBarrelUpdateTime, true];

View File

@ -0,0 +1,26 @@
if (isDedicated) exitwith{};
CSE_ICON_PATH = "cse\cse_gui\radialmenu\data\icons\";
cse_exchangeBarrelDisplaySubMenu = {
[_this] call cse_fnc_Debug;
private ["_subMenus"];
_subMenus = [];
if ([player, currentWeapon player, currentMuzzle player] call cse_fnc_canSwapBarrel_wh) then {
_subMenus pushBack ["Swap barrel", CSE_ICON_PATH + "icon_swap_barrels.paa", {
closeDialog 0;
[player, currentWeapon player, currentMuzzle player] spawn cse_fnc_swapBarrel_wh;
}, true, "Swaps out the barrel"];
};
[_this select 3, _subMenus, _this select 1, CSE_SELECTED_RADIAL_OPTION_N_GUI, true] call cse_fnc_openRadialSecondRing_GUI;
};
_entries = [
["Weapon", {([player, currentWeapon player, currentMuzzle player] call cse_fnc_canSwapBarrel_wh)}, CSE_ICON_PATH + "icon_lines_horizontal_s.paa", cse_exchangeBarrelDisplaySubMenu, "Shows available weapon interactions"]
];
["ActionMenu","equipment", _entries ] call cse_fnc_addMultipleEntriesToRadialCategory_F;

View File

@ -0,0 +1,26 @@
/**
* fn_removeParticleEffectHeat_wh.sqf
* @Descr: N/A
* @Author: Glowbal
*
* @Arguments: [unit OBJECT]
* @Return: BOOL Whatever or not a particle effect has been removed
* @PublicAPI: false
*/
private ["_unit", "_currentParticleEffect"];
_unit = _this select 0;
_currentParticleEffect = _unit getvariable "cse_particleEffect_Heat_WH";
if (!isnil "_currentParticleEffect") exitwith {
deleteVehicle _currentParticleEffect;
_unit setvariable ["cse_particleEffect_Heat_WH", nil];
_dummyObj = _unit getvariable "cse_particleEffect_Heat_dummyObj_WH";
deleteVehicle _dummyObj;
_unit setvariable ["cse_particleEffect_Heat_dummyObj_WH", nil];
true
};
false

View File

@ -0,0 +1,19 @@
/**
* fn_setBarrelTemperature_wh.sqf
* @Descr: Calculates the current barrel temperature
* @Author: Ruthberg
*
* @Arguments: [unit OBJECT, weapon STRING, muzzle STRING]
* @Return: barrel temperature in degree celsius
* @PublicAPI: true
*/
private ["_unit", "_weapon", "_muzzle", "_barrelTemperature"];
_unit = _this select 0;
_weapon = _this select 1;
_muzzle = _this select 2;
_barrelTemperature = _this select 3;
_unit setVariable [format["CSE_BarrelTemperature_%1", _weapon], _barrelTemperature, !(_unit isKindOf "Man")];
_unit setVariable [format["CSE_BarrelUpdateTime_%1" , _weapon], diag_tickTime, !(_unit isKindOf "Man")];

View File

@ -0,0 +1,11 @@
private ["_unit", "_percentage", "_currentParticleEffect", "_dummyObj"];
_unit = _this select 0;
_percentage = _this select 1;
_currentParticleEffect = _unit getvariable "cse_particleEffect_Heat_WH";
if (!isnil "_currentParticleEffect") then {
_dummyObj = _unit getvariable "cse_particleEffect_Heat_dummyObj_WH";
_dummyObj attachTo [_unit, (_unit weaponDirection _weapon) vectorMultiply 0.2, "LeftHand"];
_particleEffect setParticleParams [["\A3\data_f\ParticleEffects\Universal\Refract",1, 0, 1, 0], "", "Billboard", 1, 1.0, [0, 0, 0], [0, 0, 0.0], 0, 0.5, 0.5, 0.1, [1.0], [[1, 0.7, 0.7, 0.5 * _percentage]], [1], 0, 0, "", "", _dummyObj];
};

View File

@ -0,0 +1,48 @@
private ["_unit", "_weapon"];
_unit = _this select 0;
_weapon = _this select 1;
if (!([_unit, _weapon] call cse_fnc_canSwapBarrel_wh)) exitWith {};
if (vehicle _unit != _unit && {driver (vehicle _unit) == _unit || commander (vehicle _unit) == _unit || gunner (vehicle _unit) == _unit}) exitWith {};
if (vehicle _unit == _unit && currentWeapon _unit != "" && !(weaponLowered _unit) && (stance _unit != "PRONE")) then {
_unit action ["WeaponOnBack", _unit];
waitUntil { weaponLowered _unit }; // probably evil
};
[_unit, _weapon] spawn {
private ["_unit", "_weapon", "_spareBarrel", "_ambientTemperature", "_barrelTemperature", "_barrelUpdateTime", "_spareBarrelTemperature", "_spareBarrelUpdateTime"];
_unit = _this select 0;
_weapon = _this select 1;
CSE_ORIGINAL_POSITION_BARREL_EXCHANGE_EQ = getPos _unit;
// TODO: Prohibit the player from using his weapon during the barrel exchange progress
CSE_CONDITION_BARREL_EXCHANGE_EQ = {((vehicle _unit != _unit && driver (vehicle _unit) != _unit && commander (vehicle _unit) != _unit && gunner (vehicle _unit) != _unit) || (((getPos _unit) distance CSE_ORIGINAL_POSITION_BARREL_EXCHANGE_EQ) < 1 && (weaponLowered _unit || stance _unit == "PRONE")))};
// TODO: Play animation
playSound "cse_weaponheat_barrel_exchange";
_barrelExchangeSuccess = [15, CSE_CONDITION_BARREL_EXCHANGE_EQ] call cse_fnc_gui_loadingBar;
if (_barrelExchangeSuccess) then {
_spareBarrel = getText(configFile >> "CfgWeapons" >> _weapon >> "cse_spareBarrel");
if (!([_unit, _spareBarrel] call cse_fnc_hasItem)) then {
_spareBarrel = "cse_sparebarrelbag";
};
_ambientTemperature = 15;
if (["cse_AB_moduleAdvancedBallistics"] call cse_fnc_isModuleEnabled_F) then {
_ambientTemperature = ((getPosASL _unit) select 2) call cse_ab_ballistics_fnc_get_temperature_at_height;
};
_barrelTemperature = _unit getVariable [format["CSE_BarrelTemperature_%1", _weapon], _ambientTemperature];
_barrelUpdateTime = _unit getVariable [format["CSE_BarrelUpdateTime_%1", _weapon], diag_tickTime];
_spareBarrelTemperature = _unit getVariable [format["CSE_BarrelTemperature_%1", _spareBarrel], _ambientTemperature];
_spareBarrelUpdateTime = _unit getVariable [format["CSE_BarrelUpdateTime_%1", _spareBarrel], diag_tickTime];
_unit setVariable [format["CSE_BarrelTemperature_%1", _weapon], _spareBarrelTemperature];
_unit setVariable [format["CSE_BarrelUpdateTime_%1", _weapon], _spareBarrelUpdateTime];
_unit setVariable [format["CSE_BarrelTemperature_%1", _spareBarrel], _barrelTemperature];
_unit setVariable [format["CSE_BarrelUpdateTime_%1", _spareBarrel], _barrelUpdateTime];
};
};

View File

@ -0,0 +1,35 @@
private ["_unit", "_container", "_item", "_itemCargo", "_spareBarrelCount", "_ambientTemperature", "_spareBarrelTemperature", "_spareBarrelUpdateTime"];
_unit = _this select 0;
_container = _this select 1;
_item = _this select 2;
if (_unit != player) exitWith {};
if (!([configFile >> "CfgWeapons" >> _item, "cse_sparebarrelbag"] call cse_fnc_inheritsFrom)) exitWith {};
if (_container == uniformContainer player || _container == vestContainer player || _container == backpackContainer player) exitWith {};
_itemCargo = getItemCargo _container;
_spareBarrelCount = 0;
{
if (_x == _item) exitWith {
_spareBarrelCount = (_itemCargo select 1) select _forEachIndex;
};
} forEach (_itemCargo select 0);
_ambientTemperature = 15;
if (["cse_AB_moduleAdvancedBallistics"] call cse_fnc_isModuleEnabled_F) then {
_ambientTemperature = ((getPosASL _unit) select 2) call cse_ab_ballistics_fnc_get_temperature_at_height;
};
_spareBarrelTemperature = _ambientTemperature;
_spareBarrelUpdateTime = diag_tickTime;
if (_spareBarrelCount == 0) then {
// Assume that we took an already used spare barrel
_spareBarrelTemperature = _container getVariable [format["CSE_BarrelTemperature_%1", _item], _ambientTemperature];
_spareBarrelUpdateTime = _container getVariable [format["CSE_BarrelUpdateTime_%1", _item], diag_tickTime];
_container setVariable [format["CSE_BarrelTemperature_%1", _item], nil];
_container setVariable [format["CSE_BarrelUpdateTime_%1", _item], nil];
};
_unit setVariable [format["CSE_BarrelTemperature_%1", _item], _spareBarrelTemperature];
_unit setVariable [format["CSE_BarrelUpdateTime_%1", _item], _spareBarrelUpdateTime];

View File

@ -0,0 +1,31 @@
if (!hasInterface) exitWith {};
waitUntil {!isNil "cse_gui" && !isNil "cse_main"};
waitUntil {!isNull player};
player addEventHandler ["Fired", {_this call cse_fnc_handleWeaponHeat_wh}];
player addEventHandler ["Take", {_this call cse_fnc_take_wh}];
player addEventHandler ["Put", {_this call cse_fnc_put_wh}];
cse_sys_weaponheat = true;
cse_genericSpareBarrel_wh = true;
_args = _this;
{
_value = _x select 1;
if (!isNil "_value") then {
_name = _x select 0;
if (_name == "genericSpareBarrel") exitWith {
cse_genericSpareBarrel_wh = _value;
};
};
} forEach _args;
// Clear Malfunction
["cse_weaponheat_clear_malfunction", (["cse_weaponheat_clear_malfunction","action",[20, 0,1,0]] call cse_fnc_getKeyBindingFromProfile_F),
{
[player, currentWeapon player, currentMuzzle player] call cse_fnc_clearMalfunction_wh;
}] call cse_fnc_addKeyBindingForAction_F;
["cse_weaponheat_clear_malfunction","action", "Clear Malfunction", "Clear Malfunction"] call cse_fnc_settingsDefineDetails_F;
call cse_fnc_registerBarrelExchangeActions_wh;

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8" ?>
<Project name="Combat Space Enhancement">
<Package name="cse_sys_weaponheat">
<Container ID="WeaponHeat">
</Container>
</Package>
</Project>