Jump to content

dwringer

Member
  • Content Count

    368
  • Joined

  • Last visited

  • Medals

Everything posted by dwringer

  1. ANIMA - Arma NSGA Interface for Milsim Applications ANIMA is a collection of functions and scripts for providing AI groups with terrain/position analysis capabilities that can be used, for example, to dynamically create waypoints with tactical advantage (by criteria that can be programmatically defined), automatically land helicopters at suitably flat/clear locations, or find places to spawn units or objects with specific visibility requirements. This release is essentially an open-ended set of scripts for getting units to do things in abstract terms like "land a helicopter nearby", find an overlook position with cover and concealment", "ambush nearby roads or intersections", "seek tactical advantage and engage targets", or "find a nearby place to unload troops". It does not affect unit AI in any way, but uses a genetic position-finding algorithm in various ways, many of which involve assigning different kinds of waypoints. Sorry, but for now, ANIMA does not have the required conditions for multiplayer, but if you're an experienced multiplayer developer and want to take a crack at it then I'd welcome your pull request! I've included a User Manual, which is essential for understanding ANIMA. There are also some example missions to accompany the manual which will hopefully elucidate some concepts. One of these (see below) comes with an additional guide that explains some of the development choices and basics of using the included applications. Please check it out and let me know what you think! I'll try to release some more examples and explanatory content as time allows. EXAMPLE MISSIONS (separate from release) VehicleTargets tank battle/ambush demo: https://github.com/dwringer/ANIMA/releases/tag/EXM-220409-A (added 9 Apr 2022) VehicleTargets application demo: https://github.com/dwringer/ANIMA/releases/tag/EXM-220407-A Vybor Airbase, w/development guide: https://github.com/dwringer/ANIMA/releases/tag/WIP-220322-A (Full mission here: https://forums.bohemia.net/forums/topic/238060-sp-vybor-airbase-stop-the-invasion/) RELEASE (includes basic examples): https://github.com/dwringer/ANIMA/releases/download/REL-220316-A/ANIMA-220316-A.zip MANUAL: https://github.com/dwringer/ANIMA/blob/main/ANIMA.pdf GITHUB (Updated regularly, may contain bugfixes as well as new featuresbugs): https://github.com/dwringer/ANIMA Known Issues: - Pausing the game while the algorithm is running sometimes causes it to fail. It will either choose a wildly incorrect position or fail to do anything at all. - Default landing zone search radius works best with only one helicopter. If you want to land more than one at a time, try bumping up the radius, step count, and population parameters of the land_helicopters/land_transport methods [55/3/13 is a possible start]. - Headquarters attack/dispatch methods occasionally assign an extra waypoint to a group - the logic needs to be refined. CHANGELOG (Latest) REL-220316-A (Updated 16 March 2022): - Added sort behavior to fnc_find_positions which can sort the final results by a given function (by default, uses the average across all objective scores) - Added a setting to allow fnc_find_positions to work faster, but less accurately, by allowing undifferentiated results after the target number of generations (a single bin after the nondominated sort, no dominance ranks in the result set) - The behavior of optional parameters for attack_targets and approach_targets methods of Headquarters was fixed - Fixed behavior of wp_config parameter of internal Headquarters method dispatch_transports - Added an optional start_offset parameter for approach/attack_targets which moves the search start location relative to the targets by [x, y, z] - Revised and expanded user manual with section on fnc_find_positions and some classes - New (WIP) example mission with all (non-airplane) waypoints generated from ANIMA positions (requires CUP addons) REL-220311-A (Updated 12 March 2022): - Added two parameters to fnc_find_positions: one is a sort-function (or "false") to sort the resulting positions (default sorts by average score). - There are now two example missions. The first one just follows the basic example in the manual, while the second employs a number of functions. - Added a User Manual chapter on fnc_find_positions. Combined with the chapter on LocationFinder, added in the last release, there should be enough information to customize the algorithm with new objective functions. REL-220310-A: - Fixed a bug with the LocationFinder method for finding helicopter landing positions, which was causing the parameter for enemies to avoid to be ignored. - Updated the example mission so that when OPFOR and BLUFOR units detect one another, their waypoints are removed and new ones are assigned using attack_targets with respect to the detected troops.
  2. I see what you mean but, for that example, what I was saying is that it would be equivalent to ( _previousDamage + (( _newDamage * 0.7 ) min 1.4 )) Just two different ways of writing the same thing. But all have their uses, for sure.
  3. Since you're reducing it anyway there's no real difference between that and (_previousDamage + ((_newDamage * 0.7) min 0.7)), but in the latter case it's more clear at a glance (IMHO) what the final damage cap is. I suppose it's just a stylistic choice more than anything.
  4. Vybor Airbase: Stop the invasion! SITUATION In a surprise attack, Russian forces from the northeast have captured the Pobeda dam and are expected to launch a combined assault on Vybor airbase imminently. What they don't know is that it wasn't actually a surprise, and in preparation we've received a large shipment of AA and AT missiles along with a state-of-the-art backpack-sized UAV control terminal from the CIA (who were also kind enough to grant us the use of an MQ-9 Reaper currently flying in from the south). An airborne platoon will also be arriving by Ghost Hawk to reinforce, but they are still a few minutes out. MISSION It's imperative that we knock out the incoming armor and clear the skies before our reinforcements arrive. Your task is to take control of the MQ-9 Reaper and ensure these goals are accomplished. EXECUTION Activate your UAV terminal and take out the Russian armor ASAP. There are some launchers beside you that can also be used to take out enemy aircraft and vehicles. This mission was created with the ANIMA library. I created a development overview guide to go along with an early WIP version of this mission. In it, I've tried to explain every aspect of how the triggers are used along with ANIMA, but it's still intended as a companion to actually looking at the example mission in the editor (which can be found on the ANIMA main thread). DOWNLOAD The mission itself can be downloaded by subscribing on the Steam workshop: https://steamcommunity.com/sharedfiles/filedetails/?id=2785257319
  5. Okay, I said I wasn't trying for that, but I couldn't say no to a challenge 😄. Now I can say I have an example mission which (might) satisfy that criterion. At least in the few tests I've done, the ambushers wins a majority of the time. I added some improvements to the VehicleTargets class, so now it makes the LOS requirements mandatory before spawning vehicles, and it sorts the positions with a weighted average calculation similar to those used with selectBestPlaces. The result of those efforts is demonstrated by this mission, in which a convoy of 4 BLUFOR tanks drives along a road and is ambushed by 4 OPFOR tanks which are placed by a genetic algorithm. Since Arma's tank AI is insane and will choose to turn its back to enemy tanks in response to a threat, I disabled the OPFOR's ability to move, and used TOV_fnc_SimpleConvoy (from https://forums.bohemia.net/forums/topic/226608-simple-convoy-script-release/) to drive the BLUFOR tanks down the road. Here's an example of one of the ambushes it generated during my tests: After a couple of minutes the remaining two red tanks worked up the courage to move forward, did manage to take out the blue tank in the road, but were promptly destroyed. Edit: On starting the mission, pull up the map. It will take a minute or two for the OPFOR to spawn, but you can watch the positions evolve as orange dots on the map. You can get the example mission here: "Tank Trials" Example Mission: (added 9 April 2022) https://github.com/dwringer/ANIMA/releases/tag/EXM-220409-A
  6. I have always thought this should be something easily done in the editor, but sadly you're right that the kind of triggers and extra waypoints it takes become very messy. I think the best way to do it instead is using a trigger and/or scripts to add a new waypoint (possibly a new seek & destroy waypoint at their current location, or a place nearby from which they'll be able to engage the spotted enemies) immediately before the one they were going to, and set that as their current waypoint. Check out the documentation for addWaypoint, setCurrentWaypoint, and currentWaypoint. You can provide an index to addWaypoint that will place it immediately before the waypoint they were already going to, use currentWaypoint to find out what that waypoint's index is. Unfortunately the whole process may require a bit of trial and error as you get used to the scripting side of it. Also check out the other pages on waypoints at the wiki. Sorry, I wish I had a simpler answer but maybe someone else has some ideas.
  7. dwringer

    How do you use your editor & script?

    Couldn't agree more with this, to me the challenge of creating something dynamic that can surprise even the creator is an endless pursuit that puts Arma head and shoulders above anything else.
  8. dwringer

    Call or Spawn

    I believe you meant to say a scheduled environment can never "turn into" an unscheduled environment. The way I'd say it is that "call" will always block until a result is returned (and can't sleep/wait), but if you use "spawn" your code will go off into a new thread where you are free to sleep, wait, "call" other things, whatever. One is also free to use "spawn" inside of a "call". But the call will return without any guarantee that the spawned code finished. At the end of the day, when you use "call" the return value you get will be the result of the called code. If you use "spawn" then the return value will be immediate, and it will be a script handle identifying the spawned thread which will go on running in parallel with the code in the context that called it.
  9. dwringer

    How do you use your editor & script?

    I think this is a really interesting question, bound to get all sorts of different answers from different people. For me, the editor has both strengths and weaknesses. Setting up waypoints in the editor has never felt right to me, because units have so much agency of their own and there are so many subtle aspects of waypoint assignment that by the time you get things working the way they should according to common sense (IMO), you've had to add all kinds of extra code and workarounds to triggers, unit init fields, and waypoint On Act fields. What the editor gets very right, IMO, is the trigger system. These can be used for all kinds of things, from simple mission init scripts and waypoint switching, to marking out areas and gathering units together to send to script functions. I really try to make full use of unit inits and triggers to do anything they can be made to do. I like putting the code here because it's easy to see in the editor and doesn't require me to Alt-Tab and navigate through labyrinths of folder structure and page through thousands of lines of code. When it comes to waypoints, I do use them in the editor because it's a lot easier than scripted solutions, but for complicated scenarios I still prefer to script them. Particularly if I want them to be dynamic in some way. I often use Game Logics to represent points in space to feed into my scripts. But, again, I often put extensive scripting inside triggers and init fields, rather than in separate files. All that said, I tend to have a huge library of function-defining scripts that I include with every mission, mostly to give me the ability to write code in the way that's most comfortable to me, with abstractions that are familiar to me. I don't like to define functions inside the editor unless it's a one-off.
  10. If the systemChat outputs anything at all, that means _filter is provably not empty. That means there is absolutely no way that "if(_filter == "") exitWith {[]};" isn't skipped. _filter is provably not equal to "", and since it's private we know it couldn't have changed. I guarantee if it printed something from the systemChat, it does skip the "if(_filter == "") exitWith {[]};" code. I can't see what the issue is because I don't know what the rest of your code looks like.
  11. If you see something output by systemchat, then the "if(_filter == "") exitWith {[]};" will be skipped, always. The systemchat confirms if _filter has a value, while the exitWith line only activates if _filter is empty. If this is working in some cases and not others, like if it prints "APC" but doesn't do anything else, it's because VVS_pre_APC doesn't work right.
  12. Hmm, I should perhaps not have used "artificial intelligence" as a tag for this because it doesn't affect unit AI in any way, but I still think of it as more of a generalized disembodied AI. Literally the only thing the VehicleTargets example does is pick places to spawn the vehicles. There are alternative ways of doing this including selectBestPlaces and silola's amazing DAC functions, but this is just a variation on that which uses a genetic algorithm to try to find the positions by evaluation a series of functions. You're right that if it can't win over 50% of the time in a 1v1, then it's not "superior", but that's not the goal here. The goal here is to be "better than randomly placing the tank somewhere in the area" or "better than the result you get using selectBestPlaces". It would be great to have such good positions as to win in a 1v1 fight, but at this time that's not the intention. The OPFOR are not given any information at all. The position finding algorithm is given two lists: one list of GameLogics which are placed along the approach BLUFOR will be taking. Positions are selected to be hidden from these gamelogics if possible. The second list is a list of GameLogics which are "kill zone" indicators. Positions are selected to have partial LOS to these logics when possible (and they are turned to face the first one to which they have LOS). As you say, sometimes the placements are ideal and other times they are imperfect. One use of this might be to run it a few times, take note of the most effective positions, and then use that knowledge to manually set up mission events. But I still enjoy the randomness for setting up skirmishes. ANIMA is really intended for people to mess around with the genetic algorithm to try creating their own position finding algorithms, or perhaps think up novel uses that I haven't implemented (of which I'm sure there are plenty). Things like the VehicleTargets and Headquarters classes, and other things from the example missions, are just examples of the applications and definitely leave room for improvement. Final Edit: I should say again, though, I appreciate your feedback and taking the time to check it out. You have definitely given me helpful things to think about. The real idea behind the VehicleTargets script was not actually to set up ambushes, but it emerged as a possible use. As the name hints, it was written to create (empty) vehicles to use as target practice, and I developed it originally on the flat tank ranges of the Hebontes map.
  13. Hey all, I'm still far from anything resembling a new release, but I feel the ANIMA engine is in good enough shape where developing applications is an equally worthwhile use of time. Here's a new example mission, showing a new application of ANIMA. Instead of creating group waypoints, this time ANIMA's position finding is used to place vehicles in a given trigger area. The vehicles are placed near cover/concealment, near roads, with LOS to some specified targets, and hidden-from-view with respect to other specified targets. The file ./classdef/VehicleTargets.hpp contains all the code that implements the new application (relying on the ANIMA system). Open the mission in the editor: Now launch it, and immediately bring up the map. You'll see some orange dots as the ANIMA algorithm evolves some positions at which to place vehicles: After the evolution process has yielded enough suitable positions, vehicles will be spawned at the found positions. These vehicles are chosen from those which were placed inside the trigger at mission start. Here you can see a few vehicles, all poised for ambush of the position at the intersection just above-right of screen center: An example of one such position, with a partially covered LOS to the ambush location: A BLUFOR tank is approaching, and you should see it enter combat around the time it reaches the targeted intersection. OPFOR positions are randomized, so it will play out differently each time, but BLUFOR is all but guaranteed to lose due to the ambush (and being significantly outnumbered). The example mission can be obtained here: https://github.com/dwringer/ANIMA/releases/tag/EXM-220407-A EDIT: Last night it was working pretty well, but today when I ran it there always seemed to be a tank that wanted to spontaneously explode itself 200m into the air. I tried to use BIS_fnc_findSafePosition to avoid this but I'm not sure if it does more good than harm. The algorithm could be tweaked to find better/safer positions but it would get a lot slower. Anyway, it works a lot better on flatter terrains in that regard.
  14. Sorry but I think there's some confusion. I'm not the OP, I was offering the OP a possible explanation for why the last car in his chain isn't being triggered. I should have clarified that's who I was replying to. My suggestion is that the second-to-last car is initialized so close to its move waypoint, that as soon as it is ordered to move into its trigger area, the waypoint is marked as complete (before the vehicle enters the trigger area!). Then, the second-to-last car just drives off without ever going into its trigger area to trigger the last car. I could be wrong, that's just what I would suspect.
  15. Although I can't see the blue/black lines linking the trigger/waypoints of the second to the last car (on the upper side), I assume they are there as you described. If they are then my thought is that the second to last car is starting so close to its "MOVE" waypoint that as soon as its switched, the "MOVE" is considered complete and thus that car never actually moves through its trigger. Vehicles don't need to get all the way to their waypoint for it to complete, although they usually will, but if they are close enough when its assigned they never actually move. In this case I believe the second-to-last car is doing this, just skipping its first MOVE right onto the next one and bypassing the small trigger area.
  16. I'm not certain but I think it might be that your variables _playerJailTimeAdjusted and _playerReleasedEarly are only defined for the first time within the loop. Outside of the loop they have no meaning, or at least not one that's well-defined. That is, they get set to true but only temporarily, so at the end during the switch they are undefined. Try adding: private ["_playerJailTimeAdjusted", "_playerReleasedEarly"]; before the loop, in the outermost script context. That will declare them in the same context as the switch, so when they get set to true they will stay that way.
  17. dwringer

    COPY RIGHT?

    It's interesting that the recommended licenses are a bit more restrictive than the ones a lot of people use. For example, I release my code under MIT license, which is pretty lenient aside from attribution requirements. I'm not sure if the requirements of the end-user license confer additional restrictions or not, and I'd imagine the specifics are difficult to sort out, differ by country and require a legal expert for real assurances. The forum rules here, though, are rather explicit (and really mirror common sense): permission is required to reuse anyone's work for any reason. This can take the form of a permissive license, or a verbal agreement, or anything else, as long as it would stand up to an independent audit. Without permission, the code should not be used.
  18. Great project here! I have encountered something strange and I wonder if it's a known issue or perhaps I'm missing something. EDIT: Sorry, I should have done more testing before posting here: the problem I'm having is not related to this mod. Solved below, I'll leave this here since it's at least tangentially related:
  19. The OP is using the word "class" in the abstract sense, defining an ad-hoc "unit class" entirely through SQF and then calling the appropriate "methods" based on that. I wrote an SQF library to do this a few years ago but it's showing its age because SQF didn't have hashmaps back then. I use the technique in all my scripts, though. Sorry I don't have just the class code as an up-to-date release somewhere and it's probably a lot more complicated than this particular scenario, anyway.
  20. dwringer

    CfgSFX & Sounds

    Please take a look at the wiki pages for CfgSounds and CfgSFX that I linked. The page for CfgSFX clearly answers your question under the heading "Class Structure". I'm afraid that you've got sections of one mixed in with sections of another - the syntaxes are different, you can't mix them.
  21. dwringer

    CfgSFX & Sounds

    According to the Wiki entry for CfgSFX, these are played "either directly with setSoundEffect command or indirectly with createSoundSource command". But in your example, stEveLoop is what you defined in CfgSounds, and stEveLoop1 is what you configured with CfgSFX. I believe as for your CfgSounds entries, these are done with say3D, which has a variety of syntaxes but simplest is speakerName say3D stEveLoop; EDIT: Sorry I hadn't followed closely enough, so I see that the CfgSounds entries are invalid and this won't work.
  22. ANIMA - Vybor Airbase example mission SITUATION In a surprise attack, Russian forces from the northeast have captured the Pobeda dam and are expected to launch a combined assault on Vybor airbase imminently. What they don't know is that it wasn't actually a surprise, and in preparation we've received a large shipment of AA and AT missiles along with a state-of-the-art backpack-sized UAV control terminal from the CIA (who were also kind enough to grant us the use of an MQ-9 Reaper currently flying in from the south). An airborne platoon will also be arriving by Ghost Hawk to reinforce, but they are still a few minutes out. MISSION It's imperative that we knock out the incoming armor and clear the skies before our reinforcements arrive. Your task is to take control of the MQ-9 Reaper and ensure these goals are accomplished. EXECUTION Activate your UAV terminal and take out the Russian armor ASAP. There are some launchers beside you that can also be used to take out enemy aircraft and vehicles. I've created a development overview guide to go along with the Vybor Airbase example mission, as well as expanded the mission significantly with more units on both sides and a winnable goal (destroy all the enemy armor). After the armor is destroyed, the player should get an action menu option to end the mission within 5-30s (sorry, there's no real notification). With the guide I've tried to explain every aspect of how the triggers are used along with ANIMA, but it's still intended as a companion to actually looking at the mission in the editor. DOWNLOAD LINKS: The mission itself can be downloaded from: https://github.com/dwringer/ANIMA/releases/tag/WIP-220322-A Development overview guide written to accompany the mission: https://github.com/dwringer/ANIMA/blob/main/ANIMA%20Guide%20-%20VyborAirbase.pdf
  23. You're too kind... you may notice that the dates in some of the source code files go back to 2016 or even earlier. That's basically because I had only the most rudimentary grasp of the codebase myself, in spite of having written it. I finally decided that it's at least useful enough for throwing together quick editor skirmishes that it would be worth documenting and releasing. This is in fact something that originated in 2012 for Arma 2, when I would actually spawn soldiers and check their knowsAbout to judge line-of-sight between positions (checkVisibility didn't exist yet and I wasn't trying to use it dynamically in missions). My primary motivation was to be able to quickly figure out where to place waypoints in the 2D editor where the AI would engage each other from a distance (it was hard for me to tell such things just looking at the topographic map). The automatic waypoint creation code could definitely be better, I think it's overly complicated in some areas and lacking basic functionality in others. As I wrote the documentation and started working on example missions I encountered many bugs, and I expect there are many more I haven't gotten to yet. Also, the actual objective functions that I wrote for the genetic algorithm are pretty basic and often not what I'd really consider ideal. Aside from code optimization, I think this is where most of the potential for improved performance lies. I'd love to write a guide on the process of creating and combining these if I get a chance, but to me at the moment it's more of a black art than science. I do plan to release an overview guide of how I put together the Winter example mission, how triggers and scripts interact, things to watch out for, etc., hopefully in the next day or two.
  24. Just a couple of things to point out here. Calling 'this execVM "savetheflag.sqf"' does two things of note: it provides "this" as the left side argument to "execVM", and it returns a script handle back to the context in which it was called. In the flagpole's "init" context, "this" refers to the flagpole itself. Thus you are providing the flagpole object directly to the script - there's no need to give it a name at all. The fact that execVM returns a script handle is a problem - an object's init field CANNOT return a value. So, your call to execVM ends up return a script handle where NOTHING should be returned. This is fixed easily, just change it to: _handle = this execVM "savetheflag.sqf"; now _handle is asisgned the return value, and the init field code as a whole returns nothing. Well, for one thing, the [ ]; around the outside are unneccessary and incorrect. [ <stuff>, <stuff>, <...>] is an array declaration, not an SQF statement. So get rid of those. The other point to note here is that since we passed the flagpole object directly to the script (with "this" in our execVM call), we don't need to use its name. Your line: _USFlag = ["USFlag1"]; Is assigning _USFlag with an array, the first element of which is a string. What we want to do is assign _USFlag with a single object. If you wanted to continue (redundantly) using the flagpole's name, then you would just write that as: _USFlag = USFlag1; No quotes are used because it's the proper global name of an object. However, since we passed the flagpole to the script, you can instead do: _USFlag = _this; In a script call, _this always refers to the entire left-side argument that was used in the original invocation. Thus, "_this" in the SQF corresponds directly to "this" in our execVM call.
  25. dwringer

    unit has string in name

    Oh that's awesome, I didn't realize there was regex matching built in. Learn something new every day even after nearly two decades, lol. EDIT: well at least I see that it was a relatively recent addition, heh.
×