• 🏆 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] Attack-Move To issue.

Status
Not open for further replies.
Level 2
Joined
Jan 4, 2023
Messages
3
Hello!
I'm new here, at least to posting, so I apologize if I format something incorrectly. - I'm also working on my first custom map, so maybe my problem is common knowledge. - Although, I will say I have looked at numerous threads, and only found solutions that add another 'problem'.

I have an issue right now in my map, I'm doing a wave based system (through triggers). Everything working (almost) according to plan, I spawn the units in a designated region, and issue an order, which would be Attack-Move To.

Here is the trigger I use to order attack move. I run this after spawning the units.

  • Unit Group - Pick every unit in (Units owned by Player 12 (Brown).) and do (Unit - Order (Picked unit) to Attack-Move To (Load (Key redbase.) of (Key redplayer.) in REDLocationOfBase.))
Things are working as intended, they move to the location I ordered, and do also attack! - But it happens, every now and then, that SOME of them just stand still. Sometimes its after chasing down a unit, or destroying a building. I'm aware that I can set a periodic timer, and reissuing the order - but that resets the attack animation of all the units. Something I have a hard time coming to terms with :).

After numerous Google searches, I have found some could be solutions, but to no avail.

I have tried:

  • Events
    • Unit - A unit owned by Player 12 (Brown) Is issued an order targeting a point
  • Actions
    • AI - Ignore the guard positions of all Player 12 (Brown) units
This does not fix my issue, it still happens. - Did however fix the issue of them hauling their butts back to spawn, once they couldn't see enemies within 1 foot.

Also, I tried this:
Note: I would normally run this trigger as a periodic one, but had to have a way to control when the trigger was 'firing', thus the -check thing.
  • Events
    • Player - Player 1 (Red) types a chat message containing -check as An exact match
  • Actions
    • Unit Group - Pick every unit in (Units owned by Player 12 (Brown) matching ((Current order of (Picked unit)) Equal to (Order(none))).) and do (Unit - Order (Picked unit) to Attack-Move To (Load (Key redbase.) of (Key redplayer.) in REDLocationOfBase.))
I thought the above trigger would be the one to work. - Since it checks for (Order(none))).) But this trigger still picks EVERY unit, even the ones not standing still. So I end up with the issue of all units resetting their animation.

What surprised me the most, is the fact that even after being issued an 'order', this condition still goes through. Its almost as if the units have no orders regardless of what I do?

But what is it I really want? = I want enemies to attack move to a point and I want them to keep doing it even after being distracted. (Without having to reissue the order ever 3 seconds, if possible)
 

Uncle

Warcraft Moderator
Level 64
Joined
Aug 10, 2018
Messages
6,564
You definitely don't want to ignore the guard positions of ALL units belonging to Player 12 every single time one of them issues an order. Instead, you can spawn your units and manage them on an individual basis, ignoring the AI and issuing an order to them one at a time. I created an example map showcasing this and posted the triggers below.

First, let's create Point variables where our units spawn and where they need to attack to:
  • Spawn Setup
    • Events
      • Time - Elapsed game time is 0.00 seconds
    • Conditions
    • Actions
      • Set VariableSet Spawn_StartPoint = (Center of Start <gen>)
      • Set VariableSet Spawn_EndPoint = (Center of End <gen>)
Next, let's spawn in our units using a For Loop. To make things efficient let's track them in a Unit Group and ignore their AI on an individual basis:
  • Spawn Create
    • Events
      • Time - Every 2.00 seconds of game time
    • Conditions
    • Actions
      • For each (Integer Spawn_Loop) from 1 to 5, do (Actions)
        • Loop - Actions
          • Unit - Create 1 Footman for Player 12 (Brown) at Spawn_StartPoint facing Default building facing degrees
          • Set VariableSet Spawn_Unit = (Last created unit)
          • Unit Group - Add Spawn_Unit to Spawn_UnitGroup
          • Unit - Order Spawn_Unit to Attack-Move To Spawn_EndPoint
