Home   Help Search Login Register  

Author Topic: help with basic ai reaction to fire  (Read 2369 times)

0 Members and 1 Guest are viewing this topic.

Offline twisted

  • Members
  • *
  • I'm a llama!
help with basic ai reaction to fire
« on: 04 Feb 2009, 18:23:04 »
hi. I am trying to figure out how to script some simple things for Arma. BUt i find it non-intuitive despite ofpec great resources. Probably because i am new at all this despite trying multiple times to get scripts going. i have read rommels great ia script and did not understand much of it at all as it is very clean and compact and noncommented.

my question.

how to script a very basic reaction to ai fire - as simple as possible to start with. the script will be placed in AI group leaders init box.

steps i think needed are.
is anyone AI in the group under fire?
                        ||
                       /  \
yes then do action.  No then do nothing.


it might be easy for most scripters, but i need to start somewhere so any help explaining the structuring/flow of the sqf would be great.





Offline Wolfrug

  • Addons Depot
  • Former Staff
  • ****
  • Official OFPEC Old Timer
Re: help with basic ai reaction to fire
« Reply #1 on: 04 Feb 2009, 19:04:38 »
Well...do you really need a generic script, or do you just need it for a specific event? E.g., is there a point in your mission in which your AI needs to know if it's come under fire which leads to an action being taken, or this a part of a larger whole (like, say, the AI shouting "get down!" when under fire, continually during the whole mission).

Now, if it's the first case, it's possible to "hack" it pretty easily using triggers and the like. A favourite of mine is the behaviour check - as soon as any AI within a trigger area is no longer in "safe" mode, it means they've either spotted an enemy or come under fire (or heard an explosion etc.).

However, there is otherwise no actual way (that I know of!) to safely decide if a unit is under fire or not. My own DSAI scripts and I believe the Suppression scripts by Second (I think) just hack it by checking for bullets in the air around the unit : if there are some, then it's likely the unit is under fire, otherwise not. However who's to say these bullets aren't friendly bullets, unless you're going to start calculating at which angles the bullets are coming or going etc. etc. Also, it won't be doable to check for this very fast or very reliably, since the commands needed (nearestObject) is quite resource-intensive; and even checking the airspace for bullets once every 0.1 seconds or so will STILL miss some bullets since, well, bullets are damned fast!

In short, there's no simple way of figuring out a foolproof way of detecing whether a unit is under fire or not, to my knowledge. Someone else might have a better idea though. :)

Wolfrug out.
"When 900 years YOU reach, look as good you will not!"

Offline laggy

  • Members
  • *
  • "Behold a pale horse"
Re: help with basic ai reaction to fire
« Reply #2 on: 04 Feb 2009, 19:16:03 »
Hi Twisted,

I'm not a scripting guru, but OK at making stuff work.  :clap:

It depends on what you really want and mean with "under fire".
I have a couple of ideas though.

1. One solution could be to add an Eventhandler "fired", like this in the "fired upon group" leaders init:
{_x addEventHandler ["fired",{underfire = true}]} forEach units group this

Then you have a trigger with:
Condition: underfire
onActivation: whatever you want...

The down part with this solution is that the trigger won't activate until someone in that group is firing back, meaning it will not work if they are just fired upon.

2. Another solution could therefore be a Trigger that checks the groups behaviour.
Condition: behaviour myGroup == "AWARE" OR behaviour myGroup == "COMBAT"
onActivation: whatever you want...

If the group is set on "SAFE" mode it will change to "AWARE" or even "COMBAT" when fired upon.
This would as I see it maybe be the easiest solution and quickest.

There might be better ways, but none that I can think of right now.

Laggy
And I looked and beheld a pale horse and his name that sat on him was Death and Hell followed with him.

Offline Rommel92

  • Members
  • *
