Jump to content
doc. caliban

Determine smallest of multiple marker areas unit is inside of.

Recommended Posts

Hello.


I am needing to find out which marker areas a unit is within, then determine which of them is the smallest.  I need the variable name of that marker returned by the script.

 

I'm guessing it would be something along the lines of this:

1 Use unit inArea against each marker returned by allMapMarkers.

2 Use getMarkerSize against the results of the above line.

3 Determine which marker from the results of step 2 is smallest, and return its variable name.

 

Any help with the actual scripting would be greatly appreciated!

 

-Doc

Share this post


Link to post
Share on other sites
// in init.sqf
waitUntil {time > 0};
player linkItem "ItemGPS";

sleep 0.75;
hintC "Open your GPS";

// marker area function
MarkerArea = {
	switch (markerShape _this) do {
		case "RECTANGLE": {getMarkerSize _this params ["_msw", "_msh"]; _msw * _msh};
		case "ELLIPSE":   {getMarkerSize _this params ["_msw", "_msh"]; _msw * _msh * 0.25 * pi};
		default {0}
	}
};

// create list of all markers ordered by area
allMapMarkersOrderedByArea = [allMapMarkers,[],{_x call MarkerArea},"ASCEND"] call BIS_fnc_sortBy;


// poll smallest marker with player and log in system chat
while {true} do {
	private _smallestMarker = {if (player inArea _x) exitWith {_x}; ""} forEach allMapMarkersOrderedByArea;
	systemChat ("Player inside marker: " + _smallestMarker);
	sleep 1;
};

Demo mission: link

Share this post


Link to post
Share on other sites

The code above will return the first marker unit is in, what is all business with getting the size and sorting???

Share this post


Link to post
Share on other sites
13 minutes ago, killzone_kid said:

The code above will return the first marker unit is in, what is all business with getting the size and sorting???

 

Yes, you're right. Code above will return the first marker unit is in, from markers array ordered by marker area, and this is exactly what he needs.

 

// return marker name or empty string if unit outside of any marker
SmallestMarkerUnitIsIn = {
	{if (_this inArea _x) exitWith {_x}; ""} forEach allMapMarkersOrderedByArea};

// Usage:
private _marker = player call SmallestMarkerUnitIsIn;

 

Share this post


Link to post
Share on other sites

What he needs (Step 3) is the smallest marker returned with unit in, and you return any marker with unit in.

Share this post


Link to post
Share on other sites
4 minutes ago, killzone_kid said:

What he needs (Step 3) is the smallest marker returned with unit in, and you return any marker with unit in.

 

Not "any", first marker unit in from array of markers ordered from smallest to biggest by area  :))

Share this post


Link to post
Share on other sites

Yes "any". I can walk into the biggest marker, and it will be returned, then I can walk into the smallest marker, and it will be returned. Then, for the final test, I can close my eyes and walk in any random marker, and it will be returned. In my books this is called returning "any" marker.

Share this post


Link to post
Share on other sites
1 minute ago, killzone_kid said:

Yes "any". I can walk into the biggest marker, and it will be returned, then I can walk into the smallest marker, and it will be returned. Then, for the final test, I can close my eyes and walk in any random marker, and it will be returned. In my books this is called returning "any" marker.

 

When you walk into area overlapped by three different markers my code returns smallest marker you're in

Share this post


Link to post
Share on other sites

Ok, fair point, but this only works for overlapped markers which there is no mention of in the original request

Share this post


Link to post
Share on other sites
4 minutes ago, killzone_kid said:

Ok, fair point, but this only works for overlapped markers which there is no mention of in the original request

 

Anyway, we need for topic starter to clarify :)

Share this post


Link to post
Share on other sites

Hello!

 

If I understand, Serena's code is in fact what I need, KK. 

 

It's ordering the markers from smallest to largest, and then returns the first one the unit is in in that order.  So if the unit is in 4 different areas, it will return the smallest of the 4.  If the unit is in any single area, it will return that marker name since that single area is by default the smallest area the unit is in.

 

Thank you, Serena!

 

Here's how I'd like to use this:

 

In the init field of some units, I have a statement that includes an array.  One of the string entries in the array is the variable name of a marker.  I'd like to utilize this code to output that string value at startup.  I currently have a less desirable solution of just getting the nearest marker, like this:

 

[([allMapMarkers, this] call BIS_fnc_nearestPosition), etc...] 

 

That works, but can easily be inaccurate since it does not take marker area into account.  (Thus this post)

 

I'd like to replace ([allMapMarkers, this] call BIS_fnc_nearestPosition) with Serena's code.  Should I precompile it as a function and call it like this?

 

[(call fnc_serenaCode), etc...]

 

It will be running a few dozen times at startup, and then won't be used again during the mission.

 

Thank you again!

 

-Doc

 

EDIT: I just saw the latest 2 replies .... typing a clarification.  Stand by... (watch this space)  :-)

 

