Zenophon

Member
  • Content count

    496
  • Joined

  • Last visited

  • Medals

Community Reputation

74 Excellent

4 Followers

About Zenophon

  • Rank
    Gunnery Sergeant

Profile Information

  • Gender
    Male
  • Location
    'Murica
  1. You mean a one-way insertion that waits for the players to get in the helicopter? As an example, I cut this out of the Abduction mission from ZMCM: _heli = ["mkBase", "b_heli_transport_01_f", 0, random 360] call Zen_SpawnHelicopter; waitUntil { sleep 2; ([_players] call Zen_AreInVehicle) }; _h_insert = [_heli, [_lzPos, "mkBase"], _players, "full"] spawn Zen_OrderInsertion; How you determine _lzPos is based upon the mission; it could be random, given by player input, etc. A self-contained function for that is not provided by the framework, but the logical parts required to do it are. You can use Zen_GetAllInArea to find the units inside the marker, as well as Zen_AreInArea and Zen_AreNotInArea to check for specific units being inside. The exact logic of the script depends upon what you consider to be 'conquered' as well as if the Opfor can recapture the zone, but for as a simple example of one-time capture // let's call it "mkTown" waitUntil { sleep 2; (count (["mkTown", [], east] call Zen_GetAllInArea) == 0) }; "mkTown" setMarkerColor "colorBlufor"; If you are using the task system, the above code is basically the same logic as that of Zen_TriggerAreaClear. Using the config viewer in the editor, 5, 6, and 8 would be 'vehicleClass', 'faction', and 'expansion' data fields. Note that units are sorted and categorized in the editor based upon these, so e.g. all the Apex guerrilla units share the same 3 values (and thus are all in the same unit submenu). You can also make use the blacklist argument to exclude any units from that set you don't want. The code for those Apex units would be: _group = [_pos, resistance, "infantry", [3,4], "Men", "IND_C_F", ["I_C_Soldier_base_unarmed_F", "I_C_Pilot_F"], "Expansion"] call Zen_SpawnInfantry; where we've left out the unarmed unit and the pilot (and confusingly the expansion value is 'Expansion', but that's the value for all Apex classes).
  2. Saving in SP works for most things; all running scripts are restored and the mission will proceed as intended. There have been issues reported in the past about UI scripts stopping, addons not loading properly, etc. (which I've never seen myself), so at the time I released my framework I made a blanket statement against saving to prevent such issues in SP. I was also mostly thinking about missions written for co-op being played in SP, where saving would not be part of the mission's design (and thus not necessary in SP). If a save/load cycle works in your mission, then of course you can enable it. There's nothing built into the framework against saving.
  3. Update Overview Greetings fellow Armaholics, this latest release ports this mission to Tanoa and offers 3 new enemy factions to choose from. You can use the additional mission parameter to choose between the AAF (the default and original faction), CSAT, FIA, or Apex guerrillas. Note that if you choose the Apex faction, you'll need that DLC to scavenge enemy weapons. I've also added random DLC loadout (for both marksmen and Apex); you'll need to have the DLC in order to receive those loadouts (you'll also see the AI using them). There is now a mission parameter for fatigue, for those who want to disable that. Changelog 2/3/17 Added: Tanoa version Added: Mission parameter for enemy faction Added: Mission parameter for fatigue Added: New DLC loadouts Improved: Various improvements and fixes included in my latest framework
  4. The issue occurs in the absence of Zen_OrderAircraftPatrol, just with the simple spawning code I tested. Zen_OrderAircraftPatrol is using 'move' and 'addWaypoint'; the aircraft always goes to [0,0,0] after a move order is complete. Since Zen_OrderAircraftPatrol gives a new waypoint after that, it means that Zen_IsReady returned true for the aircraft. I don't think anything is ordering the AI to move [0,0,0]; it seems like an intrinsic bug in their AI. Instead of circling their last waypoint (or their spawn point), they forget it and go to [0,0,0].
  5. You can edit the missions if you want; just add new playable units to the existing group in the editor. Those new slots will be detected automatically by the code (and they can JIP). It's all generalized, so you could add as many slots as you wanted. I'm assuming they're all human players, so it doesn't matter that they're all in the same group; if you want multiple groups that requires some coding changes. You might find that the mission is too easy with 12 players; you can change the values of all the difficulty parameters in ParseParams.sqf. For example, in case 2 of AI strength, put '_maxIndfor = 160;'. The mission will accommodate any values you choose.
  6. Update Overview Greetings fellow Armaholics, this latest release ports this mission to Tanoa and offers 3 new enemy factions to choose from. You can use the additional mission parameter to choose between the AAF (the default and original faction), CSAT, FIA, or Apex guerrillas. Note that if you choose the Apex faction, you'll need that DLC to scavenge enemy weapons. Changelog Added: Tanoa version Added: Mission parameter for enemy faction Improved: Various improvements and fixes included in my latest framework
  7. Zen_OrderAircraftPatrol does have a bug; for some reason ArmA didn't print an error for an undefined variable. Line 45 should have '_center' replaced with '_movecenter'; I've checked other patrol scripts and they don't have this bug. if (typeName _movecenter == "STRING") then { \ However, this is not the cause of the [0,0,0] bug; it was only preventing Zen_OrderAircraftPatrol from negating that bug. After a quick test, that bug is not caused by the framework; it is a result of spawning an aircraft using standard SQF script commands. I tested this code in an empty mission with only the player (I didn't even save the mission): plane = createVehicle ["c_plane_civil_01_f", (getPosATL player) vectorAdd [0,0, 100], [], 0, "FLY"]; createVehicleCrew plane; The aircraft always flies towards [0,0,0]. I have no idea what is causing this; however, it does not affect aircraft placed in the editor. My guess is that BIS have introduced a bug with either createVehicle or something in the AI's flying code; it is possible that the editor-placed object is running some internal code when it spawns that fixes this bug. I don't know what SQF commands to use to replicate this fix, if any can. Aircraft spawned with createVehicle will follow move commands and waypoints, but when their final waypoint is complete, they will always immediately move to [0,0,0]. One solution is to issue them new waypoints forever (through Zen_OrderAircraftPatrol or a similar script).
  8. Update and Release #48 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 includes a new function, Zen_SubdivideMarker, which acts exactly as you would expect. It breaks up large rectangles (it pretends ellipses are rectangles) into smaller rectangles. You can use this to spread out spawning and patrols more evenly, quickly get more granularity in zone capture style gamemodes, etc.. We have reached a total of 90 preprocessor macros with the addition of ZEN_FMW_Code_GetRemoteVar. This is handy for dealing with cases where every client may have a different value of the same global variable. Also, in the case where the server is managing data attached to each client, retrieving the client's data on-demand typically saves bandwidth compared to always publicVariable'ing the data from the client when it changes. The dialog system has received several improvements. Zen_InvokeDialog can now move the origin of the dialog anywhere on (or off) the screen; that argument works with safeZoneX etc. for determining screen edges. There is a new type of a control, the map itself. Other than size and position, there's not much customization to do, but it can be a useful alternative to have the real map open behind the dialog. Zen_InvokeDialog now allows you to enable user input while a dialog is open. This a bit of a hack and isn't really intended; you enable it at your own risk. 1/26/17 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. One issue that arises in creating co-op missions with a large mission area and/or a high number of players is having AI patrol in separate areas so that a reasonable portion of the map is populated. While this is of course possible, it results in having dozens or more threads managing each separate area's patrols. The solution I've arrived at is Zen_OrderMultiInfantryPatrol; it will not included as a framework function (due to how it accepts arguments). Rather it is an external script (that still requires the framework) that generalizes Zen_OrderInfantryPatrol so that all patrols can be handled by a single thread. This single thread can scale its execution to maintain good performance regardless of how many patrols it is given. The code is basically a copy-paste from Zen_OrderInfantryPatrol, but below it I will show the unique way it accepts arguments. The function itself has no arguments; it should be spawned as a thread on the server. You can compile it as a separate file (hence the #include's at the top) or make it an in-line function in the init. It relies upon a global variable, Zen_Multi_Infantry_Patrol_Array to receive its arguments. For simplicity, Zen_Multi_Infantry_Patrol_Array doesn't support defining the patrol area with a marker. I'll probably add that in the future; if anyone really wants it now, just ask and I'll show you what to add.
  9. Update and Release #47 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 endless road towards perfection continues, if a bit slowly recently. This release is a mix of suggestions, bug fixes, and other minor improvements I've found. Most notably, Zen_FindTerrainSlope has been removed, and Zen_FindTerrainGradient modified to handle both its original duties as well as Zen_FindTerrainSlope's. The conversion should be // the old Zen_FindTerrainSlope is now the same as (90 - (([_pos] call Zen_FindTerrainGradient) select 2)) This also relates to the standardization of coordinate system among framework functions (such as measuring that second angle from the Z axis). Zen_ExtendPosition has been renamed Zen_ExtendVector; I am aware that this is a common function and renaming it is annoying, but no other change to is arguments is necessary. Zen_ExtendVector has the same parameters, with the addition of an optional parameter sequence using a standardized vector. Also, Zen_FindAveragePosition now averages the Z coordinate, so it can now be used with other vector functions by converting to Cartesian coordinates.Zen_FindInRange (and indirectly Zen_SpawnInfantry and all other functions that use it) has had its distribution corrected when using rounded numbers. Specifically, Zen_SpawnInfantry can spawn the maximum number of units given; Zen_SpawnInfantry also supports a Gaussian distribution of random units. Zen_OrderInfantryPatrol should prevent units from chasing a spotted enemy even though they can no longer see them (or had already killed them). This keeps the AI in the patrol area better and reduces aggressive behavior in which the AI kept chasing players after the player had evaded them. Zen_SetAISkill has a new present for 'player' skill. This sets all skills except accuracy and spot time to 1; accuracy has been tuned such that the AI has comparable accuracy to an experienced ArmA player (obviously player skill varies widely, so this is just an estimate). The AI fires more slowly than a player at long range, but they can reliably hit a standing target at 400-500 meters. The spotting time skill of the AI is much more subjective, as I don't know the details of internal AI code that allows them to spot enemies. Its value is meant to be an estminate of how much situational awareness the average player has, particularly when they are engaged in a firefight. As for documentation, I have added a new demonstration for the Dialog System. This demonstration includes five dialogs with explanations of the specific properties as well as how the dialog system work conceptually. This should provide good examples to support the (somewhat terse) list of controls and properties within the dialog system documentation file itself. Also, a relatively short section has been added to the AI caching demonstration. 11/20/16 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. There are several issues about friendly AI in ArmA that have always bothered me, and while the AI can be useful in some situations, they end being a hindrance or just becoming cannon fodder in others. I wanted to find a way to being the friendly AI on a more equal footing with players and give players the sense that the AI can be an effective tool. Setting their skill to a high value helps, but having an aimbot AI do all the work for you isn't fun. The new 'player' Zen_SetAISkill preset is designed to find a balance between spray-and-pray and aimbot AI. However, teamwork isn't just about who can kill the enemy. The code below intends to correct the issue of AI communication with players. Typically, AI say something like 'Enemy spotted, 300 meters, south.'; which is generally vague and useless. Compare that to a message like "He's in the second story window of the yellow building bearing 137"; this is extremely specific and allows teammates to immediately engage the threat. My solution allows the mission to simulate the AI calling out enemies like human can by marking the enemies the AI spots on the map. This varies in effectiveness based upon whether the player is marked on the map, if they have a GPS, how much map/situational awareness they have. The information is taken directly from the AI knowledge, and the marker fades away when the AI cannot see the enemy. To use this code, just copy-paste it into the init.sqf and let the thread run. The main things of interest that you might want to tweak are the 'sleep 5; \' in the marker thread, and the sideChat message about the spotting. The sleep command controls how quickly a marker fades, so having it fade quickly means the players will have to pay closer attention to the map. The sideChat is a very accurate spotting report in the form of 'X distance at Y degrees'; by default it only appears when a new enemy is spotted.
  10. The AI's skills, loadout, etc. will remain the same since the cache system uses enableSimulationGlobal rather than deleting and respawning them.
  11. Before calling Zen_Cache, all threads that manage those units must be stopped using terminate. Those threads must be stored along with the set identifiers. For brevity, I will implement that in the previous example I gave. The four additional parts are highlighted by comments. Also note that you can use Zen_GetCachedUnits to get the units listed in their groups more efficiently.
  12. I cut the init.sqf to the minimum, and this is what I tested At 25 areas, the fps starts around 60 for me, and declines to around 20-30 during the spawning process, with some stutters to below 10; I did not turn down the graphics from what I normally play at. The spawning process took 165 seconds and spawned 938 AI. While the cache loop was running, I got a fairly constant 35 fps walking around and about 25 while driving fast. If I turn down the graphics to the absolute minumum, I get 45 fps when stationary and 30 when driving fast. All of this was done on Altis, with a i5-6600k at 3.5Ghz, a GTX 970, and 8GB RAM. I didn't run it on a dedicated server, but I imagine a server with a good CPU will be able to manage 35-45 fps with all of the units cached. I urge you to test this init.sqf exactly as I posted it and in an isolated environment (you just need a player unit and an area marker "mkAll" that covers Altis). If the game is unplayable and locked to 1 fps for you, look at your CPU/GPU usage and temperatures. Also, in the full mission, if you have many players in different places, more AI will be uncached at once; the scripts cannot control the performance impact of uncached AI. Estimate or count via scripts how many AI are really uncached at once, if it's beyond a hundred or two, expect poor performance if they are all being managed by the server. Check out the framework's headless client demonstration; even running the HC as a separate .exe on the same machine as the server will help.
  13. The '0 = ' is just a habit I have now that I developed to indicate that the return value was void or unwanted; I'm just used to seeing it when I skim code looking for function calls (mainly spawned threads or calls that have some side effect). I didn't really highlight this before, but this is supposed to run on only one thread. You have spawned 22 threads by dividing the sets of groups into their own thread. The thread should combine every set of units into a single loop. That's the the only way that you can handle 1000 AI with performance issues. You also have to prevent the 1000 AI from all being uncached at the same time.
  14. What you have running on the server is correct, i.e. this sleep 1; loadoutPOW = [[["uniform","LOP_U_AFR_Civ_02"],["items",[["ACE_quikclot",2],["ACE_morphine",1],["ACE_epinephrine",1],["ACE_EarPlugs",1]]]]] call Zen_CreateLoadout; In short, the assignment 'loadoutPOW = ...' is completely separate from what Zen_CreateLoadout is doing with the data internally. loadoutPOW isn't defined on the clients, but the data is there.How Zen_CreateLoadout works is different from how remote execution in general works. Zen_CreateLoadout is an abstract data structure that takes information and stores it with a name; that name is just a string that Zen_CreateLoadout returns. The identifier/namestring/key is returned immediately (thus there is no need for the waitUntil), and it really is just a string; it has no meaning outside the loadout system. Within the loadout system, Zen_CreateLoadout propagates the key and its data to all clients, so the key can be used on the client machines to find the data. When you call Zen_GiveLoadoutCustom on the server, the function passes the literal value of the key to the client, and the client looks up the correct data for that key. The server stores the key string in a variable, but the client receives the key without ever storing it in a variable. If you want to manually do what Zen_GiveLoadoutCustom is doing for you when you run it on the server, then you you would use something like // from the server publicVariable "loadoutPOW"; // and on the client waitUntil {!isNil "loadoutPOW"}; 0 = [player, loadoutPOW] call Zen_GiveLoadoutCustom; Now the waitUntil is useful because the PV is a time-dependent event; in contrast to the assignment operation '=', which is local and instant (or rather uninterrupted). Many framework functions like Zen_GiveLoadoutCustom will do this PV process for you using a RE method built into the framework. There are demonstrations about the framework's RE process that explain how it's doing this.
  15. In this case the core code is a switch based upon the players being near the groups, which is iterated over every set of groups and accounts for them being wiped out. I use a list of markers in the code, but you could also compute the position of the sets directly from the units using Zen_FindCenterPosition or Zen_FindAveragePosition (which is statistically equivalent if they are constrained to patrol within the marker). This time I can test the code and it is working; note that the responsiveness is reduced by each set added due to the 'sleep 1' in the forEach loop. If your mission isn't script-heavy, you could reduce that to 0.5 to 0.25 to get a faster cache/uncache reaction time.