• 🏆 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!
  • 🏆 Hive's 6th HD Modeling Contest: Mechanical is now open! Design and model a mechanical creature, mechanized animal, a futuristic robotic being, or anything else your imagination can tinker with! 📅 Submissions close on June 30, 2024. Don't miss this opportunity to let your creativity shine! Enter now and show us your mechanical masterpiece! 🔗 Click here to enter!

[Solved] MUI Passive Abilities and Auras with Triggers?

Status
Not open for further replies.
Level 3
Joined
Dec 7, 2020
Messages
20
Hello guys!

I've been using Bribe's indexing system to make my units MUI, based off his template, but I've found myself kind of stuck when it comes to passives and auras. First of all, this abilities aren't learnt, they're unit abilities so they come naturally with the hero, so I cannot initiate the trigger with "A unit learns an ability."; second, I don't know how to disable the necessary trigger/abilities only for an specific unit.

What I'm trying to do is basically Muradin's Second Wind from HotS, he regenerates health every second, but receiving damage deactivates the regeneration for a while. Chopinski does exactly what I want with his Muradin Hero Concept, but he uses JASS and I just can't understand much of it, if anything at all.

So, is there a way to do this with GUI, while keeping it MUI? There are other abilities planned that function somewhat similar so it'd be great to find a solution.
 

Uncle

Warcraft Moderator
Level 64
Joined
Aug 10, 2018
Messages
6,583
So we're aiming to create this effect: Muradin restores 55 (+4% per level) Health per second when he has not taken damage for 4 seconds. When below 40% Health, increased to 111 (+4% per level) Health per second.

For the sake of simplicity we will make this ability only add 10 Life (Health) per second and disregard all of the %/low life stuff.

First you would need to know whether or not your unit has taken or dealt damage in the last 4 seconds. To do this, you need a Damage Event, which can be provided by a Damage system like this: Damage Engine 5.7.1.2

Next, you would want to create an ability that adds 10 Life regen. There are multiple passive abilities that add Life regen but let's go with the Item Life Regen ability.

Then, create an ability that we will use for strictly Art purposes. Note that this is optional. I based this ability on Unholy Aura and set it up so that it does nothing besides create a Special Effect (Art - Target) on our unit.

Then, we add both of these abilities to our unit by default. Do this in the Object Editor.

Finally, we create our trigger so that whenever our unit takes/deals damage, we remove both of these abilities from it, since it's now in combat.

Then after 4 seconds has passed while being out of combat, we add these abilities back to our unit.

To manage this we can use the Unit Indexer, Damage Engine, and a simple counter method using an Integer array. When our unit takes/deals damage increase it's counter by 1 and if it's counter is equal to 1 then remove the abilities. After 4.00 seconds, check if our unit is even still alive, and if so reduce this counter by 1. If it's counter is back to 0 after this reduction, add the abilities back to the unit because this means that it hasn't dealt damage/been damaged in the last 4 seconds.

To achieve this so that it's MUI I use a trick called Shadowing Globals found here: local udg_

