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

Not sure whats going on here!

Status
Not open for further replies.
Level 2
Joined
Dec 26, 2019
Messages
8
I have this trigger:

  • Player death lvl1
    • Events
      • Unit - A unit Dies
    • Conditions
      • (Unit-type of (Triggering unit)) Equal to Prisoner
    • Actions
      • Player - Set (Owner of (Triggering unit)).Current gold to (((Owner of (Triggering unit)) Current gold) - 1)
      • Floating Text - Create floating text that reads |cffff0000Ohh... Th... above (Triggering unit) with Z offset 0.00, using font size 10.00, color (100.00%, 100.00%, 100.00%), and 0.00% transparency
      • Game - Display to (All players) the text: ((Name of (Owner of (Triggering unit))) + has been caught!)
      • Wait 1.00 seconds
      • Floating Text - Destroy (Last created floating text)
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • ((Owner of (Triggering unit)) Current gold) Greater than 0
        • Then - Actions
          • Unit - Create 1.Prisoner for (Owner of (Triggering unit)) at (Random point in Level1revive <gen>) facing (Random real number between 0.00 and 360.00) degrees
          • Camera - Pan camera for (Owner of (Triggering unit)) to (Position of (Last created unit)) over 1.00 seconds
          • Floating Text - Create floating text that reads (Try again! Your remaining lives are: + (String(((Owner of (Triggering unit)) Current gold)))) above (Last created unit) with Z offset 0.00, using font size 10.00, color (100.00%, 100.00%, 100.00%), and 0.00% transparency
          • Wait 2.00 seconds
          • Floating Text - Destroy (Last created floating text)
        • Else - Actions
          • Do nothing

The trigger works up until the if then else function, I am not sure if its getting the conditions mixed up or where its getting hung up any insight would be greatly appreciated. Thank you!
 
Last edited:
Level 38
Joined
Feb 27, 2007
Messages
4,951
  • How To Post Your Trigger
  • You're leaking some locations: Things That Leak
  • You can use Player - Add Property instead of Player - Set Property to just add -1 gold.
  • You may permanently leak your floating text by attempting to use Last created floating text after a wait. Instead you can do this series of events to make FT automatically expire and clean themselves up:
    • Create FT
    • Disable permanence (needs to happen before lifespan)
    • Set its lifespan to the proper duration
  • The Do Nothing action is worthless and should never be used.
  • Not sure why it's not working; perhaps put some debug messages in various places to see what is running and what isn't.
 
Level 2
Joined
Dec 26, 2019
Messages
8
Thank you for the information and advice!

  • Cycle2
    • Events
      • Unit - A unit enters Region 023 <gen>
    • Conditions
      • (Unit-type of (Triggering unit)) Equal to Guard Dog
    • Actions
      • Set VariableSet Locations = (Center of Region 022 <gen>)
      • Unit - Move (Triggering unit) instantly to (Center of Region 022 <gen>), facing 0.00 degrees
      • Unit - Order (Triggering unit) to Move To.(Center of Region 023 <gen>)
      • Custom script: call RemoveLocation(udg_Locations)
does this seem correct?

also what would you suggest in terms of the do nothing action?
 
Level 20
Joined
Feb 23, 2014
Messages
1,264
does this seem correct?
Nope.

First of all, it's still leaking a point for (Center of Region 023).

Secondly - I believe that the way (Center of Region) function works is that it creates a new point each time it is run, which means that in your trigger you create a point for the center of Region 022 two times - first time when you assign a variable, second time when you actually move a unit. The first one isn't a leak, but the second one is.

This is how your trigger should look like:

  • Cycle2
    • Events
      • Unit - A unit enters Region 023 <gen>
    • Conditions
      • (Unit-type of (Triggering unit)) Equal to Guard Dog
    • Actions
      • Set VariableSet Locations = (Center of Region 022 <gen>)
      • Unit - Move (Triggering unit) instantly to Locations, facing 0.00 degrees
      • Custom script: call RemoveLocation(udg_Locations)
      • Set VariableSet Locations = (Center of Region 023 <gen>)
      • Unit - Order (Triggering unit) to Move To Locations
      • Custom script: call RemoveLocation(udg_Locations)
I'm guessing you're pretty new to this, so here's a bit more detailed explanation of how leaks work:

