-
Content Count
530 -
Joined
-
Last visited
-
Medals
Everything posted by Zenophon
-
Zenophon's ArmA 3 Co-op Mission Making Framework
Zenophon replied to Zenophon's topic in ARMA 3 - MISSION EDITING & SCRIPTING
Using a more formal analysis of performance, the work done in checking and spawning enemies in the markers increases by O(n) as you add markers. https://en.wikipedia.org/wiki/Big_O_notation However, math functions dealing with markers (e.g. Zen_IsPointInPoly) are O(1) in regards to the size of the marker. Zen_SpawnInfantry would be nearly O(1) for small numbers (less than 10) of units, but in general it uses Zen_SpawnGroup, which is about O(n) for many units. Loadout function are also about O(n). Also, every marker spawned creates a Zen_OrderInfantryPatrol thread (unsurprisingly O(n)), which runs every ten seconds to check on the groups. Thus, spawning fewer groups of more units in fewer markers should improve performance. Decreasing the number of markers will about linearly increase performance (at 200 markers it will take half as long, etc.). It will speed up not only the spawning, but checking for the enemy to be dead, as fewer markers means fewer arrays of groups to check on. However, mission performance may not noticeably improve. The work done to spawn and check on the areas is done every 10 seconds, but any AI spawned will require constant management by the engine. Spawning 100-200 AI will always decrease performance more than any script with a reasonable sleep in it. -
Zenophon's ArmA 3 Co-op Mission Making Framework
Zenophon replied to Zenophon's topic in ARMA 3 - MISSION EDITING & SCRIPTING
Introduction Greetings fellow scripters and Armaholics, in this latest installment, I will continue to discuss the development of the framework and, of course, shamelessly advertise the framework in any way possible. If this sounds boring, you can download the latest version from the original post. As always, the link to Google Drive for the .7z and .zip versions are already up to date. For those looking for older versions, go to file>revisions. The new version should be on Armaholic when Foxhound sees this or I PM him. Please bring any technical issues or mistakes to my attention, so e.g. people don't download the wrong version etc. Changelog Release #8 marks the passing of 2 months of framework releases; this is also the first release for September. You might notice that amongst the 27 changes, 15 of them are for the new Preprocessor Library that is now a new feature of the framework. This is a new way of helping scripters by automating short code snippets, common actions, and helping with arguments for more complex functions. Instead of full functions, these libraries provide smaller, simpler macros that can represent values and take arguments similarly to functions. The Preprocessor Library is divided into two parts: framework and standard. Macros in the framework category use and support framework functions, while standard macros are general to the SQF language. The starting line-up of macros has a fair number of each type, and they have been carefully chosen to be useful. These macros represent code that I have written many times and are actually useful in either coding the framework itself or making missions. Finally, the documentation about the macros appears in its own file, alongside the function category documentation files. This documentation also explains a little about the preprocessor and how to setup and use these macros. Currently, that explanation is somewhat terse, so I might add more substantial document about the preprocessor and the libraries offered by the framework. Moving on to more usual changes, the StringTable.xml did not have an entry for 'gunship', which I thought was eliminated from the BIS configs. The only vehicle affected is the Mi-48 (all versions); it will now spawn and be given a crew properly. The various loadout functions tend to make the unit play some sort of animation, such as drawing their weapon etc. To put a stop to this, the loadout functions will now reset a unit's animation after giving the loadout. Regardless of the animation the unit has (e.g. sitting in a vehicle), they will always be returned to that animation without playing any other. The JIP demonstration has been improved with what is (hopefully) the final part of the JIP jigsaw with the inclusion of a solution for tracking when using any of the framework's unit tracking functions. This is only necessary if you use those functions and have disabled friendly AI. If playable units have AI, the tracking reset will have no effect, as they are already being tracked. Like a lot of JIP, the general solution requires some customization for your mission. 9/3/14 Roadmap The only thing planned for next week is the expansion and refinement of the preprocessor library. If you've ever wanted to suggest a major function, now is the time. Mostly I will be focusing on making missions (since that is the point of all this). Function Spotlight As users of my framework know, there is an enormous number of functions at your disposal. The amount of documentation that has to be sifted through can be extremely daunting. Each week I spotlight a function and talk about its usefulness. If you have found an obscure function (not in tutorials, barely seen in demonstrations or sample missions) that you think is useful, PM me and I can spotlight it. The function chosen for this week is: Zen_ReassignTask. This function can simultaneously remove a task from some units, while giving it to others. Tasks are treated in an object-oriented way, with their names being strings. Thus, every task system function can work together to manipulate global task entities. This means that using any combination of functions will modify every local instance of that task for all objects on all machines. You can use Zen_ReassignTask to simply add the task to another group of units. For example, if group A fails their objective, give the task to group B: if ({alive _x} count units A == 0) then { 0 = [_task, group B] call Zen_ReassignTask; }; Also, in PvP style missions, if the Blufor team e.g. captures a supply depot, you could easily reverse the task so the Opfor team is told to retake it: 0 = [_taskSecureDepot, east, west] call Zen_ReassignTask; The exact same task will them seamlessly swap sides and be shown to the players as either 'task removed' or 'task created'. This also prevents long lists of tasks from cluttering players' logs if the same objective was taken 10 times. You could go even further and have a defend the depot task that is swapped: 0 = [_taskDefendDepot, west, east] call Zen_ReassignTask; Currently, neither task will ever be able to succeed or fail, they would always be incomplete. However, they still simply and effectively represent one of the goals of the player's team in the mission. Beta As already stated, the framework is in the beta stage of development. I am making every effort to quality control releases, but there will be bugs. Both new features and old ones could have bugs, issues, and things people just don't like. There is no ETA or plan for a 'final' version. The framework is a work in progress, and it will continue to progress while there are improvements to be made (there always will be). Feedback As expected, some of the bugs have been pointed out by users, and those fixes are included in the changelog above. I want to thank everyone who has used/supported the framework. ---------- Post added at 01:11 ---------- Previous post was at 23:29 ---------- If enemies spawn, the loop is somewhat functional, so the issue could be with just turning the markers green. You can add some debug to see if the server ever runs that code: if ([_groupsArray, _x] call Zen_AreNotInArea) then { _x setMarkerColor "colorGreen"; diag_log (format["Marker %1 clear, changing color to green", _x]); // ... The server's log location depends upon how you set up the dedicated server. For me it is here (Windows 7) C:\Program Files (x86)\Steam\steamapps\common\Arma 3\Server. Based upon these wiki pages: https://community.bistudio.com/wiki/setMarkerColor https://community.bistudio.com/wiki/setMarkerColorLocal The command should have global effect. ---------- Post added at 01:19 ---------- Previous post was at 01:11 ---------- By custom init I assume you mean running some code on each unit. You don't need a special init field for each unit, because you can code whatever you need immediately after spawning them. _group = [player, west, 0.5, 4] call Zen_SpawnInfantry; { if (_x == leader _group) then { // ... } else { // ... }; } forEach units _group; If you have some code that you always run for units, then make it a function: f_InfantryInit = { // ... }; then: _group = [player, west, 0.5, 4] call Zen_SpawnInfantry; [_group] call f_InfantryInit; You can do anything to a spawned unit that you can do in the editor. Such as give the group leader a name that all clients can see: X = leader _group; publicVariable "X"; -
I does seem like the AI hearing feature would be good idea for a standalone script. Until I do that though, I will just go through how to set it up manually. The AI hearing feature uses a 'fired' eventhandler on the clients, which sends a request to the server to inform the AI (as the AI are local to the server). The first step is defining the EH code on all clients and the server: Last_Fire_Event_Time_Local = 0; f_HandleFire = { if (time > (Last_Fire_Event_Time_Local + 5)) then { 0 = [(_this select 0), "f_AlertPatrols", false] call BIS_fnc_MP; }; Last_Fire_Event_Time_Local = time; }; That will send a remote execution request to the server to run f_AlertPatrols with the unit that fired as the only argument. In my mission, I don't use BIS_fnc_MP, but it should achieve that same effect as my method. Then you must define f_AlertPatrols for the server: f_AlertPatrols = { { if (!(isNull (leader _x)) && {(side leader _x) == east}) then { _distance = (leader _x) distance _this; if (_distance < 700) then { if ((vehicle leader _x) == leader _x) then { _x reveal [_this, (200 / _distance) min 2]; }; }; }; } forEach allGroups; }; This function is entirely automatic, once the unit fires, this function takes over on the server and gives information to the AI. You never need to call this function directly from your code. You can also tweak the max range (700 here) and the reveal coefficient (200) for different results. The range is based upon a reasonable distance a rifle shot is clearly audible, accounting for different terrain, ambient noise, etc. The coefficient is arbitrary, increasing it will give the AI more information at longer range. Finally, you have to assign the EH itself to the units you want. I use this code in the mission, but you can get the objects any way you want. _rangers = [west] call Zen_ConvertToObjectArray; { _x addEventHandler ["Fired", f_HandleFire]; } forEach _rangers; It is possible to limit where the objectives spawn to more reasonable areas. I think I will soon release an update of the mission using the latest version of my framework, as there are a lot of indirect bugfixes and improvements that will make the mission smoother. I can also improve the objectives and anything else I can think of.
-
Zenophon's ArmA 3 Co-op Mission Making Framework
Zenophon replied to Zenophon's topic in ARMA 3 - MISSION EDITING & SCRIPTING
Zen_CreateLoadout should be used after both 'if !(isServer) exitWith{};' and 'sleep X;', as it needs to send the loadout information to the clients, but this is not possible (engine limitation with PVEH's) during the briefing. I believe that using Zen_CreateLoadout before 'if !(isServer) exitWith{};' will work, provided that you give the loadout a fixed named as the second argument. This is not exactly an intended feature, but it works on the same principle as Zen_InvokeTaskBriefing does. If you have a fixed name and data, every machine will record the same values into its local array. However, allowing a random name will never work, as all clients will have the loadout under a different name. ---------- Post added at 19:56 ---------- Previous post was at 18:58 ---------- Yes, I have the mission that inspired the event queue itself, and it is part of a campaign I have been (very slowly) working on, which is currently SP only. Because it is not the first mission in the campaign and the campaign has a little story to it, I will release just the init.sqf with all possible spoilers redacted: http://pastebin.com/pjjzgc7C The mission is still a bit WIP, but it is fully playable. -
Zenophon's ArmA 3 Co-op Mission Making Framework
Zenophon replied to Zenophon's topic in ARMA 3 - MISSION EDITING & SCRIPTING
For the markers array, I suggest: _townMkArray = []; for "_i" from 1 to 400 do { _townMkArray pushBack ("infmk" + str _i); }; The JIP code, #include "JIPSync.sqf", (line 80), must be before if (!isServer) exitWith {}; (line 18). The JIP logic there will work for enabled AI, but not for when there are no AI. This should not interfere with players who joined at the start. Also, in JIPSync.sqf, line 19, there is no fastroping, or 11th argument as far as I can tell. The extra weather code, lines 83-92 is not necessary. They can be put into the main loop to allow weather changes in a long mission. However, you must define (time can be different): _fogTime = 60*30; _overcastTime = 60*60; _fogStart = time; _overcastStart = time; f_HandleRespawn must be above 'if (!isServer) exitWith {};' so that it is defined for all clients, as MPRespawn EH does not run on the server (it should, this is a bug for BIS to fix). However, until then, f_HandleRespawn will run on the client that is respawning. In the description.ext, the framework #includes should be: #include "Zen_FrameworkFunctions\Zen_LoadoutFunctions\Zen_LoadoutDialog.hpp" class CfgNotifications { #include "Zen_FrameworkFunctions\Zen_TaskSystem\Zen_TaskNotifications.hpp" }; class CfgCommunicationMenu { #include "Zen_FrameworkFunctions\Zen_FireSupportSystem\Zen_FireSupportMenu.hpp" }; I noticed that the custom loadouts cannot give both magazines and GL shells, nor can you skip a matching magazine with []. I will make both of those improvements to the custom loadouts for next week. Also, BIS seems to have left the textSingular config entry for the Mi-48 as gunship, so I need to update the StringTable and relevant functions. I don't know why all helicopters can't just be 'helicopter'. This vehicle now spawns without a crew, so you will have to use createVehicleCrew until the next framework release. On line 286, waiting for the objective to complete is not necessary. It is stopping the while loop, so that it never continues to check the areas or spawn more enemies. Removing this code will allow the loop to function normally: waitUntil { sleep 5; ([[(_Objective1 select 1)]] call Zen_AreTasksComplete) }; Also, _sideObjTime is in seconds, so it should be e.g.: _sideObjTime = time + (60*([20, 30] call Zen_FindInRange)); To be 20-30 minutes; as currently it creates objectives every 5-10 seconds. Finally, the mission should not require that the AI exist, but that one player exists (it probably won't work as persistent when no one is playing). Disabling the AI removes their object from the mission, but I don't see any direct references to the players in the init.sqf. I have tested by putting this at the very top of the init.sqf: { if (_forEachIndex > 0) then { deleteVehicle _x; }; } forEach units player; Everything seems to work fine in SP with that. -
Zenophon's ArmA 3 Co-op Mission Making Framework
Zenophon replied to Zenophon's topic in ARMA 3 - MISSION EDITING & SCRIPTING
Since I wrote that occupy house script, I have a few tricks for determining things about buildings. I would do something like this: // Assume some urban area is covered by 'mkTown' // Assume there is some unit, '_unit' we want to put in a building _building = objNull; for "_i" from 1 to 100 do { // Get a random building _pos = ["mkTown"] call Zen_FindGroundPosition; _building = nearestBuilding _pos; // Set two positions in the XY center of the building _housePos = getPosASL _building; // Set a test position 50 meters in the air _checkPos =+ _housePos; _checkPos set [2, (_checkPos select 2) + 50]; // All buildings have 1 floor _floors = 1; for "_j" from 1 to 2 step 0 do { // To be sure, let each floor be 5 meters, and start on the 2nd floor _housePos set [2, (_housePos select 2) + 5]; // If a ray from the floor to the sky hits something, count this as a floor if !(lineIntersects [_housePos, _checkPos, objNull, objNull]) exitWith {}; _floors = _floors + 1; }; if (_floors > 2) exitWith {}; }; // Now we have a random building with more than 2 floors // Positions are 0-based _buildingPositions = 0; // Apply the standard algorithm to count its positions for "_i" from 0 to 100 do { if ((_building buildingPos _buildingPositions) isEqualTo [0,0,0]) exitWith {}; _buildingPositions = _buildingPositions + 1; }; // Generate an array of all valid positions _buildingPosArray = []; for "_i" from 0 to (_buildingPositions - 1) do { _buildingPosArray set [_i, _i]; }; // Randomize the array and loop through _buildingPosArray = [_buildingPosArray] call Zen_ArraySortRandom; { // More than three meters ATL should be the 2nd floor or above if (((_building buildingPos _x) select 2) > 5) exitWith { // Good position found, so put the unit there _unit setPosATL (_building buildingPos _x); }; } forEach _buildingPosArray; I have tested this in Kavala, and it detected a large office building just fine. You might need to increase the number of attempts for larger areas. I mean use the optional argument to Zen_CreateLoadout to give a meaningful name: 0 = [// ... loadout code ... // ], "MG Soldier"] call Zen_CreateLoadout; Now you can refer to that loadout from anywhere using 'MG Soldier'. You can put that name and others into an array: #define CUSTOM_LOADOUTS ["MG Soldier", "AT Soldier", "SF Soldier"] // or _loadouts = ["MG Soldier", "AT Soldier", "SF Soldier"]; You can use the preprocessor to fill in the loadouts in the entire init.sqf file, regardless of scope. You can also make different lists of loadouts, as well as shuffle and sort the loadouts. For the first part with sorting markers, I suggest: _nearMarkers = [["mkOreokastro", "mkCastle"], compile format ["(getMarkerPos _this) distance %1", getPosATL player]] call Zen_ArraySort; For the patrols, you can do: { SPAWN_NEAR(_x) } forEach ["mkOreokastro", "mkCastle"]; However, that waitUntil loop doesn't have a condition to exit, so the mission won't get to check if the fire support is queued. In the demonstration, the fire support event is only removed if a certain action is completed, but I don't see any code that connects destroying the mortar object to removing that fire support. The demonstration uses actions, but you could do something simpler: 0 = _obj2Object spawn { waitUntil { sleep 2; !(alive _this) }; 0 = "f_EventAction_FireSupport" call f_RemoveEvent; }; If the players manage to destroy the mortar, no fire support can happen. For spawning other patrols, you can just spawn them normally. The events are only for controlling effects with multiple causes. For sharing info, there is a short demonstration about that. You could expand who the squads can share info about and with. -
Zenophon's ArmA 3 Co-op Mission Making Framework
Zenophon replied to Zenophon's topic in ARMA 3 - MISSION EDITING & SCRIPTING
Introduction Greetings fellow scripters and Armaholics, in this latest installment, I will continue to discuss the development of the framework and, of course, shamelessly advertise the framework in any way possible. If this sounds boring, you can download the latest version from the original post. As always, the link to Google Drive for the .7z and .zip versions are already up to date. For those looking for older versions, go to file>revisions. The new version should be on Armaholic when Foxhound sees this or I PM him. Please bring any technical issues or mistakes to my attention, so e.g. people don't download the wrong version etc. Changelog Lucky release #7 has 17 changes, most of which involve the position functions. This is the first release for stable version 1.26, and will not work with 1.24. The most jarring changes are the renaming of Zen_AvoidPosition to Zen_FindValidDirection and Zen_AveragePositions to Zen_FindAveragePosition. I also apologize for a documentation oversight that let Zen_FindNearHeight have very incorrect parameter descriptions. Its documentation now fully agrees with the code. Zen_FindValidDirection has been completely rewritten and some parameters removed. A geometric proof occurred to me, in which the angle sector blocked by each circle was actually a triangle defined by the lines tangent to the circle and the line perpendicular through the center. Knowing the distance and direction to, and radius of each circle to avoid, blocked sector angles can be defined extremely easily with some trig. The function is now 100% accurate and gives all angles (whole numbers) that would avoid the given positions. In addition to geometric proofs, I was further embarrassed by finally realizing a simple and better algorithm for Zen_FindTerrainSlope. It now uses a simple trig algorithm to convert a surfaceNormal vector into the Z angle of the equivalent polar coordinate. Zen_FindTerrainSlope now only has one parameter, as using a radius to find an angled plane is no longer necessary. The 10th parameter for Zen_FindGroundPosition has been changed to reflect this as well. Leaving your code as is will be fine for this, extra arguments are simply ignored. I am also a fan of the new pushBack command added in 1.26, which I have used to replace every ugly looking '_array set [(count _array ...' line. It looks elegant and works faster, so there's no reason not to use it. A few other changes include fixing Zen_TransformObject so that it rotates the object correctly. The logic for setting the normal vector and the direction conflicted. Zen_OrderInfantryPatrol now works better in urban areas by giving the groups waypoints on a road. The AI should patrol the streets more rather than wander through backyards. Because I read every line of every BIS changelog, I could not help but notice that createVehicleCrew now works with partially filled vehicles. Obviously, I had to improve Zen_SpawnVehicleCrew to function similarly. The crew spots will also be filled with the correct class, e.g. a UH-80 with two pilots will get two crewman on the door guns. 8/27/14 Roadmap Although I claimed there would be a Zen_FindTerrainGradient, there doesn't seem to be any use for that. For those who want the direction of a hill, here's some trig: _normal = surfaceNormal _pos; _dir = ((_normal select 0) atan2 (_normal select 1)) + 180; I will probably use that in Zen_IsHillArea for next week. The preprocessor library is being written internally, but I am delaying the release until next week so that I can use some of the macros in the framework's source code. The point of these constants is that they are actually useful, so if I can't use them anywhere in the framework's 12000 lines of code they're probably useless. Function Spotlight As users of my framework know, there is an enormous number of functions at your disposal. The amount of documentation that has to be sifted through can be extremely daunting. Each week I spotlight a function and talk about its usefulness. If you have found an obscure function (not in tutorials, barely seen in demonstrations or sample missions) that you think is useful, PM me and I can spotlight it. The function chosen for this week is: Zen_ArraySortRandom. This function makes randomizations easier. Compare these two blocks: _markers = ["mk00", "mk01", "mk02", "mk03", "mk04"]; for "_i" from 1 to 5 do { _randMk = [_markers] call Zen_ArrayGetRandom; 0 = [_markers, _randMk] call Zen_ArrayRemoveValue; // ... do something }; or _markers = [["mk00", "mk01", "mk02", "mk03", "mk04"]] call Zen_ArraySortRandom; { // ... do something } forEach _markers; Also, array indexes will not line up easily in the first block for a parallel data structure. An example: if you have 5 markers and want to spawn three squads in each marker, you can have an array of markers and an array of arrays (containing the groups). In the first block, the array of markers would have to be reordered so that each marker aligned with the array of groups. In the second block, simply appending the groups to the groups array will keep it in synch with the markers. The difference is: _markersNew = []; _groupsArray = []; _markers = ["mk00", "mk01", "mk02", "mk03", "mk04"]; for "_i" from 0 to 4 do { _randMk = [_markers] call Zen_ArrayGetRandom; 0 = [_markers, _randMk] call Zen_ArrayRemoveValue; // ... do some spawning to define _groups; _markersNew pushBack _randMk; _groupsArray pushBack _groups; }; or _groupsArray = []; _markers = [["mk00", "mk01", "mk02", "mk03", "mk04"]] call Zen_ArraySortRandom; { // ... do some spawning to define _groups; _groupsArray pushBack _groups; } forEach _markers; I as much as I encourage you to code creatively using the framework, there is no doubt that the second block is simpler and more elegant. Beta As already stated, the framework is in the beta stage of development. I am making every effort to quality control releases, but there will be bugs. Both new features and old ones could have bugs, issues, and things people just don't like. There is no ETA or plan for a 'final' version. The framework is a work in progress, and it will continue to progress while there are improvements to be made (there always will be). Feedback As expected, some of the bugs have been pointed out by users, and those fixes are included in the changelog above. I want to thank everyone who has used/supported the framework. ---------- Post added at 22:39 ---------- Previous post was at 22:25 ---------- I am fairly certain that a for loop will round the upper bound, so 1 to 0.1 will become 1 to 0, which won't run. That kind of for loop uses a <= test, so 0 to 0 runs once, but 0 to -1 does not. Generally, you can't go wrong with: if (random 1 > 0.9) then { // ... }; For the loadouts, m0nkey is right, _loadout2 is a local variable undefined in the eventhandler's scope. Since you can't pass arbitrary variables directly to an EH, you need to use a global variable. You could also make use of the preprocessor if the loadouts have a fixed name literal; I always do this instead of letting them get the random string names like "Zen_loadout_123abc*()&". That name will also display on the loadout dialog. -
Zenophon's ArmA 3 Co-op Mission Making Framework
Zenophon replied to Zenophon's topic in ARMA 3 - MISSION EDITING & SCRIPTING
Thank you for your kind words; it's always good to know my work has made difference. As much as I would like to do everything, I have to focus on vital parts of mission making first. The more abstract features, such as repacking magazines, are greatly outnumbered by very direct functions dealing with spawning, objects, data structures, etc. For PvP, a few categories of functions will be useless (AI spawning and orders), and there are no demonstrations or sample missions to help with TvT gamemodes. However, significant features such as the task system, fire support, and the math and data functions with work exactly the same as before. The examples of player respawn and JIP using the framework will also function the same. Does the marker 'Oreokastro' cover the roads in the town? I have tested with a 200m circle over the town and the spawn points were always on a road. You can use Zen_SpawnMarker to quickly mark each spawn point, e.g.: _spawnPos = ["Oreokastro",0,0,1,[2,0]] call Zen_FindGroundPosition; 0 = [_spawnPos] call Zen_SpawnMarker; Also, Zen_OrderInfantryPatrol does not prefer roads, and this results in strange patrol patterns in urban areas. For the next release, Zen_OrderInfantryPatrol will move waypoints to roads less than 50 meters away. This should only affect patrols in dense urban areas by making them go around city blocks. I cannot reproduce the convoy issue either. The sound is likely a collision sound, and a collision can injure the crew of a vehicle. This could be an engine physics bug. Try removing the randomization of the convoy start and start the convoy on an open road away from obstacles. The spawning of the vehicle should not damage it immediately. -
Zenophon's ArmA 3 Co-op Mission Making Framework
Zenophon replied to Zenophon's topic in ARMA 3 - MISSION EDITING & SCRIPTING
m0nkey is right, you must get the groups or units dynamically every loop iteration. Using 'group X11' will work fine X11 exists. A more complex solution is: // Infinite loop that runs every ten seconds while {true} do { { // Redefine the players array to account for respawn/JIP _players = [west] call Zen_ConvertToObjectArray; _players = [_players, "!(isPlayer _x)"] call Zen_ArrayFilterCondition; // Only spawns patrols if at least one player is within 700 meters if !([_players, getMarkerpos _x, [700, 700], 0, "Ellipse"] call Zen_AreNotInArea) then { // ... }; // ... } // ... }; This will account for any number of players in any number of west groups and filter out AI. The '_players' variable is local to the init, and is undefined in eventhandlers as they are a different scope (the respawn eventhandler is even running on a client machine). -
Yes that will work. However, the loadouts are selected at random, so units would have a 1/12 chance of getting it. If you duplicated 'Guerrilla' 11 times, you would have a 1/2 chance, and so on. You will still get groups that are part Opfor and part FIA though. In order to make the groups homogeneous you would need to modify the spawning code to give the entire squad either a standard or FIA loadout.
-
The supply drop itself is set up as functions near the top of the init. You just need to put the code that uses them in the right place. Find this code (line 650): sleep 5; _exfilTask = [_rangers, "When all objectives are completed, the extraction point will appear on your map.", "Move to Extraction"] call Zen_InvokeTask; sleep 45; { deleteVehicle _x; } forEach (crew _infilHeli + [_infilHeli]); and replace it with: sleep 5; _exfilTask = [_rangers, "When all objectives are completed, the extraction point will appear on your map.", "Move to Extraction"] call Zen_InvokeTask; _playerGroups = [_rangers] call Zen_ConvertToGroupArray; { _playerGroups set [_forEachIndex, leader _x]; } forEach _playerGroups; if !(isDedicated) then { 0 = [_playerGroups, "Zen_SupplyDrop", "Ammo Drop", "[_pos, 'Ammo Drop'] call f_SupplyDrop"] call f_GiveSupport; }; Zen_MP_Closure_Packet = ["f_GiveSupport", [_playerGroups, "Zen_SupplyDrop", "Ammo Drop", "[_pos, 'Ammo Drop'] call f_SupplyDrop"]]; publicVariable "Zen_MP_Closure_Packet"; sleep 45; { deleteVehicle _x; } forEach (crew _infilHeli + [_infilHeli]); This will assign the leader of each Blufor group a support drop request immediately after all the Opfor and objectives have spawned.
-
Zenophon's ArmA 3 Co-op Mission Making Framework
Zenophon replied to Zenophon's topic in ARMA 3 - MISSION EDITING & SCRIPTING
Respawning is separate from JIP; JIP players run code to sync up with other clients and get the respawn eventhandler. After this they can respawn normally like other clients. There are more things that are not synch'd at JIP (e.g. weather, tasks) than at respawn (only actions, position, loadout). The respawn event only has to handle those things: f_HandleRespawn = { if (time < 5) exitWith {}; private ["_players", "_body"]; _player = _this select 0; _body = _this select 1; if (player == _player) then { titleText ["Still Alive", "BLACK FADED", 0.2]; }; 0 = [_player] call Zen_AddGiveMagazine; 0 = [_player] call Zen_AddRepackMagazines; 0 = _body spawn { sleep 300; deleteVehicle _this; }; }; Because you have a respawn marker, the engine handles moving the new player object there for you. Otherwise, you would have to code teleporting them to base yourself. If you wanted respawned players to have a different loadout than default, you could add that in as well. If an AI unit could be respawning, make sure to set their skill again. As for the mission not exporting correctly, check the size of the .pbo; it should be just over 500KB with just the framework source code alone. If it's too small, try exporting using the MP editor, or export to SP, or try an external .pbo packing tool. I have never had this issue with the regular editor, but I have seen it reported by other mission makers. I have also seen a bug in which an export to SP does not override an existing .pbo. -
This will not work, as that variable is only used to filter ammo boxes. In general, I do not recommend editing the framework source code unless you are 100% sure what you are doing. The point of using a function library is that you can use the functions the way you want without having to change internal code. Zen_ConfigGetVehicleClasses will not return anything that is not visible in the editor (scope = 2 in the config); this is to filter out base classes. The only framework function that will let you spawn hidden units is Zen_SpawnGroup. For example: _group = [_pos, ["O_G_Soldier_F", "O_G_Soldier_F"]] call Zen_SpawnGroup; If you want to change the mission to be FIA enemies only, this is what I recommend: First, make sure you have the original init.sqf from the last release of the mission. You also want the original code to spawn vehicles, not what I posted previously. Replace this (very top): #define OPFOR_LOADOUTS ["Rifleman", "Rifleman", "AssistantAA", "AssistantAT", "AssistantAR", "Recon", "TeamLeader", "Grenadier", "Autorifleman", "Marksman", "Medic"] #define OPFOR_VEHICLES ["O_MRAP_02_gmg_F", "O_MRAP_02_hmg_F", "O_MRAP_02_hmg_F"] with: #define OPFOR_LOADOUTS ["Guerrilla"] #define OPFOR_VEHICLES ["B_G_Offroad_01_armed_F"] Replace this (line 203): _reinforcements = [[0,0,0], ENEMY_SIDE, _AISkill, [4, 6]] call Zen_SpawnInfantry; with (I forgot to give these guys loadouts): _reinforcements = [[0,0,0], ENEMY_SIDE, _AISkill, [4, 6]] call Zen_SpawnInfantry; 0 = [_reinforcements, ENEMY_SIDE, OPFOR_LOADOUTS] call Zen_GiveLoadout; I have tested this, and everything works fine. Every time units spawn, they are given a loadout from the list at the top of the init. By changing the loadouts and vehicle list, you are changing everything that spawns for the entire mission. The enemy will look like FIA and drive their offroad, but will attack you the same as if they were Opfor. You can also use my custom loadout system and put those loadouts in there, as Zen_GiveLoadout handles both built-in loadouts and custom ones.
-
There are config entries for FIA soldiers that are technically 'east' or 'resistance'; these are hidden in the editor. If you look through cfgVehicles in the config view you should be able to find them. Like a lot of other classes, their names follow a standard scheme (I forget what that is). Another trick you can do is to use createGroup on the side that you want, then fill the group with any unit using createUnit. I assume that is what BIS_fnc_spawnGroup is doing. These methods are not used in my framework, as I prefer the loadouts method I used above. I don't intend for scripters to spawn units on the wrong side or use hidden classes; I think changing their uniforms and weapons is the most legitimate, issue-free method. In my framework, all classnames are retrieved dynamically from lists filtered from cfgVehicles. The function that does this is Zen_ConfigGetVehicleClasses. Thus, if you use Zen_SpawnInfantry with the 'east' side, it defaults to using classes of type 'men' with faction 'OPF_F' on side 'east'. This category is that same that you see in the editor under East -> Opfor -> Men. The function provides optional parameters for the type and faction, so you could use 'menSniper' if you want a sniper team. I also like randomization (as you can tell from my mission), so the function selects units randomly from this pool of classnames. If you really want to specificy which classes should spawn, use Zen_SpawnGroup.
-
Glad you are enjoying the mission. To change which vehicles spawn and spawn vehicles of different sides, you need to alter the logic for spawning vehicles so that a crew of the correct side spawns. Because FIA are technically on the Blufor side, you will have to fake it by giving Opfor units guerilla loadouts. This will have no impact when playing, it's just a coding trick. First you need to add the vehicles into the list to spawn. Replace this line (very top): #define OPFOR_VEHICLES ["O_MRAP_02_gmg_F", "O_MRAP_02_hmg_F", "O_MRAP_02_hmg_F"] with something like: #define OPFOR_VEHICLES ["O_MRAP_02_gmg_F", "O_MRAP_02_hmg_F", "O_MRAP_02_hmg_F", "B_G_Offroad_01_armed_F"] Then you need to change the vehicle spawning logic. Find this block (starts at line 635): for "_j" from 1 to 1 do { _opforVehicle = [([_x, [100, 800]] call Zen_FindGroundPosition), OPFOR_VEHICLES] call Zen_SpawnGroundVehicle; 0 = [_opforVehicleArray, _opforVehicle] call Zen_ArrayAppend; }; Replace it with this: for "_j" from 1 to 1 do { _vehicleType = [OPFOR_VEHICLES] call Zen_ArrayGetRandom; _opforVehicle = [([_x, [100, 800]] call Zen_FindGroundPosition), _vehicleType, 0, random 360] call Zen_SpawnVehicle; 0 = [_opforVehicle, ENEMY_SIDE] call Zen_SpawnVehicleCrew; 0 = [_opforVehicleArray, _opforVehicle] call Zen_ArrayAppend; // The 'in' command is case sensitive for strings if (_vehicleType in ["B_G_Offroad_01_armed_F"]) then { 0 = [(crew _opforVehicle), "guerilla"] call Zen_GiveLoadoutOpfor; }; }; Hope this helps, as I did not test it. This mission is using my co-op mission framework, (see my sig). If you want the documentation for all of the functions, it is included in the download from that thread. The support requests are given as rewards for completing the objectives. The current leaders of the group(s) (highest rank or first to join for JIP) get one usage of each support. The team leader loadout is not required in anyway; that is just a purely aesthetic name. There's no reason FAR revive won't work, as the mission has no respawn (except default group type, so JIP players can join). However, JIP itself may be an issue. If you need help with JIP, just ask and I can recommend some code. I have no idea if ALIVE will work; I don't use it as I prefer to create missions and objectives very manually through code. If it does, you could see things like objectives being close together, the extra Opfor units making things too hard, etc. Because ALIVE is an addon, I don't think it would be easy to make it compatible if it is not.
-
Zenophon's ArmA 3 Co-op Mission Making Framework
Zenophon replied to Zenophon's topic in ARMA 3 - MISSION EDITING & SCRIPTING
Introduction Greetings fellow scripters and Armaholics, in this latest installment, I will continue to discuss the development of the framework and, of course, shamelessly advertise the framework in any way possible. If this sounds boring, you can download the latest version from the original post. As always, the link to Google Drive for the .7z and .zip versions are already up to date. For those looking for older versions, go to file>revisions. The new version should be on Armaholic when Foxhound sees this or I PM him. Please bring any technical issues or mistakes to my attention, so e.g. people don't download the wrong version etc. Changelog This week sees a more impressive turnout, with 27 changes ranging from new functions, old functions remade, and minor fixes of all kinds. It seems that a framework release wouldn't be complete without a new function, so this week Zen_IsHillArea rounds out the new Position Functions category in helping you evaluate terrain. Zen_IsHillArea is especially valuable, in that is does not consider a slope to be a hill; only a true hill that comes to a top will be given a high value. Be prepared to find and replace, because Zen_FindMaxTerrainSlope is now named Zen_FindTerrainSlope. This is done so that the function name agrees semantically with what one calls the 'slope' of the terrain, rather than the mathematical meaning of 'slope' or gradient. In an even more drastic change, the parameters for Zen_FindNearHeight have changed entirely, only the first two were untouched. I know I spotlit that function last week, but I then realized that its search pattern arguments were unnecessarily esoteric. It now uses a faster, easier algorithm, similar to that used by Zen_IsNearTerrain. You don't have to worry about its search accuracy, just providing a radius is sufficient. Another parameter change (an optional one this time) for Zen_SpawnFortification makes the functions significantly more useful. You can now specific the exact radius of the ring of fortifications. Beware that you may experience strange behavior with very low numbers (below 3 meters). A lot of tweaking has been done to Zen_OrderExtraction and Zen_OrderInsertion to make helicopters land more realistically, and prevent AI stupidity such as taking off while units jump out. Helicopters should fire any weapons they can while approaching for a landing, or even on the ground. The curse of Zen_SpawnVehicle with heights over the ocean has been lifted. It turns out that boats and flying vehicles were being placed automatically at different heights. The function now carefully checks for all possible combinations of land/water, car/boat/helicopter, and collide/don't collide to make sure every situation is correct. This function is used so extensively that fixing this will make almost every other spawning function work properly now. Another bug concerns the functionality of Zen_TransformObject in MP, which was previously none for remote objects. Remember, no (public) framework function is meant to only work locally, or needs to be remotely executed manually. If the function runs on the server and doesn't do what the documentation claims, this is a bug and should be reported. To cut this excessive explanation short, I will end with the only exciting documentation change. The JIP demonstration has been partly rewritten to support JIP players for both enabled and disabled AI for playable characters. It also makes an elegant use of Zen_ReassignTask from the client machine instead of the ugly brute force solution to tasks previously used. 8/20/14 Roadmap Although much work has been done, there is always more to do. Next week I plan on a new function: Zen_FindTerrainGradient, which is the 3d vector version of Zen_FindTerrainSlope. I am also planning on improving the algorithm of Zen_AvoidPosition in some way just as was done for Zen_FindTerrainSlope, but testing will reveal if this will work out. The function may change entirely and fill a slightly different role (if you love Zen_AvoidPosition and want it to stay PM me). With only a few changes planned, I will probably introduce the new preprocessor library next week. I already have a lot of ideas for what will be included, but getting the documentation format set up will slow progress at first. Function Spotlight As users of my framework know, there is an enormous number of functions at your disposal. The amount of documentation that has to be sifted through can be extremely daunting. Each week I spotlight a function and talk about its usefulness. If you have found an obscure function (not in tutorials, barely seen in demonstrations or sample missions) that you found useful, PM me and I can spotlight it. The function chosen for this week is: Zen_SetAISkill. This is the framework tool for controlling mission difficulty and AI balance. The first important thing to note is: you have all been using this function indirectly every time you call Zen_SpawnInfantry. The third parameter of Zen_SpawnInfantry is the skill parameter passed to Zen_SetAISkill. For ease of use, Zen_SetAISkill offers several presets that differentiate different skill levels. These are all listed in the documentation, but the most useful ones are 'militia', 'infantry', and 'SOF'. These presets categorize the average AI soldier into three difficulty levels. The presets cover all possible AI abilities, including accuracy, recoil, teamwork, and spotting ability. If you only enter one value (not in an array of value), that is the value for all skills. However, for those who really want control over each skill, you can also enter every value directly. The values are matched with the skills in this order: 'aimingAccuracy', 'aimingShake', 'aimingSpeed', 'commanding', 'courage', 'endurance', 'general', 'reloadSpeed', 'spotDistance', 'spotTime'. This option has a special feature unique to this function. If you enter fewer values than there are skills, the remaining skills with use the last value entered. For example: 0 = [units X, [0.2, 0.8]] call Zen_SetAISkill; The units in X's group now have 0.2 accuracy and 0.8 of all other skills. This is most useful when you want to set the accuracy separately from all other skills. Finally, for a more detailed explanation on how these number translate to the AI's true skill, see the AI section of FrameworkIntroduction.txt. Beta As already stated, the framework is in the beta stage of development. I am making every effort to quality control releases, but there will be bugs. Both new features and old ones could have bugs, issues, and things people just don't like. There is no ETA or plan for a 'final' version. The framework is a work in progress, and it will continue to progress while there are improvements to be made (there always will be). Feedback As expected, some of the bugs have been pointed out by users, and those fixes are included in the changelog above. I want to thank everyone who has used/supported the framework. -
Zenophon's ArmA 3 Co-op Mission Making Framework
Zenophon replied to Zenophon's topic in ARMA 3 - MISSION EDITING & SCRIPTING
The code to check the vehicle's type and have it patrol uses '_randomObjectiveType' (which is 'custom') instead of the vehicle that was spawned. You must get the object created: // This is the first and only object spawned _objectiveVehicle = (_Objective1 select 0) select 0; if (_objectiveVehicle isKindOf "Air") then { 0 = [_objectiveVehicle, _objPos] spawn Zen_OrderAircraftPatrol; } else { 0 = [_objectiveVehicle, _objPos] spawn Zen_OrderVehiclePatrol; }; ---------- Post added at 22:09 ---------- Previous post was at 21:47 ---------- As CallMeSarge said, this is function library and SQF API with a strong focus on good documentation and learning to script missions. The functions are higher level than the built-in SQF commands, while being smaller pieces than large systems like EOS or UPSMON. For example, you can create any fire support imaginable with two lines, or randomly spawn dozens of squads patrolling in an area with about 6 lines. I am aiming for the right balance of ease of use that plain SQF lacks and adaptability that larger systems lack. It is not like MCC in that players can get editor-like functionality during the mission. It is a toolset for scripters and mission makers to aid them in building their mission using external scripts. In my opinion, scripting with my framework is easier and better for almost every part of mission making than using the editor. The point of using my framework for scripting is that instead of e.g. struggling to make tasks work or being frustrated about an AI helicopter insertion, you simply use the Zen function that does what you want. Although the framework is advertised as beta software, about 80-90% of it is nearly finished and working very well. It is very possible to create a mission using 100% scripting and dozens of my functions. The two missions in my signature are perfect examples of that. When creating a mission with the framework, you focus on the important logic in your mission and coding concrete steps using functions. When you want to change or improve your mission, or you need to fix a bug, all of your mission code is easy to find and read. If you want to change the skill of all AI, find and replace a few values and it's done; that would take hundreds of tedious clicks in the editor. -
Zenophon's ArmA 3 Co-op Mission Making Framework
Zenophon replied to Zenophon's topic in ARMA 3 - MISSION EDITING & SCRIPTING
Unfortunately, Zen_CreateObjective is not that smart; it cannot determine which units should be crew and which should not be in the vehicle. Instead you can spawn the crew yourself: // ... _extraArgs = [["O_MBT_02_cannon_F", "O_Heli_Attack_02_black_F"]]; // ... // Define _objPos and _units somewhere _objectiveData = ([_objPos, _units, east, _randomObjectiveType, "eliminate"] + _extraArgs) call Zen_CreateObjective; if (_randomObjectiveType == "custom") then { { 0 = [_x] call Zen_SpawnVehicleCrew; } forEach (_objectiveData select 0); }; This will work regardless of how many vehicles there are, as all the spawned vehicles are returned by Zen_CreateObjective. -
Zenophon's ArmA 3 Co-op Mission Making Framework
Zenophon replied to Zenophon's topic in ARMA 3 - MISSION EDITING & SCRIPTING
For randomizing extra objective arguments, there are different ways you could organize the data. Here is one: _objectiveTypes = ["box", "officer", "wreck", "mortar", "convoy", "custom"]; _randomObjectiveType = [_objectiveTypes] call Zen_ArrayGetRandom; _extraArgs = []; switch (_randomObjectiveType) do { case "convoy": { _extraArgs = ["mkConvoy", "normal"]; }; case "custom": { _extraArgs = [["B_Soldier_F", "B_Soldier_GL_F", "B_Helipilot_F"]]; }; }; // Define _objPos and _units somewhere 0 = ([_objPos, _units, west, _randomObjectiveType, "eliminate"] + _extraArgs) call Zen_CreateObjective; For some reason, Zen_SpawnVehicleCrew does not return anything. I think I just assumed that using the 'crew' command would work fine. However, there's no harm in returning the group of the crew, and it certainly fits in with the other spawning functions better. Until the next release though, this will work: 0 = [_spawnedVehicle, ENEMY_SIDE] call Zen_SpawnVehicleCrew; 0 = [_groupsArray, _enemyGroup, _enemyGroupG, (crew _spawnedVehicle)] call Zen_ArrayAppend; Also, Zen_SpawnVehicleCrew does not have parameters for AI skill or number. It fills the vehicle to however many position it requires (driver, gunners, etc.) and sets their skill to the 'crew' preset. You can still just change the skill with Zen_SetAISkill later. -
I will just quote my previous post on how to debug issues:
-
Overview Greeting fellow Armaholics, this update should put an end to the unfortunate series of issues with playing the mission in different player/AI configurations. I apologize that this could not be fixed sooner, but there are a lot different combinations and possibilities to consider when dealing with JIP and AI vs. no AI with a variable number of players. I want to be sure that something else is not broken in the attempt to fix one issue. Also, by user request, I have added a parameter for disabling the increased damage feature. To be clear, when this feature is disabled, the mission is fully compatible with any mods that use a 'HandleDamage' eventhandler on any of the units. Furthermore, and again by user request, I have created versions of the mission on Chernarus and Takistan. These versions are 100% exact ports of the mission; everything will work exactly as it does on Altis, just with the mission area resized to fit the maps. If anyone want me to port the mission to their favorite map, just give me a link to the mods required to get the map running and I will get it done swiftly. If you want to port it yourself, as it truly is very easy, I can send you a quick guide to doing it. The Google Drive link has been updated, and the Armaholic link will be soon. I have added links to the alternate map versions to the main post, with a link to the map pack required. Changelog 8/15/14 Fixed: All mission logic now works properly when only one player exists Fixed: JIP players are now considered for extraction and support options Added: Versions of the mission on Chernarus and Takistan Added: Mission parameter for increased damaged feature
-
Zenophon's ArmA 3 Co-op Mission Making Framework
Zenophon replied to Zenophon's topic in ARMA 3 - MISSION EDITING & SCRIPTING
Such a variable does exist. It is called 'Zen_Print_All_Errors', use: Zen_Print_All_Errors = false; Place it directly below the framework #include in the init.sqf to stop all errors printing to the screen as hint/chat. They will still log to the rpt file as always. -
Zenophon's ArmA 3 Co-op Mission Making Framework
Zenophon replied to Zenophon's topic in ARMA 3 - MISSION EDITING & SCRIPTING
1. This error is non blocking, meaning that it doesn't stop anything or return some other position; you can just ignore it. Is obviously not supposed to appear when the position is on the map. It is based upon config file data. I assume you are using the Chernarus from here: http://www.armaholic.com/page.php?id=23863 I just downloaded that to port a mission to Chernarus/Takistan. Looking at the config, the value is there and gives a resulting map size of 10100 meters. However, that is not the true size of the map (about 15360 meters), so there is a mistake somewhere. I am working on fixing this, but it is difficult when it is different for every map. 2. Yes, D1 as an object (player or AI) must exist in the mission, else 'D1' returns null. This should cause an engine error to print on the screen, something like 'undefined variable in expression'. There are several solutions; you could name all of them, then loop through until one is not null. You could also put a marker on the group, and use Zen_GetAllInArea. Finally, you could just give the repack action to all west units. 3. The weapons and their magazines must line up, and the TRG21 takes different magazines: ["weapons", [["arifle_TRG21_MRCO_F", "arifle_TRG21_GL_ACO_pointer_F", "LMG_Zafir_F","srifle_EBR_DMS_F","launch_RPG32_F"],"hgun_Pistol_heavy_01_F","Rangefinder"]], ["magazines", [[["30Rnd_556x45_Stanag", 9], ["30Rnd_556x45_Stanag", 9], ["150Rnd_762x51_Box", 4], ["20Rnd_762x51_Mag", 8], ["RPG32_F", 4]], ["11Rnd_45ACP_Mag", 2], ["HandGrenade", 2], [["SmokeShell", 4], ["SmokeShellBlue", 4]]]], It is working for me using those weapons and magazines, with the rest of the loadout unchanged. ---------- Post added at 16:58 ---------- Previous post was at 16:11 ---------- I have run the top loadout hundreds of times with no error: for "_i" from 0 to 99 do { 0 = [player, "Quadra"] call Zen_GiveLoadoutCustom; }; I assume you mean the error that pause the game and pop up a windows saying something like 'No config entry cfgMagazines\...'. If it does not actually list a magazine, but is '.' or empty string, I think this either an engine error or a script trying to access some invalid config value. Even this works: player addMagazine ""; The mistake is not in your loadout, and, at least for me, not in Zen_GiveLoadoutCustom. I can only assume it is a bug in the engine, a corrupt file, etc. No, after the loadout is given, nothing is recorded about what unit has what loadout. However, this is a perfect use for Zen_GetUnitLoadout. On each client machine: player setVariable ["Zen_Loadout_Data", ([player] call Zen_GetUnitLoadout)]; Unfortunately, due to a bug in Zen_GetUnitLoadout (which is already fixed internally), until next week you will have to use: _loadoutData = ([player] call Zen_GetUnitLoadout); ((_loadoutData select 7) select 1) resize ((count ((_loadoutData select 7) select 1)) - 2); player setVariable ["Zen_Loadout_Data", _loadoutData]; I apologize for the strange code, but it works fine. You could also put that into a 'killed' eventhandler, then get the data when they respawn. _loadoutTemp = [(player getVariable "Zen_Loadout_Data")] call Zen_CreateLoadout; 0 = [player, _loadoutTemp] call Zen_GiveLoadoutCustom; 0 = [_loadoutTemp] call Zen_RemoveLoadout; -
The AI skill is set only when they are spawned, for each group. Any mod that changes the skills after that, e.g. at 30 second intervals, would work fine. I don't know the details of how ASR works though; it might have a clever way of detecting spawned units. So long as it sets the skill more than a few frames after the group spawns, it will simply override the skill set by the mission. If you test it and it doesn't work, I can make an AI skill option that is 0.5 or 1, whatever the default would be after using createUnit.
-
Zenophon's ArmA 3 Co-op Mission Making Framework
Zenophon replied to Zenophon's topic in ARMA 3 - MISSION EDITING & SCRIPTING
Introduction Greetings fellow scripters and Armaholics, in this latest installment, I will continue to discuss the development of the framework and, of course, shamelessly advertise the framework in any way possible. If this sounds boring, you can download the latest version from the original post. As always, the link to Google Drive for the .7z and .zip versions are already up to date. For those looking for older versions, go to file>revisions. The new version should be on Armaholic when Foxhound sees this or I PM him. Please bring any technical issues or mistakes to my attention, so e.g. people don't download the wrong version etc. Changelog This update has 16 changes, with many fixes and a few improvements. Most importantly, there is a new file that must be put into your mission folder for the framework to operate correctly. This is a StringTable.xml file that localizes some specific config values so that a few functions will work regardless of your language setting. Also, very importantly, the framework code in the Description.ext has changed. This must be updated for all missions by replacing the old three lines with the new code in the sample description.ext. This was done to ensure not compatibility issues with missions that use custom config entries under CfgCommunicationMenu and cfgNotifications. There is also one new function, Zen_IsUrbanArea. It is similar to Zen_IsForestArea, but handles buildings and roads instead of trees. The more minor fixes this week include another argument checking mistake for Zen_ConfigGetVehicleClasses, getting Zen_SpawnVehicle to use the height as ATL or ASL, and Zen_InvokeFireSupport never firing three possible type of ammunition. Zen_OrderExtraction and Zen_OrderInsertion now make helicopters behave more realistically by not turning off their engines momentarily. This used to be done to keep them from moving, but now they are forced to stay on the ground my other means. 8/13/14 Roadmap That last promised function, Zen_IsHillArea, should be done next week. It is only a matter of interpreting the terrain slope and difference in elevation relative area size into a 0-1 number. I am still designing the preprocessor library; two obvious categories have emerged: function-specific values that can fill in for arguments, and general purpose argument macros for common code. Due to popular demand, I am going to improve the demonstration dealing the JIP so that it handles disabled AI (players join as a new object, not into an AI). I am trying to make the solution as elegant and readable as possible, so beginners and experts alike can use the code. Function Spotlight As users of my framework know, there is an enormous number of functions at your disposal. The amount of documentation that has to be sifted through can be extremely daunting. Each week I spotlight a function and talk about its usefulness. If you have found an obscure function (not in tutorials, barely seen in demonstrations or sample missions) that you found useful, PM me and I can spotlight it. The function chosen for this week is: Zen_FindNearHeight. This functions uses a random search pattern to find the position with the highest elevation. It is very useful for finding hills and high points that are not named locations on the map. It could be used to put a sniper team on a hill near a town, or you are looking for a possible landing zone. For example: _hill = ["mkTown", 500] call Zen_FindNearHeight; _snipers = [_hill, west, "sniper", 2, "menSniper"] call Zen_SpawnInfantry; The function checks a number of random points in the radius; how many times is determined as a function of the radius size. After you have the high point, you can make use of Zen_FindGroundPosition or another position function to check that it is a certain type of point. For example, a helicopter landing zone near the player: for "_i" from 0 to 320 step 60 do { _center = [player, 100, _i] call Zen_ExtendPosition; _hill = [_center, 100] call Zen_FindNearHeight; if (([_hill, 50] call Zen_IsForestArea) < 0.3) exitWith { _lz = [_hill, [1, 50], 0, 1, 0, 0, 0, 0, 0, [1, 20, 10], [1, [0, -1, -1], 15]] call Zen_FindGroundPosition; }; }; Looking at the arguments to Zen_FindGroundPosition to avoid steep slopes and trees, you can see why a preprocessor constant for find an LZ is a good idea. Beta As already stated, the framework is in the beta stage of development. I am making every effort to quality control releases, but there will be bugs. Both new features and old ones could have bugs, issues, and things people just don't like. There is no ETA or plan for a 'final' version. The framework is a work in progress, and it will continue to progress while there are improvements to be made (there always will be). Feedback As expected, some of the bugs have been pointed out by users, and those fixes are included in the changelog above. I want to thank everyone who has used/supported the framework. The specific request this week is: spawning randomization. I want to know how much mission makers use exact vehicles, soldiers, and loadouts, and how much you let things be random. This will help me determine if I should offer parameters that can be both precise and random, or just focus on one of those. --------------------------------------------------------------------------------------------- ---------- Post added at 19:59 ---------- Previous post was at 19:18 ---------- --------------------------------------------------------------------------------------------- Without seeing your init.sqf I cannot offer an specific fixes. However, make sure that all framework functions are used only on the server and after 'sleep 1' in the init.sqf. Any functions used before this can have duplicate effects by running on all clients and will not propagate in MP correctly. The only things meant to be put above 'sleep 1' or 'if !(isServer) exitWith {}' are those put there in the tutorials and sample missions. If you intent for things like repacking magazines to work with JIP, then you must include the code from the JIP demonstration and set it up correctly. However, if all players are there from the start (ready at briefing) then JIP is not necessary. The only framework documentation resource that addresses what you are trying to do is the Zen_AssaultFrini sample mission. The JIPSync.sqf file there is designed to handle JIP players when there are no AI. The problem is that when you disable the AI, players that join that mission are created as new objects. This means that because they previously did not exist, existing tasks cannot be sent to them without extra code that merges their object into the framework task system data. You also need to set up giving tasks in the mission so that all current players get that task. This will be much easier if you give all Blufor players the same tasks, rather than giving different groups of players different tasks. Then, if all players leave the server, you will be able to give the first new player tasks without trying to figure out which set of tasks he should get. First, when giving a task, use Zen_ConvertToObjectArray to give it to all Blufor units: _task = [([west] call Zen_ConvertToObjectArray), "Description", "Title"] call Zen_InvokeTask; Then, in the JIP sync code, you must include the new player object in the array of objects of each task: { _x set [1, (_x select 1) + [player]]; } forEach Zen_Task_Array_Global; publicVariable "Zen_Task_Array_Global"; I pointed you to my Black Ops mission not for the mission itself, but for the JIPSync.sqf logic that handles what to do with players that join. It check whether or not the player is a new object, so it can assign the task properly. One of the tests I ran for that mission was to join and leave several times, into different groups, from two separate client machines on a dedicated server. Even having the dead objects in the task data did not interfere with giving the client the tasks every time. I personally don't like solutions that involve dealing with internal framework data, so I am going to improve the JIP demonstration to handle no AI using Zen_ReassignTask instead of this manual approach. That will be included in the release next week, and it should make that JIP code a solution for all missions.