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

Questions about variables and array, unitgroup vs unit vs array, Specific triggers for attackmoving

Status
Not open for further replies.
Level 2
Joined
Jul 12, 2021
Messages
6
Would the AddHeroestoUnitGroupHeroes cause any problems if any of the players repeatedly go in and out of the MidCenter Region?
I suppose I only need to have all of the heroes added into the UnitGroupHeroes variable that enters the region at the beginning of the map, and then it could be deactivated after that, somehow?

If the unit later levels up will it still work as the unit itself is put into the variable?

Should the variable that the heroes find themselves to be put into, have its variable type defined as a unit group, or a unit? And should it be an array or not an array?

I'm not really sure what it means if it's an array or not, just that if I tick of the box array that the size is changeable, which I guess indicates that multiple "things" or units can be put into there. However when I for example use a variable that I put all the units owned by the triggering hero, to kill them all, a variable of variable type unit group, without being an array, seems to be able to put all of the units in there and then perform an action on all of them.


Specific Triggers for attackmoving (for reference this is like a tag game where the players main unit is quite weak, and they run around, build walls, maze a little, kite the enemies)
As for the second part I'm wondering about the different ways to go about making triggers, events and actions for making enemies that spawn at the mid center of the map to go about attacking different players at different locations. Prioritization would be overall; melee military units, ranged towers, ranged military units, the main hero, walls. It doesn't need to be that precice, just targeting the non-hero units that deal dmg first, then the hero, then the walls.

For clarification I don't mean that the enemies need to actively really hunt down any military units or towers, just that once in close quarter combat that they will prioritize those units.

For this I have written some different triggers, and maybe a combination of them will work the best? Will a good attackmove system plus manually manipulating the "priority" field on the object editor of units to make the zombies attack such that they prioritize to destroy what hurts them first? And if they can't get directly to it (blocked by walls) that they destory the walls, then the towers. Would attackmove plus priority do that well?


Could the attackmove1 be one of the many other triggers for attackmoving, where there are other triggers that for example work by picking a few random enemies to attack-move to a temporary location of one of the players heroes? And should there be a few regions around the playable map area that also has the same function like the MidCenter, that it makes that entering unit (belonging to Player12) to then attack-move to another random location?

On Attackmove2 I wasn't sure how I was supposed to get the location of a random hero within the variable UnitGroupHeroes.

With Attackmove3, maybe a good addition, as a somewhat semi-responsive system that changes from game to game?
 

Attachments

  • HeroGroup.PNG
    HeroGroup.PNG
    9.5 KB · Views: 25
  • Array1.PNG
    Array1.PNG
    4.4 KB · Views: 21
  • Attackmove1.PNG
    Attackmove1.PNG
    7.2 KB · Views: 22
  • Attackmove2.PNG
    Attackmove2.PNG
    15.3 KB · Views: 18
  • Attackmove3.PNG
    Attackmove3.PNG
    10.1 KB · Views: 24

Uncle

Warcraft Moderator
Level 64
Joined
Aug 10, 2018
Messages
6,535
Some things to note:
You need to use conditions when creating your Unit Groups. You can do this either using the Matching function or my personal preference, filter through them using the Pick Every Unit function in order to end up with a group of the desired units.

Keep in mind that Unit Groups will add dead units to the group and dead units will remain inside of the group forever unless you manually remove them. So when you do something like TempGroupZombies = Random 2 units, you could end up grabbing 2 dead units which is obviously a problem.

Here is some examples of good design methods:

First, keep track of your living/dead zombies at all times. This could be applied to player Heroes as well (taking into consideration reviving):
  • Track Zombies Add
    • Events
      • Unit - A unit enters (Playable map area)
    • Conditions
      • (Level of Zombie Group Class for (Triggering unit)) Equal to 1
    • Actions
      • Unit Group - Add (Triggering unit) to ZombieGroup
  • Track Zombies Remove
    • Events
      • Unit - A unit Dies
    • Conditions
      • (Level of Zombie Group Class for (Triggering unit)) Equal to 1
    • Actions
      • Unit Group - Remove (Triggering unit) from ZombieGroup.
