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

Multi-Instancible GUI Spell Making

Level 11
Joined
Oct 13, 2005
Messages
233
Warning The first suggestion for local variables is incorrect. While the use of multiple local variables is demonstrated, in fact only ONE local variable can be used in GUI. Until the tutorial is updated, please keep this in mind and either use only one local variable in GUI or consider using JASS for spells.

I've been looking through the spells section lately, and what I see greatly disappoints me. Most of the spells I've looked at - specifically the GUI ones aren't multi-instancible. What this means is that they cannot be cast by more than one unit at a time and still work properly. There are many reasons to why they don't work, and I will go over some of the problems and why they don't work right. After, I will go over methods on how (with little extra trouble) you can make your spell multi-instancible.

First example - waits
Probably one of the most common errors I see in GUI spells involves setting a single global variable to a unit - let's say the caster. The spell then does a bunch of actions and then uses a large wait action. After waiting, the user refers to the specific global variable to do things. Let's say the wait was around 10 seconds. What would happen if another unit cast the spell within 10 seconds of the first unit? Here's an example I'll walk through:
  • bloodL
    • Events
      • Unit - A unit Begins channeling an ability
    • Conditions
      • (Ability being cast) Equal to Bloodrage
    • Actions
      • Set Luster = (Triggering unit)
      • Unit - Add speed to Luster
      • Special Effect - Create a special effect attached to the right,hand of Luster using Abilities\Spells\Other\BreathOfFire\BreathOfFireDamage.mdl
      • Set BLse1 = (Last created special effect)
      • Special Effect - Create a special effect attached to the left,hand of Luster using Abilities\Spells\Other\BreathOfFire\BreathOfFireDamage.mdl
      • Set BLse2 = (Last created special effect)
      • Special Effect - Create a special effect attached to the head of Luster using Abilities\Weapons\NecromancerMissile\NecromancerMissile.mdl
      • Set BLse3 = (Last created special effect)
      • Wait 15.00 seconds
      • Special Effect - Destroy BLse1
      • Special Effect - Destroy BLse2
      • Special Effect - Destroy BLse3
      • Unit - Remove speed from Luster
This is a spell from a recent map I've been looking at - a real example of someone's work I've seen. Now, in the test map the spell may work find or at least seem to, but if you look closely enough you should be able to easily find the error. The ability is added to a unit, and many effects are created as well. Each of these are set to their own variable, and after 15 seconds are referenced. Well, now what happens if 2 units cast it within 15 seconds of another? I'll tell you what, the effects and the ability from the first round of the spell still remain on the hero - not a good sign!

Second example - periodic events and multiple triggers
This one is another one I see all the time. People need to create a spell that does a certain thing - such as knocking back repetitively over and over again. These people use another trigger and a periodic event in order to accomplish this. Sure it works for a single unit, but what if someone wants all the units in a map able to cast the spell? Let me show you an example of this:
  • Flurry
    • Events
      • Unit - A unit Begins casting an ability
    • Conditions
      • (Ability being cast) Equal to Flurry
    • Actions
      • Set F_Archer = (Triggering unit)
      • Trigger - Turn on FlurryReg <gen>
      • Animation - Change F_Archer's animation speed to 200.00% of its original speed
      • Unit - Pause F_Archer
      • For each (Integer A) from 1 to 20, do (Actions)
        • Loop - Actions
          • Wait 0.01 seconds
          • Unit - Create 1 arow effect for (Owner of F_Archer) at (Position of F_Archer) facing (Facing of F_Archer) degrees
          • Unit - Order (Last created unit) to Move To (Center of Region 002 <gen>)
          • Unit - Move F_Archer instantly to (Position of F_Archer), facing ((Facing of F_Archer) + 18.00) degrees
          • Animation - Play F_Archer's attack animation
          • -------- Line removed due to taking up too much space --------
      • Animation - Change F_Archer's animation speed to 100.00% of its original speed
      • Unit - Unpause F_Archer
      • Selection - Select F_Archer for (Owner of F_Archer)
      • Set ArrowEffect[(Integer A)] = (Units of type arow effect)
      • Trigger - Turn off FlurryReg <gen>
      • Wait 0.50 seconds
      • Unit Group - Pick every unit in ArrowEffect[(Integer A)] and do (Unit - Remove (Picked unit) from the game)
