Jump to content
Zenophon

Zenophon's ArmA 3 Co-op Mission Making Framework

Recommended Posts

On a dedicated server in the latest update of Black Ops missions (all 3 maps) only the squad leader is in the Helicopter, all other squad member are left behind on the ground? Was not the case in previous versions.

Thank you again for this report, I send you a PM. I've also made a bug report request in the Black Ops thread (you already answered most of that; it's for other users).

Since you posted in my framework's thread...I also want to make a request to any framework users reading this:

As you may know, the function in question is Zen_MoveInVehicle. This function works for a single client on a dedicated server, but appears to fail in some cases for multiple clients on a dedicated server (the vehicle is local to the server). Thus, if anyone is testing this function with multiple players and can reproduce this failure, please report as much information as possible about it. Also, if you can replace Zen_MoveInVehicle with code that works in the same situation, please send me that code as well so I can compare. Everything is potentially important here: the ping of the clients, the version of the framework and of ArmA, other code in the mission, etc.

Share this post


Link to post
Share on other sites
Is the pilot a player? All orders functions are intended for the AI only. For a player, I would use setSlingLoad/ropeCreate directly (like you did) or through an action, as Zen_OrderSlingLoad uses setVelocity to force the AI pilot to do it.

Pilot was player in my mission, but I have tested it with AI too.

Zen_MoveInVehicle is using moveInTurret, maybe that vehicle You used had no turrets configured?

Here is nice script to check turrets in vehicle: http://kronzky.info/turrets/index.htm

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

Good news, everyone. I'm taking advantage of the flexible release schedule I mentioned to bring you numerous changes. The highlights of this release are improvements to fire support actions and corrections and refinements to several macros.

A new function, Zen_UpdateFireSupportAction, allows you add units dynamically to an existing fire support action as well as change the maximum number of usages. Unfortunately, I cannot offer changing the name, support template, or guidance information at this point. I'm going to rewrite the internal data structure for next release, which should bring easier management and more features with minimal change to function arguments.

Zen_AddFireSupportAction now offers a new 'player' special argument, which will make the designating unit the player that calls the action (regardless of which client it is). Zen_AddFireSupportAction can now run only locally, which helps solve JIP issues. The JIP demonstration has been updated with an example of this. Zen_RemoveFireSupportAction now has a parameter to remove only specific units, so you can now manage units assigned to an action dynamically.

Zen_InvokeFireSupport now offers several new types of artillery rounds that it can fire; "cluster_155mm_amos" might be especially interesting to some. The list of working classnames at the top of Zen_FireSupportSystem.txt has been updated. Any classnames not listed will likely not work.

The framework's helpful remote execution macros, ZEN_FMW_MP_REAll, ZEN_FMW_MP_REClient, ZEN_FMW_MP_RENonDedicated, and ZEN_FMW_MP_REServerOnly, now offer a parameter to choose between spawn or call when running the function locally. This is not an optional argument (not possible for macros), so you must update all usages of these commands. All remote executed functions are still always run with spawn; remote executing with call is pointless as the function is already being run out of scope.

By user request, Zen_OrderSlingLoad now offers an optional parameter to use a manually created rope instead of the engine's built-in sling-loading feature. This will allow any helicopter to lift any object. This rope is only used if the object cannot be lifted by the default means, and the argument defaults to false.

I realize that what I said last week about ZEN_FMW_Math_TerrainGradientCart and something about a level set might have been confusing. Thus, a new macro, ZEN_FMW_Math_TerrainParallelCart, does what I described last week. It is the unit vector (magnitude 1) parallel (tangent) to the terrain pointing towards the greatest elevation increase (up hill). It is exactly perpendicular to surfaceNormal in all cases; their dot product is the zero vector ([0,0,0]), their cross product points in the direction of no elevation increase.

ZEN_FMW_Math_TerrainGradientCart is the proper 2D Cartesian gradient. It gives the direction in the XY plane towards the greatest Z increase, and its magnitude is the ratio of the change in Z for the change in X and Y parallel to the gradient. Thus, its dot product with an XY displacement vector gives the change in elevation (near the given point).

6/17/15

  1. New Function: Zen_UpdateFireSupportAction
  2. Fixed: Zen_AddFireSupportAction did not update the usage count on all other clients
  3. Fixed: Zen_InvokeFireSupport caused an error on guided rounds
  4. Fixed: Zen_RemoveFireSupportAction caused an error on a dedicated server
  5. Added: Zen_OrderSlingLoad parameter to create a rope manually
  6. Added: Zen_AddFireSupportAction parameter to remote execute
  7. Added: Framework macro ZEN_FMW_Math_TerrainParallelCart
  8. Added: Zen_RemoveFireSupportAction parameter to remove from specific units
  9. Added: ZEN_FMW_MP_REAll, ZEN_FMW_MP_REClient, ZEN_FMW_MP_RENonDedicated, and ZEN_FMW_MP_REServerOnly call or spawn locally argument
  10. Improved: Zen_AddFireSupportAction allows a special value to make the guiding object the invoking player
  11. Improved: Zen_InvokeFireSupport supports more round types
  12. Improved: ZEN_FMW_Math_TerrainGradientCart is now a 2D gradient with correct length
  13. Improved: ZEN_FMW_Misc_ErrorExitVoid renamed to ZEN_FMW_Code_ErrorExitVoid
  14. Improved: ZEN_FMW_Misc_ErrorExitValue renamed to ZEN_FMW_Code_ErrorExitValue
  15. Improved: ZEN_FMW_Misc_Error renamed to ZEN_FMW_Code_Error
  16. Documentation: Added for Zen_UpdateFireSupportAction and ZEN_FMW_Math_TerrainParallelCart
  17. Documentation: Improved Zen_JIP.sqf demonstration with fire support and for general readability
  18. Documentation: Updated for Zen_AddFireSupportAction, ZEN_FMW_MP_REAll, ZEN_FMW_MP_REClient, ZEN_FMW_MP_RENonDedicated, ZEN_FMW_MP_REServerOnly, ZEN_FMW_Code_ErrorExitVoid, ZEN_FMW_Code_ErrorExitValue, ZEN_FMW_Code_Error, ZEN_FMW_Math_TerrainParallelCart, Zen_OrderHelicopterLand, Zen_OrderSlingLoad, and Zen_RemoveFireSupportAction
  19. Documentation: Updated Notepad++ SQF language and autocompletion file with ArmA 1.46 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 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_FindValidDirection. This function provides direction avoidance of arbitrary circular areas. Its primary purpose is to determine which direction to go to escape from a point or where to start to reach a point. The circular areas could be AA sites, snipers, MG nests, etc.

