Crap. Me and my big mouth
Ehm, ok. Note that this is for east enemy AI only. I thought I had a more generalized version available, but I'm not sure how up to date that one is compared to how I use it in Domino, so I show this way.
When units are created, call this:
Code:
[_unit] call x_equipunit;
Where x_equipunit is:
Code:
x_equipunit = {
private ["_unit"];
_unit = _this select 0;
_muzzles = getArray(configFile>> "cfgWeapons" >> primaryWeapon _unit >> "muzzles");
if (count _muzzles == 2) then {
_flaremagsw = ["FlareWhite_M203","FlareGreen_M203","FlareRed_M203","FlareYellow_M203"];
_flaremagse = ["FlareWhite_GP25","FlareGreen_GP25","FlareRed_GP25","FlareYellow_GP25"];
if ("M203Muzzle" in _muzzles) then {
if (typeOf _unit in ["TK_Soldier_GL_EP1"]) then {
{_unit removeMagazine "1Rnd_HE_M203"} forEach [1,2,3,4];
};
for "_i" from 0 to 3 do {
_unit addMagazine (_flaremagsw select (_flaremagsw call XfRandomFloorArray));
};
};
if ("GP25Muzzle" in _muzzles) then {
_unit addMagazine (_flaremagse select (_flaremagse call XfRandomFloorArray));
};
_unit addEventHandler ["fired",{_this spawn DOM_EH_Fired}];
[_unit] execVM "bat\EnemyFlares.sqf";
};
};
XfRandomFloorArray is a basic randomizer:
Code:
XfRandomFloorArray = {floor (random (count _this))};
The DOM_EH_Fired is precompiled via:
Code:
DOM_EH_Fired = compile preprocessFileLineNumbers "bat\EH-Fired.sqf";
which looks like this (tried to remove all additional stuff it does):
Code:
_unit = _this select 0;
_weapon = _this select 1;
_muzzle = _this select 2;
_mode = _this select 3;
_ammo = _this select 4;
_magazine = _this select 5; //Not in use yet.
_projectile = _this select 6; //_this expanded removed, now uses internal projectile support.
_flareammo = ["F_40mm_White","F_40mm_Green","F_40mm_Red","F_40mm_Yellow"];
_flaremagsw = ["FlareWhite_M203","FlareGreen_M203","FlareRed_M203","FlareYellow_M203"];
_flaremagse = ["FlareWhite_GP25","FlareGreen_GP25","FlareRed_GP25","FlareYellow_GP25"];
//For AI, add back ammo if shooting flares
if (_unit != player) then {
_restore = "";
if (_muzzle == "GP25Muzzle") then {
switch (_ammo) do {
case "F_40mm_White" : {_restore = "FlareWhite_GP25"};
case "F_40mm_Green" : {_restore = "FlareGreen_GP25"};
case "F_40mm_Red" : {_restore = "FlareRed_GP25"};
case "F_40mm_Yellow" : {_restore = "FlareYellow_GP25"};
};
} else {
switch (_ammo) do {
case "F_40mm_White" : {_restore = "FlareWhite_M203"};
case "F_40mm_Green" : {_restore = "FlareGreen_M203"};
case "F_40mm_Red" : {_restore = "FlareRed_M203"};
case "F_40mm_Yellow" : {_restore = "FlareYellow_M203"};
};
};
if (_restore != "") then {_unit addMagazine _restore};
};
if (_ammo in _flareammo) then { //Forget these for now, I'll try to explain in detail later.
// ["glflareclient", [_projectile]] call XNetCallEvent;
// ["glflareserver", [_projectile]] call XNetCallEvent;
};
And finally, the actual script that does the shooting of the flares:
Code:
private ["_unit","_check","_leader","_flarechance","_mags","_one_flare","_one_flare_muzzle","_muzzles","_enemies"];
_unit = _this select 0;
_flarechance = 0.6;
_enemylist = [];
_flareammo = ["F_40mm_White","F_40mm_Green","F_40mm_Red","F_40mm_Yellow"];
_flaremagsw = ["FlareWhite_M203","FlareGreen_M203","FlareRed_M203","FlareYellow_M203"];
_flaremagse = ["FlareWhite_GP25","FlareGreen_GP25","FlareRed_GP25","FlareYellow_GP25"];
_flarefired = false;
_unit setVariable ["flarefired", false];
sleep 0.123;
while {alive _unit} do {
_flarefired = _unit getVariable "flarefired";
if (_flarefired) then {sleep 10.123 + (random 10)};
_leader = leader _unit;
_check = false;
_enemies = [];
_enemies = nearestObjects [_unit,["SoldierWB"],400];
{
scopeName "xxxx1";
if((_leader knowsAbout _x >= 0.05) && (_unit distance _x < 300) && ((side _unit) getFriend (side _x)) < 0.6) then {
_check = true;
breakout "xxxx1";
sleep 1.123;
};
} forEach _enemies;
if (_check && !_flarefired && (random 1 < _flarechance) && !(call X_fnc_isDay)) then {
_one_flare = "";
_mags = magazines _unit;
{
scopeName "xxxx2";
if (_x in _flaremagsw || _x in _flaremagse) then {
_one_flare = _x;
breakOut "xxxx2";
};
} forEach _mags;
sleep 3.345;
if (!_flarefired && alive _unit) then {
if (_one_flare != "") then {
sleep 1.234;
_muzzles = getArray(configFile>> "cfgWeapons" >> primaryWeapon _unit >> "muzzles");
_one_flare_muzzle = "";
if ("GP25Muzzle" in _muzzles) then {_one_flare_muzzle = "GP25Muzzle"};
if ("M203Muzzle" in _muzzles) then {_one_flare_muzzle = "M203Muzzle"};
sleep (3 + random 6);
_unit selectWeapon _one_flare_muzzle;
if (count _enemies == 0) then {
_unit doWatch [getPos _unit select 0, getPos _unit select 1, 200];
} else {
_unit doWatch [getPos (_enemies select 0) select 0, getPos (_enemies select 0) select 1, 150 + (300 - (_unit distance (_enemies select 0))/2)];
};
sleep 1.234;
_unit fire [_one_flare_muzzle, _one_flare_muzzle, _one_flare];
sleep 1.234;
_flarefired = true;
_unit setVariable ["flarefired", true];
_unit doWatch objNull;
sleep 31.234;
if (random 1 < 0.7) then {
if (_one_flare_muzzle == "GP25Muzzle") then {
_unit addMagazine (_flaremagse select (_flaremagse call XfRandomFloorArray));
} else {
_unit addMagazine (_flaremagsw select (_flaremagsw call XfRandomFloorArray));
};
};
};
}
else {
_flarefired = false;
};
sleep 30;
};
sleep 10 + (random 10);
_flarefired = false;
_unit setVariable ["flarefired", false];
};
Note the low knowsAbout value in red. That's what trigger the unit to use flares in the first place. Adjust to suit. Also I'm using "SoldierWB", which isn't very generalized. Adjust to suit. The blue command nearestObjects would probably work even better with nearestEntities.
The script checks for night using a generalized function that looks like:
Code:
X_fnc_IsDay = {
private ["_ret"];
_ret = if (call X_fnc_SunElev > 0) then {true} else {false};
_ret
};
and (phew...)
Code:
X_fnc_SunElev = {
/*
Author: CarlGustaffa
Description:
Returns the suns altitude for current day and hour of the year on any island (whos latitude may differ).
Parameters:
None needed.
Returns:
Suns altitude in degrees, positive values after sunrise, negative values before sunrise.
*/
private ["_lat", "_day", "_hour", "_angle", "_isday"];
_lat = -1 * getNumber(configFile >> "CfgWorlds" >> worldName >> "latitude");
_day = 360 * (dateToNumber date);
_hour = (daytime / 24) * 360;
_angle = ((12 * cos(_day) - 78) * cos(_lat) * cos(_hour)) - (24 * sin(_lat) * cos(_day));
_angle
};
but for a static mission on a static island you could pull it off with a normal time check instead.
Now, about those effect files, they are called in this weird looking way because that's the semantics that Domination uses. How you end up calling them are up to you, but they are split up into client and server scripts so you can easily see what's going on. In Domination there is a middle wrapper handling system that sits between everything, but I'm not going to add more confusion by using that here, so I'll just show the scripts that end up on clients and server:
client:
Code:
GL_Effects_Flare_Client = {
_projectile = _this select 0;
_delay = time + 3;
waitUntil {count getArray (configFile >> "CfgAmmo" >> typeOf _projectile >> "lightColor") > 1 || time > _delay};
if (time > _delay) exitWith {}; //Not a flare.
sleep 2;
if (!alive _projectile) exitWith {}; //Color will not have enough elements if dead.
_timetolive = getNumber (configFile >> "CfgAmmo" >> (typeOf _projectile) >> "timeToLive");
_color = getArray (configFile >> "CfgAmmo" >> typeOf _projectile >> "lightColor");
_r = _color select 0;
_g = _color select 1;
_b = _color select 2;
_a = _color select 3;
sleep 0.05;
_sm = "#particlesource" createVehicleLocal getPos _projectile;
_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, 3, [0, 0, 0],
[0,0,0], 1, 1, 0.80, 0.5, [0.6,1.4],
[[0.9,0.9,0.9,0.6], [1,1,1,0.3], [1,1,1,0]],[1],0.1,0.1,"","",_projectile];
_sm setdropinterval 0.02;
_sp = "#particlesource" createVehicleLocal getPos _projectile;
_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],
[[_r,_g,_b,-4], [_r,_g,_b,-4], [_r,_g,_b,-2],[_r,_g,_b,0]],[1000],0.1,0.1,"","",_projectile,360];
_sp setdropinterval 0.001;
// _projectile say3D "FlareBurnGL"; //Activate if you have a 30 second sound sample available.
_to_delete = [_sm, _sp];
sleep 0.1;
[_to_delete, _projectile] spawn {
_to_delete = _this select 0;
_projectile = _this select 1;
waitUntil {!alive _projectile};
{deleteVehicle _x} forEach (_to_delete);
};
};
server:
Code:
GL_Effects_Flare_Server = {
_projectile = _this select 0;
_delay = time + 3;
waitUntil {count getArray (configFile >> "CfgAmmo" >> typeOf _projectile >> "lightColor") > 1 || time > _delay};
if (time > _delay) exitWith {}; //Not a flare.
sleep 2;
if (!alive _projectile) exitWith {}; //Color will not have enough elements if dead.
_color = getArray (configFile >> "CfgAmmo" >> typeOf _projectile >> "lightColor");
_r = _color select 0;
_g = _color select 1;
_b = _color select 2;
_a = _color select 3;
_li = "#lightpoint" createVehicleLocal [0,0,0]; //getPos _projectile;
_li setLightBrightness 0.24; //2.44;
_li setLightAmbient[_r*0.8, _g*0.8, _b*0.8];
_li setLightColor[_r, _g, _b];
_li lightAttachObject [_projectile, [0,0,0]];
[_projectile] spawn {
_projectile = _this select 0;
while {alive _projectile} do {
_projectile setPosASL [(getPosASL _projectile select 0) + 0.05 * (wind select 0), (getPosASL _projectile select 1) + 0.05 * (wind select 1), (getPosASL _projectile select 2) + 0.2];
sleep 0.075;
};
};
waitUntil {!alive _projectile};
deleteVehicle _li;
};
Client script adds a lightsource (really only needed if you have AIs on your team, since AI will see what you see, and the flare alone as I said will not actually give additional spotting capabilities to the AI) to the flare. It also adds a glowing orb, also visible in daylight, and some smoke effects. Burnt residue effect was removed (didn't like how it looked in the end).
Server script also adds a lightsource (highly needed in COOP games, or they won't be aided by the flare). It doesn't add glowing orb or smoke as AI could care less. But it does add wind drift, but you may have to adjust its effect and delay to suit. Due to how AI sometimes shoots flares by aiming at you, I decided not to include any simulation stopping just above ground (like in ACE), and I rather just call it "destroyed on impact" instead.
Feel free to enhance and fix, no permissions needed, and no credits required. It may look a bit complex, but it's actually quite straightforward - no rocket science going on here
Remember, running scripts on a per unit basis is BAD stuff, so optimizing this to loop over all units instead might be a first optimization step. GL flares are a bit more straightforward to handle than arty flares, as there are no incoming sounds, delay, expel sound, delay, ignite sequence that needs to be maintained.
Hope this is useful, and not adding too much confusion to the mix. Alternatively, you can try to create it for yourself from scratch, and come back and check how I solved some of the error messages you might come across. Hope I managed to put it all in this time, instead of just fragments