Jump to content
bazzaro135

Friendly AI take no damage from players

Recommended Posts

How can I make ai blufor members take no damage from players, now there is also civilians and they still need to be able to take damage.

Share this post


Link to post
Share on other sites

{
   if (!(isPlayer _x)) then 
   {
   _x addEventHandler ["HandleDamage",{ if ((side (_this select 0)) == (side (_this select 3))) then {0}; } ];
   }; 
}
forEach allUnits;

Throw that into init.sqf in the mission root folder.

 

 

What it should do is make all AI units immune to friendly fire.  Players will still take friendly fire, however.  Will not work on units spawned in after the mission begins, but you can addEventHandler the same thing on those spawned units to get the same effect.

 

 

Note:  I didn't test this, I just threw it together off the top of my head.  Might not work and there may be syntax errors

Share this post


Link to post
Share on other sites

{
   if (!(isPlayer _x)) then 
   {
   _x addEventHandler ["HandleDamage",{ if ((side (_this select 0)) == (side (_this select 3))) then {0}; } ];
   }; 
}
forEach allUnits;

Throw that into init.sqf in the mission root folder.

 

 

What it should do is make all AI units immune to friendly fire.  Players will still take friendly fire, however.  Will not work on units spawned in after the mission begins, but you can addEventHandler the same thing on those spawned units to get the same effect.

 

 

Note:  I didn't test this, I just threw it together off the top of my head.  Might not work and there may be syntax errors

 

A unit that was there on mission start up was able to be shot still.

Share this post


Link to post
Share on other sites

A unit that was there on mission start up was able to be shot still.

is the unit captive?

Share this post


Link to post
Share on other sites

is the unit captive?

 

 

Make sure the unit isn't captive, as the above poster has said.  Units on which you have called setCaptive=true; will basically join the civillian side and the script command "side" will return civilian if called on the unit.

 

As a result, the little function I posted before will do its job, but when the event handler is called it will return nothing and the normal damage value will be applied to the unit.

 

Basically, any unit with setCaptive = true; will behave unexpectedly and will only be immune to damage from civilian players.

 

 

 

 

Speaking of which, it is good practice to always return something from a function, so here is a slight rewrite of the above script.  I am not familiar with how HandleDamage works, but this might work a bit better because it returns the normal damage value if the side of the attacker and target are different, else it returns 0.

{
   if (!(isPlayer _x)) then 
   {
      _x addEventHandler ["HandleDamage",
      {
         if ((side (_this select 0)) != (side (_this select 3))) then [{_this select 2},{0}]; 
      }];   
   }; 
}
forEach allUnits;
  • Like 1

Share this post


Link to post
Share on other sites

 

Make sure the unit isn't captive, as the above poster has said.  Units on which you have called setCaptive=true; will basically join the civillian side and the script command "side" will return civilian if called on the unit.

 

As a result, the little function I posted before will do its job, but when the event handler is called it will return nothing and the normal damage value will be applied to the unit.

 

Basically, any unit with setCaptive = true; will behave unexpectedly and will only be immune to damage from civilian players.

 

 

 

 

Speaking of which, it is good practice to always return something from a function, so here is a slight rewrite of the above script.  I am not familiar with how HandleDamage works, but this might work a bit better because it returns the normal damage value if the side of the attacker and target are different, else it returns 0.

{
   if (!(isPlayer _x)) then 
   {
      _x addEventHandler ["HandleDamage",
      {
         if ((side (_this select 0)) != (side (_this select 3))) then [{_this select 2},{0}]; 
      }];   
   }; 
}
forEach allUnits;

 

Or just because we can  :)

{
	_x addEventHandler ["HandleDamage", {
		params ["_unit", "", "_damage", "_source"];
		[_damage, 0] select (side _unit isEqualTo side _source);
	}];
} forEach (allUnits select {!isPlayer _x});

Share this post


Link to post
Share on other sites

 

Or just because we can  :)

{
	_x addEventHandler ["HandleDamage", {
		params ["_unit", "", "_damage", "_source"];
		[_damage, 0] select (side _unit isEqualTo side _source);
	}];
} forEach (allUnits select {!isPlayer _x});

 

I'm new to ArmA scripting.  Would you mind explaining a few things to me?

 

