Jump to content
LSValmont

[Release] BossAi Script! Units with custom Hit Point Pools, amount of lives/revives etc!

Recommended Posts

Hello dear A3 community! 

 

Today I present you my first ever script (released) so please be gentle with me, I am still a virgin! :don13:

 

I've often run into players in my servers who complain about how Arma 3 and/or most of its missions do not offer incapacitated NPCs (a la Farcry 5).

 

Previously, most Arma 3 mission makers had to set important NPCs to be immortal so their mission's functionality could remain intact and/or use Objects such as Boards, stands, computers etc as Vendors/Traders etc. It was that or having extremely fragile NPCs that "evil" players could exploit to ruin other players' experiences. There was no middle ground and I often found these immortal NPCs and/or Objects as traders quite immersion breaking.

 

Another mayor complaint from Arma mission makers was the extremely high difficulty revolving around setting custom Hit Points (HP) for units. Mission makers often found their important characters dying faster than they wanted or perhaps even tankier than what the mission required. This script is the solution to both problems =).

 

It is also a solution that is both system resources friendly and Multiplayer compatible!

 

So with that in mind and since I couldn't find any script that does exactly that or what my players wanted I came up with this:

Spoiler

/* -------------------------------------------------------------------------------
// In the init field of a AI UNIT on the EDEN Editor add:
// null = [this, 40, 2, 60] execVM "scripts\bossAi.sqf";
// Where: 
// "this" is the name of the unit that will have increased HP.
// "40" is the ammount of HP the Unit will have. (40 health means units can take ~4 shots).
// "2" is the amount of lives/revives the Unit will have. (0 lives disables the increased HP so 1 is minimum)
// "60" is the time in seconds the Ai unit will remain in Unconscious state.
// *******************************************************************************
// This script makes a specific Ai unit simulate having a larger/smaller healthpool than default Arma 3. 
// After depleting their healthpool the unit will go into incapacitated state instead of dying after taking fatal damage.
// After all its revives/lives are spent the unit will die normally (and permanently!).
// Additionally the script will:
// Makes it comunicate that it is "Down" via globalchat.
// Broadcasts the player/unit who attacks this special NPC via systemchat.
// Broadcasts the player/unit who kills this special NPC via systemchat. (After all its lives are spent).
// Removes All Actions from the NPC's dead body.(You should've protected your special NPC!)
// *******************************************************************************
// Script by Valmont
   ------------------------------------------------------------------------------- */

if (!isServer) exitWith {};
params [["_unit",objNull,[objNull]],["_hp_unit",40,[40]],["_lives_unit",2,[2]],["_downtime_unit",60,[0]]];

_hp_orig_unit = 1/_hp_unit;
_hp_curr_unit = _hp_orig_unit;
private _myOwner = owner _unit;

_unit setVariable ["unit_orig_hp",_hp_orig_unit,true];
_unit setVariable ["downtime_unit",_downtime_unit,true];
_unit setVariable ["lives_left_unit",_lives_unit,true];
_unit setVariable ["unit_dam_total",_hp_curr_unit,true];
_unit setVariable ["unit_dam_incr",_hp_curr_unit,true];

_unit removeAllEventHandlers "HandleDamage";

_unit addEventhandler ["HandleDamage",{
params ["_unit","_hitSelection","_damage","_source","_projectile"];

_orig_dam = (_unit getVariable "unit_orig_hp");
_lives_left = (_unit getVariable "lives_left_unit");

_curr_dam = (_unit getVariable "unit_dam_total") + (_unit getVariable "unit_dam_incr");
_unit setVariable ["unit_dam_total",_curr_dam,true];

if (_lives_left < 1) exitWith {_unit removeAllEventHandlers "HandleDamage";};

if ((_projectile=="") or ((_unit getVariable "unit_dam_total")<1)) then {0} else {
    _unit setUnconscious true;
    _unit setCaptive true;
    [_unit,"I am down! Send help!"] remoteExec ["globalChat" ,0];
    _unit disableAI "ANIM";
    _lives_left = _lives_left - 1;
    _unit setVariable ["lives_left_unit",_lives_left,true]; // Stores the new lives left.
    _unit setVariable ["unit_dam_total",_orig_dam,true]; // Ai back to full health.
    [_unit] Spawn {
    params ["_unit"];
    _downtime_seconds = (_unit getVariable "downtime_unit");
    sleep _downtime_seconds;
    _unit setDamage 0;
    _unit enableAI "ANIM";
    _unit setUnconscious false;
    sleep 1;
    _unit setUnitPos "UP";
    _unit setCaptive false;
    };
}
}];

_unit addEventHandler ["killed", {
params ["_unit", "_killer"];

0 = [[_unit, _killer],{
        params [["_unit",objNull,[objNull]],["_killer",objNull,[objNull]]];
        removeAllActions _unit;
        systemChat format ["%2 has killed %1",name _unit,name _killer];
    }] remoteExecCall ["bis_fnc_call", [0,-2] select isDedicated,false];
}];

