The same point variable for 20 different triggers? Memory leak?

Level 3
Joined
Sep 20, 2024
Messages
15
Hello,

1. Do I need to make many point variables "TempPoint1, TempPoint2, TempPoint3... etc." and then have each point variable only be used for maximum 1 trigger to fix all memory leaks? Or can I use only one variable "TempPoint1" for all my triggers even though triggers are active at same time and different regions for the point variable?
2. Should I use the variable called "Point" or "Point Array" for best optimization and no leaks?

Below is some triggers from my map:

  • Wave Green base
    • Events
      • Time - Every 30.00 seconds of game time
    • Conditions
    • Actions
      • Set VariableSet AE_TmpGroup[0] = (Units in (Playable map area) matching ((((Matching unit) is alive) Equal to True) and (((Unit-type of (Matching unit)) Equal to Crypt) and ((Owner of (Matching unit)) Equal to Player 7 (Green)))))
      • Set VariableSet AE_Tmpinteger[0] = (Random integer number between 1 and 3)
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • AE_Tmpinteger[0] Equal to 1
        • Then - Actions
          • Set VariableSet Wave_Type1 = Ghoul
          • Set VariableSet Wave_Amount1 = 2
          • Set VariableSet Wave_Amount1 = (Wave_Amount1 + (Wave_Bonus1 x (Integer(0.75))))
          • Set VariableSet Wave_Type2 = Necromancer
          • Set VariableSet Wave_Amount2 = 0
          • Set VariableSet Wave_Amount2 = (Wave_Amount2 + (Wave_Bonus1 x (Integer(0.34))))
          • Set VariableSet Wave_Type3 = No unit-type
          • Set VariableSet Wave_Amount3 = 0
          • Set VariableSet Wave_Type4 = No unit-type
          • Set VariableSet Wave_Amount4 = 0
        • Else - Actions
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • AE_Tmpinteger[0] Equal to 2
        • Then - Actions
          • Set VariableSet Wave_Type1 = Skeleton Warrior
          • Set VariableSet Wave_Amount1 = 1
          • Set VariableSet Wave_Amount1 = (Wave_Amount1 + (Wave_Bonus1 x (Integer(0.75))))
          • Set VariableSet Wave_Type2 = Skeleton Archer
          • Set VariableSet Wave_Amount2 = 1
          • Set VariableSet Wave_Amount2 = (Wave_Amount2 + (Wave_Bonus1 x (Integer(0.75))))
          • Set VariableSet Wave_Type3 = Skeletal Orc
          • Set VariableSet Wave_Amount3 = 1
          • Set VariableSet Wave_Amount3 = (Wave_Amount3 + (Wave_Bonus1 x (Integer(0.75))))
          • Set VariableSet Wave_Type4 = Skeletal Mage
          • Set VariableSet Wave_Amount4 = 1
          • Set VariableSet Wave_Amount4 = (Wave_Amount4 + (Wave_Bonus1 x (Integer(0.75))))
        • Else - Actions
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • AE_Tmpinteger[0] Equal to 3
        • Then - Actions
          • Set VariableSet Wave_Type1 = Zombie
          • Set VariableSet Wave_Amount1 = 2
          • Set VariableSet Wave_Amount1 = (Wave_Amount1 + Wave_Bonus1)
          • Set VariableSet Wave_Type2 = Abomination
          • Set VariableSet Wave_Amount2 = 0
          • Set VariableSet Wave_Amount2 = (Wave_Amount2 + (Wave_Bonus1 x (Integer(0.20))))
          • Set VariableSet Wave_Type3 = No unit-type
          • Set VariableSet Wave_Amount3 = 0
          • Set VariableSet Wave_Type4 = No unit-type
          • Set VariableSet Wave_Amount4 = 0
        • Else - Actions
      • Set VariableSet AE_Tmpinteger[1] = (Random integer number between 1 and 2)
      • For each (Integer A) from 1 to Wave_Amount1, do (Actions)
        • Loop - Actions
          • Set VariableSet AE_TmpPoint[1] = (Position of (Random unit from AE_TmpGroup[0]))
          • Unit - Create 1 Wave_Type1 for Player 1 (Red) at AE_TmpPoint[1] facing Default building facing degrees
          • AI - Ignore (Last created unit)'s guard position
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • AE_Tmpinteger[1] Equal to 1
            • Then - Actions
              • Set VariableSet AE_TmpPoint[0] = (Center of GreenHordeGather2 <gen>)
              • Unit - Order (Last created unit) to Attack-Move To AE_TmpPoint[0]
              • Custom script: call RemoveLocation (udg_AE_TmpPoint[0])
            • Else - Actions
              • Set VariableSet AE_TmpPoint[0] = (Center of GreenHordeGather1 <gen>)
              • Unit - Order (Last created unit) to Attack-Move To AE_TmpPoint[0]
              • Custom script: call RemoveLocation (udg_AE_TmpPoint[0])
          • Custom script: call RemoveLocation (udg_AE_TmpPoint[1])
      • For each (Integer A) from 1 to Wave_Amount2, do (Actions)
        • Loop - Actions
          • Set VariableSet AE_TmpPoint[1] = (Position of (Random unit from AE_TmpGroup[0]))
          • Unit - Create 1 Wave_Type2 for Player 1 (Red) at AE_TmpPoint[1] facing Default building facing degrees
          • AI - Ignore (Last created unit)'s guard position
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • AE_Tmpinteger[1] Equal to 1
            • Then - Actions
              • Set VariableSet AE_TmpPoint[0] = (Center of GreenHordeGather2 <gen>)
              • Unit - Order (Last created unit) to Attack-Move To AE_TmpPoint[0]
              • Custom script: call RemoveLocation (udg_AE_TmpPoint[0])
            • Else - Actions
              • Set VariableSet AE_TmpPoint[0] = (Center of GreenHordeGather1 <gen>)
              • Unit - Order (Last created unit) to Attack-Move To AE_TmpPoint[0]
              • Custom script: call RemoveLocation (udg_AE_TmpPoint[0])
          • Custom script: call RemoveLocation (udg_AE_TmpPoint[1])
      • For each (Integer A) from 1 to Wave_Amount3, do (Actions)
        • Loop - Actions
          • Set VariableSet AE_TmpPoint[1] = (Position of (Random unit from AE_TmpGroup[0]))
          • Unit - Create 1 Wave_Type3 for Player 1 (Red) at AE_TmpPoint[1] facing Default building facing degrees
          • AI - Ignore (Last created unit)'s guard position
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • AE_Tmpinteger[1] Equal to 1
            • Then - Actions
              • Set VariableSet AE_TmpPoint[0] = (Center of GreenHordeGather2 <gen>)
              • Unit - Order (Last created unit) to Attack-Move To AE_TmpPoint[0]
              • Custom script: call RemoveLocation (udg_AE_TmpPoint[0])
            • Else - Actions
              • Set VariableSet AE_TmpPoint[0] = (Center of GreenHordeGather1 <gen>)
              • Unit - Order (Last created unit) to Attack-Move To AE_TmpPoint[0]
              • Custom script: call RemoveLocation (udg_AE_TmpPoint[0])
          • Custom script: call RemoveLocation (udg_AE_TmpPoint[1])
      • For each (Integer A) from 1 to Wave_Amount4, do (Actions)
        • Loop - Actions
          • Set VariableSet AE_TmpPoint[1] = (Position of (Random unit from AE_TmpGroup[0]))
          • Unit - Create 1 Wave_Type4 for Player 1 (Red) at AE_TmpPoint[1] facing Default building facing degrees
          • AI - Ignore (Last created unit)'s guard position
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • AE_Tmpinteger[1] Equal to 1
            • Then - Actions
              • Set VariableSet AE_TmpPoint[0] = (Center of GreenHordeGather2 <gen>)
              • Unit - Order (Last created unit) to Attack-Move To AE_TmpPoint[0]
              • Custom script: call RemoveLocation (udg_AE_TmpPoint[0])
            • Else - Actions
              • Set VariableSet AE_TmpPoint[0] = (Center of GreenHordeGather1 <gen>)
              • Unit - Order (Last created unit) to Attack-Move To AE_TmpPoint[0]
              • Custom script: call RemoveLocation (udg_AE_TmpPoint[0])
          • Custom script: call RemoveLocation (udg_AE_TmpPoint[1])
      • Custom script: call DestroyGroup (udg_AE_TmpGroup[0])
      • Wait 30.00 seconds
      • Unit Group - Pick every unit in (Units in GreenHordeGather1 <gen> owned by Player 1 (Red)) and do (Actions)
        • Loop - Actions
          • Unit - Order (Picked unit) to Attack-Move To (Random point in Hearthglen <gen>)
      • Unit Group - Pick every unit in (Units in GreenHordeGather2 <gen> owned by Player 1 (Red)) and do (Actions)
        • Loop - Actions
          • Unit - Order (Picked unit) to Attack-Move To (Random point in Hearthglen <gen>)
  • Summon Loop
    • Events
      • Time - Every 1.00 seconds of game time
    • Conditions
      • (Boss_Necromaster is hidden) Equal to False
    • Actions
      • Set VariableSet AE_TmpPoint[0] = (Position of Boss_Necromaster)
      • Set VariableSet AE_TmpPoint[1] = (AE_TmpPoint[0] offset by 150.00 towards (Random angle) degrees.)
      • Set VariableSet AE_TmpPoint[2] = (Random point in Hearthglen <gen>)
      • Set VariableSet AE_TmpType[0] = Skeleton Warrior
      • Set VariableSet AE_TmpType[1] = Skeletal Orc
      • Set VariableSet AE_TmpType[2] = Skeleton Archer
      • Unit - Create 1 AE_TmpType[(Random integer number between 0 and 2)] for Player 1 (Red) at AE_TmpPoint[1] facing (Random angle) degrees
      • Unit - Add a 600.00 second Generic expiration timer to (Last created unit)
      • Unit - Order (Last created unit) to Attack-Move To AE_TmpPoint[2]
      • Special Effect - Create a special effect at AE_TmpPoint[1] using Abilities\Spells\Undead\RaiseSkeletonWarrior\RaiseSkeleton.mdl
      • Special Effect - Destroy (Last created special effect)
      • Custom script: call RemoveLocation (udg_AE_TmpPoint[0])
      • Custom script: call RemoveLocation (udg_AE_TmpPoint[1])
      • Custom script: call RemoveLocation (udg_AE_TmpPoint[2])
  • Necroblast
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • (Ability being cast) Equal to Necroblast
    • Actions
      • Set VariableSet AE_TmpPoint[0] = (Position of (Triggering unit))
      • Set VariableSet AE_TmpGroup[0] = (Units within 500.00 of AE_TmpPoint[0] matching ((((Matching unit) is alive) Equal to True) and (((Matching unit) belongs to an enemy of Player 1 (Red).) Equal to True)).)
      • Set VariableSet AE_Tmpinteger[0] = 0
      • Unit Group - Pick every unit in AE_TmpGroup[0] and do (Actions)
        • Loop - Actions
          • Set VariableSet AE_Tmpinteger[0] = (AE_Tmpinteger[0] + 1)
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • AE_Tmpinteger[0] Less than 6
            • Then - Actions
              • Set VariableSet AE_TmpPoint[1] = (Position of (Picked unit))
              • Unit - Create 1 Necroblast (Target) for Player 1 (Red) at AE_TmpPoint[1] facing Default building facing degrees
              • Unit - Add a 2.20 second Generic expiration timer to (Last created unit)
              • Custom script: call RemoveLocation (udg_AE_TmpPoint[1])
            • Else - Actions
      • Custom script: call RemoveLocation (udg_AE_TmpPoint[0])
  • Final wave ghouls
    • Events
      • Time - Every 1.00 seconds of game time
    • Conditions
    • Actions
      • Set VariableSet AE_TmpPoint[0] = (Center of FinalAttackGhouls1 <gen>)
      • Unit - Create 1 Ghoul for Player 6 (Orange) at AE_TmpPoint[0] facing Default building facing degrees
      • AI - Ignore (Last created unit)'s guard position
      • Custom script: call RemoveLocation (udg_AE_TmpPoint[0])
      • Unit - Order (Last created unit) to Attack-Move To (Random point in Hearthglen <gen>)
      • Set VariableSet AE_TmpPoint[1] = (Center of FinalAttackGhouls2 <gen>)
      • Unit - Create 1 Ghoul for Player 8 (Pink) at AE_TmpPoint[1] facing Default building facing degrees
      • AI - Ignore (Last created unit)'s guard position
      • Custom script: call RemoveLocation (udg_AE_TmpPoint[1])
      • Unit - Order (Last created unit) to Attack-Move To (Random point in Hearthglen <gen>)