Why are you calling "params" in the EH code?  Just to clean it up so instead of (_this select #) you have readable variables?

 

My biggest question though is the array you are returning with the little function "(allUnits select {!isPlayer _x})"

 

Say you have an array [A,B,C].  Imagine that A and B are not players, but C is a player.  Wouldnt (select {!isPlayer _x}) return 0 for A and B, and therefore value A would be selected or value B would be selected as it is the first (and only) value of the array inside the main array?  But for C, (select {!isPlayer _x}) would return 1, which would select the value in the second slot of the array at value C, which does not exist.  The code, therefore, would perform as intended, but wouldn't this throw an error? 

 

Basically, wouldn't this iterate through all units in the game, but select an array value that is out of bounds if {!isPlayer _x} returns false?  As such, wouldn't this throw an error each time it encounters a player unit in the allUnits array? 

 

 

 

 

And for the OP.  I am working on a function to disable or enable friendly fire on a single unit by passing a unit and a boolean to the function.  You could use a script to call this on all AI units if you wanted.  I'll post it when it is ready and give an example of calling the function on multiple non-player units.

Share this post


Link to post
Share on other sites

I'm new to ArmA scripting.  Would you mind explaining a few things to me?

 

Why are you calling "params" in the EH code?  Just to clean it up so instead of (_this select #) you have readable variables?

 

My biggest question though is the array you are returning with the little function "(allUnits select {!isPlayer _x})"

 

Wouldn't this iterate through all units in the game, but select an array value that is out of bounds if {!isPlayer _x} returns false?  As such, wouldn't this throw an error each time it encounters a player unit in the allUnits array? 

I'll try my best to explain:

 

params: Essentially you can "Parse input arguments into an array of private variables". If no argument is provided then _this is automatically used. In this case, _this is used and automatically creates and privates the variables as well as assigning a value to each.

argument params [element1, element2,...elementN]

//Example from wiki
[1, 2, 3] call {
	private ["_one", "_two", "_three"];
	_one = _this select 0;
	_two = _this select 1;
	_three = _this select 2;
	// .....
};

// Same as above, only using params
[1, 2, 3] call {
	params ["_one", "_two", "_three"];
	// .....
};

select: The syntax I'm using is relatively(?) new and follows:

_newArray = _oldArray select expression

The expression is code that will return true. The new array will only contain elements from the old array that satisfied the expression. For example, in the above case:

allUnits select {!isPlayer _x}

This will return an array of all units that are not players. Another example (from the wiki):

_even = [1,2,3,4,5,6,7,8,9,0] select {_x%2 == 0};
// returns [2, 4, 6, 8, 0]

So overall, the wiki is much better at explaining than I am (thank goodness I don't write handbooks for a living). Highly suggest giving it a read and playing around with the examples.

 

Edit 1: I can't spell.

  • Like 1

Share this post


Link to post
Share on other sites

Thanks for explaining!

 

Anyways, here is a function to disable or enable friendly fire on a specific unit.  It works, I tested it.  Units of the same side are unable to damage a unit that you call the function on.  You can also turn the friendly fire back on.

params [
	["_unit", objNull, [objNull], 1],
	["_tf", false, [true], 1]
];
_ret = false;
if (vehicle _unit == _unit) then {
  if (_tf) then {
    _unit setVariable ["FF_disabled", (
      _unit addEventHandler [
        "HandleDamage",
        {
          if ((side (_this select 0)) != (side (_this select 3))) then [{_this select 2},{0}];
        }
      ])
    ];
    _ret = true;
  }
  else {
    _eh = _unit getVariable "FF_disabled";
    if (!(isNil "_eh")) then {
      _unit removeEventHandler ["HandleDamage", _eh];
      _unit setVariable ["FF_disabled", nil];
    };
  };
};
_ret

So what I did was add the function to my function library in the mission.  Inside of description.ext, I put: 

class cfgFunctions {
    #include "functions\functions.hpp"
};

Then I made a folder in the mission directory and named it "functions".  Then inside that folder I created a text file and named it "functions.hpp"  Inside of "functions.hpp" I put the following code:

class JWL
{
  tag = "JWL";
  class functions
  {
    file = "functions";
    class disableFriendlyFire {};
//-----------------------------------------------------------------------------------
//Here are all my other functions.  
//They are defined by simply putting "class myFunction {};" After the line above.
//I can call them with "returnValue = [parameter1, parameter2, ect] call JWL_fnc_myFunction;
//-----------------------------------------------------------------------------------
  };
};

Ok.  Now the game expects to find the function as a file within a folder named functions that is in the mission folder.  It will look for an sqf file with the name fn_myFunction, or in this case, fn_disableFriendlyFire.  So I made a file named fn_disableFriendlyFire.sqf and I put this code inside it:

params [
	["_unit", objNull, [objNull], 1],
	["_tf", false, [true], 1]
];
_ret = false;
if (vehicle _unit == _unit) then {
  if (_tf) then {
    _unit setVariable ["FF_disabled", (
      _unit addEventHandler [
        "HandleDamage",
        {
          if ((side (_this select 0)) != (side (_this select 3))) then [{_this select 2},{0}];
        }
      ])
    ];
    _ret = true;
  }
  else {
    _eh = _unit getVariable "FF_disabled";
    if (!(isNil "_eh")) then {
      _unit removeEventHandler ["HandleDamage", _eh];
      _unit setVariable ["FF_disabled", nil];
    };
  };
};
_ret

Now, to use the function, I simply put "[unit, true] call JWL_fnc_disableFriendlyFire;" in the script somewhere, where unit is the unit that I want to turn friendly fire off.

 

If I want to turn friendly fire back on for that unit, I do the same thing but with a slight change: "[unit, false] call JWL disableFriendlyFire;" 

 

 

Now I can call this function in the init field of a unit that I place in the editor with "[this, true] call JWL_fnc_disableFriendlyFire;" or I can call it after spawning a unit  using createUnit Array in a script.  If I wanted to do this to all currently existing (at the time I run the script) AI units on the Blufor side, for example, I would use a forEach loop in a script.

 

Like this:

{
   [_x, true] call JWL_fnc_disableFriendlyFire;
} forEach (allUnits select {(!isPlayer _x) && (side _x == west)});

A few things to note:

 

-If you disable friendly fire on a unit, you must call the function from the same machine that disabled friendly fire if you want to enable it again on that unit.

 

-The function will not work on vehicles.  Only infantry units.

Share this post


Link to post
Share on other sites

Thanks for explaining!

 

Anyways, here is a function to disable or enable friendly fire on a specific unit.  It works, I tested it.  Units of the same side are unable to damage a unit that you call the function on.  You can also turn the friendly fire back on.

params [
	["_unit", objNull, [objNull], 1],
	["_tf", false, [true], 1]
];
_ret = false;
if (vehicle _unit == _unit) then {
  if (_tf) then {
    _unit setVariable ["FF_disabled", (
      _unit addEventHandler [
        "HandleDamage",
        {
          if ((side (_this select 0)) != (side (_this select 3))) then [{_this select 2},{0}];
        }
      ])
    ];
    _ret = true;
  }
  else {
    _eh = _unit getVariable "FF_disabled";
    if (!(isNil "_eh")) then {
      _unit removeEventHandler ["HandleDamage", _eh];
      _unit setVariable ["FF_disabled", nil];
    };
  };
};
_ret

So what I did was add the function to my function library in the mission.  Inside of description.ext, I put: 

class cfgFunctions {
    #include "functions\functions.hpp"
};

Then I made a folder in the mission directory and named it "functions".  Then inside that folder I created a text file and named it "functions.hpp"  Inside of "functions.hpp" I put the following code:

class JWL
{
  tag = "JWL";
  class functions
  {
    file = "functions";
    class disableFriendlyFire {};
//-----------------------------------------------------------------------------------
//Here are all my other functions.  
//They are defined by simply putting "class myFunction {};" After the line above.
//I can call them with "returnValue = [parameter1, parameter2, ect] call JWL_fnc_myFunction;
//-----------------------------------------------------------------------------------
  };
};

Ok.  Now the game expects to find the function as a file within a folder named functions that is in the mission folder.  It will look for an sqf file with the name fn_myFunction, or in this case, fn_disableFriendlyFire.  So I made a file named fn_disableFriendlyFire.sqf and I put this code inside it:

params [
	["_unit", objNull, [objNull], 1],
	["_tf", false, [true], 1]
];
_ret = false;
if (vehicle _unit == _unit) then {
  if (_tf) then {
    _unit setVariable ["FF_disabled", (
      _unit addEventHandler [
        "HandleDamage",
        {
          if ((side (_this select 0)) != (side (_this select 3))) then [{_this select 2},{0}];
        }
      ])
    ];
    _ret = true;
  }
  else {
    _eh = _unit getVariable "FF_disabled";
    if (!(isNil "_eh")) then {
      _unit removeEventHandler ["HandleDamage", _eh];
      _unit setVariable ["FF_disabled", nil];
    };
  };
};
_ret

Now, to use the function, I simply put "[unit, true] call JWL_fnc_disableFriendlyFire;" in the script somewhere, where unit is the unit that I want to turn friendly fire off.

 

If I want to turn friendly fire back on for that unit, I do the same thing but with a slight change: "[unit, false] call JWL disableFriendlyFire;" 

 

 

Now I can call this function in the init field of a unit that I place in the editor with "[this, true] call JWL_fnc_disableFriendlyFire;" or I can call it after spawning a unit  using createUnit Array in a script.  If I wanted to do this to all currently existing (at the time I run the script) AI units on the Blufor side, for example, I would use a forEach loop in a script.

 

Like this:

{
   [_x, true] call JWL_fnc_disableFriendlyFire;
} forEach (allUnits select {(!isPlayer _x) && (side _x == west)});

A few things to note:

 

-If you disable friendly fire on a unit, you must call the function from the same machine that disabled friendly fire if you want to enable it again on that unit.

 

-The function will not work on vehicles.  Only infantry units.

my man you need to make a youtube video. my problem is i have two teams in a multiplayer scenario my uncle and i are the team leaders and we have 6 guys each to control. my problem is that when i die i dont respawn as the team leader. it counts helicopter crash as the same thing. now ive done research and found this is due to losing tickets or something like that. i am new to arma and new to scripting as in i dont know SHIIIITTTT about it lol but ive been catching on to some things. i do have the enhanced eden editor mod on which helped with alot of things.... PLEASE HELP ME IN LOTS OF DETAIL heh and explain it like you were explaining it to a 3 year old. i was infantry in real life man so things take me awhile to learn.

Share this post


Link to post
Share on other sites

Please avoid using fullquotes for posts on the same page. It's pretty useless and generates a lot of clutter.

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

×