For example, if you place some AA infantry near your insertion point and want your helicopter to reach it alive:

// define _insertionPos before
_AAPos = [_insertionPos, [700, 1000]] call Zen_FindGroundPosition;
_AAgroup = [_AAPos, east, "infantry", 2] call Zen_SpawnInfantry;
0 = [_AAgroup, "AA specialist", false] call Zen_GiveLoadoutOpfor;

_anglesArray = [_insertionPos, _AAPos, 500] Zen_FindValidDirection;
_infilAngle = ZEN_STD_Array_RandElement(_anglesArray);

// define _players before
_heliStartPos = [_insertionPos, [3000, 4000], 0, 0, 0, [_infilAngle - 1, _infilAngle + 1, "trig"]] call Zen_FindGroundPosition;
_heli = [_heliStartPos, "b_heli_transport_01_f"] call Zen_SpawnHelicopter;
0 = [_players, _heli] call Zen_MoveInVehicle;
0 = [_heli, [_insertionPos, _heliStartPos], _players] spawn Zen_OrderInsertion;

Zen_FindValidDirection returns trig angles (east is 0, then goes counter-clockwise), so Zen_FindGroundPosition needs to be told that. If there is no possible solution (complete 360 coverage), Zen_FindValidDirection will return an empty array (that's not possible in the above example).

Feedback

Pilot was player in my mission, but I have tested it with AI too.

Zen_MoveInVehicle is using moveInTurret, maybe that vehicle You used had no turrets configured?

Here is nice script to check turrets in vehicle: http://kronzky.info/turrets/index.htm

Zen_GetTurretPaths should be working (I haven't changed it in a while). It might be failing due config changes in the last few BIS patches. I'll have to run it against all the vanilla vehicles to check.

For Zen_MoveInVehicle, the mission (Black Ops) uses the UH-80, which has moveInCargo positions for the players. You bring up a good point: is the bug due to some difference between moveInCargo and moveInTurret? It also makes me think about using an index with moveInCargo. It may be that the clients are trying to take the same seat due to lag. If every unit gets a different seat assigned by the server, the engine won't have to decide exactly where to put them. Thanks for this.

I'm also going to start working on a very low-traffic, high-ping version of Zen_MoveInVehicle with the minimum remote execution possible. It may be that I've gone too far trying to make it work, and now it's just too bloated for some connections.

Share this post


Link to post
Share on other sites

Hi Zen,

Glad to see your excellent work on the framework continues. After an Arma 3 hiatus, i am back, and playing around with the framework.

I am building a mission where i want to gate the players access to good weaponry. i would ideally like to do this by issuing reward crates that i can manually compile the loadouts of (crate 1 SMGs, Crate 2 semi rifles, crate 3 LMGs, etc)

Looking through the documentation, I do not think this is currently possible with Zen_SpawnAmmoBox. Do you have any plans to expand that function to allow customised crates? Can you suggest another way i could achieve this?

Many Thanks

CMS

Edited by CallMeSarge
typos

Share this post


Link to post
Share on other sites

@CallMeSarge

I used the loadouts to create 6 different types (ie. default, recon, mercenary) and within each type, there are sets of gear (ie. rifleman, marksman, grenadier).

So when I assign a loadout to a vehicle or ammobox (the option to select a loadout) I can assign "recon" or "mercenary" or "guerilla", etc. I don't know if thats what you mean, but rather than modify the contents, I could just spawn a typical ammo crate, and apply whichever "loadouts" I wanted to it. It uses only Zens framework. I just had to be a little more creative in my script and how to use the loadout function(s).

@Zen

I am wondering, in a coop mission, with say 4 "playableUnits", each a "human" player, how could I get the current task of a given unit that is not the player? In other words, the server wants to know a clients current task (or the end result is the position of the clients current task).

Share this post


Link to post
Share on other sites
Hi Zen,

Glad to see your excellent work on the framework continues. After an Arma 3 hiatus, i am back, and playing around with the framework.

I am building a mission where i want to gate the players access to good weaponry. i would ideally like to do this by issuing reward crates that i can manually compile the loadouts of (crate 1 SMGs, Crate 2 semi rifles, crate 3 LMGs, etc)

Looking through the documentation, I do not think this is currently possible with Zen_SpawnAmmoBox. Do you have any plans to expand that function to allow customised crates? Can you suggest another way i could achieve this?

Many Thanks

CMS

As m0nkey said, you could use custom loadouts and Zen_GiveLoadoutCargo (just leave out 'uniform', 'vest', etc.). You would be able to clear and reset the cargo using loadout presets that represent the different tiers. You can randomize the loadouts, give each one multiple times, etc. You can spawn the box itself with Zen_SpawnAmmoBox or Zen_SpawnVehicle; either way, you'd need to clear the existing cargo. I did this in my ZMCM mission 'Cleaner' to put a sniper rifle in a box.

@CallMeSarge

I used the loadouts to create 6 different types (ie. default, recon, mercenary) and within each type, there are sets of gear (ie. rifleman, marksman, grenadier).

So when I assign a loadout to a vehicle or ammobox (the option to select a loadout) I can assign "recon" or "mercenary" or "guerilla", etc. I don't know if thats what you mean, but rather than modify the contents, I could just spawn a typical ammo crate, and apply whichever "loadouts" I wanted to it. It uses only Zens framework. I just had to be a little more creative in my script and how to use the loadout function(s).

@Zen

I am wondering, in a coop mission, with say 4 "playableUnits", each a "human" player, how could I get the current task of a given unit that is not the player? In other words, the server wants to know a clients current task (or the end result is the position of the clients current task).

You mean not the player as in an AI, or a remote object? You want a framework equivalent of 'currentTask' that returns the abstract task? That's not possible with only the public API, as I don't use 'assigned' as a possible task state. I'm not aware of an EH that can catch switching to a new current task in the UI, so there's no way to keep track of which is assigned automatically.

However, you find the logical task using a true task by searching the hidden local task data. Usually, I don't generally recommend going through data like this, but I think this is the only way. if this works well, I'll probably tweak it a little (make it work from the server) make it a function for next release.

Running on the machine where the object (AI or player) is local:

_unit = _this select 0;
_curTask = currentTask _unit;

_nameString = "";
{
   if (_curTask in (_x select 1)) exitWith {
       _nameString = _x select 0;
   };
} forEach Zen_Task_Array_Local;

_unit setVariable ["Zen_Current_Task", _nameString, true];

You can also use missionNamespace setVariable, or just a plain global variable (e.g. Current_Task) and publicVariable. Putting the variable on the unit makes the most sense if you're going to use this a lot or generalize it to many units. It's less work if units die, players quit, etc. than with a object-string paired array.

Share this post


Link to post
Share on other sites

Great example, I borrowed the code from the cleaner mission - thanks Zen, worked like a charm!

Share this post


Link to post
Share on other sites

@Zen

I am talking about the ability to find a clients current task when using Zen task system. Whether from dedicated or from listen coop. Actually I want the server to get position of a given clients current "chosen" task.

Share this post


Link to post
Share on other sites
@Zen

I am talking about the ability to find a clients current task when using Zen task system. Whether from dedicated or from listen coop. Actually I want the server to get position of a given clients current "chosen" task.

You mean the current task selected on the UI, which players can change at any time? There's no way to keep track of that globally (i.e. server-side), so you need to search the client locally. Using Zen_SetTaskCurrent and the current parameter for Zen_InvokeTask have the same effect as clicking that UI button.

The code returns the global Zen Task System task name, so you can use Zen_GetTaskDataGlobal. I've added a check for no selected current task (default at mission start).

F_GetCurrentTask = {
   _unit = _this select 0;
   _curTask = currentTask _unit;

   _nameString = "";
   if !(isNull _curTask) then {
       {
           if (_curTask in (_x select 1)) exitWith {
               _nameString = _x select 0;
           };
       } forEach Zen_Task_Array_Local;
   };

   _unit setVariable ["Zen_Current_Task", _nameString, true];

   // debug
   player commandChat str _nameString;
   player commandChat str ([_nameString] call Zen_GetTaskDataGlobal);
};

_testTask = [player, "", "test", 0, true] call Zen_InvokeTask;
0 = [player] call F_GetCurrentTask;

I just tested that in SP. In MP, you can do something like (didn't test this):

ZEN_FMW_MP_REClient("F_GetCurrentTask", _unit, call, _unit)
waitUntil {
   !((_unit getVariable ["Zen_Current_Task", 0]) isEqualTo 0)
};

_task = _unit getVariable "Zen_Current_Task";
if (_task != "") then {
   _destination = ([_task] call Zen_GetTaskDataGlobal) select 3;
};

Share this post


Link to post
Share on other sites

Hi Zeno,

I really like what your doing with this framework and all the hardwork your putting into it. its very much appreciated and is really useful. I have a question/situation that I hope you'd be willing to look at, if you have time.

I'm making a small co-op mission whereby the player squad starts in an sdv, in scuba gear (wetsuit, rebreather, diving googles). They also have a back pack which has kit in it, which they will put on when reaching a secure location on land (Balaclava, vest and uniform).

I used 'Zen_GetUnitLoadout' on a named editor placed unit which I had already geared up (This works really well btw!) and I have managed to call this loadout with Zen_GiveLoadoutCustom. It works, but, some of the items are added to the wetsuit. This means players will need to move items from the wetsuit to the backpack before changing. Also, some of the items are not assigning to the correct locations - Like NVGoggles.

I have a unit in the editor named 'ap1', which I gear him initially with the following:

Initial loadout

RemoveAllWeapons ap1;
RemoveAllItems ap1;
RemoveAllAssignedItems ap1;
RemoveUniform ap1;
RemoveVest ap1;
RemoveBackpack ap1;
RemoveHeadgear ap1;
RemoveGoggles ap1;

ap1 forceAddUniform "U_B_Wetsuit";
ap1 addVest "V_RebreatherB";
ap1 addGoggles "G_Diving";

ap1 addBackpack "B_FieldPack_blk";
clearMagazineCargoGlobal (unitBackpack ap1);
(unitBackpack ap1) additemCargoGlobal ["AAFVest01_black", 1];
(unitBackpack ap1) additemCargoGlobal ["CamoU_Black", 1];
(unitBackpack ap1) additemCargoGlobal ["G_Balaclava_blk", 1];
(unitBackpack ap1) additemCargoGlobal ["hlc_30rnd_556x45_EPR", 5];
(unitBackpack ap1) additemCargoGlobal ["11Rnd_45ACP_Mag", 2];
(unitBackpack ap1) additemCargoGlobal ["MiniGrenade", 2];
(unitBackpack ap1) additemCargoGlobal ["Chemlight_green", 2];
(unitBackpack ap1) additemCargoGlobal ["Chemlight_blue", 2];
ap1 linkitem "itemCompass";
ap1 linkitem "itemGPS";
ap1 linkitem "itemMap";
ap1 linkitem "ItemWatch";
ap1 linkItem "tf_anprc152_3";
ap1 linkitem "NVGoggles_OPFOR";

ap1 addWeapon "hlc_rifle_M4";
ap1 addPrimaryWeaponItem "hlc_muzzle_556NATO_KAC";
ap1 addPrimaryWeaponItem "acc_pointer_IR";
ap1 addPrimaryWeaponItem "optic_Nightstalker";
ap1 addPrimaryWeaponItem "bipod_01_F_blk";
ap1 addWeapon "hgun_Pistol_heavy_01_F";
ap1 addHandgunItem "muzzle_snds_acp";
ap1 addWeapon "Laserdesignator";
ap1 addItemToBackpack "Laserbatteries";

Image of desired loadout.

zen_scr_03.png

Definition of custom loadout for use with Zen_CreateLoadout.

playReqLoadout = [
[["uniform","U_B_Wetsuit"],
["vest","V_RebreatherB"],
["backpack","B_FieldPack_blk"],
["goggles","G_Diving"],
["assignedItems",["ItemMap","ItemCompass","ItemWatch","tf_anprc152_1","ItemGPS","NVGoggles_OPFOR"]],
["weapons",["hlc_rifle_M4","hgun_Pistol_heavy_01_F","Laserdesignator"]],
["magazines",[["hlc_30rnd_556x45_EPR",4],["11Rnd_45ACP_Mag",1],["MiniGrenade",2],["Chemlight_green",2],["Chemlight_blue",2],["hlc_30rnd_556x45_EPR",1],["11Rnd_45ACP_Mag",1],["LaserBatteries",1]]],
["items",["AAFVest01_black","CamoU_Black","G_Balaclava_blk"]],
["primaryAttachments",["hlc_muzzle_556NATO_KAC","acc_pointer_IR","optic_Nightstalker","bipod_01_F_blk"]],
["handgunAttachments",["muzzle_snds_acp"]]]
] call Zen_CreateLoadout;

0 = [ap1, playReqLoadout] call Zen_GiveLoadoutCustom;

The result of Zen_GiveLoadoutCustom:

Backpack

zen_scr_02.png

Wetsuit

zen_scr_01.png

It looks like this may well be default engine behaviour, filling up the first container it comes across, before adding items to the backpack. Is there a way to specify where to place items in a custom loadout? If there is, I do apologise if I missed it. If there isn't, is there a work-around, for this particular exception?

Again, thanks for all your time and efforts, Keep up the good work mate ;)

Share this post


Link to post
Share on other sites
Hi Zeno,

I really like what your doing with this framework and all the hardwork your putting into it. its very much appreciated and is really useful. I have a question/situation that I hope you'd be willing to look at, if you have time.

I'm making a small co-op mission whereby the player squad starts in an sdv, in scuba gear (wetsuit, rebreather, diving googles). They also have a back pack which has kit in it, which they will put on when reaching a secure location on land (Balaclava, vest and uniform).

I used 'Zen_GetUnitLoadout' on a named editor placed unit which I had already geared up (This works really well btw!) and I have managed to call this loadout with Zen_GiveLoadoutCustom. It works, but, some of the items are added to the wetsuit. This means players will need to move items from the wetsuit to the backpack before changing. Also, some of the items are not assigning to the correct locations - Like NVGoggles.

I have a unit in the editor named 'ap1', which I gear him initially with the following:

Initial loadout

RemoveAllWeapons ap1;
RemoveAllItems ap1;
RemoveAllAssignedItems ap1;
RemoveUniform ap1;
RemoveVest ap1;
RemoveBackpack ap1;
RemoveHeadgear ap1;
RemoveGoggles ap1;

ap1 forceAddUniform "U_B_Wetsuit";
ap1 addVest "V_RebreatherB";
ap1 addGoggles "G_Diving";

ap1 addBackpack "B_FieldPack_blk";
clearMagazineCargoGlobal (unitBackpack ap1);
(unitBackpack ap1) additemCargoGlobal ["AAFVest01_black", 1];
(unitBackpack ap1) additemCargoGlobal ["CamoU_Black", 1];
(unitBackpack ap1) additemCargoGlobal ["G_Balaclava_blk", 1];
(unitBackpack ap1) additemCargoGlobal ["hlc_30rnd_556x45_EPR", 5];
(unitBackpack ap1) additemCargoGlobal ["11Rnd_45ACP_Mag", 2];
(unitBackpack ap1) additemCargoGlobal ["MiniGrenade", 2];
(unitBackpack ap1) additemCargoGlobal ["Chemlight_green", 2];
(unitBackpack ap1) additemCargoGlobal ["Chemlight_blue", 2];
ap1 linkitem "itemCompass";
ap1 linkitem "itemGPS";
ap1 linkitem "itemMap";
ap1 linkitem "ItemWatch";
ap1 linkItem "tf_anprc152_3";
ap1 linkitem "NVGoggles_OPFOR";

ap1 addWeapon "hlc_rifle_M4";
ap1 addPrimaryWeaponItem "hlc_muzzle_556NATO_KAC";
ap1 addPrimaryWeaponItem "acc_pointer_IR";
ap1 addPrimaryWeaponItem "optic_Nightstalker";
ap1 addPrimaryWeaponItem "bipod_01_F_blk";
ap1 addWeapon "hgun_Pistol_heavy_01_F";
ap1 addHandgunItem "muzzle_snds_acp";
ap1 addWeapon "Laserdesignator";
ap1 addItemToBackpack "Laserbatteries";

Image of desired loadout.

Definition of custom loadout for use with Zen_CreateLoadout.

playReqLoadout = [
[["uniform","U_B_Wetsuit"],
["vest","V_RebreatherB"],
["backpack","B_FieldPack_blk"],
["goggles","G_Diving"],
["assignedItems",["ItemMap","ItemCompass","ItemWatch","tf_anprc152_1","ItemGPS","NVGoggles_OPFOR"]],
["weapons",["hlc_rifle_M4","hgun_Pistol_heavy_01_F","Laserdesignator"]],
["magazines",[["hlc_30rnd_556x45_EPR",4],["11Rnd_45ACP_Mag",1],["MiniGrenade",2],["Chemlight_green",2],["Chemlight_blue",2],["hlc_30rnd_556x45_EPR",1],["11Rnd_45ACP_Mag",1],["LaserBatteries",1]]],
["items",["AAFVest01_black","CamoU_Black","G_Balaclava_blk"]],
["primaryAttachments",["hlc_muzzle_556NATO_KAC","acc_pointer_IR","optic_Nightstalker","bipod_01_F_blk"]],
["handgunAttachments",["muzzle_snds_acp"]]]
] call Zen_CreateLoadout;

0 = [ap1, playReqLoadout] call Zen_GiveLoadoutCustom;

The result of Zen_GiveLoadoutCustom:

Backpack

Wetsuit

It looks like this may well be default engine behaviour, filling up the first container it comes across, before adding items to the backpack. Is there a way to specify where to place items in a custom loadout? If there is, I do apologise if I missed it. If there isn't, is there a work-around, for this particular exception?

Again, thanks for all your time and efforts, Keep up the good work mate ;)

It doesn't have an option for which container to put things in. That would required subdividing items, magazines, etc. into further into categories, then dealing with units that don't have backpack or vest, etc. It relies on the engine to go in order of uniform, vest, backpack.

However, you can get around this with additive loadouts. Using the 'additive' parameter means Zen_GiveLoadoutCustom will not remove everything before giving the equipment. You can use it to give the backpack and the items in it first (in 'complete' mode), then add the uniform and vest.

playReqLoadoutLand = [[
   ["backpack","B_FieldPack_blk"],
   ["weapons",["hlc_rifle_M4","hgun_Pistol_heavy_01_F","Laserdesignator"]],
   ["assignedItems",["ItemMap","ItemCompass","ItemWatch","tf_anprc152_1","ItemGPS","NVGoggles_OPFOR"]],
   ["magazines",[["hlc_30rnd_556x45_EPR",4],["11Rnd_45ACP_Mag",1],["MiniGrenade",2],["Chemlight_green",2],["Chemlight_blue",2],["hlc_30rnd_556x45_EPR",1],["11Rnd_45ACP_Mag",1],["LaserBatteries",1]]],
   ["items",["AAFVest01_black","CamoU_Black","G_Balaclava_blk"]],
   ["primaryAttachments",["hlc_muzzle_556NATO_KAC","acc_pointer_IR","optic_Nightstalker","bipod_01_F_blk"]],
   ["handgunAttachments",["muzzle_snds_acp"]]
]] call Zen_CreateLoadout;

playReqLoadoutDiver = [[
   ["uniform","U_B_Wetsuit"],
   ["vest","V_RebreatherB"],
   ["goggles","G_Diving"]
]] call Zen_CreateLoadout;

0 = [ap1, playReqLoadoutLand] call Zen_GiveLoadoutCustom;
0 = [ap1, playReqLoadoutDiver, "additive"] call Zen_GiveLoadoutCustom;

That will put everything in the backpack, then add the diving equipment with nothing in it. You could chain together more 'additive' loadouts to add specific items to the vest and uniform (so long as you add in order of backpack, vest, uniform).

Share this post


Link to post
Share on other sites

For Non-AI equipment I reccomend my friends script:

http://forums.bistudio.com/showthread.php?186947-ACC-EqKreator-V1-0-Making-equipment-scripts-was-never-so-easy&highlight=gienkov

You can save gear as You see it in editor :) This is only for players equipment.

