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 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 release offers fixes and improvements for many functions, including an improved syntax for Zen_FindGroundPosition's blacklist parameter and very reliable MP synch'ing by Zen_MoveInVehicle. Also, the Notepad++ function hints documentation (which I doubt many people use) now follow the same format as regular framework functions.

Zen_FindGroundPosition can, firstly, default to the entire map (just give '0' for argument 1), and now offers multiple blacklist/whitelist filters at the same time. To clarify this, first is the blacklist: the point must be none of these marker, then the 'all' whitelist: the point must be in all of these markers, and finally the 'one' whitelist: the point must be in at least one of these markers. If, by popular depend, a 'one' blacklist is useful, I can add that as well.

Zen_MoveInVehicle used to remote execute 'moveIn*' commands, then check that they succeeded. This did not give time for clients to receive and execute this code, resulting in clients being in cargo (the fail-safe) instead of driver, gunner, etc. I recently added 'sleep 0.1' to wait for synch, but this is rather lazy and unreliable. Therefore, Zen_MoveInVehicle now uses a system of set and get variable to communicate the status of units between server and client. This technique is more complex, but results in faster execution time (0.1 is sometimes too much), especially in SP.

Sometime ago, I discovered that Zen_InvokeFireSupport was sending some types of rounds horizontally instead of towards the ground. I changed it to spawn the shells directly on the ground, resulting in 100% reliability and accuracy. However, this breaks the round guidance feature, which requires that the rounds' position be adjusted in flight. This release, Zen_InvokeFireSupport now fires all rounds from 1000 meters altitude with good accuracy and working guidance.