Unit Groups won't automatically remove Dead units so we need to do it ourselves:
  • Spawn Die
    • Events
      • Unit - A unit owned by Player 12 (Brown) Dies
    • Conditions
    • Actions
      • Unit Group - Remove (Triggering unit) from Spawn_UnitGroup.
Now let's periodically check for idle units in our Unit Group and order them to attack again:
  • Spawn Order
    • Events
      • Time - Every 10.00 seconds of game time
    • Conditions
    • Actions
      • Unit Group - Pick every unit in Spawn_UnitGroup and do (Actions)
        • Loop - Actions
          • Set VariableSet Spawn_Unit = (Picked unit)
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • (Current order of Spawn_Unit) Equal to (Order(stand down))
            • Then - Actions
              • Unit - Order Spawn_Unit to Attack-Move To Spawn_EndPoint
            • Else - Actions
Apparently the idle order is called "stand down".

If you're confused about the variable/custom script usage, it's to avoid Memory Leaks.

Another problem you may run into is an issue where units begin to ignore orders or "stutter". The fix to this is to spread ownership of the spawned units among multiple computer players. A safe bet would be about 60 units max per computer player. I've also heard that reducing the unit's collision size can help as well.

The multiple computer method can easily be done by adding a couple more variables and modifying our triggers slightly:
  • Spawn Setup Copy
    • Events
      • Time - Elapsed game time is 0.00 seconds
    • Conditions
    • Actions
      • Set VariableSet Spawn_StartPoint = (Center of Start <gen>)
      • Set VariableSet Spawn_EndPoint = (Center of End <gen>)
      • -------- --------
      • Set VariableSet Spawn_ComputerNumber = 12
      • For each (Integer Spawn_Loop) from 13 to 24, do (Actions)
        • Loop - Actions
          • Set VariableSet Spawn_Computer = (Player(Spawn_Loop))
          • Player - Change color of Spawn_Computer to Brown, Changing color of existing units
          • Player - Set name of Spawn_Computer to (Name of Player 12 (Brown))
  • Spawn Create Copy
    • Events
      • Time - Every 2.00 seconds of game time
    • Conditions
    • Actions
      • Set VariableSet Spawn_Computer = (Player(Spawn_ComputerNumber))
      • Set VariableSet Spawn_ComputerNumber = (Spawn_ComputerNumber + 1)
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • Spawn_ComputerNumber Greater than 24
        • Then - Actions
          • Set VariableSet Spawn_ComputerNumber = 12
        • Else - Actions
      • -------- --------
      • For each (Integer Spawn_Loop) from 1 to 5, do (Actions)
        • Loop - Actions
          • Unit - Create 1 Footman for Spawn_Computer at Spawn_StartPoint facing Default building facing degrees
          • Set VariableSet Spawn_Unit = (Last created unit)
          • Unit Group - Add Spawn_Unit to Spawn_UnitGroup
          • Unit - Order Spawn_Unit to Attack-Move To Spawn_EndPoint
  • Spawn Die Copy
    • Events
      • Unit - A unit Dies
    • Conditions
      • (Level of Spawn Classification for (Triggering unit)) Not equal to 0
    • Actions
      • Unit Group - Remove (Triggering unit) from Spawn_UnitGroup.
Spawn Classification is a passive and hidden ability based on Storm Hammers. You would give this ability to units that are spawned by the computers as an easy way to detect when a spawned unit (which could belong to players 12 - 24) died. You could add this ability through the Object Editor or through the Spawn Create trigger. This is probably the most efficient way of handling it, although checking the Team number of the Player that the dying unit belonged to might be a fine alternative.
 

Attachments

  • Spawn Attack Example 1.w3m
    19 KB · Views: 6
Last edited:
Level 2
Joined
Jan 4, 2023
Messages
3
You definitely don't want to ignore the guard positions of ALL units belonging to Player 12 every single time one of them issues an order. Instead, you can spawn your units and manage them on an individual basis, ignoring the AI and issuing an order to them one at a time. I created an example map showcasing this and posted the triggers below.

First, let's create Point variables where our units spawn and where they need to attack to:
  • Spawn Setup
    • Events
      • Time - Elapsed game time is 0.00 seconds
    • Conditions
    • Actions
      • Set VariableSet Spawn_StartPoint = (Center of Start <gen>)
      • Set VariableSet Spawn_EndPoint = (Center of End <gen>)
