Jump to content
thirith

How to check that all players are in trigger area?

Recommended Posts

I'm currently working on a coop mission that has up to six individual soldiers (i.e. not grouped) stuck in a city under siege and a Hummingbird with a pilot and co-pilot whose task is to rescue the survivors. In practice, the idea is that only the units that are actually played spawn, and the win condition is for all surviving units to return to base.

 

Thing is, I'm not sure how to script this, due to the fact that not all of the available units might be spawned and some of the player units might be dead. How can I check that all players are in an area? Is it as easy as syncing all potential player units to the trigger, and the game takes care of any units that either haven't been spawned or are dead?

Share this post


Link to post
Share on other sites

Put this in the condition field of the trigger:

thisTrigger call {
  private _alivePlayers = allPlayers select {alive _x};
  private _inArea = _alivePlayers count {vehicle _x inArea _this};
  _inArea > 0 && _inArea == (count _alivePlayers)
}

I would not use any synchronization if you plan to support joining-in-progress (synchronization is broken in that regard).

  • Like 1

Share this post


Link to post
Share on other sites

I've just tried the code, and it generates a generic error. The first and second lines are okay, so it's something to do with the following lines. Will have to revisit when I get back from work, but I just wanted to post this in case you see what the problem is.

 

Edit: I've had a quick look around for others with similar errors, and I found one case where it had something to do with grouped units. In this case, perhaps I need to mention that the pilot and co-pilot are grouped together, while the six survivors that need to be rescued aren't.

Share this post


Link to post
Share on other sites

simple:

{alive _x} count allPlayers == {alive _x && _x inArea thisTrigger} count allPlayers

 

You don't have to check for player(s) in vehicle(s) or not.

  • Like 3

Share this post


Link to post
Share on other sites

Cool, I'll try that when I get home. Any idea why the script posted earlier produces a generic error?

 

Edit: While I'm at it, is there some good resource on how to read Arma's error messages?

Share this post


Link to post
Share on other sites
10 minutes ago, thirith said:

Cool, I'll try that when I get home. Any idea why the script posted earlier produces a generic error?

 

Edit: While I'm at it, is there some good resource on how to read Arma's error messages?

Count and select haven't the same syntax. The count one seems false (should be: condition count array)

For error message, I'm like you. I read the rpt file. Sometimes there is some weird msg (not understandable for me) like "wrong color format" which doesn't help, but it's more often useful.

Share this post


Link to post
Share on other sites

count (allPlayers select {alive _x && _x inArea thisTrigger}) isEqualTo count allPlayers

 

Could be another way.

  • Like 1

Share this post


Link to post
Share on other sites

Quick question about this: I've usually got a Headless client running. Does this interfere with the player count? And can spectator scripts screw things up? (I would assume that spectators don't register as players, but it's not like I know how they work.)

Share this post


Link to post
Share on other sites
2 minutes ago, thirith said:

Quick question about this: I've usually got a Headless client running. Does this interfere with the player count? And can spectator scripts screw things up? (I would assume that spectators don't register as players, but it's not like I know how they work.)

 

 

Yes, read the description on the wiki:

 

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

  • Like 1

Share this post


Link to post
Share on other sites

It might be worth going for playableUnits instead of allPlayers (no dead units are reported, and neither are HC's)

 

You have to account for playable units occupied by AI, but if you have disabled AI playable units, then it is a non-issue

 

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

 

or just do the (allPlayers - entities "HeadlessClient_F") thing.  As you say though, it might pick up spectators - (not sure about players lurking in the lobby while they 420 blaze joints and drink mountain dew either)

  • Haha 1

Share this post


Link to post
Share on other sites

Thanks, good to know. Does a HC register as alive, though, i.e. would pierremgi's script work?

Share this post


Link to post
Share on other sites

{alive _x} count (allPlayers -  entities "HeadlessClient_F" ) == {alive _x && _x inArea thisTrigger} count (allPlayers - entities "HeadlessClient_F" )

  • Like 1

Share this post


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

{alive _x} count allPlayers == {alive _x && _x inArea thisTrigger} count allPlayers

That will trigger prematurely if you play with respawn and all are currently dead. Same with your latest.

5 hours ago, jshock said:

count (allPlayers select {alive _x && _x inArea thisTrigger}) isEqualTo count allPlayers

This will never work if even a single player is dead.

 

Here is my updated version. I also ran it this time:

thisTrigger call { 
  private _alivePlayers = (allPlayers select {alive _x}) - entities "HeadlessClient_F"; 
  private _inArea = {vehicle _x inArea _this} count _alivePlayers; 
  _inArea > 0 && _inArea == (count _alivePlayers) 
}

 

Share this post


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

You don't have to check for player(s) in vehicle(s) or not.

Could have sworn you used to have to do this, or maybe in was in another context. Good to know you don't have to anymore. I still left it in mine since I think it conveys the intent better (but again I'm "damaged" from previous experiences).

