Jump to content
Sign in to follow this  
Nephris1

AI reacting on flare

Recommended Posts

Hi friends,

today i played around with some behaviourd of AI at night.

1. AI reacts on enemy at night (0:00h) at a distance of max 30m

2. AI dont notice enemies at 40m, even if i triggered a flare.

I changed the skill from 1% to 100%, what made no differences.

The enemy (me) was just walking on the radius to test at.

As soon as i do a shot (even from 200m) the AI react directly, with precise shots.

So i know AI doesnt react on any "viewabout" but "knowsabout" command.

Nevertheless i hoped the knowsabout value would increase at night if a flare lighten a territory with an enemy is walking by.

Do u have any ideas how to make AI to react on enemies if they are lighten up with a flare?

Edited by Nephris1

Share this post


Link to post
Share on other sites

Yeah, wouldn't we all :)

Either ES onFlare or EH fired.

Here is what I used as fired eventhandler:

private ["_ammo","_types","_dummy","_color","_r","_g","_b","_delay","_pos","_radius","_i","_groupsenemy","_groupsfriendly","_unitsEnemy","_unitsFriendly"];
_shooter = _this select 0;
_ammo = _this select 4;
_groupsenemy = [];
_groupsfriendly = [];
_unitsenemy = [];
_unitsfriendly = [];
_types = ["F_40mm_White","F_40mm_Yellow","F_40mm_Green","F_40mm_Red"];
if !(_ammo in _types) exitWith {};
_delay = time + 1;
waitUntil {!isNull nearestObject [player, _ammo] || time > _delay}; //BIS, PLEASE give us object reference from "fired" eventhandler.
if (time > _delay) exitWith {}; //Failsafing. Exiting prevents error messages.
_dummy = nearestObject [_shooter, _ammo];
_color = getArray (configFile >> "CfgAmmo" >> typeOf _dummy >> "lightColor");
_r = _color select 0;
_g = _color select 1;
_b = _color select 2;
sleep 1.4; //Not sure how to look up the correct value, or even find it, but this is close enough for current ignition delay.

//Make an array of units in the vicinity of the flare
_pos = [getPos _dummy select 0, getPos _dummy select 1, 0];
_radius = 133 * (_r + _g + _b); //Gives 200m for a white flare since base vanilla value is 0.5
for "_i" from 0 to (count allGroups) - 1 do {
if(side (allGroups select _i) != playerside) then {
	if (leader (allGroups select _i) distance _pos < _radius) then {
		_groupsenemy set [count _groupsenemy, allGroups select _i];
		sleep 0.012;
	};
} else {
	if (leader (allGroups select _i) distance _pos < _radius) then {
		_groupsfriendly set [count _groupsfriendly, allGroups select _i];
		sleep 0.012;
	};
};
};
for "_i" from 0 to (count _groupsenemy) do {
{_unitsEnemy set [count _unitsenemy, _x]} forEach units leader (_groupsenemy select _i);
sleep 0.012;
};
for "_i" from 0 to (count _groupsfriendly) do {
{_unitsFriendly set [count _unitsfriendly, _x]} forEach units leader (_groupsfriendly select _i);
sleep 0.012;
};
sleep 5; //Artificial delay to make units "study the surroundings" a little more. Already way too powerful.
for "_i" from 0 to (count _groupsfriendly) - 1 do {
{(leader (_groupsfriendly select _i)) reveal _x} forEach _unitsEnemy;
sleep 0.012;
};
for "_i" from 0 to (count _groupsenemy) - 1 do {
{(leader (_groupsenemy select _i)) reveal _x} forEach _unitsFriendly;
sleep 0.012;
};
_groupsenemy = nil;
_groupsfriendly = nil;
_unitsenemy = nil;
_unitsfriendly = nil;

Note the number of for next and forEach loops - not good, even if the for next loops have some builtin delays. My _radius value is set quite small, since I at the time couldn't figure out a way to cause a correct behaviour (not hard btw), but more importantly, couldn't find a way to check for validity of reveal. I.e. you might base

{_unitsEnemy set [count _unitsenemy, _x]} forEach units leader (_groupsenemy select _i);

on the stance and speed of _x. The correct reaction procedure is to lay down and stay still, and anyone doing that would have a greater chance of not get added to the array. Also there is the lacking canSee command which would have been helpful here - if _x is hidden from view by building etc, then he is not added the array.

So this is way from perfect (or even usable in terms of realism), but at least it manages to get the action going instead of being stupidly blind.

Edited by CarlGustaffa

Share this post


Link to post
Share on other sites

Hi Carl,

thx for your effort posting your script.

I tried to get it working.

My EH executes but i cant notice a difference on AI behaviour.

Perhabs i am missing something.

I created a testmission ,if u r interested to have a look, i would appreciate that.

As this feature is imho a very interesting one, the more for earlier battle campaigns before NVGoggles.

Nevertheless it is a bit annoying that AI reacts on fire at night as well as on daylight.

Share this post


Link to post
Share on other sites
Would this work for the streetlamps too?

for one streetlamp

trigger then activation

([0,0,0] nearestObject IDname) switchLight "OFF"

for lots of streetlamp

{_x switchLight "OFF"} forEach ((getPos centre) nearObjects ["StreetLamp",200]);

200 is the radius

Share this post


Link to post
Share on other sites

I mean if you stand in the light of the streetlamp at night the AI doesn't recognize you even if they watch at you.

Share this post


Link to post
Share on other sites

Not at this state of the script.

As no unit will be added to the array....and the script wont be executed by a streetlamp if u use a EH.

So the answer is no, relating to that script as it is.

Share this post


Link to post
Share on other sites

I had a look at the mission.

Put a ; at the end of your added hint in the start.

And attach it as sqf (execVM) instead of sqs (exec).

And, always use -showScriptErrors in your Arma shortcut. :)

Doing that, it worked for me. Takes a while for the loops to finish, then everyone opens fire on everyone :D