Next, let's spawn in our units using a For Loop. To make things efficient let's track them in a Unit Group and ignore their AI on an individual basis:
  • Spawn Create
    • Events
      • Time - Every 2.00 seconds of game time
    • Conditions
    • Actions
      • For each (Integer Spawn_Loop) from 1 to 5, do (Actions)
        • Loop - Actions
          • Unit - Create 1 Footman for Player 12 (Brown) at Spawn_StartPoint facing Default building facing degrees
          • Set VariableSet Spawn_Unit = (Last created unit)
          • Unit Group - Add Spawn_Unit to Spawn_UnitGroup
          • Unit - Order Spawn_Unit to Attack-Move To Spawn_EndPoint
Unit Groups won't automatically remove Dead units so we need to do it ourselves:
  • Spawn Die
    • Events
      • Unit - A unit owned by Player 12 (Brown) Dies
    • Conditions
    • Actions
      • Unit Group - Remove (Triggering unit) from Spawn_UnitGroup.
Now let's periodically check for idle units in our Unit Group and order them to attack again:
  • Spawn Order
    • Events
      • Time - Every 10.00 seconds of game time
    • Conditions
    • Actions
      • Unit Group - Pick every unit in Spawn_UnitGroup and do (Actions)
        • Loop - Actions
          • Set VariableSet Spawn_Unit = (Picked unit)
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • (Current order of Spawn_Unit) Equal to (Order(stand down))
            • Then - Actions
              • Unit - Order Spawn_Unit to Attack-Move To Spawn_EndPoint
            • Else - Actions
Apparently the idle order is called "stand down".

If you're confused about the variable/custom script usage, it's to avoid Memory Leaks.

Another problem you may run into is an issue where units begin to ignore orders or "stutter". The fix to this is to spread ownership of the spawned units among multiple computer players. A safe bet would be about 60 units max per computer player. I've also heard that reducing the unit's collision size can help as well.

The multiple computer method can easily be done by adding a couple more variables and modifying our triggers slightly:
  • Spawn Setup Copy
    • Events
      • Time - Elapsed game time is 0.00 seconds
    • Conditions
    • Actions
      • Set VariableSet Spawn_StartPoint = (Center of Start <gen>)
      • Set VariableSet Spawn_EndPoint = (Center of End <gen>)
      • -------- --------
      • Set VariableSet Spawn_ComputerNumber = 12
      • For each (Integer Spawn_Loop) from 13 to 24, do (Actions)
        • Loop - Actions
          • Set VariableSet Spawn_Computer = (Player(Spawn_Loop))
          • Player - Change color of Spawn_Computer to Brown, Changing color of existing units
          • Player - Set name of Spawn_Computer to (Name of Player 12 (Brown))
  • Spawn Create Copy
    • Events
      • Time - Every 2.00 seconds of game time
    • Conditions
    • Actions
      • Set VariableSet Spawn_Computer = (Player(Spawn_ComputerNumber))
      • Set VariableSet Spawn_ComputerNumber = (Spawn_ComputerNumber + 1)
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • Spawn_ComputerNumber Greater than 24
        • Then - Actions
          • Set VariableSet Spawn_ComputerNumber = 12
        • Else - Actions
      • -------- --------
      • For each (Integer Spawn_Loop) from 1 to 5, do (Actions)
        • Loop - Actions
          • Unit - Create 1 Footman for Spawn_Computer at Spawn_StartPoint facing Default building facing degrees
          • Set VariableSet Spawn_Unit = (Last created unit)
          • Unit Group - Add Spawn_Unit to Spawn_UnitGroup
          • Unit - Order Spawn_Unit to Attack-Move To Spawn_EndPoint
  • Spawn Die Copy
    • Events
      • Unit - A unit Dies
    • Conditions
      • (Level of Spawn Classification for (Triggering unit)) Not equal to 0
    • Actions
      • Unit Group - Remove (Triggering unit) from Spawn_UnitGroup.
