• 🏆 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!

[Trigger] Problem with moving multiple dummy units at the same time

Level 2
Joined
Apr 19, 2023
Messages
11
Hey there!

Im a bit lost on how to finish this, i dont know if im on the right path to it. What i need is simple, just make all dummy units move towards the (killing unit), what am i missing?

  • Sacrifice
    • Events
      • Unit - A unit Dies
    • Conditions
      • (Level of Sacrifice for (Killing unit)) Equal to 1
    • Actions
      • Set VariableSet Sacrifice_TU = (Killing unit)
      • Set VariableSet Sacrifice_Loc[1] = (Position of Sacrifice_TU)
      • Set VariableSet Sacrifice_Loc[2] = (Position of (Picked unit))
      • Set VariableSet Sacrifice_Loc[3] = (Sacrifice_Loc[2] offset by 15.00 towards (Angle from Sacrifice_Loc[2] to Sacrifice_Loc[1]) degrees.)
      • Unit - Create 1 Dummy Sacrifice for (Owner of Sacrifice_TU) at (Position of (Dying unit)) facing (Angle from Sacrifice_Loc[2] to Sacrifice_Loc[1]) degrees
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (Sacrifice_DummyGroup is empty) Not equal to True
        • Then - Actions
          • Trigger - Turn on Sacrifice Loop <gen>
        • Else - Actions
      • Unit Group - Add (Last created unit) to Sacrifice_DummyGroup
      • Custom script: call RemoveLocation(udg_Sacrifice_Loc[1])
      • Custom script: call RemoveLocation(udg_Sacrifice_Loc[2])
      • Custom script: call RemoveLocation(udg_Sacrifice_Loc[3])

  • Sacrifice Loop
    • Events
      • Time - Every 0.03 seconds of game time
    • Conditions
    • Actions
      • Unit Group - Pick every unit in Sacrifice_DummyGroup and do (Actions)
        • Loop - Actions
          • Set VariableSet Sacrifice_Loc[1] = (Position of Sacrifice_TU)
          • Set VariableSet Sacrifice_Loc[2] = ((Position of (Picked unit)) offset by 15.00 towards (Angle from (Position of (Picked unit)) to Sacrifice_Loc[1]) degrees.)
          • Unit - Move (Picked unit) instantly to Sacrifice_Loc[2], facing (Angle from Sacrifice_Loc[2] to Sacrifice_Loc[1]) degrees
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (Distance between Sacrifice_Loc[2] and Sacrifice_Loc[1]) Less than or equal to 20.00
        • Then - Actions
          • Hero - Modify Intelligence of Sacrifice_TU: Add 1.
          • Set VariableSet Sacrifice_IntGain = (Sacrifice_IntGain + 1)
          • Ability - Set Extended Tooltip of Sacrifice to (Collects the souls of the enemies slain by the Cursed Noble, each soul gives |cff0080C01 intelligence|r. Because of the pact, all souls are lost on death. |n|n|cff0080C0Souls Collected: + ((String(Sacrifice_IntGain)) + .|r)) for level 0
          • Unit Group - Pick every unit in Sacrifice_DummyGroup and do (Actions)
            • Loop - Actions
              • Special Effect - Create a special effect at Sacrifice_Loc[2] using Abilities\Weapons\ZigguratMissile\ZigguratMissile.mdl
              • Special Effect - Set Scale of (Last created special effect) to 2.00
              • Special Effect - Destroy (Last created special effect)
              • Hashtable - Clear all child hashtables of child (Key (Picked unit).) in Hashtable.
              • Unit Group - Remove (Picked unit) from Sacrifice_DummyGroup.
              • Unit - Remove (Picked unit) from the game
          • Custom script: call RemoveLocation(udg_Sacrifice_Loc[1])
          • Custom script: call RemoveLocation(udg_Sacrifice_Loc[2])
        • Else - Actions
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (Sacrifice_DummyGroup is empty) Equal to True
        • Then - Actions
          • Trigger - Turn off (This trigger)
        • Else - Actions
 

