[Trigger] Little help with Mechanical Shell

Level 6
Joined
Sep 19, 2006
Messages
191
  • Mechanized Shell
    • Events
      • Unit - A unit Is attacked
    • Conditions
      • (Unit-type of (Attacking unit)) Equal to Goblin Tank
    • Actions
      • Set GTUnit_I = (GTUnit_I + 1)
      • Set GTUnit_MUI = (GTUnit_MUI + 1)
      • Set GTUnit_U[GTUnit_MUI] = (Attacking unit)
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (Random integer number between 1 and 100) Less than or equal to 30
          • Or - Any (Conditions) are true
            • Conditions
              • ((Attacked unit) is A structure) Equal to True
        • Then - Actions
          • Special Effect - Create a special effect attached to the weapon of GTUnit_U[GTUnit_MUI] using Abilities\Spells\NightElf\Taunt\TauntCaster.mdl
          • Set GT_SE[GTUnit_MUI] = (Last created special effect)
          • Special Effect - Destroy GT_SE[GTUnit_MUI]
          • Unit - Add Mechanized Shell (Book) to GTUnit_U[GTUnit_MUI]
          • Player - Disable Mechanized Shell (Book) for (Owner of GTUnit_U[GTUnit_MUI])
          • Wait 6.00 seconds
          • Unit - Remove Mechanized Shell (Book) from GTUnit_U[GTUnit_MUI]
        • Else - Actions
      • Set GTUnit_I = (GTUnit_I - 1)
      • Set GTUnit_MUI = (GTUnit_MUI - 1)
Did get a bit used to MUI. Keep in mind this is a passive ability
The special effects appears if the Goblin Tank shoots at the building while having the Mechanical book equipped.
I wanted it to show up when the Goblin Tank receives the book spell.
Can anyone help me with this?
  • ((Attacked unit) is A structure) Equal to True
I'm not sure if this should exist, since the tank is set to attack buildings.
 

Uncle

Warcraft Moderator
Level 73
Joined
Aug 10, 2018
Messages
7,866
You should only run your logic in the Then - Actions. Nothing else should happen outside of that. Your trigger works like this:

A unit is attacked -> Attacker is a Goblin Tank -> Roll a 100 sided die.
If it lands on 30 or less THEN proceed with the Mechanized Shell actions.
If it lands on 31 or more THEN do absolutely nothing.

That means you don't even need an If Then Else since you're not taking advantage of the Else - Actions.
  • Mechanized Shell
    • Events
      • Unit - A unit Is attacked
    • Conditions
      • (Unit-type of (Attacking unit)) Equal to Goblin Tank
      • (Random integer number between 1 and 100) Less than or equal to 30
      • Or - Any (Conditions) are true
        • Conditions
          • ((Attacked unit) is A structure) Equal to True
    • Actions
      • Set GTUnit_MUI = (GTUnit_MUI + 1)
      • Set GTUnit_U[GTUnit_MUI] = (Attacking unit)
      • Special Effect - Create a special effect attached to the weapon of GTUnit_U[GTUnit_MUI] using Abilities\Spells\NightElf\Taunt\TauntCaster.mdl
      • Special Effect - Destroy (Last created special effect)
      • Unit - Add Mechanized Shell (Book) to GTUnit_U[GTUnit_MUI]
      • Player - Disable Mechanized Shell (Book) for (Owner of GTUnit_U[GTUnit_MUI])
      • Wait 6.00 seconds
      • Unit - Remove Mechanized Shell (Book) from GTUnit_U[GTUnit_MUI]
      • Set GTUnit_MUI = (GTUnit_MUI - 1)