I will be very thankful for any help! Tutorials for fixing memory leaks only show how its done if you only have 1 trigger.
 
Last edited:
Level 45
Joined
Feb 27, 2007
Messages
5,578
A variable is a bucket and the data that the variable points to is the sand that fills up the bucket. If you properly empty your bucket of sand (destroy the data with RemoveLocation, DestroyGroup, unit timed life) you can put new a new thing in your bucket without any issues. The previous sand was properly returned to the beach and the bucket has space to accommodate a new scoop of sand = no old sand was 'lost' without being dealt with.

If the information needs to be stored for any non-zero length of time, then no you cannot reuse variables to store that specific information (since it could be overwritten while being used for storage). If you are certain two bits of code could never run at the same time and the data only needs to be stored temporarily within the trigger actions (no waits) you can safely use the same variable across multiple triggers. Consider that sometimes triggers can cause other triggers to fire, which interrupts the 'outer' trigger while the 'inner' one fully executes, and then resumes the 'outer' trigger so it can finish its execution.
 
Level 3
Joined
Sep 20, 2024
Messages
15
Thank you. So the 4 triggers I posted above overwrite each other's variables since they use exactly same variable. It's strange, when you play my map everything works even though the codes run at the same time in many cases. I am currently creating more unique variables for each trigger as you have suggested and replacing all "Point Array" with normal "Point" variables.

