Filtering Groups

XeRo13g

New Member
Reaction score
3
Ok, I thought I was doing well in learning Jass, until I've reached to the point that i wanted to convert something like this:

Code:
Set Temp_Group = (Units within 512.00 of Temp_Point matching (Several conditions))

Following the lead of a tutorial, I've created this:

Code:
set i=0
loop
  set i=i+1
  exitwhen i==6
  set g = GetUnitsInRangeOfLocAll(500.00, o)
    loop
      set u1 = FirstOfGroup(g)
      exitwhen u1==null
      if  (IsUnitAlly(u1, GetOwningPlayer(u))!=true or GetOwningPlayer(u1) == Player(PLAYER_NEUTRAL_PASSIVE)) and GetUnitState(u1, UNIT_STATE_LIFE) > 0 and IsUnitType(u1, UNIT_TYPE_UNDEAD) != true then
       call GroupRemoveUnit(g,u1)
      if IsUnitType (u1, UNIT_TYPE_STRUCTURE) == true then
       set r=500
       else
     set r=( 700+(GetUnitStateSwap(UNIT_STATE_MAX_LIFE, u1) * 0.03 ))
    endif
  call DisplayTextToPlayer( Player(0),0,0, R2S(r) )
       call UnitDamageTargetBJ( u, u1, r, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_UNKNOWN )
        else
         call GroupRemoveUnit(g,u1)
      endif
    endloop

Yet, after reading several posts about how FirstOfGroup can be buggy and how ForGroup is faster in most cases, i've tried to find out more about ForGroup. But then again, there is boolexpr as callback which sound promising...After several hours, I've ended up more confused than ever...

According to Vexorian, there are ways to deal with this by Dynamic Arrays(???), without creating groups?!? What?/How?

I've tried to examine Jass spells but that confused me even more with scary codes like "antileak function" which does nothing but returns true.

At the moment and for the last 3 days, I'm totally stuck.
Can someone please direct me to a helpful tutorial or anything that includes examples? If there was an example of each usage, I think I could try and figure out the rest, or at least ask questions that point somewhere specific.
All those posts refer to everything as if the reader has deep knowledge or at least a decent background knowledge. Well, I'm a total newbie and I found myself very close in giving up.

All I want to replicate is codes like the first GUI line I've posted.
Thanks for taking the time to read.-
 

XeRo13g

New Member
Reaction score
3
This might be graveyard, but works like a charm and it's very very fast.
http://www.thehelper.net/forums/showthread.php/167137-GroupTools

Thanks for the reply Dirac.
I'll have to study the Group tool you've made but I can't adopt a system that I'm unable to fully understand. I have no clue about methods or how to use them...I wouldn't even know how to implement it, let alone use it.

One would tell that examples found here:
http://wiki.thehelper.net/wc3/jass/common.j/Group_API#FirstOfGroup

Would be sufficient but somehow I fail to understand how to use those commands in practice. I know that the Jass code in the OP works(at least it seems to) but how would I use "ForGroup", "boolexpr as callback", "dynamic arrays" or any of the ways mentioned in various posts, instead of FirstOfGroup?
 

Dirac

22710180
Reaction score
147
JASS:
scope Test
    function B takes nothing returns boolean
        call KillUnit(GetFilterUnit()) //kills the unit being filtered
        return false //determines the permanence of the unit inside the group, if false, the unit is deleted from it
    endfunction
    function A takes nothing returns nothing
        local group g=CreateGroup() //new empty group
        call GroupEnumUnitsInRange(g,0,0,600,Filter(function B)) //Picks every unit withing 600 disntace from point 0,0 of the map and runs it through "B"
        call DestroyGroup(g)
    endfunction
endscope
JASS:
scope Test
    function B takes nothing returns nothing
        call KillUnit(GetEnumUnit()) //kills the unit being filtered
    endfunction
    function A takes nothing returns nothing
        local group g=CreateGroup() //new empty group
        call GroupEnumUnitsInRange(g,0,0,600,null) //Picks every unit withing 600 disntace from point 0,0 of the map and adds it to the group
        call ForGroup(g,function B) //runs every unit from the group g into "B"
        call DestroyGroup(g)
    endfunction
endscope
 

Dirac

22710180
Reaction score
147
Yes and i also "forgot" to null the boolexpr used to enum groups, but i was trying to explain something, not uploading a resource.
Also if i were using GroupTools there would be no need for nulling or destroying stuff.

PD: Your mood msg matches my avatar :D
 

XeRo13g

New Member
Reaction score
3
Apologies for taking that long to reply.
After Dirac's reply, I went through everything once more and tried to recreate the simple spell I've posted at the OP with both ways. They seem to work, yet I feel that they leak and there are still a few things I can't get a grasp on.

The test spell works like flamestrike and damages units in the area for 5 seconds, simple as that.

Using a Boolexpr:

JASS:
function Hell_001 takes nothing returns boolean
 local unit u=GetTriggerUnit() //<-----Should I replace this somehow?
 local unit u1=GetFilterUnit()
 local real r
    if  (IsUnitAlly(u1, GetOwningPlayer(u))!=true or GetOwningPlayer(u1) == Player(PLAYER_NEUTRAL_PASSIVE)) and GetUnitState(u1, UNIT_STATE_LIFE) > 0 and IsUnitType(u1, UNIT_TYPE_UNDEAD) != true then
        if IsUnitType (u1, UNIT_TYPE_STRUCTURE) == true then
            set r=500
        else
            set r=( 700+(GetUnitState(u1,UNIT_STATE_LIFE) * 0.03 ))
        endif
      call UnitDamageTarget(u, u1, r, true, false, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_UNKNOWN, WEAPON_TYPE_WHOKNOWS)
    endif
    set u=null
    set u1=null
        return false
    endfunction

function Trig_Hell_Bool_Actions takes nothing returns nothing
    local location o=GetSpellTargetLoc()
    local group g=CreateGroup()
    local effect array sfx
    local integer i=0
    local filterfunc f = Filter(function Hell_001)
set sfx[1]=AddSpecialEffectLoc("Abilities\\Spells\\Human\\FlameStrike\\FlameStrikeTarget.mdl", o)
call TriggerSleepAction(0.50)
set sfx[2]=AddSpecialEffectLoc("Abilities\\Spells\\Human\\FlameStrike\\FlameStrike1.mdl", o)
call TriggerSleepAction(0.50)
set sfx[3]=AddSpecialEffectLoc("Abilities\\Spells\\Human\\FlameStrike\\FlameStrike2.mdl", o)
set sfx[4]=AddSpecialEffectLoc("Abilities\\Spells\\Human\\FlameStrike\\FlameStrike.mdl", o)
call TriggerSleepAction(0.50)

loop
  set i=i+1
  exitwhen i==6
    call GroupEnumUnitsInRangeOfLoc(g,o,500,f)
    call TriggerSleepAction(1.00)
  endloop
    call DestroyGroup(g)
    set g=null
    call DestroyFilter(f)
    set f = null
set i=0
    loop
    set i=i+1
    exitwhen i>4
    call DestroyEffect(sfx<i>)
    set sfx<i>=null
    endloop
call RemoveLocation(o)
set o = null
endfunction</i></i>


Since there is a wait in there, should I change "local unit u=GetTriggerUnit()" in the Hell_001 function with a global or is this fine? How should I go about it?

Using ForGroup:

JASS:
function Hell_002 takes nothing returns boolean
 local unit u=GetTriggerUnit()
 local unit u1=GetEnumUnit()
 local real r
    if  (IsUnitAlly(u1, GetOwningPlayer(u))!=true or GetOwningPlayer(u1) == Player(PLAYER_NEUTRAL_PASSIVE)) and GetUnitState(u1, UNIT_STATE_LIFE) &gt; 0 and IsUnitType(u1, UNIT_TYPE_UNDEAD) != true then
        if IsUnitType (u1, UNIT_TYPE_STRUCTURE) == true then
            set r=500
        else
            set r=( 700+(GetUnitState(u1,UNIT_STATE_LIFE) * 0.03 ))
        endif
      call UnitDamageTarget(u, u1, r, true, false, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_UNKNOWN, WEAPON_TYPE_WHOKNOWS)
    endif
    set u=null
    set u1=null
        return false
    endfunction

    
    function Hell_NoLeak takes nothing returns boolean
    return true
    endfunction
 
 
function Trig_Hell_ForGroupp_Actions takes nothing returns nothing
    local unit u=GetTriggerUnit()
    local location o=GetSpellTargetLoc()
    local group g=CreateGroup()
    local effect array sfx
    local integer i=0
    local filterfunc f = Filter(function Hell_NoLeak)
    
set sfx[1]=AddSpecialEffectLoc(&quot;Abilities\\Spells\\Human\\FlameStrike\\FlameStrikeTarget.mdl&quot;, o)
call TriggerSleepAction(0.50)
set sfx[2]=AddSpecialEffectLoc(&quot;Abilities\\Spells\\Human\\FlameStrike\\FlameStrike1.mdl&quot;, o)
call TriggerSleepAction(0.50)
set sfx[3]=AddSpecialEffectLoc(&quot;Abilities\\Spells\\Human\\FlameStrike\\FlameStrike2.mdl&quot;, o)
set sfx[4]=AddSpecialEffectLoc(&quot;Abilities\\Spells\\Human\\FlameStrike\\FlameStrike.mdl&quot;, o)
call TriggerSleepAction(0.50)

