diff --git a/A3A/addons/core/CfgFunctions.hpp b/A3A/addons/core/CfgFunctions.hpp
index 143e50d6fd..32714a1adb 100644
--- a/A3A/addons/core/CfgFunctions.hpp
+++ b/A3A/addons/core/CfgFunctions.hpp
@@ -536,11 +536,14 @@ class CfgFunctions
file = QPATHTOFOLDER(functions\Revive);
class actionRevive {};
class carry {};
+ class calcVestDamageAdj {};
class fatalWound {};
class handleDamage {};
class handleDamageAAF {};
class initRevive {};
class isMedic {};
+ class selfRevive {};
+ class selfReviveReset {};
class respawn {};
class unconscious {};
class unconsciousAAF {};
diff --git a/A3A/addons/core/Params.hpp b/A3A/addons/core/Params.hpp
index ac84f051ef..25e722faf5 100644
--- a/A3A/addons/core/Params.hpp
+++ b/A3A/addons/core/Params.hpp
@@ -119,6 +119,13 @@ class Params
texts[] = {"5 seconds","10 seconds","15 seconds"};
default = 10;
};
+ class A3A_selfReviveMethods
+ {
+ title = "Self-revive methods enabled";
+ values[] = {0,1};
+ texts[] = {"Disabled", "Withstand"};
+ default = 0;
+ };
class SpacerMembership
{
diff --git a/A3A/addons/core/Stringtable.xml b/A3A/addons/core/Stringtable.xml
index 00efbf7b70..e8e239cba7 100644
--- a/A3A/addons/core/Stringtable.xml
+++ b/A3A/addons/core/Stringtable.xml
@@ -6886,5 +6886,22 @@
%1 Contact Report
+
+
+ Self Revive
+
+
+ You don't have a first aid kit for self-revive.
+
+
+ You have already revived yourself recently.
+
+
+ You shake off the injury, but you're not feeling great.
+
+
+ You are feeling much better.
+
+
\ No newline at end of file
diff --git a/A3A/addons/core/functions/Base/fn_vehicleBoxRestore.sqf b/A3A/addons/core/functions/Base/fn_vehicleBoxRestore.sqf
index 38e6b627be..999ca477a3 100644
--- a/A3A/addons/core/functions/Base/fn_vehicleBoxRestore.sqf
+++ b/A3A/addons/core/functions/Base/fn_vehicleBoxRestore.sqf
@@ -53,6 +53,9 @@ private _rebelPlayers = allUnits select {side _x in [teamPlayer, civilian] && {_
_x setDamage 0;
_x setVariable ["incapacitated",false,true];
_x setVariable ["compromised", 0, true];
+ if !(A3A_hasACEMedical) then {
+ [true] remoteExecCall ["A3A_fnc_selfReviveReset", 0];
+ };
} forEach _rebelPlayers;
private _hqVehicles = (vehicles inAreaArray [_posHQ, 150, 150]) select {
diff --git a/A3A/addons/core/functions/EventHandler/fn_enemyUnitKilledEH.sqf b/A3A/addons/core/functions/EventHandler/fn_enemyUnitKilledEH.sqf
index 07284c49ff..ed2eb9659c 100644
--- a/A3A/addons/core/functions/EventHandler/fn_enemyUnitKilledEH.sqf
+++ b/A3A/addons/core/functions/EventHandler/fn_enemyUnitKilledEH.sqf
@@ -26,6 +26,15 @@ if (A3A_hasACE) then
{
_killer = _victim getVariable ["ace_medical_lastDamageSource", _killer];
};
+}
+else
+{
+ if (_victim getVariable ["incapacitated", false]) then {
+ private _downedBy = _victim getVariable "A3A_downedBy";
+ if (!isNil "_downedBy") then {
+ _killer = _downedBy;
+ };
+ };
};
if (_victimSide == Occupants or _victimSide == Invaders) then {
@@ -44,7 +53,6 @@ if (side (group _killer) == teamPlayer) then
[_killer,false] remoteExec ["setCaptive",_killer];
};
};
- _killer addRating 1000;
};
if (vehicle _killer isKindOf "StaticMortar") then
{
@@ -61,13 +69,13 @@ if (side (group _killer) == teamPlayer) then
Debug("aggroEvent | Rebels killed a surrendered unit");
if (_victimSide == Occupants) then
{
- [0,-2,getPos _victim] remoteExec ["A3A_fnc_citySupportChange",2];
+ [0,-2,getPosATL _victim] remoteExec ["A3A_fnc_citySupportChange",2];
};
[_victimSide, 20, 30] remoteExec ["A3A_fnc_addAggression", 2];
}
else
{
- [-1,1,getPos _victim] remoteExec ["A3A_fnc_citySupportChange",2];
+ [-1,1,getPosATL _victim] remoteExec ["A3A_fnc_citySupportChange",2];
[_victimSide, 0.5, 45] remoteExec ["A3A_fnc_addAggression", 2];
};
}
@@ -75,11 +83,11 @@ else
{
if (_victimSide == Occupants) then
{
- [-0.25,0,getPos _victim] remoteExec ["A3A_fnc_citySupportChange",2];
+ [-0.25,0,getPosATL _victim] remoteExec ["A3A_fnc_citySupportChange",2];
}
else
{
- [0.25,0,getPos _victim] remoteExec ["A3A_fnc_citySupportChange",2];
+ [0.25,0,getPosATL _victim] remoteExec ["A3A_fnc_citySupportChange",2];
};
};
diff --git a/A3A/addons/core/functions/Revive/fn_actionRevive.sqf b/A3A/addons/core/functions/Revive/fn_actionRevive.sqf
index 163aa1c673..bc628a1450 100644
--- a/A3A/addons/core/functions/Revive/fn_actionRevive.sqf
+++ b/A3A/addons/core/functions/Revive/fn_actionRevive.sqf
@@ -1,7 +1,7 @@
params ["_cured", "_medic"];
private _player = isPlayer _medic;
-private _inPlayerGroup = if !(_player) then {if ({isPlayer _x} count (units group _medic) > 0) then {true} else {false}} else {false};
+private _inPlayerGroup = !_player and ({isPlayer _x} count (units group _medic) > 0);
private _isMedic = [_medic] call A3A_fnc_isMedic;
if (captive _medic) then { _medic setCaptive false }; // medic is will be local
@@ -42,7 +42,7 @@ if (!_hasMedkit && {count _medicFAKs == 0 && count _curedFAKs == 0}) exitWith
false
};
-private _timer = [10, A3A_reviveTime] select _inPlayerGroup;
+private _timer = [10, A3A_reviveTime] select (_player or _inPlayerGroup);
if ([_cured] call A3A_fnc_fatalWound) then { _timer = _timer * 2 };
if (!_isMedic) then { _timer = _timer * 2 };
_timer = (_timer * (1 + random 0.5)) + time;
diff --git a/A3A/addons/core/functions/Revive/fn_calcVestDamageAdj.sqf b/A3A/addons/core/functions/Revive/fn_calcVestDamageAdj.sqf
new file mode 100644
index 0000000000..e943def945
--- /dev/null
+++ b/A3A/addons/core/functions/Revive/fn_calcVestDamageAdj.sqf
@@ -0,0 +1,43 @@
+/*
+ Calculate vest damage adjustment for low-armoured body hits
+
+ Reads _unit and _hitpoint as local vars from caller
+ Used with getDefaultOrCall so can't use exitWith
+*/
+
+#define NEWMIN 10 // new body armour baseline (original is 2)
+#define UNCHANGED 16 // vest armor level where damage is unchanged
+#define SCALEFACT ((NEWMIN-2) / UNCHANGED)
+
+// vestpart hashmap version
+//diag_log format ["calcVestDamageAdj called with unit %1, vest %2, part %3", _unit, vest _unit, _hitpoint];
+if (vest _unit == "") then {2 / NEWMIN} else {
+ private _configs = "_hitpoint == getText (_x >> 'hitpointName')" configClasses (configfile >> "CfgWeapons" >> vest _unit >> "ItemInfo" >> "HitpointsProtectionInfo");
+ if (_configs isEqualTo []) exitWith {2 / NEWMIN};
+ private _armour = getNumber (_configs#0 >> "Armor");
+ if (_armour >= UNCHANGED) exitWith {1};
+ (2 + _armour) / (NEWMIN + SCALEFACT*_armour);
+};
+
+// three cases then...
+// 1. no vest => 2/NEWMIN adj
+// 2. 18+ total => 1
+// 3. oldarmor (2 + armor) / newarmor (NEWMIN + (UNCHANGED - NEWMIN) / (UNCHANGED - 2)
+
+
+/*
+// vest hashmap -> part hashmap version
+if (vest _unit == "") exitWith { ["spine1","spine2","spine3"] createHashMapFromArray [0.2,0.2,0.2] };
+private _output = createHashMap;
+private _config = configfile >> "CfgWeapons" >> vest _unit >> "ItemInfo" >> "HitpointsProtectionInfo";
+{
+ _x params ["_hitpoint", "_hitpart"];
+ private _adj = call {
+ if !(isClass (_config >> _hitpoint)) exitWith {0.2};
+ private _armour = getNumber (_config >> _hitpoint >> "Armor");
+ (2 + _armour) / (10 + _armour/2);
+ };
+ _output set [_hitpart, _adj];
+} forEach [["Chest","spine1"], ["Diaphragm","spine2"], ["Abdomen","spine3"]];
+_output;
+*/
\ No newline at end of file
diff --git a/A3A/addons/core/functions/Revive/fn_fatalWound.sqf b/A3A/addons/core/functions/Revive/fn_fatalWound.sqf
index 04912ed5ea..dd6b615697 100644
--- a/A3A/addons/core/functions/Revive/fn_fatalWound.sqf
+++ b/A3A/addons/core/functions/Revive/fn_fatalWound.sqf
@@ -1,5 +1,5 @@
private _unit = _this select 0;
-if (_unit getHit "head" >= 0.9) exitWith {true};
-if (_unit getHit "body" >= 0.9) exitWith {true};
+if (_unit getHitPointDamage "hitface" >= 0.9) exitWith {true};
+//if (_unit getHit "body" >= 0.9) exitWith {true};
false
diff --git a/A3A/addons/core/functions/Revive/fn_handleDamage.sqf b/A3A/addons/core/functions/Revive/fn_handleDamage.sqf
index a9811a2620..167979cee8 100644
--- a/A3A/addons/core/functions/Revive/fn_handleDamage.sqf
+++ b/A3A/addons/core/functions/Revive/fn_handleDamage.sqf
@@ -6,36 +6,36 @@ params ["_unit","_part","_damage","_injurer","_projectile","_hitIndex","_instiga
// Helmet popping: use _hitpoint rather than _part to work around ACE calling its fake hitpoint "head"
if (_damage >= 1 && {_hitPoint == "hithead"}) then
{
- if (random 100 < helmetLossChance) then
- {
- removeHeadgear _unit;
- };
+ if (random 100 < helmetLossChance) then
+ {
+ removeHeadgear _unit;
+ };
};
if (_part == "" && _damage > 0.1) then
{
- // this will not work the same with ACE, as damage isn't accumulated
- if (!isPlayer (leader group _unit) && dam < 1.0) then
- {
- //if (_damage > 0.6) then {[_unit,_unit,_injurer] spawn A3A_fnc_chargeWithSmoke};
- if (_damage > 0.6) then {[_unit,_injurer] spawn A3A_fnc_unitGetToCover};
- };
-
- // Contact report generation for rebels
- if (side group _injurer == Occupants or side group _injurer == Invaders) then
- {
- // Check if unit is part of a rebel garrison
- private _marker = _unit getVariable ["markerX",""];
- if (_marker != "" && {sidesX getVariable [_marker,sideUnknown] == teamPlayer}) then
- {
- // Limit last attack var changes and task updates to once per 30 seconds
- private _lastAttackTime = garrison getVariable [_marker + "_lastAttack", -30];
- if (_lastAttackTime + 30 < serverTime) then {
- garrison setVariable [_marker + "_lastAttack", serverTime, true];
- [_marker, side group _injurer, side group _unit] remoteExec ["A3A_fnc_underAttack", 2];
- };
- };
- };
+ // this will not work the same with ACE, as damage isn't accumulated
+ if (!isPlayer (leader group _unit) && dam < 1.0) then
+ {
+ //if (_damage > 0.6) then {[_unit,_unit,_injurer] spawn A3A_fnc_chargeWithSmoke};
+ if (_damage > 0.6) then {[_unit,_injurer] spawn A3A_fnc_unitGetToCover};
+ };
+
+ // Contact report generation for rebels
+ if (side group _injurer == Occupants or side group _injurer == Invaders) then
+ {
+ // Check if unit is part of a rebel garrison
+ private _marker = _unit getVariable ["markerX",""];
+ if (_marker != "" && {sidesX getVariable [_marker,sideUnknown] == teamPlayer}) then
+ {
+ // Limit last attack var changes and task updates to once per 30 seconds
+ private _lastAttackTime = garrison getVariable [_marker + "_lastAttack", -30];
+ if (_lastAttackTime + 30 < serverTime) then {
+ garrison setVariable [_marker + "_lastAttack", serverTime, true];
+ [_marker, side group _injurer, side group _unit] remoteExec ["A3A_fnc_underAttack", 2];
+ };
+ };
+ };
};
@@ -45,94 +45,93 @@ if (A3A_hasACEMedical) exitWith {};
private _makeUnconscious =
{
- params ["_unit", "_injurer"];
- _unit setVariable ["incapacitated",true,true];
- _unit setVariable ["helpFailed", 0];
- _unit setUnconscious true;
- if (vehicle _unit != _unit) then
- {
- moveOut _unit;
- };
- if (isPlayer _unit) then {_unit allowDamage false};
- private _fromside = if (!isNull _injurer) then {side group _injurer} else {sideUnknown};
- [_unit,_fromside] spawn A3A_fnc_unconscious;
+ params ["_unit", "_injurer", "_fatalWound"];
+ //diag_log format ["Friendly unit %1 downed, fatal %2", _unit, _fatalWound];
+
+ _unit setVariable ["incapacitated",true,true];
+ _unit setVariable ["helpFailed", 0];
+ _unit setUnconscious true;
+ _unit setVariable ["incapFrame", diag_frameno+1];
+ if (isPlayer _unit) then {_unit allowDamage false};
+
+ if (vehicle _unit != _unit) then { moveOut _unit };
+
+ private _fromside = if (!isNull _injurer) then {side group _injurer} else {sideUnknown};
+ [_unit, _fromside, _fatalWound] spawn A3A_fnc_unconscious;
};
+//diag_log format ["%1 damage on part %2, hitpoint %3", _damage, _part, _hitpoint];
+
if (_part == "") then
{
- if (_damage >= 1) then
- {
- if (side _injurer == civilian) then
- {
- // apparently civilians are non-lethal
- _damage = 0.9;
- }
- else
- {
- if !(_unit getVariable ["incapacitated",false]) then
- {
- _damage = 0.9;
- [_unit, _injurer] call _makeUnconscious;
- }
- else
- {
- // already unconscious, check whether we're pushed into death
- _overall = (_unit getVariable ["overallDamage",0]) + (_damage - 1);
- if (_overall > 1) then
- {
- if (isPlayer _unit) then
- {
- _damage = 0;
- [_unit] spawn A3A_fnc_respawn;
- }
- else
- {
- _unit removeAllEventHandlers "HandleDamage";
- };
- }
- else
- {
- _unit setVariable ["overallDamage",_overall];
- _damage = 0.9;
- };
- };
- };
- }
- else
- {
- if (_damage > 0.25) then
- {
- if (_unit getVariable ["helping",false]) then
- {
- _unit setVariable ["cancelRevive",true];
- };
- if (isPlayer (leader group _unit)) then
- {
- if (autoheal) then
- {
- if (!isNull (_unit getVariable ["helped",objNull])) exitWith {};
- [_unit] call A3A_fnc_askHelp;
- };
- };
- };
- };
+ if (_damage >= 1) then
+ {
+ if (side _injurer == civilian) exitWith
+ {
+ // apparently civilians are non-lethal
+ _damage = 0.9;
+ };
+
+ if !(_unit getVariable ["incapacitated",false]) exitWith
+ {
+ //diag_log format ["Friendly %1 downed by %2 general damage", _unit, _damage];
+ [_unit, _injurer, _damage >= 2] call _makeUnconscious;
+ _damage = 0.9;
+ };
+
+ // Don't double-tap with one projectile
+ if (diag_frameno <= _unit getVariable "incapFrame") exitWith {_damage = 0.9};
+
+ // already unconscious, check whether we're pushed into death
+ _overall = (_unit getVariable ["overallDamage",0]) + (_damage - 0.9);
+
+ //diag_log format ["Downed friendly %1 accumulated %2 damage from %3", _unit, _overall, _damage];
+
+ if (_overall > 1) exitWith
+ {
+ _unit setDamage 1;
+ _unit removeAllEventHandlers "HandleDamage";
+ };
+
+ _unit setVariable ["overallDamage",_overall];
+ _damage = 0.9;
+ }
+ else
+ {
+ if (_damage > 0.25) then
+ {
+ if (_unit getVariable ["helping",false]) then
+ {
+ _unit setVariable ["cancelRevive",true];
+ };
+ if (isPlayer (leader group _unit)) then
+ {
+ if (autoheal) then
+ {
+ if (!isNull (_unit getVariable ["helped",objNull])) exitWith {};
+ [_unit] call A3A_fnc_askHelp;
+ };
+ };
+ };
+ };
}
else
{
- if (_damage >= 1) then
- {
- if !(_part in ["arms","hands","legs"]) then
- {
- _damage = 0.9;
- if (_part in ["head","body"]) then
- {
- if !(_unit getVariable ["incapacitated",false]) then
- {
- [_unit, _injurer] call _makeUnconscious;
- };
- };
- };
- };
+ if ("spine" in _part and { !(uniform _unit in A3A_strongUniformsHM) } ) then {
+ private _adj = A3A_vestDamageAdj getOrDefaultCall [_part + vest _unit, A3A_fnc_calcVestDamageAdj, true];
+ //diag_log format ["Armor adjust: %1 part, %2 damage, %3 oldDamage, %4 adj", _part, _damage, _unit getHit _part, _adj];
+ private _oldDmg = _unit getHit _part;
+ _damage = _oldDmg + _adj * (_damage - _oldDmg);
+ };
+
+ if (_damage >= 1 && { !(_hitpoint in ["hitarms","hithands","hitlegs"]) }) then
+ {
+ if !(_unit getVariable ["incapacitated",false]) then {
+ //diag_log format ["Friendly %1 downed by %2 hit on part %3, hitpoint %4", _unit, _damage, _part, _hitpoint];
+ [_unit, _injurer, true] call _makeUnconscious;
+ };
+ _damage = 0.9;
+ };
};
_damage
diff --git a/A3A/addons/core/functions/Revive/fn_handleDamageAAF.sqf b/A3A/addons/core/functions/Revive/fn_handleDamageAAF.sqf
index c557d8fe06..a4190a6323 100644
--- a/A3A/addons/core/functions/Revive/fn_handleDamageAAF.sqf
+++ b/A3A/addons/core/functions/Revive/fn_handleDamageAAF.sqf
@@ -5,137 +5,126 @@ params ["_unit","_part","_damage","_injurer","_projectile","_hitIndex","_instiga
// Functionality unrelated to Antistasi revive
if (side group _injurer == teamPlayer) then
{
- // Helmet popping: use _hitpoint rather than _part to work around ACE calling its fake hitpoint "head"
- if (_damage >= 1 && {_hitPoint == "hithead"}) then
- {
- if (random 100 < helmetLossChance) then
- {
- removeHeadgear _unit;
- };
- };
-
- private _groupX = group _unit;
- if (time > _groupX getVariable ["movedToCover",0]) then
- {
- if ((behaviour leader _groupX != "COMBAT") and (behaviour leader _groupX != "STEALTH")) then
- {
- _groupX setVariable ["movedToCover",time + 120];
- {[_x,_injurer] spawn A3A_fnc_unitGetToCover} forEach units _groupX;
- };
- };
-
- if (_part == "" && _damage < 1) then
- {
- if (_damage > 0.6) then {[_unit,_injurer] spawn A3A_fnc_unitGetToCover};
- };
-
- // Contact report generation for PvP players
- if (_part == "" && side group _unit == Occupants) then
- {
- // Check if unit is part of a garrison
- private _marker = _unit getVariable ["markerX",""];
- if (_marker != "" && {sidesX getVariable [_marker,sideUnknown] == Occupants}) then
- {
- // Limit last attack var changes and task updates to once per 30 seconds
- private _lastAttackTime = garrison getVariable [_marker + "_lastAttack", -30];
- if (_lastAttackTime + 30 < serverTime) then {
- garrison setVariable [_marker + "_lastAttack", serverTime, true];
- [_marker, teamPlayer, side group _unit] remoteExec ["A3A_fnc_underAttack", 2];
- };
- };
- };
+ // Helmet popping: use _hitpoint rather than _part to work around ACE calling its fake hitpoint "head"
+ if (_damage >= 1 && {_hitPoint == "hithead"}) then
+ {
+ if (random 100 < helmetLossChance) then
+ {
+ removeHeadgear _unit;
+ };
+ };
+
+ private _groupX = group _unit;
+ if (time > _groupX getVariable ["movedToCover",0]) then
+ {
+ if ((behaviour leader _groupX != "COMBAT") and (behaviour leader _groupX != "STEALTH")) then
+ {
+ _groupX setVariable ["movedToCover",time + 120];
+ {[_x,_injurer] spawn A3A_fnc_unitGetToCover} forEach units _groupX;
+ };
+ };
+
+ if (_part == "" && _damage < 1) then
+ {
+ if (_damage > 0.6) then {[_unit,_injurer] spawn A3A_fnc_unitGetToCover};
+ };
};
// Let ACE medical handle the rest (inc return value) if it's running
if (A3A_hasACEMedical) exitWith {};
+if (side _injurer != teamPlayer) exitWith {_damage};
private _makeUnconscious =
{
- params ["_unit", "_injurer"];
-
- _unit setVariable ["incapacitated",true,true];
- _unit setVariable ["helpFailed", 0];
- _unit setUnconscious true;
- if (vehicle _unit != _unit) then
- {
- moveOut _unit;
- };
- if (isPlayer _unit) then {_unit allowDamage false};
-
- //Make sure to pass group lead if unit is the leader
- if (_unit == leader (group _unit)) then
- {
- private _index = (units (group _unit)) findIf {[_x] call A3A_fnc_canFight};
- if(_index != -1) then {
- (group _unit) selectLeader ((units (group _unit)) select _index);
- };
- };
-
- [_unit, group _unit, _injurer] spawn A3A_fnc_AIreactOnKill;
-
- [_unit,_injurer] spawn A3A_fnc_unconsciousAAF;
+ params ["_unit", "_injurer", "_fatalWound"];
+
+ _unit setVariable ["incapacitated",true,true];
+ _unit setVariable ["helpFailed", 0];
+ _unit setUnconscious true;
+ _unit setVariable ["incapFrame", diag_frameno+1];
+
+ // Assume killed handler will be local as well
+ // TODO: Check killed/instigator stuff?
+ if (!isNull _injurer) then { _unit setVariable ["A3A_downedBy", _injurer] };
+
+ if (vehicle _unit != _unit) then { moveOut _unit };
+
+ //Make sure to pass group lead if unit is the leader
+ if (_unit == leader (group _unit)) then {
+ private _index = (units (group _unit)) findIf {[_x] call A3A_fnc_canFight};
+ if(_index != -1) then {
+ (group _unit) selectLeader ((units (group _unit)) select _index);
+ };
+ };
+
+ [_unit, group _unit, _injurer] spawn A3A_fnc_AIreactOnKill;
+
+ [_unit, _injurer, _fatalWound] spawn A3A_fnc_unconsciousAAF;
};
-if (side _injurer == teamPlayer) then
+if (_part == "") then
{
- if (_part == "") then
- {
- if (_damage >= 1) then
- {
- if (!(_unit getVariable ["incapacitated",false])) then
- {
- _damage = 0.9;
- [_unit,_injurer] call _makeUnconscious;
- }
- else
- {
- // already unconscious, check whether we're pushed into death
- _overall = (_unit getVariable ["overallDamage",0]) + (_damage - 1);
- if (_overall > 0.5) then
- {
- _unit removeAllEventHandlers "HandleDamage";
- }
- else
- {
- _unit setVariable ["overallDamage",_overall];
- _damage = 0.9;
-
- };
- };
- }
- else
- {
-
- //Abort helping if hit too hard
- if (_damage > 0.25) then
- {
- if (_unit getVariable ["helping",false]) then
- {
- _unit setVariable ["cancelRevive",true];
- };
- };
- };
- }
- else
- {
- if (_damage >= 1) then
- {
- if !(_part in ["arms","hands","legs"]) then
- {
- _damage = 0.9;
- // Don't trigger unconsciousness on sub-part hits (face/pelvis etc), only the container
- if (_part in ["head","body"]) then
- {
- if !(_unit getVariable ["incapacitated",false]) then
- {
- [_unit,_injurer] call _makeUnconscious;
-
- };
- };
- };
- };
- };
+ if (_damage >= 1) then
+ {
+ if !(_unit getVariable ["incapacitated",false]) exitWith
+ {
+ if (_damage > 2 and random 1 < 0.5) exitWith {
+ _unit removeEventHandler ["HandleDamage", _thisEventHandler];
+ };
+
+ [_unit, _injurer, _damage > 2] call _makeUnconscious;
+ _damage = 0.9;
+ };
+
+ // Don't double-tap with one projectile
+ if (diag_frameno <= _unit getVariable "incapFrame") exitWith {_damage = 0.9};
+
+ // already unconscious, check whether we're pushed into death
+ _overall = (_unit getVariable ["overallDamage",0]) + (_damage - 0.9);
+ if (_overall > 1) exitWith
+ {
+ _unit setDamage 1;
+ _unit removeAllEventHandlers "HandleDamage";
+ };
+
+ _unit setVariable ["overallDamage",_overall];
+ _damage = 0.9;
+ }
+ else
+ {
+
+ //Abort helping if hit too hard
+ if (_damage > 0.25) then
+ {
+ if (_unit getVariable ["helping",false]) then
+ {
+ _unit setVariable ["cancelRevive",true];
+ };
+ };
+ };
+}
+else
+{
+ if ("spine" in _part and { !(uniform _unit in A3A_strongUniformsHM) } ) then {
+ private _adj = A3A_vestDamageAdj getOrDefaultCall [_part + vest _unit, A3A_fnc_calcVestDamageAdj, true];
+ private _oldDmg = _unit getHit _part;
+ _damage = _oldDmg + _adj * (_damage - _oldDmg);
+ };
+
+ if (_damage >= 1 && { !(_hitpoint in ["hitarms","hithands","hitlegs"]) }) then
+ {
+ if (_unit getVariable ["incapacitated",false]) exitWith {
+ _damage = 0.9;
+ };
+
+ // Decide whether this is a kill or down
+ if (random 1 < [0.5, 0.75] select (_hitPoint == "hithead")) exitWith {
+ _unit removeEventHandler ["HandleDamage", _thisEventHandler];
+ };
+ [_unit, _injurer, true] call _makeUnconscious;
+ _damage = 0.9;
+ };
};
_damage
diff --git a/A3A/addons/core/functions/Revive/fn_respawn.sqf b/A3A/addons/core/functions/Revive/fn_respawn.sqf
index dfaf298a5a..539d4f1256 100644
--- a/A3A/addons/core/functions/Revive/fn_respawn.sqf
+++ b/A3A/addons/core/functions/Revive/fn_respawn.sqf
@@ -1,87 +1,15 @@
-private ["_unit"];
-_unit = _this select 0;
+params ["_unit"];
+
if (!local _unit) exitWith {};
if (_unit getVariable "respawning") exitWith {};
-//if (not( _unit getVariable "inconsciente")) exitWith {};
if (_unit != _unit getVariable ["owner",_unit]) exitWith {};
if (!isPlayer _unit) exitWith {};
+
+if (!isNil "respawnMenu") then {(findDisplay 46) displayRemoveEventHandler ["KeyDown", respawnMenu]};
_unit setVariable ["respawning",true];
-//_unit enableSimulation true;
private _layer = ["A3A_infoCenter"] call BIS_fnc_rscLayer;
["Respawning",0,0,3,0,0,_layer] spawn bis_fnc_dynamicText;
-//titleText ["", "BLACK IN", 0];
-if (!isNil "respawnMenu") then {(findDisplay 46) displayRemoveEventHandler ["KeyDown", respawnMenu]};
-if (isMultiplayer) exitWith
- {
- if (captive _unit) then {[_unit,false] remoteExec ["setCaptive",0,_unit]; _unit setCaptive false};
- //_unit setVariable ["inconsciente",false,true];
- _unit setVariable ["respawning",false];
- //if (captive _unit) then {[_unit,false] remoteExec ["setCaptive"]};
- _unit setDamage 1;
- };
-private ["_positionX","_radiusX","_roads","_road","_pos"];
-_positionX = getMarkerPos respawnTeamPlayer;
-if (lifeState _unit == "incapacitated") then {_unit setUnconscious false};
-_unit setVariable ["helped",objNull];
-_unit setVariable ["helping",false];
-_unit setDamage 0;
-_unit setVariable ["compromised",0];
-_unit setVariable ["disguised",false];
-_unit setVariable ["incapacitated",false];
-
-if (rating _unit < 0) then {_unit addRating (rating _unit * -1)};
-_nul = [0,-1,getPos _unit] remoteExec ["A3A_fnc_citySupportChange",2];
-
-_hr = round ((server getVariable "hr") * 0.1);
-_resourcesFIA = round ((server getVariable "resourcesFIA") * 0.05);
-
-[- _hr, - _resourcesFIA] remoteExec ["A3A_fnc_resourcesFIA",2];
-{
-//_x hideObject true;
-if ((_x != vehicle _x) and (driver vehicle _x == _x)) then
- {
- sleep 3;
- _radiusX = 10;
- while {true} do
- {
- _roads = _positionX nearRoads _radiusX;
- if (count _roads > 0) exitWith {};
- _radiusX = _radiusX + 10;
- };
- _road = _roads select 0;
- _pos = position _road findEmptyPosition [1,50,typeOf (vehicle _unit)];
- vehicle _x setPos _pos;
- }
-else
- {
- if ([_x] call A3A_fnc_canFight) then
- {
- _x setPosATL _positionX;
- _x setVariable ["rearming",false];
- _x doWatch objNull;
- _x doFollow leader _x;
- }
- else
- {
- _x setDamage 1;
- };
- };
-//_x hideObject false;
-} forEach (units group _unit) + (units stragglers) - [_unit];
-removeAllItemsWithMagazines _unit;
-_hmd = hmd _unit;
-if (_hmd != "") then
- {
- _unit unassignItem _hmd;
- _unit removeItem _hmd;
- };
-{_unit removeWeaponGlobal _x} forEach weapons _unit;
-removeBackpack _unit;
-removeVest _unit;
-_unit setPosATL _positionX;
-_unit setCaptive false;
-_unit setUnconscious false;
-_unit playMoveNow "AmovPpneMstpSnonWnonDnon_healed";
-sleep 4;
-_unit setVariable ["respawning",false];
\ No newline at end of file
+if (captive _unit) then {_unit setCaptive false};
+_unit setVariable ["respawning",false];
+_unit setDamage 1;
diff --git a/A3A/addons/core/functions/Revive/fn_selfRevive.sqf b/A3A/addons/core/functions/Revive/fn_selfRevive.sqf
new file mode 100644
index 0000000000..1e7767216c
--- /dev/null
+++ b/A3A/addons/core/functions/Revive/fn_selfRevive.sqf
@@ -0,0 +1,51 @@
+/*
+ A3A_fnc_selfRevive
+ Attempt to self-revive the local player (needs FAK, 5min timeout)
+
+ No arguments, no return
+
+ Environment: Player-local
+*/
+
+if !(player getVariable ["incapacitated", false]) exitWith {};
+
+private _firstAidKits = ["FirstAidKit"] + (A3A_faction_reb get "firstAidKits");
+private _hasFAKs = _firstAidKits arrayIntersect items player;
+
+private _hintTitle = localize "STR_A3A_selfRevive_title";
+if (_hasFAKs isEqualTo []) exitWith {
+ [_hintTitle, localize "STR_A3A_selfRevive_noFAK"] call A3A_fnc_customHint;
+};
+
+if (time < player getVariable ["A3A_selfReviveTimeout", -1]) exitWith {
+ [_hintTitle, localize "STR_A3A_selfRevive_recent"] call A3A_fnc_customHint;
+};
+
+// ok so now we actually do it...
+player setVariable ["incapacitated", false, true];
+player setDamage 0.5;
+player removeItem selectRandom _hasFAKs;
+
+private _timeout = missionNamespace getVariable ["A3A_selfReviveTimeout", 300];
+player setVariable ["A3A_selfReviveTimeout", _timeout + time];
+
+[_hintTitle, localize "STR_A3A_selfRevive_success"] call A3A_fnc_customHint;
+
+private _aimCoef = missionNamespace getVariable ["A3A_selfReviveAimCoef", 3];
+player setCustomAimCoef _aimCoef;
+
+// Some bog standard desaturation
+private _handle = ppEffectCreate ["ColorCorrections", 1537];
+_handle ppEffectEnable true;
+_handle ppEffectAdjust [1, 1, 0,
+ [0, 0, 0, 0],
+ [1, 1, 1, 0.5],
+ [0.299, 0.587, 0.114, 0]
+];
+_handle ppEffectCommit 5;
+A3A_selfRevivePPHandle = _handle;
+
+_timeout spawn {
+ sleep _this;
+ [false] call A3A_fnc_selfReviveReset;
+};
diff --git a/A3A/addons/core/functions/Revive/fn_selfReviveReset.sqf b/A3A/addons/core/functions/Revive/fn_selfReviveReset.sqf
new file mode 100644
index 0000000000..146237fe2b
--- /dev/null
+++ b/A3A/addons/core/functions/Revive/fn_selfReviveReset.sqf
@@ -0,0 +1,37 @@
+/*
+ A3A_fnc_selfReviveReset
+ Remove any self-revive after-effects and clear the timeout
+
+ Arguments:
+ 1. True for no effect transition or message
+
+ Environment: Player-local
+*/
+
+params [["_instant", true]];
+
+if (!A3A_selfReviveMethods) exitWith {};
+
+if (!isNil "A3A_selfRevivePPHandle") then {
+ _handle = A3A_selfRevivePPHandle;
+ A3A_selfRevivePPHandle = nil;
+ if (!_instant) then {
+ _handle ppEffectAdjust [1, 1, 0,
+ [0, 0, 0, 0],
+ [1, 1, 1, 1],
+ [0.299, 0.587, 0.114, 0]
+ ];
+ _handle ppEffectCommit 10;
+ sleep 10;
+ };
+ _handle ppEffectEnable false;
+ ppEffectDestroy _handle;
+};
+
+// Already cleared by box or respawn
+if (!_instant && !isNil { player getVariable "A3A_selfReviveTimeout" }) then {
+ [localize "STR_A3A_selfRevive_title", localize "STR_A3A_selfRevive_timeout"] call A3A_fnc_customHint;
+};
+player setVariable ["A3A_selfReviveTimeout", nil];
+
+if (getCustomAimCoef player > 1) then { player setCustomAimCoef 1 };
diff --git a/A3A/addons/core/functions/Revive/fn_unconscious.sqf b/A3A/addons/core/functions/Revive/fn_unconscious.sqf
index 4d9895cb87..2e2e0e4dd3 100644
--- a/A3A/addons/core/functions/Revive/fn_unconscious.sqf
+++ b/A3A/addons/core/functions/Revive/fn_unconscious.sqf
@@ -1,48 +1,42 @@
private ["_unit","_groupX","_groups","_isLeader","_dummyGroup","_bleedOut","_suicide","_saveVolume","_isPlayer","_camTarget","_saveVolumeVoice"];
-_unit = _this select 0;
-//if (_unit getVariable "inconsciente") exitWith {};
-//if (damage _unit < 0.9) exitWith {};
-//if (!local _unit) exitWith {};
-//_unit setVariable ["inconsciente",true,true];
+
+params ["_unit", "_injurer", "_fatalWound"];
+
+_unit setDamage 0.9;
+if (!_fatalWound) then { _unit setHitPointDamage ["hitface", 0.5]; }; // fatal wound marker
+
_bleedOut = time + 300;//300
_isPlayer = false;
_playersX = false;
_inPlayerGroup = false;
_unit setBleedingremaining 300;
-_injurer = _this select 1;
if (isPlayer _unit) then
- {
+{
_isPlayer = true;
- if (!isMultiplayer) then {_bleedOut = time + 600};//50
- _unit spawn
- {
- sleep 5;
- _this allowDamage true;
- };
+ _unit spawn { sleep 5; _this allowDamage true };
closeDialog 0;
+ openMap false;
if (!isNil "respawnMenu") then {(findDisplay 46) displayRemoveEventHandler ["KeyDown", respawnMenu]};
respawnMenu = (findDisplay 46) displayAddEventHandler ["KeyDown",
- {
- _handled = false;
- if (_this select 1 == 19) then
- {
- if (player getVariable ["incapacitated",false]) then
- {
- (findDisplay 46) displayRemoveEventHandler ["KeyDown", respawnMenu];
- [player] spawn A3A_fnc_respawn;
- };
- };
- _handled;
- }];
+ {
+ if !(player getVariable ["incapacitated",false]) exitWith {false};
+ if (_this select 1 == 19) then {
+ [player] spawn A3A_fnc_respawn;
+ };
+ if (_this select 1 == 35) then {
+ if (A3A_selfReviveMethods) then { [] spawn A3A_fnc_selfRevive };
+ //if (A3A_selfReviveMethods == 2) then { [] spawn A3A_fnc_transferToAI }; // different keys later?
+ };
+ false;
+ }];
if (_injurer != Invaders) then {_unit setCaptive true};
- openMap false;
{
- if ((!isPlayer _x) and (vehicle _x != _x) and (_x distance _unit < 50)) then {unassignVehicle _x; [_x] orderGetIn false}
+ if ((!isPlayer _x) and (vehicle _x != _x) and (_x distance _unit < 50)) then {unassignVehicle _x; [_x] orderGetIn false}
} forEach units group _unit;
- }
+}
else
- {
+{
if ({isPlayer _x} count units group _unit > 0) then {_inPlayerGroup = true};
_unit stop true;
if (_inPlayerGroup) then
@@ -96,21 +90,25 @@ while {(time < _bleedOut) and (_unit getVariable ["incapacitated",false]) and (a
};
if (_isPlayer) then {
- private _textX = "There is no AI near to help you.
Hit R to Respawn";
- if !(isNull _helper) then {
- if (_helper distance _unit < 3) then {
- _textX = format ["%1 is on the way to help you.
Hit R to Respawn", name _helper];
- } else {
- _textX = format ["%1 is helping you.
Hit R to Respawn", name _helper];
- };
+ private _helpText = "" + call {
+ if (isNull _helper) exitWith { "There is no AI near to help you." };
+ if (_helper distance _unit < 3) exitWith { format ["%1 is helping you.", name _helper] };
+ format ["%1 is on the way to help you.", name _helper];
+ };
+ private _respawnText = "
Hit R to Respawn";
+ private _reviveText = call {
+ if (A3A_selfReviveMethods) exitWith { "
Hit H to Withstand Injury" };
+ //if (A3A_selfReviveMethods == 2) exitWith { "
Hit H to take over nearest AI ally" };
+ ""
};
private _layer = ["A3A_infoCenter"] call BIS_fnc_rscLayer;
- [_textX,0,0,3,0,0,_layer] spawn bis_fnc_dynamicText;
+ [_helpText + _respawnText + _reviveText,0,0,3,0,0,_layer] spawn bis_fnc_dynamicText;
};
- sleep 3;
- if !(isNull attachedTo _unit) then {_bleedOut = _bleedOut + 3}; // delay bleedout if dragged or loaded into vehicle
- if (random 20 < 1) then {playSound3D [(selectRandom injuredSounds),_unit,false, getPosASL _unit, 1, 1, 50]};
+ private _sleepTime = [3, 1] select (isPlayer _unit);
+ sleep _sleepTime;
+ if !(isNull attachedTo _unit) then {_bleedOut = _bleedOut + _sleepTime}; // delay bleedout if dragged or loaded into vehicle
+ if (random 60 < _sleepTime) then {playSound3D [(selectRandom injuredSounds),_unit,false, getPosASL _unit, 1, 1, 50]};
};
if (_isPlayer) then
@@ -133,25 +131,27 @@ else
};
};
-if (captive _unit) then {_unit setCaptive false};
_unit setVariable ["overallDamage",damage _unit];
if (_isPlayer and (_unit getVariable ["respawn",false])) exitWith {};
if (time > _bleedOut) exitWith
- {
- if (_isPlayer) then
- {
- [_unit] call A3A_fnc_respawn
- }
- else
- {
- _unit setDamage 1;
- };
- };
+{
+ if (isPlayer _unit) exitWith { [player] spawn A3A_fnc_respawn };
+ if (captive _unit) then {_unit setCaptive false};
+ _unit setDamage 1;
+};
if (alive _unit) then
- {
+{
_unit setUnconscious false;
//_unit playMoveNow "AmovPpneMstpSnonWnonDnon_healed";
_unit playMoveNow "unconsciousoutprone";
_unit setBleedingremaining 0;
+
+ // Temp invulnerability on revive
+ _unit allowDamage false;
+ _unit spawn {
+ sleep 5;
+ if (captive _this) then {_this setCaptive false};
+ _this allowDamage true;
};
+};
diff --git a/A3A/addons/core/functions/Revive/fn_unconsciousAAF.sqf b/A3A/addons/core/functions/Revive/fn_unconsciousAAF.sqf
index 389c500d53..da0b91a427 100644
--- a/A3A/addons/core/functions/Revive/fn_unconsciousAAF.sqf
+++ b/A3A/addons/core/functions/Revive/fn_unconsciousAAF.sqf
@@ -1,22 +1,22 @@
#include "..\..\script_component.hpp"
FIX_LINE_NUMBERS()
-params ["_unit", "_injurer"];
+params ["_unit", "_injurer", "_fatalWound"];
+
+_unit setDamage 0.9;
+if (!_fatalWound) then { _unit setHitPointDamage ["hitface", 0.5]; }; // fatal wound marker
private _bleedOutTime = if (surfaceIsWater (position _unit)) then {time + 60} else {time + 300};
private _playerNear = false;
private _group = group _unit;
private _side = side _group;
-// This is... quite weird
-if ({if ((isPlayer _x) and (_x distance _unit < distanceSPWN2)) exitWith {1}} count allUnits != 0) then
+if (playableUnits inAreaArray [getPosATL _unit, distanceSPWN2, distanceSPWN2] isNotEqualTo []) then
{
_playerNear = true;
[_unit,"heal"] remoteExec ["A3A_fnc_flagaction",0,_unit];
_unit setCaptive true;
};
-_unit setFatigue 1; // Doesn't do anything since Arma stamina rework?
-
private _nextRequest = 0;
while { (alive _unit) && (time < _bleedOutTime) && (_unit getVariable ["incapacitated",false]) } do
{
@@ -51,14 +51,6 @@ if (_playerNear) then
if (time >= _bleedOutTime) exitWith
{
- if (side _injurer == teamPlayer) then
- {
- if (isPlayer _injurer) then
- {
- [1,_injurer] call A3A_fnc_playerScoreAdd;
- };
- [-1,1,getPos _unit] remoteExec ["A3A_fnc_citySupportChange",2];
- };
_unit setDamage 1;
};
@@ -67,6 +59,7 @@ if (alive _unit) then
_unit setUnconscious false;
_unit playMoveNow "unconsciousoutprone";
_unit setVariable ["overallDamage",damage _unit];
+ _unit setVariable ["A3A_downedBy", nil];
if (_unit getVariable ["surrendering", false]) exitWith {
_unit setVariable ["surrendering", nil, true];
diff --git a/A3A/addons/core/functions/init/fn_initVarCommon.sqf b/A3A/addons/core/functions/init/fn_initVarCommon.sqf
index 036f402df2..cb8a070ca5 100644
--- a/A3A/addons/core/functions/init/fn_initVarCommon.sqf
+++ b/A3A/addons/core/functions/init/fn_initVarCommon.sqf
@@ -15,6 +15,9 @@ Info("Setting initial variables");
debug = false;
//A3A_customHintEnable = false; // Disables custom hints for boot duration. Is set to true in initClient.
+// Antistasi revive vest damage adjustments
+A3A_vestDamageAdj = createHashMap;
+
////////////////////////////////////
// BEGIN SIDES AND COLORS ///
////////////////////////////////////
@@ -183,6 +186,19 @@ for "_person" from 1 to 18 do {
};
+////////////////////////////////////
+// MEDICAL STUFF ///
+////////////////////////////////////
+
+// Generated by scanning for abdomen hitpoint armor > 1. Will probably never change.
+private _strongUniforms = ["U_O_CombatUniform_ocamo","U_O_GhillieSuit","U_O_PilotCoveralls","U_O_Wetsuit","U_O_CombatUniform_oucamo","U_O_SpecopsUniform_ocamo",
+"U_O_SpecopsUniform_blk","U_I_pilotCoveralls","U_O_FullGhillie_lsh","U_O_FullGhillie_sard","U_O_FullGhillie_ard","U_O_T_Soldier_F",
+"U_O_T_Sniper_F","U_O_T_FullGhillie_tna_F","U_O_V_Soldier_Viper_F","U_O_V_Soldier_Viper_hex_F","U_O_R_Gorka_01_F","U_O_R_Gorka_01_brown_F",
+"U_O_R_Gorka_01_camo_F","U_O_R_Gorka_01_black_F"];
+
+A3A_strongUniformsHM = _strongUniforms createHashMapFromArray []; // fills with nils, which is fine
+
medicAnims = ["AinvPknlMstpSnonWnonDnon_medic_1","AinvPknlMstpSnonWnonDnon_medic0","AinvPknlMstpSnonWnonDnon_medic1","AinvPknlMstpSnonWnonDnon_medic2"];
+
Info("initVarCommon completed");
diff --git a/A3A/addons/core/functions/proxy/fn_onPlayerRespawn.sqf b/A3A/addons/core/functions/proxy/fn_onPlayerRespawn.sqf
index e837edd429..09aa55d2aa 100644
--- a/A3A/addons/core/functions/proxy/fn_onPlayerRespawn.sqf
+++ b/A3A/addons/core/functions/proxy/fn_onPlayerRespawn.sqf
@@ -27,6 +27,8 @@ _nul = [_oldUnit] spawn A3A_fnc_postmortem;
_oldUnit setVariable ["incapacitated",false,true];
_newUnit setVariable ["incapacitated",false,true];
+[true] call A3A_fnc_selfReviveReset;
+
if (side group player == teamPlayer) then
{
_owner = _oldUnit getVariable ["owner",_oldUnit];