A leak happens when you create something like a point or a unit group that:
- You no longed have any need for (e.g. you used it once and then it's no longer needed).
- You have no way of referencing (i.e. reusing or removing) it.

Now, I get it might be difficult to imagine, because points are invisible, but try to think that each point is like a small dot that's put in your map - so small that you can't see it, but it's there. And each time you use a function like for instance (Center of Region) or (Position of Unit), one of these tiny dots is created and placed in your map.

The problem is that unless you assign that point to a variable the moment it is created, there's no way to "select" it later - you can't use it again or remove it, it's just going to sit there. The issue with that is that it's going to take up a tiny bit of memory space - not enough to have any noticeable impact on the game on its own, but if you have a lot of triggers or your map runs for a long time, all these points and other leaks might add up and cause the game to slow down or even crash.

All of that because you have a bunch of junk that you no longer need and cannot do anything with.

To counter this:
- You need to make sure you have a way to reference (i.e. "select") a point you're creating and the only way to do that is to assign it to a variable the moment it is being created - this is why I'm doing things like "Set VariableSet Locations = (Center of Region 022 <gen>)". This isn't a leak, because the point from the "Center of Region" function is assigned to a variable (i.e. I can do stuff with it) and I still need it for something.
- Once you have a point ready to be used and assigned to a variable, you can just use it for whatever and when it is no longer needed, you can remove the point to free up the variable to be used for something else (for example, another time this trigger will be run).

One very important thing to note here - one variable can only be assigned to one point, so if you have a variable assigned to "point A" and you assign it to "point B" without removing "point A" or assigning it to a different variable first, you are going to leak, because you will no longer be able to reference "point A".

In short - you need to assign a point to a variable the moment it is created, then use that variable to reference this point in whatever actions you want and finally remove the point once it is no longer needed. That's exactly what I did in the example above.

---

That said, perhaps you're wondering - "isn't it a bit silly to create a new point each time and then remove it straight away? Isn't there a way that I could just make one point and then use it multiple times?". And the answer is - yes, there is.

First things first - in order for you to be able to use a point later, you have to have a way to reference it, i.e. have the point assigned to a variable. It doesn't matter too much when you do it - just remember to make sure that the trigger that tassigns the variable won't get run more than once and that the variable is assigned before you're going to use it.

Alternatively, you could also put something like this at the beginning of your trigger:

  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
    • If - Conditions
      • (Execution count of (This trigger)) Equal to 1 //Integer Comparison
    • Then - Actions
      • Set VariableSet Location1 = (Center of Region 022 <gen>)
      • Set VariableSet Location2 = (Center of Region 023 <gen>)
    • Else - Actions
What this does is that the first time the trigger containing this block is run (i.e. execution count = 1), it will assign the needed variables, but it won't do so the next or any other time that this trigger is run.

a) If you use the execution count method, your trigger would look like this:

  • Cycle2
    • Events
      • Unit - A unit enters Region 023 <gen>
    • Conditions
      • (Unit-type of (Triggering unit)) Equal to Guard Dog
    • Actions
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (Execution count of (This trigger)) Equal to 1
        • Then - Actions
          • Set VariableSet Location1 = (Center of Region 022 <gen>)
          • Set VariableSet Location2 = (Center of Region 023 <gen>)
        • Else - Actions
      • Unit - Move (Triggering unit) instantly to Location1, facing 0.00 degrees
      • Unit - Order (Triggering unit) to Move To.Location2
b) If you set the variables in some other trigger, it would look like this:

  • Cycle2
    • Events
      • Unit - A unit enters Region 023 <gen>
    • Conditions
      • (Unit-type of (Triggering unit)) Equal to Guard Dog
    • Actions
      • Unit - Move (Triggering unit) instantly to Location1, facing 0.00 degrees
      • Unit - Order (Triggering unit) to Move To.Location2
This method has one little caveat - if at any point you will want to disable this trigger permanently or if there are some conditions that make it obsolote and thus the point variables will no longer be needed, you might want to clean them up. It's not hard to do, but it might require a bit of planning, so generally I'd recommend that you stick to assigning a temporary variable that you clean right after it is used (i.e. the first example in this post).

also what would you suggest in terms of the do nothing action?
Don't use it - i.e. just leave the area below "Else - Actions" empty or if you really want to put in something to remind you that no actions are meant to be there, use a comment instead.

The trigger works up until the if then else function, I am not sure if its getting the conditions mixed up or where its getting hung up any insight would be greatly appreciated. Thank you!
This might be a bit of wild guess, but try removing the wait action before the If/Then/Else block and tell us did it work :) I'll explain if it does :D
 