I'll throw together a quick mission where AI are also given flares, and will use them on suspicion, and where this "madness reveal" takes place :)

Edited by CarlGustaffa

Share this post


Link to post
Share on other sites

Did i mention it works like it does ?!

Cheerz m8!

---------- Post added at 09:11 PM ---------- Previous post was at 08:10 PM ----------

I would like to refer to one of your scripts, that make an AI shoot flare into the sky by knowsabout, as i do not want to make AI shoot flares by executing triggers e.g.

Well this is your script (i changed it to vanilla class)

hint "jo";
private ["_unit","_check","_leader","_flarechance","_mags","_one_flare","_one_flare_muzzle"];
_unit = _this select 0;
_check = false;
_flarechance = 0.6;
_enemylist = [];
while {alive _unit} do{
   if (flarefired) then {sleep 10.123 + (random 10)};
   _leader = leader _unit;
   {
       if(_leader knowsAbout _x >= 0.7) then
       {
           _check = true;
           sleep 1.123;
       };
   } forEach list tEastAriAllEnemies;

   if (_check && !flarefired && (random 1 < _flarechance) && !(call fn_isDay)) then {
       _one_flare = "";
       _mags = magazines _unit;
       {
           scopeName "xxxx1";
           if (_x in d_flarelist) then {
               _one_flare = _x;
               breakOut "xxxx1";
           };
       } forEach _mags;
       sleep 3.345;
       if (!flarefired && alive _unit) then {
           if (_one_flare != "") then {
               flarefired = true;
               sleep 1.234;
               _one_flare_muzzle = "GP25Muzzle";
               _unit selectWeapon _one_flare_muzzle;
               _unit doWatch [getPos _unit select 0, getPos _unit select 1, 200];
               sleep 1.234;
               _unit fire [_one_flare_muzzle, _one_flare_muzzle, _one_flare];
               sleep 31.234;
               if (random 1 < 0.7) then {_unit addMagazine (d_flarelist select (floor random count d_flarelist));};
           };
       }
       else {
           flarefired = false;
       };
       sleep 30;
   };
   sleep 1 + (random 1);
   flarefired = false;
};

I created a trigger 5000x5000 called it tEastAriAllEnemies, triggered by bluefor.In activation: nil=[] execVM "enemydetect.sqf"

I hoped to make one of the grenadiers shooting flares as soon as they know enough about any bluefor unit, but nothing happened,

So i expect sth wrong here.

Can u give me hand once again plz?

Share this post


Link to post
Share on other sites
nil=[] execVM "enemydetect.sqf"

Ouch! Never use nil, call it xxx, dummy, nothing, handle, but never nil :) This is a fairly old script of mine, so if I do it myself somewhere, I didn't know at the time.

Is d_flarelist defined and flarefired set, i.e. in init.sqf?

Do you have the function fn_isDay defined?

And of course the units needs to have the script started and been given some flares.

Here is some updated scripts, including an updated isDay function, should work better with any island at different latitudes:

init.sqf:

flarefirede = false;
flarefiredw = false;
d_flareliste = ["FlareWhite_GP25", "FlareWhite_GP25", "FlareWhite_GP25", "FlareWhite_GP25", "FlareWhite_GP25", "FlareWhite_GP25", "FlareRed_GP25", "FlareGreen_GP25", "FlareYellow_GP25"];
d_flarelistw = ["FlareWhite_M203", "FlareWhite_M203", "FlareWhite_M203", "FlareWhite_M203", "FlareWhite_M203", "FlareWhite_M203", "FlareRed_M203", "FlareGreen_M203", "FlareYellow_M203"];

X_fnc_isDay = {
private ["_world", "_lat", "_day", "_hour", "_angle", "_isday"];
_world = gettext(configFile >> "CfgWorlds" >> worldName >> "description"); //In order to look up correct latitude.
_lat = -1 * getNumber(configFile >> "CfgWorlds" >> _world >> "latitude"); //Arma latitude is negated for some odd reason.
_day = 360 * (dateToNumber date);
_hour = (daytime / 24) * 360;
_angle = ((12 * cos(_day) - 78) * cos(_lat) * cos(_hour)) - (24 * sin(_lat) * cos(_day));
_isday = (if (_angle > 0) then {true} else {false});
_isday
};

[] execVM "scripts\Equip.sqf";

Note that I by accident recently found BIS' own code for sun and moon angles calculations hidden somewhere in the Biki (not that I'm able to find it again right now, lol), so I might have a new go on this function. BIS: Scene brightness would have been better though :) This function of mine doesn't match BIS' by 100%, but it does the trick pretty good.

Equip.sqf (This is for a mission that does oldschool coldwar stuff, so you might exclude certain parts for your mission):

private ["_i","_j","_groupseast","_groupswest","_muzzles"];
_groupseast = [];
_groupswest = [];
for "_i" from 0 to (count allGroups) - 1 do {
if(side (allGroups select _i) == east) then {
	_groupseast set [count _groupseast, allGroups select _i];
//		sleep 0.0012;
} else {
	_groupswest set [count _groupswest, allGroups select _i];
//		sleep 0.0012;
};
};

