• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!

[Lua] Breaking ForGroup loop

Status
Not open for further replies.
In GUI there is "skip remaining actions" which means "return" in JASS. I wonder is it possible in Lua to break ForGroup in the middle.
Suppose we have 50 units in group and if any of these units has life lower then max, then we return false

I've tried this, but script always continues over all units on group
Lua:
function GroupHealthy(g)
   local result=true
   ForGroup(g, function()
       local u=GetEnumUnit()
       local l = GetWidgetLife(u)
       if l < BlzGetUnitMaxHP(u) then
           result=false
           print("damaged " .. GetHandleId(u) .. ", life " .. l)
           return -- <-- this doesn't work
       else
           print("full hp " .. GetHandleId(u) .. ", life " .. l)      
       end
   end)
   return result
end
 

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,202
It is not possible, just like how it is not possible with JASS.

In JASS if you "return" all it does is skip the rest of the current iteration and move on to the next. In other words a "continue". Unless there is some magical hard-coded behaviour I am not aware of.

A possible solution to this is a standard loop through all units. Using the new natives one can get the unit at a specific position from a unit group and break the loop when the condition is met. This sort of loop is faster for small groups but gets slower for larger groups due to the O(n) complexity of looking up a unit.
 
It is not possible, just like how it is not possible with JASS.
Of course you're right, I had too long break in programming War3 ;)
You can use firstofgroup
Yeah, I did just that many times, but it has downside by tracking a group for removed/dead units.

I found these new natives DSG mentioned and it seems best solution.
Lua:
function GetDisplayedHP(life)-- real as parameter --// displayed on UI
    local hp= math.floor(life) --//integer (cuts decimals)
    if life - hp > 0.00 then return (hp+1) end
    return hp
end

function GroupHealthy2(g)
   local count=BlzGroupGetSize(g)
   local u
   local life
     
   print("group size: " .. count)
   for i = 0, (count-1) do
       u = BlzGroupUnitAt(g, i)
       life = GetDisplayedHP(GetWidgetLife(u))
       print(GetUnitName(u) .. " at position " .. i)
       if life < BlzGetUnitMaxHP(u) then
           print("damaged " .. GetHandleId(u) .. ", life " .. life)
           break
       else
           print("full hp " .. GetHandleId(u) .. ", life " .. life)     
       end
   end
end
I've also checked for group with only 1 unit inside, and this for i = 0, (count-1) do works fine (BlzGroupUnitAt counts from "0")
Thanks guys!

EDIT
Unfortunatelly, using BlzGroupGetSize BlzGroupUnitAt is not save. Unit removed from the game still remains in the group..
 
Last edited:
Level 20
Joined
May 16, 2012
Messages
635
Dont use ForGroup(), Enumerate units within range Using GroupEnumUnitsInRange() or any other group enumaration fuction and loop through it using FirstOfGroup() Like this:

JASS:
local group g = CreateGroup()
    local unit v
 
    call GroupEnumUnitsInRange(g, x, y, aoe, null)
    loop
        set v = FirstOfGroup(g)
        exitwhen v == null
            if (SomeCondition or filtering) then
                //Do your Stuff
            endif
        call GroupRemoveUnit(g, v)
    endloop
    call DestroyGroup(g)

    set g = null

Its Faster and inlined. If you want to break out of this loop you just need to set v = null.
 
Last edited:
Status
Not open for further replies.
Top