Jump to content

Zenophon

Member
  • Content Count

    527
  • Joined

  • Last visited

  • Medals

Community Reputation

100 Excellent

5 Followers

About Zenophon

  • Rank
    Gunnery Sergeant

Profile Information

  • Gender
    Male
  • Location
    'Murica

Recent Profile Visitors

The recent visitors block is disabled and is not being shown to other users.

  1. Are you spawning the units on the deck (or placing them in the editor) and then using a loadout function? There might be a delay for ArmA to create/initialize units on the ship; try adding a second or two wait before the functions run. In general, units can have their equipment changed even if they are e.g. skydiving, in a vehicle, etc.; though, as you say, being on a ship might be a special case that is bugged. The second fix is to spawn/place them on land, apply the loadout, wait/check that it is applied, then move them onto the boat. Sometimes setup like this requires a short 'mission loading' black screen so that the player doesn't see units teleporting or changing equipment.
  2. This is in the FAQ.txt under "Q: Can the framework easily spawn addon units?". The Zen_RandomBattle demonstration explains how to use Zen_ConfigGetVehicleClasses to search for vanilla vehicles; you can just replace the keywords with those of addon vehicles/people. This approach is meant to be very flexible and requires using the editor's config viewer. If you have classnames for specific vehicles, you can given them directly to Zen_SpawnAircraft, Zen_SpawnGroundVehicle, etc.. Zen_SpawnGroup and Zen_SpawnVehicle are the more basic functions that actually do the spawning, if you want to use them directly. For loadouts, the Zen_CustomLoadout demonstration explains how to get (with Zen_GetUnitLoadout) and format weapon/item/ammo classnames.
  3. Occupy House is a separate script that doesn't require the framework (thread link in my signature); it tries to position units at windows and in the right direction. It also relies on the built in positions defined by the building (buildingPos command); the framework offers Zen_FindBuildingPositions for any random point in a building (though the quality may vary). Of course, you can combine these in a mission or even edit Occupy House to use Zen_FindBuildingPositions. For placing markers, the editor is of course easier for visual placement, but you can use Zen_SpawnMarker if you want to create/delete lots of markers dynamically. Once you have the markers, you can put them into an array and use Zen_ArrayGetRandom, Zen_ArrayGetRandomSequence, and Zen_ArrayShuffle to randomly use them one at a time or in a random order. For a particular order, Zen_ArraySort can be given any comparator/hash function (there are a few macros for this). If some markers have to be removed later, Zen_ArrayFilterCondition can help. With the marker selected, Zen_FindGroundPosition (some argument macros offered here as well) is the main system for generating positions. You might also use Zen_IsUrbanArea etc. (these scale with area/objects and might not run very fast) to determine what kind of filters you need. You can then put this into a loop to repeat the objective. Zen_CreateObjective offers some presets for you; for scripting your own, Zen_TriggerAreDead etc. can be surprisingly flexible. I recommend browsing through the Index.txt in the root documentation folder; most of the functions have straightforward names, and it's much easier to find one there than looking through each full function documentation files. The tutorials, demonstrations, and sample missions have a readme/intro with a short description of what's in each one; all the documentation tries to make it clear when previous knowledge is required. As always, you can ask here for more examples or specific answers.
  4. I cannot remember a specific reason for excluding .jpg; I didn't even include the check for pictures in a list. Maybe I thought .paa was preferred or .jpg wouldn't work for some control types; it appears that .jpg is perfectly fine though. I'll change it to allow .jpg in the next update.
  5. Update and Release #53 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 This release marks the beginning of the framework's fifth year; for this milestone I want to offer a new level of randomness that is accessible and fits with existing functions (i.e. Zen_FindGroundPosition). The new feature is called Zen_FindLinePosition. Zen_FindLinePosition's first feature is to find a random point on any curve. This curve is any function that accepts an X value and returns a Y value. It can also find a random point between any two such curves. While the function itself is not very complex, it is fully integrated into Zen_FindGroundPosition, including verifying that road positions lie inside the curve and limiting the angles around the center. By using blacklist markers, angle limits, and every other Zen_FindGroundPosition filter, you can create a much greater variety of areas more efficiently. Some examples of this are: The calculation of roads includes a buffer to account for the discrete nature of road objects in ArmA; when the single line (green dots) crosses a road, it should find one or two road points to use. It is important to note that all Zen_FindGroundPosition options still use the given center position, so shifting the X limits far away from this may cause odd behavior. Also, consider that the function itself can be random, allowing you to weight the distribution of points within the area or around a central curve in any way you want. E.g. using the built-in random: 7/10/18 1. New Function. Zen_FindLinePosition 2. Fixed: Zen_FindGroundPosition road argument force and avoid options failed in some cases 3. Added: Zen_FindGroundPosition can use Zen_FindLinePosition 4. Improved: Zen_AddFireSupportAction and Zen_AddSupportActionCustom include the map on the support selection dialog 5. Documentation: Fixed for Zen_InvokeDialog 6. Documentation: Fixed tutorial AltisPatrol script errors 7. Documentation: Added for Zen_FindLinePosition 8. Documentation: Updated for Zen_FindGroundPosition The AltisPatrol tutorial is fixed; there were multiple errors in ReinforceGroups.sqf On a more general note, I will be reviewing all documentation that uses code in the next few months to ensure that it adheres to current framework functions and styles. The tutorials are the most out of date, but most of them should still work. If anything is inconsistent or confusing in an example, just post and I can clarify. I have made missions on various CUP maps in the past; I think the latest CUP Terrains version I tested was 1.3.0. I have looked at the changelog for 1.4 and I don't see anything that could cause such a significant problem. Can you post which terrain you are using and what the code is? I can't see that picture, but Zen_SpawnGroup (which Zen_SpawnInfantry uses) spawns all units very close together. Their AI should make them go into a normal formation immediately and maintain it when they move. You might have to repeat setFormation every time the group gets a new waypoint. Also, make sure you're not running any AI mods and that the group is local. Do the AI demonstrate the same behavior when placed close together in the editor and with editor waypoints (which are ostensibly the same as scripted)? Zen_OrderVehicleMove does everything it can for AI driving, but the issues are with lower level AI code; I consider it a success if the vehicle reaches it destination at all. Edit: It's much better to repeat the commands and ensure that the AI comply than have a function that doesn't work. The first priority is to make the functions always do what they say they will. Especially for functions dealing with the AI, as I have learned not to trust them.
  6. Update and Release #52 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 It's been a while, and this update addresses all bug reports and requests since last release as well as keeping the framework up to date with the latest ArmA version. There's always little things like helicopter pods spawning as vehicles and ropeCreate not working. The action system will be much more robust about removing null objects from its local and server lists. This does not include objects that are not alive (hence the new parameter for Zen_ArrayRemoveDead); you can put actions on destroyed objects (the transition from alive to dead may not preserve actions; this is the engine creating a new object). I've also added a check for duplicate actions; changing an action then invoking it again is still considered a duplicate action (create a new action or use Zen_UpdateAction's refresh argument). Zen_CreateObjective and the trigger functions it uses account for newly spawned units or JIP players being added to groups; previously they only scanned for new units when a entire side was given. Zen_SpawnConvoy will no longer spawns guerrilla factions or DLC factions unless you specifically input that faction. Zen_SpawnVehicleCrew will print a proper error if a very strange object spawns as a vehicle; please report any spawns that obviously are not an appropriate vehicle so I can add a special filter in Zen_ConfigGetVehicleClasses. 5/2/18 1. Fixed: Zen_ConfigGetVehicleClasses filters cargo helicopter attachment pods 2. Fixed: Zen_InvokeAction, Zen_DeleteAction, and Zen_RemoveAction filter null objects 3. Fixed: Zen_OrderFastRope did not create its ropes correctly 4. Fixed: Zen_SpawnConvoy spawned mixed factions for east and resistance sides when the faction argument was not given 5. Fixed: Zen_TransformObject argument checking allowed a scalar as the fourth argument 6. Added: Zen_ArrayRemoveDead argument to check for objects being alive 7. Improved: Zen_CreateObjective, Zen_TriggerAreDead, Zen_TriggerAreNear, Zen_TriggerAreRescued, Zen_TriggerAreaClear, and Zen_TriggerAreaSecure dynamically update the units they are considering for all inputs 8. Improved: Zen_InvokeAction prevents duplicate actions 9. Improved: Zen_OrderVehicleMove stops ground vehicles and boats at a reasonable distance from their waypoint 10. Improved: Zen_SpawnVehicleCrew prints an error and returns null if no crew can be created 11. Documentation: Fixed Zen_RespawnPatrol.Altis used Zen_TransformObject wrong 12. Documentation: Updated for Zen_ArrayRemoveDead 13. Documentation: Updated Notepad++ SQF language and autocompletion file with ArmA 1.74, 1.76, 1.78, 1.82 stable commands
  7. I was a bit vague about cleaning because I had to work out the details of implementing it. The action system is a manager and locality wrapper for addAction; it tracks global information about an abstract action as well as local information from addAction. The error is from the system's global tracking of which objects have the action; that server based list has to be cleaned of null objects. Any action system function that uses or updates the server data now calls Zen_ArrayRemoveDead 'on demand' so that the system cleans itself as it is used (Zen_DeleteActionClient already did this for local data). For example, Zen_InvokeAction would look like _nameString = _this select 0; _units = [(_this select 1)] call Zen_ConvertToObjectArray; _actionData = [_nameString] call Zen_GetActionDataGlobal; _text = _actionData select 1; _addActionArgs = _actionData select 4; // I've added this filter for null objects _oldObjects = [(_actionData select 5)] call Zen_ArrayRemoveDead; _allUnits = [_oldObjects + _units] call Zen_ArrayRemoveDuplicates; Zen_ConvertToObjectArray will filter the argument for null objects as well. Zen_RemoveAction and Zen_DeleteAction will use Zen_ArrayRemoveDead similarly. I've also changed Zen_InvokeActionClient to clean the local data and prevent duplicate actions. Don't worry about changing all this yourself, I'm going to release a new framework version in a couple days (after I test this and a few other things).
  8. There are two separate errors starting in the f_HandleRespawn function. First, Zen_InvokeAction is confused by null objects in the list of objects that already have the action (I'm guessing those units died); I'll need to modify the action system to clean its data as necessary. Second, Zen_TransformObject is given the wrong arguments on line 92; it should be 0 = [_unit, (((units group _unit) - [_unit]) call Zen_FindAveragePosition), 500, 0, random 360] call Zen_TransformObject; where the fourth arg is a 0 to skip the velocity transform rather than the 'random 360' direction transform; Zen_TransformObject was also incorrect in letting a number get through to the setVelocity command. Shell.Stratis was renamed to Shell and the mission.sqm removed some time ago to prevent confusion since there are many maps now (long ago Stratis was the only map in A3). The current instructions are based around creating a blank mission on the desired map using the editor, then copying framework files (as opposed to creating the mission files, then opening them in the editor). Some/all of the tutorial pdf's were never updated. For the markers, Eden editor has a map view ('M' by default or whatever your in-game map key is; there's probably a button on the interface as well) that makes placing markers easier (there's also a stretch tool for sizing markers accurately). Markers are preferable to triggers for use in external scripts since triggers have unnecessary complexity and overhead; it is also simpler to dynamically create markers and alter/inspect their properties in scripts. The framework isn't updated frequently because it's basically finished; the goal is to provide a robust set of tools for external scripts as well as major systems for common/standard things. Over the years, my style of coding some parts (e.g. remote execution) has become old fashioned; however, everything still works (if not, report it and I'll fix it) and you won't notice when using the functions. I still read all official patches notes for potential incompatibilities and new script commands. With the most recent bug report I'll probably release the accumulated fixes/improvements soon. The documentation talks about this much more, but essentially my framework/library is giving you a large code base and detailed documentation (and my assistance with any errors or questions) for you to learn and script missions with. The more you learn to program in SQF, the more use you will get out of the framework. The first tutorial is showing you how little code you need to create a basic mission; the amount of code will go up from there.
  9. If you place code anywhere in the editor that runs on mission start (i.e. not a trigger), it will run before an external spawning script; at the time it runs those spawned units don't exist. Anything that acts on the spawned units must run after the spawning code; also be aware of the spawning script using 'spawn' or 'execVM', which will run it on another thread. You would end up with something like _units = [...] call <Spawning_Function>; // if you want different positions you'll need a similar loop over the groups/units 0 = [..., _units, ...] call Zen_OccupyHouse; or 0 = [...] spawn <Spawning_Function>; waitUntil { // determine when <Spawning_Function> has finished } // you'll also need another way to get the objects _units = ... 0 = [..., _units, ...] call Zen_OccupyHouse; Any script using the 'buildingPos' command is entirely dependent upon the building being configured correctly. It is possible to generate entirely dynamic positions within a building, but this is more computationally expensive and can result in odd/bad positions. If you want Zen_OccupyHouse to only use part of a group, you'll need to select them somehow (i.e. any slicing/selecting function/command, maybe shuffle/sort before etc.) from the full list, e.g. // pick the first two units 0 = [getPosATL leader _x, (units _x) select [0, 2], -1, true, true] call Zen_OccupyHouse;
  10. To find a good place for a camp, you would use the slope argument (the 10th) to find a flat area, which leaves the terrain height above sea level (12th) argument. You can check the heights of the hills and valleys on the map and set a limiting value that only chooses the valleys; this would include a tolerance above the valley floor based upon their variations. If there is a overall tilt to the terrain (e.g. the valley and ridge elevations are all increasing/decreasing), you'll need to split the region into different areas with their own elevation limit (the number depending upon terrain tilt and the tolerance). Basically, any area in which the highest valley point is above the lowest ridge elevation needs to be divided. Depending on how well this works out, check out Zen_FindNearHeight and Zen_IsHillArea. A ridge looks like a hill on 2 of 4 sides (Zen_IsHillArea might return around 0.5), but Zen_IsHillArea will have a lower value for a valley (assuming the ridges and valley slope up/down equally lengthwise). Zen_FindNearHeight can be used iteratively to find the minimum of terrain (repeat Zen_FindNearHeight in an e.g. 100m radius of each point it finds until the elevation is low enough); this will move from a ridge to a valley, then down the slope of a valley (but not at random) until the minimum is local by the radius used. Once you know you're in a valley, Zen_FindTerrainGradient with a reasonable scan radius will tell you its slope. If the slope along the valley is weak, a large radius might result in errors from the valley walls (they can be asymmetric in slope magnitude), but a radius too small will not reflect the overall terrain features. About the width of the flatter part of the valley (assuming the point is centered in the valley) should work well (unfortunately this varies by valley). As you can see, scanning terrain dynamically is difficult. If nothing's working, placing several dozen preset locations manually and choosing from them is less random (also tedious to port your mission to other maps, if you're planning to do that), but runs faster and guarantees quality placement.
  11. Having to restart the mission has been an issue for a while; the first time the mission is run there is a varying delay in the server sending messages to clients. Having the admin use #restart in the console once the briefing is loaded will fix it. As far as I can tell this is due to some quirk of dedicated servers that only BI can fix. The radioman is chosen at random from all Opfor that aren't in a vehicle. I was a bit lazy and didn't give him specific equipment; he might be patrolling the streets or in a building. I think the radioman concept was meant to make the mission a little easier by having an increasing chance of stopping the mortars as the town is cleared; the difficulty of the mission is meant to decrease as players eliminate Opfor vehicles and reinforcements and secure more of the town.
  12. Zen_FindGroundPosition does not account for the size of buildings, rocks, etc when avoiding them; it treats them as point objects. This is done for efficiency, since using sizeOf (or even worse using boundingBox and then getting the rotation/orientation of the box) for every object will add another nested loop over all nearby objects (and that's assuming sizeOf/boundingBoxReal are correct for all static terrain objects). Currently the code finds all objects of a certain type within the given radius from a point and just counts them. This means that the avoidance distance must account for the size of the objects you are trying to avoid, e.g. if we estimate roads to have a width of 5 meters, buildings a radius of 15, and large rocks at 10, that can be added that to the size of the object you're trying to fit private _carPos = [_x, 0, [], 1, [3 , _objsize + 5], [0,360,'compass'], [1,0,_objsize + 15], [0,0,0], [0,0], [0,0,-1], [1,[0,0,-1], _objsize + 10], [0,0,0],0] call Zen_FindGroundPosition; You can tweak those tolerances for a certain map/area. It may also be helpful to use blacklist markers to remove any difficult areas (e.g. very large buildings, a very dense city, etc.); that will probably speed up the search as well (it's faster to find if a point is in an ellipse/rectangle than to check for nearby objects, particularly for larger avoidance distances).
  13. The 'MAP' control of the dialog system is essentially the same as the 'real' map. Thus, it functions and responds as the real map does. You can use 0 = ["Dialog_Map_Click", "onMapSingleClick", {Map_Pos = _pos}, []] call BIS_fnc_addStackedEventHandler; once at the beginning of the mission. When you prompt the user to click: Map_Pos = 0; waitUntil { (typeName Map_Pos == "ARRAY") }; _local_Map_Pos =+ Map_Pos; You would then use the local copy of the position in your code. This ensures we are using the correct position for that click; you can run multiple functions in parallel that are storing and using different click position instances (assuming the waitUntil of each does not run concurrently). If you need to prevent input from the real map, you can either remove the stacked EH with a BIS function or have your functions check that your dialog and map are open rather than the main map.
  14. First, did you put the framework code in the mission folder (I know this sounds ridiculous, but I have to start here)? Which mission(s) in particular don't work for you? As killick says, some (at least 'Airbase Assault') require two or more people. I picked one at random ('Clean Sweep') and didn't see any issues. Do the missions work in the editor? If it doesn't work there, it's certainly not going to work in MP. Do you have '-showScriptErrors' (or the launcher's equivalent setting) enabled, or are you checking the .rpt logs for script errors? These sample missions are fairly old and there might be a compatibility issue with the latest framework code.
  15. For your specific case, you could do what I'm going to do: change the units update in all the trigger functions to not include the 'if (typeName (_this select 0) == "SIDE")' check (yes, Zen_TriggerAreNear had the wrong index), so that they always update (e.g. if an array of groups is given) and make Zen_CreateObjective give the true argument to its trigger functions so it can use this feature as well. This will fix the problem without having to change how any code uses these functions. However, the above assumes that we want all units of the side to be able to complete the objective or (if we use groups instead of sides) that the JIP unit will join a defined group. These assumptions cover a large number of possible usages. In a more general case, there are a few things you can do to change the units the trigger is considering. One solution is to use the return values of Zen_CreateObjective to spawn a new thread to check for the JIP player. This is fine for JIP players; the trigger functions can run on any machine as well as have duplicates running (across machines or on the same machine) without issue. // create the objective the same way _a_ret_objective = [_objPos, west, west,"Box","reach"] call Zen_CreateObjective; // and put it in Zen_JIP_Args_Server (I think it should be 11 in Infantry Patrol) Zen_JIP_Args_Server set [11, _a_ret_objective]; // ... // and in the JIP sync code, spawn the trigger for the player using this information _a_ret_objective = Zen_JIP_Args_Server select 11; 0 = [player, _a_ret_objective select 1, "succeeded", _a_ret_objective select 0] spawn Zen_TriggerAreNear; However, this method only allows for adding players, not removing them. You could modify Zen_CreateObjective to return the thread _h_trigger = scriptNull; switch {// ... // ... case "reach": { _h_trigger = [_rangers, _taskUniqueName, "succeeded", _objects] spawn Zen_TriggerAreNear; }; }; // ... call Zen_StackRemove; ([_objects, _taskUniqueName, _h_trigger]) // ... // note that this is now global a_ret_objective = [_objPos, west, west,"Box","reach"] call Zen_CreateObjective; then terminate and update the thread when a JIP client joins // in the server's JIP code (Zen_SyncJIPServer) // All global variables on the server are accessible in this scope terminate (a_ret_objective select 2); // I've put west here just to match the code you've given // The units given to the trigger could be found in any way you want 0 = [west, a_ret_objective select 1, "succeeded", a_ret_objective select 0] spawn Zen_TriggerAreNear; See the JIP demo's changing of Zen_TrackInfantry threads for a similar example (that one uses a group instead of a side).
×