However, you're making some other mistakes. GTUnit_I currently does nothing and serves no purpose. GT_SE does nothing, you immediately destroy the special effect. It'd only be useful if you wanted to destroy the effect at a later time. Wait actions are unreliable and bad practice, also if you have to use one I suggest using Wait game-time. Your trigger stacks with itself, meaning a single Goblin Tank could have 10 instances of this trigger running at the same time. This does not play nice with Wait actions and the Adding/Disabling/Removing of an ability and will create a mess of an outcome where things get Removed for apparently no reason. Lastly, you're using an "Attack" event which is not a reliable way to determine when a unit strikes another unit. This occurs before the unit has even begun playing it's attack animation and can be spammed repeatedly. The Event would've been better named "A unit prepares to Attack". You likely want to use a Damage Event which will require the use of a system like Bribe's Damage Engine since you're on an older version.


To avoid most of these issues I suggest using a system called Unit Indexing. Here's a working example:
  • Mechanized Shell NEW
    • Events
      • Unit - A unit Is attacked
    • Conditions
      • (Unit-type of (Attacking unit)) Equal to Goblin Tank
      • (Random integer number between 1 and 100) Less than or equal to 30
      • Or - Any (Conditions) are true
        • Conditions
          • ((Attacked unit) is A structure) Equal to True
    • Actions
      • Set GTUnit = (Attacking unit)
      • Set GTMUI = (Custom value of GTUnit)
      • -------- --------
      • -------- Optional special effect: --------
      • Special Effect - Create a special effect attached to the weapon of GTUnit using Abilities\Spells\NightElf\Taunt\TauntCaster.mdl
      • Special Effect - Destroy (Last created special effect)
      • -------- --------
      • -------- Set or reset the duration to 6.00 seconds: --------
      • Set GTDuration[GTMUI] = 6.00
      • -------- --------
      • -------- You only need to Add the ability if it isn't already active: --------
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (Level of Mechanized Shell (Book) for GTUnit) Equal to 0
        • Then - Actions
          • Unit - Add Mechanized Shell (Book) to GTUnit
          • Player - Disable Mechanized Shell (Book) for (Owner of GTUnit)
          • Unit Group - Add GTUnit to GTGroup
          • Trigger - Turn on Mechanized Shell Loop
        • Else - Actions
  • Mechanized Shell Loop
    • Events
      • Time - Every 0.05 seconds
    • Conditions
    • Actions
      • Unit Group - Pick every unit in GTGroup and do (Actions)
        • Loop - Actions
          • Set GTUnit = (Picked unit)
          • Set GTMUI = (Custom value of GTUnit)
          • -------- --------
          • -------- Reduce this unit's duration by the amount of time that has passed: --------
          • Set GTDuration[GTMUI] = (GTDuration[GTMUI] - 0.05)
          • -------- --------
          • -------- Remove this unit from the group if it's duration has finished (or if it died): --------
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • Or - Any (Conditions) are true
                • Conditions
                  • GTDuration Less than or equal to 0.01
                  • (GTUnit is Alive) Equal to False
            • Then - Actions
              • Unit - Remove Mechanized Shell (Book) from GTUnit
              • Unit Group - Remove GTUnit from GTGroup
              • -------- --------
              • -------- We can turn this trigger off while the group is empty to make this more efficient: --------
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • (GTGroup is empty) Equal to True
                • Then - Actions
                  • Trigger - Turn off (this trigger)
                • Else - Actions
            • Else - Actions
^ This Loop trigger should be initially OFF. It's turned on/off automatically through the two triggers. These are the new variables I created:
GTGroup = Unit Group
GTDuration = Real (array)

Now we're tracking our Goblin Tanks in a Unit Group and we're tracking each of their remaining Durations using the GTDuration variable. This works because the Unit Indexer is running in the background, automatically assigning a unique Custom Value to each of our Units. Since each unit will have it's own unique Custom Value, and that's used as the [index] in the GTDuration array, we avoid any conflicts like one unit overwriting another unit's data. It also means that we can effectively "reset" the duration when the ability procs rather than starting ANOTHER instance. Now each Goblin Tank can only have one duration running at a time.