for "_i" from 0 to (count _groupseast) -1 do {
_leader = leader (_groupseast select _i);
for "_j" from 0 to count (units _leader) -1 do {
	_done = false;
	_unit = units _leader select _j;
	removeAllWeapons _unit;
	removeAllItems _unit;
//Anyone with grenade launchers.
	if (typeOf _unit in ["MVD_Soldier_GL","MVD_Soldier_TL","RU_Soldier_GL","RU_Soldier_TL","Ins_Soldier_GL"]) then {
		if (_unit != player) then {[_unit] execVM "scripts\EnemyFlares.sqf"};
		_unit addEventHandler ["fired", {_this execVM "scripts\EH-flares.sqf"}];
		if (typeOf _unit in ["MVD_Soldier_GL","RU_Soldier_GL","Ins_Soldier_GL"]) then {
			{_unit addMagazine "30Rnd_545x39_AK"} forEach [1,2,3,4,5,6];
			{_unit addMagazine "1Rnd_HE_GP25"} forEach [1,2,3,4];
			{_unit addMagazine (d_flareliste select (floor random (count d_flareliste)))} forEach [1,2,3,4];
			_unit addWeapon "AK_74_GL";
		};
	_done = true;
	};
//Anyone with machineguns.
	if (!_done && typeOf _unit in ["MVD_Soldier_MG","RU_Soldier_AR","RU_Soldier_MG"]) then {
		{_unit addMagazine "100Rnd_762x54_PK"} forEach [1,2,3,4];
		_unit addWeapon "PK";
		_done = true;
	};
//Scopes are not part of this scenario, so not included.
//The rest
	if (!_done) then {
		{_unit addMagazine "30Rnd_545x39_AK"} forEach [1,2,3,4,5,6,7,8];
		{_unit addMagazine "1Rnd_HE_GP25"} forEach [1,2,3,4];
		_unit addWeapon "AK_74";
	};
	if (_j == 0) then {
		_unit addWeapon "Binocular";
		_unit addWeapon "ItemRadio";
		_unit addWeapon "ItemMap";
	};
	_unit addWeapon "ItemWatch";
	_unit addWeapon "ItemCompass";
	_unit selectWeapon (primaryWeapon _unit);
	_muzzles = getArray(configFile>>"cfgWeapons" >> (primaryWeapon _unit) >> "muzzles");
	_unit selectWeapon (_muzzles select 0);
};
};
for "_i" from 0 to (count _groupswest) -1 do {
_leader = leader (_groupswest select _i);
for "_j" from 0 to count (units _leader) -1 do {
	_done = false;
	_unit = units _leader select _j;
	removeAllWeapons _unit;
	removeAllItems _unit;
//Anyone with grenade launchers.
	if (typeOf _unit in ["USMC_Soldier_TL","USMC_Soldier_GL","FR_Assault_GL","FR_AC","FR_Cooper","FR_GL","FR_TL","FR_Miles"]) then {
		if (_unit != player) then {[_unit] execVM "scripts\EnemyFlares.sqf"};
		_unit addEventHandler ["fired", {_this execVM "scripts\EH-flares.sqf"}];
//hint format ["%1", typeOf _unit];
		{_unit addMagazine "1Rnd_HE_M203"} forEach [1,2,3,4];
		{_unit addMagazine "30Rnd_556x45_Stanag"} forEach [1,2,3,4,5,6];
		{_unit addMagazine (d_flarelistw select (floor random (count d_flarelistw)))} forEach [1,2,3,4];
		_unit addWeapon "M16A2GL";
		_done = true;
	};
//Anyone with machineguns.
	if (!_done && typeOf _unit in ["FR_AR","FR_Rodriguez","USMC_Soldier_AR","USMC_Soldier_MG"]) then {
		{_unit addMagazine "100Rnd_762x51_M240"} forEach [1,2,3,4];
		_unit addWeapon "M240";
		_done = true;
	};
//Scopes are not part of this scenario, so not included.
//The rest
	if (!_done) then {
		{_unit addMagazine "30Rnd_556x45_Stanag"} forEach [1,2,3,4,5,6,7,8];
		{_unit addMagazine "1Rnd_HE_GP25"} forEach [1,2,3,4];
		_unit addWeapon "M16A2";
	};
	if (_j == 0) then {
		_unit addWeapon "Binocular";
		_unit addWeapon "ItemRadio";
		_unit addWeapon "ItemMap";
	};
	_unit addWeapon "ItemWatch";
	_unit addWeapon "ItemCompass";
	_unit selectWeapon (primaryWeapon _unit);
	_muzzles = getArray(configFile>>"cfgWeapons" >> (primaryWeapon _unit) >> "muzzles");
	_unit selectWeapon (_muzzles select 0);
};
};
if !(player hasWeapon "ItemMap") then {player addWeapon "ItemMap"};
_groupsenemy = nil;
_groupsfriendly = nil;