Spawn Classification is a passive and hidden ability based on Storm Hammers. You would give this ability to units that are spawned by the computers as an easy way to detect when a spawned unit (which could belong to players 12 - 24) died. You could add this ability through the Object Editor or through the Spawn Create trigger. This is probably the most efficient way of handling it, although checking the Team number of the Player that the dying unit belonged to might be a fine alternative.

Uncle, thank you for the VERY thorough explanation, it is much appreciated!!

First of all, it works. So, thank you! A side effect of this learning experience, was that I realized that I had an abundance of leaks. In fact I had to apply this new knowledge to a lot of what I had already 'coded'.

One of the things I had to patch up, was the farm mechanic. I read up on leaks, and it was clear to me that the original version of the mechanic was a mess. So I applied some of the things I learned from your reply, and came out with this:

  • Crop Replace
    • Events
      • Unit - A unit owned by Player 1 (Red) Finishes construction
    • Conditions
      • (Unit-type of (Triggering unit)) Equal to Plant Crop
    • Actions
      • Unit - Replace (Triggering unit) with a Fully Grown Crop using The new unit's default life and mana
      • Set VariableSet REDSpawn_Crop = (Last replaced unit)
      • Unit Group - Add REDSpawn_Crop to RED_CropUG
And then when its time to sell/harvest

  • Crop Harvest
    • Events
      • Unit - A unit owned by Player 1 (Red) Finishes casting an ability
    • Conditions
      • (Ability being cast) Equal to Sell/Harvest Crops
      • (Unit-type of (Casting unit)) Equal to Farm
    • Actions
      • Set VariableSet REDCropAmount = (Number of units in RED_CropUG)
      • Unit Group - Pick every unit in RED_CropUG and do (Actions)
        • Loop - Actions
          • Unit - Remove (Picked unit) from the game
          • Unit Group - Remove all units of RED_CropUG from RED_CropUG.
      • Player - Add REDCropAmount to Player 1 (Red).Current gold
      • Floating Text - Create floating text that reads (String(REDCropAmount)) above (Casting unit) with Z offset 30.00, using font size 10.00, color (100.00%, 100.00%, 0.00%), and 0.00% transparency
      • Floating Text - Change (Last created floating text): Disable permanence
      • Floating Text - Change the lifespan of (Last created floating text) to 5.00 seconds
      • Set VariableSet REDCropAmount = 0
It works in game, but did I apply what you wrote about in your reply correctly?

Again, thank you for the help!!
 

Uncle

Warcraft Moderator
Level 64
Joined
Aug 10, 2018
Messages
6,564
Glad you got it working and no problem. The methods you're using appear to be correct there's just some slight mistakes being made.

1) I would say that the REDSpawn_Crop variable in Crop Replace is perfectly fine but also somewhat unnecessary. If you were to reference the (Last replaced unit) multiple times then it would help make the trigger more efficient (extremely minor optimization). It could also help avoid issues where (Last replaced unit) changes to something else (very rare and can depend on a lot of things).

2) For casting spells we have multiple Events: Begins casting, Finishes casting, Stops casting, Begins channeling, and Starts the effect. All of these have different timings/rulings and should be used in specific situations. Starts the effect of an ability is the go to Event for detecting the exact moment an ability is executed - that is when the mana is spent, the cooldown starts, and the effects come into play whether that be a missile being launched or whatever. The issue with using Finishes casting an ability is that it can actually be interrupted and the trigger can fail to run. I suggest using Starts whenever possible.

3) Do not Remove all units from RED_CropUG inside of your Pick Every Unit action:
  • Unit Group - Remove all units of RED_CropUG from RED_CropUG.
If you want to clear that Unit Group then simply do it afterwards, and also I think you're using the wrong clearing action:
  • Unit Group - Pick every unit in RED_CropUG and do (Actions)
    • Loop - Actions
      • Unit - Remove (Picked unit) from the game
  • Unit Group - Remove all units from RED_CropUG
Remember that the actions in Loop - Actions will happen once PER unit, so if you have an action that only needs to happen once or isn't related to the (Picked unit) then that action should happen before or after you Loop over the Unit Group. In your case it would be after since you obviously don't want to clear the Unit Group before you use it.


