Jump to content
redarmy

Adding Nearest AI to player group

Recommended Posts

I came up with an idea for a scenario that is quite simple: If Player has radio in assigned items,then he is able to activate a radio trigger,and the nearest West / friendly side AI should join his group.

 

So condition looks like so:

 

 Radio trigger Alpha:

 

Condition:  

"ItemRadio" in assignedItems player

 

(the next part is tricky,i know multiple way to make AI join a player group however iv no idea how to go about finding the nearest friendly unit distance wise on map,and having that AI join,as that AI will be dynamically spawned and wont have a variable name)

 

 

On activation should resemble something like this :

 

{side _x == <friendly side>} count nearestObjects join player;

Obviosly the above on activation isnt correct. Iv tried a few different things but i am unable to get it to work

Share this post


Link to post
Share on other sites
10 hours ago, redarmy said:

the nearest West / friendly side AI should join his group.

 

The naive solution would be to just iterate over units BLUFOR and compare distances. To save on perf we can use distanceSqr to compare. Assuming the code runs rarely ( as in not several times per frame ) this should be fine even with a lot of units: 

 

private _nearest = objNull;

private _minDistance = 1e39; // infinity

{

   if ( !isPlayer _x ) then {

        private _d = _x distanceSqr player;

        if( _d < _minDistance ) then {

            _nearest = _x;

            _minDistance = _d;

       };

    };

} forEach units BLUFOR;

 

// _nearest now contains the closest blufor AI

 

[_nearest] joinSilent group player;

  • Like 1

Share this post


Link to post
Share on other sites
3 minutes ago, mrcurry said:

 

The naive solution would be to just iterate over units BLUFOR and compare distances. To save on perf we can use distanceSqr to compare. Assuming the code runs rarely ( as in not several times per second ) this should be fine even with a lot of units: 

 

private _nearest = objNull;

private _minDistance = 1e39; // infinity

{

   if ( !isPlayer _x ) then {

        private _d = _x distanceSqr player;

        if( _d < _minDistance ) then {

            _nearest = _x;

            _minDistance = _d;

       };

    };

} forEach units BLUFOR;

 

// _nearest now contains the closest blufor AI

 

[_neatest] joinSilent group player;

Thank you. theres a typo in nearest last line.

I actually want to make it as simple as is possible.

 

im going to forget about "nearest",and instead complicate condition.  How can i edit this to include any blufor on the map?

 

allunits  join player;

Iv tried various iterations of "allunits side==west" etc and jus am met with syntax errors

 

Share this post


Link to post
Share on other sites
5 minutes ago, redarmy said:

tried various iterations of "allunits side==west" etc and jus am met with syntax errors

 

units side select { !isPlayer _x } joinSilent group player

Share this post


Link to post
Share on other sites
22 minutes ago, mrcurry said:

 

units side select { !isPlayer _x } joinSilent group player

what is "units side select"? iv never seen this before. you mean replace this with what?

 

as is written i just get errors and changing unit side select to allunits gives errors.

 

Im simply trying to change "allunits join player;" to something that replaces allunits with all west units. But every variation i try produces errors in syntax

 

another example of what m trying without success

 

{ 
  if ((side _x) == West) then 
  { 
      joinSilent player 
  }; 
} forEach allUnits;

 

 

Share this post


Link to post
Share on other sites
21 minutes ago, redarmy said:

what is "units side select"? iv never seen this before. you mean replace this with what?

 

as is written i just get errors and changing unit side select to allunits gives errors.

Replace side with BLUFOR or whichever given side you wish to get units for.

  • Thanks 1

Share this post


Link to post
Share on other sites
3 minutes ago, mrcurry said:

Replace side with BLUFOR or whichever given side you wish to get units for.

Ah ok i understand that now. cheers

Share this post


Link to post
Share on other sites
On 10/6/2023 at 3:52 PM, redarmy said:

