Jump to content

Scripting with MIST - Unit spawn by unhooking cargo


Go to solution Solved by Grimes,

Recommended Posts

Posted

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 :)

Posted

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

 

Posted
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 ServerScripting Wiki

Useful Links: Mission Scripting Tools MIST-(GitHub) MIST-(Thread)

 SLMOD, Wiki wishlist, Mission Editing Wiki!, Mission Building Forum

  • 1 month later...
Posted (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 by ata_sa
  • Solution
Posted

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. 

  • Thanks 1

The right man in the wrong place makes all the difference in the world.

Current Projects:  Grayflag ServerScripting Wiki

Useful Links: Mission Scripting Tools MIST-(GitHub) MIST-(Thread)

 SLMOD, Wiki wishlist, Mission Editing Wiki!, Mission Building Forum

Posted (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 by ata_sa
Posted
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 ServerScripting Wiki

Useful Links: Mission Scripting Tools MIST-(GitHub) MIST-(Thread)

 SLMOD, Wiki wishlist, Mission Editing Wiki!, Mission Building Forum

Posted (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 by ata_sa
Posted

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 ServerScripting Wiki

Useful Links: Mission Scripting Tools MIST-(GitHub) MIST-(Thread)

 SLMOD, Wiki wishlist, Mission Editing Wiki!, Mission Building Forum

Posted (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 by ata_sa
Posted
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 ServerScripting Wiki

Useful Links: Mission Scripting Tools MIST-(GitHub) MIST-(Thread)

 SLMOD, Wiki wishlist, Mission Editing Wiki!, Mission Building Forum

Posted (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 by ata_sa
Posted (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

...

image.png

image.png

Edited by ata_sa
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...