Jump to content
Godis_1

Randomly count & select a marker by script

Recommended Posts

Hello everyone.

 

I don't know how to desribe my problem in the title, my English isn't good enough on that..

 

I want let the script to randomly pick a marker. My problem is that the markers are being created dependant on the amount of towns on the map. It detects all towns and creates an invisible marker at each, with name "Mark_1", "Mark_2", etc...

 

I need to know how can I let my script at first count all created markers (as each map has a different amount of villages) and then randomly pick one of these markers.

The markers are being created as follows (a part of the script):

 

towns.sqf

/*

	Location finder for towns, villages and cities

    Places triggers and/or markers at these locations

*/



// Get each locations of villages or cities and create trigger/marker

//  Original script for finding locations by BrotherhoodOfHam
//  Final script by Godis


if (!isServer) exitWith {};
//#define MARK
#define OFFSET 0

_locations = (nearestLocations [[0,0,0], ["NameCity", "NameVillage", "NameCityCapital"], 40000]);

{
	_xy = size _x;

	_trig = createTrigger ["EmptyDetector", position _x];
	_trig setTriggerArea
	[
		(_xy select 0) + OFFSET,
		(_xy select 1) + OFFSET,
		direction _x,
		false
	];

	_trig setTriggerActivation
	[
		"WEST",
		"PRESENT",
		true
	];

	_trig setTriggerStatements
	[
		"this",
		"hint 'Entered Village: Watch out in this area';",
		"hint 'Leaving Village...';"
	];

	//#ifdef MARK
	_mkr = createMarker [format ["Mark_%1", _forEachIndex], position _x];
	_mkr setMarkerShape "ELLIPSE";
	_mkr setMarkerAlpha 0.0;
	_mkr setMarkerSize
	[
		(_xy select 0) + OFFSET,
		(_xy select 1) + OFFSET
	];
	//#endif

} forEach _locations;

// Now place units

 

I thought I could just add a counter to towns.sqf, so I would get the total amount of all created markers stored in a variable, like:

all_markers = 0;


// Content of towns.sqf here (create markers)


all_markers = all_markers + 1;	// count each marker and store number in 'all_markers'

 

But this would need another check for this variable's value, and also another code to select one of them according to the amount of created markers. I think it's kind of inconvenient. There must be another easier way to archive that, I guess.

Is there any code I can use to get that in only a few lines?

 

At the end I just need to:

 

1. find the amount of markers with name Mark_1, Mark_2, Mark_3, etc, etc

2. Randomly select one of these (i.e. to make it visible by setMarkerAlpha or sth else)

 

 

Thanks in advance.

 

 

 

 

 

 

Share this post


Link to post
Share on other sites
// select all settlement markers
private _settlements = allMapMarkers select {_x find "Mark_" isEqualTo 0}; // result: ["Mark_1", "Mark_2", "Mark_3"]


// select random settlement marker
private _settlement = selectRandom _settlements; // result: "Mark_?"


// get settlement markers count
private _count = count _settlements; // result: 3

* code updated

  • Like 2

Share this post


Link to post
Share on other sites
20 minutes ago, serena said:

// select all settlement markers
private _settlements = allMapMarkers select {_x find "Mark_" isEqualTo 0}; // result: ["Mark_1", "Mark_2", "Mark_3"]


// select random settlement marker
private _settlement = selectRandom _settlements; // result: "Mark_?"


// get settlement markers count
private _count = count _settlements; // result: 3

 


Thank you :-) I guess this is what I was searching for...

Share this post


Link to post
Share on other sites

Forgot sth. Can I "split" the result of "_settlements" into even and odd numbers and put them into a new array? I mean, two arrays in this case. One for the odd numbers, another for even numbers.

And, In example, I am calling a function which needs markers to be defined in an array:

null = 	[["Mark_4","Mark_10","Mark_16","Mark_20","Mark_24","Mark_30"], [blabla], ...

is there another way to define them more accurate instead of putting them manually? Otherwise I would have to write an endless "if (_count > whatever_nr) then {};" condition, based off the amount resulted by "_count".


Edit: Maybe this would work by "selectmarkers = _settlements select [0,3,5,7,9...]" // would that work?

Edit 2: Ok, I got sth from the wiki:

_even = [1,2,3,4,5,6,7,8,9,0] select {_x%2 == 0}; 

In this case can I replace the array with number with the "_settlements" array?
 

_even = [_settlements] select {_x%2 == 0}; 

 

Share this post


Link to post
Share on other sites
12 hours ago, Godis_1 said:

Can I "split" the result of "_settlements" into even and odd numbers and put them into a new array?

private _all = ["A", "B", "C", "D", "E"];
private _evn = [];
private _odd = [];

{	if (_forEachIndex % 2 > 0)
  		then {_evn pushBack _x}
 		else {_odd pushBack _x}
} forEach _all;

// Result: 
// _evn = ["B","D"]
// _odd = ["A","C","E"]
  • Like 1

Share this post


Link to post
Share on other sites
10 hours ago, serena said:

private _all = ["A", "B", "C", "D", "E"];
private _evn = [];
private _odd = [];

{	if (_forEachIndex % 2 > 0)
  		then {_evn pushBack _x}
 		else {_odd pushBack _x}
} forEach _all;

// Result: 
// _evn = ["B","D"]
// _odd = ["A","C","E"]

All right, thanks again :-)

Going to try around.

Share this post


Link to post
Share on other sites

Hi again, my last problem :) So far you helped me a lot, thx a lot for this!
However, I didn't want to open an extra thread for this.

