Skip to content
Draft
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
4cb8671
smoke: new component
BrettMayson Jan 7, 2026
307aa65
headers
BrettMayson Jan 7, 2026
c4ea58b
Apply suggestions from code review
BrettMayson Jan 7, 2026
e9e58b4
Apply suggestion from @PabstMirror
BrettMayson Jan 7, 2026
7dcb19e
compat: aegis
BrettMayson Jan 7, 2026
8a958b5
compat: cup
BrettMayson Jan 7, 2026
838ab18
fix default breathing protection
BrettMayson Jan 9, 2026
1fbd5cd
fix var assignment
BrettMayson Jan 9, 2026
28bdebc
use 500
BrettMayson Jan 10, 2026
db09e41
compat: ws
BrettMayson Jan 10, 2026
c7a5c5f
don't check inside vehicles
BrettMayson Jan 11, 2026
1fd6f2c
Apply suggestions from code review
BrettMayson Jan 25, 2026
2a60198
don't seVariable every run
BrettMayson Jan 25, 2026
3ad6102
reduce pfh frequency, fix detection in tight spaces
BrettMayson Jan 25, 2026
7ff70cc
5 times per second
BrettMayson Jan 25, 2026
729c5a4
don't apply in tanks
BrettMayson Jan 25, 2026
a3b0064
Merge remote-tracking branch 'upstream/master' into smoke
BrettMayson Feb 2, 2026
9d26334
better vehicle handling
BrettMayson Feb 2, 2026
f6cb458
full protection allows recovery
BrettMayson Feb 2, 2026
dc53019
reuse code, various tweaks
BrettMayson Feb 2, 2026
33001b1
improve vehicle logic
BrettMayson Feb 2, 2026
7399a22
change helicopter config
BrettMayson Feb 3, 2026
276a584
add back sky check
BrettMayson Feb 3, 2026
98feb6b
Update addons/smoke/functions/fnc_isOpenSeat.sqf
BrettMayson Feb 3, 2026
4c3feef
remove false positive when going prone in some environments
BrettMayson Feb 16, 2026
58a346a
Apply suggestions from code review
BrettMayson Feb 20, 2026
3c0a940
Apply suggestions from code review
BrettMayson Feb 20, 2026
2759bea
Apply suggestion from @PabstMirror
PabstMirror Feb 20, 2026
fbc8503
Disable visual effects in spectator/zeus
PabstMirror Mar 7, 2026
9952aee
smoke -> irritants
BrettMayson Mar 20, 2026
a8a538c
Update addons/compat_cup_units/compat_cup_smoke/CfgGlasses.hpp
BrettMayson Mar 21, 2026
370da58
replace all ace_smoke -> ace_irritants
PabstMirror Mar 24, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions .hemtt/launch.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@ workshop = [
"450814997", # CBA_A3
]

[adt]
extends = "default"
workshop = [
"3499977893", # ADT
]