1. I see some developers add space between "DestroyGroup" and "(udg_NAMEOFVARIABLE)":
  • Custom script: call DestroyGroup (udg_AE_TmpGroup[0])
  • Custom script: call RemoveLocation (udg_AE_TmpPoint[0])
and some developers remove the space:
  • Custom script: call DestroyGroup(udg_AE_TmpGroup[0])
  • Custom script: call RemoveLocation(udg_AE_TmpPoint[0])
Which one is best in terms of memory leak fix and optimization? Remove or add space?


2. Can this part of one of my triggers be more optimized?: If you look at "Then - Actions" and "Else Actions", can I remove both "Custom script: call RemoveLocation (udg_AE_TmpPoint[0])" and then add 1 "Custom script: call RemoveLocation (udg_AE_TmpPoint[0])" just before "Custom script: call RemoveLocation (udg_AE_TmpPoint[1])"?
  • Set VariableSet AE_Tmpinteger[1] = (Random integer number between 1 and 2)
  • For each (Integer A) from 1 to Wave_Amount2, do (Actions)
    • Loop - Actions
      • Set VariableSet AE_TmpPoint[1] = (Position of (Random unit from AE_TmpGroup[0]))
      • Unit - Create 1 Wave_Type2 for Player 1 (Red) at AE_TmpPoint[1] facing Default building facing degrees
      • AI - Ignore (Last created unit)'s guard position
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • AE_Tmpinteger[1] Equal to 1
        • Then - Actions
          • Set VariableSet AE_TmpPoint[0] = (Center of GreenHordeGather2 <gen>)
          • Unit - Order (Last created unit) to Attack-Move To AE_TmpPoint[0]
          • Custom script: call RemoveLocation (udg_AE_TmpPoint[0])
        • Else - Actions
          • Set VariableSet AE_TmpPoint[0] = (Center of GreenHordeGather1 <gen>)
          • Unit - Order (Last created unit) to Attack-Move To AE_TmpPoint[0]
          • Custom script: call RemoveLocation (udg_AE_TmpPoint[0])
      • Custom script: call RemoveLocation (udg_AE_TmpPoint[1])
  • Custom script: call DestroyGroup (udg_AE_TmpGroup[0])