Re: help with basic ai reaction to fire
« Reply #3 on: 04 Feb 2009, 20:32:18 »
Check my ROMM_IA script, for readability I have replaced all the letters with appropriate variable names, the basis of this script is to make AI hit the deck when under fire and stay down while under continuous fire; and to make the AI fire back in your general direction.

Code: (ROMM_IA(edited)) [Select]
/*
ROMM_IA.sqf;
Version: 112 [14, 06, 2008];
Author(s): Rommel
Execution: nul = [group this] call compile preProcessFile "ROMM_IA.sqf";
*/

if !(isServer) exitWith {};

_formA =
{
_grp = _this select 0;
_spd = _this select 1;
_beh = _this select 2;
_form = _this select 3;

_leader = leader _grp;

{_x doFollow _leader; _x setUnitPos "AUTO";} forEach units _grp;

_grp setCombatMode _beh;
_grp setSpeedMode _spd;
_grp setFormation _form;

_bool = false;
};

_formB =
{
private ["_grp", "_dir", "_ovrwtch", "_unit"];

_grp = _this select 0;
_dir = _this select 1;

_grp setCombatMode "YELLOW";
_grp setSpeedMode "FULL";
_grp setFormation "LINE";

_ovrwtch = [];

{_unit = _x; {if (_unit hasWeapon _x) then {_ovrwtch = _ovrwtch + [_unit]};} forEach ["M249","M240","PK"];} forEach units _grp;

{[_x, _bool, _dir] spawn _formC} forEach units _grp;

_bool = true;

{[_x, _dir] spawn _formD} forEach _ovrwtch;

sleep 8.0;

{[_x, _dir] spawn _formD} forEach units _grp - _ovrwtch;
};

_formC =
{
private ["_unit", "_bool", "_dir", "_y"];

_unit = _this select 0;
_bool = _this select 1;
if (_bool) exitWith {};

_unit setUnitPos "DOWN";

if (count _this > 1) then
{
_dir = _this select 2;
_unit commandWatch [(getPos _unit select 0)+ sin(_dir) * 43,(getPos _unit select 1)+ cos(_dir) * 43, (getPos _unit select 2) + 1];
};

_bool = _unit findCover [getPos _unit, getPos _unit, 43];
_y = (_unit distance _bool) / 2;

_unit commandMove getPos _bool;

sleep _y;

commandStop _unit;

sleep _y;

_unit commandMove getPos _bool;

if (floor(random 10) > 9) then
{
_unit setUnitPos "AUTO";
};
};

_formD =
{
private ["_unit", "_dir", "_i", "_t", "_form","_v"];

_unit = _this select 0;

if (primaryWeapon _unit in ["M24", "M107", "SVD"]) exitWith {};

_dir = _this select 1;

_t = "Logic" createVehicleLocal [0,0,0];
_form = _unit findNearestEnemy getPos _unit;

if !(vehicle _form in crew _form) exitWith {};

_i = 0;

while {(alive _unit) AND (_i < 14)} do
{
   _unit commandWatch position _form;

sleep (random 7.0);

_v = (((getPos _form select 0) - (getPos _unit select 0)) atan2 ((getPos _form select 1) - (getPos _unit select 1))) +360 % 360;

if (abs _v < 25) then
{
_t action ["useWeapon",_unit,_unit,1];
};
_i = _i + 1;
};
deleteVehicle _t;
};

private ["_grp", "_i", "_bool","_spd", "_beh", "_leader", "_dir", "_t", "_ovrwtch", "_ovrwtchd", "_c"];

_grp = _this select 0;
_i = {alive _x} count units _grp;
_bool = false;


_spd = speedMode _grp;
_beh = combatMode _grp;
_form = formation _grp;

_c = -1;