It also seems that 'setMass' does not work with the new heli AFM (the mass command for that model doesn't work at all), so Zen_OrderExtraction and Zen_OrderInsertion will have to turn of the helicopter's engines if AFM is enabled (the functions can detect that).

Various spawning functions now have a DLC vehicle parameter (which just gets passed along to Zen_ConfigGetVehicleClasses) to use when they select a vehicle at random. It also defaults to no DLC, so if you e.g. don't want Zen_SpawnAmbientVehicles to spawn any karts, you can do that now.

Finally, I have added this warning in the documentation: all framework functions are designed and tested in scheduled environment; calling them in an unscheduled environment will result in undefined behavior. A further explanation appears in FAQ.txt and FrameworkIntroduction.txt.

1/28/15

  1. New Function: Zen_IsIsland
  2. Fixed: Zen_ExecuteCommand did not print the stack on an invalid command error
  3. Fixed: Zen_GetUnitLoadout did not record laser designator batteries
  4. Fixed: Zen_InvokeFireSupport guidance feature
  5. Fixed: Zen_MoveInVehicle now reliably and instantly checks for remote execution synch
  6. Fixed: Zen_OrderExtraction and Zen_OrderInsertion did not keep an AFM helicopter on the ground
  7. Added: Zen_ExecuteCommand new commands
  8. Added: Framework macro ZEN_FMW_Code_GiveLoadoutsOrdered
  9. Added: Zen_SpawnAircraft, Zen_SpawnAmbientVehicles, Zen_SpawnBoat, Zen_SpawnGroundVehicle, Zen_SpawnHelicopter, Zen_SpawnInfantry, and Zen_SpawnInfantryGarrison parameter for DLC vehicles
  10. Improved: Zen_CreateObjective convoy end disembark logic simplified
  11. Improved: Zen_FindGroundPosition parameter 1 is optional and defaults to the entire map
  12. Improved: Zen_FindGroundPosition blacklist whitelist parameter redesigned
  13. Improved: Zen_InvokeFireSupport allows rounds to realistically fall from above
  14. Improved: Zen_SpawnConvoy allows troops to disembark when under fire
  15. Documentation: Corrected for Zen_ConfigGetVehicleClasses and Zen_MoveInVehicle
  16. Documentation: Added for ZEN_FMW_Code_GiveLoadoutsOrdered and Zen_IsIsland
  17. Documentation: Improved for many macros
  18. Documentation: Improved Notepad++ SQF autocompletion macro hints' text
  19. Documentation: Updated FAQ.txt, FrameworkIntroduction.txt, and KnownIssues.txt
  20. Documentation: Updated for Zen_FindGroundPosition, Zen_SpawnAircraft, Zen_SpawnAmbientVehicles, Zen_SpawnBoat, Zen_SpawnGroundVehicle, Zen_SpawnHelicopter, Zen_SpawnInfantry, and Zen_SpawnInfantryGarrison
  21. Documentation: Updated Notepad++ SQF language and autocompletion file with ArmA 1.38 stable commands

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_GetAllInBuilding. This function is short and simple, but, like every function, has its uses. In past releases I have added and improved Zen_FindBuildingPositions, as well as making sure Zen_SpawnGroup works for building positions (this affects Zen_SpawnInfantry and Zen_SpawnInfantryGarrison). Thus, with better functions for building-oriented objectives and missions, I remembered Zen_GetAllInBuilding.

Zen_GetAllInBuilding will return all entities (a living person of any side) within the nearest building. As with other functions that deal with buildings, simply giving the building itself as an argument will work fine. This is useful for a 'clear the building style objective':

// you spawn several Opfor in the building nearest _housePos
waitUntil {
   sleep 5;
   ((count ([_housePos, east] call Zen_GetAllInBuilding)) == 0)
};

Or perhaps an hostage rescue mission (recall that setCaptive makes a unit's side civilian):

// you spawn several Opfor and a hostage in the building nearest _housePos
waitUntil {
   sleep 5;
   _units = [_housePos] call Zen_GetAllInBuilding;
   ((({side _x == east} count _units) == 0) && (({side _x == civilian} count _units) == 1) && (({side _x == west} count _units) > 0))
};

Zen_GetAllInBuilding also accounts for units fleeing the building, so players don't have to hunt down and kill the former occupants 1km away to complete the mission (which is how a dead/alive completion logic would work).

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

Thanks again for informing us about the new version :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

Hi, just started using the framework and it's already hugely improved and streamlined my mission design. Running into a few questions, though. I have the following foreach loop assigning equipment:

{
0 = [_x, _alphaLoadout] call Zen_GiveLoadoutCustom;
} foreach ContactTypeAlpha;

I can include an "none" option in a loadout by inserting empty arrays, eg:

["headgear", [["H_MilCap_dgtl", "H_Cap_blk_Raven", "H_Cap_police", "H_Cap_blk"], []]]

functions well enough as "pick one of these hats or no hat" for one unit, but it stops after the first guy in the foreach loop. If I remove the empty array from the headgear nested array, it iterates through the foreach loop properly. Is there a better way to do this?

Share this post


Link to post
Share on other sites
Hi, just started using the framework and it's already hugely improved and streamlined my mission design. Running into a few questions, though. I have the following foreach loop assigning equipment:

{
0 = [_x, _alphaLoadout] call Zen_GiveLoadoutCustom;
} foreach ContactTypeAlpha;

I can include an "none" option in a loadout by inserting empty arrays, eg:

["headgear", [["H_MilCap_dgtl", "H_Cap_blk_Raven", "H_Cap_police", "H_Cap_blk"], []]]

functions well enough as "pick one of these hats or no hat" for one unit, but it stops after the first guy in the foreach loop. If I remove the empty array from the headgear nested array, it iterates through the foreach loop properly. Is there a better way to do this?

The 'headgear' category is like uniforms or vests, there's only one array of possibilities:

["headgear", ["H_MilCap_mcamo", "", "", "", "", "", "", "", ""]],

The function stops because it isn't expecting another [] at the end. However, giving "" in the array of items should work fine.

Share this post


Link to post
Share on other sites

Ah, right, I missed that!! Thanks Zenophon! One more question: I'm not clear on what this means:

Zen_FindBuildingPositions

Attempts to generate up to (2) 2D random positions ATL inside the building nearest (1)

on every floor and, if (3), the roof.

Does "attempts to" refer to this function's returning arrays that are smaller than (2) if it can't find positions? I'm trying to use this function to distribute guys in some buildings, but it doesnt do it reliably. I'm giving it building IDs from arrays built by nearestBuilding. I can reliably setPosATL at the buildings through Zen_ConvertToPosition, but Zen_FindBuildingPosition ~50% of the time returns null arrays for houses.

Share this post


Link to post
Share on other sites
Ah, right, I missed that!! Thanks Zenophon! One more question: I'm not clear on what this means:

Does "attempts to" refer to this function's returning arrays that are smaller than (2) if it can't find positions? I'm trying to use this function to distribute guys in some buildings, but it doesnt do it reliably. I'm giving it building IDs from arrays built by nearestBuilding. I can reliably setPosATL at the buildings through Zen_ConvertToPosition, but Zen_FindBuildingPosition ~50% of the time returns null arrays for houses.

'Attempts' means generated 2D points. Imagine the function looking down on the building from above, and drawing lines through it. Those lines appear as 2D points on the terrain (the XY plane). It starts where these lines are no longer in the ground or another object and follows them upwards in increments (Z direction). Every 3D point is evaluated for being in a building an at a certain distance the floor and ceiling. The function checks many 3D points for each 2D point, climbing up a 'ladder' through the building; most of those points fail some check. If the point passes, it gets added to the array.

It should never return null; an empty array means it found no valid positions. To test this, I used an empty mission (just a player unit) and this code:

player setPosATL [14066,18679,0];
posArray = [];
for "_i" from 0 to 9 do {
   _pos = [player, [50, 400]] call Zen_FindGroundPosition;
   posArray pushBack _pos;
   player globalChat str ([_pos] call Zen_FindBuildingPositions);
};

Using the debug console, I inspected each building that had 0 positions returned:

player setPosATL getPosATL (nearestBuilding (posArray select 0));

I found two types of buildings returned 0 positions:

  1. Small sheds
  2. Ruins with no roof

The small sheds failed because they had a dirt floor. That is fixed and will be included in the next release. The ruins failed because the roof parameter was 'false': no roofs allowed. Those worked when I allows roofs.

Running it several times, I found no failures on normal houses. If you have a standard looking house that fails consistently, post the exact coordinates of this building and I will debug it. Otherwise, I can't reproduce a 50% failure rate.

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

The third release of 2015 brings relatively few changes. The highlight of which is a new math function Zen_FindRayIntersection; this function determines where two rays (not lines) will intersect, if they do at all. I'm sure someone can put this function to good use.

I've fixed a very rare bug with Zen_ConvertToGroupArray and Zen_ConvertToObjectArray; which was really small typo in the code. You can now list multiple sides in the arguments to these functions.

By user report, Zen_FindBuildingPositions should now work for buildings with dirt floors. This mostly affects small sheds and shanty houses. I've also taken the opportunity to extend the function's upward search range and optimize it by detecting if it has cleared the building.

By user request, Zen_OrderHelicopterLand and Zen_OrderVehicleMove now have parameters to delete the vehicle and its crew in the event of a crash (Zen_OrderHelicopterLand) or having reached its destination (Zen_OrderVehicleMove). These are the first of several changes oriented towards improving vehicle cleanup and thus performance (more in the roadmap section).

Finally, I've updated the Zen_RandomPositions demonstration with Zen_FindGroundPosition's new blacklist/whitelist feature. I've also brought the JIP code in two sample missions up to the current standard (Zen_AssaultFrini remains the same, as an example for missions with no friendly AI). I've also added a new check to distinguish between disabled and enabled friendly AI.

2/11/15

  1. New Function: Zen_FindRayIntersection
  2. Fixed: Zen_ConvertToGroupArray, Zen_ConvertToObjectArray did not work when given multiple sides
  3. Fixed: Zen_FindBuildingPositions failed for buildings with a dirt floor
  4. Fixed: Zen_FindRoadDirection error typo
  5. Added: Zen_OrderHelicopterLand has parameter to cleanup the helicopter if it crashes enroute
  6. Added: Zen_OrderVehicleMove has parameter to delete the vehicle when it reaches its destination
  7. Improved: Zen_FindBuildingPositions optimized
  8. Improved: Zen_FindBuildingPositions searches for higher positions in tall buildings
  9. Documentation: Added for Zen_FindRayIntersection
  10. Documentation: Updated for Zen_OrderHelicopterLand, Zen_OrderVehicleMove
  11. Documentation: Updated Zen_RandomPositions and Zen_JIP demonstration
  12. Documentation: Updated Zen_InfantryPatrol and Zen_RespawnPatrol sample missions JIP logic

Roadmap

Next release, I plan to add dead vehicle cleanup logic to Zen_OrderAircraftPatrol, Zen_OrderBoatPatrol, Zen_OrderVehicleDrop, and Zen_OrderVehiclePatrol. This may include deleting the crew as well, or I might have them patrol or try to join nearby friendlies. I also plan to add cleanup for vehicles killed enroute in Zen_OrderVehicleMove. The goal of these changes is to make mission cleanup and performance even easier with the framework.

Also, I'm currently working on a complete solution to check for disabled AI in JIP (the JIP player is a new object) that doesn't depend upon the task system. That might end up as a local variable as _Zen_Is_JIP is.

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_SetTaskTarget. This function will make a task track a specific object, updating the task's destination in real time. If you want players to be aware of exactly where their target is, Zen_SetTaskTarget provides that feature.

// Assume X is an object in the players' group
_playerGroup = group X;

_targetPos = [X, [300, 600], 0, 1, [1, 200]] call Zen_FindGroundPosition;
_targetVeh = [_targetPos, east] call Zen_SpawnGroundVehicle;
0 = [_targetVeh, _targetPos] spawn Zen_OrderVehiclePatrol;

_taskDestroyVeh = [_playerGroup, "Find and eliminate the patrolling Opfor vehicle.", "Destroy Opfor Vehicle", _targetPos, true] call Zen_InvokeTask;
0 = [_taskDestroyVeh, _targetVeh] call Zen_SetTaskTarget;

It's up to you if you want to reveal the objective to the players. Zen_SetTaskTarget can also simulate spotters or a UAV.

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

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

If anyone can edit this to use RHS and/or Leights opfor pack you would save me a lot of time.

Also I'd love it if there were some YouTube videos explaining how to use this effectively. This seems like a very powerful framework but the amount of time to get a grasp of it is a little long for this visual learner. if nobody beats me to either of these tasks and if I have the patience to complete them, I'll make sure to share both.

Excellent stuff though, keep up the good work Zenophon.

Share this post


Link to post
Share on other sites
If anyone can edit this to use RHS and/or Leights opfor pack you would save me a lot of time.

Also I'd love it if there were some YouTube videos explaining how to use this effectively. This seems like a very powerful framework but the amount of time to get a grasp of it is a little long for this visual learner. if nobody beats me to either of these tasks and if I have the patience to complete them, I'll make sure to share both.

Excellent stuff though, keep up the good work Zenophon.

I'll quote myself on the subject of using addon units and vehicles once again:

In general, all the functions related to directly spawning people and vehicles can spawn addon units, and everything spawned using the framework can be 100% controlled by the mission maker. The framework does not use any preset lists of units that spawn. Whenever it spawns soldiers or vehicles randomly, it dynamically reads the config files looking for certain kinds of objects.

Specifically to your question, I assume you mean spawning soldiers using one of these functions:

  • Zen_SpawnGroup
  • Zen_SpawnInfantry

For Zen_SpawnGroup, you can simply list the classnames from the addon units as they appear in the editor or the readme of the mod. This is the fastest, simplest option to get addon units into your mission. For example:

_group = ["mkSpawn", <Array of Addon Classnames Here>] call Zen_SpawnGroup;

This will spawn the soldier objects in order at 'mkSpawn' and return the group. You still might want to set the AI's skill though, using Zen_SetAISkill.

For Zen_SpawnInfantry, getting addon units requires a little more work and some basic knowledge of config files. You need to provide information about certain config file values. However, you then get to use the features of Zen_SpawnInfantry, such as a randomized number and type of units.

You must open the config files in the editor, then find the addon units classnames under cfgVehicles (BIS really needs to add a search/filter option). The values for parameters 5 and 6 are called 'vehicleClass' and 'faction'. See Zen_SpawnInfantry documentation for parameters 5 and 6. For example:

_group = ["mkSpawn", east, 0.3, 5, <vehicleClass value (String)>, <faction value (String)>] call Zen_SpawnInfantry;

This will spawn 5 random soldiers whose side, vehicleClass, and faction match the arguments at 'mkSpawn' with skill 0.3 and return the group.

For vehicle spawning functions, you can give classnames just like Zen_SpawnGroup. However, the crew of the vehicle (for those functions that create it) will be from the vanilla pool of units (they cannot default to anything else). You should first spawn the vehicle empty, using Zen_SpawnVehicle, then spawn the addon crew and put them inside like so:

_vehicle = ["mkSpawn", <Addon Vehicle Classname (String)>] call Zen_SpawnVehicle;
_crew = [_vehicle, <Array of Addon Classnames Here>] call Zen_SpawnGroup;
0 = [_crew, _vehicle, "All"] call Zen_MoveInVehicle;

The vehicle at 'mkSpawn' now has all possible positions filled with addon units from the group. Just be sure to list the right number of classnames for that particular vehicle. You could also use an empty vehicle from the editor instead of spawning one in the code. This lets you put any crew you want into any vehicle.

Finally, if you want to directly generate the classname lists the functions are using, the function to use is Zen_ConfigGetVehicleClasses. See the demonstration mission entitled RandomBattle.Altis for a very detailed explanation of that function and what I just posted about config values.

In fact, you can see exactly how to use all that in a complete mission:

http://forums.bistudio.com/showthread.php?185113-CO-4-8-ZEN-Insurgency-Chernarus-by-WmD

As for videos, I don't think I could make any that weren't boring and useless, as 90% of to time they would just show me typing code. It would be no more visual than the existing wall-of-text/code documentation. Thus, I just include all those typed things in the documentation, rather than narrating and typing them in a video. Tutorials are the most visual documentation, as they were done with PDF.

My framework is 99% oriented towards programming; if you don't have any programming experience, it may be useful to look at tutorials for real programming languages. Any internet tutorial on C/C++, Java, Python, etc. will explain the basics of variables, control structures, etc. I assume my users have an understanding of functions, literals, types, etc.; the documentation must be useful to advanced mission makers.

Finally, I find it is generally best to learn by doing. Look at the tutorials and sample missions to see what functions they use, then try making your own missions with those functions. You can do a lot with the two dozen or so most common functions. I don't expect anyone to be completely familiar with every function (175 public ones); I wrote (and often rewrote) every single function myself, I still forget and have to look at their documentation.

Share this post


Link to post
Share on other sites

Hey Zenophon. Your framework is working awesome! I have a feature request! Can you add the ability to the Zen_OrderVehiclePatrol to only put the patrol waypoints on roads. As everyone knows the AI driving is bad and the soft wheels of the technicals and offroads are especially bad for the AI taking out their tires on rocks and such. Having them stick to the roads (As much as possible) would be a nice option!

Share this post


Link to post
Share on other sites
Hey Zenophon. Your framework is working awesome! I have a feature request! Can you add the ability to the Zen_OrderVehiclePatrol to only put the patrol waypoints on roads. As everyone knows the AI driving is bad and the soft wheels of the technicals and offroads are especially bad for the AI taking out their tires on rocks and such. Having them stick to the roads (As much as possible) would be a nice option!

Zen_OrderVehiclePatrol already tells Zen_FindGroundPosition to prefer road positions. However, the range to scan for a road was being influenced by the vehicle's position from the center. Basically, when the vehicle was at the center of the patrol area, it worked fine; when the vehicle was on the very edge of the patrol area, the road scanning radius was reduced to 0.

That doesn't make sense, and I don't know why I put it in there. So, next release it will scan for roads using twice the entire size of the patrol area. This should return a position on a road 99% of the time if there are roads in the patrol area. A large distance requires more processing time (as it will also find roads outside the patrol area); however, a new waypoint is only calculated every few minutes or more.

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

The highlights of this release are new parameters for several AI orders functions, focusing on the cleanup of dead units. Zen_OrderInfantryPatrol also get a different sort of cleanup, by allowing small groups to join larger ones nearby.

Zen_OrderAircraftPatrol, Zen_OrderBoatPatrol, and Zen_OrderVehiclePatrol can automatically cleanup destroyed vehicles after 60 seconds. Since there wasn't a simple solution for what to do with any surviving crew, they will be deleted as well. As always, if you don't like that, tell me about it and I'll try something else.

Zen_OrderVehicleDrop and Zen_OrderVehicleMove now join Zen_OrderHelicopterLand in being able to cleanup a vehicle that has been destroyed before reaching its destination. All of this cleanup is optional, and the parameters default to false; old missions won't be affected by this new logic.

Some more mathematical improvements: there's a new macro, ZEN_STD_Math_VectRotateZ, for rotating a vector by an angle. This is useful for manipulating XYZ (Cartesian coordinate) vectors such as velocity or position. The algorithm used is faster than converting from Cartesian to polar then back.

Zen_FindRayIntersection was converted from a polar coordinates solution to a Cartesian coordinates solution. The time difference in the optimization is small, but it avoids some issues with angles that made the polar solution complex.

I've finally got around to optimizing Zen_IsWaterArea (previously it disabled argument checking to go faster) by adapting the algorithms in Zen_FindPositionPoly to Cartesian coordinates; those are faster for the specific case of Zen_IsWaterArea (no limited angles). The blacklist feature is still enforced, so you can define any arbitrary area to check for water. By 'significantly' optimized, I mean about 5 times faster on average (with the same number of points checked).

2/25/15

  1. Fixed: Zen_GetAllInArea returned animals
  2. Fixed: Zen_OrderVehicleMove did not search for road positions in a large enough radius
  3. Added: Standard macro ZEN_STD_Math_VectRotateZ
  4. Added: Zen_OrderAircraftPatrol, Zen_OrderBoatPatrol, and Zen_OrderVehiclePatrol have a parameter to cleanup destroyed vehicles and their crew
  5. Added: Zen_OrderInfantryPatrol parameter to join weak groups to nearby ones
  6. Added: Zen_OrderVehicleDrop and Zen_OrderVehicleMove have a parameter to cleanup the vehicle if it is destroyed enroute
  7. Improved: ZEN_STD_Math_TransformATL renamed ZEN_STD_Math_VectTransformATL
  8. Improved: Zen_ArrayRemoveValue optimized
  9. Improved: Zen_FindRayIntersection optimized
  10. Improved: Zen_IsWaterArea significantly optimized
  11. Documentation: Fixed JIP demonstration had two small code errors
  12. Documentation: Added for ZEN_STD_Math_VectRotateZ
  13. Documentation: Updated for Zen_OrderAircraftPatrol, Zen_OrderBoatPatrol, Zen_OrderInfantryPatrol, Zen_OrderVehicleDrop, Zen_OrderVehicleMove, Zen_OrderVehiclePatrol, ZEN_STD_Math_VectTransformATL
  14. Documentation: Updated Zen_FindGroundPosition diagram

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_TriggerAreaClear. This function is not exactly obscure, but is sufficiently useful to warrant it's week of fame (and indirectly advertise the other trigger functions).

Zen_TriggerAreaClear is useful for missions where AI (or players in PvP) can wander in and out of objective zones. It allows you to give any objects to look for in the area, but most often giving a side is easiest:

_clearAreaTask = [group X, "", "Clear Town"] call Zen_InvokeTask;
0 = [east, _clearAreaTask, "succeeded", "mkTown"] spawn Zen_TriggerAreaClear;

Zen_TriggerAreaClear will automatically consider all east units, even those spawned after this code runs. This allows the task to succeed if the Opfor flee the town (in contrast to Zen_TriggerAreDead), and it accounts to Opfor reinforcements moving into the town.

Zen_TriggerAreaClear also operates in 2 dimensions, allowing it to be used for buildings:

_buildingPos = ["mkTown"] call Zen_FindGroundPosition;
_building = nearestBuilding _buildingPos;

_clearBuildingTask = [group X, "", "Secure Building", _building] call Zen_InvokeTask;
0 = [east, _clearBuildingTask, "succeeded", _building, [10, 10], 0, "rectangle"] spawn Zen_TriggerAreaClear;

However, you might be thinking: that's not a trigger! A trigger allows you to run any code you want. Using the framework, you can write triggers that are more efficient and more complex just by putting the code in a new thread.

// using _clearAreaTask from the first example
0 = _clearAreaTask spawn {
   _h_areaSecure = [east, _this, "succeeded", "mkTown"] spawn Zen_TriggerAreaClear;

   ZEN_STD_Code_WaitScript(_h_areaSecure)
   // ... Your code here
};

Finally, what if you want to stop the trigger due to some mission event (e.g. Opfor counter-attack) so that task can't be completed.

_h_areaSecure = [east, _this, "succeeded", "mkTown"] spawn Zen_TriggerAreaClear;

// ... Later ...
terminate _h_areaSecure;

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

Excellent work, I started creating missions for my small community few weeks ago and your framework is very helpful.

I had some issues with the spawning vehicle functions that I use for airdrops: the unit is spawned on the marker before being moved in to the set altitude. Which becomes a problem if something, or someone is occupying the spawn marker - both are destroyed. Same problem occurs if I don't set a delay between spawning vehicles - they collide destroying each other. Is there remedy for this behavior ?

Share this post


Link to post
Share on other sites

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
Excellent work, I started creating missions for my small community few weeks ago and your framework is very helpful.

I had some issues with the spawning vehicle functions that I use for airdrops: the unit is spawned on the marker before being moved in to the set altitude. Which becomes a problem if something, or someone is occupying the spawn marker - both are destroyed. Same problem occurs if I don't set a delay between spawning vehicles - they collide destroying each other. Is there remedy for this behavior ?

This works fine in singleplayer (although they will crash without a crew):

// X is the player
0 = [X, "b_heli_transport_01_f", 0] call Zen_SpawnVehicle;
0 = [X, "b_heli_transport_01_f", 0] call Zen_SpawnVehicle;
0 = [X, "b_heli_transport_01_f", 50] call Zen_SpawnVehicle;

Then, I tested it in multiplayer on a dedicated server, and it worked there as well. Every spawning function that create vehicles (but not infantry) eventually calls Zen_SpawnVehicle, so this applies to Zen_SpawnHelicopter, etc.

There's no timing issue in this test because Zen_SpawnVehicle (using 'call') executes until it finishes entirely, then the init.sqf resumes and the next Zen_SpawnVehicle is called. Vehicles that don't start in the air default to avoiding existing vehicles using an argument to createVehicle. The flying helicopter gets a argument to createVehicle that starts it in the air, after which it is placed at the exactly correct position.

So long as the heights are different by a few meters (or are less than 2), the helicopters can never collide, so long as execution is linear. It's possible that multiple threads could interfere with each other and interrupt the placement of the helicopter.

I need to see the code that's related to this bug to reproduce it, as it's likely that you have encountered some special case or an unlikely sequence of events that does cause a collision, beyond the simple case I checked here.

Share this post


Link to post
Share on other sites

I use it for spawning air drop of few HummVees with gear, when players are near certain markpoint (airDrop):

for "_i" from 1 to 2 do{
_truck=["airDrop","rhsusf_m998_d_4dr",200,135,FALSE] call Zen_SpawnVehicle;
#include "Truck_Load.sqf";
nul=[_truck,"SmokeShellOrange"]spawn Zen_SpawnParachute;
sleep 3;
};

If I omit the sleep function: both explode on the airDrop marker (ground level), and then fall as burning wreckage. If I set sleep to less than 3, they will collide in the air.

Truck_Load.sqf is just simple list of attachto-s, and additemcargo-s to configure those trucks as I want them. The outcome is the same if I rem that line out or not.

Share this post


Link to post
Share on other sites
I use it for spawning air drop of few HummVees with gear, when players are near certain markpoint (airDrop):

for "_i" from 1 to 2 do{
_truck=["airDrop","rhsusf_m998_d_4dr",200,135,FALSE] call Zen_SpawnVehicle;
#include "Truck_Load.sqf";
nul=[_truck,"SmokeShellOrange"]spawn Zen_SpawnParachute;
sleep 3;
};

If I omit the sleep function: both explode on the airDrop marker (ground level), and then fall as burning wreckage. If I set sleep to less than 3, they will collide in the air.

Truck_Load.sqf is just simple list of attachto-s, and additemcargo-s to configure those trucks as I want them. The outcome is the same if I rem that line out or not.

They can't collide on the ground because the first on is already 200 meters in the air before the second one spawns, even without sleep. They collide in the air because Zen_SpawnVehicle is overriding the 'false' parameter if the height is greater than 2. This is because createVehicle only checks in 2 dimensions for collisions, so that option isn't needed when spawning vehicles above the ground.

Thus, the trucks are being put at the same exact position in the air. This is solved by putting the vehicles at different heights. This is tested and working for me:

for "_i" from 1 to 2 do {
   _truck = [player, "b_mrap_01_f", 50*_i + 100, 135] call Zen_SpawnVehicle;
   0 = [_truck, "SmokeShellOrange"] spawn Zen_SpawnParachute;
};

Next release, I will change Zen_SpawnVehicle to respect its fifth parameter if that argument is given (so giving false will always avoid collisions). Otherwise, it will default to false on the ground and true in the air (as it is now). This seems like the best solution.

Share this post


Link to post
Share on other sites

Hello Zenophon

Im currently working on a co-op mission but has hit a dead end currently trying to improve the first current objective

the first objective is to eliminate an aaf officer

the objective itself works great i have the officer and his camp spawning at random within a marker along with that i have a empty strider thats parked up with a unit crouched near and a partol group roaming the area close by

i would like to expand on this objective

i would like the objective to be completed once the officer has been killed and intel has been picked up from his body

the intell that is grabed would lead on to the second objective the objective would be to rescue a blufor team help captive

here is the code currently used fror the task and surrounding area

// Generate random position within area marker:
_ObjectivePos = ["officer"] call Zen_FindGroundPosition;

// Place a Warlord task objective at this random point:
_warlordReference = [_ObjectivePos, X11, resistance, "Officer","eliminate"] call Zen_CreateObjective;
_warlord = (_warlordReference select 0) select 0;

// Spawns Patrol Around Officer
for "_i" from 0 to 1 do {
   _PatrolPos = [_objectivePos, [10,80]] call Zen_FindGroundPosition;
   _GuardPatrol = [_PatrolPos, resistance, "infantry", [2,6]] call Zen_SpawnInfantry;
   _GuardsPatrolArray set [(count _GuardsPatrolArray), _GuardPatrol];
};

0 = [_GuardsPatrolArray, _objectivePos, [15,90]] spawn Zen_OrderInfantryPatrol;

_returnArray = [(_GuardsPatrolArray), "group"] call Zen_TrackInfantry;

// Officer's car 
_CarPosition = ["officer", [5,40]] call Zen_FindGroundPosition;
_Strider = [_CarPosition,"I_MRAP_03_F",0,180] call Zen_SpawnVehicle;

_OfficerGaurds = [_CarPosition,[0,20],0,1,[1,10]] call Zen_FindGroundPosition;
_staticSquad = [_OfficerGaurds, resistance, "infantry", [1,3]] call Zen_SpawnInfantry;

// force them to kneel down
{
   _x setUnitPosWeak "Middle";
} forEach (units _staticSquad);

waituntil { sleep 2; !(alive _warlord) };

thanks in advanced zen

Share this post


Link to post
Share on other sites
Hello Zenophon

Im currently working on a co-op mission but has hit a dead end currently trying to improve the first current objective

the first objective is to eliminate an aaf officer

the objective itself works great i have the officer and his camp spawning at random within a marker along with that i have a empty strider thats parked up with a unit crouched near and a partol group roaming the area close by

i would like to expand on this objective

i would like the objective to be completed once the officer has been killed and intel has been picked up from his body

the intell that is grabed would lead on to the second objective the objective would be to rescue a blufor team help captive

here is the code currently used fror the task and surrounding area

// Generate random position within area marker:
_ObjectivePos = ["officer"] call Zen_FindGroundPosition;

// Place a Warlord task objective at this random point:
_warlordReference = [_ObjectivePos, X11, resistance, "Officer","eliminate"] call Zen_CreateObjective;
_warlord = (_warlordReference select 0) select 0;

// Spawns Patrol Around Officer
for "_i" from 0 to 1 do {
   _PatrolPos = [_objectivePos, [10,80]] call Zen_FindGroundPosition;
   _GuardPatrol = [_PatrolPos, resistance, "infantry", [2,6]] call Zen_SpawnInfantry;
   _GuardsPatrolArray set [(count _GuardsPatrolArray), _GuardPatrol];
};

0 = [_GuardsPatrolArray, _objectivePos, [15,90]] spawn Zen_OrderInfantryPatrol;

_returnArray = [(_GuardsPatrolArray), "group"] call Zen_TrackInfantry;

// Officer's car 
_CarPosition = ["officer", [5,40]] call Zen_FindGroundPosition;
_Strider = [_CarPosition,"I_MRAP_03_F",0,180] call Zen_SpawnVehicle;

_OfficerGaurds = [_CarPosition,[0,20],0,1,[1,10]] call Zen_FindGroundPosition;
_staticSquad = [_OfficerGaurds, resistance, "infantry", [1,3]] call Zen_SpawnInfantry;

// force them to kneel down
{
   _x setUnitPosWeak "Middle";
} forEach (units _staticSquad);

waituntil { sleep 2; !(alive _warlord) };

thanks in advanced zen

Zen_CreateObjective will complete the task automatically, so you can create another task to get the intel once he is dead. Then use Zen_CreateObjective again to create the rescue objective.

waituntil { sleep 2; !(alive _warlord) };  

_taskIntel = [X11, "Get to the warlord's body and take the intel.", "Secure Intel", _warlord] call Zen_InvokeTask;

ZEN_FMW_Code_WaitDistanceLess(X11, _warlord, 2)
sleep 2;
0 = [_taskIntel, "succeeded"] call Zen_UpdateTask;

_captivePos = [X, [200, 300]] call Zen_FindGroundPosition;
_captiveObjective = [_captivePos, X11, west, "custom", "rescue", ["B_Soldier_F", "B_Soldier_F"]] call Zen_CreateObjective;
ZEN_FMW_Code_SpawnPoint(_captivePos, 100, 2, east)

waitUntil {
   sleep 2;
   ([(_captiveObjective select 1)] call Zen_AreTasksComplete)
};

// ... next part of mission ...

If you want the intel to be taken with an action, that's harder to do in multiplayer due to locality issues. Having to stand next to the body is quite nearly the same thing.

Share this post


Link to post
Share on other sites
They can't collide on the ground because the first on is already 200 meters in the air before the second one spawns, even without sleep. This is tested and working for me:

for "_i" from 1 to 2 do {
   _truck = [player, "b_mrap_01_f", 50*_i + 100, 135] call Zen_SpawnVehicle;
   0 = [_truck, "SmokeShellOrange"] spawn Zen_SpawnParachute;
};

Thanks, although I figured out what caused the ground level explosions. I was also spawning a smoke grenade and a chemlight on that same marker before the HummVees. Switched it to mark the drop zone after the HummVees have spawned and that issue is resolved. Still if any other vehicle is on the drop zone marker - when the Zen_SpawnVehicle is triggered - they will collide with appearing HummVees. I'll have to set an offset for that mark to be in the air:

for "_i" from 1 to 2 do{
_truck=[[(getMarkerPos "airDrop" select 0), (getMarkerPos "airDrop" select 1),(getMarkerPos "airDrop" select 2)+50],"rhsusf_m998_d_4dr",50*_i+100,135] call Zen_SpawnVehicle;
#include "Truck_Load.sqf";
0=[_truck,"SmokeShellOrange"]spawn Zen_SpawnParachute;
};

But I'm too tired for that right now, I've spend whole day forcing an C-130 to stay on the ground till the mission group board it - had to be aircraft from RHS pack, had to be as civilian, when the mission group was west... whole day of pulling hairs... and now the dedicated server is not executing half of the code: setting textures, changing gear, adding addActions, attaching things to other things...

I need a holiday from ArmA scripting.

Edited by Sundowner

Share this post


Link to post
Share on other sites

I have a question about the 'Zen_OrderInfantryPatrol'. If I give a squad this order, and then after an armoured unit that they are protecting is destroyed, I want to give them a 'Zen_OrderInfantryPatrolBuilding' order, will the previous order be cancelled, or only when all the squad is dead?

Thanks,

Share this post


Link to post
Share on other sites
Still if any other vehicle is on the drop zone marker - when the Zen_SpawnVehicle is triggered - they will collide with appearing HummVees. I'll have to set an offset for that mark to be in the air:

for "_i" from 1 to 2 do{
_truck=[[(getMarkerPos "airDrop" select 0), (getMarkerPos "airDrop" select 1),(getMarkerPos "airDrop" select 2)+50],"rhsusf_m998_d_4dr",50*_i+100,135] call Zen_SpawnVehicle;
#include "Truck_Load.sqf";
0=[_truck,"SmokeShellOrange"]spawn Zen_SpawnParachute;
};

Aaaaaand of course it doesn't work. The problem for me lies in the 62 line of code in Zen_SpawnVehicle.sqf:

_vehicle = createVehicle [_class, _pos, [], 0, _special];

Because its using "createVehicle", and that vehicle is a truck - it always spawns on the ground before being moved to the air, and because that code is not run in an instant, those could be few frames in-between - giving time for collision detection to trigger. I had such trouble creating a base camp, where things being spawned, moved and rotated created collisions.

For now I modified that line of code to be:

_vehicle = createVehicle [_class, [0,0,0], [], 0, _special];

So it will spawn those trucks in the origin point, and then move to _pos. Works like a charm.

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

×