(This trigger is initially disabled)
  • FlurryReg
    • Events
      • Time - Every 0.01 seconds of game time
    • Conditions
    • Actions
      • Region - Center Region 002 <gen> on ((Position of F_Archer) offset by 300.00 towards (Facing of F_Archer) degrees)
You could argue that this spell isn't coded very well, but that's not the point. As you can see, this spell turns on the disabled spell in the middle of the spell. The disabled spell moves a specific region to a unit's position every .01 seconds. The problem now is that this other trigger will be turned on for some time. If this spell were being cast again, the 'F_Archer' global variable would be changed to a different unit. The first and second trigger would then be referring to the second unit to cast the spell and not the first, this is a big problem!

Some Solutions
There is no single answer for fixing these kind of problems. Sometimes just better thinking can find you a better solution. If you're unable to find answers, here are some possible solutions:

GUI Local Variable Bug
Someone once found that local variables and global variables could share the same name, and that local variables are looked at before globals. Now, if you don't understand what I just said, here's the same thing in different terms. It means you can declare a local variable with the same name as a global variable, and then each time you refer to the global variable you will really be referencing the local variable. Here's an example of what I'm trying to say:
  • Untitled Trigger 001
    • Events
    • Conditions
    • Actions
      • Custom script: local unit udg_Caster
      • Set Caster = (Triggering unit)
      • Wait 60.00 seconds
      • Unit - Kill Caster
Now, everything should make sense to you except for the first line. The first line uses some JASS to declare a local variable with the same name as a particular global. This means that we can use the name of the global variable to really refer to the local variable. You're still probably wondering how more than one unit can use this at once and not cause problems I'm sure. If you were to create a global variable 'Caster' and test this code, you'd see that it would work without failing. Once again, you may be a bit confused so I'll explain how local variables work. Local variables are called local variables for a reason, they're only able to be accessed by the function they're in. "Functions, isn't that some kind of confusing JASS thing?" you might say. Let me tell you that GUI is converted to JASS when the map is saved (inefficient JASS, but still JASS nonetheless). All the actions inside a specific trigger are all part of one function for the most part. There are exceptions to this, but I'll review those later. Local variables being specific to each function may not make sense to you, so I'll word it in terms you may understand. Creating a local variable is like creating a completely new variable each time the spell starts. Basically, this makes it so we'll be able to refer to the caster no matter how many units cast it at once.

Now, let's fix up the first spell to use this method:
  • bloodL
    • Events
      • Unit - A unit Begins channeling an ability
    • Conditions
      • (Ability being cast) Equal to Bloodrage
    • Actions
      • Custom script: local unit udg_Luster
      • Custom script: local effect udg_BLes1
      • Custom script: local effect udg_BLes2
      • Custom script: local effect udg_BLes3
      • Set Luster = (Triggering unit)
      • Unit - Add speed to Luster
      • Special Effect - Create a special effect attached to the right,hand of Luster using Abilities\Spells\Other\BreathOfFire\BreathOfFireDamage.mdl
      • Set BLse1 = (Last created special effect)
      • Special Effect - Create a special effect attached to the left,hand of Luster using Abilities\Spells\Other\BreathOfFire\BreathOfFireDamage.mdl
      • Set BLse2 = (Last created special effect)
      • Special Effect - Create a special effect attached to the head of Luster using Abilities\Weapons\NecromancerMissile\NecromancerMissile.mdl
      • Set BLse3 = (Last created special effect)
      • Wait 15.00 seconds
      • Special Effect - Destroy BLse1
      • Special Effect - Destroy BLse2
      • Special Effect - Destroy BLse3
      • Unit - Remove speed from Luster
As you can see, we've added a local variable for each variable used after the wait in the spell. This spell is now MUI. Now, there's still some more explaining to do. All the global variables you make in the editor are renamed to "udg_Variable_Name" when the GUI is converted to JASS. So when you want to refer to a global variable in JASS, you need to add "udg_" to the front of the variable name and also replace any spaces with an underscore( the _ character).