While {_i > 0} do
{
if (isNull _grp) exitWith {};
If (_i > count units _grp) then
{
{[_x, _bool] spawn _formC} forEach units _grp;
_c = _t + 143;

_i = {alive _x} count units _grp;
};

_leader = leader _grp;
_dir = getDir _leader;
_t = time;

if (!(isNull _leader)) then
{
_ovrwtch = nearestObject [_leader, "BulletBase"];

If (!(isNull _ovrwtch)) exitWith
{
_ovrwtchd = getDir _ovrwtch - 180;

If ((_ovrwtchd < _dir + 109 AND _ovrwtchd > _dir - 109) OR (_ovrwtchd > _dir + 109 AND _ovrwtchd < _dir - 109)) then
{
[_grp, _ovrwtchd] call _formB;
_c = _t + 143;
};
};

_ovrwtch = nearestObject [_leader, "GrenadeHand"];

If (!(isNull _ovrwtch)) exitWith
{
{[_x, _bool] spawn _formC} forEach units _grp;
_bool = true;

_c = _t + 43;
};
_ovrwtch = nearestObject [_leader, "G_40mm_HE"];

If (!(isNull _ovrwtch)) exitWith
{
{[_x, _bool] spawn _formC} forEach units _grp;
_bool = true;

_c = _t + 23;
};
_ovrwtch = nearestObject [_leader, "RocketCore"];

If (!(isNull _ovrwtch)) exitWith
{
{[_x, _bool] spawn _formC} forEach units _grp;
_bool = true;

_c = _t + 33;
};
_ovrwtch = nearestObject [_leader, "ShellCore"];

If (!(isNull _ovrwtch)) exitWith
{
{[_x, _bool] spawn _formC} forEach units _grp;
_bool = true;

_c = _t + 23;
};
_ovrwtch = nearestObject [_leader, "MissileCore"];

If (!(isNull _ovrwtch)) exitWith
{
{[_x, _bool] spawn _formC} forEach units _grp;
_bool = true;

_c = _t + 43;
};
};

If (_c != -1 AND _t > _c) then
{
[_grp, _spd, _beh] call _formA;

_c = -1;
};

sleep 1.0;
};
« Last Edit: 22 Jun 2013, 06:09:04 by Rommel92 »

Offline twisted

  • Members
  • *
  • I'm a llama!
Re: help with basic ai reaction to fire
« Reply #4 on: 04 Feb 2009, 21:28:35 »
thank you very much for all your replies. I have learnt alot for your replies and now see that incoming fire using nearestobject respects the fact that even friendly fire kills!

  Rommel92 thanks for taking the time to comment your script! appreciate it! this will help me loads mate.

EDIT - i have written a script heavily based on Rommel92s script but it doesn't make the AI run upto 100m away when under fire. there are probably loads of mistakes i have made as this is my first try at a script ever. also trying to use the sleep command at the end of script doesn't work.

EIT - when i use hint to get incoming info it tells me incoming is null even if i am shooting right next to AI so maybe the AI isn't noting bulletbase.
Quote
hint format ["\n incoming is %1", _incoming];


Code: [Select]
/* AIreaction.sqf;
Version: 0.001 [5 feb 09]
Author(s): Core from Rommel92's ROMM_IA.sqf script. mucked with by twisted.
Execution: nul = [group this] call compile preProcessFile "AIreaction.sqf";
*/
// AI run to cover if under fire. trying to fix the problem of AI just lying there when under fire.
// thanks to wolfrug, loopis and big thanks to Rommel92 for his script and taking the time to make it clear to a novice like me.


if !(isServer) exitWith {};

_reacttofire =
//looks for cover then runs there

