Jump to content
  • 0

SQF help - random positions from an array


Guest

Question

I'm guessing this is probably pretty easy to do. I'm just not familiar enough with SQF. The first place I'm looking to do it is with some loot crates. Basically I want them to show up in positions, randomly selected from an array, per restart. 

 

So for instance:

 

positionArray = [[8103.18,13557.3],[8102.68,13476.3],[8020.13,13633.4],[8098.68,13542.8]];

 

positon = positionArray[floor(random positionArray.length)];

 

_this = createVehicle ["TKVehicleBox_EP1", position, [], 0, "CAN_COLLIDE"];

 

_this setPos [position];

 

 

Thanks in advance!

-Silk

 

 

Link to comment
Share on other sites

19 answers to this question

Recommended Posts

  • 0

Example:

_coord1 = [4908.355,11216.505,0];
_coord2 = [6162.9888,11324.005,0];
_coord3 = [7761.3657,11569.265,0];
_coord4 = [8336.6055,10441.17,0];
_coord5 = [7201.0664,10400.667,0];
_coords = [_coord1, _coord2, _coord3, _coord4, _coord5] call BIS_fnc_selectRandom;

_crate = createVehicle ["USLaunchersBox",[(_coords select 0), (_coords select 1),0],[], 0, "NONE"];
_crate setVariable ["Mission",1,true];
_crate setVariable ["permaLoot",true];
[_crate] execVM "\z\addons\dayz_server\missions\misc\fillBoxesS.sqf";  //fills the box with random stuff


///////////////
//fillBoxesS.sqf
///////////////

_crate2 = _this select 0;

clearWeaponCargoGlobal _crate2;
clearMagazineCargoGlobal _crate2;

// RIFLES
_crate2 addWeaponCargoGlobal ["M4A1_RCO_GL", 1];
_crate2 addWeaponCargoGlobal ["M16A4_GL", 1];
_crate2 addWeaponCargoGlobal ["M4A3_CCO_EP1", 1];
_crate2 addWeaponCargoGlobal ["M4SPR", 1];
_crate2 addWeaponCargoGlobal ["RPK_74", 1];
_crate2 addWeaponCargoGlobal ["SVD", 1];

// PISTOLS
_crate2 addWeaponCargoGlobal ["glock17_EP1", 1];
_crate2 addWeaponCargoGlobal ["MakarovSD", 1];

// AMMUNITION
_crate2 addMagazineCargoGlobal ["17Rnd_9x19_glock17", 10];
_crate2 addMagazineCargoGlobal ["8Rnd_9x18_MakarovSD", 10];
_crate2 addMagazineCargoGlobal ["30Rnd_556x45_Stanag", 10];
_crate2 addMagazineCargoGlobal ["75Rnd_545x39_RPK", 10];
_crate2 addMagazineCargoGlobal ["10Rnd_762x54_SVD", 10];

// ITEMS
_crate2 addWeaponCargoGlobal ["ItemToolbox", 5];
_crate2 addWeaponCargoGlobal ["ItemMatchbox", 5];

// BACKPACKS
_crate2 addBackpackCargoGlobal ['DZ_Backpack_EP1', 1];


Link to comment
Share on other sites

  • 0

if you still need the position and not a random element for whatever reason your code was pretty close, just the wrong syntax :D

ArmA script has no array operator [] or something, you just use the "select" command to select an element at a specified index.

e.g. "array select 0" to get the first element or "array select 5" to get the 6th etc.

also there is no .operator (.length) use the count command: "count array"

 

so if you want to get a random index form an array you can do it like this:

_pos = floor random count _array;
_element = _array select _pos;

( ) are optional in ArmA script, if not needed :)

Link to comment
Share on other sites

  • 0

if you still need the position and not a random element for whatever reason your code was pretty close, just the wrong syntax :D

ArmA script has no array operator [] or something, you just use the "select" command to select an element at a specified index.

e.g. "array select 0" to get the first element or "array select 5" to get the 6th etc.

also there is no .operator (.length) use the count command: "count array"

 

