I think the first post is long enough to warrant another one for clarity's sake.
Okay, so how do we do it my way? It'd be the easiest to use either
hashtables or
dynamic indexing. The links in previous sentence will take you to really good guides on both. It doesn't really matter which one you pick, both are fine and both will allow you to keep track of each unit individually. Since I prefer hashtables (and think they're much easier to get into than indexing), I'll explain how to use them.
---
Imagine a regular table, where you named rows by using letters A, B, C (...) columns by using numbers 1, 2, 3 (...):
View attachment 381314
Now, if I asked you to tell me which table cell is green, you can easily do so by describing both the row and the column it uses. In the case of the example above, the answer would be Row C and Column 4 -> C4. Alternatively, you could also say something like this: "Column 4 of Row C". Remember this.
That's exactly how hashtables work. Okay, but how does this help us? Well, each unit has a certain hidden
unique number attached to it called the handle ID, which can be used by hashtables to describe where the data should be or is stored. For instance, let's say a Footman unit has the ID 24312 - you can read and use that number to point toward a data cell inside a hashtable.
That way you can have a row 24312 where in columns 1, 2, 3, etc. you store the data corresponding to that Footman. If you want to store some data about it then you can just tell the hashtable to use "Column 1 of Row 24312". That's exactly what this action does:
View attachment 381320
Now, the key to navigating hashtables is consistency. If you're going to store a certain data type (e.g. a duration of an effect), it's best that you use the same "column" for every row to do it. What this does is create a situation where just by the unit's handle ID (which is your row number), you can easily access desired data, because the column for that type of data is always the same and known to you.
So, let's say you want to store a 30 seconds timer for each unit - 30 is going to be the information you store, unit's handle ID will be your row number and the column number is your choice, though it's preferrable to start with the first one, which in hashtables is described by number 0.
Let's do this:
1. If we want to use a hashtable, we have to first create it. It's also smart to put it under some hashtable variable, so that you can easily reference it. You're free to do it whenever you want, but since the intention appears to be for the timer to run the entire game, it'd probably be best to do it at map initialization. All you need to do that are these two simple actions:
-
Actions
-

Hashtable - Create a hashtable
-

Set MyFirstHashtable = (Last created hashtable)
2. Now that we have our hashtable ready to go, we need to store our data. And here's where you have to make a choice - how accurate do you want to be with it? If you're comfortable checking/updating the timer every second, I'd recommend going with integers (full numbers), you might want to go with reals (decimal numbers). This matters, because both integers and reals use a different action to store its value in a hashtable.
For the sake of keeping this easy, I'll go with integers and checking the timer every 1 second. Okay, so let's store our data. First pick all units owned by the Neutral Hostile player and bind it to a unit group variable (you'll need it!):
-
Actions
-

Set NeutralHostileUnits = (Units owned by Neutral Hostile)
I'd recommend doing this right after creating the hashtable, so that the timer starts immediately when the map launches. Now, pick all units in the group:
-
Actions
-

Set NeutralHostileUnits = (Units owned by Neutral Hostile)
-

Unit Group - Pick every unit in NeutralHostileUnits and do (Actions)
And add a hashtable action - Save Integer - and fill it in with the timer duration (30 seconds), your "column" number (0) and the hashtable variable:
View attachment 381322
Now, when you click at the last unfilled value, you're going to be greeted with this:
View attachment 381323
This allows you to read the units handle ID. Since we're using this action inside a "Pick all units" action, we want to read the handle ID of a unit that is currently being picked, so click on "Handle" and find "Picked Unit" in the dropdown menu. That's all. Your completed action should look like this:
-
Actions
-

Set NeutralHostileUnits = (Units owned by Neutral Hostile)
-

Unit Group - Pick every unit in NeutralHostileUnits and do (Actions)
-


Loop - Actions
-



Hashtable - Save 30 as 0 of (Key (Picked unit)) in MyFirstHashtable
What this does is that every unit in the group (i.e. every unit owned by Neutral Hostile), will have 30 stored under "Column 0" of their handle ID "Row" in the hashtable. One more important thing - don't remove this unit group. It's not a leak, because we're going to be using it. Here's how:
a) Create a trigger like this:
-
TriggerName
-

