ata_sa Posted June 24, 2023 Posted June 24, 2023 Hi all, I am new to scripting and I have been studying some tutorials. So far I have made some simple scripts. My goal is to create something like this. I would be glad if you help me. lets say I have X number of cargos and 1 cargo drop zone ... Per each cargo I unhook in the zone, one group unit is activated (total X number of groups). Units do not have to be linked to specific cargo crate, they can be activated randomly from a list of X number of groups. Thanks :)
ata_sa Posted June 24, 2023 Author Posted June 24, 2023 I have another question: I have 4 zones and some ground units. I want to give 20 score to blue team if they capture 1 city (at least 1 unit in zone means flag is on). So if units capture all, blue team has 80 scores. In this code I create a flag for city and if a unit enters this city the flag is on and if not flag is off (using toggle). Later on at mission goals section I use these flags to give score. (If flag is true ... Score <20>) I was wondering how can write this code in less expensive way ? so it does take lots of CPU calculations ? do mist.flagFunc.units_in_zones{ units = {'[blue][vehicle]'}, zones = {'Red City - 1'}, flag = 61, interval = 5, toggle=true } mist.flagFunc.units_in_zones{ units = {'[blue][vehicle]'}, zones = {'Red City - 2'}, flag = 62, interval = 5, toggle=true } mist.flagFunc.units_in_zones{ units = {'[blue][vehicle]'}, zones = {'Red City - 3'}, flag = 63, interval = 5, toggle=true } mist.flagFunc.units_in_zones{ units = {'[blue][vehicle]'}, zones = {'Red City - 4'}, flag = 64, interval = 5, toggle=true } end
Grimes Posted June 29, 2023 Posted June 29, 2023 On 6/24/2023 at 4:56 PM, ata_sa said: I was wondering how can write this code in less expensive way ? so it does take lots of CPU calculations ? Dissect what those functions are actually doing and re-purpose it for your own needs. Think of it like this, with that script you are telling it to iterate all blue vehicles for each zone. This means that it is getting the location of the same unit 4 different times and comparing it to each zone. Furthermore by your own rules only one unit has to be in the zone for it to be captured. That script doesn't know that, which means if may find the first unit in the zone on the first check, or it might find that unit on the last check, and anywhere in between. Point is it is probably checking units when it doesn't need to. local blueUnits = {} -- assumes list of unit objects. local zones = {{zone = 'Red City - 4'},{zone = 'Red City - 3'}, {zone = 'Red City - 2'}, {zone = 'Red City - 1'}, } --saved as tables so that you can save or set values associated with each zone. local function checkZones() local cZones = mist.utils.deepCopy(zones) local num = 0 for i = 1, #blueUnits do local unit = Unit.getByName(blueUnits[i]) if unit then local pos = unit:getPoint() for j = 1, #cZones do if not cZones[j].found then if unitInZone == true then -- whatever your code for checking it is, whether its a circle or polyzone -- set flag if needed cZones[j].found = true num = num + 1 end end end end if num == #cZones then -- once all zones have 1 unit then the loop can be broken out of break end end end On 6/24/2023 at 3:55 AM, ata_sa said: lets say I have X number of cargos and 1 cargo drop zone ... Per each cargo I unhook in the zone, one group unit is activated (total X number of groups). Units do not have to be linked to specific cargo crate, they can be activated randomly from a list of X number of groups. Unfortunately we don't have a cargo unhook event which means you have to constantly check the position of the cargo objects to determine if it is in a zone. local dropZones = {"dz1", "dz2"} local crates = {"c1", "c2", "c3"} local rngGroups = {"g1", "g2"} for i = 1, #crates do local so = StaticObject.getByName(crates[i]) if so then local point = so:getPoint() for j = 1, #dropZones do if mist.utils.get2DDist(point, mist.DBs.zonesByName[dropZones[j]].point) < mist.DBs.zonesByName[dropZones[j]].radius then -- only works for circle zones local ng = mist.getGroupData(rngGroups[math.random(#rngGroups)] -- picks random from list local offset = {x = point.x - ng.units[1].x, y = point.z - ng.units[1].y} -- figures out the difference of where the group was placed at vs where it will be ng.units[1].x = point.x -- redfines start point X ng.units[1].y = point.z -- redefines start point y if #ng.units > 1 then for u = 2, #ng.units do --- offsets other units in the group ng.units[u].x = ng.units[u].x + offset.x ng.units[u].y = ng.units[u].y + offset.y end end ng.clone = true -- sets the group as a clone so it creates a fully new group. mist.dynAdd(ng) -- spawns a new group so:destroy() -- removes the crate crates[i] = nil -- removes the crate name from the list end end end end The right man in the wrong place makes all the difference in the world. Current Projects: Grayflag Server, Scripting Wiki Useful Links: Mission Scripting Tools MIST-(GitHub) MIST-(Thread) SLMOD, Wiki wishlist, Mission Editing Wiki!, Mission Building Forum
ata_sa Posted August 24, 2023 Author Posted August 24, 2023 (edited) Thanks @Grimes for your effort and valuable time . Looks amazing. Some questions: For the first line can I do ? local blueUnits = {[blue][vehicle]} I want this function for any type of vehicle enters the area. I dont have specific list. --------------------------------------- if unit then this means if any unit available ? ----------------------------------------- local pos = unit:getPoint() This function returns location of the unit. However, pos is never used anywhere ? ------------------------------------- if not cZones[j].found then What is this part for ? if unitInZone == true then -- whatever your code for checking it is, whether its a circle or polyzone -- set flag if needed sorry I dont understant this part ------------------------------------- -- set flag if needed for each city I set one flag, my flag numbers are 64,65,66,67 to use in score section. so should I write flag=63+j in this part ? How can I toggle this flag ? for exampe if one city is out of units this will turn off the flag for that city. Edited August 24, 2023 by ata_sa
Solution Grimes Posted August 25, 2023 Solution Posted August 25, 2023 Yes you can define the blueUnits table however you want. However {"[blue][vehicles]"} is a special thing that a few mist functions use. Otherwise it will do nothing simply because it is looking for a specific unit name "[blue][vehicles]". local blueUnits = mist.makeUnitTable({"[blue][vehicle]"}) 22 hours ago, ata_sa said: this means if any unit available ? Its checking a list of unit names, you don't have the unit object at all which is what is used to get where that unit is at. If Unit.getByName("whatever") doesn't return anything then that unit is dead. It isn't saving the unit object anywhere so each time its gotta get the object again. 22 hours ago, ata_sa said: This function returns location of the unit. However, pos is never used anywhere ? I left the part where it would be used blank, hoping to A. not do all of the work for you. B. You can figure it out. local zone = trigger.misc.getZone(cZone.name) if mist.utils.get2DDist(zone.point, pos) < zone.radius then -- whatever your code for checking it is, whether its a circle or polyzone trigger.action.setUserFlag(cZone.flag, 1) --- action to set the flag end 22 hours ago, ata_sa said: for each city I set one flag, my flag numbers are 64,65,66,67 to use in score section. so should I write flag=63+j in this part ? How can I toggle this flag ? for exampe if one city is out of units this will turn off the flag for that city. I'd just define it in the zones table. {zone = 'Red City - 2', flag = 65}, {zone = 'Red City - 1', flag = 64} Toggling it off would be just a simple check at the end for each zone. Put it outside of the loop iterating the units. You could make it smarter to check if the flag is enabled true before setting it to false, but that doesn't really matter all that much. Same goes for setting it to true. for i = 1, #cZones do if not cZones[i].found then trigger.action.setUserFlag(cZones[i].flag, 0) end end 22 hours ago, ata_sa said: if not cZones[j].found then What is this part for ? An optimization. For the sake of argument you have 2000 blue ground units in the mission, how many need to be in each zone for it to set the flag to true? If it is just 1 then you don't need to check that zone anymore once the requirement was reached. If no units are in the zones it is running 8000 checks. If the first unit it checks is in the first zone then it will just need 5999 checks. Which is what the break lower down is for because it occurs if units are found in all zones, it stops checking the remaining units because it doesn't need to. 1 The right man in the wrong place makes all the difference in the world. Current Projects: Grayflag Server, Scripting Wiki Useful Links: Mission Scripting Tools MIST-(GitHub) MIST-(Thread) SLMOD, Wiki wishlist, Mission Editing Wiki!, Mission Building Forum
ata_sa Posted August 25, 2023 Author Posted August 25, 2023 (edited) Dear @Grimes Thanks for your time again. Your explanations are amazing. I am re-writing the code and I will try on DCS I may have a mistake at local zone = trigger.misc.getZone(cZone.name) part why do we have to write cZones[j].found = true ? Doesnt is automatically become true if there is 1 unit in the city according to your last comment ? If it does not automatically become true and we use cZones[j].found = true , then when it checks next time (if not cZones[j].found then) and imagine that the unit left the city this will stay remain true. sorry I am very new to this and struggling alot to understand all functions ... local blueUnits = mist.makeUnitTable({"[blue][vehicle]"}) -- need to make table since [blue][vehicle] is not a unit name local zones = {{zone = 'Red City - 1', flag = 64},{zone = 'Red City - 2', flag = 65}, {zone = 'Red City - 2', flag = 66}, {zone = 'Red City - 2', flag = 67}} local function checkZones() local cZones = mist.utils.deepCopy(zones) local num = 0 for i = 1, #blueUnits do local unit = Unit.getByName(blueUnits[i]) if unit then local pos = unit:getPoint() for j = 1, #cZones do if not cZones[j].found then trigger.action.setUserFlag(cZones[i].flag, 0) local zone = trigger.misc.getZone(cZone[j].name) --- mistake ??? if mist.utils.get2DDist(zone.point, pos) < zone.radius then -- whatever your code for checking it is, whether its a circle or polyzone trigger.action.setUserFlag(cZone[j].flag, 1) --- action to set the flag cZones[j].found = true num = num + 1 end end end end if num == #cZones then -- once all zones have 1 unit then the loop can be broken out of break end end end Edited August 25, 2023 by ata_sa
Grimes Posted August 25, 2023 Posted August 25, 2023 local blueUnits = mist.makeUnitTable({"[blue][vehicle]"}) -- need to make table since [blue][vehicle] is not a unit name local zones = {{zone = 'Red City - 1', flag = 64},{zone = 'Red City - 2', flag = 65}, {zone = 'Red City - 2', flag = 66}, {zone = 'Red City - 2', flag = 67}} local function checkZones() local cZones = mist.utils.deepCopy(zones) local num = 0 for i = 1, #blueUnits do local unit = Unit.getByName(blueUnits[i]) if unit then local pos = unit:getPoint() for j = 1, #cZones do if not cZones[j].found then local zone = trigger.misc.getZone(cZones[j].name) --- typed cZone[j].name instead of cZones[j].name if mist.utils.get2DDist(zone.point, pos) < zone.radius then -- whatever your code for checking it is, whether its a circle or polyzone trigger.action.setUserFlag(cZones[j].flag, 1) --- action to set the flag cZones[j].found = true num = num + 1 end end end end if num == #cZones then -- once all zones have 1 unit then the loop can be broken out of break end end for i = 1, #cZones do --- check it down here. The way you had it would set a flag off a ton if not cZones[i].found then trigger.action.setUserFlag(cZones[j].flag, 0) end end end This is more what I had in mind with the setting flag to 0 at the end of the check. The way you had it the setUserFlag function would run for every unit until one was found to be in the zone. It just needs to run once. if not someCondition means that if that it will do that check if it isn't present. The function doesn't change which zones are listed in the cZones table, it just adds a value to one of them. A change mind you that is temporary because cZones is a true copy of the zones table. Anyway it'll check all 4 zones for that value and then for each zone that doesn't have it, it will check the position of the units relative to the zone. Think of it as it just skips the zone that has already been found. The right man in the wrong place makes all the difference in the world. Current Projects: Grayflag Server, Scripting Wiki Useful Links: Mission Scripting Tools MIST-(GitHub) MIST-(Thread) SLMOD, Wiki wishlist, Mission Editing Wiki!, Mission Building Forum
ata_sa Posted August 25, 2023 Author Posted August 25, 2023 (edited) Dear @Grimes thanks for your help. I appreciate that. I understand that you used if not cZones[j].found then to check if the zone is already accupied code does have to search anymore for that zone (it does not pass the if not condition.) But now if the zone is occupied cZones[j].found = true this value becomes true. However, even if the zone gets empty this value remains true for ever. Also our outer loop is for i = 1, #blueUnits do this means that all units will be checked once and then loop will be closed. How does this work for DCS ? Does DCS keeps running this script over and over again every second ? Edited August 25, 2023 by ata_sa
Grimes Posted August 25, 2023 Posted August 25, 2023 You run it as often as you want. Either by just throwing it into a trigger action and executing that trigger action every so often. Or by adding the whole thing to its own function and then using timer.scheduleFunction to call it at the set interval. The right man in the wrong place makes all the difference in the world. Current Projects: Grayflag Server, Scripting Wiki Useful Links: Mission Scripting Tools MIST-(GitHub) MIST-(Thread) SLMOD, Wiki wishlist, Mission Editing Wiki!, Mission Building Forum
ata_sa Posted August 25, 2023 Author Posted August 25, 2023 (edited) I think if I add this line it will solve my problem: first lines ... local function checkZones() local cZones = mist.utils.deepCopy(zones) local num = 0 Then this line for m = 1, #cZones do -- when DCS trigger starts running code again it will set all founds to false otherwise the zone with previous true value will never be checked again cZones[m].found = false end 40 minutes ago, Grimes said: You run it as often as you want. Either by just throwing it into a trigger action and executing that trigger action every so often good point ! I found this comment from old topics : Once("kickstart loop") -> (desired condition) -> Set flag (X) Switch Condition ("Restart/reset loop") -> Time Since Flag(X, desired time) -> Clear Flag (X), Set Flag(X), Run the script Edited August 25, 2023 by ata_sa
Grimes Posted August 25, 2023 Posted August 25, 2023 43 minutes ago, ata_sa said: Then this line It isn't required local cZones = mist.utils.deepCopy(zones) Isn't a reference to the zones table, it is a completely new copy. Therefore cZones effectively gets deleted once the function is complete. It has a "fresh state" of what is in the zones table. That said the whole function could be written like you are keeping the data of the previous run. The right man in the wrong place makes all the difference in the world. Current Projects: Grayflag Server, Scripting Wiki Useful Links: Mission Scripting Tools MIST-(GitHub) MIST-(Thread) SLMOD, Wiki wishlist, Mission Editing Wiki!, Mission Building Forum
ata_sa Posted August 25, 2023 Author Posted August 25, 2023 (edited) 24 minutes ago, Grimes said: Isn't a reference to the zones table, it is a completely new copy. Therefore cZones effectively gets deleted once the function is complete. It has a "fresh state" of what is in the zones table. That said the whole function could be written like you are keeping the data of the previous run. wow amazing ! Thanks I only need flags from previous run so this is ok Edited August 25, 2023 by ata_sa
ata_sa Posted August 25, 2023 Author Posted August 25, 2023 (edited) I tried this code but it is not working. Switched condition is created and works correctly (attached picture). There is no error when code is run but when I put units in the zone flag does not turn on. I used a message code as shown below to see if it enters this if conditions. It seems that it does not since I dont get the message. I even placed the message after local function checkZones() but got no output local zones = {{zone = 'Z1', flag = 1},{zone = 'Z2', flag = 2}} ... for j = 1, #cZones do if not cZones[j].found then local zone = trigger.misc.getZone(cZones[j].name) if mist.utils.get2DDist(zone.point, pos) < zone.radius then trigger.action.setUserFlag(cZones[j].flag, 1) local msg = {} msg.text = 'flag is on' msg.displayTime = 10 msg.msgFor = {coa = {'all'}} mist.message.add(msg) cZones[j].found = true num = num + 1 end ... Edited August 26, 2023 by ata_sa
ata_sa Posted August 29, 2023 Author Posted August 29, 2023 @Grimes After reading more about lua functions, I realized that this is a function so I need to call it somehow. Still struggling with this part
Recommended Posts