Dj Rolnik 29 Posted April 16, 2022 Hey everyone, I am working on a game mode idea that is loosely based on the idea of Dark Zones in The Division games. The game mode would be PvP and would revolve around both Player killing, collecting items and performing various tasks. I would like to create a system that would allow players to extract found items in exchange for points. The idea is that players collect items throughout the game (both by finding them on the map and looting them from other players) and may deposit them in certain "extraction zones" on the map in exchange for "points". Those points would stack up with all the items the players extracted. When the game ends, the points would have to be tallied including both the extracted loot as well as the one still in the players' inventory - the data would have to be pullable for the game summary somehow so that the best player can be chosen as the winner. So... a full list of what I'm going after, exactly: - multiple different loot-items worth a different amount of points - loot-items can be extracted in specific areas of the map one by one, possibly with an action that takes some time to complete - extracted loot-items are converted to points and awarded to the player (or a whole group if several members are working as part of one team). - if the player dies, he loses all of his points and is eliminated but the loot-items in his inventory can be looted by other players - exchanging the earned points OR loot-items for specific game items (ammo, meds, etc.) On a slightly different, but still related note, the game mode will feature a few separate factions, all with different goals during the game. Other players will have different goals and I would also like to reward them with points for stuff like: - collecting players' dog tags - collecting a different category of items found in the game - spending some time inside a specific area (researchers performing researcher things..) I believe those last three should be fairly easy once I have the reward system in place and working, since I can tweak the method I use for granting those points to players later on. How I roughly see it is twofold: - Either I assign variables to each player and adjust those variables according to the aforementioned actions and criteria - I exchange the items players extract for, say, a money item (in that case money would be the points equivalent to summarize the end game) Now the thing is, my scripting knowledge is probably insufficient for this task, so I would be very grateful for any tips or even some useful snippets of code that you guys could share with me. Any pointers and suggestions are highly welcome. Thanks! Adam Share this post Link to post Share on other sites
_foley 192 Posted April 16, 2022 Hej It looks like it's going to be a large project relatively to usual questions here but you seem to have a good idea of what you want to achieve which is a great start! Quote How I roughly see it is twofold: - Either I assign variables to each player and adjust those variables according to the aforementioned actions and criteria This is a solid approach, perhaps you can start working towards it and let us know when you encounter specific problems. Anyway, here's a few pointers: - https://community.bistudio.com/wiki/BIS_fnc_holdActionAdd - this is how you can implement an action that takes time - https://community.bistudio.com/wiki/Category:Command_Group:_Unit_Inventory - here's a collection of commands to create, read, delete, update unit inventory - https://community.bistudio.com/wiki/setVariable - this is how you can assign a variable to a specific unit (player) - To keep track of how many points is each item worth, you need to obtain the classnames of the items (i.e. use ctrl+c in Arsenal or https://community.bistudio.com/wiki/Arma_3:_Assets for vanilla items) and then you can construct a hashmap like so: lootValues = createHashMap; lootValues set ["FirstAidKit", 3]; // set first aid kit to be worth 3 points lootValues set ["Medikit", 10]; // set medikit to be worth 10 points lootValues get "FirstAidKit"; // returns 3 5 Share this post Link to post Share on other sites
Harzach 2517 Posted April 16, 2022 Great advice from @_foley (nice new avatar, btw). You seem organized and interested in learning. I'll throw in some very general advice - focus on one concept at a time. The folks who get frustrated and show up here asking for help with their spaghetti code are the ones who try to do everything at once without actually learning how to do anything correctly. When learning a new function/concept/whatever, I like to make a simple, single-task mission for it. That way, I'm thinking about the thing, and not all of the other things. Create a mission where you walk up to a flagpole and use a holdAction to receive a "Hello World" message. Then increase the complexity. Use the holdAction to add an item to your inventory. Or spawn an item in front of you. Or pass variables to and execute a script. At some point, you'll "get it" and can move on to the next concept. Soon, you'll start to "get" the bigger picture, and will see solutions for your more complex ideas. Good luck, have fun! 2 Share this post Link to post Share on other sites
Dj Rolnik 29 Posted April 17, 2022 Hey guys, Thank you very much for your kind responses! You are right, I should just get on it, start working and then see what comes out of it. I do have a cavemen-like idea of how to best approach it. Might be primitive, but I think I have a plan on how to get it done. I will post updates as I go. Cheers! 2 Share this post Link to post Share on other sites
Dj Rolnik 29 Posted April 17, 2022 Ok, so... I didn't spend too much time on it yet, but I got the basics done. I have decided to make it so that once the player secures his loot in an extraction point, it is removed from his inventory but an exact copy of it is created in a separate, distant box. I know, it is a very caveman-y solution, but I think I will go with it, unless it suddenly breaks. From that distant box I can run some commands that get the class names and amount of the items stored. Now here's where I got a bit stuck. I am trying to parse this data so that I can display it using a hintC command. So far I managed to get to work those two: magazineCargo chest2 -> ["some_item_class_name","some_item_class_name"] getMagazineCargo chest2 -> [["some_item_class_name"],[2]] Now I would like to turn it into a hintC in the format: Player name - total point value Item 1* - count - sum point value Item 2* - count - sum point value *(i don't want a class name, but the name of the object, but I think I know how to convert them later on, that is not an issue now) Problem I have is that I cannot seem to run the count command in any way that works. I was expecting to run a few of these that would count individual items and show them in this one neat prompt. However there is always some kind of error and I cannot sum the amount of items in the chest. Thanks! Share this post Link to post Share on other sites
Dj Rolnik 29 Posted April 20, 2022 Ok, I actually got it working using this: {_x == "some_item_class_name"} count magazineCargo chest2 <gets back to working> Share this post Link to post Share on other sites
Dj Rolnik 29 Posted April 20, 2022 Ok, I have a different issue now. I am currently feeding the contents of the chest to hintC, but I would like to avoid hinting items that are of value "0". To explain it clearer, there will be around 20 items to be found. Not all of them will be found by each player so I would like to hint only the ones that the player HAS found, that is, which variables return more than "0". I tried to look for a solution but could not find a way to SKIP a variable if it is equal to 0. As a bonus, it would be great if it was possible to sort the results descdending by the itemPoints value (after multiplying by the amount). Currently I have it set up as follows: // Variables _itemOneValue = 1000; _itemTwoValue = 2000; //Calculations _itemOne = {_x == "item_class_1"} count magazineCargo chest2; _itemOnePoints = _itemOne * _itemOneValue; _itemTwo = {_x == "item_class_2"} count magazineCargo chest2; _itemTwoPoints = _itemTwo * _itemTwoValue; //Formatting score _itemOneHint = format ["Item One: %1 - %2 Points", _itemOne, _itemOnePoints]; _itemTwoHint = format ["Item Two: %1 - %2 Points", _itemTwo, _itemTwoPoints]; //HintC format ["%1 - Points", _nick] hintC [ _itemOneHint, _itemTwoHint ]; Anyone willing to help? Thanks! Share this post Link to post Share on other sites
Dj Rolnik 29 Posted April 21, 2022 Anyone knows if I can "skip" a variable if it's value is equal to 0? In the aforementioned example, if itemOne = 0 then skip itemOneHint altogether so it does not show? Share this post Link to post Share on other sites
Harzach 2517 Posted April 21, 2022 There are a few ways, I'm sure. My first thought is to do something like: if (_itemOne > 0) then { _itemOneHint = format ["Item One: %1 - %2 Points", _itemOne, _itemOnePoints]; }; If _itemOne == 0 it will then skip the code block and move on. But then again, see the first line in my signature, then see @_foley's reply below. Share this post Link to post Share on other sites
_foley 192 Posted April 21, 2022 Variables like _itemOneValue, _itemTwoValue are usually a red flag. If you have a collection of items, you ought to use an array or hashmap so it's easy to do operations on all items and filter them. private _lootValues = createHashMap; _lootValues set ["FirstAidKit", 3]; // set first aid kit to be worth 3 points _lootValues set ["Medikit", 10]; // set medikit to be worth 10 points // Calculate item values private _presentItems = _lootValues apply { private _itemName = _x; private _itemValue = _y; private _itemCount = {_x isEqualTo _itemName} count magazineCargo chest2; [_itemName, _itemCount, _itemCount * _itemValue] }; // Filter out missing items _presentItems = _presentItems select {_x select 1 > 0}; // Prepare hint text private _hintLines = _presentItems apply { format ["%1 - %2 Points", _x select 0, _x select 2]; }; private _hintTitle = format ["%1 - Points", name player]; // Show hint _hintTitle hintC _hintLines; Code untested, let me know how it works. 2 Share this post Link to post Share on other sites
Dj Rolnik 29 Posted April 21, 2022 42 minutes ago, Harzach said: There are a few ways, I'm sure. My first thought is to do something like: if (_itemOne > 0) then { _itemOneHint = format ["Item One: %1 - %2 Points", _itemOne, _itemOnePoints]; }; If _itemOne == 0 it will then skip the code block and move on. Before I delve deeper into it and try to go with @_foley's approach, I am experiencing an error when going with the aforementioned method. For some reason I cannot hint the variable if I manipulate it beforehand. To be more precise, adjusting the formatting score section by adding the condition that you provided, the hintC command just says that the _itemOneHint is an undefined variable and points to the line _itemOneHint in the hintC section down below. 15 hours ago, Dj Rolnik said: // Variables _itemOneValue = 1000; _itemTwoValue = 2000; //Calculations _itemOne = {_x == "item_class_1"} count magazineCargo chest2; _itemOnePoints = _itemOne * _itemOneValue; _itemTwo = {_x == "item_class_2"} count magazineCargo chest2; _itemTwoPoints = _itemTwo * _itemTwoValue; //Formatting score if (_itemOne > 0) then { _itemOneHint = format ["Item One: %1 - %2 Points", _itemOne, _itemOnePoints]; }; _itemTwoHint = format ["Item Two: %1 - %2 Points", _itemTwo, _itemTwoPoints]; //HintC format ["%1 - Points", _nick] hintC [ _itemOneHint, _itemTwoHint ]; Share this post Link to post Share on other sites
Dj Rolnik 29 Posted April 21, 2022 1 hour ago, _foley said: Variables like _itemOneValue, _itemTwoValue are usually a red flag. If you have a collection of items, you ought to use an array or hashmap so it's easy to do operations on all items and filter them. private _lootValues = createHashMap; _lootValues set ["FirstAidKit", 3]; // set first aid kit to be worth 3 points _lootValues set ["Medikit", 10]; // set medikit to be worth 10 points // Calculate item values private _presentItems = _lootValues apply { private _itemName = _x; private _itemValue = _y; private _itemCount = {_x isEqualTo _itemName} count magazineCargo chest2; [_itemName, _itemCount, _itemCount * _itemValue] }; // Filter out missing items _presentItems = _presentItems select {_x select 1 > 0}; // Prepare hint text private _hintLines = _presentItems apply { format ["%1 - %2 Points", _x select 0, _x select 2]; }; private _hintTitle = format ["%1 - Points", name player]; // Show hint _hintTitle hintC _hintLines; Code untested, let me know how it works. Okay, it does work as intended. Thank you for that. The problem is... I barely understand anything out of it which makes it hard for me to iterate on... Nevertheless, I would require a few tweaks to this solution. 1. I would like to sum up all the point values into one total value that I could display in the heading of the hint 2. I cannot rely on the class names of items within hint, but rather on their display names so I would have to convert them somehow at some point of the script. I am only planning to have a maximum of 20 items with values so to be perfectly honest, if I had a choice, I would rather go with the simpler to understand approach, provided it works, of course... Share this post Link to post Share on other sites
_foley 192 Posted April 21, 2022 I introduced only 2 new things: - apply - select Take a look at wiki pages. These commands are very similar to count, which you used before. Share this post Link to post Share on other sites
Dj Rolnik 29 Posted April 21, 2022 It's not exactly the commands that I have issue with, but the complex structure of ambiguous references. I always had problems with understanding code that was all _x, _y, command names only and everything referenced everything. I will need some time to fully understand the solution you provided >.>. Share this post Link to post Share on other sites
Harzach 2517 Posted April 21, 2022 Indeed, my "solution" was not fully formed as I did not take into account the following code. Apply yourself to _foley's solution. The variables _x and _y are magic variables that do specific things in specific situations. Code loops and recursive functions use variables like this to represent whatever values are currently being iterated. So, in _foley's code, for example, apply is iterating through the hashMap _lootValues. _x is the current hash key (e.g. "FirstAidKit") and _y is the current hash value (e.g. 3). 2 Share this post Link to post Share on other sites
Dj Rolnik 29 Posted April 21, 2022 And what does private mean? It's a little confusing to me. Share this post Link to post Share on other sites
Harzach 2517 Posted April 22, 2022 https://community.bistudio.com/wiki/private Basically, it confines a local variable to the scope in which it is declared. Run this in the debug console: private _myVar = "systemChat"; call { systemChat format ["%1 from inner scope", _myVar]; private _myVar = "hint"; hint format ["%1 from inner scope", _myVar]; }; systemChat format ["%1 from outer scope", _myVar]; First, _myVar is declared as the string "systemChat". Next, we call a bit of code that: prints a systemChat that says "systemChat from inner scope" - _myVar still holds the string "systemChat" redeclares _myVar as the string "hint" in this scope prints a hint that says "hint from inner scope" Finally, we print another systemChat that says "systemChat from outer scope". In general, it is used to prevent local variables from being redefined in inner scopes, though as you can see, it can be used to do exactly that if necessary. But variable names are functionally infinite, so there really is no reason to reuse them. Clear as mud? 1 Share this post Link to post Share on other sites
Dj Rolnik 29 Posted April 22, 2022 I think so. So technically I can use the same variable multiple times depending on where and how I call them as long as I maintain the proper structure. I will think about it and try to do some more work in the coming days. Muchas Gracias! Share this post Link to post Share on other sites
Dj Rolnik 29 Posted April 22, 2022 If I want to also display a total value of points for all accumulated items, would this be enough? _totalItemsValue = _presentItems * _itemValue Another question: If in the hint I do not want to display class names but rather predefined text strings, can I do this? (writing this form work, cannot test at home!) - Create a separate hashmap with class names and their corresponding display names I want: private _lootNames = createHashMap; _lootNames set ["FirstAidKit", "FAK Test Display Name"]; _lootNames set ["Medikit", "MED Test Display Name"]; then add a variable to the _presentItems array that I could call from the new hashmap? // Calculate item values private _presentItems = _lootValues apply { _itemName = _x; _itemValue = _y; _itemCount = {_x isEqualTo _itemName} count magazineCargo chest2; _itemDisplayName = lootNames get _x; [_itemName, _itemCount, _itemCount * _itemValue, _itemDisplayName] }; and finally refer to it in the hint? // Prepare hint text private _hintLines = _presentItems apply { format ["%1 - %2 Points", _x select 3, _x select 2]; }; private _hintTitle = format ["%1 - %2 Points", name player, _totalItemsValue]; I may have messed something up, I feel... Share this post Link to post Share on other sites
_foley 192 Posted April 22, 2022 Yes, that's exactly right! About total value, you'll have to sum the points while you loop over _presentItems. 1 Share this post Link to post Share on other sites
Dj Rolnik 29 Posted April 22, 2022 5 minutes ago, _foley said: Yes, that's exactly right! About total value, you'll have to sum the points while you loop over _presentItems. Oh God, I swear I almost felt your excitement there 😄 I almost took brain damage while trying to figure this stuff out but it's cool to finally understand something ^^" When I get back home I will try to put it into practie! 1 Share this post Link to post Share on other sites
Harzach 2517 Posted April 22, 2022 13 hours ago, Dj Rolnik said: So technically I can use the same variable multiple times depending on where and how I call them as long as I maintain the proper structure. Sure, but again, there's no good reason to reuse variable names in a script. It's not what private is for, exactly, and it's kind of a bad idea. I was just hoping to illustrate how it works. Here's a good quote on the subject from @Dedmen: Quote When you access a local variable, Arma searches current scope, and then goes through all the parent scopes till it finds a variable with that name. If it doesn't find one, it either creates a new one in the current scope (when using _var=..) or returns nil. private keyword just disables that lookup and forces Arma to only look in the current scope, and ignore the parents. Share this post Link to post Share on other sites
Dj Rolnik 29 Posted April 23, 2022 21 hours ago, _foley said: Yes, that's exactly right! About total value, you'll have to sum the points while you loop over _presentItems. Ok well, I spoke too soon. Turns out I am still too much in the dark when it comes to understanding it as I cannot figure out how to do the total value thing. I tried making new sections where I apply new code to the already filtered items and I tried to pull this data out somehow, even trying to change the _hintTitle to the same "apply" structure but apparently I cannot do that in the header of the hint? I am clueless and it hurts my ego to ask for a ready-to-go solution, so I would like to ask for a bit clearer explanation on where the heck I would put this total thing. Just to get on the same page, let me throw in the actual final code without placeholder variables and such, to make it easier to follow. // Display names hashmap _lootNames = createHashMap; _lootNames set ["ARMST_ART_control", "Altered Wheel"]; _lootNames set ["ARMST_ART_black_angel", "Angel"]; // Loot values hashmap _lootValues = createHashMap; _lootValues set ["ARMST_ART_control", 2000]; _lootValues set ["ARMST_ART_black_angel", 1000]; // Calculate item values _presentItems = _lootValues apply { _itemName = _x; _itemValue = _y; _itemCount = {_x isEqualTo _itemName} count magazineCargo chest1; _itemDisplayName = _lootNames get _x; [_itemName, _itemCount, _itemCount * _itemValue, _itemDisplayName] }; // Filter out missing items _presentItems = _presentItems select {_x select 1 > 0}; /*_sumScore = */ // Prepare hint text _hintLines = _presentItems apply { format ["%1: %2 - %3 RUB", _x select 3, _x select 1, _x select 2]; }; _hintTitle = format ["%1 - %2 RUB", name player/*, _sumScore*/]; // Show hint _hintTitle hintC _hintLines; // Hide regular hint at the end hintC_arr_EH = findDisplay 72 displayAddEventHandler ["unload", { 0 = _this spawn { _this select 0 displayRemoveEventHandler ["unload", hintC_arr_EH]; hintSilent ""; }; }]; It all seems to make sense when I read it, but for the love of me, I cannot process this and create it on my own. Share this post Link to post Share on other sites
Dj Rolnik 29 Posted April 23, 2022 Ok, small update is that I managed to grab the total value of items and throw it into the hint Title, but I haven't yet added all the values. So far it only cycles through them (I assume) and then shows the last one. // Filter out missing items _presentItems = _presentItems select {_x select 1 > 0}; _sumScore = {_x select 2} forEach _presentItems; // Prepare hint text _hintLines = _presentItems apply { format ["%1: %2 - %3 RUB", _x select 3, _x select 1, _x select 2]; }; _hintTitle = format ["%1 - %2 RUB", name player, _sumScore]; So yeah, I do not know how to loop that so that I can add all those values together. Share this post Link to post Share on other sites
Harzach 2517 Posted April 23, 2022 It's already looping/iterating through the array (that's what forEach does), but I think maybe @_foley forgot to add each new value to _sumScore: _sumScore = {_sumScore + (_x select 2)} forEach _presentItems; 1 Share this post Link to post Share on other sites