Last edited:
Level 2
Joined
Dec 26, 2019
Messages
8
First let me say I am beyond grateful for your explanation, I am certainly no expert in These matters and it's one of those things that I only dabble in especially in warcraft because it makes it simpler for me, so Thank you for taking the time to explain further! I feel I have the most trouble understanding and using variables, I generally try to avoid using them but as I get better and understand more I realize I need to. Anyways I will try to go through my triggers and work out all my location leaks. If you have the time could you explain unit group leaks for me that makes even less sense to me lol... Also I did adjust my trigger a bit and removed the wait function and ta da the trigger is working as intended why? Haha
 
Level 20
Joined
Feb 23, 2014
Messages
1,264
I have the most trouble understanding and using variables
Very simply put - assigning something to a variable is basically like giving it a name, with the variable itself being that name.

The easiest way to imagine it would be - you have an Archmage hero in your map and you assign it to a unit variable called "Steve". The game will remember that and due to this, every time you tell the game to do something with "Steve", it will now exactly which unit you mean. If you don't do that, every time you want to do something with that Archmage, you will have to explain the game which unit you want to use. And depending on what you're doing, explaining that might be tedious or very difficult.

Granted, this is a very simple example, but the idea is - variables are your friend and they're meant to make life easier, so don't avoid using them. Just experiment a bit and you'll get familiar with how it works very fast. And as a bonus, once you go a bit deeper, you will notice that variables allow you to do a lot of really fun stuff.

explain unit group leaks for me that makes even less sense to me
Okay, so... unit group leaks - unit group is basically like a list of units. Let's say that you have a Footman, a Rifleman and a Priest standing in Region 001.

So when you use an action like:

  • Actions
    • Unit Group - Pick every unit in (Units in Region 001 <gen>) and do (Actions)
      • Loop - Actions
        • Unit - Change color of (Picked unit) to Red
The game will make a list of every unit that's in Region 001 - in our example it will look like this: "Footman, Rifleman, Priest". That list will be stored in your PCs memory and... here's the problem. Remember how I said that variables are like names? Well, this list (i.e. unit group) wasn't assigned to a variable and so it doesn't have a name. Because of that, you don't have a way to tell the game to do anything else with that list (i.e. reference it again) and if you try using (Units in Region 001 <gen>) again then the game will create another list, because - well, maybe there are now some other units in that region, so it makes sense to make another "list", right?

And here's where the leak happens - that list will remain in your memory, even though you no longer need it for anything and you have no way of referencing/using it again even if you wanted to. That's pretty much the definition of a leak.

There are two ways of dealing with that:

a) If you know that you won't need this unit group later, you can just just tell the game to automatically remove it after it is used (i.e. erase the list from memory). It is done by putting this action before an action that creates a unit group:
  • Actions
    • Custom script: set bj_wantDestroyGroup = true
In our example above, it would look like this:

  • Actions
    • Custom script: set bj_wantDestroyGroup = true
    • Unit Group - Pick every unit in (Units in Region 001 <gen>) and do (Actions)
      • Loop - Actions
        • Unit - Change color of (Picked unit) to Red
b) Alternatively - you can just set this unit group to a variable (i.e. "give it a name"), so that you can later tell the game to remove it. It works exactly the same as it did with points - you assign the unit group to a variable the moment it is created, then do whatever you want to do and finally use the removal custom code where the part after "udg_" is the name of your unit group variable:

  • Actions
    • Custom script: call DestroyGroup(udg_UnitGroupVariableName)
In our example above it would look like this:

  • Actions
    • Set VariableSet UnitGroup = (Units in Region 001 <gen>)
    • Unit Group - Pick every unit in UnitGroup and do (Actions)
      • Loop - Actions
        • Unit - Change color of (Picked unit) to Red
    • Custom script: call DestroyGroup(udg_UnitGroup)
One very, very important thing to note here - removing a unit group DOES NOT remove the units that are inside that unit group, it only deletes the "list of units" I've talked about earlier from your memory. It also doesn't remove the variable itself - it still exists and you're free to use it for something else.

And remember that you don't have to remove your unit group if you're planning to use it later. A point or a unit group isn't a leak until it is no longer useful.

Also I did adjust my trigger a bit and removed the wait function and ta da the trigger is working as intended why? Haha
I'm not really sure about technicalities, but the short story is that what I think was the problem is that the (Triggering Unit) was dead and the wait was enough for the game to stop "detecting" that unit properly, i.e. Triggering Unit was equal to "No Unit" and as such the condition couldn't be passed.
 
Last edited:
Status
Not open for further replies.
Top