Sometime ago Rocket was making a big deal out of how the loot in DayZ SA would spawn on shelves and under furniture, in places you would usually expect to find something. So I thought to myself, is it possible to do this in Arma 3? Of course the answer to the question was “Yes” even before I started. What I got curious about was how easy it would be to make it work in Arma 3. And the answer is, not that easy.

Well, the code I wrote, I’m not happy with. It should have been much more straightforward, instead I ended up working around quite a few limitations. In Arma 2? This would probably be even more difficult since it lacks some commands and eventhandlers. I will include the whole code from the video at the end for anyone to play with. In the mean time let’s look at some of the limitations.

Arma 3 now has PhysX objects (think those come from ThingX class). Basically if you let such object loose it should behave accordingly to the laws of real Physics depending on object’s properties. The shelves rack I used is also a PhysX object. Weapons on the other hand are not separate objects. You don’t just spawn a rifle or a pistol. You have to put them in a weaponholder. Weaponholder is a storage container you can interact with.

There are different type of weaponholders in Arma 3. For example “GroundWeaponHolder” is a weaponholder that has no PhysX properties. If you spawn it in the air it will stay in the air. This happens to objects if you disable simulation with enableSimulation false command, they freeze.

Another weaponholder is “WeaponHolderSimulated”. The name suggests that it should fall down if it is spawned in the air, and in fact it does. And here comes the first problem. I could not place this type of weaponholder on a shelf because it would fall through. Now the reason for it could be that the rack does not have surfaces for individual shelves. There is only one surface and it is the top of boundingBox.

So I ended up using “GroundWeaponHolder”, because if I wedge it in the rack as if it placed on a shelf, it stays there. So this turned into pretty simple task, get offsets of shelves positions and create a “GroundWeaponHolder” at each position. But here comes another problem. Arma 3 will automatically delete empty weaponholders milliseconds after their creation. You must place something inside to stop the deletion. Fine for when you create an item on a shelf ready to be picked up. But what if you want to place item on the shelf from your inventory?

It would have been pretty easy if there was a type of weaponholder that does not get deleted. You simply leave it on a shelf. When player approaches it, he gets inventory operation action and everything is very simple. But there isn’t one as far as I know. You can mod one yourself, but I really would like to see what could be done with simple mission creation not modding. Another solution is for BIS devs to make one for everyone to use. But I don’t hold my hopes for this happening any time soon. I have already asked for an extremely simple modified C4 class, and it is just not happening.

Another problem is that weapon holder should only hold 1 item, because the size of shelf and the size of weaponholder do not match and you can end up with additional items visually hanging the air. There are however weaponholders that will only display the first item you put in, but unfortunatelly you can also put 100 other items in. I don’t think this is intended but I’m seriously don’t know anything anymore that goes with Arma 3.

Then yet another problem. If I attach weapon holder to PhysX object I cannot take or add items to it. I can see action menu, I can open inventory, but the item transfer does not work and event handlers are not firing. Again not sure if intended. So I ended up attaching weaponholders to the rack and then detaching them to make them operational. It worked, but wait!

The shelves rack can be moved. But the weaponholders will not move with it. On top even attached weaponholders would not move together with PhysX object. So I ended up continuously attaching them to the rack while the shelf was moving, and did this via collision detection. Thanks BIS we have eventhandlers for that. That worked. But main question remains, how to place item from inventory on a shelf?

Well, if you don’t yet know, when you open inventory, a “GroundWeaponHolder” is immediately created at your position and your inventory gets connected to it, it is the left column of inventory. If you delete this weaponholder while inventory is open, the inventory will close. If you close inventory and don’t put anything in the weaponholder, it will get deleted.

So in order to put item on the shelf it is enough to move the inventory created weaponholder to a new position, corresponding to shelf position. And thanks BIS again for PUT and TAKE event handlers it is possible to obtain the weaponholder object with a transaction. It is also possible to tell if another transaction is going to the same weaponholder and if so remove it from the shelf and put it on the ground. This is how I solved the “only single item per shelf weaponholder” problem. Not the best solution.