loop
  set i=i+1
  exitwhen i==6
    call GroupEnumUnitsInRangeOfLoc(g,o,500,f)
    call ForGroup(g,function Hell_002)
    call GroupClear(g)  //&lt;----Not sure if this necessary but it seems logical
    call TriggerSleepAction(1.00)
  endloop
    call DestroyGroup(g)
    set g=null
    call DestroyFilter(f)
    set f = null  
    
    set i=0
    loop
    set i=i+1
    exitwhen i&gt;4
    call DestroyEffect(sfx<i>)
    set sfx<i>=null
    endloop
call RemoveLocation(o)
set o=null
set u=null
endfunction</i></i>


Was the function Hell_NoLeak, used correctly?!
Clearing the group was necessary?

I would be most grateful if someone more experienced, took the time to go through these two variations and tell me if I did anything wrong, if it leaks or if anything should or could be improved?!
Any suggestions would be appreciated!

PS. Dirac, you can't imagine how helpful your reply was... +Rep, seems a very lowly reward for it. Cheers!!
 

Dirac

22710180
Reaction score
147
Don't ever use waits on your triggers, always clean up the indentation
JASS:
globals
	private group ENUM_GROUP=CreateGroup()
endglobals

function Actions takes nothing returns nothing
	local unit u=GetTriggerUnti()
	local unit f
	local real x=GetSpellTargetX()
	local real y=GetSpellTargetY()
	call GroupEnumUnitsInRange(ENUM_GROUP,x,y,500,null)
	loop
		set f=FirstOfGroup(ENUM_GROUP)
		exitwhen (null=f)
		call UnitDamageTarget(u,f,true,false,ATTACK_TYPE_CHAOS,DAMAGE_TYPE_UNIVERSAL,null)
	endloop
	set u=null
	set f=null
endfunction
That's the unsafe way to do it using FirstOfGroup()

Using GroupTools
JASS:
function Actions takes nothing returns nothing
	local unit u=GetTriggerUnti()
	local unit f
	local real x=GetSpellTargetX()
	local real y=GetSpellTargetY()
	local integer i=0
	local SimpleGroup g=SimpleGroup.create()
	call g.enumUnitsInRange(x,y,500)
	loop
		set f=g.NextOfGroup
		exitwhen i==g.count
		call UnitDamageTarget(u,f,true,false,ATTACK_TYPE_CHAOS,DAMAGE_TYPE_UNIVERSAL,null)
		set i=i+1
	endloop
	call g.destroy()
	set u=null
	set f=null
endfunction
 

XeRo13g

New Member
Reaction score
3
Don't ever use waits on your triggers, always clean up the indentation
JASS:
globals
	private group ENUM_GROUP=CreateGroup()
endglobals

-How can I avoid waits, if the group needs to take damage over a period of time? While using FirstOfGroup, I didn't use any waits in the part of the code that takes each unit and deals with it, if that is what you mean.

-Not sure what you mean by clean up the Indentation:(

-private group ENUM_GROUP=CreateGroup() - is this Jass or vJass?

Using GroupTools
JASS:
function Actions takes nothing returns nothing
	local unit u=GetTriggerUnti()
	local unit f
	local real x=GetSpellTargetX()
	local real y=GetSpellTargetY()
	local integer i=0
	local SimpleGroup g=SimpleGroup.create()
	call g.enumUnitsInRange(x,y,500)
	loop
		set f=g.NextOfGroup
		exitwhen i==g.count
		call UnitDamageTarget(u,f,true,false,ATTACK_TYPE_CHAOS,DAMAGE_TYPE_UNIVERSAL,null)
		set i=i+1
	endloop
	call g.destroy()
	set u=null
	set f=null
endfunction

This looks extremely like FirstOfGroup usage. Do you mean that I should use the filter function -only- for filtering and do what is to be done with the group in the main trigger?
 

Dirac

22710180
Reaction score
147
It's like you forgot the post i wrote before that one, explaining how the for group and enumeration call works.

If you don't use vJass i cannot help you
 

XeRo13g

New Member
Reaction score
3
I don't mind to study vJass but I just started on Jass and I can't say I have a grip on it yet.

In any case...
Those two codes I did for the test spell using your example, were made correctly or do they leak like hell?
 

Dirac

22710180
Reaction score
147
Well i can't spot a leak at plain sight however, you do use lots of Locations, which should always be avoided by instead using X and Y.
 

Bribe

vJass errors are legion
Reaction score
67
What exactly is intended to be achieved here by using waits? The only time to use waits is maybe in a cinematic? Maybe.
 

XeRo13g

New Member
Reaction score
3
What exactly is intended to be achieved here by using waits? The only time to use waits is maybe in a cinematic? Maybe.

It takes a group of units and damage it once per second for 5 seconds, thus the: call TriggerSleepAction(1.00) in the code. It's my 3rd post if you want to check.

Is there another way?
 
General chit-chat
Help Users
  • No one is chatting at the moment.

      The Helper Discord

      Members online

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top