[
    _unit, 
    "Revive NPC", 
    "\a3\ui_f\data\IGUI\Cfg\holdactions\holdAction_reviveMedic_ca.paa",  
    "\a3\ui_f\data\IGUI\Cfg\holdactions\holdAction_reviveMedic_ca.paa",   
    "(_this distance _target < 4) && (lifeState _target == ""INCAPACITATED"")",                                                      
    "_caller distance _target < 4",
    {},
    {hintsilent format ["Healing Progress :%1 / 24",_this select 4] }, 
    { 
    params ["_target", "_caller", "_actionId", "_arguments"];
    sleep 0.1;
    private _orig_dam = (_target getVariable "unit_orig_hp");
    private _myOwner = _arguments select 0;
    _target setDamage 0;
    0 = [_target, {
        params[ ["_object",objNull,[objNull]] ];
        _object enableAI "ANIM";
        _object setUnconscious false;
        _object setUnitPos "UP";
        _object setCaptive false;
    }] remoteExecCall ["bis_fnc_call", _myOwner];
    _target setVariable ["unit_dam_total",_orig_dam,true];
    0 = [_target,"Thanks, I feel fine again!"] remoteExec ["globalChat" ,[0,-2] select isDedicated,false];
    }, 
    {}, 
    [_myOwner], 
    10,
    1000, 
    false,
    true                                                                        
] remoteExec ["BIS_fnc_holdActionAdd",[0,-2] select isDedicated,_unit];

 

 