To clarify: Overlapping areas (cases where a smaller area is not completely contained within a larger area) are not an issue for my needs.  I just need to work with areas that are completely contained within other areas, or if the unit is only in one area, the name of that area.  Does that help?

 

Share this post


Link to post
Share on other sites

.

 

16 minutes ago, doc. caliban said:

Should I precompile it as a function and call it like this?

 

[(call fnc_serenaCode), etc...]

 

It will be running a few dozen times at startup, and then won't be used again during the mission.

 

Simple variant:

// in init.sqf
waitUntil {time > 0};

MarkerArea = {
	switch (markerShape _this) do {
		case "RECTANGLE": {getMarkerSize _this params ["_msw", "_msh"]; _msw * _msh};
		case "ELLIPSE":   {getMarkerSize _this params ["_msw", "_msh"]; _msw * _msh * 0.25 * pi};
		default {0}
	}
};

allMapMarkersOrderedByArea = [allMapMarkers,[],{_x call MarkerArea},"ASCEND"] call BIS_fnc_sortBy;

// Somewhere in scripts (replace player with actual unit)
private _marker = {if (player inArea _x) exitWith {_x}; ""} forEach allMapMarkersOrderedByArea;

 

Wrapped variant:

// add this to init.sqf
SmallestMarkerUnitIsIn = {
	{if (_this inArea _x) exitWith {_x}; ""} forEach allMapMarkersOrderedByArea};

// Somewhere in scripts (replace player with actual unit)
private _marker = player call SmallestMarkerUnitIsIn;

* if  unit is not in any marker area, an empty string is returned

Share this post


Link to post
Share on other sites

My limited understanding of this stuff is really starting to show now.  :-)

 

It looks like I could use it in my array like this:

 

[(player call SmallestMarkerUnitIsIn), etc...]

That would result in the array containing ["markerName", etc...], correct?

 

If so, to do that I'd need to have this in init.sqf?

 

waitUntil {time > 0};

MarkerArea = {
	switch (markerShape _this) do {
		case "RECTANGLE": {getMarkerSize _this params ["_msw", "_msh"]; _msw * _msh};
		case "ELLIPSE":   {getMarkerSize _this params ["_msw", "_msh"]; _msw * _msh * 0.25 * pi};
		default {0}
	}
};

allMapMarkersOrderedByArea = [allMapMarkers,[],{_x call MarkerArea},"ASCEND"] call BIS_fnc_sortBy;
 
SmallestMarkerUnitIsIn = {
	{if (_this inArea _x) exitWith {_x}; ""} forEach allMapMarkersOrderedByArea};

Off to bed.  I'll check this in the morning.  Thank you again.  This will help massively reduce the time it takes me to make missions.  I'll explain once I've got it working.

 

-Doc

Share this post


Link to post
Share on other sites

 

6 minutes ago, doc. caliban said:

That would result in the array containing ["markerName", etc...], correct?

If so, to do that I'd need to have this in init.sqf?

 

Yes and yes.

Result also can be ["", etc... ] when unit outside of any marker area.

Share this post


Link to post
Share on other sites
1 hour ago, doc. caliban said:

I just need to work with areas that are completely contained within other areas, or if the unit is only in one area, the name of that area


Then Serena's code is valid solution for your problem ;)

Share this post


Link to post
Share on other sites

Thank you both very much.   It's a very specific thing I wanted to be able to do, and while there are certainly fringe cases that it might not handle, those are not of concern for my purposes.

 

Here's what I'm doing:

 

I use the script-only version of the AI mod that's bundled into MCC, Gaia.  The mission making process is to place area markers that will be used at Gaia "zones", place groups in the zones, then edit the init for each group leader to define, among other things, the zone they are assigned to.

 

That meant a lot of init editing, which meant a few mistakes in almost every mission.  I wanted to make the process more automated and error-proof.

 

I have custom groups saved with the other init settings that I want, so all I have to do is paste them into whatever zones I want, but I still had to edit each group leader's init to specify the zone.  With this code the zone will now be automatically set, so my Gaia-related mission making phase is super fast and simple, and pretty much error-proof.

 

I always have zones nested inside of other zones, but rarely have any that partially overlap by much.  If they do, it's very little, and I simply don't place groups in the overlapping areas.  Every group is in at least one zone, but if I make a mistake and have one that is not, the code returning "" is just fine.  It won't hurt a thing.

 

Again, thank you so much... this has been a huge help, and will have a great impact on my missions in that I can spend more time working on the other aspects of them once the basic Gaia zones and troops are laid down.

 

Best,

-Doc

 

EDIT: I've run into one snag: Using (this call smallestMarkerUnitIsIn) does not seem to work.  Using player instead of this works on myself, but these need to run against AI units, not playable units.  I'm sorry if my not specifying that sooner caused a problem!

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

×