Jump to content
Zenophon

Zenophon's ArmA 3 Co-op Mission Making Framework

Recommended Posts

for anyone working with LOP units, this is what I found works for spawning those units;

_resGarrison = [_housePos, _side, _AISkill,5,"LOP_Men","LOP_AFR",[],"LOP_LeightsOPFOR"] call Zen_SpawnInfantryGarrison;

Share this post


Link to post
Share on other sites

Hey Zen, I tried adding fastroping to the MELB little bird

 

http://www.armaholic.com/page.php?id=28856&highlight=MELB

 

classname MELB_MH6M

 

Added it in the init.sqf using:

 

0 = [[LB_1,LB_2,LB_3]] call Zen_AddFastRope;

 

My three littlebirds were all ID'd as in the above array argument.   Tried testing this out with a friend but no scroll wheel option at any height while hovering.  

 

So what did I break   :blink:

Share this post


Link to post
Share on other sites

1. Okay I understand vehicle classes, and now I understand that ammo was the class for boxes. But my main issue still remains. How do I make it so it calls FIA boxes? I found this line in ConfigGetVehicleClasses:

if (["ammo", _classType] call Zen_ValueIsInArray) then {
    _returnClasses = [_returnClasses, ["box_ind_ammoveh_f", "box_east_ammoveh_f", "box_nato_ammoveh_f"]] call Zen_ArrayFilterValues;
};
I don't want a randomly selected box out of a large side dependent array, I want to choose 1 or maybe 2 or 3 boxes of my own and I want them to be the only ones spawning. They are FIA boxes.

2. The main issue is that I am doing this on Fallujah. Somebody on Steam released a version of Fallujah that works on Arma 3 on Feb 27th this year. Most of the buildings are not enterable or partially enterable. I have noticed that most of the time FindBuildingPositions works with partially enterable buildings. Is there ANY way to exclude certain buildings from the list? A blacklist of sort? I have also noticed that only ground positions are being chosen, no first floor or roof positions. I feel like I'm doing something wrong.

3. I will try it out ASAP.

Zen_ConfigGetVehicleClasses is a search tool for finding everything in a category. If you have just a few ammo boxes you want to use, you can just name them:

// you can use the editor preview objects and copy/paste the classname
_boxClasses = ["classname_1", ...];

// then if you want one
_class = [_boxClasses] call Zen_ArrayGetRandom;

// or if you want several at random
_classArray = [_boxClasses, 2] call Zen_ArrayGetRandomSequence;

// or all of them at random
_boxClassesRand = [_boxClasses] call Zen_ArrayShuffle;

Zen_FindBuildingPositions is using whatever building is nearest the point given, so you can just give it the building itself as the first argument. To build the blacklist, you would have to examine each building in-game and add its classname (CUP makes a lot of them placeable in the editor). Once you have that, you can search for a building:

_blacklist = ["classname", ...];

// place 5 boxes
for "_i" from 1 to 5 do {
    // choose buildings within an area marker, "mkCity"
    _pos = ["mkCity"] call Zen_FindGroundPosition;
    _building = nearestBuilding _pos;
    while {(typeOf _building) in _blacklist} do {
        _pos = ["mkCity"] call Zen_FindGroundPosition;
        _building = nearestBuilding _pos;
    };

    // get positions and spawn the box
    _buildingPos = [_building] call Zen_FindBuildingPositions;
    _box = [...] call Zen_SpawnVehicle;
    _box setPosATL ([_buildingPos] call Zen_ArrayGetRandom);
};

For a whitelist, just switch the while loop condition to !((typeOf _building) in _whitelist).

 

Hey Zen, I tried adding fastroping to the MELB little bird

http://www.armaholic.com/page.php?id=28856&highlight=MELB

classname MELB_MH6M

Added it in the init.sqf using:

0 = [[LB_1,LB_2,LB_3]] call Zen_AddFastRope;

My three littlebirds were all ID'd as in the above array argument. Tried testing this out with a friend but no scroll wheel option at any height while hovering.

So what did I break :blink:

The type of vehicle shouldn't affect the function; the action appears in my testing for SP and MP. Try it in SP, if there's an action there, it's likely a MP issue. In MP, do either of you get the action? If either of you were JIP that would cause an issue if unhandled.

Share this post


Link to post
Share on other sites

Does the fast roping require units in cargo slots? Asking because the spots on the MELB are FFV locations.

That's a good point, as I did the fastroping stuff before there was FFV. The condition on the action is:

(_this in _target) && (_this != driver _target) && (speed _target < 10) && (((getPosATL _target) select 2) > 5)
which is why I suggest there is some MP issue and the action hasn't been added. That condition should work for in a turret or in cargo in any helicopter. When calling Zen_OrderFastRope directly, units in FFV positions should be forced out just the same as if they were in cargo seats. This applies to Zen_OrderInsertion with fastroping as well.

The only issue is when the player is leading an AI group and uses the Zen_AddFastRope action; in that case, only AI group members that are 'assignedCargo' will be fastroped with the player. There is no 'assignedTurret' command, so to fix this I'll likely use 'turretUnit' on all the vehicle's turret paths and filter for AI that belong to that player.

Share this post


Link to post
Share on other sites

Excellent set of functions Zenophon. 

 