3. When I set variable as "Random point in region" and then do " Unit - Order (Picked unit) to Attack-Move To (NAMEOFVARIABLE Random point in Hearthglen <gen>)" for a bunch of units in beginning of game and then later for completely different units do same action "Unit - Order (Picked unit) to Attack-Move To (NAMEOF VARIABLE Random point in Hearthglen <gen>)" : Do the units in beginning and the different units later go to exatly the same point in that region or does it become randomly generated point in region everytime the action is done?


4. I have some ghouls and abominations which spawn together with dreadlords and are all added to the same unit group. I can't find any tutorial if I need to remove units from unit group when they die to prevent memory leaks, crashes and lag? For instance if you don't remove units from a unit group that have died and continue to give orders every 30 seconds (wait 30 seconds action) to attack center of region, will the dead units in the unit group cause memory leaks, crashes and lag?
  • Dreadlord remove unit group
    • Events
      • Unit - A unit Dies
    • Conditions
      • ((Triggering unit) is in RedWave.) Equal to True
    • Actions
      • Unit Group - Remove (Triggering unit) from RedWave.
 
Last edited:

Uncle

Warcraft Moderator
Level 73
Joined
Aug 10, 2018
Messages
7,866
1. Which one is best in terms of memory leak fix and optimization? Remove or add space?
That doesn't make a difference here, they have the same exact result. But it's a good practice to avoid unnecessary spaces, in programming the space often implies that you're referring to a separate thing. Regardless, the Trigger Editor will throw an error if it doesn't like what you wrote (most of the time).

