Jump to content
Sign in to follow this  
Harzach

Adding a condition to a forEach system

Recommended Posts

Hi all -

I'm trying to add a condition to a forEach system and just can't figure it out.

Here's an abstract of the system:

{_pos = [random position code];
x setPos _pos;
} forEach _array;

What this does is move multiple objects to random positions. This all works perfectly. What I want to do is check if _pos is outside a certain area using:

if (_pos distance (getMarkerPos "exclude") > 2000) then

so that any _pos falling inside that area gets re-processed. End result, all objects are placed somewhere on the map, outside that area. I've tried a few things, but I can't seem to get it to work properly. Perhaps I am going about it the wrong way?

I hope that's all clear, thanks for any insight!

Share this post


Link to post
Share on other sites

Why don't you just limit the random to 2000 in the first place so it can never be outside the area?

you could use a while if you want to do it your way something like this may work.

{
_checking = false;

while {!_checking} do {

_pos = [random position code];

if (_pos distance (getMarkerPos "exclude") < 2000) then { _checking = true};

};

_x setPos _pos;
} forEach _array;

Edited by F2k Sel

Share this post


Link to post
Share on other sites
Why don't you just limit the random to 2000 in the first place so it can never be outside the area?

Because that's the exact opposite of what I want. As I suspected, I wasn't clear enough.

you could use a while if you want to do it your way something like this may work.

{
_checking = false;

while {!_checking} do {

_pos = [random position code];

if (_pos distance (getMarkerPos "exclude") < 2000) then { _checking = true};

};

_x setPos _pos;
} forEach _array;

I tried a while loop before, but I'm sure I did it incorrectly - I'll give this a shot. Thanks for the reply!

Share this post


Link to post
Share on other sites

While F2k Sel's code is correct and would give you the result you're looking for, I'd like to suggest a slight change to his code:

_pos = [];
_excludeArea = getMarkerPos "exclude";
{
   while {_pos = [random position code]; _pos distance _excludeArea < 2000} do {};
   _x setPos _pos;
} forEach _array; 

This should be a (little) bit more efficient and less code to write :D

Yeah I know, I don't contribute to actually solving your problem but showing people alternative ways to code is also nice :)

The random placement could reach the maximum efficiency when you'd use a circle area with its center equal to the exlude area to spawn your objects/units within.

Then you could easily use trig functions and break down the complexity of the function by the factor of O(m) (while m being regulated by the mapsize), which could save some milliseconds when placing a huge list of units/objects.

This is also nothin you'd concern yourself when placing a handful of units but it could make a difference when time (and efficiency) is critical to your requirements.

Share this post


Link to post
Share on other sites

Cool, thanks! Efficiency isn't an issue in this case, as it's only a handful of objects, but it's always good to see different solutions to a problem.

And I'm still not making myself totally understood on the "excluded area" thing ... :D

Share this post


Link to post
Share on other sites

Well as far as I understood the "excluded area", its actually an area in the random locations area which should not be used to spawn stuff into.

http://oi48.tinypic.com/15nlhqd.jpg (260 kB)

This is an example using a map, is this how you imagined it to be?

I just ask this despite the original topic is being solved because if we happen to misunderstand you, the examples above won't work the way they should.

Share this post


Link to post
Share on other sites

No, you got it right, I just misread your post.

Everything is working great, and I understand this stuff more and more every day thanks to folks like you two!

Share this post


Link to post
Share on other sites

Arg. While everything is working perfectly in editor preview and hosted server, it doesn't seem to work on a dedi server.

I added a hint in a few places for an audible check on what is or isn't happening:

//HINT 1 HERE;

{
_checking = false;

while {!_checking} do {

//HINT 2 HERE;

_pos = [random position code];

if (_pos distance (getMarkerPos "exclude") < 2000) then { _checking = true};

};

_x setPos _pos;

//HINT 3 HERE;

} forEach _array;  

Enabling only one hint at a time, of course:

  • HINT 1 produces a single hint chime, telling me that the script is getting called correctly.
  • HINT 2 produces a hint chime in an endless loop, suggesting that no valid positions are being generated. This may have something to do with the code here, more on that in a second.
  • HINT 3 produces no hint chime, reinforcing what we learned from HINT 2.

The actual random position code uses Shuko's random position script - SHK_pos. The full code is as follows:

{
_checking = false;
while {!_checking} do {
_pos = [getMarkerPos "center", random 10000, random 359, false, [1, 5000]] call SHK_pos;
if ((_pos distance (getMarkerPos "exclude_1") > 1500) && (_pos distance (getMarkerPos "exclude_2") > 500)) then { _checking = true};
};
_x setPos _pos;

//DEBUG MARKERS
_name = str(_x) + str(random 100); 									
_marker = createMarker [_name, (getPos _x)]; 						
_marker setMarkerShape "ICON"; 										
_marker setMarkerType "DOT"; 										

} forEach _array; 

So once again I find myself completely stumped. Halp!

Share this post


Link to post
Share on other sites

Did you output _pos aswell as the both distances using hint/globalChat/sideChat?

This may help you figuring out possible problems with the markers and/or calculations (put a sleep after every while loop to be able to read the output before the next one comes)

As far as I can see there is no logical error in your while-loop but using more than one exclude area could lengthen the loop count by multiple times, depending on the mapsize and the maximum radius you set on the random location.

Just a little hint: If you use a value which is not changing more than once, put it into a variable and refer to them. Both marker positions can be saved in variables to spare some milliseconds (and you could output them to doublecheck!).

Edited by XxAnimusxX

Share this post


Link to post
Share on other sites
Did you output _pos aswell as the both distances using hint/globalChat/sideChat?

This may help you figuring out possible problems with the markers and/or calculations (put a sleep after every while loop to be able to read the output before the next one comes)

As far as I can see there is no logical error in your while-loop but using more than one exclude area could lengthen the loop count by multiple times, depending on the mapsize and the maximum radius you set on the random location.

Just a little hint: If you use a value which is not changing more than once, put it into a variable and refer to them. Both marker positions can be saved in variables to spare some milliseconds (and you could output them to doublecheck!).

No, the hints were just letting me know if and how far the script was getting before an issue arose. I'll have a go at adding some meaningful output, as you suggest. I just find it odd that the while loop works perfectly unless it's on a dedi server. Is it possible that there is something in the SHK_pos coding that is preventing it from running properly? I don't recall any mention of issues in dedi environments in that topic, and it is initializing well before I call it in my script. Or jeez - maybe it isn't. I'll drop a debug line in SHK_pos_init to make sure that's not the issue.

I'm really not concerned with processor time, as the array is only between 4-12 objects objects, and completes within a couple of seconds in a hosted environment. It's not a time-critical operation either - so long as it is done within 10-15 minutes of mission start it's fine. Still, the tips regarding efficiency are definitely appreciated!

Share this post


Link to post
Share on other sites

OK, I am getting coord/distance hints now. Editor/Hosted still work perfectly, while Dedi returns only a value of "Any" for coordinates and "Scalar" for distances.

Edited by Harzach

Share this post


Link to post
Share on other sites

Well trying to get the distance of two objects while one of them is null or invalid will yield the Scalar result :D

Did you try to evaluate the output in your arma2(oa).RPT-File or did you start the dedi-server with "-showScriptErrors" parameter? These steps will help you figure out if somethin went wrong along the way - I suspect something off in your random locations script you're using.

If this suspicion comes true, you're going to have to choose another random locations script :S

Furthermore I'm at a loss here because I never made a mission to launch it on a dedi so I don't know of any peculiarities involved with dedi servers.

My assumption: Either the markers aren't returning valid values or the random location script is messing somethin up on the dedi.

Share this post


Link to post
Share on other sites

Not sure I follow - are you saying I can only check the distance from one of my exclude markers to _pos, and not both?

No script errors are coming up, nothing relevant in .rpt file.

The random position script is Shuko's, which seems pretty solid.

I have to assume it has something to do with running it on a dedi, as it works flawlessly otherwise.

Thanks so much for your assistance!

edit: current code for reference:

_attackzones = [attackwp1,attackwp2,attackwp3,attackwp4,attackwp5,attackwp6,attackwp7,attackwp8,attackwp9,attackwp10,attackwp11,attackwp12];
_pos = [];
_distex1 = [];
_distex2 = [];