Not sure if it's intended or not, but the behavior of objects dropped from aircraft by Zen_OrderVehicleDrop seems to vary depending on whether the _drop object exists, or if it is a classname than it spawned.

 

    if (typeName _className == "STRING") then {
        _drop = [_vehicle, _className, (ZEN_STD_OBJ_ATLPositionZ(_vehicle) - 10)] call Zen_SpawnVehicle;
    } else {
        _drop = _className;
        0 = [_drop, _vehicle, -10, ZEN_STD_Math_VectCartCyl((velocity _vehicle)), (random 360)] call Zen_TransformObject;
    };

So what I'm seeing if the new spawned object just appear and drop straight down, the transformed objects fly forwards under the aircraft?

 

Share this post


Link to post
Share on other sites

Excellent set of functions Zenophon.

Not sure if it's intended or not, but the behavior of objects dropped from aircraft by Zen_OrderVehicleDrop seems to vary depending on whether the _drop object exists, or if it is a classname than it spawned.

 

    if (typeName _className == "STRING") then {
        _drop = [_vehicle, _className, (ZEN_STD_OBJ_ATLPositionZ(_vehicle) - 10)] call Zen_SpawnVehicle;
    } else {
        _drop = _className;
        0 = [_drop, _vehicle, -10, ZEN_STD_Math_VectCartCyl((velocity _vehicle)), (random 360)] call Zen_TransformObject;
    };
So what I'm seeing if the new spawned object just appear and drop straight down, the transformed objects fly forwards under the aircraft?

Sorry for the belated reply... . You're right, it should be:

    if (typeName _className == "STRING") then {
        _drop = [_vehicle, _className, (ZEN_STD_OBJ_ATLPositionZ(_vehicle) - 10)] call Zen_SpawnVehicle;
    } else {
        _drop = _className;
    };

    0 = [_drop, _vehicle, -10, ZEN_STD_Math_VectCartCyl((velocity _vehicle)), (random 360)] call Zen_TransformObject;

Also, for next release, I'll make Zen_SpawnParachute have the parachute inherit some of the velocity of the object, so things like the ammo drop will look more realistic.

Share this post


Link to post
Share on other sites

 

Also, for next release, I'll make Zen_SpawnParachute have the parachute inherit some of the velocity of the object, so things like the ammo drop will look more realistic.

 

 

Sounds very good. And thanks for the clarification.

Share this post


Link to post
Share on other sites

As biggdogg says, the fifth parameter must also match the classes you want. Here's an example specifically for RHS:

_group = [_pos, west, "SOF", 4, "rhs_vehclass_infantry_ocp", "rhs_faction_usarmy_d"] call Zen_SpawnInfantry;
Hi all,
 
im still having real trouble using Zen_SpawnInfantry with RHS units. I tried the example code above, but it throws the error "No soldiers found for the given side, type, faction, and blacklist"
 
Digging around in the config viewer confirms that the values in the example above are valid but don't seem to work for me. The mod is installed and working correctly because a workaround is to use Zen_CreateLoadout and build loadouts manually using RHS bits and bobs. While this works it brings its own challenges and Zen_SpawnIfantry would be the ideal solution.
 
Here are what appear to be the key values in the config viewer of, as an example, the rhsusf_usarmy_autorifleman unit in the RHS mod.
faction = "rhs_faction_usarmy_d";
side = 1;
type = 0;
vehicleClass = "rhs_vehclass_infantry_ocp";
 
Has anyone had any success using Zen_SpawnInfantry with RHS units? Any additional working examples would be greatly appreciated.

Share this post


Link to post
Share on other sites

Hi all,

im still having real trouble using Zen_SpawnInfantry with RHS units. I tried the example code above, but it throws the error "No soldiers found for the given side, type, faction, and blacklist"

Digging around in the config viewer confirms that the values in the example above are valid but don't seem to work for me. The mod is installed and working correctly because a workaround is to use Zen_CreateLoadout and build loadouts manually using RHS bits and bobs. While this works it brings its own challenges and Zen_SpawnIfantry would be the ideal solution.

Here are what appear to be the key values in the config viewer of, as an example, the rhsusf_usarmy_autorifleman unit in the RHS mod.

 

faction = "rhs_faction_usarmy_d";
side = 1;
type = 0;
vehicleClass = "rhs_vehclass_infantry_ocp";
Has anyone had any success using Zen_SpawnInfantry with RHS units? Any additional working examples would be greatly appreciated.

I didn't realize how old that example spawning code is; it's almost 9 months out of date. The faction and class have probably changed, and RHS is using the DLC property as well. The DLC parameter is mentioned only once or twice in the documentation, but it is necessary for finding classes that specify it.

Here are two lines that spawn RHS units (I tested them this time):

_group = [player, resistance, "infantry", 2, "Men", "rhs_faction_insurgents", [], "RHS_AFRF"] call Zen_SpawnInfantry;
_group = [player, west, "infantry", 2, "rhs_vehclass_infantry_ocp", "rhs_faction_usarmy_d", [], "RHS_USAF"] call Zen_SpawnInfantry;

Share this post


Link to post
Share on other sites

Hi Zenophon. Thank you very much for taking the time to provide some examples. They work great! I also better understand how the config properties relate to the elements in the call.

 

I did see the reference to the DLC property in your documentation and while I did try it, I obviously still had an error in there somewhere as I couldnt get it to play ball.

 

Thanks again for all your hard work. Your framework has become an absolute must have!

Share this post


Link to post
Share on other sites

Update and Release #43

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

Here we have the definitive release for version 1.58 stable. It includes some fixes and requested additions. I've improved the reliability of positions returned by Zen_FindBuildingPositions, as well as let Zen_AreIndoors and Zen_AreNotIndoors use the same precision. There are still more tweaks to be done.