Events
-


Time - Every 1.00 seconds of game time
-

Conditions
-

Actions
-


Unit Group - Pick every unit in NeutralHostileUnits and do (Actions)
b) Create an integer variable and set it's value under "Loop - Actions". When you click on the "Value" field, select the function called: "Hashtable - Load Integer Value (hashtable). This one:
View attachment 381325
You'll need to fill in the "Column" and "Row" numbers plus the name of the Hashtable. It's done exactly the same as above. You should get this:
-
Actions
-

Unit Group - Pick every unit in NeutralHostileUnits and do (Actions)
-


Loop - Actions
-



Set IntegerVariable = (Load 0 of (Key (Picked unit)) from MyFirstHashtable)
Here's where the magic happens. Add actions to make the trigger look like this:
-
Unit Group - Pick every unit in NeutralHostileUnits and do (Actions)
-

Loop - Actions
-


Set IntegerVariable = (Load 0 of (Key (Picked unit)) from MyFirstHashtable)
-


Set IntegerVariable = (IntegerVariable - 1) // use the Arithmetic function in the value field of Set Variable
-


If (All Conditions are True) then do (Then Actions) else do (Else Actions)
-



If - Conditions
-




IntegerVariable Equal to 0
-



Then - Actions
-




-------- Add your ability to (Picked unit) here --------
-



Else - Actions
-


Hashtable - Save IntegerVariable as 0 of (Key (Picked unit)) in MyFirstHashtable
Why? Let's go through it together - what happens is that you read the timer value from the hashtable and store it in the IntegerVariable. Then you reduce it by 1 to account for the fact that 1 second has passed since you last read the timer value. And then you check - if the variable is equal to 0, that means the timer was depleted (i.e. the unit wasn't in combat for the required amount of time) and so you can give it your ability.
Then you simply store the new updated timer value in the hashtable (overwriting the old one) for future use. So, in practice - each unit will have its "0" column in hashtable go like this: 30 -> 29 -> 28 -> ... -> 0 (apply ability) -> -1 -> -2, etc. That's the individualized timer I've talked about.
---
So, how does this solve your problem? Well, if you do something like this:
-
TriggerName
-

Events
-


Unit - A unit Is attacked
-

Conditions
-

Actions
-


If (All Conditions are True) then do (Then Actions) else do (Else Actions)
-



If - Conditions
-




(Owner of (Triggering unit)) Equal to Neutral Hostile
-



Then - Actions
-




-------- Remove your healing ability here --------
-




Hashtable - Save 30 as 0 of (Key (Triggering unit)) in MyFirstHashtable
-



Else - Actions
-




If (All Conditions are True) then do (Then Actions) else do (Else Actions)
-





If - Conditions
-






(Owner of (Attacking unit)) Equal to Neutral Hostile
-





Then - Actions
-






-------- Remove your healing ability here --------
-






Hashtable - Save 30 as 0 of (Key (Attacking unit)) in MyFirstHashtable
-





Else - Actions
Then every time a neutral hostile unit is attacked or attacks, the timer value stored in the hashtable is going to be set back to its full value of 30, meaning that in order for the unit to get the healing ability, it will have to wait full 30 seconds.
The final piece of the puzzle is this:
-
TriggerName
-

Events
-

Conditions
-


((Triggering unit) is in NeutralHostileUnits) Equal to True // Boolean condition, function: Unit - Unit in Unit Group
-

Actions
-


Unit Group - Remove (Triggering unit) from NeutralHostileUnits
-


Hashtable - Clear all child hashtables of child (Key (Triggering unit)) in MyFirstHashtable // Hashtable - Clear Child Hashtable
The purpose of this little trigger is to remove all Neutral Hostile units from the timer system and clear all their timer data so that you don't have any unnecessary timer checks or pointlessly stored data.
That'd be all. I know it's a lot of reading, but trust me - hashtables are EXTREMELY useful, so learning them (or indexing) is really worth it