[rhs]
extends = "default"
workshop = [
Expand All @@ -27,10 +33,9 @@ workshop = [
]

[wardrobe]
extends = "default"
extends = "adt"
mission = "Wardrobe.VR"
workshop = [
"3499977893", # Advanced Developer Tools
"1779063631", # ZEN
# "751965892", # ACRE
# "623475643", # eden enhanced
Expand Down
1 change: 1 addition & 0 deletions addons/smoke/$PBOPREFIX$
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
z\ace\addons\smoke
20 changes: 20 additions & 0 deletions addons/smoke/ACE_Arsenal_Stats.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
class EGVAR(arsenal,stats) {
class statBase;
class GVAR(breathing_protection): statBase {
scope = 2;
displayName = CSTRING(statBreatingProtection);
showBar = 1;
condition = QUOTE(getNumber (_this select 1 >> QQGVAR(Breathing_Protection)) > 0);
barStatement = QUOTE(getNumber (_this select 1 >> QQGVAR(Breathing_Protection)));
tabs[] = {{7}, {}};
};

class GVAR(eyes_protection): statBase {
scope = 2;
displayName = CSTRING(statEyesProtection);
showBar = 1;
condition = QUOTE(getNumber (_this select 1 >> QQGVAR(Eyes_Protection)) > 0);
barStatement = QUOTE(getNumber (_this select 1 >> QQGVAR(Eyes_Protection)));
tabs[] = {{7}, {}};
};
};
15 changes: 15 additions & 0 deletions addons/smoke/CfgEventHandlers.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
class Extended_PreStart_EventHandlers {
class ADDON {
init = QUOTE(call COMPILE_FILE(XEH_preStart));
};
};
class Extended_PreInit_EventHandlers {
class ADDON {
init = QUOTE(call COMPILE_FILE(XEH_preInit));
};
};
class Extended_PostInit_EventHandlers {
class ADDON {
init = QUOTE(call COMPILE_FILE(XEH_postInit));
};
};
53 changes: 53 additions & 0 deletions addons/smoke/CfgGlasses.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
class CfgGlasses {
class None;

class G_AirPurifyingRespirator_01_base_F: None {
GVAR(Eyes_Protection) = 1;
GVAR(Breathing_Protection) = 1;
};

class G_Balaclava_blk: None {
GVAR(Breathing_Protection) = 0.2;
};
class G_Balaclava_combat: G_Balaclava_blk {
GVAR(Eyes_Protection) = 1;
};
class G_Balaclava_lowprofile: G_Balaclava_blk {
GVAR(Eyes_Protection) = 1;
};

class G_Combat: None {
GVAR(Eyes_Protection) = 1;
};
class G_Lowprofile: None {
GVAR(Eyes_Protection) = 1;
};

class G_RegulatorMask_base_F: None {
GVAR(Eyes_Protection) = 1;
GVAR(Breathing_Protection) = 1;
};

class G_Respirator_base_F: None {
GVAR(Breathing_Protection) = 0.8;
};

class G_EyeProtectors_base_F: None {
GVAR(Eyes_Protection) = 0.2;
};

class G_Balaclava_TI_blk_F: None {
GVAR(Breathing_Protection) = 0.4;
};
class G_Balaclava_TI_G_blk_F: G_Balaclava_TI_blk_F {
GVAR(Eyes_Protection) = 1;
};
class G_Balaclava_TI_tna_F;
class G_Balaclava_TI_G_tna_F: G_Balaclava_TI_tna_F {
GVAR(Eyes_Protection) = 1;
};

class G_Blindfold_01_base_F: None {
GVAR(Eyes_Protection) = 0.6;
};
};
2 changes: 2 additions & 0 deletions addons/smoke/XEH_PREP.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
PREP(isInSmoke);
PREP(pfh);
22 changes: 22 additions & 0 deletions addons/smoke/XEH_postInit.sqf
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#include "script_component.hpp"

GVAR(ppHandleDynamicBlur) = ppEffectCreate ["DynamicBlur", 400];
GVAR(ppHandleColorCorrections) = ppEffectCreate ["ColorCorrections", 1500];
GVAR(ppHandleDynamicBlur) ppEffectEnable GVAR(enabled);
GVAR(ppHandleColorCorrections) ppEffectEnable GVAR(enabled);

if (GVAR(enabled)) then {
GVAR(pfh) = [{
[ace_player] call FUNC(pfh);
}] call CBA_fnc_addPerFrameHandler;
};
Comment thread
BrettMayson marked this conversation as resolved.
Outdated

["loadout", {
params ["_unit"];
if !(local _unit) exitWith {};
private _config = configFile >> "CfgGlasses" >> goggles _unit;
private _breathing = getNumber (_config >> QGVAR(Breathing_Protection));
_unit setVariable [QGVAR(breathingProtection), _breathing, true];
private _eyes = getNumber (_config >> QGVAR(Eyes_Protection));
_unit setVariable [QGVAR(eyesProtection), _eyes, true];
}, true] call CBA_fnc_addPlayerEventHandler;
11 changes: 11 additions & 0 deletions addons/smoke/XEH_preInit.sqf
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#include "script_component.hpp"

ADDON = false;

#include "XEH_PREP.hpp"

#include "initSettings.inc.sqf"

GVAR(pfh) = -1;

ADDON = true;
2 changes: 2 additions & 0 deletions addons/smoke/XEH_preStart.sqf
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#include "script_component.hpp"
#include "XEH_PREP.hpp"
16 changes: 16 additions & 0 deletions addons/smoke/config.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#include "script_component.hpp"

class CfgPatches {
class ADDON {
name = QUOTE(COMPONENT);
units[] = {};
weapons[] = {};
requiredVersion = REQUIRED_VERSION;
requiredAddons[] = {"ace_main"};
VERSION_CONFIG;
};
};

#include "CfgEventHandlers.hpp"
#include "CfgGlasses.hpp"
#include "ACE_Arsenal_Stats.hpp"
43 changes: 43 additions & 0 deletions addons/smoke/functions/fnc_isInSmoke.sqf
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#include "..\script_component.hpp"
/*
* Author: BrettMayson
* Check if a unit is in smoke (or any thick particle effect that has `blockAIVisibility`)
*
* Arguments:
* 0: Unit <OBJECT>
*
* Return Value:
* Is the unit in smoke? <BOOL>
*
* Example:
* [player] call ace_smoke_fnc_isInSmoke
*
* Public: Yes
*/

params ["_unit"];

private _coverage = 0;

private _eyePos = eyePos _unit;
private _positions = [
[_eyePos, _eyePos vectorAdd [5, 0, 0], _unit],
[_eyePos, _eyePos vectorAdd [-5, 0, 0], _unit],
[_eyePos, _eyePos vectorAdd [0, 5, 0], _unit],
[_eyePos, _eyePos vectorAdd [0, -5, 0], _unit]
];

{
private _intersect = lineIntersectsSurfaces _x;
if (_intersect isNotEqualTo []) then {
_x set [1, _intersect select 0 select 0];
};
// Check visibility can return 0 for really close surfaces
if ((_x#0) distance (_x#1) < 0.05) then {
_coverage = _coverage + 1;
} else {
_coverage = _coverage + ([objNull, "VIEW"] checkVisibility [_x#0, _x#1]);
};
} forEach _positions;

_coverage < ((count _positions) / 2)
75 changes: 75 additions & 0 deletions addons/smoke/functions/fnc_pfh.sqf
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
#include "..\script_component.hpp"
/*
* Author: BrettMayson
* Per Frame Handler that updates smoke effects on units
*
* Arguments:
* 0: Unit <OBJECT>
*
* Return Value:
* Nothing <NOTHING>
*
* Example:
* [{
* [player] call ace_smoke_fnc_pfh
* }] call CBA_fnc_addPerFrameHandler
*
* Public: No
*/

params ["_unit"];

private _isInSmoke = [_unit] call FUNC(isInSmoke);

private _change = (if (_isInSmoke) then {
0.175 * GVAR(effectFactor)
} else {
-0.04 * GVAR(recoveryFactor)
}) * diag_deltaTime;

// Eyes
private _levelEyes = _unit getVariable [QGVAR(eyesLevel), 0];
private _newLevelEyes = _levelEyes + _change;
_newLevelEyes = _newLevelEyes min 1;
_newLevelEyes = _newLevelEyes max 0;

private _eyesProtect = _unit getVariable [QGVAR(eyesProtection), false];
Comment thread
BrettMayson marked this conversation as resolved.
Outdated
if (_eyesProtect != 0) then {
Comment thread
Drofseh marked this conversation as resolved.
Outdated
_levelEyes = _levelEyes * (1 - _eyesProtect);
};
_unit setVariable [QGVAR(eyesLevel), _levelEyes, true];
Comment thread
BrettMayson marked this conversation as resolved.
Outdated

private _dynamicBlurValue = linearConversion [0.2, 1, _levelEyes, 0, 0.8, true];
private _colorCorrectionsValue = linearConversion [0.2, 1, _levelEyes, 1, 0.6, true];

if (_unit == ace_player) then {
GVAR(ppHandleDynamicBlur) ppEffectAdjust [_dynamicBlurValue];
GVAR(ppHandleColorCorrections) ppEffectAdjust [1,1,0,[0,0,0,0],[0.8, 0.8, 0.8, _colorCorrectionsValue],[1,1,1,0]];

GVAR(ppHandleDynamicBlur) ppEffectCommit 0;
GVAR(ppHandleColorCorrections) ppEffectCommit 0;
};

// Breathing
private _levelBreathing = _unit getVariable [QGVAR(breathingLevel), 0];
private _newLevelBreathing = _levelBreathing + _change;
_newLevelBreathing = _newLevelBreathing min 1;
_newLevelBreathing = _newLevelBreathing max 0;

Comment thread
BrettMayson marked this conversation as resolved.
Outdated
private _breathProtect = _unit getVariable [QGVAR(breathingProtection), false];
if (_breathProtect != 0) then {
Comment thread
Drofseh marked this conversation as resolved.
Outdated
_levelBreathing = _levelBreathing * (1 - _breathProtect);
};
_unit setVariable [QGVAR(breathingLevel), _levelBreathing, true];

private _breathingEffectiveness = linearConversion [0.2, 1, _levelBreathing, 1, 0.6, true];
if !(isNil "ace_medical_vitals_fnc_addSpO2DutyFactor") then {
Comment thread
BrettMayson marked this conversation as resolved.
Outdated
[ADDON, _breathingEffectiveness] call ace_medical_vitals_fnc_addSpO2DutyFactor;
Comment thread
BrettMayson marked this conversation as resolved.
Outdated
};

// Event
private _smoked = _unit getVariable [QGVAR(smoked), false];
if (_isInSmoke != _smoked) then {
[QGVAR(smoked), _isInSmoke] call CBA_fnc_localEvent;
};
_unit setVariable [QGVAR(smoked), _isInSmoke, true];
Comment thread
BrettMayson marked this conversation as resolved.
Outdated
46 changes: 46 additions & 0 deletions addons/smoke/initSettings.inc.sqf
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
private _category = format ["ACE %1", localize LSTRING(DisplayName)];

[
QGVAR(enabled), "CHECKBOX",
[LSTRING(enabled_DisplayName), LSTRING(enabled_Description)],
_category,
true,
1,
{
[QGVAR(enabled), _this] call EFUNC(common,cbaSettings_settingChanged);
Comment thread
BrettMayson marked this conversation as resolved.
Outdated
GVAR(ppHandleDynamicBlur) ppEffectEnable _this;
GVAR(ppHandleColorCorrections) ppEffectEnable _this;
if (_this) then {
if (GVAR(pfh) == -1) then {
Comment thread
Drofseh marked this conversation as resolved.
Outdated
GVAR(pfh) = [{
[ace_player] call FUNC(pfh);
}] call CBA_fnc_addPerFrameHandler;
};
} else {
if (GVAR(pfh) != -1) then {
Comment thread
Drofseh marked this conversation as resolved.
Outdated
[GVAR(pfh)] call CBA_fnc_removePerFrameHandler;
GVAR(pfh) = -1;
Comment thread
BrettMayson marked this conversation as resolved.
Outdated
};
};
}
] call CBA_fnc_addSetting;

[
QGVAR(effectFactor), "SLIDER",
[LSTRING(effectFactor_DisplayName), LSTRING(effectFactor_Description)],
_category,
[0, 1, 0.5, 0.1],
1,
{[QGVAR(effectFactor), _this] call EFUNC(common,cbaSettings_settingChanged)},
true // Needs mission restart
] call CBA_fnc_addSetting;

[
QGVAR(recoveryFactor), "SLIDER",
[LSTRING(recoveryFactor_DisplayName), LSTRING(recoveryFactor_Description)],
_category,
[0, 1, 0.5, 0.1],
1,
{[QGVAR(recoveryFactor), _this] call EFUNC(common,cbaSettings_settingChanged)},
true // Needs mission restart
] call CBA_fnc_addSetting;
17 changes: 17 additions & 0 deletions addons/smoke/script_component.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#define COMPONENT smoke
#define COMPONENT_BEAUTIFIED Smoke
#include "\z\ace\addons\main\script_mod.hpp"

// #define DEBUG_MODE_FULL
// #define DISABLE_COMPILE_CACHE
// #define ENABLE_PERFORMANCE_COUNTERS

#ifdef DEBUG_ENABLED_SMOKE
#define DEBUG_MODE_FULL
#endif

#ifdef DEBUG_SETTINGS_SMOKE
#define DEBUG_SETTINGS DEBUG_SETTINGS_SMOKE
#endif

#include "\z\ace\addons\main\script_macros.hpp"
Loading
Loading