Zombie Group Class is an ability based on Storm Hammers that does nothing besides act like a unit Classification for your triggers. It's hidden from sight (Button Positions set to 0, -11) and is given to each unit that you want to Add to ZombieGroup.

Then if you wanted to do something like what you described in AttackMove2:
  • Periodic
    • Events
      • Time - Every 30.00 seconds of game time
    • Conditions
    • Actions
      • -------- Create an array of points at the position of each hero: --------
      • Set VariableSet TempInt = 0
      • Unit Group - Pick every unit in HeroGroup and do (Actions)
        • Loop - Actions
          • Set VariableSet TempInt = (TempInt + 1)
          • Set VariableSet TempPoints[TempInt] = (Position of (Random unit from HeroGroup))
      • -------- --------
      • -------- Get 2 zombies and order them to attack at a random one of these points: --------
      • Set VariableSet TempGroup = (Random 2 units from ZombieGroup)
      • Unit Group - Pick every unit in TempGroup and do (Actions)
        • Loop - Actions
          • Unit - Order (Picked unit) to Attack-Move To TempPoints[(Random integer number between 1 and TempInt)]
      • -------- --------
      • -------- Clean up memory leaks: --------
      • Custom script: call DestroyGroup (udg_TempGroup)
      • For each (Integer TempLoop) from 1 to TempInt, do (Actions)
        • Loop - Actions
          • Custom script: call RemoveLocation (udg_TempPoints[udg_TempLoop])

To answer your questions:
1) Your AddHeroestoUnitGroupHeroes trigger is fine but couldn't you achieve the same effect by using the "A unit enters playable map area" event? This would only trigger once when the hero first enters the map. Or you could possibly use the unit is Sold event if they're purchased from a Tavern or Finishes Training if they come from an Altar.

2) A Unit variable won't lose track of it's unit unless the unit gets replaced, so be cautious when using the Replace Unit function since this actually removes the original unit and creates an entirely NEW unit at it's position (borrowing hp/mana properties from the original unit).

3) If each player controls a single hero then it's always good practice to track the heroes using a Unit array. You can use the player number as the index in this array. For example: PlayerHero[1] = Red's hero. PlayerHero[2] = Blue's hero. PlayerHero[3] = Teal's hero.

This allows you to make simple triggers like:
Pick every player in Users -> Set Variable PN = Player number of picked player -> Kill PlayerHero[PN]

The above trigger would kill each of the user's heroes.

4) Speaking on attack priority, what you described is already pretty much how warcraft 3 AI works. A Wall won't be targeted over a damaging unit. I believe giving a unit Fortified Armor has this "low attack target priority" property as well.

Important note:
Be careful when using "Temp" variables, or any Variable that you Set repeatedly throughout multiple triggers. It's possible that one trigger can set off another trigger MID execution, causing these variables to get overwritten if they're shared between them.

For example:
  • TriggerA
  • Events:
  • Unit - A unit dies
  • Actions:
  • Set Variable Point = Position of dying unit
  • Unit - Create 1 Zombie at Point
  • Special Effect - Create a Special Effect at Point of type Animate Dead
  • Trigger B
  • Events:
  • Unit - A unit enters the map
  • Actions:
  • Set Variable Point = Center of the map
This is a problem! The "Create Zombie" action from Trigger A will cause Trigger B to execute IMMEDIATELY, and since Trigger B sets the Point variable as well, the original value (Position of dying unit) is overwritten. This will result in the Special Effect being created at the (Center of the map) instead of the desired location which would be the (Position of the dying unit).
 

Attachments

  • Group Examples.w3m
    18.6 KB · Views: 12
Last edited:
Level 2
Joined
Jul 12, 2021
Messages
6
In the tempZombieGroup variable in which I set that variable to be equal to that of units owned by player 12 (brown), does that not only add in living zombies? Or do all the previous dead ones also count as owned by player 12 (brown), and therefore also gets added into that group potentially by random?