Also, is your map multiplayer? And if so, are you finding yourself needing to create multiple copies of the same trigger / variable in order to make them work for multiple Players? You can remove a lot of that redundancy by taking advantage of variable Arrays and using simple Indexing techniques.
For example here are your two crop triggers modified to use Array versions of your REDCrop variables in order to make them generic:
  • Crop Replace
    • Events
      • Unit - A unit Finishes construction
    • Conditions
      • (Unit-type of (Triggering unit)) Equal to Plant Crop
    • Actions
      • Set VariableSet Crop_Player = (Owner of (Triggering unit))
      • Set VariableSet Crop_PN = (Player number of Crop_Player)
      • Unit - Replace (Triggering unit) with a Fully Grown Crop using The new unit's default life and mana
      • Unit Group - Add (Last replaced unit) to Crop_UnitGroup[Crop_PN]
  • Crop Harvest
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • (Ability being cast) Equal to Sell/Harvest Crops
      • (Unit-type of (Casting unit)) Equal to Farm
    • Actions
      • Set VariableSet Crop_Player = (Owner of (Casting unit))
      • Set VariableSet Crop_PN = (Player number of Crop_Player)
      • Set VariableSet Crop_Amount[Crop_PN] = (Number of units in Crop_UnitGroup[Crop_PN])
      • Unit Group - Pick every unit in Crop_UnitGroup[Crop_PN] and do (Actions)
        • Loop - Actions
          • Unit - Remove (Picked unit) from the game
      • Unit Group - Remove all units from Crop_UnitGroup[Crop_PN]
      • Player - Add Crop_Amount[Crop_PN] to Crop_Player Current gold
      • Floating Text - Create floating text that reads (String(Crop_Amount[Crop_PN])) above (Casting unit) with Z offset 30.00, using font size 10.00, color (100.00%, 100.00%, 0.00%), and 0.00% transparency
      • Floating Text - Change (Last created floating text): Disable permanence
      • Floating Text - Change the lifespan of (Last created floating text) to 5.00 seconds
      • Set VariableSet Crop_Amount[Crop_PN] = 0
These two Crop triggers will work for each and every Player.

How it works is quite simple. Arrays allow you to store data at what's called an index. The index is the number in the [brackets]. This allows us to create a single variable that can contain multiple sets of data at once. It's sort of like a grocery list where your variable is the list and each grocery is numbered at a different [index] inside of that list.

In this case, I take advantage of the Arrays functionality by using the Player Number of the Player involved in the triggers as the [index] of the Arrays. This allows us to store data to that specific Player. This is much better than having RED, BLUE, TEAL, etc, variables that are dedicated to individual players. You'll see I also use the Crop_Player and Crop_PN variables in order to keep the triggers clean and understandable. Also, in case you were wondering, you can turn any variable into an Array by simply enabling it's Array checkbox when creating it in the Variable Editor. You can also turn an existing non-Array variable into an Array the same way, but note that this will reset it so you'll probably want to create entirely new variables instead.

To clarify what the Arrays are doing, take a look at these three variables:
  • Set VariableSet REDCropAmount = 100
  • Set VariableSet BLUECropAmount = 200
  • Set VariableSet TEALCropAmount = 300
These can be simplified down to a single Integer variable with an Array enabled. The number in the brackets is the [index] and in this case it represents the Player Number:
  • Set VariableSet Crop_Amount[1] = 100
  • Set VariableSet Crop_Amount[2] = 200
  • Set VariableSet Crop_Amount[3] = 300
So Crop_Amount[1] = Player 1's crop amount, Crop_Amount[2] = Player 2's crop amount, and Crop_Amount[3] = Player 3's crop amount. etc. Note that this is just one way of using an Array, the [index] can be used to represent just about anything you want!