I must mention one problem with using locals in GUI. The problem is that they cannot be used everywhere. For instance, you should not refer to local variables in if/then/else blocks and "pick every ..." blocks. The reason behind this is that if/then/else sometimes creates additional functions (even if they really are unnecessary) for the condition amongst other things. The "pick ever ..." blocks will always create an additional function that is called for each picked object. All of this information I just told you is hidden from you in GUI, which is why I'm warning you.

Implementing a Stack
Now, that solves one possible problem, but what if we need to use a separate trigger for periodic events? Local variables can't be used outside of the function they're created in. We'll have to be much cleverer to accomplish this task, but it's still possible. This method may be a bit confusing at first, but I'll try to explain it as best I can. I'll be showing you how you might make a knockback ability with this method.

This particular method I have in mind uses a "stack" of unique integers. When you need a unit to get knocked back, you "take" one of those integers off the stack and use it in conjunction with global arrays to put in data. The knockback trigger will then go through each index in use and do the proper actions. I realize what I said probably doesn't make sense, which is why I'll show you some triggers right now. Here is the trigger that would go off when the spell is cast:

  • Start
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
    • Actions
      • -------- Will increase the index, granting us a unique number --------
      • Trigger - Run NewIndex <gen> (ignoring conditions)
      • -------- Now we will set our variables --------
      • Set KnockbackUnit[CurrentIndex] = (Target unit of ability being cast)
      • Set KnockbackDistance[CurrentIndex] = 10.00
      • Set KnockbackTime[CurrentIndex] = 10.00
      • -------- Our loop trigger will handle the rest --------
And here's the "loop" trigger that would handle moving the units:

  • Loop
    • Events
      • Time - Every 0.04 seconds of game time
    • Conditions
    • Actions
      • -------- For each index in use --------
      • For each (Integer A) from 1 to 50, do (Actions)
        • Loop - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • KnockbackUnit[(Integer A)] Not equal to No unit
            • Then - Actions
              • -------- Decrease the time in each index, when it reaches 0 the unit will stop moving --------
              • Set KnockbackTime[(Integer A)] = (KnockbackTime[(Integer A)] - 0.04)
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • KnockbackTime[(Integer A)] Greater than 0.00
                • Then - Actions
                  • -------- The unit is still being knocked back, move it --------
                  • Unit - Move KnockbackUnit[(Integer A)] instantly to ((Position of KnockbackUnit[(Integer A)]) offset by KnockbackDistance[(Integer A)] towards 0.00 degrees)
                • Else - Actions
                  • -------- The unit should no longer be knocked back, return the index for future use --------
                  • Set CurrentIndex = (Integer A)
                  • Trigger - Run ReturnIndex <gen> (ignoring conditions)
            • Else - Actions
Now, I've purposefully left out the other triggers being run so I can first explain what's going on here. The start trigger would go off whenever a unit started the effect of an ability. Next, we run the NewIndex trigger which will return a unique integer for use with this knockback spell. The unique integer is stored by the NewIndex function in the CurrentIndex variable. Now, we have also set up a bunch of global array variables. To be exact, there is one for each type of information we want to store. We have one for the unit being knocked back, one for how far the unit is moved each cycle, and how long the knockback should go on for. Next, we store the target unit, the distance we want, and the time in their respective global arrays with the index being the value in the CurrentIndex global variable (which is a unique) integer for this spell.