Here are the Triggers:
This Event is used by the Damage Engine. It happens whenever A unit takes damage.
  • Regen Damage Event
    • Events
      • Game - DamageEvent becomes Equal to 1.00
    • Conditions
    • Actions
      • -------- Find out which one of the units was our Regen unit (Damaged unit or Damaging unit). --------
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (Unit-type of DamageEventSource) Equal to Footman
          • (DamageEventSource is alive) Equal to True
        • Then - Actions
          • Set VariableSet Regen_Unit_Initial = DamageEventSource
          • Trigger - Run Regen Counter <gen> (ignoring conditions)
        • Else - Actions
      • -------- --------
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (Unit-type of DamageEventTarget) Equal to Footman
          • (DamageEventTarget is alive) Equal to True
        • Then - Actions
          • Set VariableSet Regen_Unit_Initial = DamageEventTarget
          • Trigger - Run Regen Counter <gen> (ignoring conditions)
        • Else - Actions
  • Regen Counter
    • Events
    • Conditions
    • Actions
      • Custom script: local unit udg_Regen_Unit
      • Set VariableSet Regen_Unit = Regen_Unit_Initial
      • -------- --------
      • -------- We're using this local variable in conjunction with a trick you can read about here: https://www.hiveworkshop.com/threads/local-udg_.248534/ --------
      • -------- This is done so that we can keep track of our Damaged/Damaging unit after the 4.00 second Wait without having MUI issues. --------
      • -------- --------
      • -------- Increase our Regen Units counter by 1. As long as this value is > 0 then we know that the unit is in combat. --------
      • Set VariableSet CV = (Custom value of Regen_Unit)
      • Set VariableSet Regen_InCombat[CV] = (Regen_InCombat[CV] + 1)
      • -------- --------
      • -------- If the counter is equal to 1 then we know that our unit wasn't in combat prior to this. Now we remove the regen/art. --------
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • Regen_InCombat[CV] Equal to 1
        • Then - Actions
          • Unit - Remove Life Regen (Heal) from Regen_Unit
          • Unit - Remove Life Regen (Art) from Regen_Unit
        • Else - Actions
      • -------- --------
      • Wait 4.00 seconds
      • -------- --------
      • -------- If the regen unit is still alive after 4 seconds, reduce it's counter by 1 and check if it's equal to 0 (out of combat entirely). --------
      • Custom script: if ( IsUnitAliveBJ(udg_Regen_Unit) ) then
      • Set VariableSet CV = (Custom value of Regen_Unit)
      • Set VariableSet Regen_InCombat[CV] = (Regen_InCombat[CV] - 1)
      • -------- --------
      • -------- If out of combat entirely, add back the life regen and art. --------
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • Regen_InCombat[CV] Equal to 0
        • Then - Actions
          • Unit - Add Life Regen (Heal) to Regen_Unit
          • Unit - Add Life Regen (Art) to Regen_Unit
        • Else - Actions
      • Custom script: endif
      • -------- --------
      • -------- Clean up unit memory leak (only necessary because the Unit is stored in a local variable) --------
      • Custom script: set udg_Regen_Unit = null
  • Regen Death
    • Events
      • Unit - A unit Dies
    • Conditions
      • (Unit-type of (Triggering unit)) Equal to Footman
    • Actions
      • -------- The Unit Indexer recycles unused Custom Values (aka those of dead/removed units). --------
      • -------- Because of that we want to make sure that Regen_InCombat is reset back to 0 after a unit dies. --------
      • -------- This way if a new unit were to be given this Custom Value it wouldn't have a value that was previously set to something > 0. --------
      • Set VariableSet CV = (Custom value of (Triggering unit))
      • Set VariableSet Regen_InCombat[CV] = 0
Remember to replace all instances of Footman with your desired Unit-Type. Also, make sure to use the correct regen/art abilities, as these can change during the copy/paste/import process.

Further explanation:
So the whole Trigger - Run Regen Counter <gen> (ignoring conditions) setup is used because whenever a Footman is damaged by another Footman, the Damage Event runs once (A unit takes damage), but both the Damaged unit and Damaging unit are Footman, so they both need to be set to the "In Combat" state and have their Counters increased/decreased by 1 at the same exact time. This design allows that to happen inside the same trigger without any issues.

Having a separate trigger (Regen Counter) allows this to be possible due to the nature of running triggers. Each time you run a trigger it creates a new instance of itself, which is useful in this case since that means that the 4.00 second Wait won't interfere with anything else. Otherwise, if I had two 4.00 second Waits in the same trigger, one unit would have it's Counter reduced after 4s, and the other after 8s, because the first Wait would delay the second Wait.

Note that this design isn't necessary, and you could instead have two triggers that use the Damage Event. One that checks if the DamageEventSource (damaging unit) is a Footman, and the other that checks if the DamageEventTarget (damaged unit) is a Footman.

I use this alternate method in the attached map: Out of Combat Regen 3 alternate.

The only reason I don't like this method is because if you want to change something in 1 of the 2 triggers, you have to change it in both. This isn't a massive issue but I like to keep things organized whenever possible.

Edit: Uploaded version 3, completely redesigned it and fixed some issues. If you have any other versions before 3, delete them.
 

Attachments

  • Out of Combat Regen 3.w3m
    63 KB · Views: 12
  • Out of Combat Regen 3 alternate.w3m
    64.4 KB · Views: 27
Last edited:
Level 3
Joined
Dec 7, 2020
Messages
20
Thank you, that worked like a charm!

There's a little problem tho. Upon death, the ability isn't restored to the dying unit. Since in this case it's a hero, resurrecting him results in the ability missing until he is attacked and 4 seconds pass again. I tried fixing it by restoring the ability on the On Death trigger, but that somehow caused the other triggers to stop working; I have three Muradins in my map, if one dies and I restore his ability trough the On Death trigger, the Regen Damage Event Source stops working only on that specific Muradin that died, or at the least it doesn't remove the abilities any longer. I also tried restoring the abilities upon creation by using Bribe's Unit Event but I didn't achieve anything at all.