so if you want to get a random index form an array you can do it like this:

_pos = floor random count _array;
_element = _array select _pos;

( ) are optional in ArmA script, if not needed :)

 

Awesome! And yeah still learning sqf syntax. Really appreciate it Axe Cop!

Link to comment
Share on other sites

  • 0

Ok I just started getting around to this again and realized an issue with what I am trying to do. Basically I'm trying to place a number of crates at random positions per restart. Each position selected randomly from one array. The issue with that is that they have a chance of ending up in the same position. In JS I would just splice() that position out of the array after assigning it to an object to keep that position from being assigned twice. So how do you do that with SQF? 

 

Also I can't seem to find good documentation on the syntax anywhere...I must be missing something cause it can't be that hard to find.

 

Thanks in advance!

-silk

Link to comment
Share on other sites

  • 0

weird, everything you shoudl need is described in the wiki here https://community.bistudio.com/wiki/Main_Page (look for the scripting pages)

look at the page about Arrays: https://community.bistudio.com/wiki/Array

 

if you know ho to program a little that should be all you need I think :)

 

anyway you can just subtract an array from another, that is the preferred way of removing elements in Arma Script I guess

_array = [1,2,3,4,5];
_array = _array - [2,4]; // removes all occurrences of 2 and 4 from the array (that works for strings and objects as well)

if the order of the elements doesn't matter (should not matter if you select random elements haha) you can use my method:

  1. select an element by index and save the value (if you need it)
  2. swap the last element of the array with the one you selected
  3. shrink the array by 1 (essentially cuts of the last element of the array)

that should be more efficient in my opinion, but if you deal with small arrays it should not matter, for an example of my method look at the spawn vehicle code in the epoch file here: https://github.com/vbawol/DayZ-Epoch/blob/1.0.4a/SQF/dayz_server/init/server_functions.sqf#L251-L256 

Link to comment
Share on other sites

  • 0

Alright. I swear I have been trying to do this on my own. Not trying to make anyone code this for me, even though you probably will(I'm looking at you Axe Cop.)

 

I'm trying to have a crate spawn in a random location selected from an array of positions.

 

This is what I have so far: 

 

if (isServer) then {

 

_positionArray=[[8086.3,13643.4,0],[8054.41,13610.1,0],[8002.69,13610.1,0]];
        
        _pos=floor random (count _positionArray);
        _position = _positionArray select _pos;
        diag_log("DEBUG: Crate spawned here " + str(_position));
        
_vehicle_999992= objNull;
 
if (true) then
{
 _this = createVehicle ["TKVehicleBox_EP1", _position, [], 0, "CAN_COLLIDE"];
 _vehicle_999992 = _this;
 _this setVariable ["permaLoot",true]; 
 _this setDir 90;
 
 clearweaponcargoGlobal _this;
 clearmagazinecargoGlobal _this;
 
 _this addWeaponCargoGlobal ["NVGoggles",2];

 _this addWeaponCargoGlobal ["ItemGPS",2]; 

 //There's more gear here...

 

 _this setPos _position;
};
 
};
 
Not getting any errors with the above. The _position is getting a random value from the array but the box isn't showing up anywhere. I tried the string modifier on _position but that did throw an error. The _position var isn't being treated like a multi-dimensional array is it? I'm probably just missing something simple.
 
btw thanks for that earlier example Axe Cop it was helpful.
Link to comment
Share on other sites

  • 0

if you still need the position and not a random element for whatever reason your code was pretty close, just the wrong syntax :D

ArmA script has no array operator [] or something, you just use the "select" command to select an element at a specified index.

e.g. "array select 0" to get the first element or "array select 5" to get the 6th etc.

also there is no .operator (.length) use the count command: "count array"

 

so if you want to get a random index form an array you can do it like this:

_pos = floor random count _array;
_element = _array select _pos;

( ) are optional in ArmA script, if not needed :)

 

You need to subtract 1 from the array count, since array selection starts at 0, counting starts at one. I'm actually not sure if floor will ever return the highest number, I would need to test it.