This is how most Buffs in Warcraft 3 work. For example, if you cast Bloodlust on a Unit twice in a row, it doesn't get 2x the AS/MS %. Instead, the second cast overwrites the first cast, restarting the Duration and removing the old stat bonuses while applying the new ones. There's only a handful of "stacking" effects in Warcraft 3 (Incinerate comes to mind) which can bend this rule. If you want a stacking effect in your custom triggers then you should probably use the Dynamic Indexing technique.
 
Last edited:

Uncle

Warcraft Moderator
Level 73
Joined
Aug 10, 2018
Messages
7,866
I do see how it's done, but shouldn't GTGroup be removed, since it's a Unit Group variable?
Nope, I think you're misunderstanding some of the concepts regarding memory leaks. I know it's tricky but you really only need to destroy (aka remove) things that you no longer need. OR things that you're about to lose a reference to. Also, this only applies to SOME things, Integers for example are exempt from these rules.

GTGroup is going to be used throughout the entire game, removing (destroying) it would actually break these triggers since there would no longer be a Unit Group to put the Goblin Tanks into. The group is meant to be permanent.

I recommend reading a bit more about memory leaks and trying to understand the difference between "temporary" and "permanent" data and why manually Adding/Removing units to and from a Unit Group is different than Setting the Unit Group. Also, it's important to understand how Variables work and how a Unit Group variable is simply keeping a reference to a Unit Group object. You don't destroy the variable, you destroy the object it's keeping track of.
 
Last edited:
Level 6
Joined
Sep 19, 2006
Messages
191
I tried testing the triggers in my map. The problem is now, the Goblin Tanks receive the effect permanent. I did see GTDuration being itself thanks to the Unit Indexer. I also see the Event only being Ever 0.05 seconds. I'm not sure how to enable those.
 

Uncle

Warcraft Moderator
Level 73
Joined
Aug 10, 2018
Messages
7,866
I would have to see your triggers to know the problem.

This line is what removes the ability:
  • Then - Actions
    • Unit - Remove Mechanized Shell (Book) from GTUnit
This happens when GTDuration reaches 0 or if the Goblin Tank dies. If it never reaches 0 then the ability will never get removed.
 
Level 6
Joined
Sep 19, 2006
Messages
191
  • Events
    • Time - Every 0.05 seconds of game time
  • Conditions
  • Actions
    • Unit Group - Pick every unit in GTGroup and do (Actions)
      • Loop - Actions
        • Set GTUnit = (Picked unit)
        • Set GTMUI = (Custom value of GTUnit)
        • -------- --------------------- --------
        • -------- Reduce the duration by the amount of time it perished. --------
        • Set GTDuration[GTMUI] = (GTDuration[GTMUI] - 0.05)
        • -------- --------------------- --------
        • -------- Remove the unit from the group if its duration ended or it died. --------
        • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
          • If - Conditions
            • GTDuration[GTMUI] Less than or equal to 0.01
            • (GTUnit is alive) Equal to False
          • Then - Actions
            • Unit - Remove Mechanized Shell (Book) from GTUnit
            • Unit Group - Remove GTUnit from GTGroup
            • -------- --------------------- --------
            • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
              • If - Conditions
                • (GTGroup is empty) Equal to True
              • Then - Actions
                • Trigger - Turn off (This trigger)
              • Else - Actions
          • Else - Actions
The first one is same as yours, but for the 2nd one, I just don't know how the GTDuration was added, even though Unit Indexer is installed for my map. There's also the event.
 

Uncle

Warcraft Moderator
Level 73
Joined
Aug 10, 2018
Messages
7,866
You forgot the OR when checking your Conditions:
  • If - Conditions
    • Or - Any (Conditions) are true
      • Conditions
        • GTDuration[GTMUI] Less than or equal to 0.01
        • (GTUnit is alive) Equal to False
Currently your Then - Actions will only happen if both GTDuration is zero AND The Goblin Tank is dead.
 
Last edited:
Top