Jump to content
diwako

Armor Plates System - Standalone Alternative Medical System

Recommended Posts

Standalone Arma 3 Alternative Medical System

 

Features

  • Many settings to fit your play style
  • Lightweight
  • ACE features support
  • Own revive system (Only when ACE medical is not loaded)
  • UI and QoL additions
  • ACE medical rewrite support (WIP)

 

Info - Standalone mode

The Armor Plates System (APS) is at its core a stand-alone medical system. It is meant to abstract Arma 3’s vanilla damage and streamline the vanilla medical system. It draws inspiration from COD MW Warzone’s medical system and allows you to put ceramic plates into your vest which act as additional HP.
Originally this system was created to accommodate the play style used by the streamer Beagle over at https://www.twitch.tv/beagsandjam/ , though as usual I want to share this with the whole community.

This system gives each unit health points (HP) which will be reduced by incoming damage. The armor plates have their own amount of HP which will act as a layer above the unit’s HP. The unit will only take damage if the ceramic plates in the unit’s vests are fully destroyed. The ceramic plates themselves are an inventory item that needs to be inserted into vests to provide protection. In order to put a ceramic plate into your vest, you must have a ceramic plate item in your inventory and press and hold the key bind to perform the action (default: T). This keybind can be changed.

This mod also includes new UI elements such as damage direction indicators, on-hit sound indicators, and downed icons in 3D space. These are meant to aid newer players or help players make sense of a chaotic battlefield. All of these features can be disabled or customized under “Armor Plates System” inside Addon Options.
Your unit’s HP and armor plates are shown beneath the stamina bar. Switching units and even remote controlling them with Zeus is supported. The armor plate color can be adjusted in “Addon Options” while the rest of the colors will use your current HUD settings.

This system makes heavy use of CBA settings, allowing server owners or mission makers to make players or AI as tanky or brittle as you’d like. If you are playing a mission that is incompatible with this system or uses its own medical system with it, you can simply disable the Armor Plates System, restart the mission, and play the mission without this mod interfering. However, ALL of the mod’s features will be disabled!
 

Info - ACE Medical mode

When ACE with its medical components (rewrite and NOT old medical!) is loaded, APS will switch its standalone arcade mode to a more realistically one. In this mode the plates in your vest will only protect from gunshots and blunt force to your torso. If your limbs or your head gets hit, it will react as ACE medical normally would. There will not be any unit HP either, as this does not fit into the ACE medical system with its structural damage and blood simulation. Many of the standalone mode’s features will be disabled, some feedback features will be still available, but turned off by default.

Ceramic plates now have a certain thickness (settable in addon options) which bullets can penetrate and bleed damage to the lower plates, or to your torso. Ceramic plates are also getting destroyed faster the less integrity (health) they have left, making it more likely that a gunshot will damage deeper protective layers.

Overall, this will make units with ceramic plates in their vests more survivable, but only temporarily as the plates can be destroyed. Damage to units without any plates will behave the same as ACE medical. Going for the head will still work as before.
 

Feature requests and Bug reports

Please use the GitHub link below and create issues for enhancement requests or bug reports. It makes it a lot easier to keep track of these things.

 

Spoiler

?imw=5000&imh=5000&ima=fit&impolicy=Lett

 

?imw=5000&imh=5000&ima=fit&impolicy=Lett

 

?imw=5000&imh=5000&ima=fit&impolicy=Lett

 

?imw=5000&imh=5000&ima=fit&impolicy=Lett

 

?imw=5000&imh=5000&ima=fit&impolicy=Lett

 

?imw=5000&imh=5000&ima=fit&impolicy=Lett

 

?imw=5000&imh=5000&ima=fit&impolicy=Lett

 

 

GitHub: https://github.com/diwako/armor_plates_system

Steam Workshop: https://steamcommunity.com/sharedfiles/filedetails/?id=2523439183

  • Like 6
  • Thanks 1

Share this post


Link to post
Share on other sites

Another Top notch contribution as we have come to expect from @diwako .

 

You have certainly consistently spoiled the Arma community with quality content that rivals even official content and for that and the countless hours of amazing gameplay brought by those contributions, I thank you!

 

Quick question: I imagine that each different armor has different Plates capacity? Like low armor suports 1 plate while the biggest amors support 3 plates? Or is it a matter of how strong the plates are to difference those light vests versus heavy vests.

Share this post


Link to post
Share on other sites
1 minute ago, LSValmont said:

Another Top notch contribution as we have come to expect from @diwako .

 

You have certainly consistently spoiled the Arma community with quality content that rivals even official content and for that and the countless hours of amazing gameplay brought by those contributions, I thank you!

 

Quick question: I imagine that each different armor has different Plates capacity? Like low armor suports 1 plate while the biggest amors support 3 plates? Or is it a matter of how strong the plates are to difference those light vests versus heavy vests.

 

