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

[Trigger] Is this spell ok? [SOLVED]

Level 11
Joined
Aug 11, 2009
Messages
594
The spell seems to work as intended but it would be nice to get some feedback on how to make it more effective / less chance for bugs as I am trying to learn more GUI :) It is only supposed to be MPI, not MUI.

How it is supposed to work is that the Hero has a chance on hit to turn invisible and hit all nearby enemies with a 0.05 interval. When all enemies has been hit the Hero reappears again. Basically the idea is that the Hero move at high speed and damage all nearby enemies.

The setup for the effect is to add all nearby living enemies to a unit group and then check if its greater than 0. If so then the hero gets hide+invul and then turn on the 0.05 interval trigger.

  • Zan Blue Effect
    • Events
      • Time - Every 0.05 seconds of game time
    • Conditions
    • Actions
      • For each (Integer Loop_FlashStrike) from 1 to 8, do (Actions)
        • Loop - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • (Number of units in UG_FlashStrike[Loop_FlashStrike]) Greater than 0
            • Then - Actions
              • Set VariableSet U_FlashStrikeTarget = (Random unit from UG_FlashStrike[Loop_FlashStrike])
              • Set VariableSet Real_AbilityDamage = (((Real((Base Damage of U_Hero[Loop_FlashStrike] for weapon index 0))) x 1.80) + ((Real((Intelligence of U_Hero[Loop_FlashStrike] (Include bonuses)))) x 15.00))
              • Set VariableSet Real_FlashStrikeFacing = ((Facing of U_FlashStrikeTarget) + 180.00)
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • Real_FlashStrikeFacing Greater than 360.00
                • Then - Actions
                  • Set VariableSet Real_FlashStrikeFacing = (Real_FlashStrikeFacing - 360.00)
                • Else - Actions
              • Set VariableSet Point_FlashStrike1 = (Position of U_FlashStrikeTarget)
              • Set VariableSet Point_FlashStrike2 = (Point_FlashStrike1 offset by 125.00 towards Real_FlashStrikeFacing degrees.)
              • Special Effect - Create a special effect at Point_FlashStrike1 using AZ_JianCi.mdx
              • Special Effect - Destroy (Last created special effect)
              • Unit - Create 1 Dummy (Zangetsu) for (Player(Loop_FlashStrike)) at Point_FlashStrike2 facing (Facing of U_FlashStrikeTarget) degrees
              • Unit - Add a 0.20 second Generic expiration timer to (Last created unit)
              • Animation - Change (Last created unit)'s vertex coloring to (100.00%, 100.00%, 100.00%) with 50.00% transparency
              • Animation - Change (Last created unit)'s animation speed to 200.00% of its original speed
              • Animation - Play (Last created unit)'s attack animation
              • Unit - Cause U_Hero[Loop_FlashStrike] to damage U_FlashStrikeTarget, dealing Real_AbilityDamage damage of attack type Hero and damage type Normal
              • Unit Group - Remove U_FlashStrikeTarget from UG_FlashStrike[Loop_FlashStrike].
              • Custom script: call RemoveLocation(udg_Point_FlashStrike1)
              • Custom script: call RemoveLocation(udg_Point_FlashStrike2)
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • (Number of units in UG_FlashStrike[Loop_FlashStrike]) Equal to 0
                • Then - Actions
                  • Unit - Make U_Hero[Loop_FlashStrike] Vulnerable
                  • Unit - Unhide U_Hero[Loop_FlashStrike]
                  • Selection - Select U_Hero[Loop_FlashStrike] for (Player(Loop_FlashStrike))
                • Else - Actions
            • Else - Actions
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • (Number of units in UG_FlashStrike[1]) Equal to 0
                  • (Number of units in UG_FlashStrike[2]) Equal to 0
                  • (Number of units in UG_FlashStrike[3]) Equal to 0
                  • (Number of units in UG_FlashStrike[4]) Equal to 0
                  • (Number of units in UG_FlashStrike[5]) Equal to 0
                  • (Number of units in UG_FlashStrike[6]) Equal to 0
                  • (Number of units in UG_FlashStrike[7]) Equal to 0
                  • (Number of units in UG_FlashStrike[8]) Equal to 0
                • Then - Actions
                  • Trigger - Turn off (This trigger)
                • Else - Actions
 
Last edited:

Uncle

Warcraft Moderator
Level 64
Joined
Aug 10, 2018
Messages
6,567
Hello, so I'm slightly confused because you left out the "Cast" trigger.

Is there a particular reason that you always loop from 1 to 8 in this For Loop? I assume it's because you want it to work for 8 players.

If so, I suggest that you adjust it to only reference the Heroes that are actually casting the ability rather than making redundant checks. For example, a single Unit Group that dynamically adds/removes casters would be more performant and logical. You could also rely on a Player Group if you know for a fact it'll always be MPI, this would be more convenient seeing as how you can get a Hero from the Player -> U_Hero[player number], and you need to reference the Player anyway.

Also, this is a bad idea:
  • If - Conditions
    • (Number of units in UG_FlashStrike[1]) Equal to 0
    • (Number of units in UG_FlashStrike[2]) Equal to 0
    • (Number of units in UG_FlashStrike[3]) Equal to 0
    • (Number of units in UG_FlashStrike[4]) Equal to 0
    • (Number of units in UG_FlashStrike[5]) Equal to 0
    • (Number of units in UG_FlashStrike[6]) Equal to 0
    • (Number of units in UG_FlashStrike[7]) Equal to 0
    • (Number of units in UG_FlashStrike[8]) Equal to 0
Checking the number of units in a Unit Group actually requires that the game loops over the Unit Group and counts one by one. Although, in your case you're checking if it's equal to 0 so it will exit the loop early, but you're doing this 8 times. Again, it's very unlikely that all 8 of these heroes will be casting Flash Strike at the same time.

Let's simplify it to this:
  • If - Conditions
    • Int_FlashStrike_Instances Equal to 0
This Integer increases by 1 whenever a unit casts Flash Strike and decreases by 1 whenever a unit's Flash Strike finishes.

We can optimize it further by using Integers to track the number of units in each player's Unit Group rather than relying on that slow function:
  • Then - Actions
    • Set Variable Int_FlashStrike_TargetCount[Loop_FlashStrike] = Int_FlashStrike_TargetCount[Loop_FlashStrike] - 1
    • Set VariableSet U_FlashStrikeTarget = (Random unit from UG_FlashStrike[Loop_FlashStrike])
Subtract 1 when a random target is found, do your damage stuff, and then check if this value is Equal to 0 afterwards rather than checking if their Unit Group is empty.

You would also set this Int_FlashStrike_TargetCount variable in the Cast trigger when you first create the player's Unit Group. It should be equal to the number of units in the Unit Group. If you're looping over that Unit Group in the Cast trigger then it can be more performant to increase it by 1 per (Picked unit). Otherwise, just set it to (Number of units in group) after filling the unit group.

Lastly, a variable for the Dummy unit would make it more efficient and is good practice. Sometimes you can lose reference to your Dummy if you're not careful.
 
Last edited:
Level 11
Joined
Aug 11, 2009
Messages
594
Thanks!
These changes makes alot of sense.

The cast trigger is quite bloated with other stuff as the Hero has 3 different spells that can trigger from normal attacks. But the ones that are tied to this is:
Set UG_Flashstrike(PlayerNumber) = units within 300 that are alive and enemies of caster.
Then a check if that unit group is empty, if so the effect wont trigger. (Since there is a chance that the attack that triggers the spell kills the last nearby enemy).

The loop 1 to 8 is for 8 players, correct :)

May I ask with the facing part of the dummy units, if I want them to appear behind a target and face them, is there a more efficient way to do it than adding the if/then/else as I did. I am not super good with math so it was the only thing i could think of to reduce the number by 360 if it goes above that.
 
Last edited:

Uncle

Warcraft Moderator
Level 64
Joined
Aug 10, 2018
Messages
6,567
Thanks!
These changes makes alot of sense.

May I ask with the facing part of the dummy units, if I want them to appear behind a target and face them, is there a more efficient way to do it than adding the if/then/else as I did. I am not super good with math so it was the only thing i could think of to reduce the number by 360 if it goes above that.
No problem! That math looks fine to me, it's very simple arithmetic so if it works then there's nothing to complain about.

Some other notes you may already be aware of:

1) Unit Group arrays need to have their Sizes initialized, in this case you'd want a Size of 8. OR you can manually create the group yourself:
  • Custom script: set udg_UG_FlashStrike[5] = CreateGroup()
This array sizing also applies to Player Group arrays and Timer arrays.

2) If you cast this ability while it's already active, which may not be possible in your map but it's worth thinking about, it MAY cause problems. I'd have to see your Cast trigger to see how you're handling it to be certain.
 
Last edited:
Level 11
Joined
Aug 11, 2009
Messages
594
Did not know about the array size but i changed it to 8, as that is how many players is available in the map :)

As the Hero is hidden during the effect it does not attack, right? If so it should not be able to cast while already casting. Or I also need to pause the Hero?

So these are the changes I made according to my understanding, is this how you meant?

  • Zan Passives
    • Events
      • Game - DamageEvent becomes Equal to 1.00
    • Conditions
      • IsDamageAttack Equal to True
      • (DamageEventTarget belongs to an enemy of (Owner of DamageEventSource).) Equal to True
      • (Unit-type of DamageEventSource) Equal to Zanpakuto Spirit (V)
    • Actions
      • Unit - Set mana of DamageEventSource to ((Mana of DamageEventSource) + 50.00)
      • Set VariableSet Int_Randomizer = (Random integer number between 1 and 100)
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • Int_Randomizer Less than or equal to INT_AbilityProc[(Player number of (Owner of DamageEventSource))]
        • Then - Actions
          • Set VariableSet UG_FlashStrike[(Player number of (Owner of DamageEventSource))] = (Units within 300.00 of (Position of DamageEventSource) matching ((((Matching unit) is alive) Equal to True) and (((Matching unit) belongs to an enemy of (Owner of DamageEventSource).) Equal to True)).)
          • Set VariableSet Int_FlashStrikeTargetCount[(Player number of (Owner of DamageEventSource))] = (Number of units in UG_FlashStrike[(Player number of (Owner of DamageEventSource))])
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • Int_FlashStrikeTargetCount[(Player number of (Owner of DamageEventSource))] Greater than 0
            • Then - Actions
              • Set VariableSet Int_FlashStrikeInstances = (Int_FlashStrikeInstances + 1)
              • Player Group - Add (Owner of DamageEventSource) to PG_FlashStrike
              • Floating Text - Create floating text that reads |cff0070ddFlash Str... above DamageEventSource with Z offset 0.00, using font size 10.00, color (100.00%, 100.00%, 100.00%), and 0.00% transparency
              • Set VariableSet FT_Ability = (Last created floating text)
              • Floating Text - Change FT_Ability: Disable permanence
              • Floating Text - Set the velocity of FT_Ability to 50.00 towards 45.00 degrees
              • Floating Text - Change the lifespan of FT_Ability to 1.50 seconds
              • Floating Text - Change the fading age of FT_Ability to 1.00 seconds
              • Unit - Make DamageEventSource Invulnerable
              • Unit - Hide DamageEventSource
              • Trigger - Turn on Zan Blue Effect <gen>
            • Else - Actions
        • Else - Actions

  • Zan Blue Effect
    • Events
      • Time - Every 0.05 seconds of game time
    • Conditions
    • Actions
      • Player Group - Pick every player in PG_FlashStrike and do (Actions)
        • Loop - Actions
          • Set VariableSet Int_PlayerNumber = (Player number of (Picked player))
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • Int_FlashStrikeTargetCount[Int_PlayerNumber] Greater than 0
            • Then - Actions
              • Set VariableSet U_FlashStrikeTarget = (Random unit from UG_FlashStrike[Int_PlayerNumber])
              • Set VariableSet Real_AbilityDamage = (((Real((Base Damage of U_Hero[Int_PlayerNumber] for weapon index 0))) x 1.80) + ((Real((Intelligence of U_Hero[Int_PlayerNumber] (Include bonuses)))) x 15.00))
              • Set VariableSet Point_FlashStrike1 = (Position of U_FlashStrikeTarget)
              • Set VariableSet Point_FlashStrike2 = (Point_FlashStrike1 offset by 125.00 towards Real_FlashStrikeFacing degrees.)
              • Set VariableSet Real_FlashStrikeFacing = ((Facing of U_FlashStrikeTarget) + 180.00)
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • Real_FlashStrikeFacing Greater than 360.00
                • Then - Actions
                  • Set VariableSet Real_FlashStrikeFacing = (Real_FlashStrikeFacing - 360.00)
                • Else - Actions
              • Special Effect - Create a special effect at Point_FlashStrike1 using AZ_JianCi.mdx
              • Special Effect - Destroy (Last created special effect)
              • Unit - Create 1 Dummy (Zangetsu) for (Player(Int_PlayerNumber)) at Point_FlashStrike2 facing (Facing of U_FlashStrikeTarget) degrees
              • Set VariableSet U_FSDummy = (Last created unit)
              • Unit - Add a 0.20 second Generic expiration timer to U_FSDummy
              • Animation - Change U_FSDummy's vertex coloring to (100.00%, 100.00%, 100.00%) with 50.00% transparency
              • Animation - Change U_FSDummy's animation speed to 200.00% of its original speed
              • Animation - Play U_FSDummy's attack animation
              • Unit - Cause U_Hero[Int_PlayerNumber] to damage U_FlashStrikeTarget, dealing Real_AbilityDamage damage of attack type Hero and damage type Normal
              • Unit Group - Remove U_FlashStrikeTarget from UG_FlashStrike[Int_PlayerNumber].
              • Set VariableSet Int_FlashStrikeTargetCount[Int_PlayerNumber] = (Int_FlashStrikeTargetCount[Int_PlayerNumber] - 1)
              • Custom script: call RemoveLocation(udg_Point_FlashStrike1)
              • Custom script: call RemoveLocation(udg_Point_FlashStrike2)
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • Int_FlashStrikeTargetCount[Int_PlayerNumber] Equal to 0
                • Then - Actions
                  • Set VariableSet Int_FlashStrikeInstances = (Int_FlashStrikeInstances - 1)
                  • Unit - Make U_Hero[Int_PlayerNumber] Vulnerable
                  • Unit - Unhide U_Hero[Int_PlayerNumber]
                  • Selection - Select U_Hero[Int_PlayerNumber] for (Picked player)
                  • Player Group - Remove (Picked player) from PG_FlashStrike.
                  • Custom script: call DestroyGroup(udg_UG_FlashStrike[udg_Int_PlayerNumber])
                • Else - Actions
            • Else - Actions
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • Int_FlashStrikeInstances Equal to 0
                • Then - Actions
                  • Trigger - Turn off (This trigger)
                • Else - Actions
 

Uncle

Warcraft Moderator
Level 64
Joined
Aug 10, 2018
Messages
6,567
That's looking good but some more optimizations can be made. I'm a bit variable crazy but I think the workflow is faster once you get into the pattern of setting these variables first and foremost at the start of your triggers since you know they'll be referenced throughout. Plus it helps resolve potential issues:
  • Zan Passives
    • Events
      • Game - DamageEvent becomes Equal to 1.00
    • Conditions
      • (Unit-type of DamageEventSource) Equal to Zanpakuto Spirit (V)
      • IsDamageAttack Equal to True
      • (DamageEventTarget belongs to an enemy of (Owner of DamageEventSource).) Equal to True
    • Actions
      • Unit - Set mana of DamageEventSource to ((Mana of DamageEventSource) + 50.00)
      • Set VariableSet Int_Randomizer = (Random integer number between 1 and 100)
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • Int_Randomizer Less than or equal to INT_AbilityProc[(Player number of (Owner of DamageEventSource))]
        • Then - Actions
          • Set VariableSet FlashStrike_Player = (Owner of DamageEventSource)
          • Set VariableSet FlashStrike_PN = (Player number of FlashStrike_Player)
          • Set VariableSet Point_FlashStrike1 = (Position of DamageEventSource)
          • Set VariableSet UG_FlashStrike[FlashStrike_PN] = (Units within 300.00 of Point_FlashStrike1 matching ((((Matching unit) is alive) Equal to True) and (((Matching unit) belongs to an enemy of FlashStrike_Player.) Equal to True)).)
          • Custom script: call RemoveLocation( udg_Point_FlashStrike1 )
          • Set VariableSet Int_FlashStrikeTargetCount[FlashStrike_PN] = (Number of units in UG_FlashStrike[FlashStrike_PN])
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • Int_FlashStrikeTargetCount[FlashStrike_PN] Greater than 0
            • Then - Actions
              • Player Group - Add FlashStrike_Player to PG_FlashStrike
              • Floating Text - Create floating text that reads |cff0070ddFlash Str... above DamageEventSource with Z offset 0.00, using font size 10.00, color (100.00%, 100.00%, 100.00%), and 0.00% transparency
              • Set VariableSet FT_Ability = (Last created floating text)
              • Floating Text - Change FT_Ability: Disable permanence
              • Floating Text - Set the velocity of FT_Ability to 50.00 towards 45.00 degrees
              • Floating Text - Change the lifespan of FT_Ability to 1.50 seconds
              • Floating Text - Change the fading age of FT_Ability to 1.00 seconds
              • Unit - Make DamageEventSource Invulnerable
              • Unit - Hide DamageEventSource
              • Set VariableSet Int_FlashStrikeInstances = (Int_FlashStrikeInstances + 1)
              • Trigger - Turn on Zan Blue Effect <gen>
            • Else - Actions
              • Custom script: call DestroyGroup(udg_UG_FlashStrike[udg_FlashStrike_PN])
        • Else - Actions
I added some more variables to clean it up and shifted the Conditions to be in an order that made the most sense - when a Condition isn't met the rest aren't checked, so if we put our "least common" condition first we can skip some unnecessary checks and get better performance on average. I also addressed a potential leak of the Unit Group when you found 0 units inside of it (it wasn't being destroyed in that case) and you were leaking a Point when setting the Unit Group.

  • Zan Blue Effect
    • Events
      • Time - Every 0.05 seconds of game time
    • Conditions
    • Actions
      • Player Group - Pick every player in PG_FlashStrike and do (Actions)
        • Loop - Actions
          • Set VariableSet FlashStrike_Player = (Picked player)
          • Set VariableSet FlashStrike_PN = (Player number of FlashStrike_Player)
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • Int_FlashStrikeTargetCount[FlashStrike_PN] Greater than 0
            • Then - Actions
              • Set VariableSet U_FlashStrikeTarget = (Random unit from UG_FlashStrike[FlashStrike_PN])
              • Set VariableSet Real_AbilityDamage = (((Real((Base Damage of U_Hero[FlashStrike_PN] for weapon index 0))) x 1.80) + ((Real((Intelligence of U_Hero[FlashStrike_PN] (Include bonuses)))) x 15.00))
              • Set VariableSet Point_FlashStrike1 = (Position of U_FlashStrikeTarget)
              • Set VariableSet Point_FlashStrike2 = (Point_FlashStrike1 offset by 125.00 towards Real_FlashStrikeFacing degrees.)
              • Set VariableSet Real_FlashStrikeFacing = ((Facing of U_FlashStrikeTarget) + 180.00)
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • Real_FlashStrikeFacing Greater than 360.00
                • Then - Actions
                  • Set VariableSet Real_FlashStrikeFacing = (Real_FlashStrikeFacing - 360.00)
                • Else - Actions
              • Special Effect - Create a special effect at Point_FlashStrike1 using AZ_JianCi.mdx
              • Special Effect - Destroy (Last created special effect)
              • Unit - Create 1 Dummy (Zangetsu) for FlashStrike_Player at Point_FlashStrike2 facing (Facing of U_FlashStrikeTarget) degrees
              • Set VariableSet U_FSDummy = (Last created unit)
              • Unit - Add a 0.20 second Generic expiration timer to U_FSDummy
              • Animation - Change U_FSDummy's vertex coloring to (100.00%, 100.00%, 100.00%) with 50.00% transparency
              • Animation - Change U_FSDummy's animation speed to 200.00% of its original speed
              • Animation - Play U_FSDummy's attack animation
              • Trigger - Turn off Zan Passives
              • Unit - Cause U_Hero[FlashStrike_PN] to damage U_FlashStrikeTarget, dealing Real_AbilityDamage damage of attack type Hero and damage type Normal
              • Trigger - Turn on Zan Passives
              • Unit Group - Remove U_FlashStrikeTarget from UG_FlashStrike[FlashStrike_PN].
              • Set VariableSet Int_FlashStrikeTargetCount[FlashStrike_PN] = (Int_FlashStrikeTargetCount[FlashStrike_PN] - 1)
              • Custom script: call RemoveLocation(udg_Point_FlashStrike1)
              • Custom script: call RemoveLocation(udg_Point_FlashStrike2)
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • Int_FlashStrikeTargetCount[FlashStrike_PN] Equal to 0
                • Then - Actions
                  • Unit - Make U_Hero[FlashStrike_PN] Vulnerable
                  • Unit - Unhide U_Hero[FlashStrike_PN]
                  • Selection - Select U_Hero[FlashStrike_PN] for FlashStrike_Player
                  • Player Group - Remove FlashStrike_Player from PG_FlashStrike.
                  • Custom script: call DestroyGroup(udg_UG_FlashStrike[udg_FlashStrike_PN])
                  • Set VariableSet Int_FlashStrikeInstances = (Int_FlashStrikeInstances - 1)
                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    • If - Conditions
                      • Int_FlashStrikeInstances Equal to 0
                    • Then - Actions
                      • Trigger - Turn off (This trigger)
                    • Else - Actions
                • Else - Actions
            • Else - Actions
I added some more variables to clean it up and and moved the "turn off" check to happen after reducing the instances by 1. I also disable the Zan Passives trigger since you're going to fire another DamageEvent whenever you deal damage in this trigger, I think there was potential to run it again which may be unwanted.

As the Hero is hidden during the effect it does not attack, right?
That's correct. An alternate approach could be to Stun the hero. We have this nice function called BlzPauseUnitEx() which is only accessible in Custom Script. It will immediately Stun the unit without needing to deal with Dummy units/abilities/buffs, etc. You could use this to disable the Hero throughout the spell. If the hero being visible is a problem, you could set it's size to 0.01%, or flying height to 5000, or Vertex Color transparency to 0%, etc.
 
Last edited:
Level 11
Joined
Aug 11, 2009
Messages
594
Ah, yeah that makes sense with the variables, saves alot of time if you have them ready at the start :D

Btw I read somewhere that Player Group also leaks? Is that a problem here since its not destroyed when loop is turned off or is it under different circumstances that it leaks?
 

Uncle

Warcraft Moderator
Level 64
Joined
Aug 10, 2018
Messages
6,567
Ah, yeah that makes sense with the variables, saves alot of time if you have them ready at the start :D

Btw I read somewhere that Player Group also leaks? Is that a problem here since its not destroyed when loop is turned off or is it under different circumstances that it leaks?
A memory leak means that you lost reference to an object and it now exists in the game's memory, unused, unnecessary, but there eating up precious space.

However, as long as you hold a reference to an object then it's not considered "leaked". You can clean this object up at any time because you still have a variable referencing it.

In this case we don't want to clean up the Player Group object since it's designed to be used throughout the game. Even if say at the 30 minute mark you had an event that removed all heroes from the game permanently, it would still NOT be a memory leak. It'd be useless since you're no longer using it, but it's still not "leaking".

It makes more sense once you understand the idea of objects and how variables simply point to them. The variable itself ISN'T the object. It becomes clear when you get into coding and see how these objects are created, IE:
vJASS:
set udg_MyUnitGroupVariable = CreateGroup()
^ MyUnitGroupVariable is storing a newly created Unit Group object. These are two separate things! When we call DestroyGroup() on MyUnitGroupVariable we aren't destroying the variable but the Unit Group object it was storing.

Oh and make sure your Loop trigger is Initially OFF by default. With my new design it won't Turn Off automatically unless a Player has been added to it beforehand.
 
Last edited:
Level 11
Joined
Aug 11, 2009
Messages
594
I see.. so if I understand it correctly this applies to all commonly removed objects that leaks like points etc. If you have an object that is constant through the whole game there is no need to destroy it? Only when using temporary objects yes?

An example would be I have Teleports. When you buy a certain item the Hero is teleported to a certain point that is always the same. Would it then be better to have a map Init that setup the point variables to different locations or is it better to create the variable as you buy the item and then remove the variable after the Hero is moved (as usually done to remove leaks)?
 
Last edited:

Uncle

Warcraft Moderator
Level 64
Joined
Aug 10, 2018
Messages
6,567
1) Yes, your main focus for memory leak cleanup will be Points, then Unit Groups, then Special Effects, and finally Player Groups. I ordered those from most common to least common - based on my experience. Luckily, Special Effects don't need Custom Script and can use the Destroy action instead.

2) Yes, relying on memory storage is a great way to save yourself trouble and helps avoid creating new objects on the fly which is almost always costly. Just don't rely on it too much since like anything it has limits, although with modern hardware I highly doubt you could make a map that stored too much data. The general rule of thumb is that it's easier/faster to get something that already exists than creating it on the fly.

For example, a common strategy in game dev is something called object pooling which relies on storing data in memory to be used later. In a zombie survival game it may be in your best interest to spawn in 100 zombies during the loading screen, add them to a list (unit group), and disable them (hide them). Then whenever you need a zombie, you can pull one from this list and enable/move it to where you need it to go. Whenever one dies, you disable it again and add it back to the list. If you know for a fact that only 50 zombies can be active at a time then your pool of 100 will never run out, otherwise, increase the pool size. And a disabled zombie isn't being rendered by the graphics card or running any code so it's quite efficient.

Take this general idea and try to apply it whenever reasonable. Also, remember that you can waste time over optimizing your map for very negligible gains - it's all about finding a good balance which comes from having an understanding of what's costly and what can be overlooked.
 
Last edited:
Level 11
Joined
Aug 11, 2009
Messages
594
Awesome, thanks for bearing with me! It has been super helpful and I feel I have a better understanding of these parts of triggers now :D will need to make alot of adjustments to all triggers in my map now but will be worth it in the end xD

Again, thanks for all your help and for the well laid out explanations!
 
Top