Zenophon if You say that this is advertisement and should not be here just ask and I will delete this post asap.

Share this post


Link to post
Share on other sites

Just curious....are you planning on adding support for the Kunduz terrain? At present the [Zen_FindGroundPosition] function fails and I'm guessing it's because the terrain isn't listed in switch statement that determines the world size.

Thanks!

Update: I think it must be more complicated than I realized as I added a "kunduz" entry to the switch statement in the [Zen_FindGroundPosition] script file but I'm still getting errors when attempting to call the script. I'm not sure whether it's because the world size is incorrect (I guessed and used [20480,20480] as the value) or if it's something else. I always seem to get a "No valid position found" error. I'd appreciate it if you could point me in the right direction. I think I'm calling the function correctly but perhaps not. Thanks!

Edited by zonker3210

Share this post


Link to post
Share on other sites
For Non-AI equipment I reccomend my friends script:

http://forums.bistudio.com/showthread.php?186947-ACC-EqKreator-V1-0-Making-equipment-scripts-was-never-so-easy&highlight=gienkov

You can save gear as You see it in editor :) This is only for players equipment.

Zenophon if You say that this is advertisement and should not be here just ask and I will delete this post asap.

It's all good, we're both just trying to help folks make missions.

Just curious....are you planning on adding support for the Kunduz terrain? At present the [Zen_FindGroundPosition] function fails and I'm guessing it's because the terrain isn't listed in switch statement that determines the world size.