{
private ["_group" , "_incomingdirection" , "_knownenemyinfo", "_groupposition" , "_chosencover", "_distancetocover", "_temp"];

_group = _this select 0;
_incomingdirection = this select 1; //where the incoming fire came from - will this stay true even if ai turns elsewhere?
_knownenemyinfo = this select 2;
_leader = leader _group;
_groupposition = getPos _leader; //center group around leaders position
_chosencover =  _leader findCover [_groupposition, _groupposition, 100, 20]; //find object that provides cover max 100m away and min 20m away from leader to force movement. min 20m forces them to at least get out of current fire range.

_distancetocover = _groupposition - _chosencover;

// split the group into fire support and runners. will happen later and this part called separately

// {_x setUnitPos "UP"; } forEach units _group; //get up and ready to run. not sure if this is good.

//get attitude right
_group setBehaviour "careless"; // under fire means you just dont care just get to cover
_group setCombatMode "YELLOW"; // kill anyone in your way but dont go hunting
_group setSpeedMode "FULL"; //run fast
_group setFormation "LINE"; // run together

//now run
while {_distancetocover > 5} do
{
// run to cover - 5m used to get units near enough
//later on will put in part of some AI randomly dropping to floor to provide cover while other run


{_x commandMove getPos _chosencover; } forEach units _group;
// each unit moves - could this move all units to exact same position? hope not but could add random number to prevent.
_distancetocover = (getpos _leader) - _chosencover;
};



_group setBehaviour "stealth"; //ok now hide
_group setCombatMode "RED"; //get in fire aggresively mode
_group setSpeedMode "NORMAL"; //slow down
//now each ai finds individual cover in 20m radius and moves there
// temp = _hider findCover [getPos _hider, getPos player,50]

{_temp = _x findCover [getPos _x, getPos _x, 20]; _x commandMove getPos _temp;} forEach units _group;

// nice to put in a watch direction command so they face last known direction of enemy

{_x commandWatch _knownenemyinfo;} forEach units _group;

{_x setUnitPos "AUTO";} forEach units _group; //kneel or go prone


{_x setUnitPos "AUTO";} forEach units _group; //kneel or go prone


};


_backtonormal =
// return sqaud to ready state
{
private ["_group", "_leader","_spd","_beh","_form"];

_group = _this select 0;
_leader = leader _group;
_spd = _this select 1;
_beh = _this select 2;
_form = _this select 3;

{_x doFollow _leader; _x setUnitPos "AUTO";} forEach units _group;

_group setSpeedMode _spd;
_group setCombatMode _beh;
_group setFormation _form;

};


//main part of sqf

private ["_group" ,"_totalunits", "_leader", "_spd", "_beh", "_form", "_suppressed", "_incoming", "_incomingdirection", "_knownenemyinfo", "_stillalive"];

_group = _this select 0; //get group ID

_totalunits = {alive _x} count units _group; //count how many untis are alive in the group

_spd = speedMode _group;
_beh = combatMode _group;
_form = formation _group;

//_suppressed = 0; //starts off not suppressed. not implemented yet

While {_totalunits > 0} do
//while there are still units alive in group
{
if (isNull _group) exitWith {}; //if group is invalid/null/destroyed then exit


if (_totalunits > count units _group) then
// check if total units is same as number of units in group as group may have suffer casualties
{
// space left for what to do if man dies. not implemented yet.
// {_x setUnitPos "DOWN";} forEach units _group; //if a mate dies hit the dirt
_totalunits  = {alive _x} count units _group; // update number of totalunits to equal number ai alive in group
};

_leader = leader _group; //get current leader

//part where incoming bullets cause reaction

if (!(isNull _leader)) then  // if leader is true
{
_incoming = nearestObject [_leader, "BulletBase"]; // get location of the nearest bullet to leader. Ta Rommel92.


if (!(isNull _incoming)) exitWith
{
// _suppressed = _suppressed +1; //every detected bullet increases chance of fleeing. not further implemented yet.
_incomingdirection = getDir _incoming -180; //-180' to original direction lets you trace source of bullet

// now identify source of fire realted to sqaud leader
_knownenemyinfo= _leader findNearestEnemy getPos _leader;


[_group,_incomingdirection,_knownenemyinfo] call _reacttofire;

};

};

_stillalive  = {alive _x} count units _group;

// something here to return to normal behaviour
if (_stillalive > 0) then
{
[_group,_spd,_beh,_form] call _backtonormal;
};


//sleep 1.0;
};

« Last Edit: 07 Feb 2009, 02:20:43 by twisted »

