Jump to content
Donald Flatulence

How to turn init code in to a script?

Recommended Posts

Hi all,

I'm still getting acquainted with scripting, I have this code placed in the init box of a grouped unit, which works perfectly.

{
_x doMove getpos Attack;   
_x setspeedmode "FULL";   
_x setbehaviour "SAFE";   
_x setskill ["spotDistance",0.1];   
_x setskill ["spotTime",0.1];   
_x setskill ["courage",1];   
_x setskill ["commanding",0.1];
_x setskill ["general",0.1];
}forEach units group this;

However when I move the units in zeus or spawn more, the effect of this code is (of course) cancelled, so I was hoping to turn this into script such as

{
if (_x side == "EAST") then {
_x doMove getpos Attack;   
_x setspeedmode "FULL";   
_x setbehaviour "SAFE";   
_x setskill ["spotDistance",0.1];   
_x setskill ["spotTime",0.1];   
_x setskill ["courage",1];   
_x setskill ["commanding",0.1];
_x setskill ["general",0.1];
};
} forEach allUnits 

I know the script is successfully called as I added a line to create a hint which showed in game, however the AI simply remains still. Ideally this would actually be a "while" loop that repeated so any movement of units using zeus, or addition of new units, would still allow the same commands to be applied. The script was being called from the init.sqf.

Any help would be much appreciated, as always.

Share this post


Link to post
Share on other sites
if (side _x == EAST) then {...};

Share this post


Link to post
Share on other sites

This should work for you.

Basically what this script does is to set the AI skills etc on mission statup, but then every 30 seconds checks to see if there's any more added/spawned units. If so then gives them the same settings.

Save it as ConfigAI.sqf and put this in your init.sqf

[] execVM "ConfigAI.sqf";

ConfigAI.sqf

// ConfigAI Skills script
// By Beerkan beta 0.97
//Client/Server Check
if (!isServer) exitWith {};

ConfigUnits = {
        _unit = _this select 0;
        _unit setskill ['aimingAccuracy',(0.3 + random 0.3)];
        _unit setskill ['aimingShake',(0.3 + random 0.3)];
        _unit setskill ['aimingSpeed',(0.3 + random 0.3)];
        _unit setskill ['commanding',(0.3 + random 0.3)];
        _unit setskill ['courage',1];
//        _unit setskill ['endurance',(0.3 + random 0.5)];// No longer used in ArmA3
        _unit setskill ['general',(0.3 + random 0.4)];
        _unit setskill ['reloadSpeed',(0.3 + random 0.2)];
        _unit setskill ['spotDistance',(0.3 + random 0.2)];
        _unit setskill ['spotTime',(0.3 + random 0.2)];
        _unit allowfleeing 0;
                };
                
  // Now filter for only East units,
	{ if (side _x isEqualTo EAST && _x IsKindof 'Man') then {[_x] spawn ConfigUnits}
		else {if (side _x isEqualTo EAST) then {{[_x] call ConfigUnits} forEach crew _x};};
	} forEach allUnits;

  // Now save this array of units for later use
    _CheckedUnits = allUnits;
  // We now have all Units that started on the map with configured with our new settings.
  // We can now set up a loop to monitor for anything new being created
  // in this case every 30 seconds
	while {true} do
	{
	// this variable will contain any new units that were not included on a previous loop
		_NewUnits = [];
	// Remove checked Units from the updated Unit array to create a list of new Units
		_NewUnits = allUnits - _CheckedUnits;
	// Now only do the following if there are new units found.
		if (count _NewUnits > 0) then 
			{
				{ if (side _x isEqualTo EAST && _x IsKindof 'Man') then {[_x] spawn ConfigUnits}
					else {if (side _x isEqualTo EAST) then {{[_x] call ConfigUnits} forEach crew _x};};
				} forEach _NewUnits;
			};
	composeText [parsetext format["<t size='1.5' align='left' color='#ffffff'>There are <t color='#00ff00'>%1 <t color='#ffffff'>new units found and <t color='#ff0000'>%2 <t color='#ffffff'>Checked Units",count _NewUnits,count _CheckedUnits]] remoteExec ["hint"];// Debug
		_CheckedUnits append _NewUnits;
		sleep 30;
	};
 
Edited by Beerkan
Added remoteExec hint for debuging reasons.

Share this post


Link to post
Share on other sites

Thanks to you both, Beerkan as your script will loop its exactly what I needed!

There was me thinking "Oh I'm sure I can work this out by myself..."

Any way, thanks again.

Share this post


Link to post
Share on other sites

Beerkan, your AI config script seems like exactly what I need for my community, and your comments make it really easy to adjust and follow along with what's happening. Thank you for making this available. For reasons unknown, I cannot get it to work on my group's server. I re-commented the debugging hint to make sure, and the hint never comes up. Does the script work for everyone else? Is it possible something in the game has changed since you put this together back in 2015 that would cause it to not work? Thanks in advance for any assistance you can offer!

 