It's not a big deal and I can live with it, still I wanted to ask if there is a solution to this little inconvenience.

On a mostly different topic, there's another ability I need to make. I suppose it's fine to ask in the same post since it's a related topic. I hope as well that you don't mind. Okay, so the ability goes like this: Hero A (still not named) regenerates a percentage of his health, say 1%, every second for every unit around him that meets a specific requirement, up to, say 5%/second. In this case, the requirement is being female. I already have coded the ability and it works, but 1) When I coded it it was a learnt ability, but now I want it as a passive trait, just like Muradin's Second Wind. 2) It's not MUI.

I think the actual code can better explain what I'm trying to do:


This is the code I have. You may notice some horrible mistakes such as that way of creating a group or that I use the Do Nothing function, that's because it's an old trigger, among the first I did.

  • Flirty Life
    • Events
      • Unit - A unit Learns a skill
    • Conditions
      • (Learned Hero Skill) Equal to Flirty Life *****
    • Actions
      • -------- Set the Hero and start the effects --------
      • Set VariableSet _Temp_TriggeringUnit_1 = (Learning Hero)
      • Trigger - Turn on Flirty Life Check <gen>
  • Flirty Life Check
    • Events
      • Time - Every 3.00 seconds of game time
    • Conditions
    • Actions
      • -------- Reset _Temp_Number_1 for the next time this triggers --------
      • Set VariableSet _Temp_Number_1 = 0
      • -------- Pick the group --------
      • Set VariableSet _Temp_Group_1 = (Units within 500.00 of (Position of _Temp_TriggeringUnit_1) matching ((((Matching unit) belongs to an ally of (Owner of _Temp_TriggeringUnit_1).) Equal to True) and (((Matching unit) is alive) Equal to True)).)
      • Unit Group - Pick every unit in _Temp_Group_1 and do (Actions)
        • Loop - Actions
          • -------- Check whether the unit is female (according to me anyways) --------
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • Or - Any (Conditions) are true
                • Conditions
                  • (Unit-type of (Picked unit)) Equal to Sorceress
                  • (Unit-type of (Picked unit)) Equal to Banshee
                  • (Unit-type of (Picked unit)) Equal to Archer
                  • (Unit-type of (Picked unit)) Equal to Huntress
                  • (Unit-type of (Picked unit)) Equal to Dryad
                  • (Unit-type of (Picked unit)) Equal to Priestess of the Moon
                  • (Unit-type of (Picked unit)) Equal to Warden
                  • (Unit-type of (Picked unit)) Equal to Shandris Feathermoon
            • Then - Actions
              • -------- Every time there is a female, increase _Temp_Number_1 --------
              • Set VariableSet _Temp_Number_1 = (_Temp_Number_1 + 1)
            • Else - Actions
              • Do nothing
      • -------- Run the actual healing trigger --------
      • Trigger - Run Flirty Life Regeneration <gen> (checking conditions)
      • Custom script: call DestroyGroup (udg__Temp_Group_1)
  • Flirty Life Regeneration
    • Events
    • Conditions
    • Actions
      • -------- Look for _Temp_Number_1 value --------
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • _Temp_Number_1 Equal to 1
        • Then - Actions
          • -------- According to the value, heal the Hero and display the healed amount --------
          • Unit - Set life of _Temp_TriggeringUnit_1 to ((Life of _Temp_TriggeringUnit_1) + ((Max life of _Temp_TriggeringUnit_1) x 0.01))
          • Floating Text - Create floating text that reads (String(((Max life of _Temp_TriggeringUnit_1) x 0.01))) above _Temp_TriggeringUnit_1 with Z offset 0.00, using font size 10.00, color (0.00%, 100.00%, 25.00%), and 0.00% transparency
          • Floating Text - Change (Last created floating text): Disable permanence
          • Floating Text - Change the fading age of (Last created floating text) to 0.50 seconds
          • Floating Text - Change the lifespan of (Last created floating text) to 2.00 seconds
        • Else - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • _Temp_Number_1 Equal to 2
            • Then - Actions
              • Unit - Set life of _Temp_TriggeringUnit_1 to ((Life of _Temp_TriggeringUnit_1) + ((Max life of _Temp_TriggeringUnit_1) x 0.02))
              • Floating Text - Create floating text that reads (String(((Max life of _Temp_TriggeringUnit_1) x 0.02))) above _Temp_TriggeringUnit_1 with Z offset 0.00, using font size 10.00, color (0.00%, 100.00%, 25.00%), and 0.00% transparency
              • Floating Text - Change (Last created floating text): Disable permanence
              • Floating Text - Change the fading age of (Last created floating text) to 0.50 seconds
              • Floating Text - Change the lifespan of (Last created floating text) to 2.00 seconds
            • Else - Actions
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • _Temp_Number_1 Equal to 3
                • Then - Actions
                  • Unit - Set life of _Temp_TriggeringUnit_1 to ((Life of _Temp_TriggeringUnit_1) + ((Max life of _Temp_TriggeringUnit_1) x 0.03))
                  • Floating Text - Create floating text that reads (String(((Max life of _Temp_TriggeringUnit_1) x 0.03))) above _Temp_TriggeringUnit_1 with Z offset 0.00, using font size 10.00, color (0.00%, 100.00%, 25.00%), and 0.00% transparency
                  • Floating Text - Change (Last created floating text): Disable permanence
                  • Floating Text - Change the fading age of (Last created floating text) to 0.50 seconds
                  • Floating Text - Change the lifespan of (Last created floating text) to 2.00 seconds
                • Else - Actions
                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    • If - Conditions
                      • _Temp_Number_1 Equal to 4
                    • Then - Actions
                      • Unit - Set life of _Temp_TriggeringUnit_1 to ((Life of _Temp_TriggeringUnit_1) + ((Max life of _Temp_TriggeringUnit_1) x 0.04))
                      • Floating Text - Create floating text that reads (String(((Max life of _Temp_TriggeringUnit_1) x 0.04))) above _Temp_TriggeringUnit_1 with Z offset 0.00, using font size 10.00, color (0.00%, 100.00%, 25.00%), and 0.00% transparency
                      • Floating Text - Change (Last created floating text): Disable permanence
                      • Floating Text - Change the fading age of (Last created floating text) to 0.50 seconds
                      • Floating Text - Change the lifespan of (Last created floating text) to 2.00 seconds
                    • Else - Actions
                      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                        • If - Conditions
                          • _Temp_Number_1 Greater than or equal to 5
                        • Then - Actions
                          • Unit - Set life of _Temp_TriggeringUnit_1 to ((Life of _Temp_TriggeringUnit_1) + ((Max life of _Temp_TriggeringUnit_1) x 0.05))
                          • Floating Text - Create floating text that reads (String(((Max life of _Temp_TriggeringUnit_1) x 0.05))) above _Temp_TriggeringUnit_1 with Z offset 0.00, using font size 10.00, color (0.00%, 100.00%, 25.00%), and 0.00% transparency
                          • Floating Text - Change (Last created floating text): Disable permanence
                          • Floating Text - Change the fading age of (Last created floating text) to 0.50 seconds
                          • Floating Text - Change the lifespan of (Last created floating text) to 2.00 seconds
                        • Else - Actions