Offline twisted

  • Members
  • *
  • I'm a llama!
Re: help with basic ai reaction to fire
« Reply #5 on: 10 Feb 2009, 22:12:49 »
sorry to bump, but when i edited the script the thread did not move up in the forum and i really would like a little help to find the solution and i have exhausted my scripting knowhow (the very little i possess).



Offline Rommel92

  • Members
  • *
Re: help with basic ai reaction to fire
« Reply #6 on: 12 Feb 2009, 12:46:58 »
You're going to hate me for un-commenting it, however I just can't focus when theres text everywhere.  :P
Changelog:
- Removed All Comments ( lol...)
- Fixed all Distance Comparisons
- Fixed all While Loops
- Fixed Certain 'Return to Normal' conditions
- Added I counter, after 75 seconds of no bullets units return to normal behavior.
- Stopped repetitive foreach commandmove, would have killed your speakers if not your CPU.
- Fixed various foreach commands
- Removed syntax errors (that I could see)
- Removed _Knownenemyinfo (unused)
- Removed _incomingdirection (unused)
- Removed repeated unused/unuseful/unproductive pieces of coding that may or may not have originated from my original ROMM_IA.

By the way, I'm running on Linux and have no way of testing this, so I hope it works out for you, good work otherwise, your making good progress, just watch your syntax and loop usage.  :)

Code: [Select]
CHECK NEW POST
For starters, you had lot of while loops with no sleeps, which would completely kill your computer lol.

And for execution use:
Code: [Select]
nul = this spawn compile preprocessfile "yourscript.sqf"
« Last Edit: 13 Feb 2009, 10:46:09 by Rommel92 »

Offline twisted

  • Members
  • *
  • I'm a llama!
Re: help with basic ai reaction to fire
« Reply #7 on: 12 Feb 2009, 15:44:47 »

absolutely appreciated mate. all the unproductive coding was certainly my handiwork :) as i am just getting started in scripting. will give this a go tonight. thanks for taking the time.



large quote prom previous post not necessary - Planck
« Last Edit: 12 Feb 2009, 15:59:12 by Planck »

Offline Rommel92

  • Members
  • *
Re: help with basic ai reaction to fire
« Reply #8 on: 13 Feb 2009, 10:50:13 »
Sorry for you probably testing this and then realising it won't work and coming and seeing this, but hope its better for you.  :confused:

Changelog:

- Changed 'dist' to 'distance' (remembered while helping another post, and that I errored here)
- Fixed a few indentations.
- Changed 'call'(s) to 'spawn'

Code: (yourscript) [Select]
if NOT (isServer) exitWith {};
_reacttofire = {
private ["_group" ,"_chosencover", "_distancetocover", "_temp"];

_group = _this select 0;
_leader = leader _group;
_chosencover =  _leader findCover [getPos _leader, getPos _leader, 100, 20];
_distancetocover = (getPos _leader) distance _chosencover;

_group setBehaviour "CARELESS"; _group setCombatMode "YELLOW"; _group setSpeedMode "FULL"; _group setFormation "LINE";

while {_distancetocover > 5} do {
{_x commandMove (getPos _chosencover) } forEach units _group;
_distancetocover = (getpos _leader) distance _chosencover;
sleep 10;
};
_group setBehaviour "STEALTH"; _group setCombatMode "RED"; _group setSpeedMode "NORMAL";
{_temp = _x findCover [getPos _x, getPos _x, 15]; _x commandMove (getPos _temp)} foreach units _group;
{_x setUnitPos "AUTO"} foreach units _group;
};
_backtonormal = {
private ["_group", "_leader","_spd","_beh","_form"];

_group = _this select 0; _leader = leader _group;
_spd = _this select 1; _beh = _this select 2; _form = _this select 3;

{_x dofollow _leader; _x setUnitPos "AUTO"} foreach units _group;
_group setSpeedMode _spd; _group setCombatMode _beh; _group setFormation _form;
};