Understand that you're simply calling a function in your Custom Script. Functions are basically Actions, they cause something to happen. So the name of the function is DestroyGroup, and the group that you want to destroy is the variable that you put inside of it's parenthesis -> (udg_AE_TmpGroup[0]). This function runs some code that empties and destroys the Unit Group then removes it from your system's memory. This "cleans up" the potential memory leak.


2. Can this part of one of my triggers be more optimized?
Yes, you shouldn't repeat yourself when it's unnecessary. Things inside of the Loops - Action section are going to happen multiple times and it doesn't make sense to do the SAME thing multiple times. If something doesn't change then it doesn't belong in the loop. Here's an optimized trigger:
  • Actions
    • Set VariableSet AE_Tmpinteger[1] = (Random integer number between 1 and 2)
    • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
      • If - Conditions
        • AE_Tmpinteger[1] Equal to 1
      • Then - Actions
        • Set VariableSet AE_TmpPoint[0] = (Center of GreenHordeGather2 <gen>)
      • Else - Actions
        • Set VariableSet AE_TmpPoint[0] = (Center of GreenHordeGather1 <gen>)
    • For each (Integer A) from 1 to Wave_Amount2, do (Actions)
      • Loop - Actions
        • Set VariableSet AE_TmpPoint[1] = (Position of (Random unit from AE_TmpGroup[0]))
        • Unit - Create 1 Wave_Type2 for Player 1 (Red) at AE_TmpPoint[1] facing Default building facing degrees
        • Custom script: call RemoveLocation (udg_AE_TmpPoint[1])
        • AI - Ignore (Last created unit)'s guard position
        • Unit - Order (Last created unit) to Attack-Move To AE_TmpPoint[0]
    • Custom script: call RemoveLocation (udg_AE_TmpPoint[0])
    • Custom script: call DestroyGroup (udg_AE_TmpGroup[0])

3. When I set variable as "Random point in region" and then do " Unit - Order (Picked unit) to Attack-Move To (NAMEOFVARIABLE Random point in Hearthglen <gen>)" for a bunch of units in beginning of game and then later for completely different units do same action "Unit - Order (Picked unit) to Attack-Move To (NAMEOF VARIABLE Random point in Hearthglen <gen>)" : Do the units in beginning and the different units later go to exatly the same point in that region or does it become randomly generated point in region everytime the action is done?
Every time you use this (Random point) function you're getting a brand new random point:
  • Set VariableSet TmpPoint = (Random point in SomeRegion <gen>)
It has no idea about your Unit, their Orders, or anything like that. It does exactly what it says and nothing more. If you want a Unit to remember a Point then you can rely on a concept like Unit Indexing to attach that data to the Unit directly. This is easier than it sounds.


4. I have some ghouls and abominations which spawn together with dreadlords and are all added to the same unit group. I can't find any tutorial if I need to remove units from unit group when they die to prevent memory leaks, crashes and lag?
Yes, Dead units will remain in Unit Groups "forever" so you NEED to Remove them yourself. The game generally avoids making assumptions about what the user wants. For example, maybe the user wants to revive those dead units in the group at some later point in time. In that case it'd be annoying if it automatically removed them so it keeps them in the group and leaves it up to you to decide.

Note that the Units will become memory leaks once they fully Decay - which is when their corpse is gone and they can no longer be revived. It's at this point in time that they're "removed from the game" but that doesn't mean that their handle is no longer being referenced somewhere (like in your Unit Group).