Is there some way to make this MUI? With the healing being triggered and all that, I get really lost. I really appreciate your help.
 

Uncle

Warcraft Moderator
Level 64
Joined
Aug 10, 2018
Messages
6,583
So since you're using Heroes instead of Units it makes some of what I did unnecessary. You can delete the Regen Death trigger and replace it with a new trigger:
  • Revive
    • Events
      • Unit - A unit Finishes reviving
    • Conditions
      • (Unit-type of Triggering unit) Equal to YourUnitType
    • Actions
      • Unit - Add Life Regen (Heal) to (Triggering unit)
      • Unit - Add Life Regen (Art) to (Triggering unit)
Note that this will bug out if your Hero is put in the Combat state, dies, and then revives <= 4.00 seconds later, because of how the Wait works. But as long as the revive takes longer than 4.00 seconds it shouldn't ever be a problem because this gives enough time for any existing Waits to finish.

Also, and this is most likely not an issue in your map, but if you ever remove one of these Heroes using the Remove Unit action you will want to reset their InCombat integer back to 0. This is only an issue if you create a new one of these Heroes and it uses the same recycled Custom Value of the removed hero. It'll probably never happen and may not even be possible depending on how your map works, but I figured I'd let you know.


For the Female Regeneration stuff:
  • FR Learn
    • Events
      • Unit - A unit Learns a skill
    • Conditions
      • (Learned Hero Skill) Equal to Female Regen (Learn)
    • Actions
      • Unit Group - Add (Triggering unit) to FR_Group
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (FR Loop <gen> is on) Equal to False
        • Then - Actions
          • Trigger - Turn on FR Loop <gen>
        • Else - Actions
  • FR Loop
    • Events
      • Time - Every 3.00 seconds of game time
    • Conditions
    • Actions
      • Unit Group - Pick every unit in FR_Group and do (Actions)
        • Loop - Actions
          • -------- Keep track of the Hero: --------
          • Set VariableSet TempUnit = (Picked unit)
          • -------- --------
          • Set VariableSet FR_Point = (Position of TempUnit)
          • Set VariableSet TempGroup = (Units within 500.00 of FR_Point.)
          • Custom script: call RemoveLocation (udg_FR_Point)
          • -------- --------
          • -------- Find nearby Females: --------
          • Set VariableSet TempInt = 0
          • 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
                  • (Level of Female Classification for (Picked unit)) Equal to 1
                • Then - Actions
                  • Set VariableSet TempInt = (TempInt + 1)
                • Else - Actions
          • Custom script: call DestroyGroup (udg_TempGroup)
          • -------- --------
          • -------- If > 0 Females, restore life: --------
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • TempInt Greater than 0
            • Then - Actions
              • -------- Determine heal amount: --------
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • TempInt Equal to 1
                • Then - Actions
                  • Set VariableSet TempReal = ((Max life of TempUnit) x 0.01)
                • Else - Actions
                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    • If - Conditions
                      • TempInt Equal to 2
                    • Then - Actions
                      • Set VariableSet TempReal = ((Max life of TempUnit) x 0.02)
                    • Else - Actions
                      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                        • If - Conditions
                          • TempInt Equal to 3
                        • Then - Actions
                          • Set VariableSet TempReal = ((Max life of TempUnit) x 0.03)
                        • Else - Actions
                          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                            • If - Conditions
                              • TempInt Equal to 4
                            • Then - Actions
                              • Set VariableSet TempReal = ((Max life of TempUnit) x 0.04)
                            • Else - Actions
                              • Set VariableSet TempReal = ((Max life of TempUnit) x 0.05)
              • -------- --------
              • -------- Heal: --------
              • Unit - Set life of TempUnit to ((Life of TempUnit) + TempReal)
              • Floating Text - Create floating text that reads (String(TempReal)) above TempUnit with Z offset 0.00, using font size 10.00, color (0.00%, 100.00%, 25.00%), and 0.00% transparency
              • Floating Text - Change (Last created floating text): Disable permanence
              • Floating Text - Change the fading age of (Last created floating text) to 0.50 seconds
              • Floating Text - Change the lifespan of (Last created floating text) to 2.00 seconds
            • Else - Actions
