• 🏆 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!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

[JASS] Creating local Player and Unit Groups

Status
Not open for further replies.
Level 18
Joined
Nov 1, 2006
Messages
1,612
I am looking for the best way to prevent "pick every unit in" triggers from leaking. I found that the best way is to set a variable = the group of units/players you want, then pick every unit in [the group variable]. However when needing to do this possibly at the same time, using a global variable in a regular triggered function sucks because it can conflict.

So I want to learn to do this in JASS, cleanly.

If you can show an optimized example of how to set a local player group variable to your desired players, pick every player in that group and perform an action, and then Clear it and do the same with a Unit group that would be perfect. I'm very eager to learn how to do this.
 
Level 40
Joined
Dec 14, 2005
Messages
10,532
Don't use a player group, just use an integer, if you are looping through all players.

Otherwise, something like this:

JASS:
local force f = CreateForce()
call ForceEnumAllies(f,somePlayer,someFilter) //or a similar enum, ForceEnumEnemies, etc.
//do stuff
//maybe call ForForce(f,function callback)
call DestroyForce(f)
set f = null
 
Level 18
Joined
Nov 1, 2006
Messages
1,612
Don't use a player group, just use an integer, if you are looping through all players.

What about solving this problem for a unit group? To clear it up: ForceEnumAllies does stuff for all Allies of somePlayer? And someFilter would be... a condition?

I am working with functions like this, for example:

  • RescueChild1 Alternate
    • Events
      • Unit - Creaky Cage 0028 <gen> Dies
    • Conditions
    • Actions
      • Trigger - Turn off (This trigger)
      • Custom script: call PlaySoundForPlayer(GetOwningPlayer(GetKillingUnit()),gg_snd_GoodJob)
      • Unit - Create 1 Widow's Child (2) for Neutral Passive at (Center of RescueChild3 <gen>) facing 40.00 degrees
      • Unit - Make (Last created unit) Invulnerable
      • Set Child2 = (Last created unit)
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • MissingChildrenInteger Equal to 1
        • Then - Actions
          • Trigger - Turn on RescueChild2 <gen>
        • Else - Actions
          • Trigger - Turn on RescueChild2 Alternate <gen>
      • Set TempQuestGroup = (Units in (Playable map area) matching (((Owner of (Matching unit)) Not equal to DKOwner) and (((Owner of (Matching unit)) Not equal to Neutral Passive) and (((Matching unit) is A Hero) Equal to True))))
      • Unit Group - Pick every unit in TempQuestGroup and do (Actions)
        • Loop - Actions
          • Set AtDPointsInt[(Player number of (Owner of (Picked unit)))] = (AtDPointsInt[(Player number of (Owner of (Picked unit)))] + 2)
          • Leaderboard - Change the value for (Owner of (Picked unit)) in AtDPoints[(Player number of (Owner of (Picked unit)))] to AtDPointsInt[(Player number of (Owner of (Picked unit)))]
          • Game - Display to (Player group((Owner of (Picked unit)))) the text: ((|cff003F87Quest Update:|r One child has been found by + (|cff00FF00 + (Name of (Owner of (Killing unit))))) + |r! |cffffcc00All Death Hunters recieve 50 gold and 100 experience!|r)
          • Hero - Add 100 experience to (Picked unit), Show level-up graphics
          • Player - Add 50 to (Owner of (Picked unit)) Current gold
      • Unit Group - Remove all units from TempQuestGroup
      • Unit - Order Child2 to Move To (Center of Child1 <gen>)
It would be nice to be able to shift it into jass and just create a LOCAL unit group and use it. But I need to know how to efficiently create unit groups in jass and use them.
 
Last edited:
Level 11
Joined
Feb 22, 2006
Messages
752
For the unit group, the easiest GUI solution is just put a Custom Script action right before the unit group loop and in it put "set bj_wantDestroyGroup = true" (without the quotes). Also, to not leak a boolexpr in the unit group loop, do not set conditions (i.e. don't use units matching conditions). Instead, just use an if-then-else action inside the unit group loop to check for the conditions you want.

For JASS, dealing with unit groups is much more efficiently handled this way (if you have vJASS):

JASS:
scope foo initializer init

globals
    group g = CreateGroup()
    boolexpr filterExpr
endglobals

private function filter takes nothing returns boolean
    // do the stuff to your units HERE. The filter already loops through every 
    // unit so you might as well have your actions here instead of looping through
    // the group AGAIN in a ForGroup() call.

    return false
endfunction

function foo takes nothing returns nothing
    call GroupEnumUnitsInRect(g, bj_mapInitialPlayableArea, filterExpr)
endfunction

private function init takes nothing returns nothing
    set filterExpr = Condition(function filter)
endfunction

endscope

Handling player groups in JASS is similar to the above code, only you use force instead of group and you use the ForceEnumPlayers() functions instead of GroupEnumUnits()
 
Level 18
Joined
Nov 1, 2006
Messages
1,612
Unfortunately "set_bjwantDestroyGroup = true" sometimes will prematurely destroy the group before everything has been done. That is why I'm looking for the next best solution.

I don't use vJASS. And so using an 'if then else' inside the unit group loop is better than setting the group matching certain conditions before picking all the units within it?
 
Level 11
Joined
Feb 22, 2006
Messages
752
set bj_wantDestroyGroup = true will not prematurely destroy a group if you set the variable immediately before using the unit group loop. Threads will not interrupt a currently executing thread in the middle of an execution (if this happened in wc, all hell would break lose, like event response functions screwing up even if you don't use waits).

And so using an 'if then else' inside the unit group loop is better than setting the group matching certain conditions before picking all the units within it?

You basically don't use any of the unit matching condition options in a pick every unit in... action. And inside the the unit group loop, you use the if-then-else action, so like:

Unit Group - pick every unit in playable map bounds and do actions
loop - actions
if (conditions) then
do your stuff here
else
do nothing
 
Level 11
Joined
Feb 22, 2006
Messages
752
Unless you destroy the group yourself or use any kind of wait functions, the group will not be destroyed prematurely.

EDIT: Actually, I'm not sure about the wait function thing. You might be able to use them, since theoretically they would also
block the code that made the call to ForGroup() since both the original code and the callback executes on the same thread.

The code for ForGroupBJ is this:

JASS:
function ForGroupBJ takes group whichGroup, code callback returns nothing
    // If the user wants the group destroyed, remember that fact and clear
    // the flag, in case it is used again in the callback.
    local boolean wantDestroy = bj_wantDestroyGroup
    set bj_wantDestroyGroup = false

    call ForGroup(whichGroup, callback)

    // If the user wants the group destroyed, do so now.
    if (wantDestroy) then
        call DestroyGroup(whichGroup)
    endif
endfunction
 
Level 8
Joined
Apr 30, 2009
Messages
338
I have a related question.

I get an error when I try to make a

JASS:
local player P

It highlights "player" like the variable type is invalid. I know this happened with "location" because I kept typing "position." What is the correct varable name for local player?
 
Level 8
Joined
Apr 30, 2009
Messages
338
Yes, I create it with other locals before anything else, and I set its value when needed. The part where I create it is where it screws up.
 
Status
Not open for further replies.
Top