Also, they could potentially cause a crash if you try to interact with them in either state, since a Dead unit is limited in what it can do and a non-existent Unit will be unable to do anything. That being said, Warcraft 3 is pretty good about avoiding these crashes, but I wouldn't rely on that.
 
Last edited:
Level 3
Joined
Sep 20, 2024
Messages
15
That was really helpful! I have now updated the first trigger to make it look like this:

  • Wave Green base
    • Events
      • Time - Every 30.00 seconds of game time
    • Conditions
    • Actions
      • Set VariableSet UnitGroup4 = (Units in (Playable map area) matching ((((Matching unit) is alive) Equal to True) and (((Unit-type of (Matching unit)) Equal to Crypt) and ((Owner of (Matching unit)) Equal to Player 7 (Green)))))
      • Set VariableSet AE_Tmpinteger[0] = (Random integer number between 1 and 3)
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • AE_Tmpinteger[0] Equal to 1
        • Then - Actions
          • Set VariableSet Wave_Type1 = Ghoul
          • Set VariableSet Wave_Amount1 = 2
          • Set VariableSet Wave_Amount1 = (Wave_Amount1 + (Wave_Bonus1 x (Integer(0.75))))
          • Set VariableSet Wave_Type2 = Necromancer
          • Set VariableSet Wave_Amount2 = 0
          • Set VariableSet Wave_Amount2 = (Wave_Amount2 + (Wave_Bonus1 x (Integer(0.34))))
          • Set VariableSet Wave_Type3 = No unit-type
          • Set VariableSet Wave_Amount3 = 0
          • Set VariableSet Wave_Type4 = No unit-type
          • Set VariableSet Wave_Amount4 = 0
        • Else - Actions
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • AE_Tmpinteger[0] Equal to 2
        • Then - Actions
          • Set VariableSet Wave_Type1 = Skeleton Warrior
          • Set VariableSet Wave_Amount1 = 1
          • Set VariableSet Wave_Amount1 = (Wave_Amount1 + (Wave_Bonus1 x (Integer(0.75))))
          • Set VariableSet Wave_Type2 = Skeleton Archer
          • Set VariableSet Wave_Amount2 = 1
          • Set VariableSet Wave_Amount2 = (Wave_Amount2 + (Wave_Bonus1 x (Integer(0.75))))
          • Set VariableSet Wave_Type3 = Skeletal Orc
          • Set VariableSet Wave_Amount3 = 1
          • Set VariableSet Wave_Amount3 = (Wave_Amount3 + (Wave_Bonus1 x (Integer(0.75))))
          • Set VariableSet Wave_Type4 = Skeletal Mage
          • Set VariableSet Wave_Amount4 = 1
          • Set VariableSet Wave_Amount4 = (Wave_Amount4 + (Wave_Bonus1 x (Integer(0.75))))
        • Else - Actions
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • AE_Tmpinteger[0] Equal to 3
        • Then - Actions
          • Set VariableSet Wave_Type1 = Zombie
          • Set VariableSet Wave_Amount1 = 2
          • Set VariableSet Wave_Amount1 = (Wave_Amount1 + Wave_Bonus1)
          • Set VariableSet Wave_Type2 = Abomination
          • Set VariableSet Wave_Amount2 = 0
          • Set VariableSet Wave_Amount2 = (Wave_Amount2 + (Wave_Bonus1 x (Integer(0.20))))
          • Set VariableSet Wave_Type3 = No unit-type
          • Set VariableSet Wave_Amount3 = 0
          • Set VariableSet Wave_Type4 = No unit-type
          • Set VariableSet Wave_Amount4 = 0
        • Else - Actions
      • Set VariableSet AE_Tmpinteger[1] = (Random integer number between 1 and 2)
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • AE_Tmpinteger[1] Equal to 1
        • Then - Actions
          • Set VariableSet Point6 = (Center of GreenHordeGather2 <gen>)
        • Else - Actions
          • Set VariableSet Point6 = (Center of GreenHordeGather1 <gen>)
      • For each (Integer A) from 1 to Wave_Amount1, do (Actions)
        • Loop - Actions
          • Set VariableSet Point7 = (Position of (Random unit from UnitGroup4))
          • Unit - Create 1 Wave_Type1 for Player 1 (Red) at Point7 facing Default building facing degrees
          • Custom script: call RemoveLocation(udg_Point7)
          • AI - Ignore (Last created unit)'s guard position
          • Unit - Order (Last created unit) to Attack-Move To Point6
      • For each (Integer A) from 1 to Wave_Amount2, do (Actions)
        • Loop - Actions
          • Set VariableSet Point7 = (Position of (Random unit from UnitGroup4))
          • Unit - Create 1 Wave_Type2 for Player 1 (Red) at Point7 facing Default building facing degrees
          • Custom script: call RemoveLocation(udg_Point7)
          • AI - Ignore (Last created unit)'s guard position
          • Unit - Order (Last created unit) to Attack-Move To Point6
      • For each (Integer A) from 1 to Wave_Amount3, do (Actions)
        • Loop - Actions
          • Set VariableSet Point7 = (Position of (Random unit from UnitGroup4))
          • Unit - Create 1 Wave_Type3 for Player 1 (Red) at Point7 facing Default building facing degrees
          • Custom script: call RemoveLocation(udg_Point7)
          • AI - Ignore (Last created unit)'s guard position
          • Unit - Order (Last created unit) to Attack-Move To Point6
      • For each (Integer A) from 1 to Wave_Amount4, do (Actions)
        • Loop - Actions
          • Set VariableSet Point7 = (Position of (Random unit from UnitGroup4))
          • Unit - Create 1 Wave_Type4 for Player 1 (Red) at Point7 facing Default building facing degrees
          • Custom script: call RemoveLocation(udg_Point7)
          • AI - Ignore (Last created unit)'s guard position
          • Unit - Order (Last created unit) to Attack-Move To Point6
      • Custom script: call RemoveLocation(udg_Point6)
      • Custom script: call DestroyGroup(udg_UnitGroup4)
      • Wait 30.00 seconds
      • Set VariableSet Point3 = (Random point in Hearthglen <gen>)
      • Set VariableSet UnitGroup1 = (Units in GreenHordeGather1 <gen> owned by Player 1 (Red))
      • Unit Group - Pick every unit in UnitGroup1 and do (Actions)
        • Loop - Actions
          • Unit - Order (Picked unit) to Attack-Move To Point3
      • Custom script: call DestroyGroup(udg_UnitGroup1)
      • Custom script: call RemoveLocation(udg_Point3)
      • Set VariableSet Point3 = (Random point in Hearthglen <gen>)
      • Set VariableSet UnitGroup1 = (Units in GreenHordeGather2 <gen> owned by Player 1 (Red))
      • Unit Group - Pick every unit in UnitGroup1 and do (Actions)
        • Loop - Actions
          • Unit - Order (Picked unit) to Attack-Move To Point3
      • Custom script: call DestroyGroup(udg_UnitGroup1)
      • Custom script: call RemoveLocation(udg_Point3)

