[Trigger] Unit movement with Unit Groups/Hashtables

Level 2
Joined
Aug 11, 2025
Messages
9
I am working on a group movement system and it seems to have some issues.
I was using unit groups as shown bellow and it seemed to work but when i try to test its limits
spawning a lot of units they started to stop every few seconds and then keep following the move order.
But I didn't notice any other problems.
  • Events
    • Unit - A unit enters lightruralhuman1 <gen>
  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
    • If - Conditions
      • (Unit-type of (Entering unit)) Equal to Light Rural Human Strength 1
    • Then - Actions
      • Unit - Order (Entering unit) to Attack-Move To (Center of lightruralhuman2 <gen>)
      • Unit Group - Add (Entering unit) to creepshumanrural1[1]
  • Events
    • Unit - A unit enters lightruralhuman2 <gen>
  • Conditions
  • Actions
    • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
      • If - Conditions
        • ((Entering unit) is in creepshumanrural1[1]) Equal to True
      • Then - Actions
        • Unit Group - Remove (Entering unit) from creepshumanrural1[1]
        • Unit - Order (Entering unit) to Attack-Move To (Center of darkruralhuman2 <gen>)
        • Unit Group - Add (Entering unit) to creepshumanrural1[2]
      • Else - Actions
Then I was adviced by AI to use Hashtables instead of Unit Groups like this.
  • test
    • Events
      • Time - Elapsed game time is 0.20 seconds
    • Conditions
    • Actions
      • Hashtable - Create a hashtable
      • Set creepshumanrural1h[1] = (Last created hashtable)
      • Hashtable - Create a hashtable
      • Set creepshumanrural1h[2] = (Last created hashtable)
      • etc...
  • Events
    • Unit - A unit enters lightruralhuman1 <gen>
  • Conditions
  • Actions
    • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
      • If - Conditions
        • ((Unit-type of (Entering unit)) Equal to Light Rural Human Strength 1
      • Then - Actions
        • Unit - Order (Entering unit) to Attack-Move To (Center of lightruralhuman2 <gen>)
          • Hashtable - Save 1 as (Key group) of (Key (Entering unit)) in creepshumanrural1h[1]
  • Events
    • Unit - A unit enters lightruralhuman2 <gen>
  • Conditions
  • Actions
    • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
      • If - Conditions
        • (Load (Key group) of (Key (Entering unit)) from creepshumanrural1h[1]) Equal to 1
      • Then - Actions
        • Unit - Order (Entering unit) to Attack-Move To (Center of darkruralhuman2 <gen>)
        • Hashtable - Save 0 as (Key group) of (Key (Entering unit)) in creepshumanrural1h[1]
        • Hashtable - Save 1 as (Key group) of (Key (Entering unit)) in creepshumanrural1h[2]
      • Else - Actions
This seems to make some units go to random regions or return back to their spawn even though most follow the order properly.
Can anyone tell me how to fix this or show me another way to make a reliable unit movement method?
Thanks in advance.
 
If you're talking about 100+ units at a time, then you're likely running into the limits of the Warcraft 3 engine. Once there are too many active orders going on at the same time, orders start to get queued and the pathfinding system slows down (e.g. units will "pause" in an area for a bit before continuing their orders). This was likely done for performance reasons at the time, since too many dynamic objects moving at a time makes pathfinding harder.

But there are some reported ways to work-around it:
  • Reducing collision sizes helps, since units can then go more easily around each other instead of "waiting" for a route to clear up
  • The limit seems to be enforced per-player (perhaps to give each player an equal share of the pathfinding system). So if you need to work around it, you can try splitting the units across multiple players and creating an alliance for those players to grant full unit control/vision.

You can read a bit more discussion about it here:
 
If you're talking about 100+ units at a time, then you're likely running into the limits of the Warcraft 3 engine. Once there are too many active orders going on at the same time, orders start to get queued and the pathfinding system slows down (e.g. units will "pause" in an area for a bit before continuing their orders). This was likely done for performance reasons at the time, since too many dynamic objects moving at a time makes pathfinding harder.

But there are some reported ways to work-around it:
  • Reducing collision sizes helps, since units can then go more easily around each other instead of "waiting" for a route to clear up
  • The limit seems to be enforced per-player (perhaps to give each player an equal share of the pathfinding system). So if you need to work around it, you can try splitting the units across multiple players and creating an alliance for those players to grant full unit control/vision.

You can read a bit more discussion about it here:
Thanks for the response, so I think I won't have a problem because I was just checking how the system works with a lot of units, I dont think I will have more than 100 units at the same time so ok.
What do you think about the bugs with hashtables or custom value of units, you think I should just use unit groups since it does seem to be the more reliable method even though ive been advised that its heavier on the engine?
 
I would stick to groups, they are internally an array. I don't have any concrete data, but it should be faster than these hashtable accesses using hashed keys. Remember to avoid FirstOfGroup though.
bugs with hashtables
That's weird. You'd need to test and see whether "Key (Entering unit)" is somehow non-unique and resets itself. Maybe the unit indexing systems were created for this reason?
 
I would stick to groups, they are internally an array. I don't have any concrete data, but it should be faster than these hashtable accesses using hashed keys. Remember to avoid FirstOfGroup though.

That's weird. You'd need to test and see whether "Key (Entering unit)" is somehow non-unique and resets itself. Maybe the unit indexing systems were created for this reason?
I did check and it was a valid key after research it seems that when so many units are being ordered at the same time even hashtables bug and I was recommended to do a queue system but it seems pretty complicated.
Now I'm continuing with unit groups less buggy but now I had another unit going to its spawn area without being ordered to and I checked if it wasn't in the unit group but it was and I don't know how to fix this.
 
Thanks for the response, so I think I won't have a problem because I was just checking how the system works with a lot of units, I dont think I will have more than 100 units at the same time so ok.
What do you think about the bugs with hashtables or custom value of units, you think I should just use unit groups since it does seem to be the more reliable method even though ive been advised that its heavier on the engine?
Cool, yeah since you were just stress testing then I think you should be fine!

As for your other question, in my opinion you should use unit groups since that is simplest and feels perfect for the job (managing a set of units). AI often ends up explaining things in absolutes (X is better than Y) because people like to hear that, but the differences are often negligible--or they just straight up tell you something false to back up their previous solution they gave you, lol.

I'm not aware of any actual bugs related to hashtables, BUT I do know that they are more bug-prone because they are a little counter-intuitive to work with (especially in GUI since they didn't really add support for all the functions you'd really need). Even after all these years, I often end up having a bug or two just because I forgot to put the correct key or I put the keys in the wrong order.

I'll try to give a quick outline of when you'd typically use each one:
  1. Unit Groups - if unit groups work for your situation, I'd recommend using them! As Luashine mentioned, they are actually very fast--and really good for managing a unique set of units. They also support the option to issue a group order, which will make units move in a formation (similar to when you drag-select units in-game and order them to move somewhere)--that way they'll adjust their speed to match the slowest person in the group and roughly "stay together".
  2. Hashtables - hashtables are great for any situation where you need to associate some specific data with some game object (e.g. a unit's custom stats, data for a spell cast, etc.). They are incredibly powerful and very versatile, but they can be a bit tricky to work with in GUI. For that reason, usually I'd recommend using simpler options if possible--your code will end up easier to maintain in the long-run. That being said, I often lean towards using hashtables for its ability to quickly look up things--so if you ever find yourself looping through a really long array or unit group to "find" something you want, you may want to try a solution with hashtables.
  3. Custom Values - before hashtables were added, people often used arrays to store everything. For example, if you wanted to store a custom stat for a unit, e.g. "Spell Power", you would probably just make an integer array and store the spell power for each unit on your map. That works fine, but it would be really painful to have to loop through the data for every unit on your map just to retrieve one unit's spell power. So instead, you could assign the spell power as a custom value! That way you can easily just store it and look it up wherever you want--no long loops necessary. But what if you wanted to store more than just a single spell power stat? That's where unit indexer systems came in. They would use the custom value to store a unique integer assigned to that unit, and then you could use that integer as the index for your array. So you could create a spell power array, defense stat array, etc. You just need to download a unit indexing system from our spells & systems section in order to use it that way. Nowadays, you can basically do all that with hashtables, but unit indexers and custom values are still handy for the convenience (it is especially convenient in GUI).
I did check and it was a valid key after research it seems that when so many units are being ordered at the same time even hashtables bug and I was recommended to do a queue system but it seems pretty complicated.
Now I'm continuing with unit groups less buggy but now I had another unit going to its spawn area without being ordered to and I checked if it wasn't in the unit group but it was and I don't know how to fix this.
Could you share your full triggers so we can help debug it? It likely isn't a bug with hashtables themselves--it is probably an implementation mistake. Same with the unit group issue.

Or you can describe what you want to do with your group movement system and we might be able to whip up a sample map as a reference.
 
Could you share your full triggers so we can help debug it? It likely isn't a bug with hashtables themselves--it is probably an implementation mistake. Same with the unit group issue.
Thanks for the analysis yea ill stick to unit groups and I really don't think there is a problem with my triggers since 5 out of 6 units follow the order but I can post them for you.
  • Actions
    • Set creepselfrural1[1] = (Last created unit group)
    • Set creepselfrural1[2] = (Last created unit group)
    • Set creepselfrural1[3] = (Last created unit group)
    • Set creepselfrural1[4] = (Last created unit group)
    • Set creepselfrural1[5] = (Last created unit group)
    • Set creepselfrural1[6] = (Last created unit group)
    • Set creepselfrural2[1] = (Last created unit group)
    • Set creepselfrural2[2] = (Last created unit group)
    • Set creepselfrural2[3] = (Last created unit group)
    • Set creepselfrural2[4] = (Last created unit group)
    • Set creepselfrural2[5] = (Last created unit group)
    • Set creepselfrural2[6] = (Last created unit group)
    • Set creepselfrural3[1] = (Last created unit group)
    • Set creepselfrural3[2] = (Last created unit group)
    • Set creepselfrural3[3] = (Last created unit group)
    • Set creepselfrural3[4] = (Last created unit group)
    • Set creepselfrural3[5] = (Last created unit group)
    • Set creepselfrural4[1] = (Last created unit group)
    • Set creepselfrural4[2] = (Last created unit group)
    • Set creepselfrural4[3] = (Last created unit group)
    • Set creepselfrural4[4] = (Last created unit group)
    • Set creepselfrural4[5] = (Last created unit group)
    • Set creepselfrural4[6] = (Last created unit group)
    • Set creepselfrural5[1] = (Last created unit group)
    • Set creepselfrural5[2] = (Last created unit group)
    • Set creepselfrural5[3] = (Last created unit group)
    • Set creepselfrural5[4] = (Last created unit group)
    • Set creepselfrural5[5] = (Last created unit group)
    • Set creepselfrural5[6] = (Last created unit group)
    • Set creepselfrural6[1] = (Last created unit group)
    • Set creepselfrural6[2] = (Last created unit group)
    • Set creepselfrural6[3] = (Last created unit group)
    • Set creepselfrural6[4] = (Last created unit group)
    • Set creepselfrural6[5] = (Last created unit group)
    • Set creepselfrural6[6] = (Last created unit group)
  • elfruralcreeps1 all
    • Events
      • Unit - A unit enters lightruralelf1 <gen>
    • Conditions
    • Actions
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • Or - Any (Conditions) are true
            • Conditions
              • (Unit-type of (Entering unit)) Equal to Light Wood Elf Strength 1
              • (Unit-type of (Entering unit)) Equal to Light Wood Elf Strength 2
              • (Unit-type of (Entering unit)) Equal to Light Wood Elf Strength 3
              • (Unit-type of (Entering unit)) Equal to Light Wood Elf Strength 4
              • (Unit-type of (Entering unit)) Equal to Light Wood Elf Strength 5
        • Then - Actions
          • Unit - Order (Entering unit) to Attack-Move To (Center of lightruralelf2 <gen>)
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • creepturn[1] Equal to 1
            • Then - Actions
              • Unit Group - Add (Entering unit) to creepselfrural1[1]
            • Else - Actions
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • creepturn[1] Equal to 2
                • Then - Actions
                  • Unit Group - Add (Entering unit) to creepselfrural2[1]
                • Else - Actions
                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    • If - Conditions
                      • creepturn[1] Equal to 3
                    • Then - Actions
                      • Unit Group - Add (Entering unit) to creepselfrural3[1]
                    • Else - Actions
                      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                        • If - Conditions
                          • creepturn[1] Equal to 4
                        • Then - Actions
                          • Unit Group - Add (Entering unit) to creepselfrural4[1]
                        • Else - Actions
                          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                            • If - Conditions
                              • creepturn[1] Equal to 5
                            • Then - Actions
                              • Unit Group - Add (Entering unit) to creepselfrural5[1]
                            • Else - Actions
                              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                                • If - Conditions
                                  • creepturn[1] Equal to 6
                                • Then - Actions
                                  • Unit Group - Add (Entering unit) to creepselfrural6[1]
                                • Else - Actions
                                  • Do nothing
        • Else - Actions
          • Do nothing
  • elfruralcreeps2 all
    • Events
      • Unit - A unit enters lightruralelf2 <gen>
    • Conditions
    • Actions
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • ((Entering unit) is in creepselfrural3[1]) Equal to True
        • Then - Actions
          • Unit Group - Remove (Entering unit) from creepselfrural3[1]
          • Unit - Order (Entering unit) to Attack-Move To (Center of darkruralelf2 <gen>)
          • Unit Group - Add (Entering unit) to creepselfrural3[2]
        • Else - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • ((Entering unit) is in creepselfrural3[5]) Equal to True
            • Then - Actions
              • Unit Group - Remove (Entering unit) from creepselfrural3[5]
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • (Dark Elven Fort 0079 <gen> is alive) Equal to True
                • Then - Actions
                  • Unit - Order (Entering unit) to Attack-Move To (Center of darkruralelf2 <gen>)
                  • Unit Group - Add (Entering unit) to creepselfrural3[2]
                • Else - Actions
                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    • If - Conditions
                      • And - All (Conditions) are true
                        • Conditions
                          • creepturn[1] Equal to 3
                          • darklanealive[3] Equal to True
                    • Then - Actions
                      • Unit - Order (Entering unit) to Attack-Move To (Center of darkruralelf2 <gen>)
                      • Unit Group - Add (Entering unit) to creepselfrural3[2]
                    • Else - Actions
                      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                        • If - Conditions
                          • (Dark Elven Castle 0080 <gen> is alive) Equal to True
                        • Then - Actions
                          • Unit - Order (Entering unit) to Attack-Move To (Center of lightcityelf2 <gen>)
                          • Unit Group - Add (Entering unit) to creepselfrural4[2]
                        • Else - Actions
                          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                            • If - Conditions
                              • (Dark Orc Fort 0081 <gen> is alive) Equal to True
                            • Then - Actions
                              • Unit - Order (Entering unit) to Attack-Move To (Center of lightruraldwarf2 <gen>)
                              • Unit Group - Add (Entering unit) to creepselfrural5[2]
                            • Else - Actions
                              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                                • If - Conditions
                                  • (Dark Orc Castle 0082 <gen> is alive) Equal to True
                                • Then - Actions
                                  • Unit - Order (Entering unit) to Attack-Move To (Center of lightcitydwarf2 <gen>)
                                  • Unit Group - Add (Entering unit) to creepselfrural6[2]
                                • Else - Actions
                                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                                    • If - Conditions
                                      • (Dark Human Fort 0043 <gen> is alive) Equal to True
                                    • Then - Actions
                                      • Unit - Order (Entering unit) to Attack-Move To (Center of lightruralhuman2 <gen>)
                                      • Unit Group - Add (Entering unit) to creepselfrural1[2]
                                    • Else - Actions
                                      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                                        • If - Conditions
                                          • (Dark Human Castle 0042 <gen> is alive) Equal to True
                                        • Then - Actions
                                          • Unit - Order (Entering unit) to Attack-Move To (Center of lightcityhuman2 <gen>)
                                          • Unit Group - Add (Entering unit) to creepselfrural2[2]
                                        • Else - Actions
                                          • Do nothing
            • Else - Actions
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • ((Entering unit) is in creepselfrural1[1]) Equal to True
                • Then - Actions
                  • Unit Group - Remove (Entering unit) from creepselfrural1[1]
                  • Unit - Order (Entering unit) to Attack-Move To (Center of lightruralhuman2 <gen>)
                  • Unit Group - Add (Entering unit) to creepselfrural1[2]
                • Else - Actions
                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    • If - Conditions
                      • ((Entering unit) is in creepselfrural2[1]) Equal to True
                    • Then - Actions
                      • Unit Group - Remove (Entering unit) from creepselfrural2[1]
                      • Unit - Order (Entering unit) to Attack-Move To (Center of lightcityhuman2 <gen>)
                      • Unit Group - Add (Entering unit) to creepselfrural2[2]
                    • Else - Actions
                      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                        • If - Conditions
                          • ((Entering unit) is in creepselfrural4[1]) Equal to True
                        • Then - Actions
                          • Unit Group - Remove (Entering unit) from creepselfrural4[1]
                          • Unit - Order (Entering unit) to Attack-Move To (Center of lightcityelf2 <gen>)
                          • Unit Group - Add (Entering unit) to creepselfrural4[2]
                        • Else - Actions
                          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                            • If - Conditions
                              • ((Entering unit) is in creepselfrural5[1]) Equal to True
                            • Then - Actions
                              • Unit Group - Remove (Entering unit) from creepselfrural5[1]
                              • Unit - Order (Entering unit) to Attack-Move To (Center of lightruraldwarf2 <gen>)
                              • Unit Group - Add (Entering unit) to creepselfrural5[2]
                            • Else - Actions
                              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                                • If - Conditions
                                  • ((Entering unit) is in creepselfrural6[1]) Equal to True
                                • Then - Actions
                                  • Unit Group - Remove (Entering unit) from creepselfrural6[1]
                                  • Unit - Order (Entering unit) to Attack-Move To (Center of lightcitydwarf2 <gen>)
                                  • Unit Group - Add (Entering unit) to creepselfrural6[2]
                                • Else - Actions
                                  • Do nothing
  • elfruralcreeps3x1
    • Events
      • Unit - A unit enters lightruralhuman2 <gen>
    • Conditions
    • Actions
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • ((Entering unit) is in creepselfrural1[2]) Equal to True
        • Then - Actions
          • Unit Group - Remove (Entering unit) from creepselfrural1[2]
          • Unit - Order (Entering unit) to Attack-Move To (Center of darkruralhuman2 <gen>)
          • Unit Group - Add (Entering unit) to creepselfrural1[3]
        • Else - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • ((Entering unit) is in creepselfrural1[6]) Equal to True
            • Then - Actions
              • Unit Group - Remove (Entering unit) from creepselfrural1[6]
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • (Dark Human Fort 0043 <gen> is alive) Equal to True
                • Then - Actions
                  • Unit - Order (Entering unit) to Attack-Move To (Center of darkruralhuman2 <gen>)
                  • Unit Group - Add (Entering unit) to creepselfrural1[3]
                • Else - Actions
                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    • If - Conditions
                      • And - All (Conditions) are true
                        • Conditions
                          • creepturn[1] Equal to 1
                          • darklanealive[1] Equal to True
                    • Then - Actions
                      • Unit - Order (Entering unit) to Attack-Move To (Center of darkruralhuman2 <gen>)
                      • Unit Group - Add (Entering unit) to creepselfrural1[3]
                    • Else - Actions
                      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                        • If - Conditions
                          • (Dark Human Castle 0042 <gen> is alive) Equal to True
                        • Then - Actions
                          • Unit - Order (Entering unit) to Attack-Move To (Center of lightcityhuman2 <gen>)
                          • Unit Group - Add (Entering unit) to creepselfrural2[2]
                        • Else - Actions
                          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                            • If - Conditions
                              • (Dark Elven Fort 0079 <gen> is alive) Equal to True
                            • Then - Actions
                              • Unit - Order (Entering unit) to Attack-Move To (Center of lightruralelf2 <gen>)
                              • Unit Group - Add (Entering unit) to creepselfrural3[1]
                            • Else - Actions
                              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                                • If - Conditions
                                  • (Dark Elven Castle 0080 <gen> is alive) Equal to True
                                • Then - Actions
                                  • Unit - Order (Entering unit) to Attack-Move To (Center of lightcityelf2 <gen>)
                                  • Unit Group - Add (Entering unit) to creepselfrural4[2]
                                • Else - Actions
                                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                                    • If - Conditions
                                      • (Dark Orc Fort 0081 <gen> is alive) Equal to True
                                    • Then - Actions
                                      • Unit - Order (Entering unit) to Attack-Move To (Center of lightruraldwarf2 <gen>)
                                      • Unit Group - Add (Entering unit) to creepselfrural5[2]
                                    • Else - Actions
                                      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                                        • If - Conditions
                                          • (Dark Orc Castle 0082 <gen> is alive) Equal to True
                                        • Then - Actions
                                          • Unit - Order (Entering unit) to Attack-Move To (Center of lightcitydwarf2 <gen>)
                                          • Unit Group - Add (Entering unit) to creepselfrural6[2]
                                        • Else - Actions
                                          • Do nothing
            • Else - Actions
              • Do nothing
The following trigger is where the bug occurs it's one of the units of the creepselfrural1[3]
  • elfruralcreeps4x1
    • Events
      • Unit - A unit enters darkruralhuman2 <gen>
    • Conditions
    • Actions
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • ((Entering unit) is in creepselfrural1[3]) Equal to True
        • Then - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • (Dark Human Fort 0043 <gen> is alive) Equal to True
            • Then - Actions
              • Unit Group - Remove (Entering unit) from creepselfrural1[3]
              • Unit - Order (Entering unit) to Attack-Move To (Center of darkhumanruralbase <gen>)
              • Unit Group - Add (Entering unit) to creepselfrural1[4]
            • Else - Actions
              • Unit Group - Remove (Entering unit) from creepselfrural1[3]
              • Unit - Order (Entering unit) to Attack-Move To (Center of lightruralhuman2 <gen>)
              • Unit Group - Add (Entering unit) to creepselfrural1[6]
        • Else - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • ((Entering unit) is in creepselfrural1[5]) Equal to True
            • Then - Actions
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • (Dark Human Fort 0043 <gen> is alive) Equal to True
                • Then - Actions
                  • Unit Group - Remove (Entering unit) from creepselfrural1[5]
                  • Unit - Order (Entering unit) to Attack-Move To (Center of darkhumanruralbase <gen>)
                  • Unit Group - Add (Entering unit) to creepselfrural1[4]
                • Else - Actions
                  • Unit Group - Remove (Entering unit) from creepselfrural1[5]
                  • Unit - Order (Entering unit) to Attack-Move To (Center of lightruralhuman2 <gen>)
                  • Unit Group - Add (Entering unit) to creepselfrural1[6]
            • Else - Actions
              • Do nothing
  • elfruralcreeps5x1done
    • Events
      • Unit - A unit enters darkhumanruralbase <gen>
    • Conditions
    • Actions
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • ((Entering unit) is in creepselfrural1[4]) Equal to True
        • Then - Actions
          • Unit Group - Remove (Entering unit) from creepselfrural1[4]
          • Unit - Order (Entering unit) to Attack-Move To (Center of darkruralhuman2 <gen>)
          • Unit Group - Add (Entering unit) to creepselfrural1[5]
        • Else - Actions
          • Do nothing
Or you can describe what you want to do with your group movement system and we might be able to whip up a sample map as a reference.
I could send you the map and check it for yourself if you up for that but also p.s I'm using an old version of warcraft 3
 
sure thing, you can send me the map in a private message (you can use the pastebin to upload your map):

and just add a few instructions so I know how to reproduce the bug.

but otherwise, my first question would be around the first trigger:
  • Set creepselfrural1[1] = (Last created unit group)
  • Set creepselfrural1[2] = (Last created unit group)
  • ...
It seems like you're making all of these variables point to the same unit group, "last created unit group", but you're not actually making any unit groups in that trigger. Is that intentional?

If you just want to initialize the arrays with empty groups, then you can go to the variable in the variable editor and change the "Size" field to the number of empty groups you want the array to be initialized with (in this case, you'd set the size to "6"). Otherwise the code probably won't make sense, since they're all going to be adding and removing the units from a single group.

Otherwise, I would recommend adding a few debug messages (Game - Text Message) in that trigger you mentioned so that you can make sure that the unit gets ordered the way you expect, e.g. you can log the unit's name and put that in the if/then/else case you expect it to reach, and check if it is actually logging the message for each unit you expect it to.
 
The Hashtable + Unit Group stuff should definitely work. Here's an example (attached map).

Edit: Oh, you're on an older patch. Maybe these triggers will make sense.
  • Setup Factions
    • Events
      • Time - Elapsed game time is 0.00 seconds
    • Conditions
    • Actions
      • Hashtable - Create a hashtable
      • Set Table = (Last created hashtable)
      • -------- --------
      • -------- Setup and register each Faction: --------
      • -------- --------
      • -------- Faction A - (Player 1 and 2): --------
      • Set Point[1] = (Center of AStart <gen>)
      • Set Point[2] = (Center of A1 <gen>)
      • Set Point[3] = (Center of A2 <gen>)
      • Set Point[4] = (Center of A3 <gen>)
      • Trigger - Run Create New Faction <gen> (ignoring conditions)
      • -------- --------
      • -------- Faction B - (Player 3 and 4): --------
      • Set Point[1] = (Center of BStart <gen>)
      • Set Point[2] = (Center of B1 <gen>)
      • Set Point[3] = (Center of B2 <gen>)
      • Set Point[4] = (Center of B3 <gen>)
      • Trigger - Run Create New Faction <gen> (ignoring conditions)
  • Create New Faction
    • Events
    • Conditions
    • Actions
      • Set Faction_ID = (Faction_ID + 1)
      • -------- --------
      • -------- Save the Unit Group for this Faction: --------
      • Custom script: set udg_Unit_Group = CreateGroup()
      • Hashtable - Save Handle of Unit_Group as 0 of Faction_ID in Table.
      • -------- --------
      • -------- Save the Points for this Faction: --------
      • For each (Integer Loop_A) from 1 to 4, do (Actions)
        • Loop - Actions
          • Hashtable - Save Handle Of Point[Loop_A] as Loop_A of Faction_ID in Table.
  • Move from Start to 1
    • Events
      • Unit - A unit enters AStart <gen>
      • Unit - A unit enters BStart <gen>
    • Conditions
    • Actions
      • Set Unit = (Triggering unit)
      • Set Unit_ID = (Custom value of Unit)
      • -------- --------
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (Player number of (Owner of Unit)) Less than or equal to 2
        • Then - Actions
          • Set Faction_ID = 1
        • Else - Actions
          • Set Faction_ID = 2
      • -------- --------
      • -------- Store their Faction: --------
      • Set Unit_Faction[Unit_ID] = Faction_ID
      • -------- --------
      • -------- Store them in their Faction's Unit Group: --------
      • Unit Group - Add Unit to (Load 0 of Faction_ID in Table.)
      • -------- --------
      • -------- Store the next Point (index): --------
      • Set Unit_Destination[Unit_ID] = 2
      • -------- --------
      • -------- And move there: --------
      • Unit - Order Unit to Move To (Load Unit_Destination[Unit_ID] of Faction_ID in Table.)
  • Move from 1 to 2 to 3
    • Events
      • Unit - A unit enters A1 <gen>
      • Unit - A unit enters A2 <gen>
      • Unit - A unit enters B1 <gen>
      • Unit - A unit enters B2 <gen>
    • Conditions
    • Actions
      • Set Unit = (Triggering unit)
      • Set Unit_ID = (Custom value of Unit)
      • Set Faction_ID = Unit_Faction[Unit_ID]
      • -------- --------
      • -------- Store the next Point (index): --------
      • Set Unit_Destination[Unit_ID] = (Unit_Destination[Unit_ID] + 1)
      • -------- --------
      • -------- And move there: --------
      • Unit - Order Unit to Move To (Load Unit_Destination[Unit_ID] of Faction_ID in Table.)
  • Demo Create Units
    • Events
      • Time - Every 5.00 seconds of game time
    • Conditions
    • Actions
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • ((Execution count of (This trigger)) mod 2) Equal to 0
        • Then - Actions
          • -------- Create some units for Faction A: --------
          • Set Faction_ID = 1
          • Set Point[0] = (Load 1 of Faction_ID in Table.)
          • Unit - Create 1 Footman for Player 1 (Red) at Point[0] facing Default building facing degrees
          • Unit - Create 1 Footman for Player 2 (Blue) at Point[0] facing Default building facing degrees
        • Else - Actions
          • -------- Create some units for Faction B: --------
          • Set Faction_ID = 2
          • Set Point[0] = (Load 1 of Faction_ID in Table.)
          • Unit - Create 1 Footman for Player 3 (Teal) at Point[0] facing Default building facing degrees
          • Unit - Create 1 Footman for Player 4 (Purple) at Point[0] facing Default building facing degrees

This trigger isn't necessary to get the above examples working, but it can prevent bugs down the line caused by "recycling":
  • Recycle Faction Data
    • Events
      • Game - UnitIndexEvent becomes Equal to 2.00
    • Conditions
    • Actions
      • -------- Future units can inherit old dead unit's custom values (recycling) so let's ensure that the old data is reset before this happens: --------
      • Set Unit_Faction[UDex] = 0
      • Set Unit_Destination[UDex] = 0
 

Attachments

Last edited:
sure thing, you can send me the map in a private message (you can use the pastebin to upload your map):

and just add a few instructions so I know how to reproduce the bug.

but otherwise, my first question would be around the first trigger:
  • Set creepselfrural1[1] = (Last created unit group)
  • Set creepselfrural1[2] = (Last created unit group)
  • ...
It seems like you're making all of these variables point to the same unit group, "last created unit group", but you're not actually making any unit groups in that trigger. Is that intentional?

If you just want to initialize the arrays with empty groups, then you can go to the variable in the variable editor and change the "Size" field to the number of empty groups you want the array to be initialized with (in this case, you'd set the size to "6"). Otherwise the code probably won't make sense, since they're all going to be adding and removing the units from a single group.

Otherwise, I would recommend adding a few debug messages (Game - Text Message) in that trigger you mentioned so that you can make sure that the unit gets ordered the way you expect, e.g. you can log the unit's name and put that in the if/then/else case you expect it to reach, and check if it is actually logging the message for each unit you expect it to.
Weirdly I didn't get the bug the next few runs never seen an inconsistent bug like that but ill keep an eye on it and send it to you if it reappears.
As for the unit groups trigger it's just a trick to activate all the empty groups remember i don't create any group in the beginning so all these groups set to the last created group finds nothing, so these groups exists as empty groups that exist constantly, and it works just fine I think u can try it and see, i know there is also a script that does the same thing but whatever, but do you mean that the groups and their arrays exist just by creating them in the variable editor? I don't think that's the case.

The Hashtable + Unit Group stuff should definitely work. Here's an example (attached map).

Edit: Oh, you're on an older patch. Maybe these triggers will make sense.
  • Setup Factions
    • Events
      • Time - Elapsed game time is 0.00 seconds
    • Conditions
    • Actions
      • Hashtable - Create a hashtable
      • Set Table = (Last created hashtable)
      • -------- --------
      • -------- Setup and register each Faction: --------
      • -------- --------
      • -------- Faction A - (Player 1 and 2): --------
      • Set Point[1] = (Center of AStart <gen>)
      • Set Point[2] = (Center of A1 <gen>)
      • Set Point[3] = (Center of A2 <gen>)
      • Set Point[4] = (Center of A3 <gen>)
      • Trigger - Run Create New Faction <gen> (ignoring conditions)
      • -------- --------
      • -------- Faction B - (Player 3 and 4): --------
      • Set Point[1] = (Center of BStart <gen>)
      • Set Point[2] = (Center of B1 <gen>)
      • Set Point[3] = (Center of B2 <gen>)
      • Set Point[4] = (Center of B3 <gen>)
      • Trigger - Run Create New Faction <gen> (ignoring conditions)
  • Create New Faction
    • Events
    • Conditions
    • Actions
      • Set Faction_ID = (Faction_ID + 1)
      • -------- --------
      • -------- Save the Unit Group for this Faction: --------
      • Custom script: set udg_Unit_Group = CreateGroup()
      • Hashtable - Save Handle of Unit_Group as 0 of Faction_ID in Table.
      • -------- --------
      • -------- Save the Points for this Faction: --------
      • For each (Integer Loop_A) from 1 to 4, do (Actions)
        • Loop - Actions
          • Hashtable - Save Handle Of Point[Loop_A] as Loop_A of Faction_ID in Table.
  • Move from Start to 1
    • Events
      • Unit - A unit enters AStart <gen>
      • Unit - A unit enters BStart <gen>
    • Conditions
    • Actions
      • Set Unit = (Triggering unit)
      • Set Unit_ID = (Custom value of Unit)
      • -------- --------
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (Player number of (Owner of Unit)) Less than or equal to 2
        • Then - Actions
          • Set Faction_ID = 1
        • Else - Actions
          • Set Faction_ID = 2
      • -------- --------
      • -------- Store their Faction: --------
      • Set Unit_Faction[Unit_ID] = Faction_ID
      • -------- --------
      • -------- Store them in their Faction's Unit Group: --------
      • Unit Group - Add Unit to (Load 0 of Faction_ID in Table.)
      • -------- --------
      • -------- Store the next Point (index): --------
      • Set Unit_Destination[Unit_ID] = 2
      • -------- --------
      • -------- And move there: --------
      • Unit - Order Unit to Move To (Load Unit_Destination[Unit_ID] of Faction_ID in Table.)
  • Move from 1 to 2 to 3
    • Events
      • Unit - A unit enters A1 <gen>
      • Unit - A unit enters A2 <gen>
      • Unit - A unit enters B1 <gen>
      • Unit - A unit enters B2 <gen>
    • Conditions
    • Actions
      • Set Unit = (Triggering unit)
      • Set Unit_ID = (Custom value of Unit)
      • Set Faction_ID = Unit_Faction[Unit_ID]
      • -------- --------
      • -------- Store the next Point (index): --------
      • Set Unit_Destination[Unit_ID] = (Unit_Destination[Unit_ID] + 1)
      • -------- --------
      • -------- And move there: --------
      • Unit - Order Unit to Move To (Load Unit_Destination[Unit_ID] of Faction_ID in Table.)
  • Demo Create Units
    • Events
      • Time - Every 5.00 seconds of game time
    • Conditions
    • Actions
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • ((Execution count of (This trigger)) mod 2) Equal to 0
        • Then - Actions
          • -------- Create some units for Faction A: --------
          • Set Faction_ID = 1
          • Set Point[0] = (Load 1 of Faction_ID in Table.)
          • Unit - Create 1 Footman for Player 1 (Red) at Point[0] facing Default building facing degrees
          • Unit - Create 1 Footman for Player 2 (Blue) at Point[0] facing Default building facing degrees
        • Else - Actions
          • -------- Create some units for Faction B: --------
          • Set Faction_ID = 2
          • Set Point[0] = (Load 1 of Faction_ID in Table.)
          • Unit - Create 1 Footman for Player 3 (Teal) at Point[0] facing Default building facing degrees
          • Unit - Create 1 Footman for Player 4 (Purple) at Point[0] facing Default building facing degrees

This trigger isn't necessary to get the above examples working, but it can prevent bugs down the line caused by "recycling":
  • Recycle Faction Data
    • Events
      • Game - UnitIndexEvent becomes Equal to 2.00
    • Conditions
    • Actions
      • -------- Future units can inherit old dead unit's custom values (recycling) so let's ensure that the old data is reset before this happens: --------
      • Set Unit_Faction[UDex] = 0
      • Set Unit_Destination[UDex] = 0
I don't see a point to use both unit groups and hashtables i thought the whole puprpose is to get rid of unit groups, also I'm scared of using hashtables now haha. But thanks for the response i might check it out if i keep getting bugs with the only unit groups method.
 
I don't see a point to use both unit groups and hashtables i thought the whole puprpose is to get rid of unit groups, also I'm scared of using hashtables now haha. But thanks for the response i might check it out if i keep getting bugs with the only unit groups method.
A Unit Group is generally the ideal way to manage a group of units and Hashtables can save and load Unit Groups. They're designed to be used together.

If you're working in GUI then it's safe to assume that you'll prefer using "Pick every unit in loaded group" over a For Each loop since the Unit Group comes with helper functions to Add/Remove units and get a unit at random. It also has automatic sorting which is very convenient.

That being said, there are reasons to save your Units in a Hashtable at different Child Keys instead. For example, if you were making a Pokemon-style game then the order of your party would matter, the first Pokemon is always the one that goes into battle and in 2v2's you'll always send out the first two. So in that case being able to load "index 1" and "index 2" directly, and having control over the sorting order at all times, might serve you better than using a Unit Group.
 
Last edited:
This seems to make some units go to random regions or return back to their spawn even though most follow the order properly.
Now this may be relevant to your situation. I've a test map where I am Player RED, but there are two units spawned for Player BLUE too. The forces are set as follows: Force 1 = (Player RED + BLUE). Options all enabled for Force 1 = (Allied + Allied Victory + Share Vision + Share Unit Control + Share Adv. Unit Control).
When I, as player RED, order BLUE's units to attack a destructible gate (attack order aka classic hotkey A), then BLUE's units go to attack the gate, keep attacking until it's destroyed. Once destroyed, they return to their old positions they were standing at prior to the attack order.
 
Weirdly I didn't get the bug the next few runs never seen an inconsistent bug like that but ill keep an eye on it and send it to you if it reappears.
As for the unit groups trigger it's just a trick to activate all the empty groups remember i don't create any group in the beginning so all these groups set to the last created group finds nothing, so these groups exists as empty groups that exist constantly, and it works just fine I think u can try it and see, i know there is also a script that does the same thing but whatever, but do you mean that the groups and their arrays exist just by creating them in the variable editor? I don't think that's the case.
for sure, feel free to send it if you do run into it again. :thumbs_up:

For the second question, yes--I mean that the groups and their arrays will exist just by creating them in the variable editor. You just need to configure the size:
1755113219825.png


If I set that to "6", then the editor will generate the following code:
JASS:
function InitGlobals takes nothing returns nothing
    local integer i= 0
    set i=0
    loop
        exitwhen ( i > 6 )
        set udg_SomeGroup[i]=CreateGroup()
        set i=i + 1
    endloop

endfunction

This will ensure that SomeGroup[0], SomeGroup[1], SomeGroup[2], ... SomeGroup[6] are all initialized with an empty group that you can immediately work with.
 
A Unit Group is generally the ideal way to manage a group of units and Hashtables can save and load Unit Groups. They're designed to be used together.

If you're working in GUI then it's safe to assume that you'll prefer using "Pick every unit in loaded group" over a For Each loop since the Unit Group comes with helper functions to Add/Remove units and get unit at random. It also has automatic sorting which is very convenient.

That being said, there are reasons to save your Units in a Hashtable at different Child Keys instead. For example, if you were making a Pokemon-style game then the order of your party would matter, the first Pokemon is always the one that goes into battle and in 2v2's you'll always send out the first two. So in that case being able to load "index 1" and "index 2" directly, and having control over the sorting order at all times, might serve you better than using a Unit Group.
thanks ill consider it.
Now this may be relevant to your situation. I've a test map where I am Player RED, but there are two units spawned for Player BLUE too. The forces are set as follows: Force 1 = (Player RED + BLUE). Options all enabled for Force 1 = (Allied + Allied Victory + Share Vision + Share Unit Control + Share Adv. Unit Control).
When I, as player RED, order BLUE's units to attack a destructible gate (attack order aka classic hotkey A), then BLUE's units go to attack the gate, keep attacking until it's destroyed. Once destroyed, they return to their old positions they were standing at prior to the attack order.
I think if that was the case then all the units of the unit group would do the same or at least it would happen more often but i have stumbled on what you are saying with player colors for some reason the force imposes colors on all players but i thought that was an old version bug.
for sure, feel free to send it if you do run into it again. :thumbs_up:

For the second question, yes--I mean that the groups and their arrays will exist just by creating them in the variable editor. You just need to configure the size:
View attachment 546010

If I set that to "6", then the editor will generate the following code:
JASS:
function InitGlobals takes nothing returns nothing
    local integer i= 0
    set i=0
    loop
        exitwhen ( i > 6 )
        set udg_SomeGroup[i]=CreateGroup()
        set i=i + 1
    endloop

endfunction

This will ensure that SomeGroup[0], SomeGroup[1], SomeGroup[2], ... SomeGroup[6] are all initialized with an empty group that you can immediately work with.
Ehm well thats awkward so i just waisted my time setting all of them at the start haha ill try to run it without that trigger to see if youre right.

Anyways thanks to everyone lets consider this solved for now.
 
Back
Top