Now I got everything working so far. What I need is to put the content of the resulting array (_settlements in this case) into another array which is part of a function call.
 

Example:

["Mark1","Mark_2","Mark_3"] call function_now;

I got the whole list of towns inside the "_settlements" array

(_settlements = ["Mark_1", "Mark_2", "Mark_3"];) 

 

but I'm not able to figure how I could put its content inside the function call.

This doesn't work:

[_settlements] call function_now;

// also doesn't work
["%1",_settlements] call function_now;

and tried some other things.. Might it work using the "str" or "set" command somehow? I don't know how to use it properly, am still very much in the learning process.

Edit: After some further researching I found it could be done somehow using "select"... I'm trying to find it by myself, but will be thankful if someone could point me into the right direction here. thx

So, what about sth like this:
 

[(_settlements select (count _settlements))] call function_now;

 

 

Share this post


Link to post
Share on other sites

So close with:

[_settlements] call function_now;

Use:

_settlements call function_now;

  • Like 1

Share this post


Link to post
Share on other sites

Awwww... Damn! I'm realy dumb! I guess I can use what's already there...
 

[allMapMarkers select {_x find "Mark_" isEqualTo 0}] call function_here;

?? :-D

 

Share this post


Link to post
Share on other sites
3 minutes ago, mrcurry said:

So close with:

[_settlements] call function_now;

Use:

_settlements call function_now;

Ooops, lol. Many thanks!! Seems we posted the same moment. 

Share this post


Link to post
Share on other sites
// function call
_settlements call function_now;


// inside function_now
private _settlements = _this; // _this variable always references arguments passed to function

 

  • Like 1

Share this post


Link to post
Share on other sites

Thx to you guys helping me out. Got another thing, nothing complicated, but still not sure.

I just want to select the last element of an array. According to the wiki it should be sth like the following, would it work like that? 
 

if (array > 0) then 
{
	_select_last_element = (_array select (count _array));
};

 

Share this post


Link to post
Share on other sites

Again so close :) Count gives you the amount but the indexes start at 0 the last element will always be amount-1. 

  • Like 1

Share this post


Link to post
Share on other sites
9 minutes ago, mrcurry said:

No, count gives you the amount but since the indexes start at 0 the last element will always be amount-1. 

Well, then it must be:

if (array > 0) then 
{
	_select_last_element = (_array select (count _array-1));
};

??

But doesn't that also remove the last element from the array? Or is it just selected this way?

Thank you, :)

 

 

EDIT: Nevermind, this would indeed move the last selected element i.e. to another one, if there was another array in front of it, like
"... array1 + (array2 select (count array2 -1));"

Thx. :)

  • Like 1

Share this post


Link to post
Share on other sites
3 hours ago, Godis_1 said:

Well, then it must be:

// last element if array contains something, otherwise nothing:
private _last = if (count _array < 1) then {nil} else {_array select (count _array - 1)};

// if you want to get default value when array empty - just replace nil constant:
private _last = if (count _array < 1) then {"This is default value - array is empty"} else {_array select (count _array - 1)};

Another way is to use the param command:

private _last = _array param [count _array - 1];
                              
private _last = _array param [count _array - 1, "Default value - when array empty"];

 

  • Like 1

Share this post


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

nvm didn't read the reply to the end

 

mine? No, I've edited it just after posting.. :)

Share this post


Link to post
Share on other sites
1 hour ago, serena said:

// last element if array contains something, otherwise nothing:
private _last = if (count _array < 1) then {nil} else {_array select (count _array - 1)};

// if you want to get default value when array empty - just replace nil constant:
private _last = if (count _array < 1) then {"This is default value - array is empty"} else {_array select (count _array - 1)};

Another way is to use the param command:


private _last = _array param [count _array - 1];
                              
private _last = _array param [count _array - 1, "Default value - when array empty"];

// So it doesn't need an extra check (i.e. "If () then {];" condition) to verfify if the array is emtpy? 
// How would that be used to keep it emtpy in case nothing was stored inside?

// Does it work with:
private _last = _array param [count _array - 1, []];

// or:
private _last = _array param [count _array - 1, ""];

?

 

Thank you. Due to code otpimization "param" could be the faster one, cause it doesn't nee a check if array is empty..Just thinking..

 

Share this post


Link to post
Share on other sites
26 minutes ago, Godis_1 said:

So it doesn't need an extra check to verify if the array is empty?

Yes

 

26 minutes ago, Godis_1 said:

How would that be used to keep it empty in case nothing was stored inside?
private _last = _array param [count _array - 1];

Note, if array is empty you got nil value attempt to use which will cause an error.

 

So, if you not sure array is not empty then use syntax with default value or check result before use:

if (not isNil "_last") then {
	// code here executed only if _last variable contains value (array not empty)
};

 

  • Like 1

Share this post


Link to post
Share on other sites

Maybe a totally dumb question, but I'm curious about if there's any difference between: "this" and "_this" ? In Jquery "this" is a selector (and in sqf it's that too, or called "magic variable".), and "_this" is a normal variable. Is it the same for SQF?

Share this post


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

When in doubt always consult with BIKI... https://community.bistudio.com/wiki/this

Hey, thank you. :) I always do - but googling "Arma 3 sqf this" didn't bring me there lol... I should have tried it by "alt+e" in Sublime Text, lol. Thx :)
 

Share this post


Link to post
Share on other sites

BTW: You debug_console extension is a great one!!

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

×