Share this post


Link to post
Share on other sites
5 hours ago, das attorney said:

It might be worth going for playableUnits instead of allPlayers (no dead units are reported, and neither are HC's)

That doesn't work in SP (my interpretation of coop allows for one player). Of course you can workaround this, but then, with also the additional code, e.g. filtering for isPlayer and so on, the command might not be worth it.

  • Like 1

Share this post


Link to post
Share on other sites

For the record, I'm not planning to allow respawning in this mission, so this doesn't have to be taken into consideration. Similarly, one player won't work for this mission, as the idea is to have at least one evac helicopter and at least one survivor.

Share this post


Link to post
Share on other sites

 

Tested with 50 units inside trigger, 50 units outside trigger and using allUnits instead allPlayers to add some workload:

Result:
0.16675 ms

Cycles:
5997/10000

Code:
triggerName call {  
  private _alivePlayers = (allUnits select {alive _x}) - entities "HeadlessClient_F";  
  private _inArea = {vehicle _x inArea _this} count _alivePlayers;  
  _inArea > 0 && _inArea == (count _alivePlayers)  
}
/*-------------------*/
Result:
0.187161 ms

Cycles:
5343/10000

Code:
 
{alive _x} count (allUnits -  entities "HeadlessClient_F" ) == {alive _x && _x inArea triggerName} count (allUnits - entities "HeadlessClient_F" ) 

 

Modified both versions with lazy evaluation:

Result:
0.163026 ms

Cycles:
6134/10000

Code:
triggerName call {  
  private _alivePlayers = (allUnits select {alive _x}) - entities "HeadlessClient_F";  
  private _inArea = {vehicle _x inArea _this} count _alivePlayers;  
  _inArea > 0 && {_inArea == (count _alivePlayers)}  
}
/*---------------------*/
Result:
0.205761 ms

Cycles:
4860/10000

Code:
{alive _x} count (allUnits -  entities "HeadlessClient_F" ) == {alive _x && {_x inArea triggerName}} count (allUnits - entities "HeadlessClient_F" )

Interestingly @pierremgis approach has worse performance when using lazy evaluation, first time I'm seeing this, weird.

In both cases performance can be neglected since both approaches are pretty fast and close to each other in terms of speed.

 

Cheers

 

  • Like 1
  • Thanks 1

Share this post


Link to post
Share on other sites
16 minutes ago, Muzzleflash said:

That doesn't work in SP (my interpretation of coop allows for one player). Of course you can workaround this, but then, with also the additional code, e.g. filtering for isPlayer and so on, the command might not be worth it.

 

Yes that's true, I don't really do SP much so didn't think of it.  Could do (playableUnits + switchableUnits) to make it work in MP and SP.

Share this post


Link to post
Share on other sites
13 minutes ago, Grumpy Old Man said:

Tested with 50 units inside trigger, 50 units outside trigger and using allUnits instead allPlayers to add some workload

I don't understand, how did you test it? Is triggerName unique for each of the 50? Might be useful to also test whether ANY PLAYER PRESENT gives a list, and whether that can be used instead of manual inArea checks.

 

But regardless, this is gross microoptimisation, for something you need only 1 of, runs only 2 times per second, with at most 6 units (at least in my case). Also what is lazy evaluation? You mean short-circuiting for && and || ? If so, you might try and swap the order in Pierre's since, the  alive check will often be true, but the inArea false, so you are short circuiting the "reverse" way. (Also add the > 0 check in both, or remove it in both, otherwise you are not comparing the same behavior)

  • Like 1

Share this post


Link to post
Share on other sites
16 minutes ago, Muzzleflash said:

I don't understand, how did you test it? Is triggerName unique for each of the 50? Might be useful to also test whether ANY PLAYER PRESENT gives a list, and whether that can be used instead of manual inArea checks.

 

But regardless, this is gross microoptimisation, for something you need only 1 of, runs only 2 times per second, with at most 6 units (at least in my case). Also what is lazy evaluation? You mean short-circuiting for && and || ? If so, you might try and swap the order in Pierre's since, the  alive check will often be true, but the inArea false, so you are short circuiting the "reverse" way. (Also add the > 0 check in both, or remove it in both, otherwise you are not comparing the same behavior)

 

Good points.

triggerName is the variable name of the trigger.

Any player in the trigger setting gives all players inside the trigger in the "thisList" variable.

Doing something as simple as:

count thisList isEqualTo count allPlayers//0.001ms

would do the trick if the triggers are set up correctly.

 

Isn't lazy evaluation fastest when the first statement is true?

It wouldn't need to evaluate the statements within if the first one is true anyway, having a statement which would return false most of the time would actually slow down the evaluation.

Having alive _x in first place would be the optimum solution since units will be alive most time during the mission, at least that's how it's explained in the wiki.

Just tested this:

Result:
0.0008 ms

Cycles:
10000/10000

Code:
false OR {true} OR {true}
/*--------------*/
Result:
0.0006 ms

Cycles:
10000/10000

Code:
true OR {false} OR {false}

Cheers

Share this post


Link to post
Share on other sites
9 minutes ago, Grumpy Old Man said:

Isn't lazy evaluation fastest when the first statement is true?

Only for an OR (||). We are using AND (&&). Think about, this is the logic tables:

 

For OR:

FALSE OR {FALSE} -->  FALSE

FALSE OR {TRUE}  --> TRUE

TRUE OR {FALSE} --> TRUE

TRUE OR {TRUE} --> TRUE

 

When one the values is true, the other does not matter anymore, we know the final result. So we can skip evaluating the right side.

 

For AND:

FALSE AND {FALSE} --> FALSE

FALSE AND {TRUE} --> FALSE

TRUE AND {FALSE} --> FALSE

TRUE AND {TRUE} --> TRUE

 

Again, when we know the first is false, the other does not matter anymore. So we can skip it.

 

In our case we use AND, and we know that  'alive _x' is likely to be true, and that '_x inArea ...' is likely to be false. So by putting the inArea check first (for an AND/&&), we can skip the other evaluation more often.

 

See:

https://community.bistudio.com/wiki/a_%26%26_b

and

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

 

Edit:

I should add: for OP, players are not likely to be in the extraction zone very often, and will likely be alive most of the time.But for your synthetic test, the assumptions about what likely true or false depend on your setup.

Share this post


Link to post
Share on other sites

You're right, with AND comparison it's the other way around:

Result:
0.0008 ms

Cycles:
10000/10000

Code:
true AND {false} AND {false}
/*--------------------*/
Result:
0.0005 ms

Cycles:
10000/10000

Code:
false AND {true} AND {true}

Well, the more you know...

Thanks for pointing that out!

 

Swapping the order of conditions in pierres example didn't do much for some reason though:

Result:
0.21245 ms

Cycles:
4707/10000

Code:
{alive _x} count (allUnits -  entities "HeadlessClient_F" ) == {_x inArea triggerName && {alive _x}} count (allUnits - entities "HeadlessClient_F" )

 

Cheers

 

Share this post


Link to post
Share on other sites
10 minutes ago, Grumpy Old Man said:

Swapping the order of conditions in pierres example didn't do much for some reason though

See edit made in previous post, near bottom. Could be because how the test is structured: try with all units out of the area. Or it could simply be how it is.

  • Like 1

Share this post


Link to post
Share on other sites

I wake up. Good mornig all

{alive _x} count (allPlayers -  entities "HeadlessClient_F" ) isEqualTo {alive _x && _x inArea thisTrigger} count (allPlayers - entities "HeadlessClient_F" )  && ({alive _x} count allPlayers) > 0

should do the trick for SP/MP respawn on start or not.

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

×