Jump to content


  • Content Count

  • Joined

  • Last visited

  • Medals

Community Reputation

10 Good

About Hypnomatic

  • Rank
    Private First Class

Contact Methods

  • Twitter

Recent Profile Visitors

The recent visitors block is disabled and is not being shown to other users.

  1. Phew, sorry for the long streak of inactivity, been a bit preoccupied for the past month or two. @Fennek: As far as exporting data goes, it's not 100% intuitive at the moment, especially considering there's a bit of a divide between the workshop branch and the github branch. I need to look at the rewrite I was working on a month ago however, as I believe that one may lend itself to this better. Will report back after I check. Now regarding optimal spacing:It really doesn't matter how far the objects are: it matters how long it takes to travel between them. Positions are calculated every time the game renders a frame, so the more frames that are rendered while the bullet is flying the more accurate the line. You can use the command setAccTime (http://community.bistudio.com/wiki/setAccTime) to slow down time so more frames are rendered per in game second. That will give you a better idea than any spacing should. Once again, sorry for being so out of the loop with ARMA for the last two months, will be trying to get fully caught back up in the next week!
  2. @Grumpy Old Man: Yep! As a matter of fact, it is almost exactly that (Below is the code for BIS_fnc_conditionalSelect): /* ...Same header rakowozz posted, but I excluded it... */ private ["_cond","_ret","_x"]; _cond = _this select 1; _ret = []; //to be filled with return array { //just call the condition directly //note the current element is already assigned to _x, and will be accessible in the condition if(call _cond) then {[_ret, _x] call BIS_fnc_arrayPush}; } foreach (_this select 0); _ret
  3. Hypnomatic

    From display name to classname

    Glad to be of help! Also good point on that error message; I got it once on my first run, then forgot to restart the mission to see if it was still happening when I finished the rest of the code. There is one minor modification I would make to your changes however; Basically combine your new check into the old check and use ARMA's clunky Lazy evaluation. It doesn't effect the actual output of this function at all, but I think the exitWiths inside the loop won't properly break the loop if they're nested inside another if statement. Not 100% positive that it actually will be behaving like that, and can't test it now, but it may be worth considering it as: Hypno_fnc_getName = { //Modified by Iceman77 private["_this","_displayName","_default","_out","_cfgWeapons","_cfgMagazines"]; _displayName = _this select 0; _default = [_this, 1, "ERROR: Item not found"] call BIS_fnc_param; _out = _default; _cfgWeapons = configFile >> "CfgWeapons"; _cfgMagazines = configFile >> "CfgMagazines"; for "_i" from 0 to count (_cfgWeapons) - 1 do { if ((isClass (_cfgWeapons select _i)) && {_displayName == getText(_cfgWeapons select _i >> "displayName")}) exitWith { _out = configName (_cfgWeapons select _i); }; }; if (_out != _default) exitWith {_out}; for "_i" from 0 to count (_cfgMagazines) - 1 do { if ((isClass (_cfgMagazines select _i)) && {_displayName == getText(_cfgMagazines select _i >> "displayName")}) exitWith { _out = configName(_cfgMagazines select _i); }; }; _out }; Also as far as naming conventions go, I tend to use hyp_ instead of Hypno_ just because I'm lazy and like to type as little as possible, but whatever you use is entirely up to you. Heck I wouldn't be offended if you just decided to remove the Hypno_/hyp_ from the name entirely if it's more convenient for you. EDIT: Just noticed that _name wasn't updated to _displayName in the private[];. Likely wouldn't ever cause issues, but worth fixing to be safe.
  4. Hypnomatic

    From display name to classname

    I came up with one possible solution (Documented heavily-ish for anyone who stumbles upon this page): /* Syntax: [_name] call _fnc_getFromName; [_name, _defaultValue] call _fnc_getFromName; Return Type: STRING (Classname of corresponding DisplayName, if found) Additional Note: Simply traverses CfgWeapons and CfgMagazines, and checks every entree to see if its what we're looking for. Returns the classname or an optional default value (Default default value is "ERROR: Item not found"). Features Modifications by Iceman77 */ _fnc_getFromName = { private["_this","_displayName","_default","_out","_cfgWeapons","_cfgMagazines"]; _displayName = _this select 0; _default = [_this, 1, "ERROR: Item not found"] call BIS_fnc_param; _out = _default; _cfgWeapons = configFile >> "CfgWeapons"; _cfgMagazines = configFile >> "CfgMagazines"; for "_i" from 0 to count (_cfgWeapons) - 1 do { if ((isClass (_cfgWeapons select _i)) && {_displayName == getText(_cfgWeapons select _i >> "displayName")}) exitWith { _out = configName (_cfgWeapons select _i); }; }; if (_out != _default) exitWith {_out}; for "_i" from 0 to count (_cfgMagazines) - 1 do { if ((isClass (_cfgMagazines select _i)) && {_displayName == getText(_cfgMagazines select _i >> "displayName")}) exitWith { _out = configName(_cfgMagazines select _i); }; }; _out }; Basically, it'll just iterate through CfgMagazines and CfgWeapons until it finds the displayName it's looking for. It'll take an optional second parameter as a default value, or returns "ERROR: Item not found" as the default default value. It's not perfect, but I think it does its job well enough. It probably goes without saying, but anyone can feel free to use/modify/etc this as they need!
  5. Not possible as far as I'm aware. The way I'm interpreting that post is that you can't ask the user to go download a separate addon of their own accord, but addons you distribute with the mission or campaign are fair game. CBA comes to mind as an example; you can't ask the user to download and install CBA, but if you get permission to include it with your submission it'd be fine. Once again this is my best guess, so I'd recommend waiting for a more official response.
  6. @Larrow: Yep, I've been looking into what else I can replace with macros for that exact reason. I actually tried writing many of these functions as Macros as well, and they predictably performed noticeably faster. I'll do more testing later, and if it's actually worth the performance I'll rewrite and release these as macros too. The two biggest reasons I put that idea on hold are optional parameters and recursion: There's no real intuitive way I could find to allow parameters to be excluded, so a few functions would become a bit more awkward. Also a few of these functions are recursive, and you can't really do recursion with macros. In hindsight I see a way to do it, but it's not as pretty as I'd like. Will do more testing later on! Also, one thing I "think" I observed is that functions in the global namespace are a bit slower to be accessed than those that are local. I haven't done any proper testing on this however, so it could have been any number of other conditions responsible. Will also do some testing on this later on and report back with what I find!
  7. Got a minor update for today! 2013-12-8 - Added kva_fnc_count and kva_fnc_forEach! (http://arma.dathypno.net/Function/kva_fnc_count/, http://arma.dathypno.net/Function/kva_fnc_forEach/) - Fixed minor bug with arr_fnc_resize not returning the reference if passed a positive length. - Added comment to arr_fnc_compare (Basically me rambling about how I found it funny string-comparison works so well on arrays). kva_fnc_count This guy's a super simple function, just returns the number of key-value pairs present in the KeyValueArray. Does not exclude anything tagged. kva_fnc_forEach Function to make traversing KeyValueArrays easier in certain circumstances, particularly if we have non-specific keys. The code you pass can include the following variables to reference the contents of the KVA: _x: Contains the current VALUE _forEachKey: Contains the current KEY _forEachIndex: Contains the current INDEX That's it for now! I'm probably next going to optimize the parsing of JSON, then switch gears to cleaning up and releasing two of my bigger functions: getting and setting an object's state via KeyValueArrays! Doing exactly this is probably the initial motivation for writing KeyValueArrays; I wanted a reliable way to completely serialize a player, vehicle, object, etc. as JSON, and pass it out of ARMA via an extension. The latest and greatest version I've written of this is likely coming soon!
  8. Okay, so now that it's a bit more reasonable of a time, I figure it's a good time for me to ramble off about some of the inner workings of this, if for no other reason for the sake of logging it for when I revisit this: Naming Conventions I used to follow the general naming convention of hyp_fnc_[functionName] for naming just about all of my functions, however my list of functions grew, and I wanted to make the name more directly reflective of its purpose and behavior. I'm also a sucker for descriptive prefixes/suffixes, so I adopted something to the effect of: hyp_fnc_[category]_[functionName]. This worked pretty well for me, however it was a bit too much typing for my taste. I finally decided that I really didn't care if I had a hyp_ prefix for every function, and decided to settle on [category]_fnc_[functionName]. I realize this technically leaves me more vulnerable to accidentally conflicting with other libraries, however we'll cross that bridge if we ever reach it. functionName and category are both in camelCase, however I may add an additional suffix from time to time, separated from category by _, but then camelCase itself. But that's a special case with reasoning that should be obvious if it ever occurs. File Structure / Includes / Etc. File structure is one of my biggest points of indecisiveness, as I very frequently change my mind on how exactly I want to organize my files. That said, I'm fairly comfortable sticking with the form I have now, which is effectively as follow: -- Mission Root -- hyp_Libraries #CfgFunction.h //Includes Config for all component folders Arrays #CfgFunctions.h //Includes Config for all "Arrays" functions #Headers.sqf //All macros or other forms of scripts to be included in every file in THIS particular folder fn_push.sqf //Begin files with each function's code ... ... Basically, we have a master #CfgFunctions.h file in the hyp_Libraries folder itself. This one #includes the #CfgFunctions.h of each category. Each of those category-specific #CfgFunctions.h hold the actual config entries for that folder/category. Each category-folder has a unique #Headers.sqf file that includes any Macros or code that should be repeated in every function. Macros #define handleNil(a) ( if true then {private "_v"; _v = a; if (!isNil("_v")) then {_v} else {nil} } ) This first macro came about when I was working on the array manipulation library. I wanted to make it work for ANY values stored in the array, and that includes nil. Nil is a tricky beast to work with, as assigning a variable to nil (ie _someVar = nil;) makes it indistinguishable from one that has never been declared, and causes an error to be thrown when you attempt to access that variable later on. Enter handleNil(). This is a simple macro that you pass a variable, or any value in general to. If the variable is valid, all is good and the macro simply returns its value. If passed a non-existent variable (a variable that equals nil), it will return nil (as created by the nil scripting command) instead of throwing errors. Simple, but necessary for any manipulations of data with unspecified datatypes. //param : "a" is an array, "b" is an index, "c" is a default value. If "a select b" is either out of bounds, or nil, c is returned. Otherwise "a select b" is returned #define param(a,b,c) ( if (count(a) > b && b >= 0) then { private "_v"; _v = a select b; if (!isNil("_v")) then {_v} else {c} } else {c} ) In working on these functions, I noticed that calling code in functions was a reasonable deal slower than directly executing the same code. As such, I wrote param(), a simple macro to get an index from an array. If the specified index is either out-of-bounds or nil, a default value is returned. It serves an awfully similar purpose to BIS_fnc_param, however trades the thoroughness of additional checks for a 90% increase in performance (ie macro is 10x faster than calling BIS_fnc_param); As a matter of fact, a few functions that accepted optional parameters were already smaller and faster than all of BIS_fnc_param itself, so using BIS_fnc_param decreased performance by over 100%. KeyValueArrays I swear I've written this same set of functions a dozen times now, but differently every time around. The intuitive design was always an array of 2 element arrays, each as a key and a value. It worked well enough, but searching for a key required a linear traversal of the array, which can reach O(n) in the worst case. I also tried a very simple linked list design, where each node looked something like this: [ ["class", "NODE"], ["key", "someKey"], ["value", 1234], ["next", <the next node>] ] The final design I've settled on is an array of keys, and an array of values, where each key corresponds to the value of the same index. Why this instead of the 2 element arrays? Simple, the engine command "find". I ran a few tests, and the extreme ends of my results were: When finding the 30th element in an array, linear traversal was 10x slower than the find command. When finding the 900th element in an array, linear traversal was 100x slower than the find command! So as you can see, find beat out linear traversal by quite a wide margin. Even a factor of 10x is massive when we're dealing with something that may be manipulated as frequently as an alternative array type. And finally, you may notice that the actual formatting of KeyValueArrays "objects" is as follows: [ ["class","KeyValueArray"], ["keys",[]], ["values",[]], ["tagged",[]] ] This is remnant of a combination of two main things; debug code to help me read the contents of the array more easily, and leftovers of my attempt at what I'm calling "Array Oriented Programming". It was basically using lots of arrays to sort of emulate OOP. It's on the backburner for now, but if it ever makes a resurgence I'd potentially maintain the same "Key-Value-Pairs" for each field, even though the keys are never actually accessed or read. Also, I mention the tagging system on the wiki page too, but it's my solution for deleting elements from the KeyValueArrays. Simply put, removing elements from an array by reference is not pretty, as you need to traverse the entire array every time you want to remove elements. That said, you can remove multiple elements in one pass with no additional impact on performance. That's where tagging comes in. Tag multiple elements if they should be removed, but don't *need* to be removed right away, and remove all of them in one well-performing swoop. So yeah, there's a quick delve into the inner workings of this library. I figure there's at least one or two guys out there who may find this interesting, and maybe a few who can offer suggestions or improvements!
  9. Hello all! I'm here to finally release the first batch of functions I've written for ARMA 3. I've been slowly accumulating a list of utilities and functions to solve miscellaneous tasks or problems since the release of the Alpha. A little while ago I decided I wanted to clean them up, document them well, and release them for all to use. One simple mini-wiki later and we're here! The full documentation, including downloads and installation instructions can be found HERE, however allow me to share a few of the highlights: Functions to add escape characters to strings, as well as strip them Functions to manipulate and handle arrays by reference more easily Functions to emulate a Key-Value (Associative) Array, complete with JSON encoding and decoding I am releasing all of this code under the very permissive BSD license, so you are more or less free to whatever you wish with this code. Use it, modify it, distribute it with your missions, it's just about all good! (Credit is always appreciated however.) If you have any issues, suggestions, comments, or criticism, please feel free to post it here! This is my first release of anything to quite this scale, so suggestions for improvement on the code, the site, etc. are very much so appreciated! Enjoy!
  10. Hypnomatic

    Array Error

    @HeliJunkie: Looks like this switch statement itself is returning a value stored in a variable outside of the pasted chunk of code. @LawlessBaron: You're missing a few commas. The ones I've noticed are missing in both arrays: - After "RH_kimber" and before nil - After "RH_g19" and before nil - After "RH_vp70" and before nil
  11. Listen vs Dedicated There are two ways to host a server in ARMA: as a "listen" server, or as a "dedicated" server. A listen server is one you host from right within your client: your computer will be acting as the host for all players in game, while you would also be presumably playing in game. A dedicated server is one you launch, usually on a separate machine in a datacenter, with no player in the same client. This server doesn't need to share any processing power with the graphics, user interface, or other features the player would interact with, so they are what you'd use for bigger servers. isServer vs isDedicated isDedicated: Returns true when client it runs on is hosting the game, and is a dedicated server. In practice, this will mostly means that there is no player being controlled by this client, so you would use this if you have code that should only run on a dedicated server, not a listen server. isServer: Returns true when the client it runs on is hosting the game. This is true on both listen servers and dedicated servers, so anything that needs to be run only on one client (for example, a global command for setting up the mission, ie spawning in vehicles). You basically need to get an understanding on when and where your code needs to be run, be it on every client, just the server, or some combination of the two. To list a few examples: Does it run on every client that has is connected to the server, but not the server? Then contain it within a: if (!isDedicated) then {...}; //Note the ! Does it run on only the server?: if (isServer) then {...}; etc. Global vs. Local There's another use of these terms for describing multiplayer locality, however that's a headache of its own for another time. Instead, I think Killzone Kid does a pretty good job of explaining this topic, so I'm going to simply point you to his tutorials: http://killzonekid.com/arma-scripting-tutorials-variables-part-1/ I'd say read that and the following articles, and you hopefully will get a good idea of how the different types of variables work. exitWith Finally, an if (...) exitWith {...}; statement will execute the code within the {}, then break out of the current scope. So as an example: //Your init.sqf //Anything that will happen on all clients, including the server, would go here if (isServer) exitWith {}; //If this computer is the server, stop executing this code. //Now anything after this will only be executed on computers that are not the server. If anyone sees anything wrong, misleading, or omitted, please tell me and I'll correct it. Rather tired while writing this so some of my points may be a bit off.
  12. typeName does exactly what you're looking for: http://community.bistudio.com/wiki/typeName Just as an example: _someVariable = []; if (typeName _someVariable == "ARRAY") then { //It's an array! } else { //It's not an array. };
  13. Very cool, I've been itching to see something to this effect get fully implemented! Just to give you a few places to look for possible further inspiration, NouberNou had been working on a something up this alley a bit ago, but I believe he's not actively worked on it for a while: http://forums.bistudio.com/showthread.php?134053-Carma-A-C-to-SQF-quot-native-quot-Interface And then for a bit of self-plugging, I threw together a very quick and crude concept for some manner of OOP-alike a bit ago in response to a thread: http://forums.bistudio.com/showthread.php?166558-256-bit-integers-and-doubles-Also-Create-a-reference-to-a-variable&p=2530812&viewfull=1#post2530812 It's not pretty, and I may have made a slipup in terminology or general programming concepts along the way, but it takes a bit of a different approach to things from your solution, so maybe it'll be interesting or possibly helpful. You seem to have all of your bases covered in that regard however, so I'm not too worried. Either way, looking forward to seeing what comes of this if you take it all the way!
  14. Very cool script Naught, thanks for posting it! I've been pretty swamped with real-life things for the past week and a half, so a lot of the functionality I have planned or wanted to implement is only partially done. Heck the mission in the Steam Workshop is a very shallow representation of what I have in mind, but I wanted to get something out the door. Despite this, I've just finished rewriting everything important to be faster, much cleaner, and hopefully more modular, and hopefully I'll publish it some point later tomorrow. I definitely will take a look at implementing some manner of your HSV calculations, as it does look very handy! And of course anything of yours I use will be duly credited.
  15. I'm pretty sure that that cursorTarget is being evaluated only when the addAction command runs. By that I mean that cursorTarget is basically running once: Whatever is in front of the player's cursor when the action is added is always going to be passed to the script. So if the player is looking at nothing when you add the action, you'll get an objNull in _this select 3 every time. If you add the action when a player is looking at something, _this select 3 will always return that unit, even once you're no longer looking at it. So I recommend assigning cursorTarget to a variable at the start of test.sqf, and you should be golden, ie: _targetPlayer = cursorTarget;