GUI: How to make Triggered Ability Work for Multiple Players/Heros

Status
Not open for further replies.
Level 2
Joined
Oct 25, 2019
Messages
11
In GUI, I designed a triggered summon demon spell that uses a variable to mark the caster and the summoned demon. The caster "controls" the demon with a siphon mana based ability that once stopped, causes demon to turn hostile and attack caster. It works fine for a single unit casting it, but when I several units cast, it obviously has issues because the variables get reassigned. For example, first caster summons demon, then a second caster summons thus the first demon loses its variable assignment and no longer will turn hostile.


How can I design the spell such that I can have multiple iterations of it, without reassigning my variables and causing problems?


(Initial event spell "channeled based")
1629465297020.png



(End of spell effect)
1629465356644.png


Ability Description: Summons a demon that fights for you until your mana leash stops casting, then control is lost and it will attack you.

(Summary) How to make this spell work properly for multiple units if they cast it simultaneously?
 

Uncle

Warcraft Moderator
Level 73
Joined
Aug 10, 2018
Messages
7,866
We call triggers that work for multiple units MUI and multiple players MPI.

Easiest method for MUI triggers: GUI Unit Indexer 1.4.0.0
More advanced method that can be used for just about anything: Visualize: Dynamic Indexing
You can even combine the Unit Indexer system with Dynamic Indexing to have even further control.

Hashtables are another option and offer even greater control than Unit Indexing. They're just slightly more advanced and a bit more awkward/difficult to use: A Complete Beginners Guide to Hashtables

In your case you'll be using Arrays to make your trigger work, you can read more about them here: [Trigger] - Loops and Arrays tutorial
That link isn't great but I couldn't find a better tutorial.

Arrays are pretty simple though, you enable them when creating a Variable and then it adds these brackets [] to your variable. Inside of these brackets you assign an integer value that can be anywhere from 0 -> 32,768. This integer is known as the Index of the Array. This index allows you to store up to 32,768 different values to a single variable, for example:
  • Set Variable HumanUnits[0] = Peasant
  • Set Variable HumanUnits[1] = Footman
  • Set Variable HumanUnits[2] = Rifleman
  • Set Variable HumanUnits[3] = Knight
HumanUnits is a Unit-type variable with an Array enabled. Instead of creating 4 different Variables to keep track of the Human Unit-types I can simply store all of them (technically only up to 32,768 but that's more than you'll ever need) inside of a single Array variable. Their [Index] is what sets them apart, it acts almost like a grocery list where you number every item you want to buy. 1: Milk, 2: Eggs, 3: Carrots, etc...

Here's an example of referencing an Array variable. I'm creating a Rifleman using the HumanUnits variable:
  • Unit - Create 1 HumanUnits[2] for Player 1 (Red) at center of playable map area
HumanUnits[2] = Rifleman. This is the most basic use of an Array, however, there are more advanced things you can do with the Index instead of just numbering things in order. The Unit Indexer is a good example of an advanced use of Arrays/Indexes.

About Array Size: You can almost always leave an Array's Size at the default value of 1. There's only a few variables that actually require you to change the Size of the Array. Doing so defines how large an Array's Index can go up to (32,768 is the limit). This is reserved for things like Timers, Unit Groups, and Player Groups. Otherwise, don't worry about the Size just leave it at 1.


So with your triggers in mind the correct solution actually depends.
If each Player can only control 1 of these "casters" then you can use a simple MPI method:
  • Events:
  • Unit - A unit Starts the effect of an ability
  • Conditions:
  • (Ability being cast) Equal to Chained Demon
  • Actions:
  • Set Variable CD_PN = Player number of Triggering player
  • Unit - Create 1 Doom Guard for Triggering player...
  • Set Variable CD_Demon[CD_PN] = Last created unit
  • do other necessary stuff...
  • Events:
  • Unit - A unit Stops casting an ability
  • Conditions:
  • (Ability being cast) Equal to Mana Leash
  • Actions:
  • Set Variable CD_PN = Player number of Triggering player
  • Unit - Change ownership of CD_Demon[CD_PN] to Neutral Hostile
  • Unit - Order CD_Demon[CD_PN] to Attack Triggering unit
  • Unit - Remove Mana Leash from Triggering unit