I use this action 2 times at end of trigger:
  • Set VariableSet Point3 = (Random point in Hearthglen <gen>)
Based on what you wrote, else the point remains exactly the same spot in that region for rest of the game. To get new random point in "Heartglen <gen>" you must use the action again "Set VariableSet Point3 = (Random point in Hearthglen <gen>)" in order to make "Units in GreenHordeGather1 <gen>" go to a different point compared to "Units in GreenHordeGather2 <gen>"?
 
Last edited:

Uncle

Warcraft Moderator
Level 73
Joined
Aug 10, 2018
Messages
7,866
That trigger looks good, although I would switch the Wait to use Game-Time. You may want to do this for all of your Waits. This is because normal Waits will continue to run while the game is paused which can cause all sorts of issues, although this is only really relevant in singleplayer where pausing occurs (afaik).

Based on what you wrote, else the point remains exactly the same spot in that region for rest of the game. To get new random point in "Heartglen <gen>" you must use the action again "Set VariableSet Point3 = (Random point in Hearthglen <gen>)" in order to make "Units in GreenHordeGather1 <gen>" go to a different point compared to "Units in GreenHordeGather2 <gen>"?
Yes, a Variable is going to remember the last thing that you Set it to. It runs the function (Random point) when you Set the variable. You need to Set it again to run that function again. It's the function that's getting you the Random Point, the variable is just a "bucket" like Pyro said, it's simply holding this information for you. You can empty that bucket and pour new information into it or just keep the same information forever if that's what you're interested in.

