Jump to content
-ami- mofo

Reducing player damage

Recommended Posts

Hi guys I have this script that I put in a units init..

this addeventhandler ["HandleDamage", {  
_unit    = _this select 0;  
_selection   = _this select 1;  
_passedDamage  = _this select 2;  
_source   = _this select 3;  
_projectile  = _this select 4;  
_oldDamage = 0;  
_damageMultiplier = 0.5; 
 switch(_selection)do{  
 case("head") :{_oldDamage = _unit      getHitPointDamage "HitHead";};  
 case("body") :{_oldDamage = _unit      getHitPointDamage "HitBody";};  
 case("hands") :{_oldDamage = _unit     getHitPointDamage "HitHands";};  
 case("legs") :{_oldDamage = _unit      getHitPointDamage "HitLegs";};  
 case("")  :{_oldDamage = damage _unit;};  
 default{};  
 };  
_return = _oldDamage + ((_passedDamage - _oldDamage) *_damageMultiplier);  
_return  
}];

And it works a treat on AI but it doesn't work for players.

 

Is there a tweak to get it so it works on players? (MP co-op hosted on my machine).

 

Thanks.

Share this post


Link to post
Share on other sites

I have two computers both with arma so tried it out in MP. Didn't make any difference like it does to AI.

Share this post


Link to post
Share on other sites

Just read that player handle damage in arma 3 isn't working but nobody knows why. It worked in Arma 2. So until BIS fix it (if they fix it) then I guess I'd better always wear a special carrier rig lol.

Share this post


Link to post
Share on other sites

Not an official source, just read in several places where ppl are trying to find other ways of achieving it as they say that it's not working like it used to.

 

Google arma 3 player reduce damage and you'll find a few bits and pieces.

Share this post


Link to post
Share on other sites

After a little more testing it seems that the culprit is Arma's own revive system. Seems like it and damage handler won't work together.

 

Turn arma's revive off and that script does work in MP. But we use revive so unfortunately no reducing player damage for us. May just have to make the enemy a little less accurate lol.

  • Like 1

Share this post


Link to post
Share on other sites

Just read that player handle damage in arma 3 isn't working but nobody knows why.

After a little more testing it seems that the culprit is Arma's own revive system.

This is correct Revive adds a HandleDamage EH to the player. As per the wiki..

 

Multiple "HandleDamage" event handlers can be added to the same unit. If multiple EHs return damage value for custom damage handling, only last returned value will be considered by the engine. EHs that do not return value can be safely added after EHs that do return value.

So all you should need to do is wait until the Revive HandleDamage EH has been applied.

Remove the EH.

Add your own that manipulates the damage recieved.

Call the Revives HandleDamage function.

Pass result back to engine at the end of the EH.

 

Something like..

params[ "_unit" ];

//Exit if we are a player and not local
//Otherwise add EH for AI every where just incase their locality
//changes due to moving into a players group
//the EH will only fire where the AI is local
if ( isPlayer _unit && { !local _unit } ) exitWith {};

if ( isPlayer _unit ) then {
	//Waituntil REVIVE handleDamage EH has been applied
	waitUntil{ !isNil { _unit getVariable "bis_revive_ehDamage" } };
	//Remove REVIVE HandleDamage EH
	_unit removeEventHandler[ "HandleDamage", _unit getVariable "bis_revive_ehDamage" ];
};

//Only damage from last applied handleDamage EH is taken into consideration by the engine
//Apply a new EH so as we can override the damage applied
_unit addEventHandler [ "HandleDamage", {
	params ["_unit", "_selection", "_damage","_source","","_index"];
	
	systemChat format[ "Damage recieved: %1", _damage ];
	
	//Do any other damage calculations here
	//_damage is the total damage the unit has for this selection once this EH returns
	//e.g lets change the damage recieved for each selection
	if ( _index > -1 ) then {
		private _selectionDamage = _unit getHit _selection;
		private _damageRecieved = (_damage - _selectionDamage) max 0;
		_damageRecieved = _damageRecieved / 4;
		_damage = _damageRecieved + _selectionDamage;
	};
	
	systemChat format[ "Damage to REVIVE: %1", _damage ];
	
	//Only players respond to REVIVE
	if ( isPlayer _unit ) then {
		_this set[ 2, _damage ];
		//Call BI REVIVE HandleDamage EH passing new _damage value
		_damage = _this call BIS_fnc_reviveOnPlayerHandleDamage;
	};
	
	systemChat format[ "Damage to engine: %1", _damage ];
	
	_damage
	
}];

systemChat format[ "Override REVIVE EH applied to %1", _unit ];
Either in the initPlayerLocal or called from somewhere where you can pass the player in.

Ive been over cautious with the player checks but you can quite easily remove them from the start of the script to apply this for AI as well  and then the EH only applies Revive damage handling if its a player.

EDIT: Changed the script so you can pass either a player or AI and it will apply the damage changes and handle Revive if its a player.

  • Like 2

Share this post


Link to post
Share on other sites

Hi mate I'm a newb when it comes to scripting, I don't even understand all that.. I went to paste that (minus all the stuff after the //) in the units init (that's what you meant by initplayer local?) and got a type bool expected nothing error.

 

You may have to guide me a little more on getting this to work.

Share this post


Link to post
Share on other sites

by initplayerlocal he meant the hard coded event script.

 

so in practice what you do is create a file called InitPlayerLocal.sqf inside your mission folder and then paste the code in there. arma has several event scripts like this one. most commonly known one is the Init.sqf.

 

you can read up on it here:

https://community.bistudio.com/wiki/Event_Scripts

https://community.bistudio.com/wiki/Initialization_Order

Share this post


Link to post
Share on other sites

Thank you Larrow and Bad Benson  :)

 