private ["_group" ,"_totalunits","_i", "_leader", "_spd", "_beh", "_form", "_incoming"];

_group = _this;
_totalunits = {alive _x} count units _group;

_spd = speedMode _group; _beh = combatMode _group; _form = formation _group;
_i = 0;

While {_totalunits != 0} do
{
_leader = leader _group; _i = _i + 1;
if (alive _leader) then {
if (_totalunits > count units _group) then {
_totalunits  = {alive _x} count units _group
};
_incoming = nearestObject [_leader, "BulletBase"];
if NOT (isNull _incoming) exitwith {
[_group] spawn _reacttofire;
_i = 0;
};
};
if(_i == 100) then {
[_group,_spd,_beh,_form] spawn _backtonormal;
};
sleep 0.667;
};

And for execution use:
Code: [Select]
nul = this spawn compile preprocessfile "yourscript.sqf"

Offline twisted

  • Members
  • *
  • I'm a llama!
Re: help with basic ai reaction to fire
« Reply #9 on: 13 Feb 2009, 16:58:30 »
actually your script worked rather well after i changed dist to distance last night. thanks. What was cool was seeing the AI running for cover rather than just lying out in the open taking fire. which was the point. I'll try out the revisions you made in the code.

curious as to how spawn will change the execution (the wiki says that 'spawn'ing a script means script is run in parallel. So would that mean that multiple AI groups react at the same time to incoming fire?

cheers.

Offline Rommel92

  • Members
  • *
Re: help with basic ai reaction to fire
« Reply #10 on: 13 Feb 2009, 23:56:46 »
Hmmm,

Well actually now thinking about it, it would be better to have a call && a spawn; like so:
A call stops the script, finishes the function it has 'called', then returns to the original script and continues. Where as a spawn runs at the same time, so its like an execution of a different script entirely.

The reason I just changed it from spawn to call, and call to spawn, is that the reacttofire shouldn't be constantly run (especially if theres a lot of fire overhead), because the AI will be constantly running to new cover.

I threw in a call to perhaps limit this occuring, but to be safe that they remain 'in cover' instead of moving around all the time (depends what you want, if you want aggressive ai, then maybe leave as is) put in a safeguard that only allows them to be pinned once, then they stay there until its 'all-clear'.  ;)

Code: [Select]
if (alive _leader) then {
if (_totalunits > count units _group) then {
_totalunits  = {alive _x} count units _group
};
_incoming = nearestObject [_leader, "BulletBase"];
if NOT (isNull _incoming) exitwith {
[_group] call _reacttofire;                                    /// CHANGED TO CALL FROM SPAWN
_i = 0;
};
};
if(_i == 100) then {
[_group,_spd,_beh,_form] spawn _backtonormal;                        //CHANGED FROM CALL TO SPAWN
};

Offline twisted

  • Members
  • *
  • I'm a llama!
Re: help with basic ai reaction to fire
« Reply #11 on: 15 Feb 2009, 00:12:14 »
thanks Rommel92 I'll put that in the script!

Your help has been fabulous and the script is a great test bed for trying to get arma ai to react in different ways to incoming fire. have learnt a heap. Cheers!

one thing i find is that there is always a couple seconds pause between being fired on and moving with the AI. the silly guys are sitting ducks for about 5-10seconds each time, then they start moving.


Offline Rommel92

  • Members
  • *
Re: help with basic ai reaction to fire
« Reply #12 on: 15 Feb 2009, 00:22:40 »
one thing i find is that there is always a couple seconds pause between being fired on and moving with the AI. the silly guys are sitting ducks for about 5-10seconds each time, then they start moving.

This could be because of a 'lack - of' voice-quiet in default ArmA. Units will wait until their commands are fully 'audible' and said by the officer before they complete them, whilst it makes sense, it leaves little room for instant reactions.

You could modify this by changing 'commandMove' to 'doMove';  :good: