Jump to content
Zenophon

Zenophon's ArmA 3 Co-op Mission Making Framework

Recommended Posts

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 links 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 soon. Please bring any technical issues or mistakes to my attention, so e.g. people don't download the wrong version etc.

Changelog

This release is another fixathon for issues great and small. New additions include a paradrop option for Zen_OrderInsertion, which is provided as an alternative to the existing landing and fastroping options for helicopters. The only downside is units will lose their existing backpack. The parameter that was true/false is now a string naming which type of insertion.

Thanks to a user report, Zen_OrderInsertion is also now working well for insertions over the ocean. The helicopter would previously crash into the water, but now the units are properly kicked out from a few meters. Counter-intuitively, that is still called 'land' in the arguments (though you can also fastrope into the ocean). Zen_OrderInsertion also has a new parameter for deleting the vehicle at the end.

Zen_OrderInfantryPatrolBuilding now supports multiple buildings, and in the spirit of randomization, all units will patrol all buildings at random. The function will still pick the nearest building first, then expand the search around that building within 100 meters, collecting the given number of extra buildings. It will also give new orders to AI that are stuck or stopped for some reason, even if they don't think they are done moving.

Due to reports that AI helicopters were trying to get away from the clutches of Zen_OrderFastRope, I've tweaked how Zen_OrderInsertion and Zen_OrderHelicopterLand hand off to Zen_OrderFastRope. This should minimize the time the AI have to change altitude; Zen_OrderFastRope will also keep the rope at the correct length so all units reach the ground safely.

I know this is always annoying, but Zen_FindBuildingPositions has had parameters 2 and 3 swapped. This is because it's not feasible to enter the default value for the number of positions, so allowing roof positions meant overriding that default with a guess. Also, ZEN_STD_Math_VectTransformATL was renamed ZEN_STD_Math_VectTransform, as it doesn't matter what the vector is; it blindly adds to each component.

Finally, you may recognize Zen_CheckArguments from error reports, as it is used in almost every framework function. I've decided to make a few improvements and document it due to its great usefulness. The documentation doesn't give any examples of how to use it, so Zen_CheckArguments will be the spotlit function this release.

3/25/15

  1. Fixed: Zen_GiveLoadoutBlufor, Zen_GiveLoadoutIndfor, Zen_GiveLoadoutOpfor turned on NVG's for guerrilla and civilian loadouts
  2. Fixed: Zen_GiveLoadoutCustom turned on NVG's when none were specified in the loadout
  3. Fixed: Zen_OrderFastRope did not adjust rope length for helicopter movement
  4. Fixed: Zen_OrderInfantryPatrolBuilding did not keep stopped units moving if the AI was not ready
  5. Fixed: Zen_OrderInsertion now remote executes disembark orders for remote AI
  6. Fixed: Zen_RotateAsSet reversed the height of objects
  7. Added: Framework macro ZEN_FMW_Loadout_DefaultPreset
  8. Added: Zen_OrderInfantryPatrolBuilding parameter for patrolling multiple buildings
  9. Added: Zen_OrderInsertion parameter for delete the vehicle at the end
  10. Improved: Zen_CheckArguments now checks that the arguments are an array
  11. Improved: Zen_CheckArguments now checks for null controls, displays, scripts, and tasks
  12. Improved: Zen_CheckArguments now accepts 'FUNCTION' to check for function string names being nil
  13. Improved: Zen_FindBuildingPositions parameters 2 and 3 swapped
  14. Improved: Zen_OrderFastRope now keeps AI helicopters at an ideal fastroping altitude better
  15. Improved: Zen_OrderHelicopterLand removed unnecessary sleep at the end
  16. Improved: Zen_OrderHelicopterLand now waits for a helicopter to hover low over the water before exiting
  17. Improved: Zen_OrderInsertion offers parachute insertion as a third option
  18. Improved: Zen_OrderInsertion turns off the helicopter's engines if only one destination is given
  19. Improved: Zen_OrderInsertion now forces units to jump out of a helicopter over the water without crashing the helicopter
  20. Improved: ZEN_STD_Math_VectTransformATL renamed ZEN_STD_Math_VectTransform
  21. Documentation: Added for Zen_CheckArguments, ZEN_FMW_Loadout_DefaultPreset
  22. Documentation: Updated for Zen_FindBuildingPositions, Zen_OrderInfantryPatrolBuilding, Zen_OrderInsertion, ZEN_STD_Math_VectTransform

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 release 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 release is: Zen_CheckArguments. This function is a powerful tool for catching errors, finding bugs, and writing maintainable, reusable code. It is designed to, as efficiently as possible, check all the arguments of a function. I've taken the time to use this function in 180 others because it forces you to comply with the documentation, at least in the type of the arguments.

Here's a very simple example:

f_testArgs = {
   player sideChat str ([_this, [["SCALAR"], ["STRING"]], [], 2] call Zen_CheckArguments);
};

[1, "hello"] call f_testArgs;
[1, 2] call f_testArgs;

'_this' will always be given, if you want to check all the arguments to the function. SCALAR and STRING are the types, as aligned with their argument. The third argument is for nested array, which is shown below. The last argument is the minimum number of arguments.

f_testArgs = {
   player sideChat str ([_this, [["SCALAR"], ["ARRAY"]], [[], ["STRING"]], 2] call Zen_CheckArguments);
};

[1, "hello"] call f_testArgs;
[1, ["hello"]] call f_testArgs;
[1, 2] call f_testArgs;
[1, [2]] call f_testArgs;

Only one of those has valid arguments. You can quickly see how useful this function is for preventing silly errors. Here's how it's used in framework functions:

if !([_this, [["VOID"], ["SIDE", "ARRAY", "STRING"], ["STRING", "ARRAY"]], [[], ["STRING"]], 2] call Zen_CheckArguments) exitWith {
   call Zen_StackRemove;
   ([objNull])
};

This one happens to be from Zen_SpawnConvoy. VOID means don't check for type (Zen_ConvertToPosition is used later to check). You can see how the documentation for Zen_SpawnConvoy has been translated into allowed arguments. Zen_SpawnConvoy is supposed to return an array of objects, so the return value is a null value of that type.

You might be thinking: isn't this a waste of time if the arguments are correct? You are correct; in fact, it is useless about 90% of the time. It's only useful when you get an error from a framework function and you don't know why. Thus, you can simply disable it entirely once your code is stable:

Zen_Debug_Arguments = false;

Just put that where all clients and the server will run it, and Zen_CheckArguments will always return true.

Finally, you cannot make good use of Zen_CheckArguments without also using the framework's stack trace, as errors from Zen_CheckArguments rely on that stack trace to show which function's arguments they are checking. See the Stack Trace demonstration mission for more information on how to use that. Of course, there's no shortage of example usages of Zen_CheckArguments (just look in any framework function).

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).

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.

Share this post


Link to post
Share on other sites
Guest

Thanks for always taking the time to inform us about your newest releases :cool:

Release frontpaged on the Armaholic homepage.

================================================

We have also "connected" these pages to your account on Armaholic.

This means soon you will be able to maintain these pages yourself if you wish to do so. Once this new feature is ready we will contact you about it and explain how things work and what options you have.

When you have any questions already feel free to PM or email me!

Share this post


Link to post
Share on other sites

Hey Zen. The new release has an issue with Zen_OrderInsertion. If you insert with a ground vehicle the Infantry won't disembark from the vehicle. I haven't tried the other vehicle types yet.

Share this post


Link to post
Share on other sites
Hey Zen. The new release has an issue with Zen_OrderInsertion. If you insert with a ground vehicle the Infantry won't disembark from the vehicle. I haven't tried the other vehicle types yet.

I found this as well however, if they detect an enemy they'll disembark.

Zen_orderExtraction, is it intended behaviour that when the vehicle gets to the 2nd marker the group that was extracted sit in the vehicle until you order them out?

Share this post


Link to post
Share on other sites
Hey Zen. The new release has an issue with Zen_OrderInsertion. If you insert with a ground vehicle the Infantry won't disembark from the vehicle. I haven't tried the other vehicle types yet.

It seems that all the code for a 'land' insertion got moved under 'if (_vehicle isKindOf "AIR")', when only the code for hovering over water was supposed to go there. I've posted a new version to google drive with that small fix, or you can correct it yourself by moving the forEach loop that starts with '["orderGetIn", [[_x], false]]' just outside the if statement.

I found this as well however, if they detect an enemy they'll disembark.

Zen_orderExtraction, is it intended behaviour that when the vehicle gets to the 2nd marker the group that was extracted sit in the vehicle until you order them out?

Disembarking under fire is controlled by the engine: setUnloadInCombat. That is the intended behavior for Zen_OrderExtraction; it only contains the logic for making units get in. Once the Zen_OrderExtraction thread has finished, you can use the macro ZEN_STD_OBJ_OrderGetOut to order AI out.

Share this post


Link to post
Share on other sites

It's amazing how a misplaced }; can break a mission....LOL! Thanks for the quick fix.

I have a question about the find ground positions function.....I want it to stay at least 10m away from all buildings and clutter, what params would I use to accomplish this? I've had no luck getting this to work on a consistent basis!

Share this post


Link to post
Share on other sites
It's amazing how a misplaced }; can break a mission....LOL! Thanks for the quick fix.

I have a question about the find ground positions function.....I want it to stay at least 10m away from all buildings and clutter, what params would I use to accomplish this? I've had no luck getting this to work on a consistent basis!

You have to consider that buildings and trees are viewed as points; so 10m from a building doesn't mean 10m from a wall, it means 10m from its center (which could place you inside the building). Likewise, the branches of trees are not considered. In general, you want to add up the distances to account for the worst case. For a helicopter to land, allow 15 meters for AI stupidity, 10 meters for a large tree, 20 meters for a large building, etc. Altis is likely to give you a valid position somewhere, even with large constraints. There are also tricks like using road positions and switching to fastroping.

Making the computer detect what constitutes a 'building' or a 'tree' relies on that object having some common property. You can be fairly confident that 'nearestObjects [_pos, ["House", "Building", "Ruins"]' will get most buildings, but trees are detected by having 't_' in their 3D model name. If the function obviously missed an object, you'd have to debug it by using the same detection methods (Zen_GetAmbientClutterCount) Zen_FindGroundPosition uses (those are Zen_CheckPositions.sqf).

This is especially problematic on addon islands, as there's absolutely no way to predict what is a tree if it doesn't have a consistent name. If you've allow more than enough distance for trees, but find positions in a forest, then Zen_FindGroundPosition has been fooled. I rarely play with addons, so if you can fool Zen_GetAmbientClutterCount with some addon objects, tell me and I'll update it to recognize those as well.

Share this post


Link to post
Share on other sites
You have to consider that buildings and trees are viewed as points; so 10m from a building doesn't mean 10m from a wall, it means 10m from its center (which could place you inside the building). Likewise, the branches of trees are not considered. In general, you want to add up the distances to account for the worst case. For a helicopter to land, allow 15 meters for AI stupidity, 10 meters for a large tree, 20 meters for a large building, etc. Altis is likely to give you a valid position somewhere, even with large constraints. There are also tricks like using road positions and switching to fastroping.

Making the computer detect what constitutes a 'building' or a 'tree' relies on that object having some common property. You can be fairly confident that 'nearestObjects [_pos, ["House", "Building", "Ruins"]' will get most buildings, but trees are detected by having 't_' in their 3D model name. If the function obviously missed an object, you'd have to debug it by using the same detection methods (Zen_GetAmbientClutterCount) Zen_FindGroundPosition uses (those are Zen_CheckPositions.sqf).

This is especially problematic on addon islands, as there's absolutely no way to predict what is a tree if it doesn't have a consistent name. If you've allow more than enough distance for trees, but find positions in a forest, then Zen_FindGroundPosition has been fooled. I rarely play with addons, so if you can fool Zen_GetAmbientClutterCount with some addon objects, tell me and I'll update it to recognize those as well.

I use addons but I'm playing on altis in it's stock form. However I never considered that it used the center point of the objects and I'll have to adjust for that. Also the parameter of the number of objects....if I set it to exclude and put the number to 0 then it shouldn't locate near any building correct?

Share this post


Link to post
Share on other sites
I use addons but I'm playing on altis in it's stock form. However I never considered that it used the center point of the objects and I'll have to adjust for that. Also the parameter of the number of objects....if I set it to exclude and put the number to 0 then it shouldn't locate near any building correct?

Yes, excluding 0 means allow 0 buildings/trees/whatever. Exclude 1 would mean that 0 or 1 objects are allowed within the radius. If you tried to include 0 it will always succeed; including 1 will succeed when there are 1 or more objects, etc.

Share this post


Link to post
Share on other sites

Hey Zen I found a couple things in my .rpt that I thought you should know about (if you don't already that is)

1. When I use the insertion as a parachute type I get this error when the disembark the heli!

22:08:14 Error in expression <(configFile >> "CfgVehicles" >> (typeOf _heli) >> "AnimationSources"));
sleep 1;>
22:08:14   Error position: <_heli) >> "AnimationSources"));
sleep 1;>
22:08:14   Error Undefined variable in expression: _heli
22:08:14 File C:\Users\I7-950\Documents\Arma 3 - Other Profiles\CDN_BiggDogg\mpmissions\Make_Way_test.Altis\Zen_FrameworkFunctions\Zen_OrdersFunctions\Zen_OrderInsertion.sqf, line 125

However it still functions properly, they all disembark and parachute to the ground fine!

BTW is there a way to remove their backpacks then give them back after they land? Not a big deal if you can't it's just the medics and engineers lose their kits and the AT and AA guys lose their launcher ammo!

2. Also for insertion I was using two positions, an insertion point and an exfiltration point with delete the vehicle enabled and the delete failed ever time with this error.

20:57:46 Error in expression <       deleteVehicle _x;     } forEach (crew _cleanup + [_cleanup]);
};

call Ze>
20:57:46   Error position: <crew _cleanup + [_cleanup]);
};

call Ze>
20:57:46   Error crew: Type Bool, expected Object
20:57:46 File C:\Users\I7-950\Documents\Arma 3 - Other Profiles\CDN_BiggDogg\mpmissions\Make_Way_test.Altis\Zen_FrameworkFunctions\Zen_OrdersFunctions\Zen_OrderInsertion.sqf, line 163

3. When I use insertion with fastrope I've found a couple problems. First and the most obvious problem is that the fast rope fails most of the time when using the Mohawk transport chopper. One of the descending units will die at the bottom and no other units will descend and the chopper just hovers there. Again....only happens with the Mohawk. And second I get this in the .rpt but the action doesn't fail.

23:42:57 Error in expression <[_linkAir, [0,-0.25,-0.5]];
ropeUnwind [_ropeAir, 7, (_ropeStartPos select 2) + >
23:42:57   Error position: <_ropeAir, 7, (_ropeStartPos select 2) + >
23:42:57   Error Undefined variable in expression: _ropeair
23:42:57 File C:\Users\I7-950\Documents\Arma 3 - Other Profiles\CDN_BiggDogg\mpmissions\Make_Way_test.Altis\Zen_FrameworkFunctions\Zen_OrdersFunctions\Zen_OrderFastRope.sqf, line 128
23:42:58 Error in expression <ble "Zen_ExecuteCommand");

ropeDestroy _ropeAir;
deleteVehicle _linkAir;
sleep >
23:42:58   Error position: <_ropeAir;
deleteVehicle _linkAir;
sleep >
23:42:58   Error Undefined variable in expression: _ropeair
23:42:58 File C:\Users\I7-950\Documents\Arma 3 - Other Profiles\CDN_BiggDogg\mpmissions\Make_Way_test.Altis\Zen_FrameworkFunctions\Zen_OrdersFunctions\Zen_OrderFastRope.sqf, line 153
23:42:59 Error in expression <[_linkAir, [0,-0.25,-0.5]];
ropeUnwind [_ropeAir, 7, (_ropeStartPos select 2) + >
23:42:59   Error position: <_ropeAir, 7, (_ropeStartPos select 2) + >
23:42:59   Error Undefined variable in expression: _ropeair
23:42:59 File C:\Users\I7-950\Documents\Arma 3 - Other Profiles\CDN_BiggDogg\mpmissions\Make_Way_test.Altis\Zen_FrameworkFunctions\Zen_OrdersFunctions\Zen_OrderFastRope.sqf, line 128
23:43:00 Error in expression <ble "Zen_ExecuteCommand");

ropeDestroy _ropeAir;
deleteVehicle _linkAir;
sleep >
23:43:00   Error position: <_ropeAir;
deleteVehicle _linkAir;
sleep >
23:43:00   Error Undefined variable in expression: _ropeair
23:43:00 File C:\Users\I7-950\Documents\Arma 3 - Other Profiles\CDN_BiggDogg\mpmissions\Make_Way_test.Altis\Zen_FrameworkFunctions\Zen_OrdersFunctions\Zen_OrderFastRope.sqf, line 153

4. The only thing that I JIP from your framework is the tasks and I'm having issues with that, likely because of the way I've implemented it. I run a persistent server that at times have no players or AI in it which seems to break the task system. The only way around this was to create a game logic that I named X5 and included it in the task 'destination' characters which seems to work for when people join but I'm have issues with updating the task array when missions are completed and also in removing them after!

OK so when I issue a taskremove I get this error most of the time.

23:44:46 "-- Zen_CheckArguments Error --"
23:44:46 "Argument 1 is void"
23:44:46 2490.82
23:44:46 [No task,[No task,No task]]
23:44:46 ["Zen_CheckArguments",[No task,[No task,No task]],2490.82]
23:44:46 ["Zen_ValueIsInArray",[No task,[No task,No task]],2490.82]
23:44:46 ["Zen_ArrayFilterValues",[[No task,No task],[No task,No task]],2490.82]
23:44:46 ["Zen_RemoveTaskClient",["basedefend",[X5,X11]],2490.82]
23:44:46 ["Zen_RemoveTask",["basedefend",[[X5],[X11]]],2490.82]
23:44:46 "-- Zen_CheckArguments Error --"
23:44:46 "Argument 1 is void"
23:44:46 2490.89
23:44:46 [No task,[No task,No task]]
23:44:46 ["Zen_CheckArguments",[No task,[No task,No task]],2490.89]
23:44:46 ["Zen_ValueIsInArray",[No task,[No task,No task]],2490.89]
23:44:46 ["Zen_ArrayFilterValues",[[No task,No task],[No task,No task]],2490.82]
23:44:46 ["Zen_RemoveTaskClient",["basedefend",[X5,X11]],2490.82]
23:44:46 ["Zen_RemoveTask",["basedefend",[[X5],[X11]]],2490.82]
23:44:46 Bad conversion: array
23:44:46 Error in expression <th {};

It seems to remove the task from the clients but not always from the 'Zen_Task_Array_Global'. So if I issue this

Zen_Task_Array_Global = [];
publicVariable Zen_Task_Array_Global;

Will that clear the task array when my tasks are finished and not mess with your frameworks systems? And do I need to publicvariable it or just run that on the server?

Please keep in mind that these aren't complaints, just reporting to you what I've found so if need be you can address them. As a mission maker I know that you can create a scenario that you think is bulletproof only to have someone tackle it a different way and introduce variables you never considered. I hope these are helpful!

Your framework is really great to work with and I appreciate all the work you have done in creating it!

Share this post


Link to post
Share on other sites
Hey Zen I found a couple things in my .rpt that I thought you should know about (if you don't already that is)

1. When I use the insertion as a parachute type I get this error when the disembark the heli!

22:08:14 Error in expression <(configFile >> "CfgVehicles" >> (typeOf _heli) >> "AnimationSources"));
sleep 1;>
22:08:14   Error position: <_heli) >> "AnimationSources"));
sleep 1;>
22:08:14   Error Undefined variable in expression: _heli
22:08:14 File C:\Users\I7-950\Documents\Arma 3 - Other Profiles\CDN_BiggDogg\mpmissions\Make_Way_test.Altis\Zen_FrameworkFunctions\Zen_OrdersFunctions\Zen_OrderInsertion.sqf, line 125

However it still functions properly, they all disembark and parachute to the ground fine!

BTW is there a way to remove their backpacks then give them back after they land? Not a big deal if you can't it's just the medics and engineers lose their kits and the AT and AA guys lose their launcher ammo!

2. Also for insertion I was using two positions, an insertion point and an exfiltration point with delete the vehicle enabled and the delete failed ever time with this error.

20:57:46 Error in expression <       deleteVehicle _x;     } forEach (crew _cleanup + [_cleanup]);
};

call Ze>
20:57:46   Error position: <crew _cleanup + [_cleanup]);
};

call Ze>
20:57:46   Error crew: Type Bool, expected Object
20:57:46 File C:\Users\I7-950\Documents\Arma 3 - Other Profiles\CDN_BiggDogg\mpmissions\Make_Way_test.Altis\Zen_FrameworkFunctions\Zen_OrdersFunctions\Zen_OrderInsertion.sqf, line 163

3. When I use insertion with fastrope I've found a couple problems. First and the most obvious problem is that the fast rope fails most of the time when using the Mohawk transport chopper. One of the descending units will die at the bottom and no other units will descend and the chopper just hovers there. Again....only happens with the Mohawk. And second I get this in the .rpt but the action doesn't fail.

23:42:57 Error in expression <[_linkAir, [0,-0.25,-0.5]];
ropeUnwind [_ropeAir, 7, (_ropeStartPos select 2) + >
23:42:57   Error position: <_ropeAir, 7, (_ropeStartPos select 2) + >
23:42:57   Error Undefined variable in expression: _ropeair
23:42:57 File C:\Users\I7-950\Documents\Arma 3 - Other Profiles\CDN_BiggDogg\mpmissions\Make_Way_test.Altis\Zen_FrameworkFunctions\Zen_OrdersFunctions\Zen_OrderFastRope.sqf, line 128
23:42:58 Error in expression <ble "Zen_ExecuteCommand");

ropeDestroy _ropeAir;
deleteVehicle _linkAir;
sleep >
23:42:58   Error position: <_ropeAir;
deleteVehicle _linkAir;
sleep >
23:42:58   Error Undefined variable in expression: _ropeair
23:42:58 File C:\Users\I7-950\Documents\Arma 3 - Other Profiles\CDN_BiggDogg\mpmissions\Make_Way_test.Altis\Zen_FrameworkFunctions\Zen_OrdersFunctions\Zen_OrderFastRope.sqf, line 153
23:42:59 Error in expression <[_linkAir, [0,-0.25,-0.5]];
ropeUnwind [_ropeAir, 7, (_ropeStartPos select 2) + >
23:42:59   Error position: <_ropeAir, 7, (_ropeStartPos select 2) + >
23:42:59   Error Undefined variable in expression: _ropeair
23:42:59 File C:\Users\I7-950\Documents\Arma 3 - Other Profiles\CDN_BiggDogg\mpmissions\Make_Way_test.Altis\Zen_FrameworkFunctions\Zen_OrdersFunctions\Zen_OrderFastRope.sqf, line 128
23:43:00 Error in expression <ble "Zen_ExecuteCommand");

ropeDestroy _ropeAir;
deleteVehicle _linkAir;
sleep >
23:43:00   Error position: <_ropeAir;
deleteVehicle _linkAir;
sleep >
23:43:00   Error Undefined variable in expression: _ropeair
23:43:00 File C:\Users\I7-950\Documents\Arma 3 - Other Profiles\CDN_BiggDogg\mpmissions\Make_Way_test.Altis\Zen_FrameworkFunctions\Zen_OrdersFunctions\Zen_OrderFastRope.sqf, line 153

4. The only thing that I JIP from your framework is the tasks and I'm having issues with that, likely because of the way I've implemented it. I run a persistent server that at times have no players or AI in it which seems to break the task system. The only way around this was to create a game logic that I named X5 and included it in the task 'destination' characters which seems to work for when people join but I'm have issues with updating the task array when missions are completed and also in removing them after!

OK so when I issue a taskremove I get this error most of the time.