I came up with an idea for a scenario that is quite simple: If Player has radio in assigned items,then he is able to activate a radio trigger,and the nearest West / friendly side AI should join his group.

 

So condition looks like so:

 

 Radio trigger Alpha:

 

Condition:  


"ItemRadio" in assignedItems player

 

(the next part is tricky,i know multiple way to make AI join a player group however iv no idea how to go about finding the nearest friendly unit distance wise on map,and having that AI join,as that AI will be dynamically spawned and wont have a variable name)

 

 

On activation should resemble something like this :

 


{side _x == <friendly side>} count nearestObjects join player;

Obviosly the above on activation isnt correct. Iv tried a few different things but i am unable to get it to work

 

Alternative to 

 

"ItemRadio" in (assignedItems player)

is

(player getSlotItemName 611) isNotEqualTo ""

which is mod-friendly for non-vanilla radio items

  • Like 1

Share this post


Link to post
Share on other sites
4 hours ago, fn_Quiksilver said:

 

Alternative to 

 


"ItemRadio" in (assignedItems player)

is


(player getSlotItemName 611) isNotEqualTo ""

which is mod-friendly for non-vanilla radio items

Interesting. Can you elaborate? "gearslot" itemname(custom class name?) 611(whats this reference?)

 

Essentially are you saying there are gear slots for NVG's,compass,map etc etc and i can detect them as there or not,modded or vanilla more easily?

Share this post


Link to post
Share on other sites

You could test something like that:

- addAction on player instead of radio A (so there is no addAction if no radio!)
- the addAction opens map (you need a map also in this case)

   while the map is opened, you can click on unit icons (markers) of your side (only), not already in your group. So You can CHOOSE unit type along with its distance.

   if you close the map the action is closed but you can recall it (don't forget to recall if you want to continue recruiting).

 

The code is:


 

MGI_activeMap = FALSE;
MGI_potRecruits = [];
private _EHMap = addMissionEventHandler ["MapSingleClick", {
    params ["_units", "_pos", "_alt", "_shift"];
    if MGI_activeMap then {
        {
            _x params ["_unit","_uPos"];
            if (_pos distance2D _uPos < 10) exitWith {
                if !(_unit in units player or isPlayer _unit) then {
                    [_unit] join player;
                };
                deleteMarkerLocal name _unit;
            };
        } forEach MGI_potRecruits;
    };
}];

player addAction ["recruit",{
    params ["_tgt","_caller","_id","_parms"];
    openMap [TRUE,FALSE];
    MGI_potRecruits = units playerSide - units player;
    private _mkrs = [];
    private "_dot";
    {
        _dot = createMarkerLocal [name _x, getPos _x];
        _dot setMarkerTypeLocal "mil_dot";
        _dot setMarkerColorLocal format ["color%1", str playerSide];
        _dot setMarkerTextLocal typeof _x;
        _mkrs pushBack _dot;
    } forEach MGI_potRecruits;
    MGI_potRecruits = MGI_potRecruits apply {[_x, getPos _x]};
    while {sleep 0.5; visibleMap} do {MGI_activeMap = TRUE};
    MGI_activeMap = FALSE;
    MGI_potRecruits = [];
    {deleteMarkerLocal _x} count _mkrs;
    },nil,1.5,true,true,"",
    "(_this getSlotItemName 611) isNotEqualTo ''"
];

 

 

Share this post


Link to post
Share on other sites
3 hours ago, pierremgi said:

You could test something like that:

- addAction on player instead of radio A (so there is no addAction if no radio!)
- the addAction opens map (you need a map also in this case)

   while the map is opened, you can click on unit icons (markers) of your side (only), not already in your group. So You can CHOOSE unit type along with its distance.

   if you close the map the action is closed but you can recall it (don't forget to recall if you want to continue recruiting).

 

The code is:


 


MGI_activeMap = FALSE;
MGI_potRecruits = [];
private _EHMap = addMissionEventHandler ["MapSingleClick", {
    params ["_units", "_pos", "_alt", "_shift"];
    if MGI_activeMap then {
        {
            _x params ["_unit","_uPos"];
            if (_pos distance2D _uPos < 10) exitWith {
                if !(_unit in units player or isPlayer _unit) then {
                    [_unit] join player;
                };
                deleteMarkerLocal name _unit;
            };
        } forEach MGI_potRecruits;
    };
}];

player addAction ["recruit",{
    params ["_tgt","_caller","_id","_parms"];
    openMap [TRUE,FALSE];
    MGI_potRecruits = units playerSide - units player;
    private _mkrs = [];
    private "_dot";
    {
        _dot = createMarkerLocal [name _x, getPos _x];
        _dot setMarkerTypeLocal "mil_dot";
        _dot setMarkerColorLocal format ["color%1", str playerSide];
        _dot setMarkerTextLocal typeof _x;
        _mkrs pushBack _dot;
    } forEach MGI_potRecruits;
    MGI_potRecruits = MGI_potRecruits apply {[_x, getPos _x]};
    while {sleep 0.5; visibleMap} do {MGI_activeMap = TRUE};
    MGI_activeMap = FALSE;
    MGI_potRecruits = [];
    {deleteMarkerLocal _x} count _mkrs;
    },nil,1.5,true,true,"",
    "(_this getSlotItemName 611) isNotEqualTo ''"
];

 

 

This is actually very cool indeed. Originally i was just looking to quickly recruit one blufor anywhere on map as only one or two get created at a time,however iv modified things and this will be pretty cool,gona try it out.

 

Cheers man!

Share this post


Link to post
Share on other sites
On 10/8/2023 at 2:46 PM, redarmy said:

Interesting. Can you elaborate? "gearslot" itemname(custom class name?) 611(whats this reference?)

 

Essentially are you saying there are gear slots for NVG's,compass,map etc etc and i can detect them as there or not,modded or vanilla more easily?

 

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

 

There are hardcoded slot numbers

 

603 - Goggles

605 - Headgear

608 - Map

609 - Compass

610 - Watch

611 - Radio

612 - GPS

616 - HMD

617 - Binoculars

701 - Vest

801 - Uniform

901 - Backpack

 

So if you are trying to determine if the player has a radio (vanilla or modded), you just do

 

(player getSlotItemName 611) isNotEqualTo ""     // the player has a radio of some sort

 

since it will return "" if there is nothing in the radio slot

Share this post


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

 

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

 

There are hardcoded slot numbers

 

603 - Goggles

605 - Headgear

608 - Map

609 - Compass

610 - Watch

611 - Radio

612 - GPS

616 - HMD

617 - Binoculars

701 - Vest

801 - Uniform

901 - Backpack

 

So if you are trying to determine if the player has a radio (vanilla or modded), you just do

 

(player getSlotItemName 611) isNotEqualTo ""     // the player has a radio of some sort

 

since it will return "" if there is nothing in the radio slot

I had no idea about the slot numbers,thats useful.

Actually i was trying to replicate the DAYZ mechanic,where when shot in say the backpack,items in there can get ruined. Since arma3 has no item state,i would just remove a random item.

 

Could i use that syntax above to make a randm array of sorts,that if player took damage,to randomly remove one of those slot numbers,and if slot number was 901, 801,or701,to then choose a random item from backpack/vest/uniform and remove it?

 

Im sure theres probably an easier way just wondering.

 

As an example i currently use this to randomly remove vest with a 10% chance if hit in "pelvis"

 

player addEventHandler ["HitPart", 
{ 
 (_this select 0) params ["_unit", "_shooter", "_bullet", "_pos", "_vel", "_hitLoc"]; 
 if ((vest _unit) != "") then 
 { 
  { 
   if (_x == "pelvis"   && 10 > random 100) then 
   { 
    removeVest _unit; 
   }; 
  } forEach _hitLoc; 
 }; 

 

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

×