Also, I recommend looking into Array variables to make this trigger a lot more simple. Check this out:
  • -------- ... --------
  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
    • If - Conditions
      • AE_Tmpinteger[0] Equal to 1
    • Then - Actions
      • Set VariableSet Wave_Type[1] = Ghoul
      • Set VariableSet Wave_Amount[1] = 2
      • Set VariableSet Wave_Amount[1] = (Wave_Amount[1] + (Wave_Bonus1 x (Integer(0.75))))
      • Set VariableSet Wave_Type[2] = Necromancer
      • Set VariableSet Wave_Amount[2] = 0
      • Set VariableSet Wave_Amount[2] = (Wave_Amount[2] + (Wave_Bonus1 x (Integer(0.34))))
      • Set VariableSet Wave_Type[3] = No unit-type
      • Set VariableSet Wave_Amount[3] = 0
      • Set VariableSet Wave_Type[4] = No unit-type
      • Set VariableSet Wave_Amount[4] = 0
    • Else - Actions
  • -------- --------
  • For each (Integer A) from 1 to 4, do (Actions)
    • Loop - Actions
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • Wave_Amount[(Integer A)] Greater than 0
        • Then - Actions
          • For each (Integer B) from 1 to Wave_Amount[(Integer A)], do (Actions)
            • Loop - Actions
              • Set VariableSet TempPoint[7] = (Position of (Random unit from UnitGroup))
              • Unit - Create 1 Wave_Type1 for Player 1 (Red) at TempPoint[7] facing Default building facing degrees
              • Custom script: call RemoveLocation(udg_TempPoint[7])
              • AI - Ignore (Last created unit)'s guard position
              • Unit - Order (Last created unit) to Attack-Move To TempPoint[6]
          • Else - Actions
  • -------- --------
  • -------- ... --------
See how I'm taking advantage of the Arrays to reduce the number of Variables we're using. I'm also only creating a Unit if Wave_Amount[A] is greater than 0, that way nothing weird happens if you have an empty Wave. I use two For Loops nested inside of one another, which creates A waves, with each wave creating B units.
Note: The ... is meant to represent the rest of your trigger, I wanted this example to be easy to read so I left some Actions out.


Other notes:

1) If you use an Array for your UnitGroup variable then you'll need to make a special exception. Unit Group, Player Group, and Timer variables have a special rule when used as Arrays. You need to manually initialize them. All you have to do is go into the Variable Editor and change their Size value to what you think will be the largest number that you'll ever use as an [index]. I recommend keeping this value at a reasonable amount like less than [100]. There's other tricks to initializing them but that's a topic for another day.

2) You likely don't need a TempPoint7, TempPoint8, TempPoint9, etc... The issue of Variable overwriting often comes from a lack of understanding how triggers work and can be avoided with careful design. HOWEVER, there are some traps to avoid. For example, the the "A unit Dies" Event is problematic because it breaks the normal trigger queue rules, therefore you'll likely want to use unique variables in any triggers that use it. There may be some more cases of this but I can't remember.

3) It's safe to assume that if your trigger runs alone and doesn't cause other triggers to run then it likely doesn't need unique variables, and even if it does cause other triggers to run then you can usually structure it in a way that avoids the issues. To clarify, when I say unique variables I mean something like creating a new TempPoint variable to be used exclusively in one trigger.

4) Minor issue, the math used to calculate the wave bonuses seems incorrect:
  • Set VariableSet Wave_Amount[1] = (Wave_Amount[1] + (Wave_Bonus1 x (Integer(0.75))))
Both 0.75 and 0.34, when converted to an Integer, will be rounded down to 0. What you want to do is convert Wave_Bonus1 to a Real, do your Real math, and then convert the final result to an Integer, for example:
  • Set VariableSet Wave_Amount[1] = (Wave_Amount[1] + (Integer(Real(Wave_Bonus1) x 0.75))))
5) Lastly, you can take the Array design a step further by defining all of this information in a database at the start of the game. This can be done using only Arrays and some smart planning, however, I would personally use a Hashtable - which if you're unfamiliar with is an even more flexible Array. In the end I would use a combination of these tools so that I only ever have to Set this information once and don't have to redefine it each time the trigger runs.
The final result: Every 30.00 seconds I roll a random number between 1 and X, then get and use data from the Hashtable associated with that number.
 
Last edited:
Top