23:44:46 "-- Zen_CheckArguments Error --"
23:44:46 "Argument 1 is void"
23:44:46 2490.82
23:44:46 [No task,[No task,No task]]
23:44:46 ["Zen_CheckArguments",[No task,[No task,No task]],2490.82]
23:44:46 ["Zen_ValueIsInArray",[No task,[No task,No task]],2490.82]
23:44:46 ["Zen_ArrayFilterValues",[[No task,No task],[No task,No task]],2490.82]
23:44:46 ["Zen_RemoveTaskClient",["basedefend",[X5,X11]],2490.82]
23:44:46 ["Zen_RemoveTask",["basedefend",[[X5],[X11]]],2490.82]
23:44:46 "-- Zen_CheckArguments Error --"
23:44:46 "Argument 1 is void"
23:44:46 2490.89
23:44:46 [No task,[No task,No task]]
23:44:46 ["Zen_CheckArguments",[No task,[No task,No task]],2490.89]
23:44:46 ["Zen_ValueIsInArray",[No task,[No task,No task]],2490.89]
23:44:46 ["Zen_ArrayFilterValues",[[No task,No task],[No task,No task]],2490.82]
23:44:46 ["Zen_RemoveTaskClient",["basedefend",[X5,X11]],2490.82]
23:44:46 ["Zen_RemoveTask",["basedefend",[[X5],[X11]]],2490.82]
23:44:46 Bad conversion: array
23:44:46 Error in expression <th {};

It seems to remove the task from the clients but not always from the 'Zen_Task_Array_Global'. So if I issue this

Zen_Task_Array_Global = [];
publicVariable Zen_Task_Array_Global;

Will that clear the task array when my tasks are finished and not mess with your frameworks systems? And do I need to publicvariable it or just run that on the server?

Please keep in mind that these aren't complaints, just reporting to you what I've found so if need be you can address them. As a mission maker I know that you can create a scenario that you think is bulletproof only to have someone tackle it a different way and introduce variables you never considered. I hope these are helpful!

Your framework is really great to work with and I appreciate all the work you have done in creating it!

I think 1 and 2 were reported by PM and I hotfixed them about a week ago. Try the latest version from google drive.

Because Zen_OrderInsertion does not continue tracking the units to the ground (just out of the helicopter), it cannot give them their original backpacks. Changing when Zen_OrderInsertion stops executing could break a lot of existing code. However, you can handle replacing backpacks yourself:

// ... insertion code here ...
_heli = [_startPos, "b_heli_transport_01_f", 300] call Zen_SpawnHelicopter;
_group = [_startPos, west, "infantry", 4] call Zen_SpawnInfantry;
0 = [_group, _heli] call Zen_MoveInVehicle;
0 = [_heli, [_insertionPos, _startPos], _group, "normal", 500, "parachute"] spawn Zen_OrderInsertion;

// get loadouts before jump
_loadouts = [];
_parachutingUnits = units _group;
{
   _loadouts pushBack ([_x] call Zen_GetUnitLoadout);
} forEach _parachutingUnits;

// thread to handle each unit reaching the ground
// loadout and unit arrays should remain aligned as elements are removed
0 = [_parachutingUnits, _loadouts] spawn {
   _parachutingUnits = _this select 0;
   _loadouts = _this select 1;
   while {count _parachutingUnits > 0} do {
       sleep 5;
       {
           if (ZEN_STD_OBJ_ASLPositionZ(_x) < 2 || ZEN_STD_OBJ_ATLPositionZ(_x) < 2) then {
               0 = [_x, _loadouts select _forEachIndex] call Zen_GiveLoadoutCustom;
               _parachutingUnits set [_forEachIndex, 0];
               _loadouts set [_forEachIndex, 0];
           };
       } forEach _parachutingUnits;

       0 = [_parachutingUnits, 0] call Zen_ArrayRemoveValue;
       0 = [_loadouts, 0] call Zen_ArrayRemoveValue;
   };
};

// mission continues

I didn't test that, but it looks good. You could make a simpler function than Zen_GetUnitLoadout and Zen_GiveLoadoutCustom that just handles backpacks, but the custom loadouts will work.

3. '_ropeAir' is the rope being created for each unit to descend on. It would only be undefined if ropeCreate failed. I just tested the Mohawk with this code:

_heli = [(getPosATL player) vectorAdd [100, 100, 0], "i_heli_transport_02_f", 40] call Zen_SpawnVehicle;
0 = [_heli, west] call Zen_SpawnVehicleCrew;

_group = [player, west, "infantry", 4] call Zen_SpawnInfantry;
0 = [_group, _heli] call Zen_MoveInVehicle;

0 = [_heli, player, _group, "normal", 40, "fastrope"] spawn Zen_OrderInsertion;

and it worked fine. I don't know why one helicopter would be different. You might want to check any addons you have running.

4. The JIP demonstration (and those sample missions that handle JIP) assume there are some reference units to get tasks from. Otherwise, it can't know which existing tasks to give to the JIP client. However, tasks with no units are supposed to be cleaned from the global array; tasks given only to players that have left shouldn't exist. Thus, you need a nonplayable proxy unit (like X5) that will have the task. JIP players will then look at X5's tasks and reassign them to themselves.

Players dying, respawning, or leaving the game is not automatically detected by the task system. It will not automatically remove that units from the global data, or remove their local task for each global task from each machine. The JIP code cannot do this because it can't tell the difference between a dead player's body waiting to respawn and the body of a player that quit.

If you use 'Zen_Task_Array_Global = []', you will break the task system because the local data has no logical global task associated with it. It won't actually remove any tasks from the UI; it will make it impossible to use Zen_RemoveTask. Zen_RemoveTask will just say 'Given task does not exist' etc.

You found a bug in which Zen_RemoveTask cannot be used manually remove objects of players that quit, because Zen_RemoveTaskClient doesn't handle null tasks. What should be possible is this: use onPlayerDisconnected or HandleDisconnect EH with Zen_RemoveTask to remove both the player's object from the global task data for all his tasks as well as all local tasks he had (or are null for any reason).

That would look like (the code used in the EH):

0 = _this spawn {
   _unit = _this select 0;
   _tasks = [_unit] call Zen_GetUnitTasks;

   {
       0 = [_x, _unit] call Zen_RemoveTask;
   } forEach _tasks;
};

