thirith 27 Posted September 4, 2017 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
Muzzleflash 111 Posted September 4, 2017 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). 1 Share this post Link to post Share on other sites
thirith 27 Posted September 4, 2017 Brilliant, thanks! That's exactly what I need. Share this post Link to post Share on other sites
thirith 27 Posted September 5, 2017 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
pierremgi 4906 Posted September 5, 2017 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. 3 Share this post Link to post Share on other sites
thirith 27 Posted September 5, 2017 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
pierremgi 4906 Posted September 5, 2017 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
jshock 513 Posted September 5, 2017 count (allPlayers select {alive _x && _x inArea thisTrigger}) isEqualTo count allPlayers Could be another way. 1 Share this post Link to post Share on other sites
thirith 27 Posted September 5, 2017 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
das attorney 858 Posted September 5, 2017 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 1 Share this post Link to post Share on other sites
das attorney 858 Posted September 5, 2017 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) 1 Share this post Link to post Share on other sites
thirith 27 Posted September 5, 2017 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
pierremgi 4906 Posted September 5, 2017 {alive _x} count (allPlayers - entities "HeadlessClient_F" ) == {alive _x && _x inArea thisTrigger} count (allPlayers - entities "HeadlessClient_F" ) 1 Share this post Link to post Share on other sites
Muzzleflash 111 Posted September 5, 2017 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
Muzzleflash 111 Posted September 5, 2017 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
Muzzleflash 111 Posted September 5, 2017 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. 1 Share this post Link to post Share on other sites
thirith 27 Posted September 5, 2017 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
Grumpy Old Man 3548 Posted September 5, 2017 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 1 1 Share this post Link to post Share on other sites
das attorney 858 Posted September 5, 2017 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
Muzzleflash 111 Posted September 5, 2017 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) 1 Share this post Link to post Share on other sites
Grumpy Old Man 3548 Posted September 5, 2017 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
Muzzleflash 111 Posted September 5, 2017 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
Grumpy Old Man 3548 Posted September 5, 2017 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
Muzzleflash 111 Posted September 5, 2017 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. 1 Share this post Link to post Share on other sites
pierremgi 4906 Posted September 5, 2017 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