I use a hidden passive ability to give the Female units the "Female" classification. It's a lot more efficient than using OR - Multiple Conditions to check through many different Unit-Types.
 

Attachments

  • Female Regen 1.w3m
    19.1 KB · Views: 11
Last edited:
Level 3
Joined
Dec 7, 2020
Messages
20
Thank you for helping me out with these things.

I don't think the resurrection times are a problem since I think even level 1 heroes take more than 4 seconds by default, not considering the time it would take someone to give the resurrection order. And no, I don't see any reason I would use the Remove Unit action normally but I'll keep an eye. Thanks for letting me know.

As for the Female Regen., that does just what I want. I never thought about using a hidden ability as classification, very clever. Sorry to bother you further but, if I were to use this one as a unit ability (for a Hero, but still unit ability) so I cannot use the A Unit Learns An Ability event, how should I go about it? Could I use A Unit Enters A Region (Entire map) and in the conditions look for the unit that has the ability? Then with that I could add it to the group just like you do.
 

Uncle

Warcraft Moderator
Level 64
Joined
Aug 10, 2018
Messages
6,583
Yeah, Enters map should work just fine. Oh and if non-hero Units use this ability then the Death trigger is necessary again.

Also, if you manually create the Hero/Unit with triggers then you can do something like "Add last created unit to FR_Group". Enters map is probably a lot easier though.
 
Last edited:
Level 3
Joined
Dec 7, 2020
Messages
20
Thank you very, very, very much! I hope I didn't bother you too much by being so nit-picky. But I learnt a lot!
 
Status
Not open for further replies.
Top