-
Posts
4303 -
Joined
-
Last visited
-
Days Won
5
Community Answers
-
cfrag's post in Unit in random defined area was marked as the answer
Not "vanilla" DCS. When you add one of the many frameworks available, it becomes trivial. See sample below (sample uses DML).
spawn random loc inside zone.miz
-
cfrag's post in Getting 1st Unit Name from a Group was marked as the answer
I believe that the following question may lead you to the answer:
Q: How do you known that a group died?
A: when the last unit from that group dies.
And that is the answer to your question: A group does not have a location, it has many units, and each of them has a their own location (in naval groups, they can be miles apart, as can be in aerial groups).
So, the condition "when a group dies" could be better written as "when the last unit of a group dies".
And that you can catch, by intercepting the unitLost or dead event. Now, be *very* careful when looking at dead events for ground units, because DCS can pull an undocumented fast one on you: it changes a ground unit into a static object that "cooks off". So what's the big deal? Well, a static objects has no group, and your script dies when it tries to access a static's group.
So although what you are trying to do would usually be a simple thing, for people who aren't very comfortable in DCS mission scripting, it will become a very frustrating experience. What you need to do is some "threading the needle" stuff: when groups spawn, keep a table that links each unit's name back to it's group name. When you receive a dead or unit lost event, get the group name from the table (not from the object, it could be a static), get the number of remaining units in the group. If it's zero, the last unit died, and you can remove the group from your table, and place the explosion and smoke on the location of the object that just dies.
It's going to be a lot of work for a simple thing. But it may be a learning experience, and even fun.
-
cfrag's post in Kill, explode, or crash a unit via mission scripting (by invoking trigger action) was marked as the answer
Since we currently cannot influence AI or AI units in a meaningful way (except through drastic ways just like the ones that you suggested), your approach seems to be workable. Setting zero fuel should get most AI planes to have the pilots bail out and the plane plummet to ground - if that was possible (spoiler: it's not). The good old explosion(unit:getPoint(), 30) should also do it, albeit a bit more visceral.
Ah, then an explosion seems fitting 🙂
I think (and that does not mean a lot) that current implementation of unit AI only kicks in with that event when the unit runs out of fuel (? undocumented) or damage (somewhat documented). So, re-top up regularly so they don't run dry.
The spanner in the works is of course that we currently cannot set a unit's fuel nor life. A colossal oversight for a military sim scripting engine, but that's DCS for you.
It won't fail in MP. The script runs on the server, and all clients sync to the server eventually. If the server thinks that a unit is dead, it is dead and removed from all clients). It will work in MP. IMHO, the most reliable way to remove a unit is destroy(), but 'setting them up the bomb' by explosion() is a lot more satisfying, and you can probably forego the destroy() yourself (schedule a timed destroy() two minutes in the future just in case)
There is the kludge approach: in the event handler that detects the unit aborting, set a named flag (I use the unit's name plus "_k" to keep this part short). Then create a trigger rule for every (messy, messy, messy!) unit that triggers on that named flag (e.g. FLAG TRUE "aerial-1-1_k") to execute the trigger for the actions (unit set life, explode). So, if you have 20 units that can abandon the mission, you'll have to create 20 separate trigger rules, one per unit. Very kludgy, very messy, extremely difficult to maintain, and wholly depressing from a scripting perspective. It really is a shame that DCS's mission scripting environment is in such a bad, amateurish state.
-
cfrag's post in GetDevice(device_id) in DO SCRIPT FILE was marked as the answer
Ah. Make sure that you try this in the "mission" environment in the console first. It is well possible that GetDevice() is only avialable for the "export" environment
-
cfrag's post in Smoke marker scripting function? was marked as the answer
Trigger.action.smoke() is the correct effect, as used in ME. You may want to adjust for terrain elevation by using land.getHeight, else most of your smoke is below the terrain.
-
cfrag's post in LUA Api reference was marked as the answer
Unfortunately, the official documentation for DCS mission scripting is next to non-existent, out of date, and misleading (at best). Hoggit is the best source of information available wrt mission scripting, and we owe @Grimes et al who maintain that site out of the good of their heart an immense debt of gratitude (THANK YOU!). And shame on ED for their continued one-finger salute to the entire mission creation community.
-
cfrag's post in AI Aircraft Radar Locked Trigger was marked as the answer
Currently this is not supported in DCS, not even with scripting. Also (nitpick), not all aircraft are equipped with RWR.
-
cfrag's post in Find the player in an existing mission - how? was marked as the answer
I'm not sure that there is such a function for ME, for the simple reason that multiple planes can be controlled by a player. If you want to find planes that can be player-controlled, your best bet would be to open the Units panel, and sort the units by Skill. Look for 'Client' and "player", and click on the unit. The screen should center on the unit that you just selected.
-
cfrag's post in Spawn group/unit at a circle on map?? was marked as the answer
That is because DCS's Lua API hates you. With a vengeance. What we have in DCS to support mission scripting is ill thought-out, does not seem to be engineered at all, and is unnecessarily difficult for neophytes who already do know how to program in Lua.
That being said, maybe I misunderstood your requirements. What are you trying to accomplish:
spawn some units at an in-game event (via F-10) at a pre-determined location, which happens to be a Mark (meaning that the spwan location is known when the mission starts up) or spawn some units at an in-game event at a dynamic, runtime player-determined location Above cases are very different. Both require spawning units. And spawning units at runtime (as opposed to late activation) is one hellish thing to learn simply because it requires you to absorb large parts of DCS's abysmal API and idiosyncrasies. It's one of the reasons why so many prefer using frameworks. Once you get beyond that, however, you have a powerful too at your disposal to create significantly better missions.
So, if "all" you need is to spawn units at some player-determined time, you will have to learn how to script spawning. Getting it done is painful, but manageable. Becoming good at it takes longer. Once you can spawn, however, since you know the location, the rest is straightforward.
Spawning units at a player-determined location requires a lot more, through. You can try and simplify the coding challenge by off-loading some complexity to the player (e.g. the mark must have a very specific text), but DCS provides very little by way of player script integration, so doing that will require a lot more understanding of DCS's API. So if you are looking to solve bullet two, you'll be in for quite a ride.
That does not mean that it's not worth the challenge, though. I'm close to being addicted to coding, and DCS's terrible API doesn't scare me any more. It still infuriates me, yes, but once you learn and abide by the silly nonsense, creating good missions in spite of the terrible API can be quite rewarding.
-
cfrag's post in X: cockpit highlight element action via script was marked as the answer
Not directly, no. But looking at what you are trying to do, i think that would be the least of your challenges:
Uh - you're in for a hellish experience here. Tutorials usually read/set cockpit switches and await control inputs using the miz actions "X" tree which are mostly unavailable via normal scripting (you can read the value of a cockpit/3D model item using unit.getDrawArgument(), but AFAIK you can't set it, so you'd have to resort to active polling and asking the player to change the setting of that model item. Each aircraft has it's own model items, they do not have standardized names, and finding an argument value for a specific plane for a specific switch is a painful procedure involving the model viewer.
Add to this the fact that in single-player you may be able to figure out what kind of aircraft "you" are flying, that is impossible in MP - the is no concept of 'I' in mission scripts.
What invocation is that? What does it do?
I believe everyone agrees that this would be great. Currently, I don't see a way to do it in vanilla DCS. Mayhaps if you have access to ED's private mission scripting tools for third paries.
-
cfrag's post in Trouble with Script - unit == null is skipped but crashed on "unit doesn't exist" was marked as the answer
Ah, the joys of DCS, mixed with one's own expectations. You already have all the pieces of the puzzle, and I think that you implicitly believe that one thing means the other (in a perfect world it would, but not Lua/DCS).
Let's go through the the steps one by one.
You enter your aircraft "Crasher" and depart. A status display call is scheduled in 20 seconds with a reference to your unit "Crasher". In computing terms, a 'reference' points to the memory location that contains data, here the data for unit "Crasher" One second later you crash your aircraft "Crasher" and it is removed from the game. The memory for that unit is freed - made available for other purposes. Your reference to "Crasher" still points to the memory location formerly assigned to "Crasher". 19 seconds later, your scheduled status display function is invoked. As part of the params that are retained is a reference to the (now crashed and invalidated) unit "Crasher" in uObject. Your code checks if uObject == nil. Your reference to "Crasher" STILL points to to the memory location that formerly contained the (now deleted) unit, meaning it is not nil, so the check correctly fails in Line 395 you now access uObject's method getLife() member via "uObject:getLife()". Unfortunately, uObject is no longer a valid object, and you get the "Unit doesn't exits" error So this is correct. A reference to a unit isn't nilled when the unit is destroyed, and a nilcheck to a cached unit (a saved unit reference) will not save you from this.
So, how do you protect against that? Many ways, one is to save the unit's name instead, and directly retrieve the unit by name before you try to access it:
uObject = Unit.getByName(uName) if not uObject then trigger.action.outText("Sorry, but unit object is nil",15) -- some spelling corrected return end
-
cfrag's post in Mission Editor Problems was marked as the answer
In the bottom right of the editor window is an icon that crudely resembles a wristwatch. That is meant to resemble a 'chronograph' and in DCS speak symbolizes the chronologically accurate filter. If it is on, you will only be able to access planes that are accurate for the time period of your currently selected year. Turn it off, and you'll regain access to all your aircraft and other units. It's really bad UX, yes.
-
cfrag's post in How to get the ObjectID that the user is currently spectating was marked as the answer
No. AFAIK, spectators have no representation in the game, i.e. for all intents and purposes they do not exist in the game at all.
-
cfrag's post in Ammo for ground troops was marked as the answer
Usually, it's one of the 'Unarmored' vehicles, e.g.
Truck M393 Heavy Truck KrAZ 6322 6x6 Trzck Ural-4320 Make sure that you position your troops inside the black 'supply radius' circle so they can get resupplied. The units may have to reside inside the same group
-
cfrag's post in Uncontrolled option for "my plane". was marked as the answer
Thank you! I've downloaded the Miz that you kindly provided. It relies (as far as I can tell) on @SUNTSAG's Pilot Ground Mod (availability unclear, I don't have it), which AFAICT is a ground unit mod, not intended to be a player controlled unit.
I believe that this feature was promised some time ago (active static to AI). But that's not for player aircraft. DCS unfortunately makes really big distinctions between player-controlled aircraft and AI. You can, however, put down a static plane as stand in for players, and simply remove that static at the 'birth' event when the player plane pops in. If you are going for cinematics, you'll then have to remove the small 'blip' when the planes are exchanged.
-
cfrag's post in Check if a point is within a Quad-Point Zone? was marked as the answer
There is if you are not too much terrorized by trigonometry, and can ensure that all your quad-point zones are convex (meaning that none of the angles inside the zone have more than 180° - the zone is then shaped like a "V")
If above restraints are met (most quad zones do), simple trig can come to the rescue, and you can test inside/outside with a few multiplications. The idea is that a point P is inside of a polygon ABCD if, and only if it is to the same side of all vertices AB, BC, CD and DA. If it isn't, it's outside the polygon. Which side a point P is to a line AB is determined by the direction of the normal vector to the two vectors PA and PB. The normal vector will either point up or down since the triangle PAB define a plane identical to DCS's XZ (ground) plane. Since the result is either positive or negative, we simply look at all four normal vectors. If they all have the same sign, the point is inside, otherwise it's outside. Calculating the normal vector is a simple matter of multiplication and subtraction, which is very fast.
Below is how DML determines if a point is inside a poly
function cfxZones.isPointInsideQuad(thePoint, A, B, C, D) -- Inside test (only convex polygons): -- point lies on the same side of each quad's vertex AB, BC, CD, DA -- how do we find out which side a point lies on? via the cross product -- see isLeft below -- so all we need to do is make sure all results of isLeft for all -- four sides are the same local mustMatch = isLeftXZ(A, B, thePoint) -- all test results must be the same and we are ok -- they just must be the same side. if (cfxZones.isLeftXZ(B, C, thePoint ~= mustMatch)) then return false end -- on other side than all before if (cfxZones.isLeftXZ(C, D, thePoint ~= mustMatch)) then return false end if (cfxZones.isLeftXZ(D, A, thePoint ~= mustMatch)) then return false end return true end function cfxZones.isLeftXZ(A, B, P) return ((B.x - A.x)*(P.z - A.z) - (B.z - A.z)*(P.x - A.x)) > 0 end
-
cfrag's post in Script to get coords of player lased target was marked as the answer
AFAIK, not in general (i.e. you can't get the location that an aircraft's targeting pod is looking at. There is a very interesting Gazelle-specific script by @CakeSorbus here:
The downside is of course that this script is only for the Zelle, and can't be generalized (I shudder to imagine the amount of sleuth work that it took CakeSorbus just to find out which parameters to access in the Gazelle). I know it's a bit silly that this kind of vital information (what location is a unit targeting now) isn't available in mission scripting, but I guess that's DCS for your. It would be great, if, for example, we could get this information from drones - but not right now. Or more specific: I don't know, and would love to be told otherwise.
That approach is tried and tested, works well, can be implemented reasonably easy - and is entirely over-powered, I'm afraid. Simply intercept the Mark event, and get the map point. Can be done in a couple of lines.
-
cfrag's post in Lua scripting error was marked as the answer
I feel it would be much better if you put in some more effort when requesting help. Everyone here loves to help, but if the question appears to be too low effort, people will answer in kind.
Now, I recommend that you tell us:
what you are trying to do How you approach this (usually showing the script helps a LOT) what went wrong, and how you know that that is wrong (a screenshot of the error helps) Now, to get you started, I looked at your code. You seem to be trying to get the AI to turn on/off navigation lights and some other stuff.
The offending code line is
unit:getController():setOption(AI.Option.NAVIGATION_LIGHTS, AI.Option.OFF) and the error is that the option is missing. Now the error is a bit misleading, and it seems that you never made sure that "AI.Option.NAVIGATION_LIGHTS" is a defined value in DCS. It is not. So AI.Option.NAVIGATION_LIGHTS returns nil, and that makes the error appear.
Where did you get these values (like AI.Option.NAVIGATION_LIGHTS) from?
Personally, I think that stringing together multiple invocations with ":" in Lua is asking for trouble. I recommend you get the controller, make sure that it's non-nil, and then invoke setOption on that. It's also faster since in your code the accessor to unit:getController() is executed multiple times.
-
cfrag's post in [ISSUE] "TransmitMessage" command via LUA script. was marked as the answer
This may be a silly question: how do you make sure that the audio file still is inside your mission? If you strip all the trigger rules that refer to your audio file, Mission Editor will also strip the audio file from the mission. This means that mission designers usually add a 'output sound' trigger for all audio files that are only referenced by Lua scripts to their missions, and these sounds play very late (some 9999999 seconds after mission start) to ensure that the sound files are present in the miz
-
cfrag's post in Mission file not showing up when starting a server was marked as the answer
It would seem that you have clicked on the (terribly named) 'open' button (that looks like a folder icon and would logically be correct) that in DCS, strangely, opens mission LIST files.
Nobody tells you that, but you should have clicked on the "plus in a circle" button to add a mission to the list of missions in the window above. If you do that, you'll be able to add your mission (that ends in .miz) to your server.
-
cfrag's post in Math(s) help needed was marked as the answer
Actually, in 3D that would be a random point on a sphere, and it can be done rather quickly by giving a radius (x miles), theta (random) and phi (random). Problem is: you'll probably want some more attributes, like the point having a certain altitude etc. If you are talking about a map, and you want a 2D point at x miles, that's even easier: take r (x miles) and random number between 0 and 360, and you have a random angle from that you can quickly calcualate x offset and y offset, add that to your current position, and you have a point on a circle around your point. You'll need to check the altitude again, but with that simple formula (radius and random angle), you can quickly resolve that issue.
So, if (X,Z) [in DCS, x and z are map coords, and y is altitude above MSL] is your current point, then make phi = math.random(360) * 0.0174533 [that 0.01... converts to rads] and r = distance you want
your new point is at (X + r * cos(phi) , Z + r * sin(phi))
Simple as that. Yupp, trigonometry all the way.
-
cfrag's post in Are there any community made missions that are like the training tutorials from ED that go step by step with instructions was marked as the answer
Yes.
[A snarky, unhelpful answer to a low-effort question. If you want other people to invest time in answering your question, I recommend that you at least afford them the courtesy of investing some effort into the question itself. Oh, and the full answer to your question is "Yes, and very good ones, too."]
-
cfrag's post in LUA Question was marked as the answer
If you are using plain vanilla DCS/Mission Editor, pasting script files has a small advantage in handling scripts should you develop scripts yourself: If you "doscriptfile", a copy of that script file is incorporated into the miz file; it is a 'snapshot' of that script at that moment. Any changes that you make to the script on your storage will NOT be included into your mission until you again select the file through the 'doscriptfile' action dialog. It is slightly easier to simply copy/paste the updated script into the doscript dialog.
Also, when debugging, the doscript option is slightly ahead of doscriptfile as doscriptfile prepends an illegible temporary file descriptor that gets in the way of identifying which table has caused the error.
NEITHER of them is comfortable or even remotely what one would expect of a program that was developed around the turn of the century/millennium, today the term 'unacceptable' comes to mind.
There is no performance benefit for either.
Unfortunately, that is currently not the case. Your script is read once, at the very moment that you choose it from the file dialog, and a snapshot copy of that file as it is on your storage at that exact moment is placed inside your mission. There are ways to do what @Pizzicato was kind enough to describe (load and execute external files at the moment that the mission is run), but these are advanced topics that in themselves are fraught with issues that you must be aware of (the mission is no longer portable - and this fact can be used as a poor man's copy protection, so to speak). I recommend that you only try that after you have some experience with mission scripts to appreciate the difference and feel the necessity.
Unless you are developing scripts yourself, it makes no difference what you choose to include scripts; when in doubt, do what the script provide recommends. If people use scripts that I have created, I tend to advocate "DOSCRIPT" as it makes it easier for me to trace an error should they run into one. YMMV.
-
cfrag's post in Can someone please check my understanding of this vector maths issue? was marked as the answer
Yes. Since you say that the direction that the aircraft moving in is normalized, it means that the magnitude of the direction is one. If you multiply that vector by the speed (itself a scalar value in m/s) you have the velocity vector for that aircraft. It is moving in that direction by that amount every second. So, to see where that plane will be in 7 seconds, multiply the velocity vector by 7, and add the resulting vector to the starting point. The result is the point where (no changes in speed or direction assumed) the plane will be in 7 seconds.