EnemyFlares.sqf (note that there is a problem, they will continue firing flares forever, I'm still only working on this occasionally, Domino is my primary assignment taking most of my time. Also both sides will now use flares, since this is supposed to be oldschool and nobody have NVGs):

private ["_unit","_check","_leader","_flarechance","_mags","_one_flare","_one_flare_muzzle","_groupsenemy","_unitsenemy","_d_flarelist","_muzzle"];
_unit = _this select 0;
_check = false;
_flarechance = 0.6;
_groupsenemy = [];
_unitsenemy = [];

if (side _unit == east) then {
_d_flarelist = d_flareliste;
_muzzle = "GP25Muzzle";
for "_i" from 0 to (count allGroups) - 1 do {
	if(side (allGroups select _i) == west) then {
		_groupsenemy set [count _groupsenemy, allGroups select _i];
	};
//		sleep 0.0012;
};
} else {
_d_flarelist = d_flarelistw;
_muzzle = "M203Muzzle";
for "_i" from 0 to (count allGroups) - 1 do {
	if(side (allGroups select _i) == east) then {
		_groupsenemy set [count _groupsenemy, allGroups select _i];
	};
//		sleep 0.0012;
};
};

for "_i" from 0 to (count _groupsenemy) do {
{_unitsenemy set [count _unitsenemy, _x]} forEach units leader (_groupsenemy select _i);
sleep 0.0012;
};

while {alive _unit} do{
if (flarefired) then {sleep 10.123 + (random 10)};
_leader = leader _unit;
{
	scopeName "xxxx1";
	if((_leader knowsAbout _x >= 0.7) && (_unit distance _x < 400)) then
	{
		_check = true;
		breakout "xxxx1";
		sleep 1.123;
	};
} forEach _unitsenemy;

if (_check && !flarefired && (random 1 < _flarechance) && !(call X_fnc_isDay)) then {
	_one_flare = "";
	_mags = magazines _unit;
	{
		scopeName "xxxx2";
		if (_x in _d_flarelist) then {
			_one_flare = _x;
			breakOut "xxxx2";
		};
	} forEach _mags;
	sleep 3.345;
	if (!flarefired && alive _unit) then {
		if (_one_flare != "") then {
			flarefired = true;
			sleep 1.234;
			_one_flare_muzzle = _muzzle;
			_unit selectWeapon _one_flare_muzzle;
			_unit doWatch [getPos _unit select 0, getPos _unit select 1, 200];
			sleep 1.234;
			_unit fire [_one_flare_muzzle, _one_flare_muzzle, _one_flare];
			sleep 1.234;
			_unit doWatch objNull;
			sleep 31.234;
//				if (random 1 < 0.7) then {_unit addMagazine (_d_flarelist select (floor random count _d_flarelist));};
		};
	}
	else {
		flarefired = false;
	};
	sleep 30;
};
sleep 10 + (random 10);
flarefired = false;
};


End finally, EH-flares.sqf, which unfortunately gives me the occasional error for reasons I haven't figured out just yet:

private ["_ammo","_types","_dummy","_color","_r","_g","_b","_delay","_pos","_radius","_i","_groupsenemy","_groupsfriendly","_unitsEnemy","_unitsFriendly"];
_shooter = _this select 0;
_ammo = _this select 4;
_groupsenemy = [];
_groupsfriendly = [];
_unitsenemy = [];
_unitsfriendly = [];
_types = ["F_40mm_White","F_40mm_Yellow","F_40mm_Green","F_40mm_Red"];
if !(_ammo in _types) exitWith {};
if (random 1 < 0.333) then {
if (side _shooter == west) then {_shooter addMagazine "FlareWhite_M203"} else {_shooter addMagazine "FlareWhite_GP25"};
};
_delay = time + 1;
waitUntil {!isNull nearestObject [player, _ammo] || time > _delay}; //BIS, PLEASE give us object reference from "fired" eventhandler.
if (time > _delay) exitWith {}; //Failsafing. Exiting prevents error messages.
_dummy = nearestObject [_shooter, _ammo];
_color = getArray (configFile >> "CfgAmmo" >> typeOf _dummy >> "lightColor");
_r = _color select 0;
_g = _color select 1;
_b = _color select 2;
sleep 1.4; //Not sure how to look up the correct value, or even find it, but this is close enough for current ignition delay.

//Make an array of units in the vicinity of the flare
while {alive _dummy} do {
_pos = getPos _dummy;
_radius = 200 * (_r + _g + _b); //Gives 300m for a white flare since base vanilla value is 0.5
for "_i" from 0 to (count allGroups) - 1 do {
	if(side (allGroups select _i) != playerside) then {
		if (leader (allGroups select _i) distance _pos < _radius) then {
			_groupsenemy set [count _groupsenemy, allGroups select _i];
			sleep 0.0012;
		};
	} else {
		if (leader (allGroups select _i) distance _pos < _radius) then {
			_groupsfriendly set [count _groupsfriendly, allGroups select _i];
			sleep 0.0012;
		};
	};
};
for "_i" from 0 to (count _groupsenemy) do {
	{_unitsEnemy set [count _unitsenemy, _x]} forEach units leader (_groupsenemy select _i);
	sleep 0.0012;
};
for "_i" from 0 to (count _groupsfriendly) do {
	{_unitsFriendly set [count _unitsfriendly, _x]} forEach units leader (_groupsfriendly select _i);
	sleep 0.0012;
};
sleep 5; //Artificial delay to make units "study the surroundings" a little more. Already way too powerful.
for "_i" from 0 to (count _groupsfriendly) - 1 do {
	{(leader (_groupsfriendly select _i)) reveal _x} forEach _unitsEnemy;
	sleep 0.0012;
};
for "_i" from 0 to (count _groupsenemy) - 1 do {
	{(leader (_groupsenemy select _i)) reveal _x} forEach _unitsFriendly;
	sleep 0.0012;
};
hint format ["_pos: %1\n_unitsfriendly: %2\n_unitsenemy: %3", _pos, count _unitsfriendly, count _unitsenemy];
_groupsenemy = nil;
_groupsfriendly = nil;
_unitsenemy = nil;
_unitsfriendly = nil;
//	sleep 4.567;
};

Naturally, reveal like this is waaaayy to powerful. Might be a better approach to increase the units setSkill [] "spotDistance", "spotTime" (and "general"?) while the flare is alive, but I haven't gotten this far yet.

Share this post


Link to post
Share on other sites
Ouch! Never use nil, call it xxx, dummy, nothing, handle, but never nil :)

You can ever use 0 (zero). Sounds bad, but 0=something works in arma.

Share this post


Link to post
Share on other sites

Couldnt bother with ArmA2 these days, as we played and lost Championsleague today, nevertheless i ll try to get it work tomorrow!

Share this post


Link to post
Share on other sites

I havn't tried this at night butyou can try the {_x reveal (unit x should be revealed to)} foreach units groupx.

If that doesn't work you can use the target command and loop a script with the action useweapon command.

Mabey you can use this in combination withthe ishidden command to check if friendly units are hidden before revealing their position to enemies.

Edited by Rejenorst

Share this post


Link to post
Share on other sites

Are any of the hide commands still valid in Arma2? I thought they were all obsolete now, but I haven't checked.

getHideFrom: No particular note.

setHideBehind: Command is not functional in Arma2.

Share this post


Link to post
Share on other sites

Hi Carl,

tested your scripts and working as it does, cheerz.

Share this post


Link to post
Share on other sites

Yeah, it will "appear" to work. But when you start using it in an actual mission, you will begin calling me stupid - at least I do :D

Share this post


