Matthew10_28 4 Posted July 23, 2016 Background Context: I have a group of semi-random enemy at a location on the map. They are divided in to groups and teams with some doing random patrols via 3den enhanced, and others defending via the CBA defend module. Each groups probability of presence is controlled such that each experience will be unique and different for multiplayer. The intent is to have a site to raid that is different each time but also authentically populated and controlled. The intent is to populate the map with many sites like this that the user can selectively activate and attack. The units are hidden via hideObjectsGlobal true and enableSimulation false upon creation so as to not necessarily burden the server and to keep those areas of the map safe and explore-able should the user choose to. The Code Problem(s): I have an addAction on an objecet a player approaches and then activates the bad guys at the raid site but it seems unnecessarily cumbersome. The addAction just serves to switch hideObjectsGlobal to false and enableSimulation to true. First, I don't know of a way to "group" or "collect" all of the objects at a site so that I could just do something like: this addAction ["Spawn All The Things!",{CollcetionOfStuff hideObjectGlobal false, CollcetionOfStuff enablesimulation true}]; Then I though I would just call upon the various group variable ID's as there are "only" 9 to 11 groups (per raid site). It spit an error saying and object was expected for hideObjectsGlobal and it needs a unit. Then I tried creating an array of the individual unit variable names (that I had to go define for all 20ish units) and passing that through hideObjectsGlobal, but it squawked at the array too. Now I'm left with and excel spreadsheet that generates the gigantic addAction code I need based on my typing in every single units variable name. I end up with this monstrosity below. I had to add the conditional ifNil part since its possible that a unit won't even be created to begin with based on the probability of presence. I works as intended and has the desired effect but, there has got to be an easier way to do this. I want to generate groups like this all over the map and have the user scroll through the addAction menu to activate the desired site the player wants to raid. This is going to get ugly if I have to individually assign variable names to everyone at each raid site. this addAction ["Spawn Raid Site",{if (isNil "HVT1") then {} else {HVT1 hideObjectGlobal false, HVT1 enableSimulation true}, if (isNil "HVT2") then {} else {HVT2 hideObjectGlobal false, HVT2 enableSimulation true}, if (isNil "Garrison1Leader") then {} else {Garrison1Leader hideObjectGlobal false, Garrison1Leader enableSimulation true}, if (isNil "Garrison1_1") then {} else {Garrison1_1 hideObjectGlobal false, Garrison1_1 enableSimulation true}, if (isNil "Garrison2Leader") then {} else {Garrison2Leader hideObjectGlobal false, Garrison2Leader enableSimulation true}, if (isNil "Garrison2_1") then {} else {Garrison2_1 hideObjectGlobal false, Garrison2_1 enableSimulation true}, if (isNil "Garrison2_2") then {} else {Garrison2_2 hideObjectGlobal false, Garrison2_2 enableSimulation true}, if (isNil "Garrison2_3") then {} else {Garrison2_3 hideObjectGlobal false, Garrison2_3 enableSimulation true}, if (isNil "Patrol1Leader") then {} else {Patrol1Leader hideObjectGlobal false, Patrol1Leader enableSimulation true}, if (isNil "Patrol1_1") then {} else {Patrol1_1 hideObjectGlobal false, Patrol1_1 enableSimulation true}, if (isNil "Patrol2Leader") then {} else {Patrol2Leader hideObjectGlobal false, Patrol2Leader enableSimulation true}, if (isNil "Patrol2_1") then {} else {Patrol2_1 hideObjectGlobal false, Patrol2_1 enableSimulation true}, if (isNil "Patrol2_2") then {} else {Patrol2_2 hideObjectGlobal false, Patrol2_2 enableSimulation true}, if (isNil "Patrol3Leader") then {} else {Patrol3Leader hideObjectGlobal false, Patrol3Leader enableSimulation true}, if (isNil "Patrol3_1") then {} else {Patrol3_1 hideObjectGlobal false, Patrol3_1 enableSimulation true}, if (isNil "Patrol4Leader") then {} else {Patrol4Leader hideObjectGlobal false, Patrol4Leader enableSimulation true}, if (isNil "Patrol4_1") then {} else {Patrol4_1 hideObjectGlobal false, Patrol4_1 enableSimulation true}, if (isNil "Patrol5eader") then {} else {Patrol5Leader hideObjectGlobal false, Patrol5Leader enableSimulation true}, if (isNil "Patrol5_1") then {} else {Patrol5_1 hideObjectGlobal false, Patrol5_1 enableSimulation true}}]; Share this post Link to post Share on other sites
theend3r 83 Posted July 23, 2016 This is going to get ugly if I have to individually assign variable names to everyone at each raid site. You could make a trigger that would collect all the units in the trigger area and put them in an array (or you could even name them with setVehicleVarName), e.g.: //put in on-actiavtion of a trigger that has east present as a condition area1 = []; {area1 pushBack _x} forEach thisList; and then do this addAction ["Spawn Raid Site",{if (isNil _x) then {} else {_x hideObjectGlobal false, _x enableSimulation true} forEach area1}]; Still, wouldn't it be better to spawn / despawn the locations depending on player distance and not actions? Simulation manager module can do all that automatically and even allow air units. The only problem is that there is no documentation that I know of. Share this post Link to post Share on other sites
Matthew10_28 4 Posted July 23, 2016 You could make a trigger that would collect all the units in the trigger area and put them in an array (or you could even name them with setVehicleVarName), e.g.: //put in on-actiavtion of a trigger that has east present as a condition area1 = []; {area1 pushBack _x} forEach thisList; and then do this addAction ["Spawn Raid Site",{if (isNil _x) then {} else {_x hideObjectGlobal false, _x enableSimulation true} forEach area1}]; Still, wouldn't it be better to spawn / despawn the locations depending on player distance and not actions? I like the idea of letting an area definition grab everything in it, but doesn't that necessitate that I would have to maintain sufficient physical separation of these raid sites? In other words if I placed down guys around a group of houses for raid site they could, in theory, blend in with units from another nearby raid site. I've already spotted points on the map where raid site 1 has patrols that may physically intersect with another raid site with the intent being only 1 is active at a time, at least local to that area. Is there a way to sync or group all the units from 1 Raid site into a single thing like a logical and just call the logical Also, I discovered forEach loops. I managed to condense my original code but now it balks at the isNil statement. It says it expects a string. this addAction ["Spawn Raid Site",{_RaidGroup1 = [HVT1, HVT2, Garrison1Leader, Garrison1_1, Garrison2Leader, Garrison2_1, Garrison2_2, Garrison2_3, Patrol1Leader, Patrol1_1, Patrol2Leader, Patrol2_1, Patrol2_2, Patrol3Leader, Patrol3_1, Patrol4Leader, Patrol4_1, Patrol5Leader, Patrol5_1]; for [{_i=0}, {_i < count _RaidGroup1}, {_i=_i+1}] do {if(isNil (_RaidGroup select _i)) then {} else{(_RaidGroup1 select _i) hideObjectGlobal false; (_RaidGroup1 select _i) enableSimulation true;} }}]; and it likes this of course, but then the player will get a black box error that kind of gives away the first unit that didn't spawn because of probability. Kinda spoils it. this addAction ["Spawn Raid Site",{_RaidGroup1 = [HVT1, HVT2, Garrison1Leader, Garrison1_1, Garrison2Leader, Garrison2_1, Garrison2_2, Garrison2_3, Patrol1Leader, Patrol1_1, Patrol2Leader, Patrol2_1, Patrol2_2, Patrol3Leader, Patrol3_1, Patrol4Leader, Patrol4_1, Patrol5Leader, Patrol5_1]; for [{_i=0}, {_i < count _RaidGroup1}, {_i=_i+1}] do { (_RaidGroup1 select _i) hideObjectGlobal false; (_RaidGroup1 select _i) enableSimulation true; }}]; Share this post Link to post Share on other sites
theend3r 83 Posted July 23, 2016 Try isNil str(_x) Edit: Yup, that should work. Also... Is there a way to sync or group all the units from 1 Raid site into a single thing like a logical and just call the logical The best way would be to simply spawn everything with a script (_group = createGroup east; _unit1 = _group createUnit ["some_class_name", [0,0,0], [], 0, "FORM"]; ...etc.) and store their names. It's a pain to create waypoints with a script but static waypoints aren't a good solution anyway. Something like the UPS script is way better and can be called by a single command. Share this post Link to post Share on other sites
SilentSpike 84 Posted July 23, 2016 isNil expected either string or code, so, you'd use: isNil {_RaidGroup select _i} in your example Share this post Link to post Share on other sites
SilentSpike 84 Posted July 23, 2016 The other option if you definitely want to be so explicit is to convert your array into strings: _units = ["Unit1","Unit2","Unit3", etc. ]; _units = _units apply { if !(isNil _x) then {missionNamespace getVariable _x} }; { _x hideObjectGlobal false; _x enableSimulation true; } forEach _units; Share this post Link to post Share on other sites
Matthew10_28 4 Posted July 23, 2016 Still, wouldn't it be better to spawn / despawn the locations depending on player distance and not actions? Simulation manager module can do all that automatically and even allow air units. The only problem is that there is no documentation that I know of. Distance triggers aren't ideal in this case. There might be a raid site the player(s) want to play, but they don't wan't to consider adjacent bad guys getting in the way in their infil or exfil. I don't want to force the player(s) to clear out multiple raid sites just to get to the one site they were really interested in. There are also completely separate missions on the maps too (or one day will be). Try isNil str(_x) Edit: Yup, that should work. Also... The best way would be to simply spawn everything with a script (_group = createGroup east; _unit1 = _group createUnit ["some_class_name", [0,0,0], [], 0, "FORM"]; ...etc.) and store their names. It's a pain to create waypoints with a script but static waypoints aren't a good solution anyway. Something like the UPS script is way better and can be called by a single command. I tried that and it said "unexpected variable" of my low probability HVT2 since it only exists in the first place 15% of the time. I looked at the script option via USPS (ultra simple patrol script) and it didn't fully perform the functions I needed it to like actually garrison intelligently. Also, creating the other raid sites is not just a copy/paste around a new group of buildings. There are minor placement adjustments of the enemy patrols to suit the terrain. isNil expected either string or code, so, you'd use: isNil {_RaidGroup select _i} in your example It didn't like this either. Same as the str() option. It said "unexpected variable" of my low probability HVT2 since it only exists in the first place 15% of the time. I'm learning so much from all of this. I think I may end up using the "area gathering" methodology suggested and and explicit route for when the sites overlap. Or just convince myself to only pick sites that don't physically overlap. Share this post Link to post Share on other sites
theend3r 83 Posted July 23, 2016 It didn't like this either. Same as the str() option. It said "unexpected variable" of my low probability HVT2 since it only exists in the first place 15% of the time. I'm learning so much from all of this. I think I may end up using the "area gathering" methodology suggested and and explicit route for when the sites overlap. Or just convince myself to only pick sites that don't physically overlap. isNil compile format ["'%1'", _x] is sure to work with forEach. Share this post Link to post Share on other sites
Matthew10_28 4 Posted July 23, 2016 You could make a trigger that would collect all the units in the trigger area and put them in an array (or you could even name them with setVehicleVarName), e.g.: //put in on-actiavtion of a trigger that has east present as a condition area1 = []; {area1 pushBack _x} forEach thisList; and then do this addAction ["Spawn Raid Site",{if (isNil _x) then {} else {_x hideObjectGlobal false, _x enableSimulation true} forEach area1}]; I put a big circular trigger around the raid site and I put exactly that code in the On-Activation box that has Independent present as a condition (I'm using the new FIA Bandits to populate my raid site) I used that addAction code, but it says "unexpected variable in expression: _x" Share this post Link to post Share on other sites
theend3r 83 Posted July 23, 2016 Yeah, sorry, it's missing {}. player addAction ["Spawn Raid Site",{{if (isNil compile format ["'%1'", _x]) then {} else {_x hideObjectGlobal false, _x enableSimulation true}} forEach area1}]; Share this post Link to post Share on other sites
Matthew10_28 4 Posted July 23, 2016 Yeah, sorry, it's missing {}. player addAction ["Spawn Raid Site",{{if (isNil compile format ["'%1'", _x]) then {} else {_x hideObjectGlobal false, _x enableSimulation true}} forEach area1}]; It worked. Thank you. But I must not be fully understanding why that format is so picky. The hideObjectGlobal and enableSimulation expects one type of data, but the isNil expects another? Hence, all these suggested methods of changing them? Now I should be able to just copy down my bad guy composition to another sites, create area2, area3, etc, then add more addAction options for each raid site. Now I see why the "area gathering" suggestion is so powerful. I shouldn't have to individually assign variable names to the units right? In much the same way I created the bad guys, now my intent is to create objects like empty parked vehicles, furniture and similar objects in buildings, and barriers on roads. It will be the extra "unknown" site variable. This method should grab those too as I understand it. MUCH better then assigning a variable name to each pen or pencil I place on a desk. Share this post Link to post Share on other sites
theend3r 83 Posted July 23, 2016 Triggers won't detect empty vehicles / objects unless they're grouped to them. I don't think static objects create much lag so I'd just ignore them but if you really want to hide them then you'd need to use the nearestObjects command and, again, it's not completely trivial. Share this post Link to post Share on other sites
Matthew10_28 4 Posted July 24, 2016 Triggers won't detect empty vehicles / objects unless they're grouped to them. I don't think static objects create much lag so I'd just ignore them but if you really want to hide them then you'd need to use the nearestObjects command and, again, it's not completely trivial. Bummer. Empty vehicles and objects like desks are treated the same in this set up? If nearestObjects picks up the empty vehicles and desks, then it's just a matter of using a separate trigger meant to just collect those and calling that in parallel with the units in the addAction. It looks like nearestObjects picks up everything, including things baked into the map, but since I'm only using it to flip the hideGlobalObjects off and to enableSimulation, it's not like I'd have to filter the stuff already on the map right? Sure, it will find EVERYTHING but since every item it finds is already "on" it should only turn on the stuff I add right? Otherwise, I have to get creative with wildcard searches for the class names listed here? Share this post Link to post Share on other sites
theend3r 83 Posted July 24, 2016 You could get a list of map objects' classnames by running this on a trigger in an empty mission: mapObjects = []; {mapObjects pushBackUnique (typeOf _x)} forEach nearestObjects [getpos trigger1, [], 500]; //or some other radius copyToClipboard str mapObjects; and then remove them from the nearestObjects result mapObjects = [*the array you got before*]; allObjects = nearestObjects [getpos trigger2, [], 500]; emptyVehicles = allObjects select {!(typeOf _x in mapObjects)}; but it may return things like mosquitoes, too. :D I'm sure there are better solutions (like not trying something like this at all). Share this post Link to post Share on other sites
Matthew10_28 4 Posted July 24, 2016 Well, my theory of grabbing everything and turning everything on works. RaidSite079124ObjectList = nearestObjects [HVT1, [], 200]; {_x hideObjectGlobal false, _x enableSimulation true} forEach RaidSite079124ObjectList; But now its not playing nice when I try to run it in parallel with the existing code in my addAction. I just learned _x is some sort of magic variable so maybe it doesn't play nice since my existing code uses that as well. This works when it's two seperate addActions... this addAction ["Spawn Raid Site @ 079124",{{if (isNil compile format ["'%1'", _x]) then {} else {_x hideObjectGlobal false, _x enableSimulation true}} forEach RaidArea079124; }]; this addAction ["Spawn Raid Objects",{RaidSite079124ObjectList = nearestObjects [HVT1, [], 200]; {_x hideObjectGlobal false, _x enableSimulation true} forEach RaidSite079124ObjectList}]; But this doesn't... this addAction ["Spawn Raid Site @ 079124",{{if (isNil compile format ["'%1'", _x]) then {} else {_x hideObjectGlobal false, _x enableSimulation true}} forEach RaidArea079124; {RaidSite079124ObjectList = nearestObjects [HVT1, [], 200]; {_x hideObjectGlobal false, _x enableSimulation true} forEach RaidSite079124ObjectList}} ]; ETA: Thinking it can't handle the double use of the magic variable _x I tried this but it spits and undefined varialbe for RaidSite079124ObjectList this addAction ["Spawn Raid Site @ 079124",{{if (isNil compile format ["'%1'", _x]) then {} else {RaidSite079124ObjectList = nearestObjects [HVT1, [], 200], _x hideObjectGlobal false, _x enableSimulation true}} forEach (RaidArea079124 + RaidSite079124ObjectList); }]; ETA 2: So moving that definition call prior to the addAction works, but I'm not entirely convinced why it can't work inside of it. RaidSite079124ObjectList = nearestObjects [HVT1, [], 200]; this addAction ["Spawn Raid Site @ 079124",{{if (isNil compile format ["'%1'", _x]) then {} else {_x hideObjectGlobal false, _x enableSimulation true}} forEach (RaidArea079124 + RaidSite079124ObjectList); }]; Share this post Link to post Share on other sites