Zen_RemoveTask will delete tasks with no units automatically (which shouldn't happen because X5 exists). Zen_RemoveTask doesn't change, but Zen_RemoveTaskClient needs to be modified. Here's what it should be (I tested this in SP for typos):

// This file is part of Zenophon's ArmA 3 Co-op Mission Framework
// This file is released under Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International (CC BY-NC-ND 4.0)
// See Legal.txt

if (count Zen_Task_Array_Local == 0) exitWith {};

_Zen_stack_Trace = ["Zen_RemoveTaskClient", _this] call Zen_StackAdd;
private ["_nameString", "_units", "_unit", "_taskArray", "_localTaskData", "_taskIndex", "_tasksRemain"];

if !([_this, [["STRING"], ["ARRAY"]], [[], ["OBJECT"]], 2] call Zen_CheckArguments) exitWith {
   call Zen_StackRemove;
};

_nameString = _this select 0;
_units = _this select 1;

if (count _units == 0) exitWith {
   call Zen_StackRemove;
};

_taskIndex = [Zen_Task_Array_Local, _nameString, 0] call Zen_ArrayGetNestedIndex;

if (_taskIndex == -1) exitWith {
   call Zen_StackRemove;
};

_localTaskData = Zen_Task_Array_Local select _taskIndex;
_taskArray = _localTaskData select 1;
_tasksRemain = [];

{
   _unit = _x;
   {
       if !(isNull _x) then {
           if (_x in simpleTasks _unit) then {
               _unit removeSimpleTask _x;
           } else {
               _tasksRemain pushBack _x;
           };
       };
   } forEach _taskArray;
} forEach _units;

Zen_Task_Array_Local set [_taskIndex, [_nameString, _tasksRemain]];
0 = [] call Zen_CleanLocalTaskArray;

if ((!isDedicated && hasInterface) && {(player in _units)}) then {
   0 = ["TaskRemoved", ["", (([_nameString] call Zen_GetTaskDataGlobal) select 5)]] call bis_fnc_showNotification;
};

call Zen_StackRemove;
if (true) exitWith {};

As for the JIP code itself, you want to use your proxy unit that held the tasks when there were no players. This gets more complex if you want some JIP players to get different tasks based upon their group/position/anything (you need to chose between more than one proxy), but the simple version is:

       {
           0 = [_x, player] call Zen_ReassignTask;
       } forEach ([X5] call Zen_GetUnitTasks);

You shouldn't need to remove any tasks in the JIP code. I assume you solved other issues with not having a reference unit in the JIP code already.

Share this post


Link to post
Share on other sites

So if I understand this correctly, the global task array contains the tasks for every unit in the game individually?

If that's true would it make more sense to assign the tasks to my X5 unit then reassign the task to each player? This would also make it easier to manage if I wanted separate tasks for players as I could assign different tasks to different logical units and reassign them to the correct players! Or would that even change anything?

I'm still trying to wrap my mind around how the tasks are handled!

I assume you solved other issues with not having a reference unit in the JIP code already.

LOL....Don't you be making assumptions about me!!! Better to assume I've been playing a broke mission all along!

Share this post


Link to post
Share on other sites
So if I understand this correctly, the global task array contains the tasks for every unit in the game individually?

If that's true would it make more sense to assign the tasks to my X5 unit then reassign the task to each player? This would also make it easier to manage if I wanted separate tasks for players as I could assign different tasks to different logical units and reassign them to the correct players! Or would that even change anything?

I'm still trying to wrap my mind around how the tasks are handled!

LOL....Don't you be making assumptions about me!!! Better to assume I've been playing a broke mission all along!

The global array (so called because it is publicVariabled, I can see that might be confused with local vs. global variables) contains the data for each abstract task, which Zen_GetTaskDataGlobal returns. The task system uses the list of objects to assign them tasks on every machine. Those real tasks get put into a local (not publicVariable'd) array; every object on every machine gets a different real task.

The system is designed to treat many real tasks as a single, logical task. Thus, everyone has the same description, destination, etc.; you can copy and delete tasks from players at will so long as the logical task remains (one unit still has it).

As a simple example, you have one group of players, who might leave the game at any time. You create an X5 unit (e.g. a civilian on an island). When you assign a task:

// _playerGroup is defined somewhere ...
_taskSecureArea = [[_playerGroup, X5], "Description", "Title", "mkArea"] call Zen_InvokeTask;

Regardless of how you use Zen_UpdateTask (which controls almost everything except the units), that logical task (which has _taskSecureArea as its string identifier) has the same units. If you use the HandleDisconnect EH with code similar to what I posted, the players' objects will be removed from the global data.

However, even though that player left (his local data is gone), the system still needs to update everyone's local data. This is because every machine has a local task for that player's object that corresponds to the global task. The task system does not assign tasks based upon locality, but to every object on every machine. Not doing this causes problems that confused me for a while when I was writing the tasks system long ago (a local-only approach does not work).

After you use Zen_RemoveTask manually, the tasks system should handle removing the local tasks that were assigned to that player's object from every machine's local data. This worked in general for AI (using teamswitch) and for players that didn't leave, but apparently not for players that have disconnected (their local tasks must become null).

After every player disconnects, you should be left with X5 as the only object to which the task is assigned. X5 is an unplayable AI that can never be deleted (with a global name JIP clients can use), so it's a sure thing for as long as the mission runs. The local data on all machines would have only one real task associated with the global task. Then, you should be able to use Zen_ReassignTask to copy the task from X5 to a JIP client.

Expanding this, you could have an X6, X7, etc. that provided 'storage' for the tasks of different groups. You'd need to detect which group the JIP client was in. I don't know if JIP player would spawn into the same group or create a new one; you'd have to test that. There probably easier ways, like having separate starting locations for each group and detecting where the JIP player is (an area marker and Zen_IsPointInPoly would work).

Without a reference unit in JIP, I guessed that you let new players spawn at their default (editor-placed) positions at some main base. The default JIP code tries to teleport them to their squad, as I don't assume there's a base or base type respawn in the JIP demonstration.

Share this post


Link to post
Share on other sites

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 links 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 soon. Please bring any technical issues or mistakes to my attention, so e.g. people don't download the wrong version etc.

Changelog

Just in time for the new Marksman DLC, this release continues to fix reported bugs and make various parts of the framework more robust. I've read BIS's changelog and tested the framework in the usual ways, and the new DLC doesn't seem to break anything outright. Nevertheless, be prepared for strange bugs. Also note, bipods should be under 'primaryAttachments' in custom loadouts.

I probably should have done this sooner, so several functions that previously sent remote execution requests to all machines now only send them to where an object is local. This will even further reduce the burden on clients in MP, as they don't have to execute a function only to find out there's nothing they can do.

I've changed how Zen_AddFireSupportAction handles the communication menu entries in MP. There seems to be odd behavior with the menu when teamswitching, so I assign the support by player (client in MP) now. If this is really an issue for you, say something and I can work on an alternate solution (such as making it a true addAction action).

ZEN_FMW_Loadout_StdInfantryPreset is a new macro; it is intended to let you quickly equip soldiers with weapons more commonly seen in an infantry squad. This will prevent pesky AA soldiers from trying to shoot down your extraction helicopter. It also provides a quick way, other than the default kits macro, to get to the remote execution parameter for loadout functions (to improve MP performance when equipping local AI).

Zen_ArraySortRandom has been renamed Zen_ArrayShuffle and modifies the array by reference. This is not just to make you use find and replace; it is to reflect how the function's algorithm has changed. Previously, Zen_ArraySortRandom would take elements at random from the given array and put them in a new array (like assigning them random values in a sort). This didn't allow the array to be modified by reference, and it was inefficient because elements had to be removed from (a copy of) the given array to prevent selecting duplicates. Zen_ArrayShuffle now swaps elements at random in the array; it does this twice so that it is possible that elements can remain in the same position (to be truly random).

Zen_OrderExtraction and Zen_OrderInsertion have several improvements. First, they encourage the AI to gain some altitude before flying away from a landing; this should help avoid collisions with trees or buildings. Second, they can no longer keep the helicopters engines turned on while landed. The way this was done (setMass) caused physics issues (like the helicopter exploding at random), because you must use a small setMass to prevent the helicopter from flying. setMass doesn't seem work with the advanced flight model anyway.

Thanks to user reports, Zen_RemoveTask will now remove null local tasks (which are hidden from users), thus improving the integrity of the task system. A few posts back, I explain how to use this improvement to properly remove the tasks of players that have disconnected from the server. If your server is persistent or you just want to cover all possibilities, you must use Zen_RemoveTask manually. This does not apply to respawn, revive, or teamswitching.

Zen_TransformObject's fourth parameter is now a velocity vector, in cylindrical coordinates. You can use ZEN_STD_Math_VectCartCyl and its kin to switch between coordinates; remember that the 2D polar angle is trigonometric. Zen_TransformObject allows a 0 to skip that parameter, making keeping the velocity easy now.

4/8/15

  1. Fixed: ZEN_FMW_Code_SpawnPointBehind now gives loadouts of the correct side
  2. Fixed: Zen_OrderInsertion did not order troops to disembark from boats and ground vehicles
  3. Fixed: Zen_OrderExtraction and Zen_OrderInsertion do not change the mass of the helicopter to keep it in place
  4. Added: Framework macro ZEN_FMW_Loadout_StdInfantryPreset
  5. Improved: Zen_AddFireSupportAction, Zen_GiveLoadout, Zen_GiveLoadoutBlufor, Zen_GiveLoadoutCustom, Zen_GiveLoadoutIndfor, Zen_GiveLoadoutOpfor, Zen_MoveInVehicle remote execution significantly optimized
  6. Improved: Zen_ArraySortRandom renamed Zen_ArrayShuffle
  7. Improved: Zen_ArrayShuffle now shuffles the array by reference
  8. Improved: ZEN_FMW_Code_SpawnMarker, ZEN_FMW_Code_SpawnPoint, ZEN_FMW_Code_SpawnPointBehind optimized
  9. Improved: Zen_OrderExtraction and Zen_OrderInsertion now make the helicopter gain altitude before flying away
  10. Improved: Zen_RemoveTask now handles void local task data
  11. Improved: Zen_TransformObject parameter 4 is now a velocity vector
  12. Improved: Zen_TransformObject remote execution sync is now faster
  13. Documentation: Added for ZEN_FMW_Loadout_StdInfantryPreset
  14. Documentation: Updated for Zen_ArrayShuffle, Zen_TransformObject
  15. Documentation: Updated Notepad++ SQF language and autocompletion file with ArmA 1.42 stable commands
  16. Documentation: Improved for Zen_AddFireSupportAction, Zen_FindInRange

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).

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 and supported the framework.

Share this post


Link to post
Share on other sites
Guest

Thanks for always taking the time to inform us about your newest releases :cool:

Release frontpaged on the Armaholic homepage.

================================================

We have also "connected" these pages to your account on Armaholic.

This means soon you will be able to maintain these pages yourself if you wish to do so. Once this new feature is ready we will contact you about it and explain how things work and what options you have.

When you have any questions already feel free to PM or email me!

Share this post


Link to post
Share on other sites

I made my first mission for any Arma title ever with your framework! I've always been curious about coding a mission and always felt the editor lacked the documentation needed to effectively manipulate the units. Thanks to you tho, I now consider myself a scripting noob! hehe... Well anyways time to put away my dumb humor and say thanks to you for providing this wonderful tool/documentation for the community to use and learn with, I am really loving it!

On to my question, I have a four player(and/or)AI unit being inserted by boat using your MoveInVehicle function. I have placed the boat as empty in the editor, and then used your function to teleport the group into it where they can then move to where they want to go. As my mission is currently scripted everything runs flawlessly except for one minor detail. When my group is moved into the boat they all fill passenger slots but not the driver(adding a fifth squad member doesn't work he gets left behind), this is fine for singleplayer just get out and back in as the driver. But, for MP I don't think many people would like to put up with that. I have used the spawnboat function and the spawncrew function as well, I like them and have plans to use them but for adaptability and reaction I'd like the players boat to be controlled by the player or players input lets insert here to hit this first etc... Is it possible to use your framework or any code for that matter to move the group into the boat and make one of them the driver?

#include "Zen_FrameworkFunctions\Zen_InitHeader.sqf"

#include "Zen_FrameworkFunctions\Zen_FrameworkLibrary.sqf"

#include "Zen_FrameworkFunctions\Zen_StandardLibrary.sqf"

// <Radio Silence> by <Soul>

// Version = <0.1_2015-4-1>

// Tested with ArmA 3 <1.40129533>

// This will fade in from black, to hide jarring actions at mission start, this is optional and you can change the value

titleText ["First In, Last Out", "BLACK FADED", 0.9];

// SQF functions cannot continue running after loading a saved game, do not delete this line

enableSaving [false, false];

// All clients stop executing here, do not delete this line

if (!isServer) exitWith {};

// Execution stops until the mission begins (past briefing), do not delete this line

sleep 1;

// Enter the mission code here

"MortarTeam" setMarkerAlpha 0;

"CommOfficer" setMarkerAlpha 0;

"APCStart" setMarkerAlpha 0;

"APCEnd" setMarkerAlpha 0;

"Beachhead" setMarkerAlpha 0;

"LZBeach" setMarkerAlpha 0;

"Patrol1" setMarkerAlpha 0;

"Patrol2" setMarkerAlpha 0;

"Patrol3" setMarkerAlpha 0;

"Patrol4" setMarkerAlpha 0;

"NorthPatrol1" setMarkerAlpha 0;

"NorthPatrol2" setMarkerAlpha 0;

_group_A11 = group A11;

_AlphaBoat = AlphaBoat;

_Ammo1 = Ammo1;

_A11 = A11;

_AlphaBoatInsert = [_group_A11, _AlphaBoat] call Zen_MoveInVehicle;

_ResupplyObj = [_Ammo1, _group_A11, west, "Box", "reach"] call Zen_CreateObjective;

_LGB_FireSupport = ["Bo_GBU12_LGB", 1, 1, 5, 10, 100, 25, true] call Zen_CreateFireSupport;

0 = [_group_A11, _LGB_FireSupport, "Air Strike", 1, A11, "designator"] call Zen_AddFireSupportAction;

_Patrol1Pos = ["Patrol1"] call Zen_FindGroundPosition;

_Patrol1 = [_Patrol1Pos, east, 2, 3, "men"] call Zen_SpawnInfantry;

0 = [_Patrol1, _Patrol1Pos] spawn Zen_OrderInfantryPatrol;

_Patrol2Pos = ["Patrol2"] call Zen_FindGroundPosition;

_Patrol2 = [_Patrol2Pos, east, 2, 3, "men"] call Zen_SpawnInfantry;

0 = [_Patrol2, _Patrol2Pos] spawn Zen_OrderInfantryPatrol;

_Patrol3Pos = ["Patrol3"] call Zen_FindGroundPosition;

_Patrol3 = [_Patrol3Pos, east, 2, 3, "men"] call Zen_SpawnInfantry;

0 = [_Patrol3, _Patrol3Pos] spawn Zen_OrderInfantryPatrol;

_Patrol4Pos = ["Patrol4"] call Zen_FindGroundPosition;

_Patrol4 = [_Patrol4Pos, east, 2, 3, "men"] call Zen_SpawnInfantry;

0 = [_Patrol4, _Patrol4Pos] spawn Zen_OrderInfantryPatrol;

_NorthPatrol1Pos = ["NorthPatrol1"] call Zen_FindGroundPosition;

_NorthPatrol1Inf = [_NorthPatrol1Pos, east, 4, 6, "men"] call Zen_SpawnInfantry;

0 = [_NorthPatrol1Inf, _NorthPatrol1Pos] spawn Zen_OrderInfantryPatrol;

_NorthPatrol1APC = [_NorthPatrol1Pos, "O_APC_Wheeled_02_rcws_F"] call Zen_SpawnGroundVehicle;

0 = [_NorthPatrol1APC, _NorthPatrol1Pos] spawn Zen_OrderVehiclePatrol;

_NorthPatrol2Pos = ["NorthPatrol2"] call Zen_FindGroundPosition;

_NorthPatrol2Inf = [_NorthPatrol2Pos, east, 4, 6, "men"] call Zen_SpawnInfantry;

0 = [_NorthPatrol2Inf, _NorthPatrol2Pos] spawn Zen_OrderInfantryPatrol;

_NorthPatrol2APC = [_NorthPatrol2Pos, "O_APC_Wheeled_02_rcws_F"] call Zen_SpawnGroundVehicle;

0 = [_NorthPatrol2APC, _NorthPatrol2Pos] spawn Zen_OrderVehiclePatrol;

_NorthPatrol2Pos = ["NorthPatrol2"] call Zen_FindGroundPosition;

_NorthPatrol2Inf = [_NorthPatrol2Pos, east, 4, 6, "men"] call Zen_SpawnInfantry;

0 = [_NorthPatrol2Inf, _NorthPatrol2Pos] spawn Zen_OrderInfantryPatrol;

waituntil { sleep 5; [(_ResupplyObj select 1)] call Zen_AreTasksComplete };

_MortarTeamPos = ["MortarTeam"] call Zen_FindGroundPosition;

_MortarTeamObj = [_MortarTeamPos, _group_A11, east, "Mortar", "eliminate"] call Zen_CreateObjective;

_MortarTeamGuard = [_MortarTeamPos, east, 3, 2, "men"] call Zen_SpawnInfantry;

0 = [_MortarTeamGuard, _MortarTeamPos] spawn Zen_OrderInfantryPatrol;

waituntil { sleep 5; [(_MortarTeamObj select 1)] call Zen_AreTasksComplete };

_CommOfficerPos = ["CommOfficer"] call Zen_FindGroundPosition;

_CommOfficerObj = [_CommOfficerPos, _group_A11, east, "Officer", "eliminate"] call Zen_CreateObjective;

_CommOfficerGuard = [_CommOfficerPos, east, 3, 4, "men"] call Zen_SpawnInfantry;

0 = [_CommOfficerGuard, _CommOfficerPos] spawn Zen_OrderInfantryPatrol;

waituntil { sleep 5; [(_CommOfficerObj select 1)] call Zen_AreTasksComplete; };

_APCStart = ["APCStart"] call Zen_FindGroundPosition;

_APCEnd = ["APCEnd"] call Zen_FindGroundPosition;

_OpforAPCObj = [_APCEnd, _group_A11, east, "Convoy", "eliminate", _APCStart, "normal", ["O_APC_Wheeled_02_rcws_F", "O_Truck_02_covered_F", "O_Truck_02_covered_F", "O_Truck_02_transport_F", "O_MRAP_02_hmg_F"]] call Zen_CreateObjective;

waituntil { sleep 5; [(_OpforAPCObj select 1)] call Zen_AreTasksComplete };

_BeachheadPos = ["Beachhead"] call Zen_FindGroundPosition;

_BeachheadObj = [_BeachheadPos, _group_A11, east, "Officer", "eliminate"] call Zen_CreateObjective;

_BeachheadGuard = [_BeachheadPos, east, 3, 2, "men"] call Zen_SpawnInfantry;

0 = [_BeachheadGuard, _BeachheadPos] spawn Zen_OrderInfantryPatrol;

waituntil { sleep 5; [(_BeachheadObj select 1)] call Zen_AreTasksComplete };

endMission "end1"

Thats the mission, the group is on Xiros at the start of the mission, the boat is down by Jay Cove. Thanks for any advice! On any part of my script not just the boat question!

Share this post


Link to post
Share on other sites

try this

https://community.bistudio.com/wiki/moveInDriver

To solve 5 players, compose something like

if (count of group > 4) then {
move units to boat A which holds 8
} else{
move units to boat B which holds 4 max
}

You can use Zen functions to spawn the vehicle near the first if you need more than one boat for example. You could split the players up into 2 groups for 2 boats. You could use subs instead of boats if 5 players exist, you could change to heli if 5 exist... so many options lol.

Share this post


Link to post
Share on other sites
try this

https://community.bistudio.com/wiki/moveInDriver

To solve 5 players, compose something like

if (count of group > 4) then {
move units to boat A which holds 8
} else{
move units to boat B which holds 4 max
}

You can use Zen functions to spawn the vehicle near the first if you need more than one boat for example. You could split the players up into 2 groups for 2 boats. You could use subs instead of boats if 5 players exist, you could change to heli if 5 exist... so many options lol.

Thanks for the quick reply! Sorry I am still very new to this so I am sure I will be back for more advice, and I will try your suggestions out in the mean time. And your right about their being a lot of options, I am trying to stick with a boat insertion and a helo extraction for this mission tho. The group will clear their LZ in a future version. Correct me if I am wrong, the little bird has room for 6 just by looking at the model?

Quick question, if I use the wiki method would I need to change the MoveInVehicle function to count unit 2,3, and 4 only if 1 is going to be the driver. so something like this?

_A11 moveInDriver _AlphaBoat;
0 = [[_A12, _A13, _A14], _AlphaBoat] call Zen_MoveInVehicle;

yes that code worked great thanks for the link monkey! the code you posted looks a little advanced for my skill set as of yet lol

Edited by Soul4Ever
Tested

Share this post


Link to post
Share on other sites
I made my first mission for any Arma title ever with your framework! I've always been curious about coding a mission and always felt the editor lacked the documentation needed to effectively manipulate the units. Thanks to you tho, I now consider myself a scripting noob! hehe... Well anyways time to put away my dumb humor and say thanks to you for providing this wonderful tool/documentation for the community to use and learn with, I am really loving it!

On to my question, I have a four player(and/or)AI unit being inserted by boat using your MoveInVehicle function. I have placed the boat as empty in the editor, and then used your function to teleport the group into it where they can then move to where they want to go. As my mission is currently scripted everything runs flawlessly except for one minor detail. When my group is moved into the boat they all fill passenger slots but not the driver(adding a fifth squad member doesn't work he gets left behind), this is fine for singleplayer just get out and back in as the driver. But, for MP I don't think many people would like to put up with that. I have used the spawnboat function and the spawncrew function as well, I like them and have plans to use them but for adaptability and reaction I'd like the players boat to be controlled by the player or players input lets insert here to hit this first etc... Is it possible to use your framework or any code for that matter to move the group into the boat and make one of them the driver?

#include "Zen_FrameworkFunctions\Zen_InitHeader.sqf"

#include "Zen_FrameworkFunctions\Zen_FrameworkLibrary.sqf"

#include "Zen_FrameworkFunctions\Zen_StandardLibrary.sqf"

// <Radio Silence> by <Soul>

// Version = <0.1_2015-4-1>

// Tested with ArmA 3 <1.40129533>

// This will fade in from black, to hide jarring actions at mission start, this is optional and you can change the value

titleText ["First In, Last Out", "BLACK FADED", 0.9];

// SQF functions cannot continue running after loading a saved game, do not delete this line

enableSaving [false, false];

// All clients stop executing here, do not delete this line

if (!isServer) exitWith {};

// Execution stops until the mission begins (past briefing), do not delete this line

sleep 1;

// Enter the mission code here

"MortarTeam" setMarkerAlpha 0;

"CommOfficer" setMarkerAlpha 0;

"APCStart" setMarkerAlpha 0;

"APCEnd" setMarkerAlpha 0;

"Beachhead" setMarkerAlpha 0;

"LZBeach" setMarkerAlpha 0;

"Patrol1" setMarkerAlpha 0;

"Patrol2" setMarkerAlpha 0;

"Patrol3" setMarkerAlpha 0;

"Patrol4" setMarkerAlpha 0;

"NorthPatrol1" setMarkerAlpha 0;

"NorthPatrol2" setMarkerAlpha 0;

_group_A11 = group A11;

_AlphaBoat = AlphaBoat;

_Ammo1 = Ammo1;

_A11 = A11;

_AlphaBoatInsert = [_group_A11, _AlphaBoat] call Zen_MoveInVehicle;

_ResupplyObj = [_Ammo1, _group_A11, west, "Box", "reach"] call Zen_CreateObjective;

_LGB_FireSupport = ["Bo_GBU12_LGB", 1, 1, 5, 10, 100, 25, true] call Zen_CreateFireSupport;

0 = [_group_A11, _LGB_FireSupport, "Air Strike", 1, A11, "designator"] call Zen_AddFireSupportAction;

_Patrol1Pos = ["Patrol1"] call Zen_FindGroundPosition;

_Patrol1 = [_Patrol1Pos, east, 2, 3, "men"] call Zen_SpawnInfantry;

0 = [_Patrol1, _Patrol1Pos] spawn Zen_OrderInfantryPatrol;

_Patrol2Pos = ["Patrol2"] call Zen_FindGroundPosition;

_Patrol2 = [_Patrol2Pos, east, 2, 3, "men"] call Zen_SpawnInfantry;

0 = [_Patrol2, _Patrol2Pos] spawn Zen_OrderInfantryPatrol;

_Patrol3Pos = ["Patrol3"] call Zen_FindGroundPosition;

_Patrol3 = [_Patrol3Pos, east, 2, 3, "men"] call Zen_SpawnInfantry;

0 = [_Patrol3, _Patrol3Pos] spawn Zen_OrderInfantryPatrol;

_Patrol4Pos = ["Patrol4"] call Zen_FindGroundPosition;

_Patrol4 = [_Patrol4Pos, east, 2, 3, "men"] call Zen_SpawnInfantry;

0 = [_Patrol4, _Patrol4Pos] spawn Zen_OrderInfantryPatrol;

_NorthPatrol1Pos = ["NorthPatrol1"] call Zen_FindGroundPosition;

_NorthPatrol1Inf = [_NorthPatrol1Pos, east, 4, 6, "men"] call Zen_SpawnInfantry;

0 = [_NorthPatrol1Inf, _NorthPatrol1Pos] spawn Zen_OrderInfantryPatrol;

_NorthPatrol1APC = [_NorthPatrol1Pos, "O_APC_Wheeled_02_rcws_F"] call Zen_SpawnGroundVehicle;

0 = [_NorthPatrol1APC, _NorthPatrol1Pos] spawn Zen_OrderVehiclePatrol;

_NorthPatrol2Pos = ["NorthPatrol2"] call Zen_FindGroundPosition;

_NorthPatrol2Inf = [_NorthPatrol2Pos, east, 4, 6, "men"] call Zen_SpawnInfantry;

0 = [_NorthPatrol2Inf, _NorthPatrol2Pos] spawn Zen_OrderInfantryPatrol;

_NorthPatrol2APC = [_NorthPatrol2Pos, "O_APC_Wheeled_02_rcws_F"] call Zen_SpawnGroundVehicle;

0 = [_NorthPatrol2APC, _NorthPatrol2Pos] spawn Zen_OrderVehiclePatrol;

_NorthPatrol2Pos = ["NorthPatrol2"] call Zen_FindGroundPosition;

_NorthPatrol2Inf = [_NorthPatrol2Pos, east, 4, 6, "men"] call Zen_SpawnInfantry;

0 = [_NorthPatrol2Inf, _NorthPatrol2Pos] spawn Zen_OrderInfantryPatrol;

waituntil { sleep 5; [(_ResupplyObj select 1)] call Zen_AreTasksComplete };

_MortarTeamPos = ["MortarTeam"] call Zen_FindGroundPosition;

_MortarTeamObj = [_MortarTeamPos, _group_A11, east, "Mortar", "eliminate"] call Zen_CreateObjective;

_MortarTeamGuard = [_MortarTeamPos, east, 3, 2, "men"] call Zen_SpawnInfantry;

0 = [_MortarTeamGuard, _MortarTeamPos] spawn Zen_OrderInfantryPatrol;

waituntil { sleep 5; [(_MortarTeamObj select 1)] call Zen_AreTasksComplete };

_CommOfficerPos = ["CommOfficer"] call Zen_FindGroundPosition;

_CommOfficerObj = [_CommOfficerPos, _group_A11, east, "Officer", "eliminate"] call Zen_CreateObjective;

_CommOfficerGuard = [_CommOfficerPos, east, 3, 4, "men"] call Zen_SpawnInfantry;

0 = [_CommOfficerGuard, _CommOfficerPos] spawn Zen_OrderInfantryPatrol;

waituntil { sleep 5; [(_CommOfficerObj select 1)] call Zen_AreTasksComplete; };

_APCStart = ["APCStart"] call Zen_FindGroundPosition;

_APCEnd = ["APCEnd"] call Zen_FindGroundPosition;

_OpforAPCObj = [_APCEnd, _group_A11, east, "Convoy", "eliminate", _APCStart, "normal", ["O_APC_Wheeled_02_rcws_F", "O_Truck_02_covered_F", "O_Truck_02_covered_F", "O_Truck_02_transport_F", "O_MRAP_02_hmg_F"]] call Zen_CreateObjective;

waituntil { sleep 5; [(_OpforAPCObj select 1)] call Zen_AreTasksComplete };

_BeachheadPos = ["Beachhead"] call Zen_FindGroundPosition;

_BeachheadObj = [_BeachheadPos, _group_A11, east, "Officer", "eliminate"] call Zen_CreateObjective;

_BeachheadGuard = [_BeachheadPos, east, 3, 2, "men"] call Zen_SpawnInfantry;

0 = [_BeachheadGuard, _BeachheadPos] spawn Zen_OrderInfantryPatrol;

waituntil { sleep 5; [(_BeachheadObj select 1)] call Zen_AreTasksComplete };

endMission "end1"

Thats the mission, the group is on Xiros at the start of the mission, the boat is down by Jay Cove. Thanks for any advice! On any part of my script not just the boat question!

Thanks for the quick reply! Sorry I am still very new to this so I am sure I will be back for more advice, and I will try your suggestions out in the mean time. And your right about their being a lot of options, I am trying to stick with a boat insertion and a helo extraction for this mission tho. The group will clear their LZ in a future version. Correct me if I am wrong, the little bird has room for 6 just by looking at the model?

Quick question, if I use the wiki method would I need to change the MoveInVehicle function to count unit 2,3, and 4 only if 1 is going to be the driver. so something like this?

_A11 moveInDriver _AlphaBoat;
0 = [[_A12, _A13, _A14], _AlphaBoat] call Zen_MoveInVehicle;

yes that code worked great thanks for the link monkey! the code you posted looks a little advanced for my skill set as of yet lol

Zen_MoveInVehicle defaults to cargo positions only, you must give the position type as 'all' to fill driver, gunner, etc. positions (remaining units are then put in passenger seats). You can also specify turret types in the next argument; however, the difference between gunner and commander is not always clear (copilots are commanders though).

_AlphaBoatInsert = [_group_A11, _AlphaBoat, "All"] call Zen_MoveInVehicle;

If you use moveInDriver, you need to sync it in MP (must run local to the unit). Zen_MoveInVehicle is doing that for you; it should also give an error if units must be left out. The order of putting units in with 'All' is: driver, turrets in order as returned by Zen_GetTurretPaths, passengers seats by index of moveInCargo from 0; occupied positions will be skipped.

Share this post


Link to post
Share on other sites

As an idea, if the team units are player1 to player5

// dimension an array that holds all player units (as an example, but there are many ways to go about this)
_arrayPlayers = [player1,player2,player3,player4,player5];

// in editor, you create 2 insertion boats, named boat1 and boat2

// at the correct point in the mission code, determine how many units are players
// if > 4, use the second boat

if (({isPlayer _x} count _arrayPlayers) > 4) then {
 [[player1,player2,player3],boat1] call Zen_MoveInVehicle;
 [[player4,player5],boat2] call Zen_MoveInVehicle;
 // you could, as Zen suggests, use the feature in his function to get a player as driver, or do it yourself, both achieve the result
 player1 moveInDriver boat1;
 player4 moveInDriver boat2;
} else {
 [[player1,player2,player3,player4],boat1] call Zen_MoveInVehicle;
 player1 moveInDriver boat1;
 // cleanup the second boat if desired by deleting it now
};

There are many ways to make this more dynamic. You could use a few of Zens functions to mix things up as well. The idea is that you use some logic to handle problems. There are many things missing from this example. Its only meant to give you an idea on using an IF statement in such a situation :)

Share this post


Link to post
Share on other sites
Zen_MoveInVehicle defaults to cargo positions only, you must give the position type as 'all' to fill driver, gunner, etc. positions (remaining units are then put in passenger seats). You can also specify turret types in the next argument; however, the difference between gunner and commander is not always clear (copilots are commanders though).

_AlphaBoatInsert = [_group_A11, _AlphaBoat, "All"] call Zen_MoveInVehicle;

If you use moveInDriver, you need to sync it in MP (must run local to the unit). Zen_MoveInVehicle is doing that for you; it should also give an error if units must be left out. The order of putting units in with 'All' is: driver, turrets in order as returned by Zen_GetTurretPaths, passengers seats by index of moveInCargo from 0; occupied positions will be skipped.

As an idea, if the team units are player1 to player5

// dimension an array that holds all player units (as an example, but there are many ways to go about this)
_arrayPlayers = [player1,player2,player3,player4,player5];

// in editor, you create 2 insertion boats, named boat1 and boat2

// at the correct point in the mission code, determine how many units are players
// if > 4, use the second boat

if (({isPlayer _x} count _arrayPlayers) > 4) then {
 [[player1,player2,player3],boat1] call Zen_MoveInVehicle;
 [[player4,player5],boat2] call Zen_MoveInVehicle;
 // you could, as Zen suggests, use the feature in his function to get a player as driver, or do it yourself, both achieve the result
 player1 moveInDriver boat1;
 player4 moveInDriver boat2;
} else {
 [[player1,player2,player3,player4],boat1] call Zen_MoveInVehicle;
 player1 moveInDriver boat1;
 // cleanup the second boat if desired by deleting it now
};

There are many ways to make this more dynamic. You could use a few of Zens functions to mix things up as well. The idea is that you use some logic to handle problems. There are many things missing from this example. Its only meant to give you an idea on using an IF statement in such a situation :)

Thanks for the replies! And I must apologize I totally missed the rest of the MoveInVehicle documentation, here the answer was right in front my eyes all along so sorry for that! Thanks for pointing it out Zen. I'll do better to make sure I read the documentation better next time.

As far as including an if statement I don't really feel that comfortable with being able to code an entire mission myself yet. Certainly this framework or at least the basics of it I can handle so far. But, I'll keep at it and I am sure at some point I'll be ready to venture into more unstable waters again.

Share this post


Link to post
Share on other sites

My advice is to learn how to use IF statements now, before you go any further in any scripting. Its the basis for any logic you want to perform. Select/switch statments can come later, but a basic understanding of the IF statement is imperative IMHO.

Share this post


Link to post
Share on other sites

Hey Zenophon I have a question for you. In your patrol scripts (for all units - Air, Vehicle, Infantry), if the units or vehicles are deleted rather than destroyed will your patrol scripts still terminate or will they "hang" with a null object error and not terminate?

And as a separate request, can you set a parameter in Zen_OrderInfantryMove for the infantry to avoid combat or the engage the enemy while in the process of their move?

Share this post


Link to post
Share on other sites

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now

×