Jump to content
Undeceived

Array of items, weapons, magazines inside a trigger area

Recommended Posts

Hi guys, I would like to "collect" the items, weapons, magazines and backpacks that the player has put on the ground inside a certain trigger and put then into a crate.

Is there a way to detect this stuff and create an array out of it.

 

The relatively new command inAreaArray looked promising at first but unfortunately it doesn't recognize items, weapons and magazines (I couldn't do it at least).

 

Does anyone know more?
 

Thanks a lot!

 

 

 

Share this post


Link to post
Share on other sites
27 minutes ago, Undeceived said:

The relatively new command inAreaArray looked promising at first but unfortunately it doesn't recognize items, weapons and magazines (I couldn't do it at least).

 

 

That's probably because those items are in virtual containers called "weaponHolders". Look for the  "groundWeaponHolder" or "WeaponHolderSimulated" types of objects, and then check their content.

Warning : it's boring. ^^

 

But I probably wrote something like that for Ravage already - I'll take a look and see if I can find some usefull bits of code.

  • Thanks 1

Share this post


Link to post
Share on other sites

in the meantime you can try this

 

_stuff = [[],[],[],[]]; 

_objs = vehicles;

_objs inAreaArray _trigger apply 
{
	(_stuff select 0) append (weaponCargo _x);
	(_stuff select 1) append (magazineCargo _x);
	(_stuff select 2) append (itemCargo _x);
	(_stuff select 2) append (backpackCargo _x);
};

 

_stuff will contain the output. i used "vehicles". if you are using a trigger that will be activated to get the items you could also use the "thisList" variable inside the onActivation line of the trigger to get every object insdie the trigger area instead of checking all present vehicles in the mission.

 

you could also filter that by class. some examples

 

//to only check certain classes based on parent class do: 
_objs = vehicles select {_x isKindOf "Car"}; 

//or explicit classes: 
_objs = vehicles select {typeOf _x in ["GroundWeaponholder", "GroundWeaponholder_Scripted", "WeaponHolder_Simulated"]};

//or by string search
_objs = vehicles select {toLower (typeOf _x) find "weaponholder" > -1};

 

that's just some quick and dirty examples though. not tested ingame.

Share this post


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

in the meantime you can try this

 


_stuff = [[],[],[],[]]; 

_objs = vehicles;

_objs inAreaArray _trigger apply 
{
	(_stuff select 0) append (weaponCargo _x);
	(_stuff select 1) append (magazineCargo _x);
	(_stuff select 2) append (itemCargo _x);
	(_stuff select 2) append (backpackCargo _x);
};

 

Thanks badbenson, I tried out this code but unfortunately the vehicles thing didn't work, so _stuff didn't have anything. As it seems to me, there are no vehicles in the trigger (I dropped an item, a mag and a rifle).

 

Your explanations after this code were too much for my brain - couldn't understand it - sorry. :icon_biggrin:

 

 

 

 

EDIT:

_objs = vehicles select {_x isKindOf "Car"};

 

worked when I placed a quad. But searching for the weaponholders didn't work.

Share this post


Link to post
Share on other sites

@Undeceived, use this function:

Spoiler

private _allStuff = [
	[], // Weapons
	[], // Magazines
	[], // Items
	[] // Backpacks
];

params [
	["_trigger", objNull, [objNull]]
];

if ((isNull _trigger) or {(typeOf _trigger) != "EmptyDetector"}) exitWith {_allStuff};

private ["_className", "_classNames", "_index", "_quantities", "_quantity", "_stuff", "_stuffOfType", "_weaponHolder", "_weaponHolders"];

_weaponHolders = (nearestObjects [_trigger, ["WeaponHolder", "WeaponHolderSimulated"], selectMax ((triggerArea _trigger) select [0, 2])]) select {_x inArea _trigger};

{
	_weaponHolder = _x;

	{
		_classNames = _x select 0;
		_quantities = _x select 1;

		_stuffOfType = _allStuff select _forEachIndex;

		{
			_className = _x;
			_quantity = _quantities select _forEachIndex;

			_index = _stuffOfType findIf {(_x select 0) == _className};

			if (_index >= 0) then {
				_stuff = _stuffOfType select _index;

				_stuff set [1, (_stuff select 1) + _quantity];
			} else {
				_stuffOfType pushBack [_className, _quantity];
			};
		} forEach _classNames;
	} forEach [
		getWeaponCargo _weaponHolder,
		getMagazineCargo _weaponHolder,
		getItemCargo _weaponHolder,
		getBackpackCargo _weaponHolder
	];
} forEach _weaponHolders;