Nah, it was decided on a gameplay and implementation level that all vests will have the same "plate slots". That means a vest with 0  armor value configured will have also the same amount of slots than a heavily armored vest. So all in all, the max amount of plates are handled via a CBA setting.

Share this post


Link to post
Share on other sites
7 minutes ago, diwako said:

 

Nah, it was decided on a gameplay and implementation level that all vests will have the same "plate slots". That means a vest with 0  armor value configured will have also the same amount of slots than a heavily armored vest. So all in all, the max amount of plates are handled via a CBA setting.

 

But doesn't that mean that players can wear a very light vest having very low stamina impact while having all the benefits of a full blown max armor vest?

Share this post


Link to post
Share on other sites
25 minutes ago, LSValmont said:

 

But doesn't that mean that players can wear a very light vest having very low stamina impact while having all the benefits of a full blown max armor vest?

 

Essentially yes. Right now. I am not too sure how a system would work that takes the vests armor value into account and calculates how much slots that vest type would have.

Share this post


Link to post
Share on other sites
22 minutes ago, diwako said:

 

Essentially yes. Right now. I am not too sure how a system would work that takes the vests armor value into account and calculates how much slots that vest type would have.

 

Perhaps the solution could be just to add arrays of Light, Medium and Heavy vests and have plates have different "health" values for each vest type.

 

Drawbacks include having to update that array for each vest/mod.

 

There was a mod by the exile devs that would show the armor on the inventory screen so there is definitely a way to get that in game.

Share this post


Link to post
Share on other sites
9 minutes ago, LSValmont said:

 

Perhaps the solution could be just to add arrays of Light, Medium and Heavy vests and have plates have different "health" values for each vest type.

 

Drawbacks include having to update that array for each vest/mod.

 

There was a mod by the exile devs that would show the armor on the inventory screen so there is definitely a way to get that in game.

 

Yeah i especially wanted to avoid the need to edit vest configs. that would be compat hell. There are armor values in the configs, but it would mean to figure out what is a high armored vest and which isn't.

Share this post


Link to post
Share on other sites
5 minutes ago, diwako said:

 

Yeah i especially wanted to avoid the need to edit vest configs. that would be compat hell. There are armor values in the configs, but it would mean to figure out what is a high armored vest and which isn't.

 

On the Arsenal screen there are bars that show the amount of "ballistic protection". You will have values from 0 to Max ballistic protection. If max ballistic protection is 1 and you can script that assigns HP based on that "ballistic Protection". 

 

Perhaps values from 0.01 to 0.25 of ballistic protection is considered low, values from 0.25 to 0.5 is medium and anything above 0.5 is heavy.

Share this post


Link to post
Share on other sites

Version 0.3.0 has been released.

 

Changelog:

The rewrite for the ACE medical integration is the biggest feature in this release. Plates behave differently in this mode now.
They only protect a unit’s torso now, break faster the less integrity (HP) they have, and they now have a thickness setting which
influences if a bullet can penetrate a plate. If a bullet penetrates a plate, it will bleed its velocity damage to lower plates
or your torso if you got none below the penetrated plate.

------