_pos = round (random (count _array - 1));

Link to comment
Share on other sites

  • 0

@icomrade: it works like that without -1 because random is exclusive like every good random function should be :D

meaning the value returned from "random x" is in the interval [0, x) if you know some math that means it can be zero but will never reach x itself.

e.g. "random 1" will be a value between 0 and 0.999999999...

 

so with that knowledge think about the "random count _array" again, if the array has 10 elements it will return a value between 0 and 9.99999...

and if you know apply the "floor" function to it it will just cut of the decimal points essentially leaving you with a random value form 0 to 9! :)

 

if you get confused with the floor and ceil functions just think of the floor beneath you (rounds the value down) and the ceiling above you (rounds the value up).

 

 

@SilkTricky: hmm I would try to use own variables and not this weird "_this" from the mission.sqf or wherever you copied that from :D

I would use something like this maybe:

 _box = createVehicle ["TKVehicleBox_EP1", _position, [], 0, "CAN_COLLIDE"];

instead of

 _this = createVehicle ["TKVehicleBox_EP1", _position, [], 0, "CAN_COLLIDE"];

and use "_box" everywhere and not "_this"  and "_vehicle_999992" and 42 other variables for the same thing, that is just confusing in my opinion :P

 

about the position thing, that is just a simple array with 3 coordinates and no special object so you just use it like any other array or print it like that,

I don't know what you mean by the string modifier!? the "str" command?

 

pro tip (I hope it works haha): if you just use 2d positional data instead of 3d it will place the box always on the ground at the position (just omit the z-value), that works with all objects in arma and is quite handy but can also be weird because the z-value is always relative to the ground (or water if there is water at the position) with setPos and never the absolute value in 3d space (like x and y is)!

there are different functions for setting the z-value relative to other things like setPosATL (above terrain level) and setPosASL (above sea level) or other, just check the wiki for the getPos command.

Link to comment
Share on other sites

  • 0
It works!! Took your advice Axe and changed the var names and bang works great.Thanks a ton. 
 
btw by string modifier, I was thinking that str() might force values into a string so it could print out like you mention. Apparently it does that on it's own. I noticed that in order to get it to print in the rpt, the "debug" line, I had to use it.  
 
Well here it is with most of the gear stripped out in-case someone wants to use it. 
 
Thanks again!
 
 
private ["_boxOne"];
 