Link to post
Share on other sites

Well atm i didnt reach the point i was supposed to do so ....

Nevertheless, i got another prob atm.#

As this scripts are worth using by night only, some units should shoot by random a flare, otherwise the "flare-drama" wont get running.

I treid to implement a triggered flare, but of course this didnt work, due to the EH.

If i make a unit shoting flares like each 600 sec ,just for controll view or whatever , how should i implement this one in your composition?

Edith sais:

I played, or better gambled around and i think i got a way that satisfie me.

Means i got one initially flare shooting unit, that makes the stone rolling.

I thought i must have to give that initially shooting unit the EH fired

_unit addEventHandler ["fired", {_this execVM "EH-flares.sqf"}];

But it seems to work without.....???

Edited by Nephris1

Share this post


Link to post
Share on other sites

For more and easier "flare drama", just lower the knowsAbout check to say 0.05. That will make them fire flares on just about any unknown contact.

For the 600 thingy, you could just separate the part of the script that does the actual firing into a separate script of function, and just call that separately without any "do I need to fire a flare check" going.

Share this post


Link to post
Share on other sites

How to set up this to work with Ambient Combat Manager?

Is that possible?

Share this post


Link to post
Share on other sites

It seems to work OK with ACM.

I tryed this

in init file:

isDay_check = true;

[] execVM "script\fncIsDay.sqf";

Then in fncIsDay.sqf I have this

while {isDay_check} do {

Your code

sleep 60;

}

Now when I have played with this, I can see AI shoot up flares like hell.

(3-5 flares in the air at the same time.)

Are they going to do that, my thought was that the AI shoot one flare, then wait 10-15 second, then shoot next one.

Good script to make AI shoot flares =)

It is really fun playing with this.

Edited by Kiptanoi

Share this post


Link to post
Share on other sites

So, are you beginning to call me stupid yet? Told ya you would :D I'm aware of the amount that goes up, and have tried to implement a system against it. Each unit is now given a variable if he can shoot a flare or not. And when someone shoots a flare, this variable is updated for nearby friendly units preventing him from launching. Also the random delay was increased.

Just for the hell of it, I now let you choose if the enemy AI will be using "rocket flares". Think of it as "old style flares" (we used them when I serviced), but it's not quite up to M127A1 standards (it's still the vanilla flare being used, but with different effects).

7u4l0DRnPFQ

And to keep in mind if you think "flares are blinding". Well... They are :)

9c4R_U_70fI

All code within the spoiler tag.

init.sqf:

d_pyrotechnics = true; //False: enemy uses normal GP based flares. True: Enemy uses rocket flares, fake, but looks awesome :)

flarefirede = false;
flarefiredw = false;
d_flareliste = ["FlareWhite_GP25", "FlareWhite_GP25", "FlareWhite_GP25", "FlareWhite_GP25", "FlareWhite_GP25", "FlareWhite_GP25", "FlareRed_GP25", "FlareGreen_GP25", "FlareYellow_GP25"];
d_flarelistw = ["FlareWhite_M203", "FlareWhite_M203", "FlareWhite_M203", "FlareWhite_M203", "FlareWhite_M203", "FlareWhite_M203", "FlareRed_M203", "FlareGreen_M203", "FlareYellow_M203"];
d_airbursts = ["AirBurst1","AirBurst2","AirBurst3","AirBurst4","AirBurst5"]; //AirBurst6 reserved for artillery delivered flares, higher and less variation on colorization and variation.

[] execVM "scripts\Functions.sqf";
[] execVM "scripts\Equip.sqf";

Functions.sqf (only the relevant ones shown, I use a lot more):

fn_SunElev = {
private ["_lat", "_day", "_hour", "_angle", "_isday"]; //Not 100% correct to BIS own code, but it does the trick.
_lat = -1 * getNumber(configFile >> "CfgWorlds" >> worldName >> "latitude"); //Arma latitude is negated for some odd reason.
_day = 360 * (dateToNumber date); //Convert current day to 360 for trigonometric calculations.
_hour = (daytime / 24) * 360; //Convert current hours to 360 for trigonometric calculations.
_angle = ((12 * cos(_day) - 78) * cos(_lat) * cos(_hour)) - (24 * sin(_lat) * cos(_day)); //New one liner magic.
_angle
};
fn_IsDay = {
private ["_ret"];
_ret = if (call fn_SunElev > 0) then {true} else {false};
_ret
};

Equip.sqf:

//Just make sure your units are given ammo, get the fired eventhandler, and set the variable for all units, and for AI units, make sure the FlareShooting,sqf is started, like:
_unit addEventHandler ["fired", {_this execVM "scripts\EH-Fired.sqf"}]; //all GL units.

{_unit addMagazine (d_flareliste select (floor random (count d_flareliste)))} forEach [1,2,3,4]; //east GL units.
{_unit addMagazine (d_flarelistw select (floor random (count d_flarelistw)))} forEach [1,2,3,4]; //west GL units.

{_x setVariable ["flarefired", false]} forEach allUnits;

if (_unit != player) then {[_unit] execVM "scripts\FlareShooting.sqf"}; //all GL units, but make sure to exclude the player

FlareShooting.sqf:

private ["_unit","_check","_leader","_flarechance","_flarefired","_mags","_one_flare","_one_flare_muzzle","_random",
"_groupsenemy","_unitsenemy","_groupsfriendly","_unitsfriendly","_closefriendly","_d_flarelist","_muzzle"];
_unit = _this select 0;
_check = false;
_flarechance = 0.35;
_flarefired = false;
_unit setVariable ["flarefired", false];
_groupsenemy = [];
_unitsenemy = [];
_groupsfriendly = [];
_unitsfriendly = [];
if (side _unit == east) then {
_d_flarelist = d_flareliste;
_muzzle = "GP25Muzzle";
for "_i" from 0 to (count allGroups) - 1 do {
	if(side (allGroups select _i) == west) then {
		_groupsenemy set [count _groupsenemy, allGroups select _i];
	} else {
		_groupsfriendly set [count _groupsfriendly, allGroups select _i];
	};
};
} else {
_d_flarelist = d_flarelistw;
_muzzle = "M203Muzzle";
for "_i" from 0 to (count allGroups) - 1 do {
	if(side (allGroups select _i) == east) then {
		_groupsenemy set [count _groupsenemy, allGroups select _i];
	} else {
		_groupsfriendly set [count _groupsfriendly, allGroups select _i];
	};
};
};
for "_i" from 0 to (count _groupsenemy) - 1 do {
{_unitsenemy set [count _unitsenemy, _x]} forEach units leader (_groupsenemy select _i);
};
for "_i" from 0 to (count _groupsfriendly) - 1 do {
{_unitsfriendly set [count _unitsfriendly, _x]} forEach units leader (_groupsfriendly select _i);
};
while {alive _unit && _unit != player} do {
_flarefired = _unit getVariable "flarefired";
_check = false;
_random = 10.123 + (random 10);
if (_flarefired) then {sleep _random};
_leader = leader _unit;
{
	scopeName "xxxx1";
	if((_leader knowsAbout _x >= 0.05) && (_unit distance _x < 400) && (alive _x)) then
	{
		_check = true;
		breakout "xxxx1";
		sleep 1.123;
	};
} forEach _unitsenemy;

if (_check && !_flarefired && (random 1 < _flarechance) && !(call fn_IsDay)) then {
	_one_flare = "";
	_mags = magazines _unit;
	{
		scopeName "xxxx2";
		if (_x in _d_flarelist) then {
			_one_flare = _x;
			breakOut "xxxx2";
		};
	} forEach _mags;
	_random = 3.456 + (random 10);
	sleep _random;
	if (!_flarefired && alive _unit && _unit != player) then {
		if (_one_flare != "") then {
			sleep 1.234;
			_one_flare_muzzle = _muzzle;
			_unit selectWeapon _one_flare_muzzle;
			if (side _unit == west) then {
				_unit say "EngFlares";
			} else {
				_unit say "RusFlares";
			};
			_pos = _unit modelToWorld [0, 50, 50 + (random 100)];
			_unit doWatch _pos;
			sleep 2.345;
			_unit fire [_one_flare_muzzle, _one_flare_muzzle, _one_flare];
			sleep 1.234;
			_unit doWatch objNull;
			(group _leader) setCombatMode "YELLOW";
			_flarefired = true;
			_unit setVariable ["flarefired", true];
			for "_i" from 0 to count _unitsfriendly - 1 do {
				if (_unitsfriendly select _i distance _unit < 500) then {
					_unitsfriendly select _i setVariable ["flarefired", true];
				};
			};
			sleep 31.234;
		};
	};
	sleep 30;
};
_random = 20 + (random 20);
sleep _random;
_flarefired = false;
_unit setVariable ["flarefired", false];
};

EH-Fired:

private ["_ammo","_types","_dummy","_color","_r","_g","_b","_a","_delay","_pos","_radius","_i","_groupsenemy","_groupsfriendly","_unitsEnemy","_unitsFriendly","_pyrotechnics"];
_shooter = _this select 0;
_weapon = _this select 1;
_ammo = _this select 4;
_groupsenemy = [];
_groupsfriendly = [];
_unitsenemy = [];
_unitsfriendly = [];
_types = ["F_40mm_White","F_40mm_Yellow","F_40mm_Green","F_40mm_Red"];
_pyrotechnics = false;

//
//Deleted a lot of stuff irrelevant to flare handling
//

if !(_ammo in _types) exitWith {};
if (_shooter == player) then {player setVariable ["flarefired", true]};
if (random 1 < 0.333) then {
if (side _shooter == west) then {_shooter addMagazine "FlareWhite_M203"} else {_shooter addMagazine "FlareWhite_GP25"};
};
_delay = time + 2;
_pyrotechnics = if (side _shooter == east) then {d_pyrotechnics} else {false};
hintSilent format ["%1",_pyrotechnics];
waitUntil {!isNull nearestObject [_shooter, _ammo] || time > _delay}; //BIS, PLEASE give us object reference from "fired" eventhandler.
if (time > _delay) exitWith {}; //Failsafing. Exiting prevents error messages.
_dummy = nearestObject [_shooter, _ammo];
_timetolive = getNumber (configFile >> "CfgAmmo" >> typeOf _dummy >> "timeToLive");
_color = getArray (configFile >> "CfgAmmo" >> typeOf _dummy >> "lightColor");
if (_pyrotechnics) then {_dummy say "RocketFlare"};
sleep 0.1;
if (player distance _shooter < 400) then {
format ["%1 at %2m just fired a %3, which is now %4m from shooter", name _shooter, round (player distance _shooter), _ammo, round (_shooter distance _dummy)] call debugChat;
};
//if (count _color == 4) exitWith {hint "Something bad happened to the flare"};
_r = _color select 0;
_g = _color select 1;
_b = _color select 2;
_a = _color select 3;