IMPORTANT NOTE:
Unit Groups, Player Groups, and Timers are special in that they require an additional step when being used as an Array. You must tell the game exactly how big you want these Arrays to be, which you would do inside of the Variable Editor. You'll see a box that says Size which will have a default value of 1, simply change this to something like 28 so it will support an [index] ranging from the size of 0 to 28, 28 being the highest Player Number available. Every other variable type can remain at it's default Size of 1 because they will dynamically update their size as needed. The Size is just there as an efficiency thing and isn't really an issue except for when working with those 3 variable types I mentioned.

Crop_UnitGroup is a Unit Group array so don't forget to change it's Size!
 
Last edited:
Level 2
Joined
Jan 4, 2023
Messages
3
Glad you got it working and no problem. The methods you're using appear to be correct there's just some slight mistakes being made.

1) I would say that the REDSpawn_Crop variable in Crop Replace is perfectly fine but also somewhat unnecessary. If you were to reference the (Last replaced unit) multiple times then it would help make the trigger more efficient (extremely minor optimization). It could also help avoid issues where (Last replaced unit) changes to something else (very rare and can depend on a lot of things).

2) For casting spells we have multiple Events: Begins casting, Finishes casting, Stops casting, Begins channeling, and Starts the effect. All of these have different timings/rulings and should be used in specific situations. Starts the effect of an ability is the go to Event for detecting the exact moment an ability is executed - that is when the mana is spent, the cooldown starts, and the effects come into play whether that be a missile being launched or whatever. The issue with using Finishes casting an ability is that it can actually be interrupted and the trigger can fail to run. I suggest using Starts whenever possible.

3) Do not Remove all units from RED_CropUG inside of your Pick Every Unit action:
  • Unit Group - Remove all units of RED_CropUG from RED_CropUG.
If you want to clear that Unit Group then simply do it afterwards, and also I think you're using the wrong clearing action:
  • Unit Group - Pick every unit in RED_CropUG and do (Actions)
    • Loop - Actions
      • Unit - Remove (Picked unit) from the game
  • Unit Group - Remove all units from RED_CropUG
Remember that the actions in Loop - Actions will happen once PER unit, so if you have an action that only needs to happen once or isn't related to the (Picked unit) then that action should happen before or after you Loop over the Unit Group. In your case it would be after since you obviously don't want to clear the Unit Group before you use it.


Also, is your map multiplayer? And if so, are you finding yourself needing to create multiple copies of the same trigger / variable in order to make them work for multiple Players? You can remove a lot of that redundancy by taking advantage of variable Arrays and using simple Indexing techniques.
For example here are your two crop triggers modified to use Array versions of your REDCrop variables in order to make them generic:
  • Crop Replace
    • Events
      • Unit - A unit Finishes construction
    • Conditions
      • (Unit-type of (Triggering unit)) Equal to Plant Crop
    • Actions
      • Set VariableSet Crop_Player = (Owner of (Triggering unit))
      • Set VariableSet Crop_PN = (Player number of Crop_Player)
      • Unit - Replace (Triggering unit) with a Fully Grown Crop using The new unit's default life and mana
      • Unit Group - Add (Last replaced unit) to Crop_UnitGroup[Crop_PN]
  • Crop Harvest
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • (Ability being cast) Equal to Sell/Harvest Crops
      • (Unit-type of (Casting unit)) Equal to Farm
    • Actions
      • Set VariableSet Crop_Player = (Owner of (Casting unit))
      • Set VariableSet Crop_PN = (Player number of Crop_Player)
      • Set VariableSet Crop_Amount[Crop_PN] = (Number of units in Crop_UnitGroup[Crop_PN])
      • Unit Group - Pick every unit in Crop_UnitGroup[Crop_PN] and do (Actions)
        • Loop - Actions
          • Unit - Remove (Picked unit) from the game
      • Unit Group - Remove all units from Crop_UnitGroup[Crop_PN]
      • Player - Add Crop_Amount[Crop_PN] to Crop_Player Current gold
      • Floating Text - Create floating text that reads (String(Crop_Amount[Crop_PN])) above (Casting unit) with Z offset 30.00, using font size 10.00, color (100.00%, 100.00%, 0.00%), and 0.00% transparency
      • Floating Text - Change (Last created floating text): Disable permanence
      • Floating Text - Change the lifespan of (Last created floating text) to 5.00 seconds
      • Set VariableSet Crop_Amount[Crop_PN] = 0