if (isServer) then {
        
    _positionArray=[[8095.11,13459.4],[8060.22,13601.7],[8188.03,13430.1],[8138.56,13565.7],[7981.14,13581.4],[7886.77,13622.2],[8053.62,13689.4]];
    
    _pos= floor random count _positionArray;
    _position = _positionArray select _pos;
    diag_log("DEBUG: Crate spawned here " + str(_position));
    
    _boxOne= objNull;
    
    if (true) then
    {
      _boxOne = createVehicle ["USSpecialWeaponsBox", _position, [], 0, "CAN_COLLIDE"];
      _boxOne setVariable ["permaLoot",true]; 
      _boxOne setDir 90;
 
      clearweaponcargoGlobal _boxOne;
      clearmagazinecargoGlobal _boxOne;
 
      GunRandomizerA=floor(random 2);
            
            if (GunRandomizerA == 0) then {
                _boxOne addWeaponCargoGlobal ["M47Launcher_EP1",1];
                _boxOne addMagazineCargoGlobal ["Dragon_EP1", 2];
                _boxOne addWeaponCargoGlobal ["M4A1_HWS_GL_SD_camo",2];
                _boxOne addMagazineCargoGlobal ["30Rnd_556x45_StanagSD", 30];
                _boxOne addWeaponCargoGlobal ["BAF_L85A2_RIS_SUSAT",1];
                _boxOne addWeaponCargoGlobal ["M16A4_ACG_GL",1];
                _boxOne addWeaponCargoGlobal ["SCAR_H_CQC_CCO", 1];
                _boxOne addMagazineCargoGlobal ["20Rnd_762x51_B_SCAR", 20];
                _boxOne addMagazineCargoGlobal ["bulk_FoodbaconCookedFull", 2];
            };
if (GunRandomizerA == 1) then {
                _boxOne addWeaponCargoGlobal ["M47Launcher_EP1",1];
                _boxOne addMagazineCargoGlobal ["Dragon_EP1", 2];
                _boxOne addWeaponCargoGlobal ["M4A1_HWS_GL_SD_camo",2];
                _boxOne addMagazineCargoGlobal ["30Rnd_556x45_StanagSD", 30];
                _boxOne addWeaponCargoGlobal ["BAF_L85A2_RIS_SUSAT",1];
                _boxOne addWeaponCargoGlobal ["M16A4_ACG_GL",1];
                _boxOne addWeaponCargoGlobal ["SCAR_H_CQC_CCO", 1];
                _boxOne addMagazineCargoGlobal ["20Rnd_762x51_B_SCAR", 20];
                _boxOne addMagazineCargoGlobal ["bulk_FoodbaconCookedFull", 2];
            };
            _boxOne addWeaponCargoGlobal ["NVGoggles",1];
            _boxOne addWeaponCargoGlobal ["ItemGPS",1];
            _boxOne addWeaponCargoGlobal ["ItemEtool", 1];
            _boxOne addMagazineCargoGlobal ["Skin_Sniper1_DZ", 2];
            _boxOne addMagazineCargoGlobal ["Skin_GUE_Soldier_Sniper_DZ", 2];
            _boxOne addMagazineCargoGlobal ["ItemGoldBar10oz", (random 100)];
            _boxOne addbackpackCargoGlobal ["DZ_LargeGunBag_EP1",1];
            _boxOne setPos _position;
    };
 
};
Link to comment
Share on other sites

  • 0

Any idea where I could define "_position" to make it a global variable? I tried just removing the underscore and renaming it to something more unique. Should I put it in my custom variables.sqf? 

Link to comment
Share on other sites

  • 0

Ugh. Here's what I got so far:

 

_positionZeroCrateArray=[[8095.11,13459.4],[8060.22,13601.7],[8188.03,13430.1]];
 
_posZero= floor random count _positionZeroCrateArray;
ZEROcratePosition = _positionArray select _posZero;
 
The above works great, thanks to you cop. And here's the other piece which is executed from a right click:
 
diag_log("DEBUG: ZERO 1 Crate Position from Marker Map");
 
player removeWeapon "Kostey_notebook";
//_zeroonecrate = createMarker ["_zeroonecrate", [8299, 12810]];  <---- if I use this line and comment out the one below, this works. 
_zeroonecrate = createMarker ["_zeroonecrate", ZEROcratePosition];
_zeroonecrate setMarkerColor "ColorBlack";
_zeroonecrate setMarkerType "Vehicle";
_zeroonecrate setMarkerText "Loot Crate";
Link to comment
Share on other sites

  • 0

so you think "ZEROcratePosition" is not defined in your menu? I don't know maybe you did not execute the script before you use the menu? hard to tell from this :D

you can use my debug tools to print out stuff like that in game and its easy to test scripts with my console without restarting the server: 

you can simple paste "ZEROcratePosition" in there and click on exec to show the value (or nil).

Link to comment
Share on other sites

  • 0

Awesome, I'll install your debug tool. 

 

I'm executing the script that defines ZEROcratePosition from my mission init.sqf. But I guess that's not early enough. When you define scripts that would execute on a event do they get added into memory before the event happens? That would certainly explain this. Call is coming from here:

 

class Kostey_notebook {
class UseZeroMap {
text = "Mark Map";
script = "execVM 'deploys\markZeroMap.sqf'";
};
};
 
and the file that contain the above is the extra_rc.hpp which is getting included at the bottom of the description.ext
Link to comment
Share on other sites

  • 0

I have no idea about events, just put a debug line in the script and check the log file if it gets executed in the correct order?

diag_log ["script executed at", time];

the "time" command should display the time in seconds from the server start

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Discord

×
×
  • Create New...