Next is the Loop trigger which handles the actual moving of the units. We're going to loop through all the indexes that are being used. To do this, you must first know that the amount of indexes being used is stored in the KnockbackIndex variable. We run a "For each integer A from 1 to 50" action which will allow us to go through each index in use and perform the necessary actions. 50 is the maximum number of indexes, so this code will run through the loop 50 times. Of course, we will need to check the current index to make sure that the unit stored in KnockbackUnit isn't equal to "no unit" (which would mean that index isn't being used). The rest should be self-explanatory because I've commented the code. For those who don't know, (Integer A) will refer to the current index being "looked at" by the trigger.

Now I will move on to what's happening in the background. We have a stack of unique integers you might say. If you're one of those people who learns better visually, you're in luck. Here's a visual representation of the stack:

123...50

This stack is basically a container that starts out just holding the numbers 1 through 50. Now, when we request a new index, we "take" the value stored on the top of the stack and the next value will be treated as the top of the stack. This is what the stack would look like if we grabbed the value stored at the "top" of the stack.

234...50

Doing things like this will ensure the same number cannot be taken twice, which grants us 50 unique numbers. Now that's great, but unless we return numbers to the stack we'll have nothing left when we get to 50. That would definitely be a problem, so we'll have another trigger to return indexes back to the stack. Let's say the indexes 1 through 5 were already in use. Here's what our stack would look like:

678...50

Now, let's say the first index was done being used. We'll put it back on the stack to be able to be used in the future by our spell. The stack would look like so if we returned the first index:

1678...50

Okay, I hope that gave you an understanding of how a stack works. If it didn't, that's too bad because I'm not going to really be covering it any longer. Next we need to implement this into trigger form. We obviously first need to have a stack before it can be used, so let's make an initializing trigger for it:

  • Init
    • Events
      • Map initialization
    • Conditions
    • Actions
      • -------- Fill up the array with 50 unique numbers --------
      • For each (Integer A) from 1 to 50, do (Actions)
        • Loop - Actions
          • Set KnockbackId[(Integer A)] = (Integer A)
          • Set KnockbackUnit[(Integer A)] = No unit
Now, the KnockbackId will contain each of our unique ids to be used with the spell. We've filled the first 50 indexes of it (we shouldn't need any more indexes) with the numbers 1 - 50. We're also going to set the unit stored in each index used in the KnockbackUnit array to "no unit" which means that the index isn't being used. I'd go into further detail on how this trigger works, only I'm not really sure that there's anything more I could say.

Moving on, let's see how we're going to get a new index from this stack:

  • NewIndex
    • Events
    • Conditions
    • Actions
      • Set KnockbackIndex = (KnockbackIndex + 1)
      • Set CurrentIndex = KnockbackId[KnockbackIndex]
KnockbackIndex originally is set to 0, meaning the current amount of used ids from the stack is 0. This variable is equivalent to how many ids are currently in use. First thing this trigger does is increment the KnockbackIndex variable so that it will accurately show how many ids are in use. Next, we set the CurrentIndex variable to the value stored in at the "top" of the stack. Since this isn't really a stack, its size will always remain at 50 which is why we have our KnockbackIndex variable. This variable is really used to tell us which index we need to take the id from when we want a new id. Here's a visual representation first when the stack is full, and second when we're taking a value:

KnockbackIndex (0) ->
1
2
...
50

KnockbackIndex (1) ->1
2
3
...
5

KnockbackIndex (1) ->
2
3
4
...
50

This should give you an idea of what's going on with this trigger. Now we will move onto returning an index back to the stack. I'm hoping you will be able to better understand this example after the previous trigger. Here it is:

  • ReturnIndex
    • Events
    • Conditions
    • Actions
      • Set KnockbackId[KnockbackIndex] = CurrentIndex
      • Set KnockbackIndex = (KnockbackIndex - 1)
From the previous example, you saw that KnockbackIndex would actually point 1 space above where the top of the stack was. First, why not just place the index being returned right there on top of the stack where it belongs? Good question, let's do so first. After the index is placed one space above the stack, KnockbackIndex is pointing directly at it when it should be pointing one space above it. So, let's fix it by setting KnockbackIndex to KnockbackIndex - 1. We of course need to set KnockbackUnit on the id to be released to "no unit" for safety measures with the Loop trigger.

Just to clear things up, CurrentIndex is equal to one of the ids that was taken from the stack while KnockbackIndex represents a position on the stack.

This basically concludes things for now. I might choose to explain how you can make a spell just multi-instancible per player for those who have a hard time understanding the stack idea, but that will have to wait. I hope this has helped you and that you will be able to use these techniques in future projects.

A member of Clan TDG - Quality mapmaking and playtesting.

Tired of boring old GUI? Want to learn JASS? Take a look at these tutorials.
 
Last edited:
Level 32
Joined
Oct 23, 2006
Messages
5,291
Multi-Instancible GUI Spell Making seems very helpful to me wrymlord: if all spell makers would carefully consider your points you would have a lot fewer messes to clean up and our spell resource section would contain far better spells.