These two Crop triggers will work for each and every Player.

How it works is quite simple. Arrays allow you to store data at what's called an index. The index is the number in the [brackets]. This allows us to create a single variable that can contain multiple sets of data at once. It's sort of like a grocery list where your variable is the list and each grocery is numbered at a different [index] inside of that list.

In this case, I take advantage of the Arrays functionality by using the Player Number of the Player involved in the triggers as the [index] of the Arrays. This allows us to store data to that specific Player. This is much better than having RED, BLUE, TEAL, etc, variables that are dedicated to individual players. You'll see I also use the Crop_Player and Crop_PN variables in order to keep the triggers clean and understandable. Also, in case you were wondering, you can turn any variable into an Array by simply enabling it's Array checkbox when creating it in the Variable Editor. You can also turn an existing non-Array variable into an Array the same way, but note that this will reset it so you'll probably want to create entirely new variables instead.

To clarify what the Arrays are doing, take a look at these three variables:
  • Set VariableSet REDCropAmount = 100
  • Set VariableSet BLUECropAmount = 200
  • Set VariableSet TEALCropAmount = 300
These can be simplified down to a single Integer variable with an Array enabled. The number in the brackets is the [index] and in this case it represents the Player Number:
  • Set VariableSet Crop_Amount[1] = 100
  • Set VariableSet Crop_Amount[2] = 200
  • Set VariableSet Crop_Amount[3] = 300
So Crop_Amount[1] = Player 1's crop amount, Crop_Amount[2] = Player 2's crop amount, and Crop_Amount[3] = Player 3's crop amount. etc. Note that this is just one way of using an Array, the [index] can be used to represent just about anything you want!


IMPORTANT NOTE:
Unit Groups, Player Groups, and Timers are special in that they require an additional step when being used as an Array. You must tell the game exactly how big you want these Arrays to be, which you would do inside of the Variable Editor. You'll see a box that says Size which will have a default value of 1, simply change this to something like 28 so it will support an [index] ranging from the size of 0 to 28, 28 being the highest Player Number available. Every other variable type can remain at it's default Size of 1 because they will dynamically update their size as needed. The Size is just there as an efficiency thing and isn't really an issue except for when working with those 3 variable types I mentioned.

Crop_UnitGroup is a Unit Group array so don't forget to change it's Size!

It is indeed a multiplayer map! Good catch. I was going to just ctrl c+v all of the triggers, and edit as necessary. - But after using this method, and implementing it, looks like I'll save myself the trouble. Thank you, once again, for the excellent help.

I feel like I'm a caveman trying to discover fire for the first time, and then Mr. Uncle walks in with a flamethrower, completely rocking my world. You really helped me a lot! You do an amazing job at explaining things in an understandable way, its truly impressive.

I discovered my first bug in the world editor, it won't let me change the size of the unit group arrays in the editor, it saves the changes 1 out of a 100 times. Big pain in the butt when using this method!
 

Uncle

Warcraft Moderator
Level 64
Joined
Aug 10, 2018
Messages
6,564
I believe the bug happens when you try to modify a variable outside of the Variable Editor. You literally need to open the menu (Control + B I think?) and make changes in there. If that still doesn't do it then I fear the latest patch has brought even more issues -_-

Also, be on the lookout for a bug that I believe happens when copying and pasting triggers from one map to another. What will happen is the type of one or more of your variables will break and become "blank", despite the fact that all of the variable references in your triggers will appear to be in working order. You can spot the bug by scrolling through your variables inside or outside of the Variable Editor (I don't think it makes a difference which) and checking each variable type for blank ones. Unfortunately, fixing the variable type will reset all of the references to that variable in your triggers so I recommend making a backup map first as well as creating a new variable and using that instead.

Anyway, I'm happy to help. I remember going through the learning process myself and the discovery of Arrays was a total game changer. That sort of opened my eyes to all of the possibilities which led me towards more advanced triggering techniques. Unit Indexing and Dynamic Indexing are two great ones worth learning next (links in my signature).
 
Last edited:
Status
Not open for further replies.
Top