I tried to make it as MP compatible as my limited knowledge allowed me to! (I've only tested on Hosted Servers). EDIT: Then came davidoss and fixed any locality issues remaining so not it should be fully MP compatible.

 

Usage: Inside a Unit's Init field in the EDEN editor add:

null = [this, 40, 2, 60] execVM "scripts\bossAi.sqf";

Where: 

"this" is the name of the unit that will have increased HP.
"40" is the ammount of HP the Unit will have. (40 health means units can take ~4 shots).
"2" is the amount of lives/revives the Unit will have. (0 lives disables the increased HP so 1 is minimum), Set it to 999 for immortal NPCs who for immersion's sake still go into incapacitated state!

"60" is the time in seconds the Ai unit will remain in Unconscious state.

 

Ver. 1.2 UPDATE 03/12/18: Completely rewritten the script from scratch!

Spoiler

 

- Added the much requested custom/increased Hit Points (HP) for Units feature: Finally you can easily set custom HP values for Units in Arma 3! 

- Heavily optimized the script by removing the while loop!

With this last update you can have for example boss battles where a unit with 200 health has to be taken down a few times before it is truly dead! Any Unit can become a predator, a super human and/or an important NPC who is harder (or easier) to kill.

 

 

Ver. 1.0 UPDATE 30/11/18: The davidoss update!

Spoiler

 

- Added improved Params to avoid potential errors (Thanks Davidoss!)

- Added HoldAction to revive incapacitated NPCs faster!

- Incapacitated NPCs are now also captives (So other Ais won't shoot them while down).

 

 

As always any optimization/improvement/request input is greatly appreciated!

 

PS: This my first ever script is dedicated to my first ever friends and idols here on the forums: Haleks, George Floros and Vandeanson!

This wouldn't have been possible without the knowledge I kindly received from the scripting/programming gurus Larrow, davidoss, pierremgi, phronk, johnnyboy and many others! So thank you very much guys!

  • Like 4
  • Thanks 1

Share this post


Link to post
Share on other sites

Hi there!

This could be written better but whatever if that works.

God for you!!

  • Like 1
  • Haha 1

Share this post


Link to post
Share on other sites
34 minutes ago, davidoss said:

Hi there!

This could be written better but whatever if that works.

God for you!!

 

Don't be greedy and teach me!

 

I've added this to 10 NPCs that act as traders on my mission and haven't seen any drops in FPSs but adding to more units should hurt performance I guess, because of all the EH + While loop! At least the loop ends when all the lives are spent =)

 

I am planning on adding a holdaction to the _unit when it is incapacitated so that players can make them stand up faster and without consuming a life!

Share this post


Link to post
Share on other sites

First lesson: :-D

instead:

 private ["_unit","_numlives"];
_unit = _this select 0;
_numlives = _this select 1; 

you can use:

private _paramsCheck = params [["_unit",objNull,[objNull]],["_numlives",0,[0]]];
if (!_paramsCheck) exitWith {diag_log format ["exiting script - wrong params given %1",str _this]};

This makes sure you will never see most common arma low scripting logic error ""Undefined variable",

and defining your params into variables and this all at  once

  • Like 1
  • Thanks 1

Share this post


Link to post
Share on other sites

I think this is a great idea. But testing your script I noticed it was not possible finish off the incapacitated enemies

Share this post


Link to post
Share on other sites

They need to run out its _numlives first, after author add this to while loop condition.

  • Thanks 1

Share this post


Link to post
Share on other sites
6 hours ago, davidoss said:

you can use:


private _paramsCheck = params [["_unit",objNull,[objNull]],["_numlives",0,[0]]];
if (!_paramsCheck) exitWith {diag_log format ["exiting script - wrong params given %1",str _this]};

This makes sure you will never see most common arma low scripting logic error ""Undefined variable",

and defining your params into variables and this all at  once

 

Nice one! I've added this to the script and also:

 

- Made the incapacitated Ai also setcaptive true so that it is not attacked during their incapacitated state (they do not take damage anyway).

- Added a HoldAction to revive the incapacitated Ai faster.

Share this post


Link to post
Share on other sites
3 hours ago, gc8 said:

I think this is a great idea. But testing your script I noticed it was not possible finish off the incapacitated enemies

 

Yeah, the whole Idea is that those NPCs are special and should not die so easily! You can set their lives to 1 with null = [this, 1] execVM "scripts\specialAi.sqf";

 

That way they will only go incapacitated once and you will be able to kill them while they are down but since I've added the HoldAction to revive them you can revive the Ai again even if it has no lives left! If you don't revive it on time or shoot it again then it is dead for good!

Share this post


Link to post
Share on other sites
6 hours ago, davidoss said:

First lesson: :-D

 

Thank you davidoss! Keep em coming if you can! I've seen lots of interest in this script and it has improved a lot since I first envisioned it.

Share this post


Link to post
Share on other sites

Lesson two: :-D

You can easily take away hit eventhandler and move its code into handledammage eventhandler

 

instead:

 _unit addEventHandler ["HandleDamage",{
_dam = _this select 2; 
if (_dam > 0.9) then {_dam = 0.8; }; 
_dam
}];

_unit addEventHandler ["Hit",{ 
systemChat format ["%2 has attacked %1", name (_this select 0), name (_this select 1)] spawn BIS_fnc_MP;
}]; 

Try:

 

_unit addEventHandler ["HandleDamage",{
	params ["_unit", "", "_damage", "_source"];
	if (!isNull _source && {isPlayer _source}) then {
		0 = [format ["%2 has attacked %1", name _unit, name _source]] remoteExec ["systemChat",[0,-2] select isDedicated,false];
	};
	if (_damage > 0.9) then {_damage = 0.8}; 
	_damage
}];

HINT 1:

Never use functions if there is engine command available which will do the same but quicker.

HINT 2:

You do not need to bother dedicated server with action/chat/radio/&&   and increasing network traffic because there are no human behind.

Quote

[0,-2] select isDedicated

Works like:

false = 0

true = 1

hosted server =  false = select index 0 ---> 0 means everywhere

dedicated server =  true = select index 1 ---> -2  means everywhere besides server

 

Next will be unlimited ammo, but first lets wait if you have more questions about this one.

  • Like 1
  • Thanks 1

Share this post


Link to post
Share on other sites
20 hours ago, davidoss said:

HINT 1:

Never use functions if there is engine command available which will do the same but quicker.

 

Ok got it! Updated the script!

 

Loving the unified code inside the "HandleDamage" addEventHandler.

 

Now that we are optimizing the "HandleDamage" addEventHandler may I ask if you can direct me towards a reliable way to reducing the damage these special Ai takes?

 

I've tried lots of "solutions" I found here on the forums involving the "HandleDamage" addEventHandler but none seem to do the trick.

 

Currently the NPCs go into incapacitated state after 2 shots (Rifles, pistols, anything) regardless of what I add to the  "HandleDamage" addEventHandler. I want them to take 4 or 5 shots before reaching that 0.8 damage. Also grenades (explosions) should still do full damage.

Share this post


Link to post
Share on other sites

Update released!

 

Completely rewritten the script from scratch!

 

- Added the much requested custom/increased Hit Points (HP) for Units feature: Finally you can easily set custom HP values for Units in Arma 3! 

- Heavily optimized the script by removing the while loop!

With this last update you can have for example boss battles where a unit with 200 health has to be taken down a few times before it is truly dead! Any Unit can become a predator, a super human and/or an important NPC who needs to be kept alive.

 

Known issues

- Every time a unit is shot it will communicate it via systemChat too many times (A single shot is broadcast several times for some reason). I have commented this line until I find a solution. 

  • Like 1

Share this post


Link to post
Share on other sites
On 30/11/2018 at 5:50 AM, LSValmont said:

PS: This my first ever script is dedicated to my first ever friends and idols here on the forums: Haleks, George Floros and Vandeanson!

This wouldn't have been possible without the knowledge I kindly received from the scripting/programming gurus Larrow, davidoss, pierremgi, phronk, johnnyboy and many others! So thank you very much guys!

 

Congratulations for this LSValmont !  :thumb::z:

Keep up the good work !

  • Thanks 1

Share this post


Link to post
Share on other sites
Just now, GEORGE FLOROS GR said:

 

Congratulations for this LSValmont !  :thumb::z:

Keep up the good work !

 

I am just following your footsteps bro!

 

Thanks! I will!

  • Thanks 1

Share this post


Link to post
Share on other sites

Updated!

 

The script now includes various locality fixes by davidoss!

  • Like 1

Share this post


Link to post
Share on other sites

This looks awesome, should be perfect for a mission I've been wanting to make for a while where I needed some "super soldiers" 

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

×