I'm not sure what exactly to do for the task changes BIS has just released. They are really only cosmetic and don't affect the operation of the task system, but I would like to give users access to the new possibilities. It doesn't seem like BIS is finished with the changes, so I'll give them some time as well as figure out how to best present their new features as arguments to the framework's task system.

4/28/16

  • Fixed: Zen_AddFastRope failed to fastrope the player in some cases in MP
  • Fixed: Zen_FindCenterPosition caused an error when the first argument was not an array
  • Fixed: Zen_OrderFastRope makes AI in the player's group fastrope from FFV positions
  • Fixed: Zen_OrderVehicleDrop makes a teleported object inherit the aircraft's velocity
  • Added: Zen_AreIndoors and Zen_AreNotIndoors optional argument to use a more complex check
  • Improved: Zen_FindBuildingPositions gives points a buffer distance from walls and ledges
  • Improved: Zen_FindBuildingPositions does not return positions on the wrong side of a wall (i.e. outside the building)
  • Improved: Zen_SpawnParachute makes the parachute move with a fraction of the object's previous velocity
  • Documentation: Fixed paramsArray did not autocomplete
  • Documentation: Updated for Zen_AreIndoors and Zen_AreNotIndoors
  • Documentation: Updated Notepad++ SQF language and autocompletion file with ArmA 1.58 stable commands

Share this post


Link to post
Share on other sites

Many thanks for this update. I want to dig more into using these for my small Arma-group. Did anybody experience any issues while using ACE? Do I have to adjust anything in the missions (e.g. for using the ACE medical system)?

Share this post


Link to post
Share on other sites

Holy hell, why have I not used more of these framework features sooner? :D I already use your random position and building position functions all the time. Thank you!

 

I spent the better part of two evenings futzing around with vanilla waypoint script commands for setting WP attributes, for a helo reaction force. Couldn't figure out how to make the helo pause, set WP position, or skip the correct waypoints. There are multiple patrols, each of which can spot BLUFOR across Stratis. I could trigger the helo, but not dynamically set its destination. Also, there was a 67% probability it would refuse to land as part of its completed WP on its destination helipad.

 

10 minutes with your Orders functions, and done -- most of which time was spent observing the helo in 4x Zeus mode to make sure it was doing its thing correctly. It did so, twice in a row successfully.

 

Zenophon, I know my mini-scripts below are crude like a fistful of crayons, but I haven't found any basic cache-type functions in your framework. I can use ALiVE mod for a full framework with units simulated outside a certain distance while remaining cached. But for smaller, more tightly written missions, I think a set of basic unit cache functions could help mission designers to add in reasonably large numbers of units (a couple platoons' worth) while keeping processor overhead very low and fast in any given 5-10 minute phase or encounter of an overall 1-3 hour mission playtime.

 

Your spawn functions are perfect for when I don't care about where the units come from, or whether their casualties, damage, or ammo expenditures matter. My cache functions currently are embarrassingly bad, and require manual naming of each group leader unit b/c I haven't been able to successfully script dynamic references to units with _this select 0 or whatever in nested script commands, execVM, Spawn commands, or otherwise. Most existing unit spawn/cache scripts don't work, don't work in a boneheaded simple and robust way, or require using their own script-specific format for parameters, which often makes it difficult for my skill level to script in your functions for units spawned elsewhere (again, due to my lack of skill/understanding of the nested _this select 0 references). I hope this provides some ideas for further framework expansion, but no big deal if it doesn't suit your needs or interests. I am still perfectly happy to use your current framework for everything it already offers!

 

TL;DR: basic unit/group caching. Freezes, hides, disables, immobilizes, and otherwise pauses all processing of a unit. Condition parameters could be anything in a trigger condition field, but defaults to a range from nearest player (suitable for MP and JIP?).

 

My concept that spurred all this (nothing fancy or original):

Armed Mi-8 starts on helipad at airbase.

 

Repeatable trigger covering all of Stratis is set to BLUFOR present, detected by OPFOR.

 

All non-repeatable triggers get a final On Act: deleteVehicle thisTrigger. Don't know if it makes a big difference, but I saw something from Killzone Kid that said the game continues to evaluate all trigger conditions even after completion.

 

On activation:

 

Mi8_target = thisList select 0; // This global variable sets the detected offending BLUFOR unit as target
Mi8_patrol = [Mi8, Mi8_target, 200] spawn Zen_OrderAircraftPatrol; //This global handle spawns a script commanding the helo to patrol a random point near the detected BLUFOR unit

 

On deactivation (i.e. BLUFOR no longer detected):

 

terminate Mi8_patrol; // stops the patrol immediately as soon as the script comes up in the game task scheduler -- IMMEDIATELY. 
Mi8_land = [Mi8, helipad] Zen_OrderHelicopterLand; // sends helo home to the object-named helipad. From Zenophon's .txt description, probably in careless mode. It's going HOME, no scenic detours or 15 minutes spent pointlessly orbiting, dancing, and engaging enemy targets or avoiding scary phantoms on the helipad.

 

I use my home-brewed super-ghetto "cache" script to disable AI units and turn off their load on the processor. All units are placed in editor normally, with waypoints, behaviours, loadouts, etc. as desired. I usually init most groups with this in the group leader unit's init field:

0=[this] execVM "disableAI.sqf";

This also has the obvious side benefit of preventing the unit from accidentally wandering off halfway across the map when it's not actively tasked.

 

Then I set a trigger (no owner or sync used, currently) with any dimensions, conditions, etc. desired, and On Act (same trigger as the Mi8_patrol above, in my example):

