dreadedentity 278 Posted October 19, 2014 Hello all, I didn't think I'd be writing another code snippet so soon! I just finished writing an extremely simple loot system for single player so I thought I'd show it off. Below is a video I just recorded, and below that will be the code. I will be privately improving this and re-writing some of the core code to be used in multiplayer missions. Enjoy! _distanceToSpawn = [_this, 0, 300, [0]] call BIS_fnc_param; _sleepTimer = [_this, 1, 10, [0]] call BIS_fnc_param; while {true} do { _positionArray = []; _buildingArray = nearestObjects [player, ["house"], _distanceToSpawn]; { _positionArray pushBack ([_x] call BIS_fnc_buildingPositions); }forEach _buildingArray; { _element = _forEachIndex; { if (({(typeOf _x) == "Sign_Arrow_Blue_F"} count (nearestObjects[player,["Sign_Arrow_Blue_F"], 1])) == 0) then { _newMarker = createMarker [format ["%1_%2", _element, _forEachIndex], _x]; _newMarker setMarkerShape "ICON"; _newMarker setMarkerType "mil_dot"; _loot = createVehicle ["Sign_Arrow_Blue_F", _x, [], 0, "CAN_COLLIDE"]; [_newMarker, _loot, _distanceToSpawn] spawn { waitUntil {player distance (_this select 1) > (_this select 2)}; deleteVehicle (_this select 1); deleteMarker (_this select 0); }; }; }forEach _x; }forEach _positionArray; sleep _sleepTimer; }; //Framework by DreadedEntity //I'll have to ask anybody that uses this code, or any parts of this code, to not delete these comments And, lastly, as always, I'll always do my best to answer any questions people might have. Share this post Link to post Share on other sites
jshock 513 Posted October 19, 2014 Looks like it could be a cool system to run :ok: Share this post Link to post Share on other sites
Losert 10 Posted October 19, 2014 Tried this baby out yesterday and it works like a charm 10/10 would download again. Share this post Link to post Share on other sites
iceman77 18 Posted October 19, 2014 (edited) Thanks Dread this is fantastic. I figured a practical example was needed, so I modified your code a bit. I created a weapon objects array from the config and added an optional debug parameter for markers and to diag_log the item + position. Cheers. Example Mission: Notes: /* ************ ** Author ** ************ - Dreadentity (modified by Iceman77) ***************** ** Description ** ***************** - Spawn random weapons inside buildings within a given radius of the player - Refresh the positions and loot every so often *********** ** Notes ** *********** - Some tinkering may be required to get the weapon objects to sit perfectly flat onto the floor. - I used BIS_fnc_selectRandom because it's clean. However there may be better ways to random, for more "even" distribution of the weapon objects.* * I say this because back in Arma2 the function was a tad wonky. It may have been optimized by now though. **************** ** Parameters ** **************** _this select 0 - <NUMBER> spawn radius _this select 1 - <NUMBER> refresh timer _this select 2 - <BOOL> debug markers + diag_log weapon object and position ( OPTIONAL ) ******************** ** Usage Examples ** ******************** [200, 600, true] spawn DREAD_fnc_lootSpawn; [100, 300] spawn DREAD_fnc_lootSpawn; */ fn_lootSpawn.sqf private ["_distanceToSpawn","_sleepTimer","_lootArray","_cfgArray","_item","_positionArray","_buildingArray","_element","_newMarker","_loot"]; _distanceToSpawn = [_this, 0, 300, [0]] call BIS_fnc_param; _sleepTimer = [_this, 1, 10, [0]] call BIS_fnc_param; _debug = [_this, 2, false, [true]] call BIS_fnc_param; _lootArray = []; _cfgArray = "( (getNumber (_x >> 'scope') >= 2) && {getText (_x >> 'vehicleClass') in ['WeaponsPrimary','weaponsSecondary','weaponsHandGuns'] && {_lootArray pushBack ( configName _x ); true} } )" configClasses (configFile >> "CfgVehicles"); while { true } do { _positionArray = []; _buildingArray = nearestObjects [player, ["house"], _distanceToSpawn]; { _positionArray pushBack ([_x] call BIS_fnc_buildingPositions); }forEach _buildingArray; { _element = _forEachIndex; { _item = _lootArray call BIS_fnc_selectRandom; if (({(typeOf _x) in _lootArray} count (nearestObjects[player,[ _item ], 1])) == 0) then { if ( _debug ) then { _newMarker = createMarker [format ["%1_%2", _element, _forEachIndex], _x]; _newMarker setMarkerShape "ICON"; _newMarker setMarkerType "mil_dot"; diag_log format ["%1 @ %2", _item, _x]; } else { _newMarker = ""; }; _loot = createVehicle [_item, _x, [], 0, "CAN_COLLIDE"]; [_newMarker, _loot, _distanceToSpawn] spawn { waitUntil {player distance (_this select 1) > (_this select 2)}; deleteVehicle (_this select 1); deleteMarker (_this select 0); }; }; }forEach _x; }forEach _positionArray; sleep _sleepTimer; }; //Framework by DreadedEntity //I'll have to ask anybody that uses this code, or any parts of this code, to not delete these comments Also, not sure why it's needed to check the nearest objects (1 meter) count. Couldn't it just be: private ["_distanceToSpawn","_sleepTimer","_lootArray","_cfgArray","_item","_positionArray","_buildingArray","_element","_newMarker","_loot"]; _distanceToSpawn = [_this, 0, 300, [0]] call BIS_fnc_param; _sleepTimer = [_this, 1, 10, [0]] call BIS_fnc_param; _debug = [_this, 2, false, [true]] call BIS_fnc_param; _lootArray = []; _cfgArray = "( (getNumber (_x >> 'scope') >= 2) && {getText (_x >> 'vehicleClass') in ['WeaponsPrimary','weaponsSecondary','weaponsHandGuns'] && {_lootArray pushBack ( configName _x ); true} } )" configClasses (configFile >> "CfgVehicles"); while { true } do { _positionArray = []; _buildingArray = nearestObjects [player, ["house"], _distanceToSpawn]; { _positionArray pushBack ([_x] call BIS_fnc_buildingPositions); }forEach _buildingArray; { _element = _forEachIndex; { _item = _lootArray call BIS_fnc_selectRandom; if ( _debug ) then { _newMarker = createMarker [format ["%1_%2", _element, _forEachIndex], _x]; _newMarker setMarkerShape "ICON"; _newMarker setMarkerType "mil_dot"; diag_log format ["%1 @ %2", _item, _x]; } else { _newMarker = ""; }; _loot = createVehicle [_item, _x, [], 0, "CAN_COLLIDE"]; [_newMarker, _loot, _distanceToSpawn] spawn { waitUntil {player distance (_this select 1) > (_this select 2)}; deleteVehicle (_this select 1); deleteMarker (_this select 0); }; }forEach _x; }forEach _positionArray; sleep _sleepTimer; }; //Framework by DreadedEntity //I'll have to ask anybody that uses this code, or any parts of this code, to not delete these comments Edited October 19, 2014 by Iceman77 Oops, posted wrong edit Share this post Link to post Share on other sites
iceman77 18 Posted October 19, 2014 Updated the code a bit. Cheers. Share this post Link to post Share on other sites
Heeeere's johnny! 51 Posted October 19, 2014 "Extremely, extremely simple." And extremely cool! Nice work, Dread! :D Share this post Link to post Share on other sites
iceman77 18 Posted October 19, 2014 Yup. Just need an array of objects and you're all set. Fantastic script. Share this post Link to post Share on other sites
Heeeere's johnny! 51 Posted October 19, 2014 Thanks for your contribution, Iceman! :) Share this post Link to post Share on other sites
iceman77 18 Posted October 19, 2014 (edited) Meh! I was excited to see the script and put it to use immediately! Figured I'd post my edit since spawning weapons is a tad more "practical" than spawning the 3d marker objects. No doubt it'd be one of the first questions in the thread "How do I make it spawn actual weapons?". Anyhow, thanks for the pat on the back! :cool: Edited October 19, 2014 by Iceman77 Share this post Link to post Share on other sites
dreadedentity 278 Posted October 19, 2014 Thanks for the feedback guys, I'll still be adding multiplayer support for this (script should be run server-side only whenever I release), but this system should be sufficient for single-player missions as is (use iceman's edit for minimal self-tweaking :p ) I wrote this partly because I kept telling everyone I'm working on something, so I probably actually should(!) and because I wanted to see how many spawned threads you could have without impacting performance. The answer: A LOT (you can set the radius to 1000 and the refresh to ~5 will no obvious impact, despite waitUntil constructs checking their conditions every few frames) Share this post Link to post Share on other sites
iceman77 18 Posted October 19, 2014 hehe. I was actually wondering that myself when I seen your script. That's alot of waitUntil instances (potentially) lol. Share this post Link to post Share on other sites
dreadedentity 278 Posted October 19, 2014 Also, not sure why it's needed to check the nearest objects (1 meter) count. I'm glad you asked this Iceman, I added that check to make sure that more loot couldn't be spawned if something was already there (that's why it's only a 1 meter radius check) Share this post Link to post Share on other sites
iceman77 18 Posted October 19, 2014 (edited) Hmm. It's iterating through the positions, I don't see how there's even an opportunity for any duplicate spawn positions as no one position will be the same as another. Anyhow it worked fine for me without the check. No double spawning in same positions etc. I'll run some more tests though.. Edited October 19, 2014 by Iceman77 Share this post Link to post Share on other sites
Tajin 349 Posted October 20, 2014 (edited) Nice. However, It's so simple that it misses almost anything that a real loot system needs. ;) I guess it'll be quite useful for anyone who's trying to write his own system and doesn't know where to start. ps.: I wouldn't run the cleanup loop on every tick, for every object, no matter how small the impact is. Try using at least a 1 second delay. pps.: How about turning it into a real framework that calls a list of functions that can then be easily rewritten / adjusted based on the current requirements. Edited October 20, 2014 by Tajin Share this post Link to post Share on other sites
iceman77 18 Posted October 20, 2014 Yeah it'd be cool to have a loot system that spawned random furniture, tables and the like, and then weapons and stuff ontop. Instead of onto the ground hehe. Idk though, it's just that.. simple. Idk if he wants to reap the fruits of a more "sophisticated" framework. I think for spawning in weapons and such, it's fine and does a good job in any case. Share this post Link to post Share on other sites
spitfire007 10 Posted October 20, 2014 Thanks Iceman for pointing me to this thread. This is quite sophisticated for a beginner like me but I would like to know a little more about it. Can you tell me how to run debug ? You don't use an init.sqf as I think you are calling it via the functions.hpp with the postInit=1 ? Correct ? Share this post Link to post Share on other sites
iceman77 18 Posted October 20, 2014 (edited) Are you talking about for spawning the vehicles in garages in your other thread? Or are you talking about actually spawning loot (weapons) like the example I've posted above? The two are drastically different... In the example above (for spawning weapons) yes I used postInit = 1 to initialize the script upon mission start. In the LSInit it should be [400, 600, true] spawn DREAD_fnc_lootSpawn; for debugging. Edited October 20, 2014 by Iceman77 Share this post Link to post Share on other sites
Rydygier 1309 Posted October 20, 2014 (edited) I would suggest to get rid of nearestobjects check. If needed, could be used some array containing eg all already looted houses, to avoid re-looting same house. But the most I would strongly suggest to get rid of spawning independent thread each loot (especially with per frame waitUntil in each of them...). This makes that system potentially very resource hungry, in extreme cases leaving not much to other scripts, if anything at all. Note, no matter, how many threads you'll spawn, you'll keep same FPS, because sqfs are scheduled and will never get more computational power, than hardcoded limit. Instead, there will be no "room" for any other scripts execution, thus huge exec delays may occur. IMO much better would be to go every cycle through array containing every looted house and check distance from player for each, all in single thread (if you wish to re-loot the house after emptying it, a house should be substracted from that array after emptying). The less parallel threads, the better. Also, instead of single and same loot class, code could spawn randomly object classes from provided array, so user can set all possible loot objects (eg furniture, but that's much more complex to do reasonable). Edited October 20, 2014 by Rydygier Share this post Link to post Share on other sites
iceman77 18 Posted October 20, 2014 Also, instead of single and same loot class, code could spawn randomly object classes from provided array, so user can set all possible loot objects (eg furniture, but that's much more complex to do reasonable). Pretty much what I'm doing in post #4 with _lootArray Share this post Link to post Share on other sites
spitfire007 10 Posted October 20, 2014 @Iceman. Yes in this example. I figure if I can see how this works the other example will make sense too. I see this in LSInit. But ... no debug ? [200, 600, true] spawn DREAD_fnc_lootSpawn; Share this post Link to post Share on other sites
Rydygier 1309 Posted October 20, 2014 Pretty much what I'm doing in post #4 with _lootArray Indeed. BTW, nice way to get all weaponry. I have to remember configClasses for future uses. :) Share this post Link to post Share on other sites
iceman77 18 Posted October 20, 2014 _this select 2 aka true. That's enabled debug (for this version... in this thread). But like I said, the two scripts are drastically different. The one I posted in your other thread and the one(s) here. If you're referring to your garageSpawner script, then we'd best carry the conversation over there. That's just how drastically different the code is... given it was initially based off of dreads framework. New parameter indexes etc. Share this post Link to post Share on other sites
NeoArmageddon 958 Posted October 20, 2014 Hey guys, just stumbled upon this thread and I really like what I see. I also started my own loot-system but for multiplayer use and with somekind of persistence but I was very busy the last and couldn't continue with my own script. But maybe I can help you guys with some stuff I already archieved: First: Persistence would be cool. You check a house, see a magazine you don't need and go on. Later you find a weapon for this mag and want to get it... but it was already despawned. For this you could create a array with all spawned items, or even better: one Array for every house with all of it's (cached) positions and spawned items. If a house is out of range, the list of items gets updated (maybe a player took soemthing). If a house is "activated" the scripts checks the array for objects. If there are no objects yet, objects get spawned by the script above. Of there are objects in the array, the objects are respawned". To accelerate the checks for the buildings and the corresponding array, I would divide the arrays into larger arrays for every mapgrid. Like somekind of hashing. This can accelerate the looping through all houses in the distance. Also the cleanup could be designed much more ressource friendly :D Another nice trick: Remove the "while(true)"-loop and but the call in a trigger that activated itself every second. The script is called in non-scheduled environment and is much faster. If you want I can try to merge your spawning with my persistence system or we can create a repository at github or something for this. Share this post Link to post Share on other sites
Tajin 349 Posted October 20, 2014 Another nice trick: Remove the "while(true)"-loop and but the call in a trigger that activated itself every second. The script is called in non-scheduled environment and is much faster. This yet again proves that there's always a slight chance to learn something new in these forums, no matter what thread you look at. ;) Share this post Link to post Share on other sites
iceman77 18 Posted October 20, 2014 Shoot. I learn new shit everyday lol. There's just sooo much to learn here ;) Share this post Link to post Share on other sites