EDIT: Sorry I didn't mention this sooner, but the hint does appear when I test in single player.

Share this post


Link to post
Share on other sites
14 hours ago, diehardfc said:

Beerkan, your AI config script seems like exactly what I need for my community, and your comments make it really easy to adjust and follow along with what's happening. Thank you for making this available. For reasons unknown, I cannot get it to work on my group's server. I re-commented the debugging hint to make sure, and the hint never comes up. Does the script work for everyone else? Is it possible something in the game has changed since you put this together back in 2015 that would cause it to not work? Thanks in advance for any assistance you can offer!

 

EDIT: Sorry I didn't mention this sooner, but the hint does appear when I test in single player.

 

I do believe hintSilent does not work on mp as i tried it out myself, change it to hint

Share this post


Link to post
Share on other sites
7 hours ago, BlacKnightBK said:

I do believe hintSilent does not work on mp as i tried it out myself, change it to hint

Dang it, that didn't do the trick. Good thought, though.

Share this post


Link to post
Share on other sites

Guys, I've replace hintSilent with hint composetext to help with debug.

 

See my changes above.

This should now work in MP as expected and show you checked units on startup, and newly spawned units if found.

 

Remove the hint composetext line when you have the script working for you.

Share this post


Link to post
Share on other sites
9 hours ago, diehardfc said:

Dang it, that didn't do the trick. Good thought, though.

Sorry, I totally remember now.

 

I have no idea why, but the only way it actually worked with me is after i did this:

_title  = "<t color='#ff0000' size='2' shadow='1' shadowColor='#000000' align='center'>New Main Mission</t>";
    _text   = "<br /><t color='#0000ff' size='1.2' shadow='1' shadowColor='#000000' align='center'>Attention Soldiers, you have a new available mission. Read the breifing and await orders from HQ on how to proceed.</t>";

    hint parseText (_title+_text);
    sleep 10;
    hint "";

Basically, I had to assign the text I needed to a variable and then I put in the hint as you see above. I know it is kind of torture but if that does not work for you I have no idea what would.

Share this post


Link to post
Share on other sites

Hmm, once again hint composeText works fine when tested in single player, but when pushed up to our dedicated server, no hints appear. Could there be a server setting preventing this from running?

Share this post


Link to post
Share on other sites
53 minutes ago, diehardfc said:

Hmm, once again hint composeText works fine when tested in single player, but when pushed up to our dedicated server, no hints appear. Could there be a server setting preventing this from running?

 

I have no idea how to help you mate, works perfectly fine for me. As a matter of fact, my issue is how to make sure the hint only appears to a certain player only. Did write a conditional code however have not yet tried it

Share this post


Link to post
Share on other sites

Another solution, initializes units in background (including created during mission progress):

// in init.sqf
if (isServer) then {
	[]spawn {
		{
			if (_x isKindof "Man" and {_x getVariable ["NotInitiallized", true]}) then {
				_x setVariable ["NotInitiallized", false];
				if (side _x == EAST) then {
					_x setspeedmode "FULL";
					_x setbehaviour "SAFE";
					_x setskill ["spotDistance",0.1];
					_x setskill ["spotTime",0.1];
					_x setskill ["courage",1];
					_x setskill ["commanding",0.1];
					_x setskill ["general",0.1];
				}
			};
			sleep 0.01
		} forEach allUnits;
		sleep 1.0
	}
};

 

  • Like 1

Share this post


Link to post
Share on other sites
11 hours ago, diehardfc said:

Hmm, once again hint composeText works fine when tested in single player, but when pushed up to our dedicated server, no hints appear.

Due to it being on a dedicated and the script only runs on the server