0=[Name] execVM "enableAI.sqf"; // group leader unit is named Name

I can make the unit repeatedly un/cache by setting trigger to repeatable, and On Deactivation:

0=[Name] execVM "disableAI.sqf";

The two .SQFs I use:

//disableAI.sqf
{
    _x enableSimulation false;
    _x disableAI "TARGET";
    _x disableAI "AUTOTARGET";
    _x disableAI "MOVE";
    _x disableAI "FSM";
    _x disableAI "SUPPRESSION";
    _x disableAI "COVER";
    _x disableAI "AUTOCOMBAT";
    _x hideObjectGlobal true;
} forEach units group (_this select 0);

//enableAI.sqf
{
    _x enableSimulation true;
    _x enableAI "TARGET";
    _x enableAI "AUTOTARGET";
    _x enableAI "MOVE";
    _x enableAI "FSM";
    _x enableAI "SUPPRESSION";
    _x enableAI "COVER";
    _x enableAI "AUTOCOMBAT";
    _x hideObjectGlobal false;
} forEach units group (_this select 0);

 

The scripts currently do not hide or unsimulate the vehicle, though that would be easy enough with the additional use of an if condition to check for a vehicle, the Vehicle command, enableSimulation, and hideObjectGlobal. I don't hide the vehicle b/c I often have set-ups where the players may be able to use stealth to destroy the vehicle and thereby prevent further patrols or responses from that cached unit.

 

For the helo patrol scenario above, I put the disableAI.sqf trigger on the helipad (radius 20, Z height 4) and included:

Mi8 setFuel 1;

Optionally I have also used setDamage 0 and setAmmo 1 to fully replenish and repair the unit. So I use a total of 2 repeatable triggers to send my QRF force out until it gets disabled/destroyed.

 

Units garrisoning a building get an additional init:

{_x forceSpeed 0} forEach units group Name; // place in init field of group's leader unit named Name

to permit them pivoting in place to fire weapons, but not to move out of position (whereas disableAI "MOVE" would lock them into their initial orientation, if I understand correctly). If movement is eventually desired, I set a separate trigger to forceSpeed -1 (usually with conditions like BLUFOR within distance 50, to permit the OPFOR unit to maneuver for CQB once the enemy is too close to remain stationary).

 

 

Many thanks for this update. I want to dig more into using these for my small Arma-group. Did anybody experience any issues while using ACE? Do I have to adjust anything in the missions (e.g. for using the ACE medical system)?

 