Uncle

Warcraft Moderator
Level 64
Joined
Aug 10, 2018
Messages
6,542
Looks like your If Then Else isn't inside of the Unit Group's Loop - Actions. You're also doing something weird with the Special Effects, why are you creating them on every single Dummy unit when only one of them reached the target?
  • Sacrifice Loop
    • Events
      • Time - Every 0.03 seconds of game time
    • Conditions
    • Actions
      • Set VariableSet Sacrifice_Loc[1] = (Position of Sacrifice_TU)
      • Unit Group - Pick every unit in Sacrifice_DummyGroup and do (Actions)
        • Loop - Actions
          • Set VariableSet Sacrifice_Dummy = (Picked unit)
          • Set VariableSet Sacrifice_Loc[2] = (Position of Sacrifice_Dummy)
          • Set VariableSet Sacrifice_Angle = (Angle from Sacrifice_Loc[2] to Sacrifice_Loc[1]) degrees.)
          • Set VariableSet Sacrifice_Loc[3] = (Sacrifice_Loc[2] offset by 15.00 towards Sacrifice_Angle)
          • Unit - Move Sacrifice_Dummy instantly to Sacrifice_Loc[3], facing Sacrifice_Angle degrees
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • (Distance between Sacrifice_Loc[3] and Sacrifice_Loc[1]) Less than or equal to 20.00
            • Then - Actions
              • Hero - Modify Intelligence of Sacrifice_TU: Add 1.
              • Set VariableSet Sacrifice_IntGain = (Sacrifice_IntGain + 1)
              • Ability - Set Extended Tooltip of Sacrifice to (Collects the souls of the enemies slain by the Cursed Noble, each soul gives |cff0080C01 intelligence|r. Because of the pact, all souls are lost on death. |n|n|cff0080C0Souls Collected: + ((String(Sacrifice_IntGain)) + .|r)) for level 0
              • Special Effect - Create a special effect at Sacrifice_Loc[3] using Abilities\Weapons\ZigguratMissile\ZigguratMissile.mdl
              • Special Effect - Set Scale of (Last created special effect) to 2.00
              • Special Effect - Destroy (Last created special effect)
              • Unit Group - Remove Sacrifice_Dummy from Sacrifice_DummyGroup.
              • Unit - Remove Sacrifice_Dummy from the game
            • Else - Actions
          • Custom script: call RemoveLocation(udg_Sacrifice_Loc[2])
          • Custom script: call RemoveLocation(udg_Sacrifice_Loc[3])
      • Custom script: call RemoveLocation(udg_Sacrifice_Loc[1])
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (Sacrifice_DummyGroup is empty) Equal to True
        • Then - Actions
          • Trigger - Turn off (This trigger)
        • Else - Actions
Also, some other improvements:
  • The Sacrifice trigger is leaking a Point.
  • You can use Special Effects instead of Dummy units. It's far more efficient although a bit more complicated since there is no Special Effect Group variable.
  • Try to avoid overusing Event Responses like referencing (Picked unit) 4+ times. Store it as a variable and reference that instead. (Unless you have Waits in your trigger since the global variable may change during the Wait).
  • Checking if something is "Not equal to True" is a bit confusing, I suggest just using "Equal to False".
 
Last edited:
Level 2
Joined
Apr 19, 2023
Messages
11
Thanks again uncle!

My thought process on the special effects was that for some reason the condition would aply to the unit group actions too, meaning only the picked unit close enough would play it. Im a total newbie in programing as you can see haha, thx for the clear explanations
 

Uncle

Warcraft Moderator
Level 64
Joined
Aug 10, 2018
Messages
6,542
Thanks again uncle!