So In order to avoid adding in the dead zombies from random, instead of doing:
Set VariableSet TempZombieGroup = (Random 2 units from (Units owned by Player 12 (Brown).))

I should put every new zombie that gets spawned in the middle (MidCenter) or playable map area, to a variable that keeps all zombies (LivingZombieGroup), and then do (if I follow your examples with my own variable names):

LivingZombieGroup (Triggername), Variable LivingZombieGroup (variable type - unit group, not array)
Events
Unit - A unit enters region (MidCenter)
Conditions - (Owner of (Triggering unit)) Equal to Player 12 (Brown)
Actions - Unit Group - Add (Triggering unit) to LivingZombieGroup

And this then sets up the variable so that I can replace (United owned by Player 12 (Brown) with LivingZombieGroup for the variable TempZombieGroup to pick random units off of.

Events - Time - Every 30 seconds of time
Actions - Set VariableSet TempLocHeroes = (Position of (Random unit from UnitGroupHeroes))
Set VariableSet TempZombieGroup = (Random 2 units from (LivingZombieGroup)).
Unit Group - Pick every unit in TempZombiegroup and do (Unit - Order (Picked Unit) to (Attack-move to TempLocHeroes)
Custom Script: call DestroyGroup(udg_TempZombieGroup)
Custom Script: call RemoveLocation(udg_TempLocHeroes)


Then when they die
DeadZombies
Events - Unit - a unit owned by Player 12 (Brown) Dies
Conditions (Owner of (Triggering unit)) Equal to Player 12 (Brown)
Actions - Unit Group - Remove (Triggering unit) from LivingZombieGroup

I don't understand what the (Level of Zombie Group class for (Triggering unit) equal to 1, means. Is it referring to the level of the zombie?


So I just use unit group variable type? no arrays or unit? For the purpose of storing units in variables.

Would the "MidToHeroAttack" work okay? Or should it be setup to be like you did with the variables, but I'm not sure what TempInt stands for, or if it's an integer, or point, and which one should be a point array. Or why is it setup like:
Set variableSet TempPoints[TempInt]

And how one would set it up like that.
I'm guessing the TempPoints is the point array, but I don't understand the setup with [TempInt] right after.


Is the Custom script: call Remove/Destroy Location/Group (udg_variablename) enough to prevent memory leaks? Or the only thing one needs to do to prevent memory leaks/lag? I suppose also making some units more expensive and more dmg/hp so you don't need as many units, to also be helpful in order to prevent lag.

In the Custom script: call RemoveLocation (udg_TempPoints[udg_TempLoop]), is the "(udg_TempLoop])" in order to stop the "Loop - Actions"?

Could I turn off the AddHeroestoUnitGroupHeroes trigger, by just creating a 60sec time elapsed event, which then has the action of: Trigger- Turn off AddHeroestoUnitGroupHeroes <gen>?

Thanks for help.
 

Attachments

  • LivingZombies.PNG
    LivingZombies.PNG
    6.1 KB · Views: 14
  • DeadZombies.PNG
    DeadZombies.PNG
    5.9 KB · Views: 17
  • MidToHeroAttack.PNG
    MidToHeroAttack.PNG
    13.3 KB · Views: 16
  • TurnOffTrigger.PNG
    TurnOffTrigger.PNG
    4.9 KB · Views: 16

Uncle

Warcraft Moderator
Level 64
Joined
Aug 10, 2018
Messages
6,535
Your triggers look good to me. Also, you should look into this: How To Post Your Trigger

Anyway, to answer some of your questions:

1: Zombie Group Class is an ability based on Storm Hammers that does nothing besides act like a unit Classification for your triggers. It's hidden from sight and is given to each unit that you want to Add to the ZombieGroup unit group.

You would add this ability to all of your Zombie units in the Object Editor. This is simply an alternative method to getting Zombie units. You could instead use the (Is owned by Player 12) condition, both are fine. I just like having complete control over things, since you can imagine (Units owned by Player 12) is pretty general, that includes Structures and maybe units that you don't actually want to attack. Whereas if you look for units with the Zombie Class ability, you know for a fact that these units are meant to be added to the group.

2: That being said, there's nothing stopping you from filtering the units owned by Player 12 like so:
  • Set VariableSet TempGroup = (Units owned by Player 12 (Brown) matching (((Matching unit) is A Hero) Equal to False).)

Or if you don't like using the Matching unit design (I personally hate it) then you can do it like this. This is slightly less efficient but it shouldn't matter:
  • Actions
    • -------- Get all units owned by Player 12 and then remove the unwanted ones: --------
    • Set VariableSet TempGroup = (Units owned by Player 12 (Brown).)
    • Unit Group - Pick every unit in TempGroup and do (Actions)
      • Loop - Actions
        • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
          • If - Conditions
            • ((Picked unit) is alive) Equal to True
            • ((Picked unit) is A structure) Equal to False
            • ((Picked unit) is A Hero) Equal to False
          • Then - Actions
            • -------- It's a valid target - do nothing --------
          • Else - Actions
            • Unit Group - Remove (Picked unit) from TempGroup.
    • -------- --------
    • -------- Random 2 zombies: --------
    • Set VariableSet TempGroup2 = (Random 2 units from TempGroup)
    • Unit Group - Pick every unit in TempGroup2 and do (Actions)
      • Loop - Actions
        • Unit - Order (Picked unit) to Attack-Move To Somewhere
    • -------- --------
    • -------- Clean up memory leaks: --------
    • Custom script: call DestroyGroup (udg_TempGroup)
    • Custom script: call DestroyGroup (udg_TempGroup2)

3: TempInt is an Integer variable that I use as the Index in my Point array. I use it in order to create a Point at the position of each player hero. Then I order the Zombies to attack towards these points at random.

So if there were 3 heroes in the game owned by p1, p2, and p3.
TempPoint[1] = Position of first hero
TempPoint[2] = Position second hero
TempPoint[3] = Position of third hero

Then the Zombies are ordered to attack towards TempPoint[Random number between 1 and 3]. So basically each Zombie attacks towards one of these points at random.

If you wanted the zombies to all attack towards the same Point then you could instead change this design to store a single point instead of an array of points.
Like:
  • Set Variable TempPoint = Position of random unit from HeroGroup
Then order the picked zombies to attack there.

Some tutorials that will help:
 
Last edited:
Level 2
Joined
Jul 12, 2021
Messages
6
The AddHeroesToUnitGroupHeroes trigger could be:

AddHeroes.PNG


And then this to turn it off:

TurnOffTrigger.PNG


But I felt like that might be inaccurate, and not as deliberate as I would like it to be. I would like to be able to count the number of players that are playing in that specific match, and having a trigger to turn off the AddHeroestoUnitGroupHeroes after all the heroes that exist on the map has been added.

And I was also worried if, after all the heroes had been added in, if one of the already added heroes then would get added into the unitgroup again? Or would that not really happen? Or that when heroes get revived, that they would then enter into the playable map area again and then get added into the unit group again.

So therefore I tried making this:

Capture10.PNG



Capture12.PNG
 
Last edited:

Uncle

Warcraft Moderator
Level 64
Joined
Aug 10, 2018
Messages
6,535
I think you're overthinking this. It's probably not that important to turn off the trigger.

But if you must, there's a boolean Condition to check if a Unit Group contains a unit already.
IE: If entering unit is in UnitGroupHeroes = False
So it won't run the Actions if the unit is already in the group.

Note that it's okay to try to add a unit into a unit group again, the function is smart and won't cause any problems.

Also, if I were you I'd be keeping track of my players in Player Groups like this:
ActiveUsers = all users currently playing.
Users = all users regardless of current status (so leavers included).

Then you can easily reference them at any time with Pick every player in functions.

Just make sure to remove Leavers from the ActiveUsers group.
IE: Player X leaves the game -> Remove Player X from ActiveUsers.
 
Last edited:
Status
Not open for further replies.
Top