Thanks!

Update: I think it must be more complicated than I realized as I added a "kunduz" entry to the switch statement in the [Zen_FindGroundPosition] script file but I'm still getting errors when attempting to call the script. I'm not sure whether it's because the world size is incorrect (I guessed and used [20480,20480] as the value) or if it's something else. I always seem to get a "No valid position found" error. I'd appreciate it if you could point me in the right direction. I think I'm calling the function correctly but perhaps not. Thanks!

The world size preset is only used if you don't give an area to calculate the position within (or enter 0 for that argument). No valid position means one or more of the filters (arguments 3 to 12) cannot be satisfied. To check that the function works, just put down an area marker (I'm calling it 'mkTestArea') and give only that as an argument:

// in the init.sqf
_pos = ["mkTestArea"] call Zen_FindGroundPosition;
player sideChat str _pos;

Can you post the full call to Zen_FindGroundPosition? Unfortantely, it's quite possible to make a logical error with the argument that can never return a valid position. It's not possible for a function to always ensure its arguments make sense.

Share this post


Link to post
Share on other sites

Thanks for the quick reply, Zenophon!

Good news...your script works just fine. The bad news...I need to rethink how I was doing things. For example, this works...

_pos = ["mkTestArea", 250] call Zen_FindGroundPosition;
player sideChat str _pos;  