My thought process on the special effects was that for some reason the condition would aply to the unit group actions too, meaning only the picked unit close enough would play it. Im a total newbie in programing as you can see haha, thx for the clear explanations
No problem, I edited that post like 5x after posting it so apologies if you were reading it during that. It should be up to date now with valid information :p

I'll try to explain how these Unit Group - Loops work in case you're still confused:
actions.gif
Loop - Actions

First, remember that triggers execute from top to bottom, left to right. The way things are ordered is extremely important since that will change the outcome of our triggers. This trigger for example works as intended:
  • Unit - Create 1 Footman...
  • Unit - Kill (Last created unit)
Where as this one does not work because our order is wrong, the unit doesn't exist yet at the time of trying to kill it:
  • Unit - Kill (Last created unit)
  • Unit - Create 1 Footman...
Moving on with that in the back of our minds let's focus on the Unit Group.

A Unit Group is simply a container for Units. It's like a drawer in your desk where you can fit any number of Units inside. Using a Unit Group variable is convenient since it allows us to remember this drawer and reference it at any time from any of our triggers.

"I want to open the drawer and pull out a random item" says the User. Or "I want to throw away everything inside of the drawer". There's many things you can do with this drawer (Unit Group). Or in your case you want to Move everything inside of the drawer to a different position.

So when you're using this Action:
unitgroup.gif
Unit Group - Pick every unit in Sacrifice_DummyGroup and do (Actions)
actions.gif
Loop - Actions

What's really happening here is a series of things:

First the game Sets a Unit variable called (Picked unit) to the "first" Unit it finds inside of our Unit Group. How it determines which Unit goes first is I believe somewhat random but that doesn't really matter. Once it finds this first Unit and Sets it to the (Picked unit) it then proceeds to run every single Action that you have placed inside of:
actions.gif
Loop - Actions.

It does this following our rules from earlier, top to bottom, left to right.

Once it has run every single Action that you've placed inside of it, the Loop does what it's name implies and circles back to the start again (loops). It now finds the second Unit inside of our Unit Group, sets it to the (Picked unit), and proceeds to run all of Actions again. This pattern continues until it has interacted with every single Unit inside of the Unit Group.

And why is (Picked unit) so important? It's the User's way of actually interacting with all of these Units. Without it you would have no reference to these Units during the looping process.

With that in mind, a Player Group works the exact same way except that it uses (Picked player) rather than (Picked unit). Also, the For Each Loops follow a very similar pattern as well although they give the user a bit more control and flexibility and aren't limited to ONLY Units or ONLY Players. Although, they require slightly more advanced methods to use and are often paired with Arrays.
 
Last edited:
Level 2
Joined
Apr 19, 2023
Messages
11
Very easy to understand, very appreciated. Just one question if im not bothering, when im clearing variables with arrays and lets say my array is another variable [MUIunits],
  • Custom script: call RemoveLocation(udg_Loc[MUIunits])
It gets me an error, how do i clear it? Sorry for asking something unrelated to the post
 
Level 2
Joined
Apr 19, 2023
Messages
11
Yes, but an integer i just made up to use as an example. Oh so thats why, would be something like udg_loc[udg_MUIunits] or udg_loc[_udg_MUIunits]
 

Uncle

Warcraft Moderator
Level 64
Joined
Aug 10, 2018
Messages
6,542
Yes, but an integer i just made up to use as an example. Oh so thats why, would be something like udg_loc[udg_MUIunits] or udg_loc[_udg_MUIunits]
udg_MyVariableName[udg_MyOtherVariableName]

I made a typo last post.

You're telling the game that it's a global variable that you made inside of the standard Trigger Editor as opposed to one that would be found in your Jass/Lua code. When you use Custom Script you're literally coding in Jass or Lua (Jass is the default programming language and Lua is a secondary option) hence why the distinction is important. Also, it's possible to have a coded variable and a standard global variable with the same exact name, which again is why this prefix is necessary to tell them apart.
 
Last edited:
Top