If a player can have multiple casters then I would recommend using the Unit Indexer method to make it MUI:
  • Events:
  • Unit - A unit Starts the effect of an ability
  • Conditions:
  • (Ability being cast) Equal to Chained Demon
  • Actions:
  • Set Variable CD_CV = Custom value of Triggering unit
  • Unit - Create 1 Doom Guard for Triggering player...
  • Set Variable CD_Demon[CD_CV] = Last created unit
  • do other necessary stuff...
  • Events:
  • Unit - A unit Stops casting an ability
  • Conditions:
  • (Ability being cast) Equal to Mana Leash
  • Actions:
  • Set Variable CD_CV = Custom value of Triggering unit
  • Unit - Change ownership of CD_Demon[CD_CV] to Neutral Hostile
  • Unit - Order CD_Demon[CD_CV] to Attack Triggering unit
  • Unit - Remove Mana Leash from Triggering unit

Important notes:

- Triggering player IS the Owner of the Casting unit.
That being said, there is potential for Triggering player to change to something else if you're not careful, in which case you can use (Owner of Triggering unit) instead. You should probably just use (Owner of Triggering unit) in your triggers to be safe for now.

- Triggering unit IS the Casting unit. It's recommended to use Triggering unit whenever possible as it's value will remain the same throughout your trigger, even after Wait actions. Some other Event Responses will lose their value after using a Wait action.

- I scrapped the Chained_Demon_Caster variable as it's not necessary. We always have a reference to this unit since it's the one that fired the Spell Cast Event.

- You actually need the Unit Indexer system imported into your map in order for the last pair of triggers I posted to work. This system automatically assigns a unique custom value to each unit when they're first created (whether that be trained, sold, summoned, etc). As a result, you can save data directly to a unit by putting it's custom value into the [Index] of your Array variables. For example, if you wanted to track a unit's kills then you could create an Integer array called Kills, and then whenever a unit dies simply do this:
  • Set Variable Kills[Custom value of Killing unit] = Kills[Custom value of Killing unit] + 1
Since no two units will ever share the same custom value then no two units will ever share the same Index in an Array. It's like each unit gets their own Index reserved for them. HOWEVER, note that the Unit Indexer that I linked will recycle custom values that are no longer in use. This can occur when a non-hero unit dies, because once it's no longer in the game the system will "recycle" and assign it's custom value to a future unit if possible. This can be a problem since any variables that the old unit was using will still have their previous values. In other words, a newly created unit may be assigned a custom value that had 100+ Kills[] already. The solution: Reset these variables back to their default values when the unit dies. Alternatively, reset them when the unit is first created.
 
Last edited:
Level 2
Joined
Oct 25, 2019
Messages
11
Thanks a million, Ive never understood arrays before, and thought I would have to manually define multiple indexes for it to work. Great help!
 

Uncle

Warcraft Moderator
Level 73
Joined
Aug 10, 2018
Messages
7,866
No problem. Another thing about your triggers that just came to mind. I'm almost certain that it's possible to interrupt the casting of Mana Leash before it even gets a chance to start. This would result in a permanent player-owned demon and can be abused. A solution would be to add a very short Wait at the end of the Chained Demon trigger and after that Wait check to see the Current order of the Triggering unit (caster). If it's current order is not equal to "siphonmana" or whatever the order string is for the Siphon Mana ability, then proceed to end the effects of the ability (remove Mana Leash, change owner of Demon, etc). That SHOULD work if orders work the way I think they do.
 
Last edited:
Level 2
Joined
Oct 25, 2019
Messages
11
No problem. Another thing about your triggers that just came to mind. I'm almost certain that it's possible to interrupt the casting of Mana Leash before it even gets a chance to start. This would result in a permanent player-owned demon and can be abused. A solution would be to add a very short Wait at the end of the Chained Demon trigger and after that Wait check to see the Current order of the Triggering unit (caster). If it's current order is not equal to "siphonmana" or whatever the order string is for the Siphon Mana ability, then proceed to end the effects of the ability (remove Mana Leash, change owner of Demon, etc). That SHOULD work if orders work the way I think they do.
Good point I'll check it out .

Also, I implemented the changes and it works great. The only strange thing is that I had to put a wait time before I order triggering unit to Mana leash the demon. With a .01 wait time it works though
 
Status
Not open for further replies.
Top