if ( !isServer ) exitwith {

you would need to remoteExec the Hint.

 

Here is a rewrite I done of Beerkans script that self initialises from CfgFunctions.

All settings can be found in \BKN\setUnitSkills\settings.hpp. Where..

  • you can set what sides to apply skill and allowFleeing settings on
  • separate settings for each side
  • set time between checks
  • whether debug info is available
  • if in MP debug is reserved only to flagged admins (via UID), in SP its always granted to the player if debug mode is available

Tested in SP, MP and on dedicated.

  • Like 1

Share this post


Link to post
Share on other sites
2 hours ago, Larrow said:

Due to it being on a dedicated and the script only runs on the server


if ( !isServer ) exitwith {

you would need to remoteExec the Hint.

 

Here is a rewrite I done of Beerkans script that self initialises from CfgFunctions.

All settings can be found in \BKN\setUnitSkills\settings.hpp. Where..

  • you can set what sides to apply skill and allowFleeing settings on
  • separate settings for each side
  • set time between checks
  • whether debug info is available
  • if in MP debug is reserved only to flagged admins (via UID), in SP its always granted to the player if debug mode is available

Tested in SP, MP and on dedicated.

 

ah, probably works for me fine then because my script is launched from the server init?

Share this post


Link to post
Share on other sites
On 2/16/2017 at 9:39 AM, Larrow said:

Here is a rewrite I done of Beerkans script that self initialises from CfgFunctions.

Tested in SP, MP and on dedicated.

This is clean, beautiful and easy to use - thank you for sharing! My unit has recently started using headless clients, which I'm learning can cause some challenges when it comes to locality. Are you able to say if your script would work for a server using headless clients? I'm guessing yes if the skills are changed before the handoff to the HC, but if the unit is handed off to the HC before the script runs, I wonder if it will work.

Share this post


Link to post
Share on other sites
1 hour ago, diehardfc said:

Are you able to say if your script would work for a server using headless clients?

It should be fine, although I have not personally checked HC, but the setUnitSkills function is called via remoteExec to where the unit is local.

  • Like 1

Share this post


Link to post
Share on other sites
On 3/24/2017 at 4:11 PM, Larrow said:

It should be fine, although I have not personally checked HC, but the setUnitSkills function is called via remoteExec to where the unit is local.

You're not obliged to troubleshoot this, Larrow, but I would be very grateful if you might lend your expertise to this issue I'm experiencing. I don't think it's related to the headless clients I mentioned. The problem I'm having is that I simply can't get your script to run on my community's dedicated server. It works in a single player mission I built, albeit with some errors related to fn_handleDebugClient.sqf. In single player, I see the debug window and have the scroll wheel menu actions available. I'm also able to place units as Zeus and check their skills and they are definitely adjusted. But, despite entering (and double checking) my player ID into the BKN_Admins field of the settings.hpp, I get nothing when I PBO the file and send it up to the dedicated server. For safety, I checked, and I've got the classCfgFunctions and the #include for settings in the description.ext. Can you think of why it might not work? I saw something in fn_addAdminAction.sqf about remoteExec and a line of commented out code. Do I need to adjust that because it's a dedicated server? Thank you in advance if you can help out!

 

EDIT: I apologize for not testing more thoroughly, but it turns out this script IS running. I placed units as Zeus and opened their Skill settings and they all changed in accordance with the script. And no changebacks or errors when handed off the headless client! There's just no debug output. I suppose the debug info would be useful, but I'm not too worried bout it everything else is working.

Share this post


Link to post
Share on other sites

If I were interested in applying the AI skill changes to both OPFOR and INDEP, could I use the "or" function like this:

{ if (side _x isEqualTo EAST or RESISTANCE && _x IsKindof 'Man') then {[_x] spawn ConfigUnits}
	else {if (side _x isEqualTo EAST or RESISTANCE) then {{[_x] call ConfigUnits} forEach crew _x};}; 
} forEach allUnits;

Or do I need special nesting? What if I was willing to apply it to all AI, regardless of side?

Share this post


Link to post
Share on other sites

(   (side _x isEqualTo EAST or side _x isEqualTo RESISTANCE) && ...

  • Like 1

Share this post


Link to post
Share on other sites

Hey guys, trying to use parts of this for a function that changes the loadout of AI when they are spawned in, problem is I cant get the units that have already been changed to be excluded. Im trying to append and use the set/get variable but its changing all the units everytime. I think it's a scope issue? What do you guys think?

 

my init.sqf:

// detect and change all units on map
private _units = allUnits select {!isPlayer _x && { alive _x } && !(_x getVariable ["CB_VAR_PAINTED",false])};    
	{
        [_x] spawn CB_fnc_factionConfig;
        _x setVariable ["CB_VAR_PAINTED",true,true];
	} forEach _units;
uiSleep 1;

CB_CHECK_UNITS = true;
private _checkedUnits = allUnits;

while {CB_CHECK_UNITS} do
	{
	// this variable will contain any new units that were not included on a previous loop
		_NewUnits = [];
	// Remove checked Units from the updated Unit array to create a list of new Units
		_NewUnits = allUnits - _checkedUnits;
	// Now only do the following if there are new units found.
		if (count _NewUnits > 0) then 
			{
				{ if (side _x isEqualTo WEST && _x IsKindof 'Man') then {[_x] spawn CB_fnc_factionConfig}
					else {if (side _x isEqualTo WEST) then {{[_x] call CB_fnc_factionConfig} forEach crew _x};}; _x setVariable ["CB_VAR_PAINTED",true,true];
				} forEach _NewUnits; _checkedUnits append _NewUnits;
			};
	 hint composeText [parsetext format["<t size='1.5' align='left' color='#ffffff'>There are <t color='#00ff00'>%1 <t color='#ffffff'>new units found and <t color='#ff0000'>%2 <t color='#ffffff'>Checked Units",count _NewUnits,count _checkedUnits]];// Debug
		
		sleep 30;
	};

 

Share this post


Link to post
Share on other sites

_newUnits is just allUnits - _checkedUnits ... but _checkedUnits is also allUnits ...  further more, your variable _units seems to be useless.

 

If I'm right you want to treat edited units and the spawned ones.

An event handler is usually better than a loop. Here, the easy way is to treat in two parts, in init.sqf:

 

{ _x spawn ...} forEach allUnits;    // or add a filter: ... forEach (allUnits select {!isplayer _x}) (alive _x is useless with allUnits)

addMissionEventHandler ["EntityCreated", {
   params ["_entity"];
  if (_entity isKindOf "CAManBase") then { do something on _entity};
}];

 

Share this post


Link to post
Share on other sites
Quote

An event handler is usually better than a loop.

 

Holy smokes, event handlers... of course. It was one of those situations where you stare at the same code/script for 2 days and it just melts your brain and you forget about simple things. Thanks for the wake up pierremgi!

Still not working though. I have the set up like yours as I agree that an EH is better for the goal, but it still changes all units whenever an entity is created. Should I use _x setVariable on them somehow? Although I tried that many ways already with no luck

 

init.sqf

private _mapUnits = allUnits select {!isPlayer _x};    
{[_x] call CB_fnc_factionConfig;} forEach _mapUnits;
uiSleep 1;

addMissionEventHandler ["EntityCreated", {
   params ["_entity"];
  if (_entity isKindOf "CAManBase") then {[_entity] call CB_fnc_factionConfig;};
}];

 

When I spawn a unit(s) every one in the world gets the function applied again, except player and dead bodies. How would I exclude those previous units and only run it on newly spawned/created?

fn_factionConfig.sqf

// handles
private _unit = _this select 0;
if (isPlayer _unit) exitWith {};


// all get naked
removeAllWeapons _unit;
removeAllItems _unit;
removeAllAssignedItems _unit;
removeUniform _unit;
removeVest _unit;
removeBackpack _unit;
removeHeadgear _unit;
removeGoggles _unit;
_unit unlinkItem hmd _unit;

/* 
    
	Factions can be one of the following
    West: "BLU_F" (NATO), "BLU_G_F" (FIA), "BLU_CTRG_F" (NATO CTRG), BLU_GEN_F (POLICE)
    East: "OPF_F" (CSAT), "OPF_G_F" (FIA), "OPF_T_F" (CSAT Tanoa)
    Guer: "IND_F" (AAF),  "IND_G_F" (FIA), "IND_C_F" (SYNDIKAT Tanoa)
    Civ: "CIV_F" (Civilians) 
*/


{ if (faction _x isEqualTo 'BLU_F' && _x IsKindof 'Man') then {[_x] execVM 'scripts\loadouts\BLUFOR\NATO.sqf';}
		else {if (faction _x isEqualTo 'BLU_F') then {{[_x] execVM 'scripts\loadouts\BLUFOR\NATO.sqf'} forEach crew _x};};
} forEach allUnits;

Im thinking I need to add these into some exclusion array that I could use instead of allUnits at the end but I am not sure of how. For some clarity, the function should essentially re-dress any spawned unit via my function CB_fnc_factionConfig. In there it takes side and faction into account and executes a loadout from other scripts that have switch/case/do for assigned classnames. 

Share this post


Link to post
Share on other sites

 {_x .... } forEach allUnits;

is OK at start, on server only (no need to re-run that at each JIP)

Note: For MP scenario, you must check if your sqf are ok for all commands with global effect GE . Multiplayer needs more attention for many things. See multiplayer threads.

and https://community.bistudio.com/wiki/Multiplayer_Scripting

 

Once in MEH "entityCreated", just use _entity for all you want to do. As there are plenty of different entities (objects like rabbits, projectiles,...), you need to filter. For example:

if (faction _entity isEqualTo "BLU_F" && {_entity isKindOf "CAManBase"}) then { [_entity] execVM "scripts\loadouts\BLUFOR\NATO.sqf"};

Here, you check for faction, which is a strong filter, then (lazy evaluation) you filter only unit ("CAManBase", because rabbits & snakes are "man") and you skip the vehicles of the faction.

Note: execVMing an sqf is not the best way for performance saving, because you're recompiling the same code again and again. Create a function instead and call or spawn it. (there threads about that and BIKI is your friend).

https://community.bistudio.com/wiki/Script_File

https://community.bistudio.com/wiki/Function

https://community.bistudio.com/wiki/Description.ext

especially : https://community.bistudio.com/wiki/Arma_3:_Functions_Library

 

 

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

×