{
_checking = false;
while {!_checking} do {
_pos = [getMarkerPos "center", random 9950, random 359, false, [1, 4975]] call SHK_pos;
_distex1 = (_pos distance (getMarkerPos "exclude1"));
_distex2 = (_pos distance (getMarkerPos "exclude2"));

//debug chat
player globalChat format["Position: %1",_pos];  											
player globalChat format["Distance from exclude1: %1",_distex1];  									      
player globalChat format["Distance from exclude2: %1",_distex2];  							
hint "";																	                         
sleep 10;																	
//end debug chat	

if ((_distex1 > 1500) && (_distex2 > 700)) then { _checking = true};
};
_x setPos _pos;

//debug markers
_name = str(_x) + str(random 100); 														
_marker = createMarker [_name, (getPos _x)]; 													
_marker setMarkerShape "ICON"; 															
_marker setMarkerType "DOT"; 															
//end debug markers

} forEach _attackzones; 

sleep 5;

Edited by Harzach

Share this post


Link to post
Share on other sites

I meant if one of the parameters of "distance" is invalid (like an empty array) it will return somethin like "Scalar" :D

The last thing to check would be outputting the marker positions to check if the dedi does mess them up or smth.

player globalChat str (getMarkerPos "center");
player globalChat str (getMarkerPos "exclude1");
player globalChat str (getMarkerPos "exclude2");

Put this code above the foreach-loop and check the output. If these output valid location arrays, we have to search for someone who has experience in dedi servers ^^

Share this post


Link to post
Share on other sites

Ah, I get it.

All of those markers are used by other functions as well, and the mission itself would definitely EXPLODE if they weren't where they were supposed to be, but I'll check this out anyway.

Share this post


Link to post
Share on other sites

Getting valid and correct values for those markers, so that's not it.

I replaced the line

	_pos = [getMarkerPos "center", random 9950, random 359, false, [1, 4975]] call SHK_pos;

with a simpler bit of code that does not call SHK_pos and it works fine on dedi. The problem must have something to do with the SHK_pos system, either in the code itself or just as a result of how it is called/initialized/whatever.

Also, after reverting then removing the bit about exclusion zones (the point of this topic), I have this:

{
_pos = [getMarkerPos "center", random 9950, random 359, false, [1, 4975]] call SHK_pos;

player globalChat format["Position: %1",_pos];  													
player globalChat format["Distance from exclude1: %1",_distex1];  										
player globalChat format["Distance from exclude2: %1",_distex2];  										
hint "";

_x setPos _pos;
_name = str(_x) + str(random 100); 																	
_marker = createMarker [_name, (getPos _x)]; 														
_marker setMarkerShape "ICON"; 																		
_marker setMarkerType "DOT"; 																		

sleep 3;

} forEach _attackzones;

All three values are now returning "Any". So the forEach itself is not even working on dedi, let alone the condition I want to add to it.

/head asplode

Edited by Harzach

Share this post


Link to post
Share on other sites

More bizarreness.

I reverted the script to the state it was in up in post #13, and now it's behaving slightly differently.

I am still getting values of "Scalar" and "Any" as previously described, and it still loops endlessly, but it is also finding valid positions and somehow moving past the forEach loop to execute further tasks (while the forEach loop continues looping). I am so thoroughly confused at this point...

Share this post


Link to post
Share on other sites

Okay I'll looked into the SHK_pos script and found out that you're using it the wrong way, somehow xD

The second parameter has to be the direction followed by the distance in the third parameter - your call has switched them.

After looking deeper into the code I didn't find any reference to finding a location near/on a road so I think it isn't needed or supported anymore.

At least using SHK_pos v0.21 (check your version in shk_pos_init.sqf and download this version if you have an older one) you can achieve your goal with this code:

_attackzones = [attackwp1,attackwp2,attackwp3,attackwp4,attackwp5,attackwp6,attackwp7,attackwp8,attackwp9,attackwp10,attackwp11,attackwp12];
_pos = [];
_distex1 = [];
_distex2 = [];

{
       _pos = ["center", false, ["exclude1", "exclude2"]] call SHK_pos;
_x setPos _pos;

//debug markers
_name = str(_x) + str(random 100); 														
_marker = createMarker [_name, (getPos _x)]; 													
_marker setMarkerShape "ICON"; 															
_marker setMarkerType "DOT"; 															
//end debug markers

} forEach _attackzones; 

The distance to the center of the spawnpoint is randomly picked using the radius of your marker "center".

E.g. the distance should be between 0 - 9950, so you have to set the radius of your marker to 9950 in the editor (you should use an elliptical shape and set both values to the same one, practically defining a circle - but square shapes should also be okay it seems).

Your both exclude markers have to be modified in the same way - just set the size of both markers in the editor to prevent the position being in them, no self checking required anymore!

