Jump to content

Best way to find out if a zone has units of a certain coalition alive in it?


Toumal

Recommended Posts

Hi,

I'm trying to find out, in LUA, whether a given zone has units of a particular coalition inside. Getting a callback for when the zone has no units alive inside would be also acceptable. So far I tried MOOSE's onEnterEmpty() which didn't fire, I tried using a filter expression ala SET_GROUP:New():FilterPrefixes("GROUP PREFIX STRING"):FilterActive(true):FilterStart(), but iterating using ForEachGroupAlive() returns me groups that are not nil, but when calling functions on them say they are nil....

So I figured I'd just ask: How can I find out, or get notified, when a zone has for example no red units in it anymore?

 

 

Link to comment
Share on other sites

Hi, make a SCHEDULER task to periodically filter objects from database, that are in your zone. I think the dead objects should be nil. Smallest interval is 1 second. I can post a snippet later, if you wish.

Wysłane z mojego MI MAX 3 przy użyciu Tapatalka

Link to comment
Share on other sites

I think this might be what you're looking for, but let me know. A function that will search a trigger zone for any object category and check if any of the found objects are of matching coalition. It will return as an array of objects if there is anything found that matches coalition and returns nil if nothing was found that matches coalition.

Here's an usage example of the function ScanZone:

-- variable for any found units
local UnitsInSenakiZone = ScanZone(Object.Category.UNIT, coalition.side.BLUE, "Senaki Zone")

-- simple check to print the found units or no found units
if UnitsInSenakiZone ~= nil then
    for _, object in pairs(UnitsInSenakiZone) do
        trigger.action.outText(object:getName().." is in Senaki Zone", 15)
    end
else
    trigger.action.outText("no units were found in Senaki Zone", 15)
end

Here's the script that contains the ScanZone function so you can include in your code/mission: ScanZone.lua

  • Like 1
Link to comment
Share on other sites

19 hours ago, Wizxrd said:

I think this might be what you're looking for, but let me know. A function that will search a trigger zone for any object category and check if any of the found objects are of matching coalition. It will return as an array of objects if there is anything found that matches coalition and returns nil if nothing was found that matches coalition.

Hey there, thanks a lot for the reply.

I gave that function a try, but unfortunately it didn't seem to work quite yet. Let's say I have a trigger zone called "BRAVO ZONE" which the function does find. I did notice that even though the radius in the mission editor was set to 1000, the searchZone.radius turned out to be an odd value: 304.79998779297
Worse, it was extremely inconsistent, sometimes it detected units properly, sometimes it did not. As it turns out, zone points are MSL, and I need to add terrain altitude.

The second problem: I have a single unit in BRAVO ZONE, yet when I iterate through the results I get this:

2022-01-12 17:55:45.544 INFO    SCRIPTING: Defenders alive in BRAVO
2022-01-12 17:55:45.544 INFO    SCRIPTING: ScanZone: Unit found: RED JULIET GROUP-1-1
2022-01-12 17:55:45.544 INFO    SCRIPTING: ScanZone: Unit found: RED JULIET GROUP-1-1#001-01

I get these results even after I kill said unit with tank fire from a player controlled tank (which is not part of that group, so that's not the reason for the two units). When I try to check for health getLife or IsAlive I get a nil pointer error. Turns out, the first object is a group, and the second object is the unit. Unless you do your object conditions in the right sequence, you run into nil errors.

 

In the end, I modified the function as follows, which works as expected:

function CaucasusPendulum.ScanZone(category, coalition, zoneName)

    local foundUnits = {}

    if trigger.misc.getZone(zoneName) ~= nil then

        local searchZone = trigger.misc.getZone(zoneName)
        -- new sphere searchVolume from searchZone
        local searchVolume = {
            ["id"] = world.VolumeType.SPHERE,
            ["params"] = {
                ["point"] = {x=searchZone.point.x, z=searchZone.point.z, y=land.getHeight({x=searchZone.point.x, y=searchZone.point.z})},
                ["radius"] = searchZone.radius,
            }
        }
        -- search the volume for an object category
        world.searchObjects(category, searchVolume, function(obj)

            -- if the found object is of the same coalition, add it to the table
            if obj ~= nil
				and obj:getLife() > 0
				and obj:isActive()
				and obj:getCoalition() == coalition then
                foundUnits[#foundUnits+1] = obj
            end
        end)
    end

    if #foundUnits > 0 then
        -- return the found units
        return foundUnits
    end

    -- return nil if no found units
    return nil
end

 

Thanks a lot for your help, I hope I could contribute back!

 

Link to comment
Share on other sites

To answer some of your questions, the reason the radius is 304.xxx is because it's feet converted to meters.
 
I'm not sure about that change made to ["point"], all it needs basically is the x and y unchanged (at least that's how I've always used it, but if it works, it works :D)
 
As for the issue of finding units that aren't supposed to be in that zone, the only way I could sort of replicate it is if there are units close to the outside perimeter of the zone, < 100 ft will find them "in zone".
 
I wasn't able to reproduce the issue where you returned both a group and unit object within the same foundUnits table, if you sent the Object.Category.UNIT as the category then it will only return unit objects so that one is puzzling me
 
But all in all glad you've made it work for what you needed!

Edited by Wizxrd
Link to comment
Share on other sites

Heya,

I had the issue that I needed a much larger radius for certain locations - mostly locations with a certain terrain elevation. Since using land.getHeight it works consistently. I think if you do a test case on a mountain top you'll find that you'll need a crazy large radius value for it to work, and zone.radius won't find a thing.

As for both unit and group being returned - yes that is the case, even with category.UNIT specified. What I found is that apparently everyone is doing this kind of alive check in their scripts (CTLD for example) which will only pass for the actual unit, not the group. That's appears to be the reason why they don't run into troubles.

 

 

 

 

Link to comment
Share on other sites

  • Recently Browsing   0 members

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