[_timetolive, _color, _dummy, _pyrotechnics] spawn {
private ["_timetolive","_color","_r","_g","_b","_object","_sm","_pd","_sp","_li","_to_delete","_pyrotechnics"];
_timetolive = _this select 0;
_color = _this select 1;
_object = _this select 2;
_r = _color select 0;
_g = _color select 1;
_b = _color select 2;
_pyrotechnics = _this select 3;
_to_delete = [];
format ["Flares - %1 - %2 - %3", _timetolive, _color, _object] call debugChat;
if (_pyrotechnics) then {
	sleep 0.01;
//smoke emitter, rocket flare
	_sm = "#particlesource" createVehicleLocal getpos _object;
	_sm setParticleRandom [0.5, [0, 0, 0], [0, 0, 0], 0, 0.3, [0, 0, 0, 0], 0, 0, 360];
	_sm setParticleParams [["\ca\Data\ParticleEffects\Universal\Universal", 16, 12, 8,0],
		"", "Billboard", 1, 2, [0, 0, 0],
		[0,0,0], 1, 1, 0.80, 0.5, [0.3,4.5],
		[[0.9,0.9,0.9,0.1], [1,1,1,0.01], [1,1,1,0]],[1],0.1,0.1,"","",_object];	
	_sm setdropinterval 0.001;
//light point
	_li = "#lightpoint" createVehicleLocal getpos _object;
	_li setLightBrightness 0.12;
	_li setLightAmbient [1, 0.8, 0.7]; //slightly amber burn of the rocket engine
	_li setLightColor [1, 0.8, 0.7]; //slightly amber burn of the rocket engine
	_li lightAttachObject [_object, [0,0,0]];
	sleep 1.4;
	_object say "FlareDeploy";
	sleep 0.2;
	_object say "FlareBurn";
	sleep 0.2;
	_li setLightAmbient [_r, _g, _b];
	_li setLightColor [_r, _g, _b];
	_sm setParticleParams [["\ca\Data\ParticleEffects\Universal\Universal", 16, 12, 8,0],
		"", "Billboard", 1, 20, [0, 0, 0],
		[0,0,0], 1, 1, 0.80, 0.5, [0.4,4.0],
		[[0.9,0.9,0.9,0.1], [1,1,1,0.03], [1,1,1,0]],[1],0.1,0.1,"","",_object];	
	_sm setdropinterval 0.015;
//glowing orb
	_sp = "#particlesource" createVehicleLocal getpos _object;
	_sp setParticleRandom [0.03, [0, 0, 0], [0, 0, 0], 0, 0.2, [0, 0, 0, 0], 0, 0, 360];
	_sp setParticleParams [["\ca\Data\ParticleEffects\Universal\Universal", 16, 13, 2,0],
		"", "Billboard", 1, 0.1, [0, 0, 0],
		[0,0,0], 1, 1, 0.80, 0.5, [1.5,0],
		[[1,1,1,-4], [1,1,1,-4], [1,1,1,-2],[1,1,1,0]],[1000],0.1,0.1,"","",_object,360];	
	_sp setdropinterval 0.001;
//burned residue dropper
	sleep 4 + (random 3);
	_pd = "#particlesource" createVehicleLocal getpos _object;
	_pd setParticleRandom [5.0, [0, 0, 0], [0, 0, 0], 0, 0.2, [0, 0, 0, 0], 0, 0, 360];
	_pd setParticleParams [["\ca\Data\ParticleEffects\Universal\Universal", 16, 13, 2,0],
		"", "Billboard", 1, 0.1, [0, 0, 0],
		[0,0,0], 1, 1, -0.30, 0.5, [1.5,0],
		[[1,1,1,-4], [1,1,1,-4], [1,1,1,-2],[1,1,1,0]],[1000],0.1,0.1,"","",_object,360];	
	_pd setdropinterval 0.1;
} else {
	sleep 1.1;
	_object say (d_airbursts select (floor random (count d_airbursts)));
	sleep 0.2;
	_object say "FlareDeploy";
	sleep 0.2;
	_object say "FlareBurn";
	sleep 0.2;
//smoke emitter, grenade launched
	_sm = "#particlesource" createVehicleLocal getpos _object;
	_sm setParticleRandom [0.5, [0, 0, 0], [0, 0, 0], 0, 0.3, [0, 0, 0, 0], 0, 0, 360];
	_sm setParticleParams [["\ca\Data\ParticleEffects\Universal\Universal", 16, 12, 8,0],
		"", "Billboard", 1, 30, [0, 0, 0],
		[0,0,0], 1, 1, 0.80, 0.5, [1.3,4],
		[[0.9,0.9,0.9,0.1], [1,1,1,0.005], [1,1,1,0]],[1],0.1,0.1,"","",_object];	
	_sm setdropinterval 0.04;
//light point
	_li = "#lightpoint" createVehicleLocal getpos _object;
	_li setLightBrightness 0.12;
	_li setLightAmbient [_r, _g, _b];
	_li setLightColor [_r, _g, _b];
	_li lightAttachObject [_object, [0,0,0]];
//burned residue dropper
	_pd = "#particlesource" createVehicleLocal getpos _object;
	_pd setParticleRandom [5.0, [0, 0, 0], [0, 0, 0], 0, 0.2, [0, 0, 0, 0], 0, 0, 360];
	_pd setParticleParams [["\ca\Data\ParticleEffects\Universal\Universal", 16, 13, 2,0],
		"", "Billboard", 1, 0.1, [0, 0, 0],
		[0,0,0], 1, 1, -0.30, 0.5, [1.5,0],
		[[1,1,1,-4], [1,1,1,-4], [1,1,1,-2],[1,1,1,0]],[1000],0.1,0.1,"","",_object,360];	
	_pd setdropinterval 0.1;
//glowing orb
	_sp = "#particlesource" createVehicleLocal getpos _object;
	_sp setParticleRandom [0.03, [0, 0, 0], [0, 0, 0], 0, 0.2, [0, 0, 0, 0], 0, 0, 360];
	_sp setParticleParams [["\ca\Data\ParticleEffects\Universal\Universal", 16, 13, 2,0],
		"", "Billboard", 1, 0.1, [0, 0, 0],
		[0,0,0], 1, 1, 0.80, 0.5, [1.5,0],
		[[1,1,1,-4], [1,1,1,-4], [1,1,1,-2],[1,1,1,0]],[1000],0.1,0.1,"","",_object,360];	
	_sp setdropinterval 0.001;
};
_object hideObject true;
//Make the added light intensity falloff drastically as it closes to earth, to simulate the lack of surface angle (grazing light illuminates just as much).
[_li, _object] spawn {
	_li = _this select 0;
	_object = _this select 1;
	while {alive _object} do {
		_height = getPosATL _object select 2;
		_height = [_height, 150, 0] call fn_normalize;
		_height = (1 - _height)^4;
		_height = 0 max _height;
		_li setLightBrightness (0.12 * _height);
		sleep 1.234;
	};
};
_to_delete = _to_delete + [_sm, _sp, _li];
[_to_delete, _timetolive, _object] spawn {
	_to_delete = _this select 0;
	_timetolive = _this select 1;
	_object = _this select 2;
	_timer = time + _timetolive;
	while {time < _timer} do {
		_object setPos [(getPos _object select 0) + 0.1 * (wind select 0), (getPos _object select 1) + 0.1 * (wind select 1), (getPos _object select 2) + 0.4];
		sleep 0.123;
	};
	{deleteVehicle _x} forEach (_this select 0);
};
};
//Make an array of units in the vicinity of the flare
while {alive _dummy} do {
_pos = getPos _dummy;
_radius = 200 * (_r + _g + _b); //Gives 300m for a white flare since base vanilla value is 0.5
for "_i" from 0 to (count allGroups) - 1 do {
	if(side (allGroups select _i) != playerside) then {
		if (leader (allGroups select _i) distance _pos < _radius) then {
			_groupsenemy set [count _groupsenemy, allGroups select _i];
			sleep 0.0012;
		};
	} else {
		if (leader (allGroups select _i) distance _pos < _radius) then {
			_groupsfriendly set [count _groupsfriendly, allGroups select _i];
			sleep 0.0012;
		};
	};
};
//	[_groupsenemy, _groupsfriendly] spawn {_en = _this select 0; _fr = _this select 1; hintSilent format ["en: %1", _en]; sleep 2; hintSilent format ["fr: %1", _fr]; diag_log format ["en = %1, fr = %2", _en, _fr]};
for "_i" from 0 to (count _groupsenemy) - 1 do {
	{if (alive _x) then {_unitsenemy set [count _unitsenemy, _x]}} forEach units leader (_groupsenemy select _i);
	sleep 0.0012;
};
for "_i" from 0 to (count _groupsfriendly) - 1 do {
	{if (alive _x) then {_unitsfriendly set [count _unitsfriendly, _x]}} forEach units leader (_groupsfriendly select _i);
	sleep 0.0012;
};
sleep 5; //Artificial delay to make units "study the surroundings" a little more. Already way too powerful.
for "_i" from 0 to (count _groupsfriendly) - 1 do {
	{(leader (_groupsfriendly select _i)) reveal _x} forEach _unitsEnemy;
	sleep 0.0012;
};
for "_i" from 0 to (count _groupsenemy) - 1 do {
	{(leader (_groupsenemy select _i)) reveal _x} forEach _unitsFriendly;
	sleep 0.0012;
};
if (debug) then {hint format ["_pos: %1\n_unitsfriendly: %2\n_unitsenemy: %3", _pos, count _unitsfriendly, count _unitsenemy]};
_groupsenemy = [];
_groupsfriendly = [];
_unitsenemy = [];
_unitsfriendly = [];
//	sleep 4.567;
if (_shooter == player) then {player addMagazine "FlareRed_M203"};
};