Added setting to protect torso only in standalone mode (#2)
Added Max HP slider in 3den editor (#3)
Added self revive setting and action (#10)

Rewritten ACE medical mode to make it more realistically (#4)

Fixed animation glitch when ACE dragging people and then reviving (#8)
Fixed left clicking in ace actions breaking on start up (#9)
Fixed being able to revive people when getting downed (#11)
Fixed disallow friendly fire setting not working properly with zeus controlled units (#15)

Added Polish translations by @genjonakasone

 

Downloads:

https://github.com/diwako/armor_plates_system/releases/tag/0.3.0

https://steamcommunity.com/sharedfiles/filedetails/?id=2523439183

 

  • Like 2
  • Thanks 1

Share this post


Link to post
Share on other sites

Version 0.4.0 has been released.

 

Changelog:

In this release the largest addition is the ability for AI to revive fallen squad mates as well as being able to be knocked unconsciousness.
Those two features only work for AI in a player’s squad!
Keep in mind, the AI is still AI, under perfect conditions the AI will be easily revive a squad mate, but under fire that might be different. Sometimes the AI will prefer to take cover instead of running out into the open.

------

Added ACE interaction to add plate (#19)
Added Zeus heal module (#24)
Added AI unconsciousness (#23)
Added revive from AI (#23)
Added 3den properties for armor plates (#20)

Changed downed indicator, now shows if someone is being revived already (#21)

Fixed plates being indestructible when changing plate HP setting mid game (ACE mode) (#25)

 

Downloads:

https://github.com/diwako/armor_plates_system/releases/tag/0.4.0

https://steamcommunity.com/sharedfiles/filedetails/?id=2523439183

  • Like 2
  • Thanks 1

Share this post


Link to post
Share on other sites

Did a bugfix release, had to address a few things.

 

Primarily a bug fix release. Adds one feature that I think people should explore. It is a script version filter for the HandleDamage event handler.
With this damage should be more predictable when using HandleDamage.
This filter is off by default and can be enabled when using the standalone mode inside the addon options directly beneath the event handler setting.


------

Added filter damage for HandleDamage eh (#26)

Changed fall damage calculation (#27)

Fixed damage indicators showing when standing near fire (ACE mode) (#28)
Fixed multiple ACE interaction issues (#29)

 

Downloads:

https://steamcommunity.com/sharedfiles/filedetails/?id=2523439183

https://github.com/diwako/armor_plates_system/releases/tag/0.4.1

 

Share this post


Link to post
Share on other sites
4 hours ago, diwako said:

Did a bugfix release, had to address a few things.


Primarily a bug fix release. Adds one feature that I think people should explore. It is a script version filter for the HandleDamage event handler.
With this damage should be more predictable when using HandleDamage.
This filter is off by default and can be enabled when using the standalone mode inside the addon options directly beneath the event handler setting.


------

Added filter damage for HandleDamage eh (#26)

Changed fall damage calculation (#27)

Fixed damage indicators showing when standing near fire (ACE mode) (#28)
Fixed multiple ACE interaction issues (#29)

 

 

Great fixes! 

 

This part on the old handledamage eh was very weird to me: 

|| {_hitPoint in ["hithead", "hitbody", "hithands", "hitlegs"]} exitWith {_curDamage};

Loving the filter because the handleDamage is such a mess that it is the best option just to pass the greater damage and leave all residual weird damage that only spam the EH and hurts performance. So your solution is both better to understand what is going on and also for optimization reasons.

 

Do you mind if I use part of that code for my own personal EH? Never to be released as a mod of course 😉

Share this post


Link to post
Share on other sites
7 hours ago, LSValmont said:

Do you mind if I use part of that code for my own personal EH? Never to be released as a mod of course 😉

 

The mod is published under GPL + an appendix to no upload to workshop. So that is fine. In general if you use parts of mods in personal, never to be released and shared mods, that is totally fine.

  • Like 2

Share this post


Link to post
Share on other sites
15 hours ago, diwako said:

 

The mod is published under GPL + an appendix to no upload to workshop. So that is fine. In general if you use parts of mods in personal, never to be released and shared mods, that is totally fine.

 

Thank you! 

 

Almost done, any suggestions?

Spoiler

 


vBloodWoundDamageEH = {
	// Vars
	vEnableDamageCache = true;
	vDisableFriendlyFire = false;
	vPlayerDamageCoef = 1;

	player addEventHandler ["HandleDamage", {
		params ["_unit", "", "_damage", "_source", "_projectile", "_hitIndex", "_instigator", "_hitPoint"];
		
		if !(local _unit) exitWith {nil};
		
		private _curDamage = 0;
		if (_hitPoint isEqualTo "") then {
			_hitPoint = "#structural";
			_curDamage = damage _unit;
		} else {
			_curDamage = _unit getHitIndex _hitIndex;
		};
		
		if !(isDamageAllowed _unit) exitWith {_curDamage};
		
		private _newDamage = _damage - _curDamage;
		if (_newDamage < 0.01) exitWith {
			_curDamage
		};
		
		// Damage from Drowning
		if (
			_hitPoint isEqualTo "#structural" &&
			{getOxygenRemaining _unit <= 0.5} &&
			{_damage isEqualTo (_curDamage + 0.005)}
		) exitWith {
			[_unit, _newDamage, _curDamage, "body", _unit] call vBloodWoundDamCalc;
			0
		};
		
		// Damage from Vehicle Collision
		private _vehicle = vehicle _unit;
		if (
			_hitPoint isEqualTo "#structural" &&
			{_projectile isEqualTo ""} &&
			{_vehicle isNotEqualTo _unit} &&
			{vectorMagnitude (velocity _vehicle) > 5}
		) exitWith {
			[_unit, _newDamage / 2, _curDamage, "vehicle", _unit] call vBloodWoundDamCalc;
			0
		};		
		
		// Fall Damage		
		if (
			_projectile isEqualTo "" && {
			([_source, _instigator] select (isNull _source)) isEqualTo _unit && {
			vectorMagnitude (velocity _unit) > 5 || {((velocity _unit) select 2) < -2}}}
		) exitWith {
			if (_hitPoint isEqualTo "incapacitated") then {
				[_unit, _newDamage * 2, _curDamage, "falldamage", _unit] call vBloodWoundDamCalc;
				0
			} else {
				_curDamage
			};
		};
		
		// No damage passed
		if (_projectile isEqualTo "" && {isNull _source}) exitWith {
			_curDamage
		};
		
		// Damage Filter
		if (vEnableDamageCache) then {
			private _damageCache = _unit getVariable [playerDamageCache, []];
			if (_damageCache isEqualTo []) then {
				_unit setVariable [playerDamageCache, _damageCache];
				[{
					params ["_unit", "_source"];
					private _damageCache = _unit getVariable [_damageCache, []];
					if (_damageCache isNotEqualTo []) then {
						_damageCache sort false;
						(_damageCache select 0) params ["_newDamage", "_hitPoint"];
						[_unit, _newDamage, _curDamage, _hitPoint, _source] call vBloodWoundDamCalc;
					};
					_unit setVariable [playerDamageCache, nil];
				}, [_unit, [_source, _instigator] select (isNull _source)]] call CBA_fnc_execNextFrame;
			};
			_damageCache pushBack [_newDamage, _hitPoint];
		} else {
			[_unit, _newDamage, _curDamage, _hitPoint, [_source, _instigator] select (isNull _source)] call vBloodWoundDamCalc;
		};
		0
	}];
};

vBloodWoundDamCalc = {
	params ["_unit", "_newDamage", "_curDamage", "_bodyPart", "_instigator"];
	if (_newDamage <= 0 || {!alive _unit} || {lifeState _unit isEqualTo "INCAPACITATED"}) exitWith {};
	
	_currentBlood = (_unit getVariable "unit_bloodCurrent");
	if (_currentBlood <= 0.20) exitWith {};
	
	if (
		(vDisableFriendlyFire) &&
		{!isNull _instigator && 
		{_instigator isNotEqualTo _unit && 
		{(side group _unit) isEqualTo (side group _instigator)}}}
	) exitWith {};
	
	// Damage multipliers.  The damage of each projectile will be multiplied by this number.
	private _damageMultiplierHead = 0.3;
	private _damageMultiplierBody = 0.25;
	private _damageMultiplierLimbs = 0.15;
	private _damageMultiplierOverall = 0.25;

	// Damage limits. Each projectile will be limited to a max of this much damage.
	private _limitHead = 0.8;
	private _limitBody = 0.30;
	private _limitLimbs = 0.15;
	private _limitOverall = 0.25;
	
	private _isHeadshot = false;
	private _isLeg = false;
	private _damageDone = false;
	private _finalWound = 0;
	private _maxWounds = 0.95;
	switch (_bodyPart) do {
		case "face_hub": {_newDamage = _newDamage * _damageMultiplierHead; if (_newDamage > _limitHead) then {_newDamage = _limitHead}; _newDamage = _newDamage * vPlayerDamageCoef; _finalWound = (_curDamage - _newDamage) max 0; _unit setHit ["hands", _finalWound]; _damageDone = true;};
		case "face": {_newDamage = _newDamage * _damageMultiplierHead; if (_newDamage > _limitHead) then {_newDamage = _limitHead}; _newDamage = _newDamage * vPlayerDamageCoef; _finalWound = (_curDamage - _newDamage) max 0; _unit setHit ["hands", _finalWound]; _damageDone = true;};
		case "head": {_isHeadshot = _newDamage > 0.5; _newDamage = _newDamage * _damageMultiplierHead; if (_newDamage > _limitHead) then {_newDamage = _limitHead}; _newDamage = _newDamage * vPlayerDamageCoef; _finalWound = (_curDamage - _newDamage) max 0; _unit setHit ["head", _finalWound]; _damageDone = true;};
		case "arms": {_newDamage = _newDamage * _damageMultiplierLimbs; if (_newDamage > _limitLimbs) then {_newDamage = _limitLimbs}; _newDamage = _newDamage * vPlayerDamageCoef; _finalWound = (_curDamage - _newDamage) max 0; _unit setHit ["arms", _finalWound]; _damageDone = true; };
		case "hands": {_newDamage = _newDamage * _damageMultiplierLimbs; if (_newDamage > _limitLimbs) then {_newDamage = _limitLimbs}; _newDamage = _newDamage * vPlayerDamageCoef; _finalWound = (_curDamage - _newDamage) max 0; _unit setHit ["arms", _finalWound]; _damageDone = true; };
		case "legs": {_isLeg = _newDamage > 0.5; _newDamage = _newDamage * _damageMultiplierLimbs; if (_newDamage > _limitLimbs) then {_newDamage = _limitLimbs}; _newDamage = _newDamage * vPlayerDamageCoef; _finalWound = (_curDamage - _newDamage) max 0; _unit setHit ["legs", _finalWound]; _damageDone = true;};
		case "vehicle": {_newDamage = _newDamage * _damageMultiplierLimbs; if (_newDamage > _limitLimbs) then {_newDamage = _limitLimbs}; _newDamage = _newDamage * vPlayerDamageCoef; _finalWound = (_curDamage - _newDamage) max 0; _unit setHit ["legs", _finalWound]; _damageDone = true;};
		case "incapacitated": {_newDamage = _newDamage * _damageMultiplierOverall; if (_newDamage > _limitOverall) then {_newDamage = _limitOverall;}; _newDamage = _newDamage * vPlayerDamageCoef; _finalWound = (_curDamage - _newDamage) max 0; _unit setHit ["legs", _finalWound]; _damageDone = true;};
		case "#structural";
		case "falldamage": {{_newDamage = _newDamage * _damageMultiplierOverall; if (_newDamage > _limitOverall) then {_newDamage = _limitOverall;};}; _newDamage = _newDamage * vPlayerDamageCoef; _finalWound = (_curDamage - _newDamage) max 0; _unit setHit ["legs", _finalWound]; _damageDone = true; [_unit,_bodyPart,_newDamage] call vSimbolicDamage;};
		default {_newDamage = _newDamage * _damageMultiplierBody; if (_newDamage > _limitBody) then {_newDamage = _limitBody}; _newDamage = _newDamage * vPlayerDamageCoef; _finalWound = (_curDamage - _newDamage) max 0; _unit setHit ["body", _finalWound]; _damageDone = true;};
	};
	
	if !(_damageDone) then {
		_newDamage = _newDamage * vPlayerDamageCoef;
		_finalWound = (_curDamage - _newDamage) max 0;
		_maxWounds = 0.95;
		_unit setDamage (0.251 max (linearConversion [0, _maxWounds, _finalWound, 0.95, 0, true]));
	};
	
	if (_isHeadShot) then {
		playSound3D ["A3\Sounds_F\characters\human-sfx\Person1\P1_breath_high_14_z.wss", player];
		[_unit,_bodypart,_finalWound] call vSimbolicDamage;
	};
	
	if (_isLeg) then {
		playSound3D ["A3\Sounds_F\characters\human-sfx\Person1\P1_breath_high_14_z.wss", player];
		[_unit,_bodypart,_finalWound] call vSimbolicDamage;
	};	
};

vSimbolicDamage = {
	params ["_unit","_selection","_finalWound"];
	
	if !(isNull objectParent _unit) exitWith {};
	if !(local _unit) exitWith {};
	if !(alive _unit) exitWith {};
	if (_finalWound < 0.05) exitWith {};
	if (lifeState _unit == "INCAPACITATED") exitWith {};
	
	switch (_selection) do {
		case "face_hub";
		case "head": {
			if ((_finalWound)>0.7) then {[_unit,8,true] spawn vTempIncapacitation;};
		};
		case "arms";
		case "hands";
		case "legs": {
			if ((_finalWound)>0.7) then {[_unit,2,true] spawn vTempIncapacitation;};
		};
		case "": {
			if ((_finalWound)>0.7) then {[_unit,5,true] spawn vTempIncapacitation;};
		};
		default { 
			if ((_finalWound)>0.7) then {[_unit,4,true] spawn vTempIncapacitation;};
		};
	};
};

vTempIncapacitation = {
	params [
	["_unit",objNull,[objNull]],
	["_recoveryTime",5,[5]],
	["_makeCaptive",false,[false]]
	];
	
	if (isBurning _unit) exitWith {}; // Better not making a unit fall uncouncious while burning!
	if (isPlayer _unit) then {[_unit,5000] call vbloodEffect;};
	if (_recoveryTime < 0.1) then {_recoveryTime = 0.1};
	_unit setUnconscious true;
	if (_makeCaptive) then {_unit setCaptive true};
	private _playersInGroup = [];
	_playersInGroup = (units (group _unit)) select {_x in allPlayers};	
	if !(isPlayer _unit) then {
		if (_playersInGroup isEqualTo []) then {
			{_unit disableAi _x} count ["FSM","TARGET","PATH","AUTOTARGET","AUTOCOMBAT","COVER","CHECKVISIBLE","MINEDETECTION","WEAPONAIM","AIMINGERROR","NVG","RADIOPROTOCOL"];
		};
	};
	sleep _recoveryTime;
	_unit setUnconscious false;
	if !(isPlayer _unit) then {
		_unit setUnitPos "UP";
		[_unit,"AgonyStop"]remoteExec["playAction",0,true];
		{_unit enableAi _x} count ["FSM","TARGET","PATH","AUTOTARGET","AUTOCOMBAT","COVER","CHECKVISIBLE","WEAPONAIM","AIMINGERROR","RADIOPROTOCOL"];
	};
	sleep 2;
	if (_makeCaptive) then {_unit setCaptive false};
};

vbloodEffect = {
	params ["_unit", "_ammount"];
	if (isPlayer _unit && local _unit) then {[_ammount] call BIS_fnc_bloodEffect};
	if (random 10>8) then {[_unit] call vPainShout;};
};

 

 

 

 

Share this post


Link to post
Share on other sites

It would be nice, if you could pick up or drag wounded soldiers. I am unsure if that would be feasible though?

Share this post


Link to post
Share on other sites
On 7/1/2021 at 11:42 PM, LSValmont said:

 

Thank you! 

 

Almost done, any suggestions?

  Reveal hidden contents

 



vBloodWoundDamageEH = {
	// Vars
	vEnableDamageCache = true;
	vDisableFriendlyFire = false;
	vPlayerDamageCoef = 1;

	player addEventHandler ["HandleDamage", {
		params ["_unit", "", "_damage", "_source", "_projectile", "_hitIndex", "_instigator", "_hitPoint"];
		
		if !(local _unit) exitWith {nil};
		
		private _curDamage = 0;
		if (_hitPoint isEqualTo "") then {
			_hitPoint = "#structural";
			_curDamage = damage _unit;
		} else {
			_curDamage = _unit getHitIndex _hitIndex;
		};
		
		if !(isDamageAllowed _unit) exitWith {_curDamage};
		
		private _newDamage = _damage - _curDamage;
		if (_newDamage < 0.01) exitWith {
			_curDamage
		};
		
		// Damage from Drowning
		if (
			_hitPoint isEqualTo "#structural" &&
			{getOxygenRemaining _unit <= 0.5} &&
			{_damage isEqualTo (_curDamage + 0.005)}
		) exitWith {
			[_unit, _newDamage, _curDamage, "body", _unit] call vBloodWoundDamCalc;
			0
		};
		
		// Damage from Vehicle Collision
		private _vehicle = vehicle _unit;
		if (
			_hitPoint isEqualTo "#structural" &&
			{_projectile isEqualTo ""} &&
			{_vehicle isNotEqualTo _unit} &&
			{vectorMagnitude (velocity _vehicle) > 5}
		) exitWith {
			[_unit, _newDamage / 2, _curDamage, "vehicle", _unit] call vBloodWoundDamCalc;
			0
		};		
		
		// Fall Damage		
		if (
			_projectile isEqualTo "" && {
			([_source, _instigator] select (isNull _source)) isEqualTo _unit && {
			vectorMagnitude (velocity _unit) > 5 || {((velocity _unit) select 2) < -2}}}
		) exitWith {
			if (_hitPoint isEqualTo "incapacitated") then {
				[_unit, _newDamage * 2, _curDamage, "falldamage", _unit] call vBloodWoundDamCalc;
				0
			} else {
				_curDamage
			};
		};
		
		// No damage passed
		if (_projectile isEqualTo "" && {isNull _source}) exitWith {
			_curDamage
		};
		
		// Damage Filter
		if (vEnableDamageCache) then {
			private _damageCache = _unit getVariable [playerDamageCache, []];
			if (_damageCache isEqualTo []) then {
				_unit setVariable [playerDamageCache, _damageCache];
				[{
					params ["_unit", "_source"];
					private _damageCache = _unit getVariable [_damageCache, []];
					if (_damageCache isNotEqualTo []) then {
						_damageCache sort false;
						(_damageCache select 0) params ["_newDamage", "_hitPoint"];
						[_unit, _newDamage, _curDamage, _hitPoint, _source] call vBloodWoundDamCalc;
					};
					_unit setVariable [playerDamageCache, nil];
				}, [_unit, [_source, _instigator] select (isNull _source)]] call CBA_fnc_execNextFrame;
			};
			_damageCache pushBack [_newDamage, _hitPoint];
		} else {
			[_unit, _newDamage, _curDamage, _hitPoint, [_source, _instigator] select (isNull _source)] call vBloodWoundDamCalc;
		};
		0
	}];
};

vBloodWoundDamCalc = {
	params ["_unit", "_newDamage", "_curDamage", "_bodyPart", "_instigator"];
	if (_newDamage <= 0 || {!alive _unit} || {lifeState _unit isEqualTo "INCAPACITATED"}) exitWith {};
	
	_currentBlood = (_unit getVariable "unit_bloodCurrent");
	if (_currentBlood <= 0.20) exitWith {};
	
	if (
		(vDisableFriendlyFire) &&
		{!isNull _instigator && 
		{_instigator isNotEqualTo _unit && 
		{(side group _unit) isEqualTo (side group _instigator)}}}
	) exitWith {};
	
	// Damage multipliers.  The damage of each projectile will be multiplied by this number.
	private _damageMultiplierHead = 0.3;
	private _damageMultiplierBody = 0.25;
	private _damageMultiplierLimbs = 0.15;
	private _damageMultiplierOverall = 0.25;

	// Damage limits. Each projectile will be limited to a max of this much damage.
	private _limitHead = 0.8;
	private _limitBody = 0.30;
	private _limitLimbs = 0.15;
	private _limitOverall = 0.25;
	
	private _isHeadshot = false;
	private _isLeg = false;
	private _damageDone = false;
	private _finalWound = 0;
	private _maxWounds = 0.95;
	switch (_bodyPart) do {
		case "face_hub": {_newDamage = _newDamage * _damageMultiplierHead; if (_newDamage > _limitHead) then {_newDamage = _limitHead}; _newDamage = _newDamage * vPlayerDamageCoef; _finalWound = (_curDamage - _newDamage) max 0; _unit setHit ["hands", _finalWound]; _damageDone = true;};
		case "face": {_newDamage = _newDamage * _damageMultiplierHead; if (_newDamage > _limitHead) then {_newDamage = _limitHead}; _newDamage = _newDamage * vPlayerDamageCoef; _finalWound = (_curDamage - _newDamage) max 0; _unit setHit ["hands", _finalWound]; _damageDone = true;};
		case "head": {_isHeadshot = _newDamage > 0.5; _newDamage = _newDamage * _damageMultiplierHead; if (_newDamage > _limitHead) then {_newDamage = _limitHead}; _newDamage = _newDamage * vPlayerDamageCoef; _finalWound = (_curDamage - _newDamage) max 0; _unit setHit ["head", _finalWound]; _damageDone = true;};
		case "arms": {_newDamage = _newDamage * _damageMultiplierLimbs; if (_newDamage > _limitLimbs) then {_newDamage = _limitLimbs}; _newDamage = _newDamage * vPlayerDamageCoef; _finalWound = (_curDamage - _newDamage) max 0; _unit setHit ["arms", _finalWound]; _damageDone = true; };
		case "hands": {_newDamage = _newDamage * _damageMultiplierLimbs; if (_newDamage > _limitLimbs) then {_newDamage = _limitLimbs}; _newDamage = _newDamage * vPlayerDamageCoef; _finalWound = (_curDamage - _newDamage) max 0; _unit setHit ["arms", _finalWound]; _damageDone = true; };
		case "legs": {_isLeg = _newDamage > 0.5; _newDamage = _newDamage * _damageMultiplierLimbs; if (_newDamage > _limitLimbs) then {_newDamage = _limitLimbs}; _newDamage = _newDamage * vPlayerDamageCoef; _finalWound = (_curDamage - _newDamage) max 0; _unit setHit ["legs", _finalWound]; _damageDone = true;};
		case "vehicle": {_newDamage = _newDamage * _damageMultiplierLimbs; if (_newDamage > _limitLimbs) then {_newDamage = _limitLimbs}; _newDamage = _newDamage * vPlayerDamageCoef; _finalWound = (_curDamage - _newDamage) max 0; _unit setHit ["legs", _finalWound]; _damageDone = true;};
		case "incapacitated": {_newDamage = _newDamage * _damageMultiplierOverall; if (_newDamage > _limitOverall) then {_newDamage = _limitOverall;}; _newDamage = _newDamage * vPlayerDamageCoef; _finalWound = (_curDamage - _newDamage) max 0; _unit setHit ["legs", _finalWound]; _damageDone = true;};
		case "#structural";
		case "falldamage": {{_newDamage = _newDamage * _damageMultiplierOverall; if (_newDamage > _limitOverall) then {_newDamage = _limitOverall;};}; _newDamage = _newDamage * vPlayerDamageCoef; _finalWound = (_curDamage - _newDamage) max 0; _unit setHit ["legs", _finalWound]; _damageDone = true; [_unit,_bodyPart,_newDamage] call vSimbolicDamage;};
		default {_newDamage = _newDamage * _damageMultiplierBody; if (_newDamage > _limitBody) then {_newDamage = _limitBody}; _newDamage = _newDamage * vPlayerDamageCoef; _finalWound = (_curDamage - _newDamage) max 0; _unit setHit ["body", _finalWound]; _damageDone = true;};
	};
	
	if !(_damageDone) then {
		_newDamage = _newDamage * vPlayerDamageCoef;
		_finalWound = (_curDamage - _newDamage) max 0;
		_maxWounds = 0.95;
		_unit setDamage (0.251 max (linearConversion [0, _maxWounds, _finalWound, 0.95, 0, true]));
	};
	
	if (_isHeadShot) then {
		playSound3D ["A3\Sounds_F\characters\human-sfx\Person1\P1_breath_high_14_z.wss", player];
		[_unit,_bodypart,_finalWound] call vSimbolicDamage;
	};
	
	if (_isLeg) then {
		playSound3D ["A3\Sounds_F\characters\human-sfx\Person1\P1_breath_high_14_z.wss", player];
		[_unit,_bodypart,_finalWound] call vSimbolicDamage;
	};	
};

vSimbolicDamage = {
	params ["_unit","_selection","_finalWound"];
	
	if !(isNull objectParent _unit) exitWith {};
	if !(local _unit) exitWith {};
	if !(alive _unit) exitWith {};
	if (_finalWound < 0.05) exitWith {};
	if (lifeState _unit == "INCAPACITATED") exitWith {};
	
	switch (_selection) do {
		case "face_hub";
		case "head": {
			if ((_finalWound)>0.7) then {[_unit,8,true] spawn vTempIncapacitation;};
		};
		case "arms";
		case "hands";
		case "legs": {
			if ((_finalWound)>0.7) then {[_unit,2,true] spawn vTempIncapacitation;};
		};
		case "": {
			if ((_finalWound)>0.7) then {[_unit,5,true] spawn vTempIncapacitation;};
		};
		default { 
			if ((_finalWound)>0.7) then {[_unit,4,true] spawn vTempIncapacitation;};
		};
	};
};

vTempIncapacitation = {
	params [
	["_unit",objNull,[objNull]],
	["_recoveryTime",5,[5]],
	["_makeCaptive",false,[false]]
	];
	
	if (isBurning _unit) exitWith {}; // Better not making a unit fall uncouncious while burning!
	if (isPlayer _unit) then {[_unit,5000] call vbloodEffect;};
	if (_recoveryTime < 0.1) then {_recoveryTime = 0.1};
	_unit setUnconscious true;
	if (_makeCaptive) then {_unit setCaptive true};
	private _playersInGroup = [];
	_playersInGroup = (units (group _unit)) select {_x in allPlayers};	
	if !(isPlayer _unit) then {
		if (_playersInGroup isEqualTo []) then {
			{_unit disableAi _x} count ["FSM","TARGET","PATH","AUTOTARGET","AUTOCOMBAT","COVER","CHECKVISIBLE","MINEDETECTION","WEAPONAIM","AIMINGERROR","NVG","RADIOPROTOCOL"];
		};
	};
	sleep _recoveryTime;
	_unit setUnconscious false;
	if !(isPlayer _unit) then {
		_unit setUnitPos "UP";
		[_unit,"AgonyStop"]remoteExec["playAction",0,true];
		{_unit enableAi _x} count ["FSM","TARGET","PATH","AUTOTARGET","AUTOCOMBAT","COVER","CHECKVISIBLE","WEAPONAIM","AIMINGERROR","RADIOPROTOCOL"];
	};
	sleep 2;
	if (_makeCaptive) then {_unit setCaptive false};
};

vbloodEffect = {
	params ["_unit", "_ammount"];
	if (isPlayer _unit && local _unit) then {[_ammount] call BIS_fnc_bloodEffect};
	if (random 10>8) then {[_unit] call vPainShout;};
};

 

 

 

 

 

Looks fine so far. Suggestions,not really. Medical system always tend to spiral into feature creep. I'd say keep it simple

 

On 7/3/2021 at 12:44 AM, R0adki11 said:

It would be nice, if you could pick up or drag wounded soldiers. I am unsure if that would be feasible though?

 

Right now no plans, It was originally made with ace loaded and just the medical part cut out. It certainly is feasible but atm not really of interest.

  • Like 1

Share this post


Link to post
Share on other sites

Version 0.4.2 released

 

Added confirmation dialog for the give up action (#36)

Fixed incorrect usages of ace_medical_allowDamage flag (ACE mode) (#34)
Fixed self revive when healing under fire (#35)

Added Polish translations by @genjonakasone (#32 #37)

 

Downloads:

https://steamcommunity.com/sharedfiles/filedetails/?id=2523439183
https://github.com/diwako/armor_plates_system/releases/tag/0.4.2

  • Like 1

Share this post


Link to post
Share on other sites

With this release this mod has a new maintainer. Their name is "Word-Mule" and they are from the community which originally requested this mod.

 

Version 0.5.0 released

 

Fixed FAKs not being consumed when healing by @fariparedes (#46)
Fixed plates not being added to player after respawn (#48)
Fixed medic disconnecting during reviving dooming the unit (#49)

Added visible bleedout timer on the downed icons by @fariparedes (#46)
Added repeating healing animations when healing/reviving action is not done by @fariparedes (#47)
Added feature to disable known thirdparty medical system usually added in missions (#50)

Updated chinese translations by @mihuan-0 (#38)

 

Downloads:

https://steamcommunity.com/sharedfiles/filedetails/?id=2523439183
https://github.com/diwako/armor_plates_system/releases/tag/0.5.0

  • Like 4

Share this post


Link to post
Share on other sites

Any idea why the revive wouldn't work on KP Liberation? If I go to revive a buddy, it revives him then he dies right away. 

Share this post


Link to post
Share on other sites

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now

×