However, I have an array of markers and want to use your script to find a ground position near one of the markers. And that's where I'm getting the error...

_targets = [
 "mkTestArea"
];
_selectedMarker = _targets call BIS_fnc_selectRandom;
hint format ["_selectedMarker (%1): %2, %3, %4", _selectedMarker, (getMarkerPos _selectedMarker select 0), (getMarkerPos _selectedMarker select 1), (getMarkerPos _selectedMarker select 2)];
_pos = [_selectedMarker, 250] call Zen_FindGroundPosition;
player sideChat str _pos;

I think that this is easily fixed by creating another marker and just moving it to same location as the marker randomly selected from the array. I should then be able to call [Zen_FindGroundPosition] using that hardcoded marker name. I thought the function allowed the first argument to be either a marker name or a position...I think I misunderstood that, though.

Anyhow, thanks for the help...and thanks for this wonderful script framework!

Share this post


Link to post
Share on other sites

You could have an array of markers

_array = ["marker1","marker2","marker3"];

and then using ZFGP to get a position within one of those markers, using the array as a whitelist, like this

_pos = [0,0,[[],[],_array]] call Zen_FindGroundPosition;

Used in this manner, parameter 1 of "0" means to use the entire map to get a position in. Parameter 2 of "0" means there is no minimum distance from center to check/look for. And parameter 3 is an array of 3 parameters, of which you would use the 3rd parameter.

