thy_ 164 Posted February 23, 2022 Hello again, everyone. I'm doing my first steps into functions and parameters. Everything in this matter is new for me so here is my idea: For studies purposes, I want to put a helmet in each unit I get close. To set the target units for the function, all I would like to do is set a "call" in each unit-target. That said, my try (not working): myFunctions\TAG_fnc_addingHelmet.sqf: if (!isServer) exitWith {}; TAG_fnc_addingHelmet = { params ["_unit"]; if ( ((player01 distance _unit) < 3) AND (headgear _unit != "H_HelmetB") ) then { removeHeadGear _unit; _unit addHeadgear "H_HelmetB"; hint "Oh, thanks for the helmet!"; }; }; [] spawn { while { alive player01 } do { // Do I need to call the TAG_fnc_addingHelmet function in here somehow? sleep 5; }; }; And all I would like to do is put it (below) in unit init for this call my function: Init of any random unit: [this] call TAG_fnc_addingHelmet; Where are my mistakes, folks? More info: description.ext: class cfgFunctions { #include "myFunctions\TAG_fnc_functions.hpp" }; myFunctions\TAG_fnc_functions.hpp: class TAG { class init { class TAG_addingHelmet { file = "myFunctions\TAG_fnc_addingHelmet.sqf"; preInit = 1; }; }; }; 1 Share this post Link to post Share on other sites
alpha993 122 Posted February 24, 2022 Description.ext class cfgFunctions { #include "myFunctions\THY_functions.hpp" // Include THY_functions.hpp file into cfgFunctions }; myFunctions\THY_functions.hpp class THY_functions // Create a category for your functions { tag = "THY"; // Define the tag that precedes your functions class functions { file = "myFunctions"; // Folder where your functions are located class addingHelmet {}; // One possible function (the game will look for fn_addingHelmet.sqf inside myFunctions folder) class someOtherFunction {}; // Another possible function (the game will look for fn_someOtherFunction.sqf inside myFunctions folder) }; }; myFunctions\fn_addingHelmet.sqf if (!isServer) exitWith {}; // Run only on server params ["_unit", "_radius"]; // Define two parameters: the chosen unit used as the center of the search radius, and the search radius itself while {alive _unit} do // Loop while the chosen unit is alive { _unitsArray = nearestObjects [_unit, ["CAManBase"], _radius]; // Find all soldiers within the set radius around the chosen unit _validUnitsArray = _unitsArray select {(headgear _x != "H_HelmetB") AND (_x != _unit)}; // Select only those soldiers without the desired helmet {removeHeadgear _x; _x addHeadgear "H_HelmetB"} forEach _validUnitsArray; // Add the desired helmet to those soldiers sleep 0.1; }; In your player's init field: [this, 5] spawn THY_fnc_addingHelmet; ____________________________________________ Some comments explaining the above: There are lots of ways you can define your functions, and the one in my example (THY_functions.hpp) is just my preferred method of doing it. More info is available here. In your example, you were declaring your function twice by (1) putting it in the CfgFunctions, and (2) declaring it as an inline function via TAG_fnc_addingHelmet = { code } inside the script file itself. Doing both is unnecessary, as shown in my example. In your example, you set your function's preInit flag to 1. This makes the function run before mission start, and will lead to errors if you do not have the parameters defined, or the function does not have default values for the parameters. Since you are already calling the function through a unit's init field, the preInit is not needed. As for your function itself, your approach will be more performance intensive since you are running a separate script for each unit. In my example, I only run it on the player, and the function then detects nearby soldiers to add a helmet to. In other words, it's better to structure a script around a common element, which in this case is the player, rather than around random elements such as the soldiers. 1 1 Share this post Link to post Share on other sites
thy_ 164 Posted February 24, 2022 @alpha993 thanks for your detailed answer! In your method, when the mission gets started, all units calling the function receive the helmet instantaneously, even when the player is not close. Also, there is an odd condition that makes the "adding helmet" behaviors weird... sometimes working, sometimes not. So to make two changes: // before _validUnitsArray = _unitsArray select {(headgear _x != "H_HelmetB") AND (_x != _unit)}; // now _validUnitsArray = _unitsArray select { headgear _x != "H_HelmetB" }; and // before { removeHeadgear _x; _x addHeadgear "H_HelmetB" } forEach _validUnitsArray; // now { if ( (player distance _x) <= _radius) then { removeHeadGear _x; _x addHeadGear "H_HelmetB"; }; } forEach _validUnitsArray; So the changes are working fine: myFunctions\fn_addingHelmet.sqf if (!isServer) exitWith {}; // private variables declaration... // params declaration... While {alive _unit} do { _unitsArray = nearestObjects [_unit, ["CAManBase"], _radius]; _validUnitsArray = _unitsArray select { headgear _x != "H_HelmetB" }; { if ( (player distance _x) <= _radius) then { sleep 2; removeHeadGear _x; sleep 0.1; _x addHeadGear "H_HelmetB"; hint "Thanks for the helmet!"; sleep 3; hint ""; }; } forEach _validUnitsArray; sleep 1; }; And just letting you know: in that way, with no "static" path declaration, basically the mission cannot find out the "fn_addingHelmet.sqf". I've tried many times, even following the best practices although it only works as an example I've copied from another example. Take a look: myFunctions\THY_functions.hpp class THY_functions { tag = "THY"; class myFunctions { class addingHelmet { file = "myFunctions\fnc_addingHelmet.sqf"; // with static path it works pretty fine! //preInit = 1; }; }; }; Then I have some questions: 0) Dynamic path in THY_functions.hpp looks much better, so if you have a clue what's going on there... 1) What if is we add a default radius number? Just to create a default value but without losing that flexibility to change the radius directly in unit init... 2) What's CAManBase mean? I did not make deep research on it yet. Is it means unit soldiers as "Man" or, even further, "LandVehicles" when do we use it in isKindOf? Share this post Link to post Share on other sites
alpha993 122 Posted February 24, 2022 4 hours ago, thy_ said: In your method, when the mission gets started, all units calling the function receive the helmet instantaneously, even when the player is not close. It works correctly on my end. I'm attaching an example mission for you HERE. _______________ I 4 hours ago, thy_ said: // before _validUnitsArray = _unitsArray select {(headgear _x != "H_HelmetB") AND (_x != _unit)}; // now _validUnitsArray = _unitsArray select { headgear _x != "H_HelmetB" }; The (_x != _unit) condition is important because the nearObjects command includes the player in its output. That condition filters out the player and leaves only the nearby soldiers. Otherwise the player would also have a helmet added. _______________ II 4 hours ago, thy_ said: // before { removeHeadgear _x; _x addHeadgear "H_HelmetB" } forEach _validUnitsArray; // now { if ( (player distance _x) <= _radius) then { removeHeadGear _x; _x addHeadGear "H_HelmetB"; }; } forEach _validUnitsArray; The nearObjects command already selects objects by distance (the defined radius), so adding another distance check when adding the helmet is redundant. _______________ III 4 hours ago, thy_ said: Dynamic path in THY_functions.hpp looks much better, so if you have a clue what's going on there... My example was copied verbatim from a working mission, so my only guess is there is something going on with your paths on your end, or perhaps a typo in a file name. For example, the game is looking for fn_addingHelmet.sqf, and not fnc_addingHelmet.sqf. _______________ IV 4 hours ago, thy_ said: What if is we add a default radius number? Just to create a default value but without losing that flexibility to change the radius directly in unit init... In that case you would not use the Params command, but rather the Param command. You would therefore define your variables like so: _unit = param [0, player, [objNull]]; _radius = param [1, 5, [0]]; This means: _unit is the first parameter passed in the function arguments, with the local player as the default value, and it must be an object. _radius is the second parameter passed in the function arguments, with a default value of 5, and it must be a number. _______________ V 4 hours ago, thy_ said: What's CAManBase mean? I did not make deep research on it yet. Is it means unit soldiers as "Man" or, even further, "LandVehicles" when do we use it in isKindOf? "Man" includes extra things other than actual human entities, such as snakes and rabbits. CAManBase is a step further down the config hierarchy, and only includes human entities. 2 Share this post Link to post Share on other sites
thy_ 164 Posted February 24, 2022 42 minutes ago, alpha993 said: For example, the game is looking for fn_addingHelmet.sqf, and not fnc_addingHelmet.sqf. Fixed. Yep, I missed that "fn" detail. 44 minutes ago, alpha993 said: It works correctly on my end. I'm attaching an example mission for you HERE. Now I got why we're reporting different behavior: I'm setting this... [this, 5] spawn THY_fnc_addingHelmet; ... in each AI unit and not the player as you told me. I missed that piece of your instruction. My bad. Everything works fine now. 51 minutes ago, alpha993 said: In that case you would not use the Params command, but rather the Param command. "Man" includes extra things other than actual human entities, such as snakes and rabbits. CAManBase is a step further down the config hierarchy, and only includes human entities. 😄 Solved! 1 Share this post Link to post Share on other sites
Larrow 2822 Posted March 2, 2022 On 2/24/2022 at 9:55 PM, alpha993 said: In that case you would not use the Params command, but rather the Param command. Why swap to param instead of params? Params can still supply default values. params[ [ "_unit", player, [ objNull ] ], [ "_radius", 5, [ 0 ] ] ]; 2 Share this post Link to post Share on other sites
alpha993 122 Posted March 12, 2022 On 3/1/2022 at 9:05 PM, Larrow said: Why swap to param instead of params? Params can still supply default values. Huh, for some reason I thought Params couldn't supply default values. I even double checked the wiki before writing that and somehow glossed over the relevant syntax parameters section. Share this post Link to post Share on other sites