I use ACE as a default in all my missions. For medical, other than the fact that AI doesn't register and can't use ACE medical, no problems with players using it. Zenophon's framework doesn't interact with ACE interactions (unless theoretically someone scripts actions that use Z's framework while hooking into ACE interactions?), so I'm not sure how there could be any issues at a basic user/mission-maker level.

Share this post


Link to post
Share on other sites

AI caching is certainty something I've considered adding. Existing caching scripts that are generalized should work regardless of how units are spawned, but I can understand that they present features in a way that isn't always easy to fit into your existing mission structure. I want the framework to support larger-scale co-op missions just as well as small ones, and AI caching is certainly useful there. Since I don't have much to release in a new framework version at present, I'll hold off and see what I can do with AI caching in a week or two.

A framework caching system would give scripters a different interface for caching than (probably all) existing caching scripts. I would just present the features of a caching system as functions and let mission makers use them however they like. I would all be tied together by a data structure that handled cached objects in an object-oriented way (like the task, fire support, etc. systems do now). I would also provide a basic example that shows how to automate caching and uncaching as well as using various features of the system.

I'll also look at whether it's more efficient to disable the units (as you did in your scripts) or delete them entirely and store various information necessary to respawn them. That choice could effect caching/uncaching time depending on the total number of units that are cached, how many units are considered to be cached together as a group, how to get features such as abstract patrols to work. Regardless of the internals, the caching system will reduce the amount of visible information about the units to what is necessary to keep track of them.

  • Like 1

Share this post


Link to post
Share on other sites

Sure and begorrah, I figured that my approach was akin to thumping the magic box with a rock. I'm sure that even 15-30 mins of planning on your part will be more informative than my tinkering thus far.

In case it prompts any investigations, I've found that most cache scripts that delete and spawn will cause a lag hiccup when the unit in question spawns. Noticed it back in Whole Lotta Altis and DUWS, then in Barbolani's Antistasi. Since all those cover action on the entirety of Altis, I had assumed it was due to the very large number of units being managed on a demanding map.

But in using smaller scripts and missions I've noticed it too. Murk spawn (edited by Wolfy to more thoroughly store all inventory contents) causes tiny hiccups even if I've only placed a couple squads. Nothing unplayable, just apparent.

 

I am by no means saying that the disable-everything hack is superior -- it really is inelegant and may well hog more memory/processor overhead if working with a hundred AI units. :D But in my limited experience, it seems to run more seamlessly during gameplay for some intuitive, seemingly obvious reasons. And for a caveman like me, inspired by Murk/Wolfy, it sure helped make waypoints easier since they're technically never deleted. Zeus maps will look really messy during play, but players won't notice the clutter.

ALiVE manages some ridonkulously large caching (though apparently with little to no specific unit info stored on damage, inventory, ammo, etc.? I may have misunderstood the posts on this topic) without much noticeable stutter.

 

Any which way, I'm happy to await what your thoughtful approach will create. There's definitely a balancing act between info to store, overhead costs of de/spawning/recreating unit WPs, inventory, etc. I'm sure you'll come up with something flexible and elegant! Absolutely no rush, and have fun in the process.

 

 

P.S. T-800a has a pretty solid spawn script otherwise, but I never got the spawn function there to work, and it may be nonfunctional currently. Tangentially related to your framework, he created some patrol and garrison functions that are super slick -- specifically urban patrols and garrison patrols that stick to street pathing and order infantry to patrol along streets plus into random buildings. I was looking over your functions and just for the sake of a learning exercise, I think a nearly identical set of patrol / garrison actions could be scripted within your framework (generate positions within an area marker of min distance from each other, with requirement for road positions, use positions for Zen move orders). This isn't an additional request of any sort -- just me tinkering with learning scripting and how different people do it. Mostly just me being amazed at yet another dimension of flexibility and capability in your framework and Arma.

 

Unrelated P.P.S. I've been messing with this init.sqf snippet:

_pos = ["air_station", 0, ["guard_tower", "guard_tower_1", "guard_tower_2", "guard_tower_3"]] call Zen_FindGroundPosition;
_bldg_pos = [_pos] call Zen_FindBuildingPositions;
doctor setPosATL (_bldg_pos select 0);

I'm using Air Station Mike-26 on Stratis to put a civ unit named doctor in one of the buildings. There are 1 large warehouse/office building, 5 small cargo container buildings, and 4 container guard towers within my "air_station" marker that I exclude with the blacklist. About half the time, it seems like the function can't properly find a building position for _bldg_pos and the big office/warehouse very rarely gets used (i.e. my civ unit stays put in its initial placement). Am I just being blind due to observation biases (maybe it's just randomly spawning the civ back into its original placement), or am I somehow being too restrictive in my use of Zen_FindBuildingPositions?

Share this post


Link to post
Share on other sites

I can experiment with spawning of saved data, as I'm almost done improving the Zen_CreateTemplate/Zen_SpawnTemplate functions into a more robust system for copy-pasting non-human objects dynamically. Disabling the units does have the advantage for selecting certain things to disable; if one wanted to e.g. target cached units with artillery, damage alone could be enabled quickly (without having to turn on AI FSM's, etc.) for that and the surviving units hidden again (without having to completely rescan the units and save the data again).

For patrols, Zen_OrderInfantryPatrol is primarily designed for large, open areas in which the patrol area is designed with some larger features of the terrain in mind (e.g. patrol within a valley, avoid a swamp, etc.). It does not handle urban areas differently or use Zen_OrderInfantryPatrolBuilding. However, units in the 'safe' behavior will automatically follow any roads between their waypoints.  Zen_OrderVehiclePatrol prefers to put waypoints on roads if it can.

Zen_OrderInfantryPatrol ends up working fairly well for both large urban areas and small villages with surrounding countryside. Typically I assign units to buildings and street patrols separately in a mission, as the AI don't move in/out of a building very smoothly. For an example of how I populated an urban area, see the mission 'Sweep' in my ZMCM pack.

For the building position, the selection of the building to use is determined by the nearest building to the point given to Zen_FindBuildingPositions. This uses what the engine considers to be the 'center' of a building, regardless of the details of its 3D model. You might have to adjust the random area in order to get a certain probability of selecting one building over the other.

Once the building is selected, Zen_FindBuildingPositions is rather strict about which positions it will return (a quality over quantity approach). You can use the 'number of positions' argument to override the default number of attempts it makes and force it to searching longer. The default is based upon the 2D area of the building (not counting multiple floors) and can be too low for very small shacks or buildings with many floors. Something like 100-200 should render some usable positions.
 

  • Like 1

Share this post


Link to post
Share on other sites

Thanks for the insights into the applications of your functions. Derp moment: I usually set my patrols to SAFE, and I have def seen them pace along the side of the road with even default waypoints. I just didn't put 2 and 2 together to realize there's no need to explicitly force it if the game already does it for me. :P

 

One last question on the building pos function, then: The output is in the format:

_my_pos_array = [[x1, y1, z1], [x2, y2, z2], [x3, y3, z3], ...]

Yes?

 

Sorry for this noob question: When I have just 3 units to place using this array, I know how to manually script:

unit1 setPos (_my_pos_array select 0);
unit2 setPos (_my_pos_array select 1);
unit3 setPos (_my_pos_array select 2);

but what's a better syntax that allows me to run this with, for more dynamic or open-ended amounts of units? (e.g. if I spawn a random number of units from 4 to 8 in a new group, so I can't just hardcode an array of 8 units)

{_x setPos (???)} forEach [unit1, unit2, unit3];

Last night I tried some bonkers for "_i" from 0 to 2 step, then conversion to text in order to create dynamic object names. Definitely the wrong n00b rabbit hole to go down.

 

I'm away from home right now, so can't open up your building garrison script which, I imagine, probably achieves exactly this. I'll look. Just didn't think to check last night how you did it.

 