That being said, it might be easier to just get a random marker from your marker array, and when you give that marker as the center point to search for (parameter 1) you then get the size of the marker (ie. its 200x200) and if you want the returned position just outside that marker, you could use parameter 2, like this

_size = getMarkerSize "marker1";
_pos = ["marker1",[(_size select 0) + 25,(_size select 0) + 125]] call Zen_FindGroundPosition;

Of course you would need to develop an algorithm that correctly handles odd sized rectangular markers (ie 150x375).

Edited by m0nkey

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 will 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

In case you didn't know, today is the framework's 1 year release anniversary (it also happens to be Nikola Tesla's birthday). As an updated accounting, there have been 561 total changes since public release, which have brought us to 184 public functions and 87 preprocessor macros; all of this is done by about 14300 lines of code (including blank lines). It's been a lot of fun working on the framework, and I'm confident the future holds more interesting things for it.

Unfortantely, I do not have any massive, awe-inspiring new features to deliver in this release, but I can offer several new function and improvements. The largest change is actually internal; the fire support actions system has been rewritten with server and client data (in the style of the task system). The functions themselves have changed very little (just Zen_UpdateFireSupportAction has some new parameters), but now fire support actions are handled very differently.

The actions are assigned a random string identifier (like tasks, custom loadouts, etc.) that will be used to refer to them. This string ID is different that a fire support template ID; mixing them up will result in errors. You can update and remove the data of this action more easily now. For example, it's now possible to change the fire support template that is called by the action. All of this greatly helps with JIP, the demonstration of which has been properly updated.

Amidst various reports of issues with Zen_MoveInVehicle (which I still cannot reproduce), the function has been completely rewritten. The function now assigns seats to the units before attempt to put them in and is more patient if it takes longer for high ping clients to respond. The new Zen_MoveInVehicle also used the code in Zen_GetFreeSeats, so I made that a new public function.

Thanks to a user request, the new function Zen_GetCurrentTask will return the task that any object has selected. This lets your mission respond based upon which task players have selected as current. Zen_ArrayGetRandom can now remove the element it selected; this is similar to Zen_ArrayGetRandomSequence's remove parameter, but it is more efficient for just one element. Zen_FindValidDirection had a slight error in its math, which could allow a few angles that crossed the avoided area.

7/10/15

  1. New Function: Zen_GetCurrentTask
  2. New Function: Zen_GetFireSupportActionData
  3. New Function: Zen_GetFreeSeats
  4. Added: Zen_ArrayGetRandom parameter to remove the chosen element from the array
  5. Added: Zen_UpdateFireSupportAction parameters for various data
  6. Removed: Zen_AddFireSupportAction parameter to remote execute
  7. Removed: Zen_RemoveFireSupportAction parameter to remote execute
  8. Improved: Zen_FindValidDirection is more accurate at shorter distances
  9. Improved: Zen_GetFireSupportData returns the full data of the template
  10. Improved: Zen_MoveInVehicle optimized
  11. Documentation: Fixed for ZEN_FMW_MP_REClient
  12. Documentation: Added for Zen_GetCurrentTask, Zen_GetFireSupportActionData, Zen_GetFreeSeats
  13. Documentation: Updated for Zen_AddFireSupportAction, Zen_ArrayGetRandom, Zen_GetFireSupportData, Zen_RemoveFireSupportAction, Zen_UpdateFireSupportAction
  14. Documentation: Updated JIP demonstration for the new fire support action features

Feedback

Thanks for the quick reply, Zenophon!

Good news...your script works just fine. The bad news...I need to rethink how I was doing things. For example, this works...

_pos = ["mkTestArea", 250] call Zen_FindGroundPosition;
player sideChat str _pos;  

However, I have an array of markers and want to use your script to find a ground position near one of the markers. And that's where I'm getting the error...

_targets = [
 "mkTestArea"
];
_selectedMarker = _targets call BIS_fnc_selectRandom;
hint format ["_selectedMarker (%1): %2, %3, %4", _selectedMarker, (getMarkerPos _selectedMarker select 0), (getMarkerPos _selectedMarker select 1), (getMarkerPos _selectedMarker select 2)];
_pos = [_selectedMarker, 250] call Zen_FindGroundPosition;
player sideChat str _pos;

I think that this is easily fixed by creating another marker and just moving it to same location as the marker randomly selected from the array. I should then be able to call [Zen_FindGroundPosition] using that hardcoded marker name. I thought the function allowed the first argument to be either a marker name or a position...I think I misunderstood that, though.

Anyhow, thanks for the help...and thanks for this wonderful script framework!

As m0nkey said, the number after the marker name means the minimum distance from the center of the marker (in your code points must be more than 250 meters away). If the marker is smaller than 250 meters, there are no possible points. An area marker is interpreted as its true geometric shape, while a point or object requires a distance because it's not already an area.

If you have e.g. 10 markers (named sequentially like "mkArea0", "mkArea1", etc.) and you want to do something in e.g. 6 of them, you can get those 6 at random and them iterate over them:

_markers = [];
for "_i" from 0 to 9 do {
   _markers pushBack ("mkArea" + str _i);
};

_selectedMarkers = [_markers, 6] call Zen_ArrayGetRandomSequence;
{
   _pos = [_x] call Zen_FindGroundPosition;
   // etc...
} forEach _selectedMarkers;

Share this post


Link to post
Share on other sites

I am putting this in player unit (p1) init field it doesnt work, i tried putting it in init.sqf it doesnt work, same for trigger also:

 

0 = ["p1",1600,10] call Zen_SpawnAmbientVehicles; // Trying to spawn 10 vehicles in agia marina. nothing spawns even 600 kms from town

0 = ["m1",east,.8,3] call Zen_SpawnInfantry; // should have spawned 3 units on marker m1, doesnt spawn.

 

And yes I am putting both the Zen_SpawnAmbientVehicles.sqf and  Zen_SpawnInfantry.sqf files in the mission folder. what gives?

 

 

Please help

Share this post


Link to post
Share on other sites

Update and Release #31

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 will 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 release brings several minor fixes and any improvements I've thought of in the past few weeks. The main addition is a new function, Zen_GetUnitFireSupportActions, which provides better management capability for the fire support actions. It functions just like Zen_GetUnitTasks. Hopefully, all of the locality issues in the fire support action system have solved with this final fix to Zen_AddFireSupportAction (and is private helper functions).

Zen_AddFireSupportAction also has a cancel action feature implemented. This action appears automatically whenever a fire support is used. Cancelling a fire support does not return a usage, so cancelling your only use of a support will waste it. The cancel button exists as an emergency abort to prevent friendly fire, not because the fire support will miss and you want a do-over.

Zen_OrderVehicleMove had some confusion about who is unitReady when a move is complete. Some vehicles may have only the driver, the commander, or both changing their ready status. This also affects Zen_IsReady, but that function is unchanged. If this fix works for all vehicles, there's no need to spend time figuring out the details of which vehicle behaves which way.

Zen_StringGetDelimitedPart is now significantly more robust, as the delimiters can now be any arbitrary string. Otherwise it functions as before; Zen_StringGetDelimitedPart is the subject of the function spotlight this release, so look there for examples and more information.

In order to improve wounding realism, I thought of a simple addition to Zen_MultiplyDamage. It now increases the unit's fatigue based upon the damage received. I think the decrease in movement speed and aiming ability provides a much better simulation of the injury/adrenaline/shock/fear of being shot. The amount of fatigue added can be tweaked, so feel free to give feedback (as always).

Finally, Zen_FindGroundPosition now uses the worldSize command as a backup if the world is not found in the preset list. This should allow compatibility with any addon map. Note, the entire map is only used when an area marker or point and distance are not given in the arguments.

8/5/15

  • New Function: Zen_GetUnitFireSupportActions
  • Fixed: Zen_AddFireSupportAction uses the server to execute the support if there is no guiding object
  • Fixed: Zen_OrderVehicleMove did not detect if some vehicles had completed their order and stop executing
  • Improved: Zen_AddFireSupportAction now offers a cancel action to stop a called fire support
  • Improved: Zen_FindGroundPosition uses worldSize
  • Improved: Zen_MultiplyDamage now adds fatigue based upon damage
  • Improved: Zen_StringGetDelimitedPart can search for delimiters of any length
  • Documentation: Fixed Zen_SpawnInfantry and Zen_SpawnInfantryGarrison Notepad++ function hint arguments
  • Documentation: Fixed Zen_JIP demonstration did not check if a fire support had been used
  • Documentation: Fixed for Zen_GetFireSupportData
  • Documentation: Added for Zen_GetUnitFireSupportActions
  • Documentation: Updated for Zen_MultiplyDamage, Zen_StringGetDelimitedPart
  • Documentation: Updated Notepad++ SQF language and autocompletion file with ArmA 1.48 stable commands

Roadmap

I said a while ago that a new, large feature additions to the framework are a possibility. The feature I can now announce is a framework system for dialogs. I'm aware that there are many tutorials and templates for dialogs out there, and a lot of mission makers have their own dialogs they're familiar with.

However, I intend to offer a completely new style of creating and managing dialogs that doesn't require creating/editing description.ext classes or any of the research/knowledge required to do that. Instead, the dialog system will mimic a real programming language's GUI library.

It will offer dynamic creation of dialogs using framework functions, object-oriented management of dialogs, and event-driven UI actions. The goal is that almost any UI design can be implemented quickly and intuitively using the functions and documentation I provide. Then, the function of the buttons, content of lists, etc. will be events that the mission maker writes function for.

I intend for every mission maker to be able to design, create, and display as many dialogs as they want to enhance the usability and presentation of their mission, all using just this new addition to the framework's API.

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_StringGetDelimitedPart. This function achieves the same effect as it has always done; however, it now can use any string as a delimiter. First, a simple example of how the new arguments work:

player sidechat str (["(1)", "(", ")"] call Zen_StringGetDelimitedPart);
These these examples are formatted as print statements so you can try them out. That example was possible with the old version of Zen_StringGetDelimitedPart; I've just split the delimiters into two different arguments. Next, an example of the new feature:

player sidechat str (["ab12345cd6789", "ab", "cd"] call Zen_StringGetDelimitedPart);
The delimiters and string or just arbitrary test values for now. One more test example:

player sidechat str (["ab12345", "ab", "cd"] call Zen_StringGetDelimitedPart);
If the end delimiter is not found, everything past the start delimiter will be returned. Now for a discussion of why this is useful.

When you want to store a lot of information, the go-to data structure is an array. You've got the basic stacks, queues, etc., but for recording many things per item, you would use a multidimensional array. Zen_StringGetDelimitedPart is now able to mimic getting data from a many elements in a nested array using a single string.

The strength of Zen_StringGetDelimitedPart is that order no longer matters, a missing property is easier to handle, and you don't have to remember what is at what index. Compare:

_multiDimArray = [["A", 27, 200]];
// We access a nested array using a key
_nestedArray = [_multiDimArray, "A", 0] call Zen_ArrayGetNestedValue;

// The actual value of the data is irrelevant
_value = _nestedArray select 2;
For this to work, you must ensure that (_nestedArray select 2) isn't out of bounds, contains the data we think it does, and doesn't have some default value we can't use. I just did that for _multiDimArray, but that's not an option for a lot of data being managed dynamically.

Then using the string method:

_stringDict = [["A", "Time: 27, Points: 200"]];
// Same look-up
_nestedArray = [_stringDict, "A", 0] call Zen_ArrayGetNestedValue;

// Now it's obvious what we are retrieving
_value = [(_nestedArray select 1), "Points: ", ","] call Zen_StringGetDelimitedPart;
If the "Points: " block is missing, we simply get an empty string. This is the 'soft' method of encoding data; it's not necessary to declare every block for every data string. It also allows more readable code. For example:

// Now this array has many elements
_nestedArray = [_stringDict, _key, 0] call Zen_ArrayGetNestedValue;

_text = [(_nestedArray select 1), "Display Name: ", ","] call Zen_StringGetDelimitedPart;
if (_text == "") then {
    _text = [(_nestedArray select 1), "Classname: ", ","] call Zen_StringGetDelimitedPart;
    if (_text != "") then {
        _text = getText (configFile >> "cfgVehicles" >> _text >> "TextSingular")
    };
};
This allows the data string to supply a display name in any number of ways without having to make each one an element in the nested array. The only downside to this system is that changing a value takes longer:

_nestedArray = [_stringDict, _key, 0] call Zen_ArrayGetNestedValue;

// if we want to add a block
_nestedArray set [1, (_nestedArray select 1) + "Display Name: Test,"];

// but if we want to change an existing block
_stringData = _nestedArray select 1;
_text = [_stringData, "Display Name: ", ","] call Zen_StringGetDelimitedPart;

_oldBlock = "Display Name: " + _text + ",";
_newBlock = "Display Name: Fun,";

_stringData = [_stringData, _oldBlock, _newBlock, true] call Zen_StringFindReplace;
_nestedArray set [1, _stringData];
You also need to be careful not to add duplicate blocks, as only the first will be read. Note that Zen_StringGetDelimitedPart is case sensitive, so Zen_StringFindReplace must be as well.

Finally, I'm not saying the string data method is much better than array. I'm just presenting the pros and cons of each based upon my experience. Sorry if this dragged on too long.

Feedback

 

I am putting this in player unit (p1) init field it doesnt work, i tried putting it in init.sqf it doesnt work, same for trigger also:

0 = ["p1",1600,10] call Zen_SpawnAmbientVehicles; // Trying to spawn 10 vehicles in agia marina. nothing spawns even 600 kms from town

0 = ["m1",east,.8,3] call Zen_SpawnInfantry; // should have spawned 3 units on marker m1, doesnt spawn.

And yes I am putting both the Zen_SpawnAmbientVehicles.sqf and Zen_SpawnInfantry.sqf files in the mission folder. what gives?

Please help

Did you follow these steps from the step-wise installation?

4: From the sample mission, Shell.Stratis, copy Zen_FrameworkFunctions, Init.sqf, Description.ext, and StringTable.xml into your mission directory

If you already have a mission with an Init.sqf, Description.ext, or StringTable.xml:

Open each file in Shell.Stratis and copy ALL of the code to the TOP of your corresponding file

5. Do not place the Zen_FrameworkDocumentation folder in your mission folder.

Does your init.sqf look anything like this:

#include "Zen_FrameworkFunctions\Zen_InitHeader.sqf"

// <Your mission name here> by <your name here>
// Version = <the date here>
// Tested with ArmA 3 <version number>

// This will fade in from black, to hide jarring actions at mission start, this is optional and you can change the value
titleText ["Good Luck", "BLACK FADED", 0.2];
// 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;

0 = [p1, 1600, 10] call Zen_SpawnAmbientVehicles;
0 = [m1, east, 0.8, 3] call Zen_SpawnInfantry;

Framework functions don't work from editor init fields or in trigger conditions. They can work in trigger activations though. Also, object names aren't written in strings, just p1, m1, etc. I highly recommend that you start with the first tutorial to see some usage examples.

Share this post


Link to post
Share on other sites

Thank you for the reply Zeno. I am a basic 'beginner' in scripting you can say. Not 100% noob. I make and play SP missions alone, hence honestly I do not decorate my init.sqf with titles as the above example.  Like I usually do with mods, I just copy pasted your call script lines along with relevant sqf files in mission folder. My init.sqf is bland as:

0 = [p1, 1600, 10] call Zen_SpawnAmbientVehicles;
0 = [m1, east, 0.8, 3] call Zen_SpawnInfantry;

I believe the scripts with text "0 =...." or "null = " dont come in init.sqf but rather in unit init or trigger. But like I said, I tried putting these there also. Anyway I will try your approach tonight.

 

In layman's terms, can you please explain to me where the script lines with "..call so-and-so" and "....execVM so-and-so.sqf" are put? Ive seen execVM's are usually in init.sqf. But call function? and I also observed that in your "call" lines you have not put ".sqf" in the end. Is it a usual practice to leave ".sqf" word in "call" lines?

 

Thnks man  :D

 

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

×