Jump to content


  • Content Count

  • Joined

  • Last visited

  • Medals

Everything posted by jwllorens

  1. Don't worry about using BIS_fnc_MP anymore. BIS_fnc_MP used to be a purely scripted way of executing code on remote machines, but as mentioned above, it lacked security and was slower than a purely engine based solution. So, BIS created remoteExec. remoteExec allows the mission maker to directly specify what clients can and cannot do in the description.ext, so you can make sure that nobody is running malicious code on your server or client from their computer. So what happened to BIS_fnc_MP now that we have remoteExec? Well, BIS_fnc_MP was basically just re-written so that it just calls remoteExec. There is no point in using it all when writing new code, they just re-wrote it to continue working but use remoteExec because it ensures that all old missions and stuff that used BIS_fnc_MP will still work. To use remoteExec, it is really easy. [_parameter1,_parameter2,_parameter3] remoteExec [myFunctionName,_targets,_jip]; _parameter1, 2, 3, are just the parameters that you want to pass to myFunction. Note that these parameters are passed as they exist on the local machine that is calling remoteExec, not how they will look on the target machine. So passing "player" as a parameter in remoteExec will retrieve the player on the local machine, THEN send it over to the target, and myFunction will execute code with the parameter referencing the player back on the machine that called remoteExec. If, however, myFunction contains something like the "player" command, it will retrieve the player within the function code on the target machine, and therefore player will reference the player on the target machine. myFunction is the function you want to execute on the target machine, and pass those parameters to. You can define functions in description.ext and just call them by name here. It works with BIS functions too. This is the easiest way to do this. note that myFunctionName needs to be a string. For example, "BIS_fnc_holdActionAdd" with the quotes like that. _targets defines where you want to execute the function. This is a very powerful parameter. You can put in all sorts of stuff here to target only the machine you want to run the code on. Use the number 0 to run the function everywhere. Use 2 to run the function on the server. Use ([0,-2] select (isMultiplayer && isDedicated)) to run the code on every machine with a player. You can also put an object in here, and the function will execute where the object is local, or specify a specific machine by using its ownerID. _jip is a little complex. I don't really have time to explain it now and don't really understand it myself.
  2. Alright, I haven't tested this, but thinking through the following script, I am pretty sure this is how it works. _variable1 = 5; _variable2 = _variable1; //_variable2 is now a copy of _variable1. Any change to either will have no effect on the other. _variable1 = "hello world"; hint str _variable2; //will display the number 5. //Arrays are a little different. _array1 = [[1,2,3],[4,5,6]]; _array2 = _array1; //_array2 and _array1 are both pointers to the array. Any change made to either _array1 or _array2 will be reflected by both variables. _array1 pushBack [7,8,9]; hint str _array1; //will obviously display [[1,2,3],[4,5,6],[7,8,9]] sleep 5; hint str _array2; //will also display [[1,2,3],[4,5,6],[7,8,9]] //we can also maintain pointers to the same array in different scripts, and therefore manipulate data in one script from another script. _array1 spawn { _array3 = _this; _array3 set [0,"Tom"]; _array3 set [1,"Dick"]; _array3 set [2,"Harry"]; }; sleep 5; hint str _array2; //will display ["Tom","Dick","Harry"] //what happens if we start changing the variables? _array2 = "sausages"; sleep 5; hint str _array1; //will hint ["Tom","Dick","Harry"] sleep5; hint str _array2; //will hint sausages. //So the array still exists out there, but _array2 no longer points to it. How can we destroy the array? _array1 = nil; //The array ["Tom","Dick","Harry"] is now gone and no longer in memory. //The array is not destroyed because we set the pointer _array1 to nil. //The array is destroyed because there are no more pointers that point to it. //What about other methods of getting and setting variables? myGlobalVariable = ["cheese","burger"]; //Now we have a global variable that points to ["cheese","burger"] //Lets see what happens if we start passing this global variable around all over the place. _myVar1 = missionNamespace getVariable "myGlobalVariable"; _myVar2 = myGlobalVariable; sleep 5; _myVar1 pushBack "with"; hint str myGlobalVariable; //will display ["cheese","burger","with"] sleep 5; _myVar2 pushBack "pickles"; hint str myGlobalVariable; //will display ["cheese","burger","with","pickles"] _myVar2 spawn { _this set [3,"tomatoes"]; }; sleep 5; hint str myGlobalVariable; //will display ["cheese","burger","with","tomatoes"] missionNamespace setVariable ["myGlobalVariable",["communism","capitalism"]]; //myGlobalVariable should now point to a different array, in this case, ["communism","capitalism"] hint str myGlobalVariable; //will display ["communism","capitalism"] //however, our array ["cheese","burger","with","tomatoes"] is not gone, it still exists in memory because we have some local variables pointing to it //this is important to note. _myVar1 and _myVar2 do not point to the myGlobalVariable pointer, they instead point directly to the original array. //setting the myGlobalVariable pointer to point at a new array does not redirect variables that were defined with _varName = myGlobalVariable sleep 5; hint str _myVar1; //will display ["cheese","burger","with","tomatoes"]; //but what if we want changes in an array done to an array to be unique to that variable and not reflected in all other variables pointing to the same array? //We make a copy of the array _myVar2 = + _myVar1; _myVar2 deleteAt 0; hint str _myVar1; //will display ["cheese","burger","with","tomatoes"] sleep 5; hint str _myVar2; //will display ["burger","with","tomatoes"] //note that using + makes a deep copy. Lets examine what that means using some new arrays. First we will redefine our old variables. _myVar1 = [["ham","burger"],["hot","dog"]]; _myVar2 = + _myVar1; _mySubArray = _myVar2 select 0; _mySubArray set [0,"tofu"]; hint str _myVar1; //will display [["ham","burger"],["hot","dog"]] sleep 5; hint str _myVar2; //will display [["tofu","burger"],["hot","dog"]]
  3. Is there a way to dynamically set an array element in a multidimensional array? For example, I have the following array: _myArray = ["hello",["my","name","is"],["frank",["and","i","like",["chicken"]]]] I know the structure of this array, but I want to be able to use one function to set any of the array elements by calling the function in this way: [_newValue,_elementPath] call fnc_setElement; so, I could do something like [_myArray,"hamburgers",[2,1,3,0]] call fnc_setElement; and the result would be: (_myArray == ["hello",["my","name","is"],["frank",["and","i","like",["hamburgers]]]]) //true or I could do [_myArray,"hate",[2,1,2]] call fnc_setElement; and the result would be: (_myArray == ["hello",["my","name","is"],["frank",["and","i","hate",["chicken]]]]) //true Now, I can do this by creating a string dynamically and then compiling it fairly easily, but I need this function to be fast so I don't want to compile at runtime. Is there a better way to do this that doesn't compile a string? Edit: I think I have an idea, but I can't test it right now. It depends on this question though: _arr = ["lonleyData"]; _data = (_arr select 0) select 0; What happens if I do that?
  4. My understanding is that waitUntil executes code on each frame. The code I posted as a test is obviously not optimal. I use waitUntil all the time, and usually with a "sleep" to try to cut down on load on the scheduled queue. In this example, waitUntil always returns false and therefore loops indefinitely on each frame. This is not important in regards to what I am pointing out. What I am trying to illustrate is that: missionNamespace setVariable ["myVariable",1]; and then _myVar = missionNamespace getVariable "myVariable"; results in a COPY of the variable which is local to the scope that _myVar is defined in. However, missionNamespace setVariable ["myVariable",[1,2,3]]; and then _myVar = missionNamespace getVariable "myVariable"; results in a POINTER that references the array rather than makes a copy of it. This means that adjustments to any pointers to "myVariable" are reflected globally and immediately IF AND ONLY IF "myVariable" is an array. If "myVariable" is a variable of some unitary type with a unitary value, then this is not the case.
  5. distanceSqr is also quite useful in any script where you need to continually check if the distance between two points is less than or greater than a hard value. Whatever your value is that you are using, simply square it ONCE and then compare the new value to distanceSqr in your loop. _maxDist = ((paramsArray select 4) ^ 2); //using a value from mission parameters, for example viewdistance or something waitUntil { if ((_obj1 distanceSqr _obj2) <= _maxDist) then { //do stuff }; false };
  6. Just realized this is completely unnecessary :banghead: _aData = missionNamespace getVariable "SomeArray"; _aData is now a pointer to the global array "SomeArray" and will always reflect changes made to it by other scripts, and not a copy unique within the script. No need to interrupt the engine. I can just set the element from directly within the script and never have to worry about overwriting anything I don't want to. This is NOT true if "SomeArray" is not an array (lets call it "SomeVariable from here on out). "SomeVariable" must be an array or any local variable that is declared = to it will be a local copy, and changes made to the local variable will not be reflected in the global variable. example: missionNamespace setVariable ["MyGlobalArray",[1,2,3]]; null = [] spawn { _myLocalArrayPointer1 = missionNamespace getVariable "MyGlobalArray"; waitUntil { hintSilent str _myLocalArrayPointer1; false }; }; null = [] spawn { _myLocalArrayPointer2 = missionNamespace getVariable "MyGlobalArray"; sleep 10; _myLocalArrayPointer2 set [3,"mind = blown"]; }; //will hint [1,2,3] for 10 seconds, and then continue to hint [1,2,3,"mind = blown"] afterwards
  7. Interesting, I should dig around the BIS functions more often. I wish they would upload the code to the wiki, even if it is out of date most of the time. Could be helpful to learn from when access to the in-game function viewer is not readily available. Regardless, I don't know why, but I guess I like re-inventing the wheel. I'd rather have a more purpose-built function for my needs and eliminate excess. For example, the only time I forsee needing to set an element in a nested array in my mission is when updating information about a specific area. Since I have decided to create unique variables on the server for each location (they contain information crucial to winning or losing the mission) I find that it is easiest to access them with getVariable and setVariable and a custom string. These server-local global variables will have somewhat randomized names to protect against a client using publicVariable to damage the data. So for this function I would want to provide a dynamically constructed variable name using the server-local keycode among other properties, then an array of ["value",[path]]'s to update. This could be anything from respawn indices to remove upon getting the information and re-setting those indices to new respawn indices, to getting and setting information about AI groups that are linked to the location through the location data variable in missionNamespace. I found that this works quite well, thanks to KK's insight: //_varName is name of missionNamespace variable to alter (string) //_data is an array consisting of [_value,_path] // _value is the new value to set at... // _path, which is an array that defines the path to the value location in the array eg. [3,2,1] // eg. (((_var select 3) select 2) select 1) [ _this, { params ["_varName","_data"]; _pArray = missionNameSpace getVariable _varName; { _tArray = _pArray; _value = _x select 0; _path = _x select 1; _index = _path deleteAt ((count _path) - 1); {_tArray = _tArray select _x} count _path; _tArray set [_index, _value]; } count _data; missionNameSpace setVariable [_varName,_pArray,false]; } ] execFSM "functions\unscheduledCall.fsm"; The change is not immediate, there is a delay before the update, but it does appear to be... what is the word... well, it gets the missionNamespace array and then sets it with the new element(s) and at least from my tests so far, wont be interrupted. I don't want other scripts calling getVariable, then updating an element, then setVariable in between the getVariable and setVariable of another script because that would result in overriding the changes made by the first script. And as I mentioned before, it doesn't do anything else, there is no fluff. I am not a huge fan of "universally applicable" functions. Call me anal, but I want to know exactly what my functions are doing, I want to know that they are doing what I want them to, and I don't want them to do any unnecessary work. (Unless, the alternate requires additional functions for similar purpose to be defined and using memory unnecessarily.)
  8. jwllorens

    emulate handheld flashlight

    I don't know that there is a way to do this with scripting. If you can get the position of the player's hand with a great deal of accuracy, maybe you could setPos a flashlight into it every frame, but I am thinking it would end up looking pretty terrible.
  9. jwllorens

    emulate handheld flashlight

    Probably best to use an addon for something like this. Otherwise, you will likely end up with a very complicated script and an effect that looks pretty sub-par.
  10. leaving out "_entities =" on the last line should cause the function to return the list of entities rather than store it in the local variable "_entities". Otherwise, calling the function stores the sorted list of entities in the local variable "_entities", returns nothing, and then the function scope is exited so _entities is lost. fnc_nearestEntities = { params ["_pos","_rad","_type"]; _entities = _pos nearEntities [_type,_rad]; _entities = _entities apply {[(_x distance _pos), _x]}; _entities sort true; _entities apply {_x select 1} }; //now you can use this anywhere in your script _someDudes = [player, 150, "Man"] call fnc_nearestEntities; _someCars = [(_someDudes select ((_size _someDudes) - 1)), 200, "Car"] call fnc_nearestEntities; //_someDudes is now a list of living men within 150m of the player, sorted from nearest to furthest. //_someCars is now a list of non-destroyed cars within 200m of the most distant man in the _someDudes array, sorted from nearest to the man to furthest from the man. But why cant you just use nearestObjects? It basically does the same thing, unless you are trying to only get a list of living objects.
  11. fnc_nearestEntities = { params ["_pos","_rad","_type"]; _entities = _pos nearEntities [_type,_rad]; _entities = _entities apply {[(_x distance _pos), _x]}; _entities sort true; _entities apply {_x select 1}; }; maybe that? I don't know if that works, but I don't think you even need to do this. If you just want a list of objects by type, within a radius, sorted by distance but don't need the actual distance of each object, then use "nearestObjects." _sortedListOfMenAndTanks = nearestObjects [_pos, ["Man","Tank"], _rad];
  12. Very slick. Thank you. Now I am trying to expand on this to see if I can set multiple values within one function. However, I am a little confused as to what is happening with "arr" and "_array". "_array" is a new variable initialized when the function is called that points to the same array as "arr." It seems like this is important, because the function works with "_array" and adjusts it so that it points to the deepest array within "arr" as specified by the _path, before calling set to adjust a value within _array. Since _array points to the original array, "arr" is therefore updated with the new value but not effected by the forEach loop which turns _array into a one-dimensional array. However, what if I wanted to define "arr" within the function, rather than passing it as a parameter to the function? I assume "arr" would be defined in the function, and "_array" would need to reference that same array "arr" but not copy it. So would this work? fnc_setAreaData = { [ _this, { params ["_area","_data"]; _varName = ("JWL_areaData_" + _area + JWL_KeyCode); _pArray = missionNameSpace getVariable _varName; { _tArray = _pArray; _value = _x select 0; _path = _x select 1; _index = _path deleteAt ((count _path) - 1); {_tArray = _tArray select _x} count _path; _tArray set [_index, _value]; } count _data; missionNameSpace setVariable [_varName,_pArray,false]; } ] execFSM "unscheduledCall.fsm"; }; That is using your call.fsm from your blog, just renamed so it is more clear what it is. I want to ensure that the variable is retrieved and set before any other scripts try to do the same, since different scripts are responsible for adjusting different elements in the global variable and I don't want them conflicting and overwriting changes made by a different script due to execution order. So that is why I am wrapping it all in your FSM that will execute the code in an unscheduled environment. I would hope this would do the following: hint str (missionNameSpace getVariable "JWL_areaData_LumberYard_9238001265"); //["Lumber Yard",JWL_areaFlag_LumberYard,WEST,true,[[JWL_areaResp_LumberYard_0,JWL_areaResp_LumberYard_1],[[WEST,2],[WEST,3]]]] _newSide = EAST _respInd1 = [EAST,4] _respInd2 = [EAST,5] ["LumberYard",[ [_newSide,[2]] , [_respInd1,[4,1,0]] , [_respInd2,[4,1,1]] ]] call JWL_fnc_setAreaData; hint str (missionNameSpace getVariable "JWL_areaData_LumberYard_9238001265"); //["Lumber Yard",JWL_areaFlag_LumberYard,EAST,true,[[JWL_areaResp_LumberYard_0,JWL_areaResp_LumberYard_1],[[EAST,4],[EAST,5]]]]
  13. In my mission I need to dynamically create and delete tasks for two factions (west and east). I would like to use the new tasks because they look very polished, although it seems I would be using them in a way that isn't really intended. So I would like to know how to accomplish this if it is possible. I have several areas on the map, and a server-side script that determines the number of hostile players in each area. It picks the top X number of areas with the most hostile players in range and stores them in an array so I can do some unit caching type stuff with this information. It is similar to how areas are "activated" in some capture-the-island game modes, but I want to incorporate the new tasks. Basically, if there are a lot of blufor players near an area that is not under blufor control, I want to "activate" the area and put an "attack" task on it that is visible by all blufor players. If that area is also under opfor control, then I want to put a "defend" task on it for all opfor players (the area might be under independent AI control in which case I wouldn't want to put a "defend" task on it, just the "attack" task for blufor.) And of course, vice-versa for opfor. Should I do this by creating two tasks (a defend and an attack) per team at every area, and then only make them visible when my server-side script deems it appropriate? Or should I create and destroy the tasks on the fly?
  14. I have many scripts that get, alter, and set missionNameSpace variables with getVariable and setVariable. These variables are local to the server and are accessed dynamically by constructing the variable name for the setVariable and getVariable parameter. Each variable represents an array with data that I need regarding a specific location, and this data is quite varied and represents different attributes of the location based on the state of the game, so I use different scripts to get the entire array, set an element, and then re-set the variable so all the other elements not pertaining to the particular script are unchanged. The problem is that while I can do all the operations to determine the data that I need to set an element in the array to inside a scheduled environment, and I usually want to, I need to make sure that the "getting" and "setting" of the variable occurs back to back in the engine. Otherwise, I could run into this problem: 1) Script A gets global variable V and stores it as local variable _vA. 2) Script A adjusts element 0 in variable _vA. 3) Script B gets global variable V and stores it as local variable _vB. 4) Script B adjusts element 1 in variable _vB. 5) Script B sets global variable V to = _vB. 6) Script A sets global variable V to = _vA. Global variable V now does not reflect changes made by script B at index 1. There are several other ways this could play out in a scheduled environment if one thread GETS the global variable in between the GETTING and SETTING of the same variable in another thread, where basically the changes made by one script to the global variable are reverted back because another script retrieved the contents of the variable before it was changed. I believe I can circumvent this by executing the the getting, adjusting (but not the computations to determine the adjustment), and setting of the global variable in an unscheduled environment to ensure that all three operations happen back to back before the same three operations in another script occur. So, can I do ["param1","param2"] remoteExecCall ["myFunction",2,false]; on the server to execute a bit of code in an unscheduled environment from a scheduled one?
  15. I wrote a script to set up all the areas that can be captured around my map. Each area consists of a flag, a marker (ellipse that covers the area of interest), and one to three game logics that mark respawn positions. All of these use a naming convention so they can be found by my scripts easily during setup. Basically, I just type the name into the init script, and add the flag, marker, and logics where I want them around the area, and it creates a new sector. The idea is that I have several sectors. Each sector is captured by using a hold action on a flag pole in that sector for 10 seconds. This hold action is added to all clients via remoteExec, but only appears if the sector is not under your side's control which is determined by a public variable that is updated whenever the side of the sector changes. Capturing a sector also remoteExecs a function to the server which basically re-jiggers the local server variable containing all the pertinent information about that sector, and changes flag textures and marker colors and enables and disables respawns. This function also remoteExecs another function to all clients that alerts them that the area has been taken by CSAT or NATO, and plays a little sound depending on whether the side that took it is your enemy or not. What I want to know is if I am doing this horribly wrong. I can't test it because I only have one machine. Although I hope to be able to test it in a few months. Is this the proper way to do multiplayer coding? I am trying to do everything I can on the server, and keep only the really really local stuff on the clients. I am also trying to not publicvariable much at all and when I do trying to make sure they are not spammed. It all works (in singleplayer at least) but I just wanted to get some advice from more experienced coders to see if I am going in the wrong direction with tackling this problem. Here are the functions: initServer.sqf _areaNames = ["LumberYard","CommsAlpha","DieselPlant"]; //create a unique identifier for server variables that can't be fucked with by publicvariable. _nums = ["1","2","3","4","5","6","7","8","9","0"]; JWL_KeyCode = ""; for "_i" from 1 to 10 do { JWL_KeyCode = (JWL_KeyCode + (selectRandom _nums)); }; _nums = nil; //add respawn trucks as initial spawn point [west,JWL_SpawnTruck_west] call BIS_fnc_addRespawnPosition; [east,JWL_SpawnTruck_east] call BIS_fnc_addRespawnPosition; //start setting up all the objectives. { _area = _x; //get the flag variable, store it, delete global public variable. _flag = missionNamespace getVariable ("JWL_flag_" + _area); missionNamespace setVariable [("JWL_flag_" + _area),nil,true]; //Create readable name from variable name by inserting spaces _name = _area call JWL_fnc_insertSpace; //create respawn array _rArr = []; { _logic = missionNamespace getVariable ("JWL_respawn_" + _area + "_" + _x); if (!(isNil "_logic")) then { _rArr pushBack _logic; missionNamespace setVariable [("JWL_respawn_" + _area + "_" + _x),nil,true]; }; } count ["1","2","3"]; //set keyed areaData variable missionNamespace setVariable [("JWL_areaData_" + _x + "_" + JWL_KeyCode),[_name,independent,_flag,_rArr,[[[WEST,-1],[WEST,-1],[WEST,-1]],[[EAST,-1],[EAST,-1],[EAST,-1]]]],false]; missionNamespace setVariable [("JWL_areaSide_" + _x),independent,true]; //set flag texture and marker color _flag setFlagTexture "a3\data_f_exp\flags\flag_synd_co.paa"; ("JWL_areaMarker_" + _x) setMarkerColor "colorIndependent"; //add capture action to all the flags, make sure JIP = true _grbg = [ _flag, (format ["Capture %1",_name]), "\A3\ui_f\data\igui\cfg\simpleTasks\types\interact_ca.paa", "\a3\3DEN\Data\CfgWaypoints\Scripted_ca.paa", (format ["((_target distance _this) < 5) && ((missionNameSpace getVariable ""JWL_areaSide_%1"") != (side _this))",_x]), "true", {}, {}, {[((_this select 3) select 0),((_this select 3) select 1),(side (_this select 1))] remoteExecCall ["JWL_fnc_captureArea",2];}, {}, [_x,_name], 10, 0, false, false ] remoteExecCall ["BIS_fnc_holdActionAdd",([0,-2] select (isMultiplayer && isDedicated)),true]; } count _areaNames; //update areaSide on all computers for the local holdaction condition _areaNames spawn { _sideOld = []; while {true} do { { _aVar = missionNamespace getVariable ("JWL_areaData_" + _x + "_" + JWL_KeyCode); _sideNew = _aVar select 1; if (_sideNew != (_sideOld select _forEachIndex)) then { missionNamespace setVariable [("JWL_areaSide_" + _x),_sideNew,true]; hint "updated"; }; _sideOld set [_forEachIndex,_sideNew]; } forEach _this; sleep 1; }; }; fn_captureArea.sqf params [ ["_area", "", [""], 1], ["_name", "", [""], 1], ["_side", independent, [west], 1] ]; //get keyed area variable _aVar = missionNamespace getVariable ("JWL_areaData_" + _area + "_" + JWL_KeyCode); //set side of keyed area variable _aVar set [1, _side]; //flag object _flag = _aVar select 2; //logic entities for spawn locations _spawnLogics = _aVar select 3; //pull out respawn indices of area variable to work with it _spawnIndices = _aVar select 4; //empty variable to work with later _spawnIndicesSide = []; _color = switch (_side) do { case west: { { _spawnIndicesSide pushBack ([west,_x] call BIS_fnc_addRespawnPosition); _aVar set [4,_spawnIndices]; } count _spawnLogics; _spawnIndices set [0,_spawnIndicesSide]; { if ((_x select 1) != -1) then { _x call BIS_fnc_removeRespawnPosition; }; true } count (_spawnIndices select 1); ["a3\data_f\flags\flag_nato_co.paa","colorBLUFOR"] }; case east: { { _spawnIndicesSide pushBack ([east,_x] call BIS_fnc_addRespawnPosition); _aVar set [4,_spawnIndices]; } count _spawnLogics; _spawnIndices set [1,_spawnIndicesSide]; { if ((_x select 1) != -1) then { _x call BIS_fnc_removeRespawnPosition; }; true } count (_spawnIndices select 0); ["a3\data_f\flags\flag_csat_co.paa","colorOPFOR"] }; }; //set flag and marker colors/textures _flag setFlagTexture (_color select 0); ("JWL_areaMarker_" + _area) setMarkerColor (_color select 1); //alert all players [(_aVar select 0),_side] remoteExecCall ["JWL_fnc_alertCapture",([0,-2] select (isMultiplayer && isDedicated)),false]; missionNamespace setVariable [("JWL_areaData_" + _area + "_" + JWL_KeyCode),_aVar,true]; fn_alertCapture.sqf params [["_area", "NONE", [], 1], ["_side", civilian, [civilian], 1] ]; if (!((_area == "NONE") || ((_side != west) || (_side != east)))) exitWith {diag_log "ERROR: Must define both side and area!";}; _team = call { if (_side == west) exitWith {["NATO","2443D1"]}; if (_side == east) exitWith {["CSAT","D12424"]}; }; [(format["<t size='0.65' color='#%1'>%2</t>",(_team select 1),(_team select 0)]),(format["<t size='0.6' color='#E0E0E0'> captured %1!</t>",_area])] call BIS_fnc_showSubtitle; if ((side player) == _side) then [{playSound "FD_Timer_F";},{playSound "addItemFailed";}];
  16. Seems like your solution is fine. For some reason it looks like the code to put the people in a plane is running before all the global variables are defined. I don't know why that is but it probably has to do with load order. Your solution is fine. Triggers are useful for all kinds of stuff and generally it is usually a good idea performance wise to contort the game engine to do what you want by using things like triggers, as opposed to having entirely scripted solutions.
  17. Ok yea then you don't need to public var anything if those are editor names. Try doing this. Put all that code, both the switch statement and the little if statement that moves the player into the plane. Take all of that and put it in this: null = [] spawn { waitUntil {player in [p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12]}; //Put the moveInCargo and switch do code here. }; I honestly don't know if this will fix anything but give it a shot.
  18. jwllorens

    Counting Units Percentage?

    null = (west countSide allUnits) spawn { waitUntil {(west countSide allUnits) < (0.3 * _this)}; ["end1",false,true,true,true] spawn BIS_fnc_endMission; }; Throw that into init.sqf and it should end the mission when about 70% of all bluFor units have been killed. Note that this will NOT work if you spawn any units during the mission with scripts, as it will not take those units into account properly.
  19. Alright so there are likely a lot of problems with what I posted, I didn't test it. All I did was rewrite it so that it only puts the player in the plane and only calls your custom function once on the player, and if it is inside of initPlayerLocal.sqf then it should do it once for each player rather than do it for every player... for each player. So lets go through and work out the errors. It isnt working, and _gear is undefined. There are no typos with the variable _gear itself. Since that means the switch statement isn't working and returning an array, we need to look at the statements in each case, and the conditions. So lets figure out why. After closer inspection, it looks like the code within each case of the switch statement is not defining anything and therefore should be returning the multidimensional array inside, so I don't think the problem is the statements in each case. Just from the syntax, _gear should be defined by the switch statement, so I am guessing that the error is being thrown when you try to pass _gear to Zade_BOC_FNC_AddChestBackpack. That means _gear must be undefined because the switch statement is not matching any case and the default case is not defined. So, we need to understand why player == p1 or player == p2 ect... is never coming up as true. Could you explain how and where you are defining the variables p1, p2, ect? You may need to "publicVariable" them or something to make sure that they exist everywhere, are consistent, and are accessible by initPlayerLocal.sqf, Try putting the following into initServer.sqf publicVariable "plane1"; for "_i" from 1 to 12 do { publicVariable ("p" + (str _i)); }; See if that fixes the problem. If not, it would really help to know what exactly p1 and p2 and all that actually is, because I am going off of assumptions here. Also, are you running any kind of respawn in the mission?
  20. If all that is in initPlayerLocal, here is what is happening. every time a player joins, they download initPlayerLocal, and run that script. That script adds backpacks and stuff to EVERY player, using script commands that have global effect most likely. Even though the script only runs once per client, it is running multiple times if there are multiple clients. Each time it runs (when a player joins), it adds stuff to EVERY player. Instead, just trim down your code. Replace this code: if (!isNil "plane1") then { { if (!isNil {_x} ) then { _x moveInCargo plane1; }; } forEach [p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12]; } else {hint "PLANE IS GONE!"}; with this: if (!isNil "plane1") then { player moveInCargo plane1; } else {hint "PLANE IS GONE!"}; Each time a player joins, they run initPlayerLocal on their machine, so "player" will return that player only. You want to run it once per player, and only on that player, and only when they join. Now, for the rest of your code. You should probably change how you define the player's role, but lets just work with what you have. Replace this: //Squad Leader if (!isNil "p1") then { [p1,"B_AssaultPack_blk",["itemMap","HLC_30rnd_556x45_SPR","HLC_30rnd_556x45_SPR","HLC_30rnd_556x45_SPR","HLC_30rnd_556x45_SPR","ACE_epinephrine","ACE_bloodIV_500","ACE_optic_MRCO_2D","ACE_EntrenchingTool","rhsusf_opscore_bk","NVGoggles_OPFOR"]] call Zade_BOC_FNC_AddChestBackpack; }; //Fire Team Leader if (!isNil "p2") then { [p2,"B_AssaultPack_blk",["itemMap","HLC_30Rnd_9x19_SD_MP5","HLC_30Rnd_9x19_SD_MP5","HLC_30Rnd_9x19_SD_MP5","HLC_30Rnd_9x19_SD_MP5","ACE_epinephrine","ACE_bloodIV_500","ACE_EntrenchingTool","rhsusf_opscore_bk","NVGoggles_OPFOR"]] call Zade_BOC_FNC_AddChestBackpack; }; //Fire Team Leader if (!isNil "p3") then { [p3,"B_AssaultPack_blk",["itemMap","HLC_30Rnd_9x19_SD_MP5","HLC_30Rnd_9x19_SD_MP5","HLC_30Rnd_9x19_SD_MP5","HLC_30Rnd_9x19_SD_MP5","ACE_epinephrine","ACE_bloodIV_500","ACE_EntrenchingTool","rhsusf_opscore_bk","NVGoggles_OPFOR"]] call Zade_BOC_FNC_AddChestBackpack; }; //Corpsman (medic) if (!isNil "p4") then { [p4,"B_AssaultPack_blk",["itemMap","HLC_30rnd_556x45_SPR","HLC_30rnd_556x45_SPR","HLC_30rnd_556x45_SPR","HLC_30rnd_556x45_SPR","ACE_epinephrine","ACE_epinephrine","ACE_epinephrine","ACE_epinephrine","ACE_epinephrine","ACE_epinephrine","ACE_epinephrine","ACE_bloodIV_500","ACE_epinephrine","ACE_bloodIV_500","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_morphine","ACE_morphine","ACE_morphine","ACE_morphine","ACE_morphine","ACE_morphine","ACE_morphine","ACE_morphine","ACE_morphine","ACE_morphine","ACE_morphine","ACE_morphine","ACE_morphine","ACE_morphine","ACE_optic_MRCO_2D","rhsusf_opscore_bk","NVGoggles_OPFOR"]] call Zade_BOC_FNC_AddChestBackpack; }; //Corpsman (medic) if (!isNil "p5") then { [p5,"B_AssaultPack_blk",["itemMap","HLC_30rnd_556x45_SPR","HLC_30rnd_556x45_SPR","HLC_30rnd_556x45_SPR","HLC_30rnd_556x45_SPR","ACE_epinephrine","ACE_epinephrine","ACE_epinephrine","ACE_epinephrine","ACE_epinephrine","ACE_epinephrine","ACE_epinephrine","ACE_bloodIV_500","ACE_epinephrine","ACE_bloodIV_500","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_morphine","ACE_morphine","ACE_morphine","ACE_morphine","ACE_morphine","ACE_morphine","ACE_morphine","ACE_morphine","ACE_morphine","ACE_morphine","ACE_morphine","ACE_morphine","ACE_morphine","ACE_morphine","ACE_optic_MRCO_2D","rhsusf_opscore_bk","NVGoggles_OPFOR"]] call Zade_BOC_FNC_AddChestBackpack; }; //Electronics Specialist if (!isNil "p6") then { [p6,"B_AssaultPack_blk",["itemMap","HLC_30rnd_556x45_SPR","HLC_30rnd_556x45_SPR","HLC_30rnd_556x45_SPR","HLC_30rnd_556x45_SPR","ACE_epinephrine","ACE_bloodIV_500","ACE_optic_MRCO_2D","ACE_wirecutter","rhsusf_opscore_bk","NVGoggles_OPFOR"]] call Zade_BOC_FNC_AddChestBackpack; }; //SAW Gunner if (!isNil "p7") then { [p7,"B_TacticalPack_blk",["itemMap","RHSUSF_200Rnd_556x45_soft_pouch","RHSUSF_200Rnd_556x45_soft_pouch","RHSUSF_200Rnd_556x45_soft_pouch","ACE_epinephrine","ACE_bloodIV_500","ACE_optic_MRCO_2D","rhsusf_opscore_bk","NVGoggles_OPFOR"]] call Zade_BOC_FNC_AddChestBackpack; }; //Designated Marksman if (!isNil "p8") then { [p8,"B_AssaultPack_blk",["itemMap","RHSUSF_20Rnd_762x51_m993_mag","RHSUSF_20Rnd_762x51_m993_mag","RHSUSF_20Rnd_762x51_m993_mag","RHSUSF_20Rnd_762x51_m993_mag","ACE_epinephrine","ACE_bloodIV_500","ACE_optic_MRCO_2D","ACE_EntrenchingTool","optic_nightstalker","rhsusf_opscore_bk","NVGoggles_OPFOR"]] call Zade_BOC_FNC_AddChestBackpack; }; //Demo Specialist if (!isNil "p9") then { [p9,"B_TacticalPack_blk",["itemMap","HLC_30Rnd_9x19_SD_MP5","HLC_30Rnd_9x19_SD_MP5","ACE_epinephrine","ACE_bloodIV_500","SatchelCharge_Remote_Mag","SatchelCharge_Remote_mag","ACE_wirecutter","rhsusf_opscore_bk","NVGoggles_OPFOR"]] call Zade_BOC_FNC_AddChestBackpack; }; //Operator (MP5) if (!isNil "p10") then { [p10,"B_AssaultPack_blk",["itemMap","HLC_30Rnd_9x19_SD_MP5","HLC_30Rnd_9x19_SD_MP5","HLC_30Rnd_9x19_SD_MP5","HLC_30Rnd_9x19_SD_MP5","HLC_30Rnd_9x19_SD_MP5","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_morphine","ACE_morphine","ACE_morphine","ACE_epinephrine","ACE_bloodIV_500","ACE_EntrenchingTool","rhsusf_opscore_bk","NVGoggles_OPFOR"]] call Zade_BOC_FNC_AddChestBackpack; }; //Operator (HK416) if (!isNil "p11") then { [p11,"B_AssaultPack_blk",["itemMap","HLC_30rnd_556x45_SPR","HLC_30rnd_556x45_SPR","HLC_30rnd_556x45_SPR","HLC_30rnd_556x45_SPR","HLC_30rnd_556x45_SPR","HLC_30rnd_556x45_SPR","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_morphine","ACE_morphine","ACE_morphine","ACE_epinephrine","ACE_bloodIV_500","ACE_optic_MRCO_2D","ACE_EntrenchingTool","rhsusf_opscore_bk","NVGoggles_OPFOR"]] call Zade_BOC_FNC_AddChestBackpack; }; //Operator (HK416) if (!isNil "p12") then { [p12,"B_AssaultPack_blk",["itemMap","HLC_30rnd_556x45_SPR","HLC_30rnd_556x45_SPR","HLC_30rnd_556x45_SPR","HLC_30rnd_556x45_SPR","HLC_30rnd_556x45_SPR","HLC_30rnd_556x45_SPR","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_morphine","ACE_morphine","ACE_morphine","ACE_epinephrine","ACE_bloodIV_500","ACE_optic_MRCO_2D","ACE_EntrenchingTool","rhsusf_opscore_bk","NVGoggles_OPFOR"]] call Zade_BOC_FNC_AddChestBackpack; }; with this: _gear = switch (player) do { case p1: {[p1,"B_AssaultPack_blk",["itemMap","HLC_30rnd_556x45_SPR","HLC_30rnd_556x45_SPR","HLC_30rnd_556x45_SPR","HLC_30rnd_556x45_SPR","ACE_epinephrine","ACE_bloodIV_500","ACE_optic_MRCO_2D","ACE_EntrenchingTool","rhsusf_opscore_bk","NVGoggles_OPFOR"]]}; case p2: {[p2,"B_AssaultPack_blk",["itemMap","HLC_30Rnd_9x19_SD_MP5","HLC_30Rnd_9x19_SD_MP5","HLC_30Rnd_9x19_SD_MP5","HLC_30Rnd_9x19_SD_MP5","ACE_epinephrine","ACE_bloodIV_500","ACE_EntrenchingTool","rhsusf_opscore_bk","NVGoggles_OPFOR"]]}; case p3: {[p3,"B_AssaultPack_blk",["itemMap","HLC_30Rnd_9x19_SD_MP5","HLC_30Rnd_9x19_SD_MP5","HLC_30Rnd_9x19_SD_MP5","HLC_30Rnd_9x19_SD_MP5","ACE_epinephrine","ACE_bloodIV_500","ACE_EntrenchingTool","rhsusf_opscore_bk","NVGoggles_OPFOR"]]}; case p4: {[p4,"B_AssaultPack_blk",["itemMap","HLC_30rnd_556x45_SPR","HLC_30rnd_556x45_SPR","HLC_30rnd_556x45_SPR","HLC_30rnd_556x45_SPR","ACE_epinephrine","ACE_epinephrine","ACE_epinephrine","ACE_epinephrine","ACE_epinephrine","ACE_epinephrine","ACE_epinephrine","ACE_bloodIV_500","ACE_epinephrine","ACE_bloodIV_500","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_morphine","ACE_morphine","ACE_morphine","ACE_morphine","ACE_morphine","ACE_morphine","ACE_morphine","ACE_morphine","ACE_morphine","ACE_morphine","ACE_morphine","ACE_morphine","ACE_morphine","ACE_morphine","ACE_optic_MRCO_2D","rhsusf_opscore_bk","NVGoggles_OPFOR"]]}; case p5: {[p5,"B_AssaultPack_blk",["itemMap","HLC_30rnd_556x45_SPR","HLC_30rnd_556x45_SPR","HLC_30rnd_556x45_SPR","HLC_30rnd_556x45_SPR","ACE_epinephrine","ACE_epinephrine","ACE_epinephrine","ACE_epinephrine","ACE_epinephrine","ACE_epinephrine","ACE_epinephrine","ACE_bloodIV_500","ACE_epinephrine","ACE_bloodIV_500","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_morphine","ACE_morphine","ACE_morphine","ACE_morphine","ACE_morphine","ACE_morphine","ACE_morphine","ACE_morphine","ACE_morphine","ACE_morphine","ACE_morphine","ACE_morphine","ACE_morphine","ACE_morphine","ACE_optic_MRCO_2D","rhsusf_opscore_bk","NVGoggles_OPFOR"]]}; case p6: {[p6,"B_AssaultPack_blk",["itemMap","HLC_30rnd_556x45_SPR","HLC_30rnd_556x45_SPR","HLC_30rnd_556x45_SPR","HLC_30rnd_556x45_SPR","ACE_epinephrine","ACE_bloodIV_500","ACE_optic_MRCO_2D","ACE_wirecutter","rhsusf_opscore_bk","NVGoggles_OPFOR"]]}; case p7: {[p7,"B_TacticalPack_blk",["itemMap","RHSUSF_200Rnd_556x45_soft_pouch","RHSUSF_200Rnd_556x45_soft_pouch","RHSUSF_200Rnd_556x45_soft_pouch","ACE_epinephrine","ACE_bloodIV_500","ACE_optic_MRCO_2D","rhsusf_opscore_bk","NVGoggles_OPFOR"]]}; case p8: {[p8,"B_AssaultPack_blk",["itemMap","RHSUSF_20Rnd_762x51_m993_mag","RHSUSF_20Rnd_762x51_m993_mag","RHSUSF_20Rnd_762x51_m993_mag","RHSUSF_20Rnd_762x51_m993_mag","ACE_epinephrine","ACE_bloodIV_500","ACE_optic_MRCO_2D","ACE_EntrenchingTool","optic_nightstalker","rhsusf_opscore_bk","NVGoggles_OPFOR"]]}; case p9: {[p9,"B_TacticalPack_blk",["itemMap","HLC_30Rnd_9x19_SD_MP5","HLC_30Rnd_9x19_SD_MP5","ACE_epinephrine","ACE_bloodIV_500","SatchelCharge_Remote_Mag","SatchelCharge_Remote_mag","ACE_wirecutter","rhsusf_opscore_bk","NVGoggles_OPFOR"]]}; case p10: {[p10,"B_AssaultPack_blk",["itemMap","HLC_30Rnd_9x19_SD_MP5","HLC_30Rnd_9x19_SD_MP5","HLC_30Rnd_9x19_SD_MP5","HLC_30Rnd_9x19_SD_MP5","HLC_30Rnd_9x19_SD_MP5","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_morphine","ACE_morphine","ACE_morphine","ACE_epinephrine","ACE_bloodIV_500","ACE_EntrenchingTool","rhsusf_opscore_bk","NVGoggles_OPFOR"]]}; case p11: {[p11,"B_AssaultPack_blk",["itemMap","HLC_30rnd_556x45_SPR","HLC_30rnd_556x45_SPR","HLC_30rnd_556x45_SPR","HLC_30rnd_556x45_SPR","HLC_30rnd_556x45_SPR","HLC_30rnd_556x45_SPR","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_morphine","ACE_morphine","ACE_morphine","ACE_epinephrine","ACE_bloodIV_500","ACE_optic_MRCO_2D","ACE_EntrenchingTool","rhsusf_opscore_bk","NVGoggles_OPFOR"]]}; case p12: {[p12,"B_AssaultPack_blk",["itemMap","HLC_30rnd_556x45_SPR","HLC_30rnd_556x45_SPR","HLC_30rnd_556x45_SPR","HLC_30rnd_556x45_SPR","HLC_30rnd_556x45_SPR","HLC_30rnd_556x45_SPR","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_FieldDressing","ACE_morphine","ACE_morphine","ACE_morphine","ACE_epinephrine","ACE_bloodIV_500","ACE_optic_MRCO_2D","ACE_EntrenchingTool","rhsusf_opscore_bk","NVGoggles_OPFOR"]]}; }: _gear call Zade_BOC_FNC_AddChestBackpack;
  21. The CCIP (continuously computed impact point) given to aircraft weapons is nice because it is hardcoded in the engine. However, a scripted version of this has a LOT more overhead because it must run on a loop, hence the name "continuously computed." CCIPs are pretty math heavy too, you have to keep getting the gun direction, then know the muzzle velocity and air resistance (which in ArmA is modeled as a constant acceleration I believe, rather than a function of velocity, which means you can avoid the calculus but it is still very math heavy). Then you calculate an estimated time of flight by assuming an impact position, use that to calculate an actual impact point, then use that impact point to calculate time of flight again, ect. Making an accurate, smooth CCIP is tough. It is certainly possible, however. The reason I like this approach is because it is simple, the only code that gets run repeatedly and often is one single line, and 99.9% of people will see it in action and never know that it is "breaking physics." In fact, I can't think of another game that doesn't do it like this anyways because the CPU time required to have realistic ballistic physics AND still give the player a good experience by giving them the tools to hit what they aim at is just too much and isn't visually worth it. ArmA is the only game I know of that does have projectiles inherit the velocity of the firing vehicle. Anyways, I updated the function, and broke it into two parts. I don't know much about multiplayer and can't test some of this stuff since I am going at it alone. But I wasn't sure if event handlers could only be removed by their index on the PC where they were added. So I rewrote the script to use a new function that I made that keeps track of event handlers added through it and makes sure they stay on the computer where the object they are added to is local, and nowhere else. This is particularly useful for enabling or disabling some functions that rely heavily on adding and removing event handlers dynamically, and being able to always turn them on or off from anywhere even if the object has changed locality. But again, I don't know if it is necessary, maybe you can call addEventhandler on one PC and call removeEventhandler on another and it will work and so all this is pointless. It does work in single player just fine though. fn_disableInheritedVelocity.sqf (ex: usage, then the function code) [_object, true] RemoteExecCall [JWL_fnc_disableInheritedVelocity, _object]; //or to disable the effect: [_object, false] RemoteExecCall [JWL_fnc_disableInheritedVelocity, _object]; params [ ["_obj", objNull, [objNull], 1], ["_act", true, [true], 1] ]; if (_act) then [{ [_obj,"JWL_vars_disableInheritedVelocity","ADD","Fired",{ _ammo = (_this select 4); _path = (configFile >> "CfgAmmo"); if ((_ammo isKindOf ["BulletCore", _path]) || (_ammo isKindOf ["ShellCore", _path])) then { (_this select 6) setVelocity ((velocity (_this select 6)) vectorDiff (velocity (_this select 0))); }; }] call JWL_fnc_migratoryEventHandler; },{ [_obj,"JWL_vars_disableInheritedVelocity","REMOVE","Fired"] call JWL_fnc_migratoryEventHandler; }]; fn_migratoryEventHandler.sqf (ex. usage, then function code) [_object, _uniqueEventHandlerName, "ADD", _eventHandlerType, _eventHandlerCode] call JWL_fnc_migratoryEventHandler; //or to remove the event handler: [_object, _uniqueEventHandlerName, "REMOVE", _eventHandlerType] call JWL_fnc_migratoryEventHandler; params [ ["_obj", objNull, [objNull], 1], ["_name", "JWL_vars_DefaultMigratoryEH", [""], 1], ["_act", "REMOVE", [""], 1], ["_type", nil, [""], 1], ["_code", {}, [{}], 1] ]; if (!(isNil "_type")) then [{ switch (_act) do { case "ADD": { _var = _obj getVariable _name; if (isNil "_var") then [{ _idx0 = _obj addEventHandler [_type,_code]; _idx1 = _obj addEventHandler ["Local",(compile (format [" if (!(_this select 1)) then { _obj = (_this select 0); _var = _obj getVariable ""%1""; _obj setVariable [""%1"",nil]; _prms = _var select 0; _idxs = _var select 1; _obj removeEventHandler [(_prms select 0),(_idxs select 0)]; _obj removeEventHandler [""Local"",(_idxs select 1)]; [(_this select 0),""%1"",""ADD"",(_prms select 0),(_prms select 1)] remoteExecCall [""JWL_fnc_migratoryEventHandler"",_obj]; }; ",_name]))]; _obj setVariable [_name,[[_type,_code],[_idx0,_idx1]]]; },{ diag_log (format ["JWL_fnc_migratoryEventHandler ERROR: Migratory event handler name ""%1"" already in use.", _name]); }]; }; case "REMOVE": { _var = _obj getVariable _name; if (!(isNil "_var")) then [{ _obj removeEventHandler [_type,((_var select 1) select 0)]; _obj removeEventHandler ["Local",((_var select 1) select 1)]; _obj setVariable [_name,nil]; },{ diag_log (format ["JWL_fnc_migratoryEventHandler ERROR: Migratory event handler name ""%1"" does not exist. Cannot remove.", _name]); }]; }; default { diag_log "JWL_fnc_migratoryEventHandler ERROR: Must specify ""ADD"" or ""REMOVE""."; }; }; },{ diag_log "JWL_fnc_migratoryEventHandler ERROR: Must specify migratory event handler ""TYPE"" to add or remove."; }]; I don't know if it is necessary to do this but I like the peace of mind of just calling disableInheritedVelocity like that from the server, and it will always add or remove the event handlers on the computer where the object is local, and the event handlers automatically move to the new machine if ownership changes (as it does with vehicles often). I think doing it this way might save on some network traffic as well compared to using addeventHandlerMP.
  22. In ArmA 3, bullets inherit the velocity of the vehicle that fires them. This means that when you are in the turret of a fast moving aircraft, it can be pretty frustrating to hit a target on the ground. To start with, your crosshairs are swinging wildly with the motion of the aircraft. Combine this with the fact that the bullets fired from the turret wont hit where the crosshairs are aiming, and it's a real party. If you have played on the new Tanoa King of the Hill map and been a gunner in a Blackfish, you know what I am talking about. If the Blackfish is doing anything but hovering, you wont hit your target. Forget loitering in a circle. Now, I am no military expert, but I am sure that advanced modern fire control computers can account for this and adjust the crosshairs. I may be wrong, but either way, being able to hit stuff is more fun that not being able to. So I wrote a little function and thought I would share it. It works perfectly. No more shells hitting 6 miles off to the right of where you were aiming. You still need to get your zeroing correct though. /*disables projectiles inheriting vehicle velocity to allow for easier aiming of aircraft turrets while vehicle is moving. arguments: vehicle(obj), enabled(bool) return: true Can be turned on and off by passing true or false in the second argument. Useful if you want to dynamically enable or disable this functionality. Reccomended for use on Blackfish, Blackfoot, Kajman, and Xi'an gunships. */ params [ ["_veh", objNull, [objNull], 1], ["_act", false, [true], 1] ]; _var = _veh getVariable "JWL_vars_disableInheritedVelocity"; if (_act) then [{ _ind = _veh addEventHandler ["Fired",{ _ammo = (_this select 4); _path = (configFile >> "CfgAmmo"); if ((_ammo isKindOf ["BulletCore", _path]) || (_ammo isKindOf ["ShellCore", _path])) then { (_this select 6) setVelocity ((velocity (_this select 6)) vectorDiff (velocity (_this select 0))); }; }]; _veh setVariable ["JWL_vars_disableInheritedVelocity",_ind,true]; },{ if (!(isNil "_var")) then { _veh removeEventHandler ["fired",_var]; _veh setVariable ["JWL_vars_disableInheritedVelocity",nil,true]; }; }]; true To use it, simply pass it a vehicle object. Bullets fired from the vehicle will now hit what they are aimed at. For example: [myVehicle, true] call DisableInheritedVelocity.sqf; If anyone wants to take a crack at optimizing it, please do.
  23. jwllorens

    Osprey Hatch

    Seems like it might be helpful to learn a little more about triggers and way points in the editor before tackling this problem. It is not too difficult to accomblish, but it will be overwhelming if you don't know your way around the editor and at least know a little scripting. Here are 4 good links that should get you more familiar with some of the concepts. Play around in the editor and start with something small, like making a car drive to a waypoint and then having it wait for a another group to arrive before the car continues on to the next waypoint. Then step it up a notch, and have the car wait for the other group to actually get in the car. Then try it with the Blackfish, but have the Blackfish land instead. Then try animating the door. If you take it in steps, you will learn more and it will be easier to accomplish what you want. Here are some good resources. https://community.bistudio.com/wiki/ArmA:_Mission_Editing https://community.bistudio.com/wiki/2D_Editor:_Waypoints https://community.bistudio.com/wiki?title=2D_Editor:_Triggers https://community.bistudio.com/wiki/Scripting
  24. I am confused by event handlers in multiplayer. The wiki says: and So if I add an event handler to a unit with addEventHandler on computer A, and that event fires (global event like "Fired"), will computer B execute the code that computer A added (assuming addEvenentHandler was not called on computer B explicitly)? Will computer B be able to use removeEventHandler to remove the event handler added by computer A? I am hoping the event handler is local and the code it runs is local too (even if the code has commands that have global effect, I am hoping it is only processed by the local machine). That would be way easier to keep track of.
  25. { if (_x isPlayer) exitWith {true}; false } count _thisList; is generally faster than... if (({_x isPlayer} count _thisList) > 0) then [{true},{false}]; assuming a: A player unit is in _thisList; b: The player unit in _thisList is not the last element in the array. Is this correct to assume?