Also, the wiki code optimization page says setPosWorld is the superior command for speed, but your find position function is in a format that requires setPos, and your building pos function requires setPosATL (if I remember correctly). For the small numbers of units I'm working with (< 30 at a time), then it's not worth converting to a posWorld format, right? (I'm slowly learning how to use everything on the optimization page)

 

EDIT: Reading through how to use count command now. I may be answering my own question later tonight!

  • Like 1

Share this post


Link to post
Share on other sites

Yes, an array of positions is list of each XYZ position as a nested array. The framework tries to remain neutral in terms of supporting hard-coded names, and in general you want to setup things in whatever way gives you easy access. For example,

 

_group = [_building, west, "infantry", 3] call Zen_SpawnInfantry;
_positions [_my_pos_array, 3, true] call Zen_ArrayGetRandomSequence;
{
    _x setPosATL (_positions select _forEachIndex)
} forEach units _group;
If you spawn units with Zen_SpawnInfantry, you get the group directly. If you place a group in the editor, then it's just

_group = group X;
where X is what you've named a group member. Basically you want to save yourself from having to name dozens of things in the editor and then having to type out unit1, unit2, etc.

setPosATL aught to be faster than just setPos, but setPosWorld is acting on the 3D model center and above sea level. Zen_FindBuildingPositions returns above ground level positions, as that makes more sense on land. You can always do ASLToATL or ATLToASL.

count is used for conditional counting. You may find examples where the condition is used to execute code, but in general a forEach loop will work just as well (and be easier to read later). The wiki also has some examples of using exitWith inside count, and you'll likely be able to get a speed advantage for simple code; however, count is not an equivalent to forEach for more complex statements (forEach loops may go on for dozens or hundreds of lines).

  • Like 1

Share this post


Link to post
Share on other sites

ALiVE manages some ridonkulously large caching (though apparently with little to no specific unit info stored on damage, inventory, ammo, etc.? I may have misunderstood the posts on this topic) without much noticeable stutter.

You must spawn the function that creates the units and also run a small sleep (0.02-0 05) within the spawning loop and you should remove a lot of stutter

  • Like 1

Share this post


Link to post
Share on other sites

Hey guys,

 

iam getting into this framework right now. And iam very satisfied with it!

But iam getting into trouble with Join In Progress.

 

 

In my mission, i have add several Task with "Zen_InvokeTask"

For example:

_taskName2 = [west, "Erreicht ungesehen den markierten Wald, um dort gedeckt den Platz der Gruppe einzurichten.", "Erreicht ungesehen den Platz der Gruppe",[2178.94,4667.96,0.0012207],false,"","Maeh_TM_Day1_Task2"] call Zen_InvokeTask;

But after rejoining the server, there is no reasigning -_-

 

I red through a bunch of the tutorials/demonstrations and come to the JIPSync.sqf

Ive filtered this section, that might be doing this job:

{ 
   0 = [(_x select 1), (_x select 4), (_x select 5), (_x select 3), false, (_x select 0), (_x select 6)] call Zen_InvokeTaskClient; 
   0 = [(_x select 0)] call Zen_UpdateTask;
} forEach Zen_Task_Array_Global;

But it doesnt. "Zen_Task_Array_Global" is filled and present on the client machine:

[
["Maeh_TM_Day1_Task1",[g121,B Alpha 1-2:1 REMOTE],"created",[1636.24,4220.74,0.00137329],"Stattet euch mit dem nötigstens aus, was ihr in den kommenden Tagen brauchen werdet! \n \n Ihr braucht mindestens die Zelte, die Verpflegung und das Hochfrequentfunkgerät.","Rüstet euch aus","",[]],
["Maeh_TM_Day1_Task2",[g121,B Alpha 1-2:1 REMOTE],"succeeded",[2178.94,4667.96,0.0012207],"Erreicht ungesehen den markierten Wald, um dort gedeckt den Platz der Gruppe einzurichten.","Erreicht ungesehen den Platz der Gruppe","",[]],
["Maeh_TM_Day1_Task3",[B Alpha 1-2:1 REMOTE,g121],"created",[2178.94,4667.96,0.0012207],"Baut die mitgebrachten Zelte auf, bereitet für die Nacht ein Lagerfeuer vor und bereitet euch mit Stellungen auf einen möglichen Angriff vor. Richtet auch einen Alarmposten ein und besetzt diesen, wärend der Rest der Gruppe verpflegt. Wechselt im Anschluss durch.","Richten Sie den Platz der Gruppe ein","",
	["Maeh_TM_Day1_Task3_1","Maeh_TM_Day1_Task3_2","Maeh_TM_Day1_Task3_3","Maeh_TM_Day1_Task3_4"]],
["Maeh_TM_Day1_Task3_1",[B Alpha 1-2:1 REMOTE,g121],"created",[2178.94,4667.96,0.0012207],"Baut die mitgebrachten Zelte auf.","Errichtet die Zelte","Maeh_TM_Day1_Task3",[]],
["Maeh_TM_Day1_Task3_2",[B Alpha 1-2:1 REMOTE,g121],"created",[2178.94,4667.96,0.0012207],"Errichtet ein Feuer zur Verpflegung und zum wärmen in der Nacht.","Errichtet ein Kochfeuer","Maeh_TM_Day1_Task3",[]],
["Maeh_TM_Day1_Task3_3",[B Alpha 1-2:1 REMOTE,g121],"created",[2178.94,4667.96,0.0012207],"Erkundet Stellungen zur Verteidigung des Platz der Gruppe, sowie einen Alarmposten, der fortan besetzt sein sollte.","Erkundet die Verteidigungsstellungen","Maeh_TM_Day1_Task3",[]],
["Maeh_TM_Day1_Task3_4",[B Alpha 1-2:1 REMOTE,g121],"created",[2178.94,4667.96,0.0012207],"Jeder Soldat sollte verpflegen (optional).","(Opt.) Verpflegt","Maeh_TM_Day1_Task3",[]]
]

But this little codeblock simply is doing nothing (without errors!). If iam using the code befor the reconnect, the codeblock invoke all the task a second time, as expected (iam running the codeblock in the adminconsole).

 

What am i doing wrong?

Share this post


Link to post
Share on other sites

I would like to 2nd the issue above.   I've tried to pair down the JIP example stuff to just sync tasks, but no joy   :unsure:

 

Is there a simple implementation using initplayerlocal using Arma's built in didJIP to sync whatever blufor tasks are still in progress (or all of them, done or not)?

Share this post


Link to post
Share on other sites

Is the core (i.e. the parts it says to never change) part of the JIP code given in that demonstration running on the client machine? Code taken out of context from that will likely not work; the server's function, publicVariable's, waitUntil, etc. are all necessary. The decision for friendly AI or no friendly AI (line 68 of the demonstration) is required for applying the tasks correctly. The lines you're using are for a player taking over a slot previously controlled by an AI (which is why they must use the private function Zen_InvokeTaskClient directly).

I'm guessing you've disabled friendly AI, so the task line is

        {
            0 = [_x, player] call Zen_ReassignTask;
        } forEach ([_refUnit] call Zen_GetUnitTasks);
However, you still need the code above to determine what _refUnit to copy tasks from (a group leader, a team commander, a dummy unit, etc.). This should copy all tasks (included completed/canceled ones) to the JIP client. An important note: if you are testing JIP alone and there is no unit to copy tasks from, this will not work (the code doesn't know which tasks you want to copy). In this case, you need to setup a dummy unit to hold the tasks that should be assigned to JIP players, then reference that unit directly in the arguments to Zen_GetUnitTasks.

For you example, if you assign a task to all west units

_task = [west, ...] call Zen_InvokeTask;

// and you have a dummy unit on the west side name 'TaskDummyWest'
// then the JIP task code should look like
{
    0 = [_x, player] call Zen_ReassignTask;
} forEach ([TaskDummyWest] call Zen_GetUnitTasks);
To answer accuracythruvolume's question: changing where or how the code executes doesn't affect the implementation. didJIP is (to my knowledge) a shorthand for traditional JIP check code. The same considerations about AI being present, requesting the necessary public variables, etc. will always be present.

Share this post


Link to post
Share on other sites

Update and Release #44

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

With some delay, I have taken the time to bring an entirely new feature to the framework; the new additions bring the total number of public functions above 200. AI caching has been a potential addition for a long time, and I believe it is time for a framework solution for this. The highlights of the framework's caching system are very fast cache/uncache times due to disabling the units rather than deleting/respawning them as well as a robust, dynamic object-oriented structure for managing cached groups.

Currently, the only information lost when caching a group is their waypoints (a result of the implementation used to workaround the 144 groups per side limit). This will be corrected in the next release, with full waypoint information being restored to each group as well as abstract waypoints and patrols allowing groups to moved while cached. For now, as a (fairly easy) workaround, just reapply any waypoints or Zen_Order functions after uncaching.

The second major component of this release is an overhaul of Zen_CreateTemplate and Zen_SpawnTemplate. They now use a object-oriented data structure with string identifiers (that's now a framework signature with a current total of seven and likely another one eventually) and are supported by the expected Zen_DeleteTemplate, Zen_GetTemplateObjects, and Zen_RemoveTemplate.

The template system is basically the opposite of the caching system, it stores data on non-human objects so they can be copy-pasted dynamically in a mission. The information saved by Zen_CreateTemplate has been expanded to differentiate between vehicles (everything with an inventory and crew), weapon holders (everything with just an inventory), simple objects (like chairs and tables). The inventory, animation states (these can be used to remove e.g. the doors of a truck), damage to specific parts, and fuel of vehicles is saved.

Zen_GetUnitLoadout and Zen_GiveLoadoutCustom (and indirectly Zen_GiveLoadout for custom loadouts) now support vehicles. Zen_GiveLoadoutCargo no longer exists; simply renaming all usages of it to Zen_GiveLoadoutCustom should work. Note that because vehicles cannot wear a single uniform, etc., those will appear as items rather than in the 'uniform' etc. slot, which is for humans.

6/20/16

  • New Function: Zen_Cache
  • New Function: Zen_DeleteTemplate
  • New Function: Zen_GetCachedUnits
  • New Function: Zen_GetTemplateObjects
  • New Function: Zen_IsCached
  • New Function: Zen_RemoveCache
  • New Function: Zen_RemoveTemplate
  • New Function: Zen_UnassignCache
  • New Function: Zen_UnCache
  • Fixed: Zen_CreateTemplate shifted the height of all objects if some had non-zero height above the terrain
  • Added: Zen_GetUnitLoadout and Zen_GiveLoadoutCustom handle vehicles
  • Removed: Zen_GiveLoadoutCargo
  • Improved: Zen_ConvertToGroupArray and Zen_ConvertToObjectArray check that their entire argument is not void
  • Improved: Zen_CreateTemplate returns identifiers used in its object-oriented data structure
  • Improved: Zen_CreateTemplate saves the damage to specific parts, fuel, inventory, and animation states of vehicles
  • Improved: Zen_FindBuildingPositions checks that its raycasts hit the building of interest
  • Improved: Zen_SpawnGroup gives a specific error message for exceeding 144 groups per side
  • Documentation: Added for Zen_Cache, Zen_DeleteTemplate, Zen_GetCachedUnits, Zen_GetTemplateObjects, Zen_IsCached, Zen_RemoveCache, Zen_RemoveTemplate, Zen_UnassignCache, and Zen_UnCache
  • Documentation: Improved for Zen_FindBuildingPositions
  • Documentation: Updated for Zen_CreateTemplate, Zen_GetUnitLoadout, Zen_GiveLoadout, Zen_GiveLoadoutCargo, Zen_GiveLoadoutCustom, and Zen_SpawnTemplate
  • Documentation: Updated Notepad++ SQF language and autocompletion file with ArmA 1.60 stable commands

Code Example

In this section, I will present a function or piece of code that shows something not present in the existing documentation. These examples are adapted to be general, accessible, and customizable. They are meant to be useful to mission makers who want to include the code as part of their mission, as well as those who want to learn general coding techniques and specific framework implementations. These are not contrived or coded with any specific skill level in mind; they are taken from full missions I have finished or am working on with minimal changes. Of course, if you have any questions about an example, suggestions for an example, your own example to present, or if find any bugs, please let me know.

This release's example is a compact way to continually spawn vehicles and have them patrol in an area. The advantage to this code is that everything is condensed into three threads (two for patrols and one for spawning). You can extend this code to spawn multiple vehicles, different types (such as adding a list of MRAPs and a check for them), or infantry (and another patrol thread for them).

_allVehicles = [];
_allAircraft = [];

// Obviously you must fill in what classnames you want
_armorClasses = [[<west vehicle classnames>], [<east vehicle classnames>]];
_heliClasses = [[<west helicopter classnames>], [<east helicopter classnames>]];

#define SPAWN_VEH(CLA, S, A) \
    _class = ZEN_STD_Array_RandElement((CLA select (S call _F_SideToInt))); \
    _vehicle = objNull; \
    _pos = [(S call _F_SideToSpawnVeh)] call Zen_FindGroundPosition; \
    if (A) then { \
        _vehicle = [[_pos, 10 + random 30, random 360] call Zen_ExtendPosition, _class, 50] call Zen_SpawnHelicopter; \
        _allAircraft pushBack _vehicle; \
    } else { \
        _vehicle = [[_pos, 10 + random 30, random 360] call Zen_ExtendPosition, _class] call Zen_SpawnGroundVehicle; \
        _allVehicles pushBack _vehicle; \
    };

// I is the index of the timing array to use for this check
// R is the random variance in the next scheduled spawn time
#define CLOCK_CHECK(I, R) \
    if (time > (_timingClocks select I)) then { \
        _timingClocks set [I, time + (_timingClocks select I) + ZEN_STD_Math_RandNegativePositive() * R];

// These area markers must be placed on the map
_F_SideToSpawnVeh = {
    (switch (_this) do {
        case west: {
            ("mkBluforVeh")
        };
        case east: {
            ("mkOpforVeh")
        };
    })
};

_F_SideToInt = {
    (switch (_this) do {
        case west: {
            (0)
        };
        case east: {
            (1)
        };
    })
};

private ["_h_airPatrol", "_h_vehPatrol"];
_timingClocks = [6*60, 8*60];

while {true} do {
    sleep 5;

    {
        CLOCK_CHECK(0, 45)
            SPAWN_VEH(_armorClasses, _x, false)
            terminate _h_vehPatrol;
            _h_vehPatrol = [_allVehicles, "mkPatrol"] spawn Zen_OrderVehiclePatrol;
        };

        CLOCK_CHECK(1, 90)
            SPAWN_VEH(_heliClasses, _x, true)
            terminate _h_airPatrol;
            _h_airPatrol = [_allAircraft, "mkPatrol"] spawn Zen_OrderAircraftPatrol;
        };
    } forEach [west, east];
};

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. On some releases, 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_CreateTemplate and the various other template functions. The template system is the framework's response to the Eden editor; it allows you to take complex, hand-crafted object placements and turn them into a dynamic template that you can spawn anywhere during the course of a mission.

I will now briefly show an easy way to start using this system. First, you would create some arrangement of objects in the editor; since the placement of the template is random in the mission, you can just move the original to some far corner of the map where no one will notice it. Then place an area marker over the template, e.g. 'mkTemplate', and

_template = ["mkTemplate"] call Zen_CreateTemplate;

// We need to generate a position to place the template somehow
// This can be at an objective, the players' base, etc.
// For now, we'll just say its somewhere in "mkDesert"
_pos = ["mkDesert"] call Zen_FindGroundPosition;

// One of the goals of this spotlight is to highlight the difference between
//     a template identifier and a spawned template identifier
// Zen_CreateTemplate creates an identifier that points to compiled data on the objects
// Zen_SpawnTemplate creates an identifier that points to a list of spawned objects
// To put it in an object-oriented way: a template is a class, and a spawned template is an instance of that class
_spawnedTemplate = [_pos, _template] call Zen_SpawnTemplate;

// When operating on the spawned objects, both identifiers are necessary
// For example, you want to add an action to an object in your template
{
    if (typeOf _x == "<vehicle classname>") then {
        _x addAction [<...>];
    };
} forEach ([_template, _spawnedTemplate] call Zen_GetTemplateObjects);

// Finally, the difference between Zen_DeleteTemplate and Zen_RemoveTemplate
// Zen_DeleteTemplate deletes the objects of a spawned template, it undoes Zen_SpawnTemplate
// This will delete the template we just spawned
0 = [_template, _spawnedTemplate] call Zen_DeleteTemplate;

// Zen_RemoveTemplate deletes the information of the template itself
// It will also prevent you from accessing the spawned objects with Zen_GetTemplateObjects and Zen_DeleteTemplate, it undoes Zen_CreateTemplate
// With this line all stored information about the template will be erased
0 = [_template] call Zen_RemoveTemplate;

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

×