Please test this code and report your results, I'm curious if this actually works :D

If it's not - well, then you have no choice but to search for another random location script or write a small one specialized for your requirements (as most of the random location scripts are designed to handle every possibile factor, even if you don't need em in your equation).

Edited by XxAnimusxX

Share this post


Link to post
Share on other sites

I'm using 0.21. The code for road positions is in SHK_getpos.sqf, starting at line 58. At the top of the same script, the format for calling the script system is laid out as "[position,distance,direction,water]", and other tests show this to be correct.

I'm using this script solely for the purpose of finding road positions, so I really want to get this to work (else I'll be huddled at my computer for the next few months trying to write my own code for it).

At any rate, I'm up for trying anything at this point, so I'll give this a shot. Thanks again for the continuing support here!

Share this post


Link to post
Share on other sites

Just curiosity here... how are you loading SHK_pos?

---

private["_exclude_1","_exclude_2","_marker_center"];
// Cache your vars that won't change but are being will be referenced multiple times
_exclude_1 = getMarkerPos "exclude_1";
_exclude_2 = getMarkerPos "exclude_2";
_marker_center = getMarkerPos "center";
{
_checking = false;

while {!_checking} do {
	_pos = [_marker_center, random 10000, random 359, false, [1, 5000]] call SHK_pos;
	if ((_pos distance _exclude_1 > 1500) && 
		(_pos distance _exclude_2 > 500)) then { 
		_checking = true};
	};
};

_x setPos _pos;


//DEBUG MARKERS
_name = str(_x) + str(random 100); 									
_marker = createMarker [_name, (getPos _x)]; 						
_marker setMarkerShape "ICON"; 										
_marker setMarkerType "DOT"; 										

} forEach _array;

Edited by _Mofo_

Share this post


Link to post
Share on other sites
Just curiosity here... how are you loading SHK_pos?

As prescribed. In init:

call compile preprocessfile "SHK_pos\shk_pos_init.sqf";

Share this post


Link to post
Share on other sites
As prescribed. In init:

call compile preprocessfile "SHK_pos\shk_pos_init.sqf";

Not sure how you structured your files... but is the init.sqf loaded behind an "isDedicated" or "!isDedicated" of some sort?

Also, I briefly recoded your function from the first page in my previous response as *thought* it had a few places with potential flaws in it.

One other thing... do you have "-showScriptErrors" as a startup param and do you get any errors at all?

Sorry to question so much... but we are flying kinda blind here and it's already hard enough trying to debug and especially when it's shots in the dark. But I do know that SHK_pos works on dedi as I've used it in MP missions and it seems to work as intended.

Share this post


Link to post
Share on other sites

Well I asked him that some time ago, his answer:

No script errors are coming up, nothing relevant in .rpt file.

If he wouldn't load the shk_pos_init file correctly, the script would break off the moment the shk_pos-command is used (due to not being able to find the command).

As he did some experiments he got some values back, being "ANY" or "SCALAR". I thought that it might be associated with the markers not being there in a dedi enviroment but he also got legit values of those.

As you said the only way to help the OP would be looking deeper into his missions, firstly getting a brief look into his init.sqf to find any logical structures interfering with the shk-script :S

Share this post


Link to post
Share on other sites

You could say that this mission is complicated - it's a deeply customized variant of ACE Insurgency.

Not sure how you structured your files... but is the init.sqf loaded behind an "isDedicated" or "!isDedicated" of some sort?

There is an

if !isDedicated then {xxx}

at the top of the init.sqf, but it's closed well before SHK_pos is compiled. Still, this prompted me to try something...

I'm now loading SHK_pos via invisible helipad and am getting meaningful values instead of the previous "Any" and "Scalar". The conditions are also executing properly.

I also implemented the changes you made - thanks for the tip! Not 100% sure that this is all sorted out, but it's looking good. Other parts of the script are still acting screwy, but that's not related to SHK_pos.

Thanks again to all who lent a hand here - it's very much appreciated!

Share this post


Link to post
Share on other sites

Harzach,

For finding roads, have a look at how I did it. I read what you are trying to do. I use nearroads to get all the road sections, then isonroad to find the edge before I place the IED.

I had exactly the same issue you did with the loops and conditions and only writing out a big flowchart with the conditions got a solution

http://www.armaholic.com/page.php?id=17869

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
Sign in to follow this  

×