Try to force a line break into the action Unit - Cause F_Archer to damage circular area after 0.00 seconds of radius 300.00 at (Position of F_Archer), dealing 5.00 damage of attack type Pierce and damage type Normal to see if you can prevent that action from stretching the page.


Let's see what your fellow Spell Resource Moderators have to add: I'm sure that they can help you further develop it.
 
Level 11
Joined
Oct 13, 2005
Messages
233
You don't show ReturnIndex (the trigger)

Other than that, no complaints.

(oh, and nice pseudo-functions :p)

Actually, it's there right at the bottom. :p I had debated on using JASS functions for this, but figured this way would be easier for GUI users.

your triggers leak locations in PERIODIC triggers! baaaaaaad :>

This tutorial is just showing methods used for multi-instancible spells. I don't think it's really necessary to remove every last leak.
 
Level 32
Joined
Oct 23, 2006
Messages
5,291
Sorry, wyrmlord, I just now noticed that you had bumped this.
  1. Approval status: almost certain.

  2. Please detach your signature from the tutorial.

  3. Would it be possible to create a simple map that includes all of your trigger techniques so that consumers will have more flexibility in their implementation?

  4. It's really up to you and the other spell mods to determine if the leak issues should be addressed. My opinion is that in tutorials, they should. If you guys don't think it's absolutely necessary to plug them up, please make a strong disclaimer in the tut. Thanks.
 
Level 11
Joined
Jul 12, 2005
Messages
764
It's really up to you and the other spell mods to determine if the leak issues should be addressed. My opinion is that in tutorials, they should. If you guys don't think it's absolutely necessary to plug them up, please make a strong disclaimer in the tut. Thanks.
I think removing all leaks would confuse beginners, as they would ask "what the well does it do with the location? what variable it is? etc.."
This tutorial perfectly covers the MUI GUI (I always loved this phrase:p) spell making. You could leave a note: "Users should remove leaks. Here is a tutorial about it".
Totally approvable!


PS: But Wolve is right, a testmap would be nice!
 
Level 4
Joined
Jun 21, 2007
Messages
116
Considering you are very sensitive on leaks thing saying about them to every beginner, even total newbies confusing them on their first steps on WE... :/

also people expect 'perfect' examples in tutorials
 
Level 32
Joined
Oct 23, 2006
Messages
5,291
Tutorial Approved

Wyrmlord: I have detached your signature file from the tutorial.

Please include a disclaimer regarding the leaks and create a map when you have the chance.

Consumers of this tutorial should note that the triggers contain (minor) leaks which should be addressed when including them in their maps.

~ Thread moved to Trigger (GUI) Editor Tutorials.
 
Level 3
Joined
May 3, 2004
Messages
46
Awesome :)
Never really used the "local" function, I've always been messing around with arrays and other stuff :(

*BUMP* ;)
 
Level 32
Joined
Oct 23, 2006
Messages
5,291
about the locals

i need to make a Weather Effect local, and im guessing the custom script goes like this
  • Custom script: local weather udg_WeatherEffect