And finally, relevant parts from my description.ext, if you have the sounds:

//Some sound effects
class RocketFlare {name="RocketFlare";sound[]={\sounds\RocketFlare.wss,db-10,1.0};titles[] = {};}; //Mono
class AirBurst1 {name="AirBurst1";sound[]={\sounds\AirBurst1.ogg,db-6,1.0};titles[] = {};}; //Mono
class AirBurst2 {name="AirBurst2";sound[]={\sounds\AirBurst2.ogg,db-6,1.0};titles[] = {};}; //Mono
class AirBurst3 {name="AirBurst3";sound[]={\sounds\AirBurst3.ogg,db-6,1.0};titles[] = {};}; //Mono
class AirBurst4 {name="AirBurst4";sound[]={\sounds\AirBurst4.ogg,db-6,1.0};titles[] = {};}; //Mono
class AirBurst5 {name="AirBurst5";sound[]={\sounds\AirBurst5.ogg,db-6,1.0};titles[] = {};}; //Mono
class AirBurst6 {name="AirBurst6";sound[]={\sounds\AirBurst6.ogg,db-6,1.0};titles[] = {};}; //Mono
class FlareDeploy {name="FlareDeploy";sound[]={\sounds\FlareDeploy.ogg,db-8,1.0};titles[] = {};}; //Mono
class FlareBurn {name="FlareBurn";sound[]={\sounds\FlareBurn.ogg,db-10,1.0};titles[] = {};}; //Mono
//Voices
class EngFlares {name="EngFlares";sound[]={\talk\eng_flares.ogg,db-20,1.0};titles[] = {};}; //Mono
class RusFlares {name="FlaresRus";sound[]={\talk\rus_flares.ogg,db-20,1.0};titles[] = {};}; //Mono

All I really need to address now is the stupid "information sharing" reveal thingy, which is waaay too good now. I know ACE is handling vanilla flares differently, so I could probably pick up some things there. Also, (I've read that) mando missiles have some sort of "can see unit" check, this might also be worth looking into.

Btw, you might want to disable the "residue dropper" for vanilla flares and use it only for rocket flares (I've seen youtube videos with this happening), as it doesn't look too good at the moment.

Have fun, I know I'm loving this :)

Edit1: Hopefully fixed FlareShooting.sqf (had some bracing errors due to last minute changes).

Edit2: Fixed _lat lookup in fn_SunElev (should now work correctly also with Thirsk Winter).

Edited by CarlGustaffa
Shown in edit note.

Share this post


Link to post
Share on other sites

Thx a lot m8!

I am trying to implement it into Dac, which shouldnt be too hard, as it can be "easily" implemented via event.

Give ya a shout or mission example if interested.

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
Sign in to follow this  

×