_allStuff

 

Usage:

_stuff = [_trigger] call fnc_getStuffInsideTrigger;

Example of result:

[[["hgun_Pistol_heavy_01_F",5]],[["11Rnd_45ACP_Mag",2]],[["H_MilCap_gry",3],["V_BandollierB_blk",1]],[["B_Kitbag_rgr",2]]]
  • Like 1
  • Thanks 1

Share this post


Link to post
Share on other sites

@Undeceived you need to use the right input array. i didn't read the whole function by Schatten but he uses nearestObjects using the trigger properties to get the right input. so it'll probably work better for what you are searching for, if my stuff confuses you.

 

of course you could just modify my version like this (just for completeness' sake)

_objs = (nearestObjects [_trigger, ["All"], selectMax ((triggerArea _trigger) select [0, 2])]) select {_x inArea _trigger}; //taken from Schatten's code

but his function also gives you an amount for each item while mine just uses doubles (class string for each individual item) which you probably want. so depends on what you need really.

 

just to add something i have noticed debugging, in case someone else finds the useful. these are the classes i found in the config that have the word weaponholder in them. so if you are still not catching any of the ones you want with any of this code you might wanna try these classes for the filter.

 

"GroundWeaponHolder",
"GroundWeaponHolder_Scripted",
"Library_WeaponHolder",
"WeaponHolder",
"WeaponHolder_Single_F",
"WeaponHolder_Single_limited_item_F",
"WeaponHolder_Single_limited_magazine_F",
"WeaponHolder_Single_limited_weapon_F",
"WeaponHolderSimulated",
"WeaponHolderSimulated_Scripted"

didn't have time to find out what those are used for. and several of those are probably parent classes. maybe someone knows more. might be used by Eden when you place a single item maybe.

 

  • Like 1

Share this post


Link to post
Share on other sites

@bad benson

 

Cool, thanks for the addition / change.

 

When using this, the code worked:

 

_trigger = myCollectorTrigger;
_stuff = [[],[],[],[]]; 

_objs = (nearestObjects [_trigger, ["All"], selectMax ((triggerArea _trigger) select [0, 2])]) select {_x inArea _trigger}; //taken from Schatten's code

_objs inAreaArray _trigger apply 
{
	(_stuff select 0) append (weaponCargo _x);
	(_stuff select 1) append (magazineCargo _x);
	(_stuff select 2) append (itemCargo _x);
	(_stuff select 3) append (backpackCargo _x);
};

 

The only problem left now is that all stuff that the units in the trigger have (and also the stuff that is in vehicles) is also added to the arrays. :icon_biggrin: Is there a way to exclude everything so that only the stuff on the ground is collected?

 

 

 

EDIT:

 

14 hours ago, bad benson said:

but his function also gives you an amount for each item while mine just uses doubles (class string for each individual item) which you probably want. so depends on what you need really.

 

Btw. this is what I need: One individual string for every item. :icon14:

Share this post


Link to post
Share on other sites

@Undeceived yes. that's what the filtering is all about.

 

_objs = (nearestObjects [_trigger, ["All"], selectMax ((triggerArea _trigger) select [0, 2])]) select {_x inArea _trigger};

 

i thought you wanted everything so i used "All". you should first try using the array that Schatten used in his function. like this

 

_objs = (nearestObjects [_trigger, ["WeaponHolder", "WeaponHolderSimulated"], selectMax ((triggerArea _trigger) select [0, 2])]) select {_x inArea _trigger};

pretty sure that will give you all fo it. if not try some of the above mentioned classes. i think though that these two are the main parent classes, so it should work.

 

  • Like 1
  • Thanks 1

Share this post


Link to post
Share on other sites

bad benson, yeah, that did the trick. Many thanks, man!

 

 

 

 

To summarize the thread for mission designers that might have the same question:

 

With this code you can create an array with items, magazines, weapons and backpacks that are laying on the ground in a trigger area:

//Code by bad benson with elements of Schatten's function:

_trigger = trigger_0; 
_stuff = [[],[],[],[]];  
 
_objs = (nearestObjects [_trigger, ["WeaponHolder", "WeaponHolderSimulated"], selectMax ((triggerArea _trigger) select [0, 2])]) select {_x inArea _trigger};  
 
_objs inAreaArray _trigger apply  
{ 
 (_stuff select 0) append (weaponCargo _x); 
 (_stuff select 1) append (magazineCargo _x); 
 (_stuff select 2) append (itemCargo _x); 
 (_stuff select 3) append (backpackCargo _x); 
};

 

To show the array:

hint str (_stuff);

 

@bad benson's code creates an array with classname strings for each individual item. E.g.:

 

[["hgun_P07_F"],["30Rnd_65x39_caseless_mag","30Rnd_65x39_caseless_mag","30Rnd_65x39_caseless_mag"],["FirstAidKit"],["B_AssaultPack_rgr_LAT"]]

 

 

 

If you need an array that looks like this:

 

[[["hgun_P07_F",1]],[["30Rnd_65x39_caseless_mag",3]],[["FirstAidKit",1]],[["B_AssaultPack_rgr_LAT",1]]]

 

then you can use @Schatten's function:

SCH_fnc_getStuffInsideTrigger = { 
 private _allStuff = [ 
  [], 
  [], 
  [],  
  []  
 ]; 
 
 params [ 
  ["_trigger", objNull, [objNull]] 
 ]; 
 
 if ((isNull _trigger) or {(typeOf _trigger) != "EmptyDetector"}) exitWith {_allStuff}; 
 
 private ["_className", "_classNames", "_index", "_quantities", "_quantity", "_stuff", "_stuffOfType", "_weaponHolder", "_weaponHolders"]; 
 
 _weaponHolders = (nearestObjects [_trigger, ["WeaponHolder", "WeaponHolderSimulated"], selectMax ((triggerArea _trigger) select [0, 2])]) select {_x inArea _trigger}; 
 
 { 
  _weaponHolder = _x; 
 
  { 
   _classNames = _x select 0; 
   _quantities = _x select 1; 
 
   _stuffOfType = _allStuff select _forEachIndex; 
 
   { 
    _className = _x; 
    _quantity = _quantities select _forEachIndex; 
 
    _index = _stuffOfType findIf {(_x select 0) == _className}; 
 
    if (_index >= 0) then { 
     _stuff = _stuffOfType select _index; 
 
     _stuff set [1, (_stuff select 1) + _quantity]; 
    } else { 
     _stuffOfType pushBack [_className, _quantity]; 
    }; 
   } forEach _classNames; 
  } forEach [ 
   getWeaponCargo _weaponHolder, 
   getMagazineCargo _weaponHolder, 
   getItemCargo _weaponHolder, 
   getBackpackCargo _weaponHolder 
  ]; 
 } forEach _weaponHolders; 
 
 _allStuff 
}; 

 

Show the result / call the function with:

hint (str ([trigger_0] call SCH_fnc_getStuffInsideTrigger));

 

 

Many thanks to you both, guys.

  • Like 1
  • Thanks 1

Share this post


Link to post
Share on other sites

Sorry for the double post:

 

bad benson's result array brought up a last question: 

There's a way to remove the brackets so that the array looks like this, isn't it?

 

["hgun_P07_F","30Rnd_65x39_caseless_mag","30Rnd_65x39_caseless_mag","30Rnd_65x39_caseless_mag","FirstAidKit","B_AssaultPack_rgr_LAT"]

 

Nevermind, I messed something up while writing the post above.

 

bad benson's array result looks like this: 

[["hgun_P07_F"],["30Rnd_65x39_caseless_mag","30Rnd_65x39_caseless_mag","30Rnd_65x39_caseless_mag"],["FirstAidKit"],["B_AssaultPack_rgr_LAT"]]
 

 

I checked it and for the achievement of my ultimate goal (fill the stuff into a crate) it's not needed to have all weapons+mags+items+backpacks in one array altogether.

 

This will put the output of bad benson's code into a container:

{crate addWeaponCargoGlobal [_x,1]; } forEach (_stuff select 0);
{crate addMagazineCargoGlobal [_x,1]; } forEach (_stuff select 1);
{crate addItemCargoGlobal [_x,1]; } forEach (_stuff select 2);
{crate addBackpackCargoGlobal [_x,1]; } forEach (_stuff select 3);


 

Share this post


Link to post
Share on other sites

note that, you could've done that with Schatten's script too. this could potentially also be faster. although formating it the way he did takes some resources too, running addXCargoGlobal only once for each type of item is less stuff to do in the second part of it all. i don't want this to get too confusing but for this purpose there is no real reason to have individual strings. maybe i'm missing something.

 

so with his output just do

{_crate addWeaponCargoGlobal _x} forEach (_stuff select 0);
{_crate addMagazineCargoGlobal _x} forEach (_stuff select 1);
{_crate addItemCargoGlobal _x} forEach (_stuff select 2);
{_crate addBackpackCargoGlobal _x} forEach (_stuff select 3);

 

  • Like 2

Share this post


Link to post
Share on other sites

Well, I slightly improved my function:

Spoiler

private _allStuff = [
	[], // Weapons
	[], // Magazines
	[], // Items
	[] // Backpacks
];

params [
	["_area", objNull, [objNull, ""]]
];

if ((_area isEqualType objNull) and {(isNull _area) or {(typeOf _area) != "EmptyDetector"}}) exitWith {_allStuff};
if ((_area isEqualType "") and {(_area == "") or {!(_area in allMapMarkers)} or {!((markerShape _area) in ["ELLIPSE", "RECTANGLE"])}}) exitWith {_allStuff};

private ["_className", "_classNames", "_index", "_predicate", "_quantities", "_quantity", "_stuff", "_stuffOfType", "_stuffType", "_values", "_weaponHolder", "_weaponHolders"];

_values = if (_area isEqualType "") then {
	[getMarkerPos _area, getMarkerSize _area]
} else {
	[ASLToAGL (getPosASL _area), (triggerArea _area) select [0, 2]]
};

_values params ["_areaPosition", "_areaSize"];

_weaponHolders = (nearestObjects [_areaPosition, ["WeaponHolder", "WeaponHolderSimulated"], selectMax _areaSize]) inAreaArray _area;

{
	_weaponHolder = _x;

	{
		_classNames = _x select 0;
		_quantities = _x select 1;

		_stuffType = _forEachIndex;

		_stuffOfType = _allStuff select _stuffType;

		_predicate = if (_stuffType == 1) then {
			{((_x select 0) == _className) and {(_x select 2) == _quantity}}
		} else {
			{(_x select 0) == _className}
		};

		{
			_values = if (_stuffType == 1) then {_x} else {[_x, _quantities select _forEachIndex]};

			_className = _values select 0;
			_quantity = _values select 1;

			_index = _stuffOfType findIf _predicate;

			if (_index >= 0) then {
				if (_stuffType == 1) then {_quantity = 1;};

				_stuff = _stuffOfType select _index;

				_stuff set [1, (_stuff select 1) + _quantity];
			} else {
				_values = if (_stuffType == 1) then {[_className, 1, _quantity]} else {[_className, _quantity]};

				_stuffOfType pushBack _values;
			};
		} forEach _classNames;
	} forEach [
		getWeaponCargo _weaponHolder,
		[magazinesAmmoCargo _weaponHolder, []],
		getItemCargo _weaponHolder,
		getBackpackCargo _weaponHolder
	];
} forEach _weaponHolders;

_allStuff

 

Now it can accept either trigger object or marker name. Also it counts ammo inside magazines.

Example of output:

[
    [["hgun_P07_F", 1], ["arifle_MX_ACO_pointer_F", 1], ["launch_NLAW_F", 1]],
    [["16Rnd_9x21_Mag", 1, 13], ["30Rnd_65x39_caseless_mag", 1, 27], ["Chemlight_green", 1, 1], ["30Rnd_65x39_caseless_mag", 2, 30]],
    [["FirstAidKit", 1], ["NVGoggles", 1], ["V_PlateCarrier2_rgr", 1], ["U_B_CombatUniform_mcam", 1], ["H_HelmetB_sand", 1]],
    [["B_AssaultPack_rgr_LAT", 1]]
]

You can handle this array using this code:

{_crate addWeaponCargoGlobal _x;} forEach (_stuff select 0);
{_crate addMagazineAmmoCargo _x;} forEach (_stuff select 1);
{_crate addItemCargoGlobal _x;} forEach (_stuff select 2);
{_crate addBackpackCargoGlobal _x;} forEach (_stuff select 3);
  • Like 1

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

×