am i wrong?
i still need help :(
Somehow, you must have missed the sticky thread:

The Hive Workshop > Warcraft III Tutorials > Trigger (GUI) Editor Tutorials >IMPORTANT NOTICE - Read Before Posting!
This forum is open for posting so that users may comment on the content, information and style of approved tutorials. Posts must directly relate to the tutorials themselves. Suggestions regarding the improvement or revision of a tutorial's subject matter are the only acceptable posts in this forum.

Questions regarding general trigger matters should be asked in THW's
[self="http://www.hiveworkshop.com/forums/forumdisplay.php?f=270"]Triggers (GUI)[/self]
 
Level 2
Joined
Apr 13, 2007
Messages
17
Really good job, so far i've been focusing on using trigger enhanced spells only for heroes, since some werent possible with the knowledge i had at the time :p Very nice info :D
 
Level 9
Joined
Jun 26, 2005
Messages
511
hmm read alll those til when you explain stacks, which i dont really get, i dont really get what i was reading, i use MUI triggers and i use wait too, but then i dont know how the local variables will work, you said they only work in triggers that doesnt has other functions, and if/then/else are very useful trigger. normally i dont use looping, when i dont understand how a trigger works, its hard to find whats the problem when incounter a bug, so i mostly just copy and paste to repeat the stuff i need.

well i must say am not really good at triggers, i didnt get much you said.
 
well i must say am not really good at triggers, i didnt get much you said.

I agree 100% with Dracula. The stack system you are trying to explain may be very good, but it is explained in an horrible way. You only give 1 simple example, and you don't explain how the system works globally. I really think you should improve that stack system section of your tutorial because no1 really understands it.

And i am learning JASS and MUI, i am an expert at GUI. I have to agree with Dracula.

Another thing, you MUI system does not work properly.... at least it doesn't work in the spell i am learing from Daelin:
  • Seduce
    • Seduce
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • (Ability being cast) Equal to Seduce
    • Actions
      • Custom script: local unit udg_SeducedUnit
      • Custom script: local player udg_SeducedPlayer
      • Set SeducedPlayer = (Owner of (Target unit of ability being cast))
      • Set SeducedUnit = (Target unit of ability being cast)
      • Unit - Change ownership of (Target unit of ability being cast) to (Owner of (Casting unit)) and Change color
      • Wait 0.10 seconds
      • Wait until ((SeducedUnit has buff Seduce ) Equal to False), checking every 0.10 seconds
      • Unit - Change ownership of SeducedUnit to SeducedPlayer and Change color
      • Set SeducedUnit = No unit
      • Set SeducedPlayer = (Matching player)
The spell DOES work, however, when i add your codes it just fails everyting. Something is wrong.

another thing is that you probably are setting you local variables in a wrong way:

JASS:
function Trig_Seduce_Conditions takes nothing returns nothing
local unit Caster = GetSpellAbilityUnit
endfunction

or

JASS:
function Trig_Seduce_Conditions takes nothing returns nothing
local unit Caster
set Caster = GetSpellAbilityUnit
endfunction

According to one of you JASS tutorials people should declare variables like this. However i am new in JASS so, i think it would be wise for me not to question your knowledge about JASS, because let's face it, you are the professional here wyrmlord. I am just trying to help and i think something is wrong in your tutorial.
 
Last edited:
Level 5
Joined
Oct 7, 2007
Messages
61
Well Pheonix, you mustn't declare that like that. Later on you can save up 1 line if you say something like:
set local Caster = GetTriggeringUnit
----------------------------------
Wymlord, just a quick Question:
Is there a way of making Local Variables work in Loops, UnitGroups?
For example something like this:
JASS:
set local integer NumberofObjects = 6
set local real Angle = 360.00/(integer(NumberofObjects))
set local real Distance = 100.00
set local unit Target = GetTargetUnit
Then make a GUI Loop:
  • Loops Trigger
  • For Each integer from 1 to NumberofObjects do Actions
    • -Loop
  • Set local location[IntegerA] = at Target in a distance of Distance towards Angle*(Real(IntegerA))
(Don't remember the Function for the PolarPoint Function in JASS, since I'm a GUIer :p)
 
Level 11
Joined
Oct 13, 2005
Messages
233
Actually, you'll just need a few lines of JASS to create a JASS loop in GUI. Here's how it'd work:
  • Loop
    • Events
    • Conditions
    • Actions
      • Set variable = 0
      • Custom script: loop
      • Custom script: exitwhen udg_variable == 7
      • -------- Put some code here. Local variables are allowed. --------
      • Set variable = (variable + 1)
      • Custom script: endloop
The "loop" statement tells Warcraft 3 that you're beginning a loop. When the code reaches the "endloop" statement, it will return to the "loop" statement and continue the loop. Now, the exitwhen line is fairly simple. You need some way to tell Warcraft 3 when to exit the loop hence "exitwhen".Following the exitwhen statement is a boolean expression.

Boolean means true or false. For the boolean expression, you're able to enter either a boolean variable (udg_myBoolean) or a comparison such as "udg_myVar == 6". When comparing two terms, you're able to use a variety of different symbols to represent different logical expressions. Here are some:
JASS:
udg_someInteger > 5 // Returns true if the integer is greater than 5
udg_someInteger >= 5 // Returns true if the integer is greater than or equal to 5
//
//
udg_someInteger < 5 // Returns true if the integer is less than 5
udg_someInteger <= 5 // Returns true if the integer is less than or equal to 5
//
//
udg_someInteger == 5 // Returns true if the integer is equal to 5. Keep in mind that you must use a "==" instead of a "="
udg_someInteger != 5 // Returns true if the integer is not equal to 5
//
//
// == and != can be used to compare other values that are not numbers such as units or players like so:
udg_someUnit != udg_someOtherUnit   // Returns true if someUnit is not someOtherUnit. This refers to a specific unit, not a unit type
//
//
//In addition to these expressions, we also have 3 others:
//
//
udg_someInteger == 5 or udg_someInteger < 3   // Returns true if the integer is equal to 5 or less than 3
//
//
udg_someInteger > 0 and udg_someInteger < 10  // Returns true if the integer is greater than 0 and less than 10
//
//
not udg_someInteger > 5     // While this isn't the best example, will return true if the integer is not greater than 5
//
// These expressions can be combined in many ways, here's an example:
//
not( udg_someInteger == 4 or udg_someInteger == 5 )    // Returns true if the integer is not equal to 4 and not equal to 5.
//
// Notice the parenthesis, they are used just like in math. First, the values inside the parenthesis are compared before moving outside of them.

Sorry for the extra "//" between lines, but otherwise the returns were ignored and it was all squeezed together. I hope this makes sense, but if it doesn't please ask questions.
 
Level 5
Joined
Oct 7, 2007
Messages
61
Actually, you'll just need a few lines of JASS to create a JASS loop in GUI. Here's how it'd work:
  • Loop
    • Events
    • Conditions
    • Actions
      • Set variable = 0
      • Custom script: loop
      • Custom script: exitwhen udg_variable == 7
      • -------- Put some code here. Local variables are allowed. --------
      • Set variable = (variable + 1)
      • Custom script: endloop
The "loop" statement tells Warcraft 3 that you're beginning a loop. When the code reaches the "endloop" statement, it will return to the "loop" statement and continue the loop. Now, the exitwhen line is fairly simple. You need some way to tell Warcraft 3 when to exit the loop hence "exitwhen".Following the exitwhen statement is a boolean expression.

Boolean means true or false. For the boolean expression, you're able to enter either a boolean variable (udg_myBoolean) or a comparison such as "udg_myVar == 6". When comparing two terms, you're able to use a variety of different symbols to represent different logical expressions. Here are some:
JASS:
udg_someInteger > 5 // Returns true if the integer is greater than 5
udg_someInteger >= 5 // Returns true if the integer is greater than or equal to 5
//
//
udg_someInteger < 5 // Returns true if the integer is less than 5
udg_someInteger <= 5 // Returns true if the integer is less than or equal to 5
//
//
udg_someInteger == 5 // Returns true if the integer is equal to 5. Keep in mind that you must use a "==" instead of a "="
udg_someInteger != 5 // Returns true if the integer is not equal to 5
//
//
// == and != can be used to compare other values that are not numbers such as units or players like so:
udg_someUnit != udg_someOtherUnit   // Returns true if someUnit is not someOtherUnit. This refers to a specific unit, not a unit type
//
//
//In addition to these expressions, we also have 3 others:
//
//
udg_someInteger == 5 or udg_someInteger < 3   // Returns true if the integer is equal to 5 or less than 3
//
//
udg_someInteger > 0 and udg_someInteger < 10  // Returns true if the integer is greater than 0 and less than 10
//
//
not udg_someInteger > 5     // While this isn't the best example, will return true if the integer is not greater than 5
//
// These expressions can be combined in many ways, here's an example:
//
not( udg_someInteger == 4 or udg_someInteger == 5 )    // Returns true if the integer is not equal to 4 and not equal to 5.
//
// Notice the parenthesis, they are used just like in math. First, the values inside the parenthesis are compared before moving outside of them.

Sorry for the extra "//" between lines, but otherwise the returns were ignored and it was all squeezed together. I hope this makes sense, but if it doesn't please ask questions.

Thats cool ^^ Now to Unit groups... Is it possible to make some JASS Lines in Unit Groups, without having it malfunction?
 
Top