That did indeed work. Tested in MP with Arma's revive plus a little script I have that keeps players in revive mode until time out. Worked perfect! 

 

The only question I have left is that when somebody takes any kind of damage even if small damage (ie- jumps off a wall) it lists all the damage info on the screen (bottom left).

 

Is there a way to remove that?

Share this post


Link to post
Share on other sites

Remove all the lines that start with systemChat as they are there exactly for that reason to show debug info about damage.

Share this post


Link to post
Share on other sites

There is some outdated information here (some bis name changes) and a bug (namely that _damageRecieved is inaccurate if _selection is "").  There is some helpful updated info here: 

 

Here's an updated version of the reduce damage script:

params[ "_unit" ];

// Damage reduction from https://forums.bistudio.com/forums/topic/198136-reducing-player-damage/

// Exit if we are a player and not local
// Otherwise add EH for AI every where just in case their locality
// changes due to moving into a players group
// the EH will only fire where the AI is local
if ( isPlayer _unit && { !local _unit } ) exitWith {};

if ( isPlayer _unit ) then {
	_unit removeAllEventHandlers 'HandleDamage';
};

// Only damage from last applied handleDamage EH is taken into consideration by the engine
// Apply a new EH so as we can override the damage applied
_unit addEventHandler [ "HandleDamage", {
	params ["_unit", "_hitSelection", "_damage","_source","_projectile","_hitPartIndex", "_instigator", "_hitPoint"];

	// 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 = 1.0;
	private _limitBody = 0.25;
	private _limitLimbs = 0.1;
	private _limitOverall = 0.25;

	private _oldDamage = 0;
	if (_hitSelection isEqualTo "") then {_oldDamage = damage _unit} else {_oldDamage = _unit getHit _hitSelection};
	private _newDamage = _damage - _oldDamage max 0;
	private _incomingDamage = _newDamage;
	private _playerHealth = damage _unit;

	// Infantry selections
	// Keep in mind that if revive is enabled then incapacitation may occur at around 0.7 damage.
	// "": The overall damage that determines the damage value of the unit. Unit dies at damage equal to or above 1
	// "face_hub": Unit dies at damage equal to or above 1
	// "neck": Unit dies at damage equal to or above 1
	// "head": Unit dies at damage equal to or above 1
	// "pelvis": Unit dies at damage equal to or above 1
	// "spine1": Unit dies at damage equal to or above 1
	// "spine2": Unit dies at damage equal to or above 1
	// "spine3": Unit dies at damage equal to or above 1
	// "body": Unit dies at damage equal to or above 1
	// "arms": Unit doesn't die with damage to this part
	// "hands": Unit doesn't die with damage to this part
	// "legs": Unit doesn't die with damage to this part

	// Do any other damage calculations here
	// _damage is the previous damage plus any new damage and will be applied
	// as the total damage the unit has for this selection once this EH returns

	// Only modify damage if it is a known projectile (leave falling damage etc alone)
	if (_newDamage > 0 && !(_projectile isEqualTo "")) then {
		// Reduce damage by damage multiplier
		private _damageMultiplier = _damageMultiplierBody;
		private _upperLimit = _limitBody;
		switch (_hitSelection) do {
			case "face_hub";
			case "head": {
				_damageMultiplier = _damageMultiplierHead;
				_upperLimit = _limitHead;
			};
			case "arms";
			case "hands";
			case "legs": {
				_damageMultiplier = _damageMultiplierLimbs;
				_upperLimit = _limitLimbs;
			};
			case "": {
				_damageMultiplier = _damageMultiplierOverall;
				_upperLimit = _limitOverall;
			};
			default { 
				_damageMultiplier = _damageMultiplierBody;
				_upperLimit = _limitBody;
			};
		};
		_newDamage = _newDamage * _damageMultiplier;

		// Place an upper limit on projectile damage done at once
		if (_newDamage > _upperLimit) then {
			_newDamage = _upperLimit;
		};

		_damage = _oldDamage + _newDamage;
	};
	
	// For players ignore damage if they are incapacitated and pass damage to bis revive handler
	if ( isPlayer _unit ) then {
		if ( lifeState _unit == "INCAPACITATED" ) then {
			//if we are incapacitated take no additional damage
			_damage = _oldDamage;
		} else {
			_this set[ 2, _damage ];
			//Call BI REVIVE HandleDamage EH passing new _damage value
			_damage = _this call bis_fnc_reviveEhHandleDamage;
		};
	};

	systemChat format[ "pHealth: %1 selection: %2 oldTotal: %3 newTotal: %4 incomingDmg: %6 appliedDmg: %6", _playerHealth, _hitSelection, _oldDamage, _damage, _incomingDamage, _newDamage];

	_damage
	
}];
systemChat format[ "Damage reduction applied to %1", _unit ];

Place this at the end of your mission initPlayerLocal.sqf and just change the multipliers you would like for the damage and remove the systemChat lines which are there for debugging. You can also remove the if statement with "INCAPACITATED" if you want players to be able to be killed while incapacitated.

 

EDIT: Added in location based multipliers and upper limits of damage per projectile and a check for _projectile not "" to avoid modifying falling damage etc.  You can set limits to 1 if you don't want an upper limit or fractions to ensure a number of shots to kill/incapacitate, keep in mind that players die at 1.0 damage but may be incapacitated at around 0.7 depending on the revive system.

  • Like 2
  • Thanks 2

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

×