But this is not all, what if you knock over the rack, should the items fall off it? They should. It is ok, you can detect if the rack is knocked over, but to move weaponholders to the ground is a different story. You cannot assume that the Z of the new position will be 0. Because the rack might not be on the ground but on the floor of a garage, like in my case, where floor is raised, so the items will end up inside the floor. I did  just cut corners there. Took the Z from the rack -0.3 (half the width of a shelf). If it falls it “most likely” will fall flat. So here you go, I am not proud of this workaround and a little angry at the lack of some simple, useful commands in Arma.

I like the fact that Arma is like Lego or Meccano, if you don’t have exact piece, you can use other pieces. Sometimes I even enjoy figuring out workaround (if it looks pretty in the end). But in this case, it would have been better to have the exact pieces. Anyway, the code is below, good luck trying to figure out what I did there. TBH I would probably be trying to figure this out myself next time I look at it:

private ["_garage","_rack"]; _garage = "Land_i_Garage_V1_F" createVehicle position player; sH = [] spawn { cT = objNull; waitUntil {!isNull findDisplay 46}; findDisplay 46 displayAddEventHandler ["KeyDown", { if (_this select 1 in actionKeys "Gear") then { cT = cursorTarget; 0 = [] spawn { waitUntil {!isNull findDisplay 602}; waitUntil {isNull findDisplay 602}; cT = objNull; }; }; false }]; }; _rack = "Land_Metal_wooden_rack_F" createVehicle position player; _rack attachTo [_garage, [1.90198,-2.20996,0.881145]]; detach _rack; _rack setVariable ["offsets", [ [0,0,-0.25], [0,0,0.25], [0,0,0.75], [0,0,1.25] ], true]; _rack setVariable ["holders", [ objNull, objNull, objNull, objNull ], true]; _rack addEventHandler ["EpeContact", { _rack = _this select 0; { if (!isNull _x) then { _x attachTo [ _rack, (_rack getVariable "offsets") select _forEachIndex ]; }; } forEach (_rack getVariable "holders"); if (scriptDone sH) then { sH = _rack spawn { waitUntil {str velocity _this == "[0,0,0]"}; _z = ((getPosATL _this) select 2) - 0.3; _fall = (vectorUp _this) select 2 < 0.6; _holders = _this getVariable "holders"; { if (!isNull _x) then { detach _x; if (_fall) then { _x setVectorUp [0,0,1]; _fallpos = getPosATL _x; _fallPos set [2, _z]; _x setPosATL _fallPos; _x setVectorUp surfaceNormal _fallpos; _x setVariable ["shelf#", nil, true]; _holders set [_forEachIndex, objNull]; }; }; } forEach _holders; _this setVariable ["holders", _holders, true]; }; }; }]; player reveal _rack; player addEventHandler ["Take", { _holder = _this select 1; if (_holder getVariable ["shelf#", -1] < 0) exitWith {}; deleteVehicle _holder; }]; player addEventHandler ["Put", { _holder = _this select 1; if ( !isNull cT && {cT getVariable ["shelf#", -1] < 0} && { typeOf cT == "Land_Metal_wooden_rack_F" && player distance cT < 2.5 && (vectorUp cT) select 2 >= 0.6 } ) then { _holders = cT getVariable "holders"; { if (isNull _x) exitWith { _holder attachTo [ cT, (cT getVariable "offsets") select _forEachIndex ]; detach _holder; _holder setVariable ["shelf#", _forEachIndex, true]; _holders set [_forEachIndex, _holder]; cT setVariable ["holders", _holders, true]; closeDialog 0; }; } forEach _holders; } else { _holder setPosATL getPosATL player; _holder setVariable ["shelf#", nil, true]; }; }];

Enjoy,
KK

EDIT: If I were you I would not try to use it in MP for now (08 Dec 2013). I’ve just tested in on my dedicated server to only find out that one of the latest dev branch updates broke inventory operation… oh dear.

More: Tents