Jump to content


  • Content Count

  • Joined

  • Last visited

  • Medals

Community Reputation

100 Excellent


About Muzzleflash

  • Rank
    First Sergeant


  • Interests
    Little of everything

Recent Profile Visitors

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

  1. Muzzleflash

    Which Release Licence?

    While they might use BI tools "under the hood", you are not using BI tools directly, in fact you are "just" using Arma 3 via. the EULA I guess. Of course this raises the question whether you have a license to do anything with a mission file .sqm at all - I guess it enters the same category as whether you may legally sell a save game.
  2. UPDATE: You might just want to wait it out. See .kju post below. Path finding is really one of those things you want the engine to do the grunt work of. --------------------------------------------------------------------- Graph problems are a vast area with plenty of theoretical and practical considerations. For your basic problem, there are many simple algorithms to find a path between two nodes. You might be able to do all you want using just a single algorithm. Define "anywhere else". Search algorithms that work for enclosed areas are often not so good for open areas and vica versa. So I would advise the following considerations: - I assume you are running this in SQF, so you might avoid doing calculations that could be done ahead of time. - How many nodes are there? What is the typical and the max? - I am guessing these nodes are particular to a specific building model/class And regarding your bonus challenge: you may want to relax that it is the shortest, and rather just have it be one of the shorter but not necessarily the best. This depends again on how many nodes, but the problem is known as the Travelling salesman problem which is well studied. Basically for around ~30 nodes it is just not practical anymore. If you have say, at most 20 nodes, you might just want to compute the best way to get to *any* destination, e.g. where to go next. For 20 nodes you just have to fill an 20*19/2 = 190 element array (a matrix). So you are at node #5 and want to get to #17. You look up in the array for #5 and destination #17 and it says #9. You go to #9, and look up again for #17 and it says #2. You go to #2, and it says #17, you go to #17. Congratulations you have arrived at your destination. The benefits of this approach is you don't really need to "compute" in SQF, you just look up so it is much faster. Though this approach does not scale so well 30 nodes might be doable too, but 100 nodes will require almost ~5000 elements in the array (this might actually also be doable....). If you only have a few nodes you are starting/ending from, and most are just "intermediates", then you can use an even smaller array. For you bonus challenge, I humbly suggest using a minimum spanning tree instead and walking around that instead. Some time ago for fun I tried that approach to create patrolling waypoints. In this example, the outer blue circle is the area to be observed, the red circles are "subtasks" making up teh area. The black dots, which are the waypoints, are placed first in each of the red circled areas, and indicates places with decent vegetation/concealment the problem should go to and observe from. Then the green lines indicate the minimum spanning tree, to reduce travelling times. https://imgur.com/a/9CBkg
  3. Muzzleflash

    Match numbers place increase

    So the inputs are Min and Max. Say the "steps" move us along the X-axis, and on the Y-axis we have the value. Using just a linear function where the Y value is the element position in the output: "Y = StepSize * X + Min" where X is the same as Index in this case, it might take a long time (many Index) to reach Y >= Max as you already observed. So rather than that, let us use a polynomial (second-degree) and drop the step size for now and just consider this perhaps: "Y = X^1.8" (this looks like this, https://www.wolframalpha.com/input/?i=y+%3D+x^1.8+where+0+<+x+<%3D+1 ). The thing we are looking for here is whether the "curve" itself looks right. The normal linear is "Y = X^1". This one makes it rise much slower in the start and much faster in the end; notice the midpoint for X=0.5 is only about Y=0.3. So half of the values would be in the first 30%. By increasing, e.g. to ^3, half would be in lower 10% of the value. To use this we just need to map our index to 0-1 and map the output to the proper value. So how many values? Well you can easily pick that yourself: NNJ_fnc_Populate = { params ["_min", "_max", "_count", ["_pow", 1.8]]; private _result = []; // We iterate from 0 to count-1 and need to divide by count-1 anyway private _countMinusOne = _count - 1; private _maxMinDiff = _max - _min; for "_i" from 0 to _countMinusOne do { // Normalize the X value to between 0 and 1 (inclusive) private _xVal = _i / _countMinusOne; // Compute the normalized Y-value private _yVal = _xVal ^ _pow; // Map the _yVal back to the desired range private _value = _min + _maxMinDiff * _yVal; _result pushBack _value; }; _result }; // So if you want a 1000 values. private _min = 0; private _max = 5000000; private _valuesA = [_min, _max, 1000] call NNJ_fnc_Populate; // Or you want 3000 values distributed but rounded, and using ^1.2 // Note, if you round with a power too multiple elements in the beginning may be the same, e.g. zeroes and ones. private _valuesB = ([_min, _max, 1000, 1.2] call NNJ_fnc_Populate) apply {round _x};
  4. Seems like this thread went off the rails, but it can still get back on tracks.
  5. Muzzleflash

    Credits Not As Intended

    I think the problem is that valign only works in some containing box. You assume that cutText operate on the entire screen as that box, but I think it just creates the box with the top in the center and then the bottom whatever height your text have. If you look at the example here at the bottom https://community.bistudio.com/wiki/Structured_Text#SQF_Code_Examples you can see they wrap size=1 text inside size=3 to demonstrate - that way the "box" will be at least 3 units large. Though my guess is that you cannot do that since cutText will still place the "main box" center and below. So my bet is you will need to use https://community.bistudio.com/wiki/cutRsc or some other command.
  6. Have you checked what the view distance on the server is? Some mods or scripts reduce this - have often occasionally seen something like if: (isDedicated) then { setViewDistance 500; }; being run from scripts in the mission.
  7. You could go with a custom debriefing section https://community.bistudio.com/wiki/Debriefing#Custom_Sections . I have used this to show lots of miscellaneous information, like distance travelled on foot, or in vehicle, amount of time spent talking on task force radio, etc.. But I would try this first addPlayerScores if you can settle with just fixing the kill statistics.
  8. Muzzleflash

    Insignia problem

    Since the original BIS function does not work in MP with non-addon based insignia image, I have modified them for proper MP/JIP. I have split them into a local and a global function: /* MF_fnc_setUnitInsignia Argument: Global Effect: Local Description: Sets unit insignia (e.g., shoulder insignia on soldiers) Parameter(s): 0: OBJECT - unit 1: STRING - CfgUnitInsignia class. Use an empty string to remove current insignia. Returns: BOOL - true if insignia was set */ #define DEFAULT_MATERIAL "\a3\data_f\default.rvmat" #define DEFAULT_TEXTURE "#(rgb,8,8,3)color(0,0,0,0)" params ["_unit", "_class", ["_forceLoad", false]]; private _isRefresh = _class isEqualTo "REFRESH"; if (_isRefresh) then { _class = _unit getVariable ["MF_fnc_setUnitInsignia_class", ""]; }; // --- load texture from config.cpp or description.ext private _cfgInsignia = [["CfgUnitInsignia", _class], configNull] call BIS_fnc_loadClass; // --- check if insignia exists if (configName _cfgInsignia != _class) exitWith { [ "'%1' is not found in CfgUnitInsignia. Available classes: %2", _class, ("true" configClasses (configFile >> "CfgUnitInsignia") apply {configName _x}) + ("true" configClasses (missionConfigFile >> "CfgUnitInsignia") apply {configName _x}) + ("true" configClasses (campaignConfigFile >> "CfgUnitInsignia") apply {configName _x}) ] call BIS_fnc_error; false }; private _set = false; // --- find insignia index in hidden textures { if (_x == "insignia") exitWith { // --- make it safe in scheduled isNil { // --- set insignia if not set if (_isRefresh or {_forceLoad} or {(_unit getVariable ["MF_fnc_setUnitInsignia_class", ""]) != _class}) then { _unit setVariable ["MF_fnc_setUnitInsignia_class", [_class, nil] select (_class isEqualTo ""), false]; _unit setObjectMaterial [_forEachIndex, getText (_cfgInsignia >> "material") call {[_this, DEFAULT_MATERIAL] select (_this isEqualTo "")}]; _unit setObjectTexture [_forEachIndex, getText (_cfgInsignia >> "texture") call {[_this, DEFAULT_TEXTURE] select (_this isEqualTo "")}]; _set = true; }; }; }; } forEach getArray (configFile >> "CfgVehicles" >> getText (configFile >> "CfgWeapons" >> uniform _unit >> "ItemInfo" >> "uniformClass") >> "hiddenSelections"); _set The global function: /* Argument: Global Effect: Global Description: Sets unit insignia (e.g., shoulder insignia on soldiers) Parameter(s): 0: OBJECT - unit 1: STRING - CfgUnitInsignia class. Use an empty string to remove current insignia. Returns: BOOL - true if insignia was set */ params ["_unit", "_class", ["_force", true]]; if (_class isEqualTo "REFRESH") then { _class = _unit getVariable ["MF_fnc_setUnitInsignia_class", ""]; }; // For remotes [_unit, _class, _force] remoteExecCall ["MF_fnc_SetUnitInsignia", -clientOwner]; // For JIPs _unit setVariable ["MF_fnc_setUnitInsignia_class", _class, true]; // We run it locally manually to get return value. // using REFRESH here after setVariable to ensure _force is respected. [_unit, "REFRESH", _force] call MF_fnc_SetUnitInsignia; To ensure proper loading for JIPs and also for player changing uniform, I run the following post-init: // Updates client insignias from broadcast data { private _insignia = _x getVariable ["MF_fnc_setUnitInsignia_class", ""]; if (not (_insignia isEqualTo "")) then { [_x, _insignia, true] call MF_fnc_setUnitInsignia; }; } forEach allUnits; // For simplicity only handle local player changing loadouts. E.g. not AI's that has later been changed by scripting. if (hasInterface) then { [] spawn { waitUntil {sleep 0.1; local player}; MF_fnc_setUnitInsignia_lastUniform = uniformContainer player; player addEventHandler ["InventoryClosed", { params ["_unit", "_targetContainer"]; private _curUniform = uniformContainer _unit; if (_curUniform != MF_fnc_setUnitInsignia_lastUniform) then { MF_fnc_setUnitInsignia_lastUniform = _curUniform; if (not (isNull _curUniform)) then { [_unit, "REFRESH", true] call MF_fnc_setUnitInsigniaGlobal; }; }; }]; }; }; The corresponding CfgFunction entry is: class CfgFunctions { class MF_Insignia { tag = "MF"; class Insignia { file = "functions"; class setUnitInsignia {}; class UnitInsignia_PostInit { postInit = 1; }; class setUnitInsigniaGlobal {}; }; }; };
  9. Muzzleflash

    Private variable in trigger?

    When you create the trigger store the bomber on it (using setVariable), and I recommend you move your activation code to a separate script: _trgr_bomber_1 setVariable ["Spatsiba_TriggerMan", _bomber, true]; _trgr_bomber_1 setTriggerStatements ["this", "[thisTrigger] execVM 'activateTriggerman.sqf';", ""]; Then you move the activation code to that script instead, and here you can the associated triggerman from the trigger. // This is activateTriggerMan.sqf params ["_trigger"]; private _bomber = _trigger getVariable "Spatsiba_TriggerMan"; if (not alive _bomber) exitWith {}; private _bomberGroup = group _bomber; hint 'trigger start'; _bomber selectWeapon '_bomber_weapon'; _bomber enableAI 'MOVE'; _bomber setUnitPos 'AUTO'; _bomberGroup setbehaviour 'COMBAT'; _bomber setCaptive false;
  10. Try with BattlEye turned off, it block non-whitelisted extensions (you can see if it did this in the launcher when starting).
  11. Muzzleflash

    Get objectID of players Map (MP)

    This is over in the more advanced scripting arena. I don't believe there is any such object id for the map item. Simply put you just have a generic map item in your inventory, no id, all maps are the same. So one basic approach would be to: whenever a player drops a map, 1. Store all marker info on the dropped container (even if you drop something on the ground a new "container" is made) 2. Remove all markers from the players "map screen" Then when someone takes from the container, you check if they take a map, if so: 1. Add all the markers to the takers "map screen" 2. Remove the data from the previous container Even then, this is not foolproof. Now the latter player have two maps. What happens when he drops one of them? Then the second one? Which is his real map? Because, AFAIK the lack of object ids this gets you into trouble. But the approach can work decently, it is the basic outline for how ACE detonators are implemented. First you should familiarize with the map commands, particularly, allMapMarkers and deleteMarkerLocal. Then you might want to check how ACE does it: https://github.com/acemod/ACE3/blob/master/addons/explosives/functions/fnc_onInventoryChanged.sqf
  12. Muzzleflash

    Copying IP from the launcher

    Agree, you shouldn't need to, though the launcher has never let me connect to a server if the game was already running. Have to do the stupid copy entire server info, then paste it somewhere so I can manually extract the IP and port.
  13. Here is my offering: MY_fnc_EnemySpawnLocation = { params ["_closeToOneOf", "_minDist", "_maxDist", ["_objDist", 3]]; _maxDist = _maxDist max (_minDist + 200); // Avoid impossible / hard to find location private _badPos = [0, 0, 0]; private _pos = _badPos; // Construct blacklist circles private _blacklist = _closeToOneOf apply { [getPos _x, [_minDist, _minDist, 0, false]] }; // Sigh... private _blacklist2 = _blacklist apply { [_x select 0] + (_x select 1) }; // Keep trying while {_pos distance _badPos < 1} do { _pos = [ selectRandom _closeToOneOf, _minDist, _maxDist, _objDist, 0, // No water 1, // Max Grad 0, // Don't have to be shore _blacklist, [_badPos, _badPos] ] call BIS_fnc_findSafePos; // BIS_fnc_findSafePos only applies blackList in initial phases might still find a bad location if (_blacklist2 findIf {_pos inArea _x} >= 0) then { _pos = _badPos; }; }; _pos }; Here is example of usage: private _spawnPos = [[player1, player2], 1000, 1500] call MY_fnc_EnemySpawnLocation; Here is an image of me creating 1000 markers on the position returned with two "players". The red area is the minimum distance, and the blue marks the maximum distance. Note that in the overlap there are many more points. This is because regardless of which player it picks, the overlapped area has a chance. If it is intended to spawn AI near players, this might in fact be an advantage since it is more likely they will spawn, still out of range, but near more players. Though if this is not desired, it is possible to workaround by using another approach. Depending on conditions, this ran take some time, e.g. if little land available for spawning, say on a small island like Utes above, so you might want to run this in a scheduled environment (eg. using spawn).
  14. I don't understand why you need to bother with the Eden IDs at all. Do you not care about ingame/Zeus spawned entities? Seems like you just want save/load functionality? Either you are: - Starting fresh mission: On mission start synchronize (assign) ids with all mission objects - Loading mission: Delete everything present in the mission (that you would normally assign IDs) and recreate from database info instead. Minor things that have to be handled differently is for instance playable units which you do not delete. Then regardless of above, synchronize any future ingame changes, either continually, or some custom save action/button (if you trust the server won't crash) for potential future load.
  15. Sorry, but there are so many things wrong with that code snippet. First of all, you already left the event handler when you used spawn and there was nothing afterwards. Your calls are basically useless. Inside the addAction code, you call into a new scope just to leave it. You could just write _exit = true; , but it would still not work because the action script runs in a different context and thus cannot access the same _exit . In fact that variable is most likely not defined on the same computer as the one your action runs on. For the second call, the reason it seems to have no affect, is again because you call into a new scope, and then you exit that scope bringing you back to the original one. Can you describe what your intended goal is? It looks like you want players to be able to toggle a radio that is somehow controlled by the server?