1. Join other hivers in a friendly concept-art contest. The contestants have to create a genie coming out of its container. We wish you the best of luck!
    Dismiss Notice
  2. The Melee Mapping Contest #4: 2v2 - Results are out! Step by to congratulate the winners!
    Dismiss Notice
  3. We're hosting the 15th Mini-Mapping Contest with YouTuber Abelhawk! The contestants are to create a custom map that uses the hidden content within Warcraft 3 or is inspired by any of the many secrets within the game.
    Dismiss Notice
  4. The 20th iteration of the Terraining Contest is upon us! Join and create exquisite Water Structures for it.
    Dismiss Notice
  5. Check out the Staff job openings thread.
    Dismiss Notice

Beginning JASS Tutorial Series

Discussion in 'JASS/AI Scripts Tutorials' started by wyrmlord, Feb 16, 2007.

  1. wyrmlord

    wyrmlord

    Joined:
    Oct 13, 2005
    Messages:
    252
    Resources:
    5
    Tools:
    1
    Maps:
    1
    Tutorials:
    3
    Resources:
    5
    Contents
    Overview
    Introduction to JASS
    Lesson 1: A Simple Function
    Lesson 2: Variables
    Lesson 3: Functions
    Lesson 4: If/Then/Else and loop structures
    Lesson 5: Triggers in JASS
    Lesson 6: Memory Leaks
    Lesson 7: Starting a Spell in JASS
    Lesson 8: Continuing the Spell

    This tutorial series is being made by:
    -darkwulfv
    -moyack
    -wyrmlord

    Overview

    Have you wanted to learn JASS, but haven't really had enough tutorials to walk you through the basics and beyond? The aim of this series of tutorials is to provide many tutorials to help a new user start from scratch and after going through the tutorials (and practicing a bit after) to have a fairly good understanding of JASS. "Lessons" are meant to be fairly small, and have only a few topics explained at once in an attempt to not overwhelm people trying to learn.

    If anything in any of the tutorials isn't explained clearly enough, please say so. We want the tutorials to be as informative as possible, and an unclear point could ruin an entire lesson.

    This tutorial series was originally posted at wc3campaigns. We decided to submit the tutorial series here on The Hive because we just recently found out that Daelin was unable to continue his JASS Classroom, so we thought it would be a good idea to have somewhere else for people to look to learn more than what Daelin had taught.

    If you are interested, the attachment at the bottom contains all the tutorials in either .doc or .html format.

    Good luck, and happy JASSing!

    Introduction to JASS

    Tutorial 1: Welcome to the world of JASS.

    What is JASS?
    -JASS is the programming language used by the Wc3 engine.

    What is GUI?
    -GUI stands for Graphic User Interface. It is the default crap used by the trigger editor, made to make triggering easier. Unfortunatly, Blizzard made it harder. GUI is bad. It uses BJ's (which will be covered later on), inneficient code, and is overall messy and limiting.

    Why use JASS? Can't I just use GUI?
    -Sure, you can use GUI. It's not recomended anymore, but it's not dead or nothing.

    Here are the Pros of JASS:
    -Easier to write out
    -Faster, more effecient, and no leaks (when done properly that is)
    -Breaks many restraints created by GUI
    -Doesn't use BJ's (which again is possible when done correctly)
    -Neater, easier on the eyes for longer triggers
    -Easier to copy/paste, and can be edited in a text editor or 3rd-party editors (such as JASScraft)
    -Generally faster to do when you get the hang of it. Much less clicking around.

    However, you must be careful with JASS. As great as it is, it must be used correctly. One single mis-type can screw up an entire trigger.

    Will it be hard to use?
    -If you've programmed anything before, JASS will be much easier. Even if you haven't, its still pretty easy. It'll take some getting used to, and can be frustrating. You may even feel like reverting back to GUI, but don't. This is worth it. Very complex things will obviously be harder, but we're gonna start you off easy.


    How do I get JASS in my editor?
    -Make a trigger and name it. Then go to Edit -> Convert to Custom Text. This cannot be reversed. Now edit away!

    I'm having trouble typing JASS in the WE!
    -Use a 3rd party program for some help. JASScraft and Silly JASS Utility are 2 I would suggest for anyone. Both can be found on the site. JASScraft is perfect for editing your new JASS, since it gives function names, native lists, and Take/Return values, plus a good syntax checker, and more. Definatly a must-have.

    When I try to save or test, I get a ton of errors!!
    -You probably have a typo or two somewhere, or an unexistant function. Check all your code and JASS is VERY case sensitive. If you type an "A" where an "a" should be, you will get an error. Also, check to make sure there aren't other errors. JASScraft can assist you here. That's why we recommend editing your codes in JASScraft. Much much much easier.

    So what's the first step to learning JASS?
    -Forget everything you know about GUI, except for globals. JASS is far different from GUI, and trying to compare them is a bad idea. However, a good first step is to make some triggers in GUI, then make them JASS. Throw them into JASScraft and have a ball converting BJ's to natives and cleaning leaks. You'll learn fast. It definatly helps the crossover from GUI to JASS.

    Ok, I know the basics. Now what?
    -If you want to learn more, read ahead to tutorial #2, by Wyrmlord. He'll teach you the basics of functions. Or, you can go ahead and take it alone from here. The choice is yours. Either way, I wish you good luck!

    ~Darkwulfv

    Lesson 1: A Simple Function

    Overview
    In this lesson, I will go over with you a very simple function example. I will explain everything you will need to know about it and then at the end I will give you a 'challenge'. This challenge contains some content from the next section, so you will be able
    to find out your answer in Lesson 2.

    Now that you've looked at an introduction to the advantages of JASS, you're probably eager to get started with some code, right? Now, forget GUI (regular 'triggers'), JASS is different from GUI, so I'll be treating
    it that way. Now, open up a text editor of some sort such as Notepad (windows) or some other program
    depending on your operating system.

    Now, I'm going to show some code. It will be a bit confusing at first, but I'll explain it throughout this lesson.
    Code (vJASS):
    function HelloWorld takes nothing returns nothing
        call BJDebugMsg("Hello World")
    endfunction


    Now, don't put this into the editor yet as it's not complete. First off, I'll start with the first line.
    JASS, like many programming languages, is made up of a series of functions. I won't go into detail
    on that yet, but for now just know that you are declaring/creating a function.

    Now, the next line:
    Code (vJASS):
    call BJDebugMsg("Hello World")


    This particular line 'calls' a function. Functions are like actions if you've used GUI before, they execute a command. This particular function puts the text "Hello World" (without the quotes) onto the screen.

    Code (vJASS):
    endfunction


    Now, the final line is pretty simple, when you declare/create a function it needs to end somewhere, right? This line just tells you that the function ends here.

    Now, I've gone over with you a very basic example of JASS, if you wish to test this function in the World Editor, simply:
    -Create a new map
    -Go to the trigger editor
    -Click on the map icon at the top of the list of triggers
    -Paste the code in the custom script section.

    Now, create a trigger (sorry for the GUI reference), you can make the event whatever you want, I'd suggest that you make it go off whenever you press an arrow key. Now, for the action, just find custom script, and in the box
    that it gives you, type:
    Code (vJASS):
    call HelloWorld()


    And there you have it, you can now test the function in the game.

    Notice how you call a function in that line. I'm now going to go over the function declarations a bit.
    When you call a function, you type 'call <function_name>( <parameter1>, <parameter2>, <parameterN> )'
    What this basically says is that you type call, while is followed by the name of the function and parenthesis '()'. If the function needs certain info (known as parameters) you put that specific info inside the parenthesis. Each set of 'info' is separated by a comma ','

    This particular function only needed a string (message) to display on the screen. Here's some more info:

    Code (vJASS):
    function HelloWorld takes nothing returns nothing


    When a function has the text 'takes nothing', that means you don't need anything in the parenthesis when calling it.
    The return value is a value that the function returns. Like the CreateUnit function returns a unit. If you're confused, don't worry as this will be covered in a later lesson.

    Now, feel free to mess around with the HelloWorld function, add more calls to the BJDebugMsg, show whatever text you want. Let me say that for now, the text should be inside quotation marks "like this"

    Challenge #1: Modify the HelloWorld function to print out other info:

    Here's an example:
    Code (vJASS):
    function HelloWorld takes nothing returns nothing
        call BJDebugMsg("Hi, my name is Bob.")
        call BJDebugMsg("I am 2 years old!")
        //And so on, by the way you can add comments to your code like this
        //Basically if you have '//' somewhere on a line, the rest of the line (after the '//') counts as a comment
    endfunction


    This may seem like a waste of time, but the more you use JASS the more familiar it will become.

    Good Luck -wyrmlord

    Lesson 2: Variables
    By: Darkwulfv

    What is a variable?
    -A variable is sort of like a place holder for a handle or other object. There are 2 types of variables. Local and Global.

    What is the difference between Local and Global variables?
    -Local variables are variables only usable by the function they’re declared in. These are used for cleaning Memory Leaks (which will be explained later), neatening code, and making script Multi-instanceable.
    -Globals are variables which can be accessed by any function, but can also be changed by any function. This can be bad for multi-instanceability (which will now be referred to as MUI), depending. MUI will be discussed later on.

    How do I create a local variable?
    -There are two ways to creating/setting a variable.
    Code (vJASS):
     function variable_test takes nothing returns nothing
      local unit u = CreateUnit()
    endfunction

    This method creates and sets it in one line, at the beginning of the function.

    Code (vJASS):
     function variable_test takes nothing returns nothing
      local unit u
        set u = CreateUnit(…..) //Creates a unit and sets the variable to it
    endfunction

    And this method creates a blank variable, to be set later on in the function.

    Hey wait! I want the value to change, does that mean I need a new variable?
    -No, not necessarily. All you need to do is put “set your_variable = newvalue
    Here’s an example.

    Code (vJASS):
    function variable takes nothing returns nothing
    local unit u = CreateUnit()
    //Other actions
    set u = other_unit //other_unit would be some other unit, don't use this example literally!
    endfunction


    Remember though, that old value isn’t set to that variable, so if you want 2 different units, use 2 different variables.


    Ok, so I have my local variable. Now what?
    -Now, use it! Here’s an example.

    Code (vJASS):
    function KillUnit takes unit u returns nothing

    -If you notice, KillUnit needs a unit. Now, you can fill this with many things, like GetTriggerUnit(), GetSpellAbilityUnit(), or any function which returns a unit. However, a variable can be a unit, so you can put that there instead. Here’s a side-by-side comparison.

    Code (vJASS):
    function variable_testA takes nothing returns nothing
      local unit u = GetTriggerUnit()
        call KillUnit(u)
    endfunction

    function variable_testB takes nothing returns nothing
        call KillUnit(GetTriggerUnit())
    endfunction

    They both work, it's up to you to choose which way you prefer.

    Naming variables
    When naming variables, you can't just use any name. First off, the only characters you can use are any letter in the alphabet, any number, and the underscore character (_). The first letter in a variable name must be a letter, after that you can use numbers, letters, and underscores all you want. Let me make it clear that you can not use spaces in a variable name.


    What about global variables?
    -Global variables are created through the Variable Editor, inside the Trigger Editor. These variables can be used in any function, unlike locals. Example:

    Code (vJASS):
     function A takes nothing returns nothing
      call KillUnit(udg_u)
    endfunction

    function B takes nothing returns nothing
        call KillUnit(udg_u)
    endfunction

    This is basically what it means. A variable starting with “udg_” usually means it is global. You can do this sort of thing with locals, but it isn't advised. If you need to refer to the same unit in a different function, there are methods of doing so which will be discussed later. The names of the variables you create are udg_variable_name. Each space in the variable name you enter in should be referred to with an underscore '_'

    You mentioned Memory Leaks, what are those?
    -Although these will be discussed in full later, it is good that you know now.
    Edit by wyrmlord
    Whenever a variable, handle, or string is created, the game must set aside space for it to use. To get rid of that space, there are various methods you can use depending on the object. For example, if you had a special effect, you could destroy it and free up any space it was using. Memory leaks occur when an object isn't able to be destroyed, and it will stay in memory until the end of the game. Another example: suppose I create another special effect, and no variable is set to it. The special effect will use up memory (even if it can't be seen), and since it's unable to be destroyed, it will continue to use memory until the end of the game. Local variables that aren't integers, reals, or boolean are like this too. The fix to them is simply setting them equal to null at the end of a function. Strings use up memory as well, but you can't do anything to stop them from doing so.


    So how do I fix Memory Leaks?
    Edit by wyrmlord
    Memory leaks will be gone over in a later tutorial. If you're eager to learn about them, by all means skip to the lesson on memory leaks. However, I wouldn't suggest doing any major amounts of coding until you know more about them


    I saw an option to make the variable an array. What’s that mean?
    -An array is a variable with more than one option, per say. It’s like an index of that variable type, sort of like a library. To access the variables, you must set them to an index number, then retrieve them as such.
    Example:
    Code (vJASS):
     function variable_test takes nothing returns nothing
      local unit array u
    set u[1] = GetTriggerUnit()
    set u[2] = GetSpellTargetUnit()
        call KillUnit(u[1])
        call KillUnit(u[2])
    set u[1] = null
    set u[2] = null
    endfunction

    There is an easier way to assign index numbers and null them. It involves integers and loops, and will be shown during the discussion of loops.
    Functions can also be fit into those brackets [] to set it to a number; any function that returns an integer or real should cover it.

    Edit by wyrmlord
    This is just to have multiple explanations of the same thing, for possibly confused readers. Arrays are basically a lot of variables squeezed into one. To be exact, 8192 variables. To declare an array in JASS, you would do something like this:
    Code (vJASS):
    local integer array int_array

    The difference is really just adding the word "array" before the variable name. You are unable to set the array to a value on the same line that you create it, keep in mind. Now, you'll need to know how to access each of the 8192 parts of the array. You do that like a normal variable, only you have brackets after the variable with an integer between them, which would be a number from 0 to 8191. If that's a bit confusing, here's an example:
    Code (vJASS):
    local integer array myIntegers //declaring the integer array
    set myIntegers[0] = 5 //Setting the 0th slot in the array to 5
    set myIntegers[1] = myIntegers[0] + 2  //Setting the 1st slot in the array to the value in the 0th slot in the array + 2
    set myIntegers[myIntegers[1]] = 2 //This is just showing that you can use a variable inside the brackets as well, it doesn't have to be an array though

    I would not recommend using arrays for a purpose as small as this. An array contains 8192 values, no more and no less. For something like this it's like killing a fly with a bazooka. (In other words, don't use arrays unless they are actually needed)


    There you have it! Variables in a nutshell. If you want to see a list of all the variables, open up either common.j in the Patch.mpq file. Or if you're not sure how to do that, get a tool like JassCraft, and on the right side of the screen when you open it up is a search box and a long list. On the bottom of that list is "show options". Click that, and then uncheck everything in the "search for" box except types. You can now click "hide options" and search through the types of variables.

    Edit by wyrmlord

    There are a few main variable types: integer, real, string, boolean, and handle. I'm sure you know what an integer is, it's a whole number (including negatives) such as: 1, 145, -37. A real is a number with decimal places such as: 3.14, -15.78, 11.1134. A string, as you might already know can be thought of as a message or text: "Hello", "This is a string". A boolean has two values: true or false. A handle, you could say, is a reference to an object such as a unit. You don't direct use the handle type usually, but you use types that extend the handle type. This basically means that they are a specific type of handle. A handle is pretty much anything that isn't an integer, real, string, boolean. Handles include: units, special effects, timers, groups, players, and so on.


    CHALLENGE:
    Can you fill in this code with the correct variables? (this does not involve arrays)
    The “_”’s represent where something needs to be filled in.

    Code (vJASS):
     function variable_challenge takes nothing returns nothing
      local ____ _ = GetTriggerUnit()
        call KillUnit(_)
    set _ = ____
    endfunction


    Good luck, and happy JASSing!
    ~Darkwulfv

    Lesson 3: Functions
    Overview

    In this lesson, I will be going over how to:
    1.Create functions
    2.Call functions
    3.Anything else I can think of

    Part 1: Creating a function

    Now, you're probably wanting to know how to create functions, right? Well, to create functions, you first need to tell the program that you're creating a function, so you do that by delcaring a function. This is basically telling the program the function's name, what values it needs to get when called, and what it returns. Take a look at this function:

    Code (vJASS):
    function DisplayAMessage takes string message returns nothing
        call BJDebugMsg(message)
    endfunction


    Now, the word 'function' tells the program that you will be declaring a function. The next part of the function is the name of the function. You need to make sure your function has a unique name that no other function has, otherwise you'll get errors when saving a map. Next, you tell the program what the function 'takes' or needs pretty much. This function 'takes' a string, which is basically a message of some sort. After you put the type the function needs, you then have to put a name for it (so you can refer to it inside of your function). Lastly, you tell the program the type the function will return. You could make this a string, integer, real, and so on. However for this example, no value will be returned so we put 'nothing'.
    After declaring a function, inside the function you need to put what the function does, otherwise it would be pretty useless. This function simply calls another function using the string value that is needed to call it. Lastly, you need to tell the program when the function ends, you do this by putting 'endfunction' at the end of the function.

    Part 2: Calling functions

    Now, that may not all make sense, so I'll now explain how you call functions, which should hopefully clear things up a bit. First off, you can call a function in a few different ways, but I'll start by the easiest way, which is using the word 'call'.

    Code (vJASS):
    call DisplayAMessage("hello")


    This line would call the function I just showed you. When calling a function this way, you need to have the word 'call' followed by the function name which is then followed by parenthesis with the values the function takes inside of them. If a function takes multiple values, they are each separated by a comma ','. It works that same way when declaring functions too (whoops forgot to mention that earlier =P)
    Now, I will go over what the return values in functions are. They're pretty simple really, though I don't want anyone to be confused about anything. When a function has a return value, you can set variables that are the same type as the return value to that function. Here's an example:

    Code (vJASS):
    local string player_name = GetPlayerName(Player(0))


    Now, see that when you set a variable to the return value of a function, you don't need the word 'call'. Also, if you want to pass the return value of a function into another function call, you don't need to put the word 'call' either, as seen with the Player function that was the needed parameter in the GetPlayerName function.

    If when and when not to use call are confusing you, let me just say you can only have 1 call in a line, and call can't be used if you have another word before that such as 'set' or you're declaring a local variable.

    Also, and this is important when declaring a function, if the function declaration states that the function returns a value, somewhere in the function if must have a line that 'returns' the value, like so:

    Code (vJASS):
    function TestReturn takes nothing returns integer
        return 5
    endfunction


    When a function reaches the line with return on it, it returns the specified value and ends (no code below that line is looked at by Wc3)

    There is one last thing you need to know when calling functions, you can only call a function that is above another, since that may not make complete sense, here's an example:

    Code (vJASS):
    function SomeFunction takes nothing returns nothing
    endfunction

    function SomeOtherFunction takes nothing returns nothing
    endfunction


    Now, this is only used as a visual example so I can more easily describe what I was saying. You can only call a function that is above the function you are currently in. So, 'SomeOtherFunction' would be able to call 'SomeFunction'. However, 'SomeFunction' wouldn't be able to call 'SomeOtherFunction'.

    Challenge Time!

    Now, I figure you're wondering why the challenges so far aren't very hard (I'm just assuming that), and that's because we haven't taught you enough for us to really stump you on something. I hope this challenge will make you think more than normal. The following code has a few errors in it, find each error in it. There are 5 errors in the following code, can you find them all?

    Code (vJASS):
    function Function2 takes nothing returns string
     local string message = SomeFunction("Hello World")
    endfunction

    function SomeFunction takes string returns nothing
     local string a message
        a message = 'Something is wrong'
        call DisplayTextToPlayer(Player(0), 0, 0, a message)
    endfunction




    Good Luck -wyrmlord

    Lesson 4: if/then/else and loop structures
    Tutorial No 4. if/then/else and loop structures. By Moyack.

    These kind of structures are the most important in any programming language. In JASS, these structures are quite versatile and useful.

    Let's see the first structure: IF/THEN/ELSE

    To work with it, we can write it in this way.

    if/then/else structure
    Code (vJASS):

    if <condition 1 function or variable> then
        <Condition 1 script>
    elseif <condition 2 function or variable> then
        <Condition 2 script>
    ...
    else
        <Else condition script>
    endif
     


    Now you understand why I said versatile :)

    As you can see, the conditions must be a function which has to return a boolean variable type (true/false) or a boolean variable. Other interesting feature with the if/then/else structure in JASS, is that it can be used as a multiselection structure too, something very useful in many cases.

    In order to ensure the understanding of this structure, This is a small example showing the IF/THEN/ELSE in action

    IF/THEN/ELSE example
    Code (vJASS):

    function Set_Damage_To_Unit takes integer level returns real
        // this example will set the damage amount in a spell, according to a level
        // (unit level, ability level, etc)
        local real dam
        if level < 2 then
            set dam = 0
        elseif level == 1 then
            set dam = 50.
            // probably you noticed the point after the number. this is used to indicate the number is a real one.
            // Is a good programming practice to do that in order to avoid annoying debugging mistakes.
        elseif level == 2 then
            set dam = 63.
        elseif level == 3 then
            set dam = 125.
        else
            set dam = 125. + 50. * (level - 1)
        return dam
    endfunction
     


    Here we are using a local variable which will have a value according to the input argument in the function, and then that variable will be returned by the function.

    Important note
    If any IF or ELSEIF clauses apply, then the ELSE clause will be avoided. This example function has a bug by purpose, in order to show an IF/THEN/ELSE characteristic. if level = 1, then the first clause will be executed (set dam = 0). Then the second condition will be executed and will be true too (elseif level == 1), then it will execute the second clause (set dam = 50). With that we can see that the IFTHENELSE structure can be used to make data filtering, for instance.


    Another Important Note
    The '=' character is used when setting a value, the '==' operator is used when comparing values. In other words, don't do: if x = 5 then... because Wc3 can't read your mind as to what you want it to really do. This line is saying to the computer "if (set x = 5) then..." and I don't think that makes much sense, how about you?


    Now let's see the LOOP structure.

    Loops in programming are used to make a set of instructions to be executed several times, loops can be classified by finite and infinite. The finite loops are which have a defined a fixed number of repetitive executions, controlled by an exit control. The Infinite loops in the other hand, will execute the script contained in it indefinitely.

    The loop structure is as following:

    Code (vJASS):

    loop
        //Here you can put code too :)
        exitwhen <condition function or variable>
        //your iterative script
    endloop
     


    This structure is quite flexible as you can see, because you can put the exitwhen condition in ANY place inside the loop. Let's see an example.

    Loop Example
    Code (vJASS):

    function Heal_Unit_Group takes group g returns nothing
        // this example will heal all units in a unit group.
        local unit u // a local unit variable
        loop
            set u = FirstOfGroup(g) //Selects the first unit in the group.
            exitwhen u == null // the loop will finish when the group will be empty,
            // in tother words, when the FirstOfGroup() function returns null
            call SetUnitState(u, UNIT_STATE_LIFE, GetUnitState(u, UNIT_STATE_MAX_LIFE))
            //sets the life of the selected unit at its maximum.
            call GroupRemoveUnit(g, u) // removes the unit from the group
        endloop
        call DestroyGroup(g) // to avoid group leaks, we must destroy the group variable.
    endfunction
     


    The usage of FirstOfGroup and group functions inside a loop is very common in AOE spells, with them we can do several things to a unit group.


    Some tips with loops


    Sometimes, we want to use the loops as a way to do a mass effect spell. If you want to add special effects inside a loop, there is a big chance the code will lag, in order to avoid that, you should use a TriggerSleepAction() function, which will give to the WC3 engine a small break to process other tasks.

    You can create an infinite and unstoppable loop using only the loop and endloop instructions without an exitwhen command.


    Exercise.


    Create a function which displays all the numbers which can divide perfectly a given number. The function should be in that way:
    Code (vJASS):

    function DivideNumbers takes integer n returns nothing
        // your code here
    endfunction
     


    For exaple, if we make
    Code (vJASS):
    DivideNumbers(12)
    we should see on the game screen something like this:

    1, 2, 3, 4, 6, 12


    Good luck :

    Lesson 5: Triggers in JASS
    Overview

    Now, if all you've ever known is GUI, you're used to everything being a trigger. GUI is just a system of triggers, but you're probably wondering what exactly is a trigger. This lesson will cover triggers in JASS and how to use them. First, I'd like to tell you exactly what a trigger is.

    What is a Trigger?

    I'm sure that you know what a trigger is if you've used GUI before, but GUI hides some important things from you. A trigger is really just another object, like a unit or a special effect. What makes triggers useful is that they are able to detect events. Without triggers, you couldn't do too much in the editor without a lot of trouble. Now, here's an example of making a trigger in JASS:\

    Code (vJASS):
    function InitTrig_JASSTrigger takes nothing returns nothing
     local trigger myTrigger = CreateTrigger()
        call TriggerRegisterPlayerEvent(myTrigger, Player(0), EVENT_PLAYER_END_CINEMATIC)
        call TriggerAddAction(myTrigger, function MyFunction)
     set myTrigger = null
    endfunction


    Now, this may be a bit overwhelming at first, but I'll explain everything well enough so that you should understand. First off, you're going to create a local variable for the trigger. This is fine if you don't need other triggers to run TriggerExecute on this trigger (TriggerExecute is a function that runs a trigger). Now, whenever you create a new trigger, you must use the function CreateTrigger(). It's like using the CreateUnit function to create a unit. Now that you have created a trigger, you'll need to add some things to it so it would be useful. The next line adds an event to the trigger. TriggerRegisterPlayerEvent takes 3 values, which are the trigger you want to add the event to, the player this event applies to, and the specific event. There are many other TriggerRegister... functions which you can experiment with later, but for now this will be fine. The next line adds an action which is basically telling the trigger to call that function when the event happens. Now, I didn't show you the function MyFunction, but you need to know that it must take nothing and return nothing. Now, the final line sets the local variable to null, which is necessary for local variables which are handles so that memory leaks can be prevented. If you don't know what a memory leak is, don't worry about it, they will be covered in a later tutorial.

    Okay, now you're probably still using that GUI trigger to run your test functions in the custom script. This JASS trigger does pretty much the exact same thing as the GUI trigger, so you can replace it. Just create a new trigger, and then go to Edit -> Convert to Custom Text. What you will see is something similar to the function shown above, only it's setting a global variable automatically generated by the editor to a trigger and just adding an action. Delete all the code and make a new function that has the name: InitTrig_[insert trigger name here]. So if the name of your trigger was JASSTrigger, you would have your function be: function InitTrig_JASSTrigger takes nothing returns nothing It's important that you name it this way so that it gets called while the map is loading.

    Now, if you've noticed, I've left out how to add a condition, oh my! Well, I'll show you how adding conditions work in triggers. Don't convert a GUI trigger to JASS to see how to do conditions, that way is inefficient. There's more code than you really need to use. Let me show you an example:

    Code (vJASS):
    function Condition_Function takes nothing returns boolean
     return GetTriggerPlayer() == Player(0)
    endfunction

    function InitTrig_JASSTrigger takes nothing returns nothing
     local trigger myTrigger = CreateTrigger()
        call TriggerRegisterPlayerEvent(myTrigger, Player(0), EVENT_PLAYER_END_CINEMATIC)
        call TriggerAddCondition(myTrigger, Condition(function Condition_Function))
        call TriggerAddAction(myTrigger, function MyFunction)
     set myTrigger = null
    endfunction


    This might look confusing, it might not. Either way I'm going to review what everything does. First off, I'll review how to set up a function so it can be used as a condition in a trigger. First off, you can name the function whatever you want, but it has to take nothing and return boolean. A boolean value, as you should know, is true/false. This function returns GetTriggerPlayer() == Player(0). You might look at that and be clueless, others might understand it already. The first part gets the player who triggered the event (the player pressing escape). And finally, the == Player(0) part checks if the player is Player(0) (Player 1 (Red)). Since this is a boolean statement, meaning it is either true or false, it can be used as a return value.

    Finally, we have the added line in the InitTrig_JASSTrigger function. The function TriggerAddCondition takes a trigger and a boolexpr (boolean expression) . You don't need to know what a boolexpr is yet, all you need to know is that you put Condition(function [insert trigger name here]) and it returns a boolexpr which is used for conditions in triggers.

    Challenge

    This challenge will require a bit of researching JASS functions, so I recommend you get a tool such as JassCraft. Well, I'll give you three possible challenges. The first challenge will to be to create a trigger in JASS that will run a function that you create (any). After you've messed with that a bit, open up JassCraft or a similar program where you can search JASS functions. You're next challenge will be to create a trigger that will go off whenever you type in "-run" or whatever kind of text message in-game. I'll give you some help in telling you that the function you're looking for to add the event is TriggerRegisterPlayerChatEvent, however it's up to you to figure out how to use it. If you've solved that challenge, then make a trigger that goes off when the message a player types contains the character "-" or whatever letter you choose. In the actions, you will then display the value the message the player typed in. Hints for this challenge are keep using the same function to add the event, only you need to change a value or two. And I suppose it would also be helpful to tell you that the GetEventPlayerChatString can be used to get the string that the player types in.

    Good Luck -wyrmlord

    Lesson 6: Memory Leaks
    Lesson 6: Memory Leaks
    By: Darkwulfv, edited by wyrmlord

    What is a memory leak?
    -A memory leak is caused by bad coding, where a handle that was stored in memory is lost from refrence. Basically, it’s something that got placed in wc3’s memory usage and never got removed, and is unable to be removed.

    What does a memory leak do?
    -A memory leak adds a little tiny bit of memory usage to Wc3 when it’s running. If enough memory leaks, your map is going to cause some serious lag.

    What causes memory leaks?
    -When a handle is created, it's stored it in Wc3’s memory. If it is not destroyed or removed when you are done with it, then it stays there, taking up memory.

    Well how am I supposed to fix them?
    -Well, there are a few ways to do so, depending.

    Method #1:
    =============================
    Code (vJASS):

    function MemoryLeak takes nothing returns nothing
      call AddSpecialEffect() //Creates a special effect
    endfunction
     

    =============================
    The native AddSpecialEffect(…) creates an effect. If you do not destroy this effect with the proper function, it will stay embedded in the memory, and thus take up memory. Now, one leak is terribly insignificant. But if your map made a lot of leaks very often, you would notice a big change.

    Here’s a way to fix that leak:

    Code (vJASS):
     function MemoryLeak takes nothing returns nothing
     local effect my_effect = AddSpecialEffect(...) //Create a special effect
       call DestroyEffect(my_effect) //Destroys the effect, removing it from memory
     set my_effect = null //You have to null local handles at the end of a function, or they leak too
    endfunction

    //Alternatively, this can be used

    function MemoryLeak2 takes nothing
       call DestroyEffect(AddSpecialEffect(...))
       //Adds a special effect and destroys it all at once. This will still show the animation once for most (not necessarily all) effects, and doesn't require the use of a variable
       //However, if you want to see the entire animation, you should wait for the duration of the effect's 'stand' animation
    endfunction
     


    This method goes for anytime you are using a handle(any variable that isn’t a real, integer, boolean, boolexpr, code, or string)
    However, the destroying/removing function changes for each type of handle. A list of variable types and how to remove them will be given later for you to refer to.

    NOTE: When destroying/removing an object, you are removing/destroying a specific object and not the variable itself. The variable just points to the location in memory where the object is stored.


    NOTE: A leak can be defined as an object that is created, not removed, unable to be removed during the game (assuming not removing it is undesired). If it’s only used once (like dummy units, rects, groups, etc.) then remove it. If not, you should leave it. (Like for spells, don’t remove the caster!)
    NOTE: All non-handle variables except strings do not leak. String leaks cannot be fixed, but you usually don't need to worry about them.

    So memory leaks only apply when you create things?
    -WRONG!
    A memory leak not only happens when you create things. It also happens when you make a handle-variable, set it to a value, and don’t null it.
    Example:
    Code (vJASS):

    function MemoryLeak takes nothing returns nothing
      local unit u
        //actions
    endfunction
     

    This example wouldn't leak, as the handle variable wasn't set to a value. However, if it had been set to a value, like:
    Code (vJASS):
    local unit u = GetTriggerUnit()
    It would leak. To fix this, set your variable to null. (Reals, integers, and booleans cannot be nulled, and don't need to be as the memory they use is automatically removed)
    To null a variable, simply put

    set yourvariable = null

    You don't need to set a variable to null after removing each object. You only need to null it once; this is usually done at the end of a function.
    Code (vJASS):
     function MemoryLeak takes nothing returns nothing
     local group g = CreateGroup()

    //Some code

     set g = null
    endfunction
     


    NOTE: To satisfy those wanting to know why handle variables leak (not referring to the object, I'm referring to the variable). When you set a handle equal to a value, the handle points to where that value is stored in memory. It will remain pointing to where that value is stored unless it is set to null (meaning 0, not pointing to a specific place in memory.)

    What about globals?
    -Since these are always in the memory to begin with, and are always available, they don't count as leaks (and don't need to be nulled).

    So uh… What do I do about non-handle variables?
    -They don’t leak though, so worry not.

    Conclusion:
    -Always clean leaks. If you don’t, and there’s enough leaks, you will notice the effects.

    Challenge!
    -Clean this function of all memory leaks:

    Code (vJASS):

    function ChallengeTrigger takes nothing returns nothing
      local unit u = GetTriggerUnit() //This unit is in the game, it needs to be kept (hint)
      local effect SFX = AddSpecialEffect()
      local group g = CreateGroup()
      local unit u2  //this is going to be a dummy unit and should be removed (hint)
      local real r = 4
        //actions
        //(hint) only one of these variables isn’t nulled.
    endfunction
     


    Good luck!
     

    Attached Files:

    Last edited: Oct 5, 2007
  2. wyrmlord

    wyrmlord

    Joined:
    Oct 13, 2005
    Messages:
    252
    Resources:
    5
    Tools:
    1
    Maps:
    1
    Tutorials:
    3
    Resources:
    5
    Update

    Lesson 7: Starting a Spell in JASS
    Overview

    Welcome to the next lesson. The basics have pretty much been covered, and now you'll probably want to use JASS to create spells or something. In this lesson, we'll go through the process of making a spell similar to the Omnislash spell found in DotA. (I've never actually seen the spell, but I know somewhat of how it works) This will show you some basic things used in JASS and room will be left for you to be able to modify the spell later on.

    Starting Off

    Before making a spell, you'll have to consider how it will work, what is happening step by step. First off, we need the trigger to go off when a unit casts a certain spell, right? And then we can begin thinking of the actions. In the spell I'm thinking off, the hero moves around in an area hitting a certain amount of units, but never the same unit twice. If you're looking at the spell being cast in-game, it might seem confusing, it might not. You have to break things down little by little. Here's some code for now that will start us off and I'll add to it as the lesson progresses:

    Code (vJASS):
    function Slash_Condition takes nothing returns boolean

        return GetSpellAbilityId() == 'A000' //Compares the ability id of the ability being cast to the ability id of our Slash spell.

    endfunction

    function Slash_Actions takes nothing returns nothing
    endfunction

    function InitTrig_Slash takes nothing returns nothing
     set gg_trg_Slash = CreateTrigger() //Set the global variable that is created for our trigger to a new trigger

        call TriggerRegisterAnyUnitEventBJ(gg_trg_Slash, EVENT_PLAYER_UNIT_SPELL_EFFECT) //This BJ function registers an event for whenever a unit starts the effect
                                                                                         //of an ability for our trigger

        call TriggerAddCondition(gg_trg_Slash, Condition(function Slash_Condition))
        call TriggerAddAction(gg_trg_Slash, function Slash_Actions)
    endfunction


    So far all we have is the basic trigger set up that will go off whenever the right ability is cast. You need to make sure you've created an ability (preferably based off channel with the values set correctly, if you need to know more about channel, please ask). Now we will create the actual effects of the spell. Now you'll need to think "what happens in the spell". Here's what happens: the hero is moved around within a certain area, he will only be moved to enemies, for each unit he is moved to, he will deal damage, and at the end he will return to the spot that he started at. The first thing to do now is to create a local variable to everything we'll need to keep track of. Here's what I thought of: a unit variable for the hero, a location for where the hero starts at, a group to hold all the enemies the hero will hit, and another unit variable to temporarily hold picked units in. You might not get the point of the last variable, but I'll show you how it's used soon. Here's what we should have now:

    Code (vJASS):
    function Slash_Actions takes nothing returns nothing

     local unit caster                       //Will hold our caster
     local location start_position        //Holds the starting position of the hero
     local group enemies                  //Will hold the unit group of enemies our hero will hit
     local unit temp                        //Used for when going through the group (explained later)

    endfunction


    Now, if you've used GUI before, you'll probably be wanting to do something like "Pick Every Unit in (group) and do actions", but there's a problem with that. In order to use that function (it's know as ForGroup in JASS), you'll need a separate function that you'll be unable to pass any values to. Now you could use global variables to transfer information, but then the spell wouldn't be able to be used by more than 1 unit at a time. You could possibly think of other ways around this, but they'd take more time than it would be worth. I'll give you a hint on how I do it, I use a loop. "Loop?" you might be thinking, "how can I use a loop?" because if you've used GUI before, the loops would run for a fixed length (for integer # through #, do actions), unlike in JASS where a loop will only end when a certain condition is met. And that condition will be that all enemies in the enemy group have been hit. Here's some more code to hopefully explain a little bit more of what I mean:

    Code (vJASS):
    function Slash_Actions takes nothing returns nothing

     local unit caster = GetSpellAbilityUnit()          //Create a local variable and set it to the unit that's casting the spell
     local location start_position = GetUnitLoc(caster) //Create the local and set it to the caster's position
     local group enemies = CreateGroup()                //When you create a group in JASS, it's like a trigger. First you need it empty, and then you add stuff to it
     local unit temp                                    //Used when looping through the group
     local integer count = 5                            //This will be the maximum amount of enemies that can be hit

        call GroupEnumUnitsInRangeOfLoc(enemies, start_position, 500.0, null)

    // GroupEnumUnitsInRangeOfLoc takes a group, a location, a radius, and a boolexpr (a condition, kind of) and then gets units within that radius and adds them to our group

        loop
            set temp = FirstOfGroup(enemies)    //FirstOfGroup returns a unit from a group in no particular order that I know of
            exitwhen temp == null or count == 0

                                                //The loop will stop when temp is null (meaning that there are no more units left in the group) or when we've hit 5 enemies

            call GroupRemoveUnit(enemies, temp) //Removes the unit from the group so that it can't be picked again
        endloop

                                                //Cleaning up memory leaks will be put here

    endfunction


    In this section of code, we've set up some more basic parts to our code. We've initialized the variables and then filled the group with units within 500 range of the caster. Next, we start a loop and for each cycle in the loop, the temporary unit variable will be set to a unit from the group. Then we'll tell the loop to exit when the group has no units left in it or the caster has hit 5 enemies (count would be decreased for each enemy hit). At the end of each loop, the unit being used will be removed from the group so that it can't be picked again (and so prevents an infinite loop as well). Then we end the code executed by the loop and end the function.
    The next step will now be to add in what the function will do for each unit picked. The first thing that you will have to notice is that the GroupEnumUnitsInRangeOfLoc grouped all units in 500 range of the hero's location, including allies and the hero. That means we'll have to add a simple condition to check whether or not the unit is an ally before performing additional actions. After that's done, what next? The unit will have to move to each enemy hit and damage them, right? Don't forget setting the count variable to count – 1 as well, or more enemies could be hit than desired. Before going on to the next bit of code, declare another location variable to hold the picked enemy's position, I'll go by the name of temp_loc. Here's what we'll have next for the loop:

    Code (vJASS):
    loop
        set temp = FirstOfGroup(enemies)
        exitwhen temp == null or count == 0
       
        if IsUnitEnemy(temp, GetOwningPlayer(caster)) then //If the enemy unit is an enemy of the owner of the caster

            set temp_loc = GetUnitLoc(temp)                //Set a temporary location variable to the enemy position
           
            call SetUnitPositionLoc(caster, temp_loc)      //Move our unit instantly to the enemy's location

            call UnitDamageTarget(caster, temp, 50, true, false, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_NORMAL, null)

                                                           //The caster will instantly damage the enemy for 50 damage with an attack type of chaos
                                                           //You can ignore the damage type, and the last parameter (weapontype) is just for sound, but we will
                                                           //have none for right now

            set count = count - 1                          //A unit has been hit, so now the units left to hit is reduced by 1

        endif

        call GroupRemoveUnit(enemies, temp)
    endloop


    Okay, this loop will now allow our unit to move to every unit within range and damage them. You might think we're done, right? Our hero will move to each unit in range and damage them, but you now have to ask yourself if we're missing anything. Are we?

    Challenge

    I bet you've already guessed the challenge, finish the spell! Don't worry about special effects (unless you want to), you just need to finish up on the basics that will happen and clean memory leaks. In the next lesson, the spell will be finished up and enhanced with special effects and more! Don't hesitate to post code on the forums if you're having trouble.

    Good Luck! -wyrmlord

    Lesson 8: Continuing the Spell

    Overview

    First off, I'd like to say sorry for taking so long, but here's finally the next tutorial in the series. In this tutorial, we'll continue off the spell from last time. Just to refresh your minds (in case you haven't looked at these tutorials in awhile like me) we were working on a slash spell where the hero would blink throughout an area and damage enemy units. He would hit up to a specified number of units, or until he had hit every nearby unit. Now to add the finishing touches, first we will rid the spell of memory leaks and add some special effects to make the spell more appealing. After that, we will work on ways to improve the spell further. To improve the spell further, we will look into timers and gamecache usage. However, this lesson will only cover the effects portion as I think you've waited long enough with no response from me and I also want to prevent the lesson from being too large.

    Starting Off

    Make sure you have the spell being worked on from last time. I'll post the code so you can take a look at it if you've misplaced the code from last time:

    Code (vJASS):
    function Slash_Condition takes nothing returns boolean
        return GetSpellAbilityId() == 'A000'
    endfunction

    function Slash_Actions takes nothing returns nothing
     local unit caster = GetSpellAbilityUnit()
     local location start_position = GetUnitLoc(caster)
     local group enemies = CreateGroup()
     local unit temp
     local integer count = 5
        call GroupEnumUnitsInRangeOfLoc(enemies, start_position, 500.0, null)
        loop
            set temp = FirstOfGroup(enemies)
            exitwhen temp == null or count == 0
            if IsUnitEnemy(temp, GetOwningPlayer(caster)) then
                set temp_loc = GetUnitLoc(temp)
                call SetUnitPositionLoc(caster, temp_loc)
                call UnitDamageTarget(caster, temp, 50, true, false, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_NORMAL, null)
                set count = count - 1
            endif
            call GroupRemoveUnit(enemies, temp)
        endloop
    endfunction
    function InitTrig_Slash takes nothing returns nothing
     set gg_trg_Slash = CreateTrigger()
        call TriggerRegisterAnyUnitEventBJ(gg_trg_Slash, EVENT_PLAYER_UNIT_SPELL_EFFECT)
        call TriggerAddCondition(gg_trg_Slash, Condition(function Slash_Condition))
        call TriggerAddAction(gg_trg_Slash, function Slash_Actions)
    endfunction



    I haven't commented the code because there's nothing new, and you should already know what it all does from last time. When making a spell, I always like to first get it working and then fine-tune it afterwards. It should already be working, but it still has errors in it because of memory leaks. I expected you to be able to fix these up yourself, but if you need to double-check your answers, here's what I would have done:

    Code (vJASS):
            set count = count – 1
            call RemoveLocation(temp_loc)   // This line has been added
            endif
            call GroupRemoveUnit(enemies, temp)
        endloop

        // Everything below has been added

        call RemoveLocation(start_position)
        call DestroyGroup(enemies)
    set caster = null
    set start_position = null
    set enemies = null
    set temp = null



    Now, if you thought the only errors were memory leaks, you've overlooked something else that needs to be changed with the code. The start_position variable is never used! We needed to return the hero to the location where the spell started being cast. I won't post the code for this, because I'm assuming you should know 100% how to do this. Just remember that you can't move the hero to a location that's been removed, and that the function you're looking for is already used for something else in the code.

    Effects

    This now brings us to the next point, making the spell more interesting. A spell where the hero just moves around an area looks rather boring don't you think? Also, you need to take into consideration how the hero moves from point to point and portray that with special effects of some sort. Since the hero is "blinking" we will use the blink model for a special effect. The model path for the blink model happens to be: Abilities\Spells\NightElf\Blink\BlinkTarget.mdl. I got this path from using the object editor. First, I found a random ability (doesn't matter) and then went to the Art – Special Field. After that, I added a new model that was the blink effect. After adding the model, I went to Edit Model and looked at the bottom text area next to the word "Custom:". The path for the model I had just picked was there.

    Now, we will go over adding an effect. The function we will be using to create an effect is the "AddSpecialEffectLoc" function. Here's the function declaration for it:

    Code (vJASS):
    native AddSpecialEffectLoc takes string modelName, location where returns effect



    This function is pretty strait-forward. You simply give it the path to the model you want to use and the location the effect is to be created at. However, there is one detail I need to go over about the model path. The above path I showed you needs a few minor modifications in order to be used properly. Here's how we would go about calling this function:

    Code (vJASS):
    set blinkEffect = AddSpecialEffectLoc("Abilities\\Spells\\NightElf\Blink\\BlinkTarget.mdl", effectLoc)



    Notice how I replaced each "\" in the model path to "\\". This is required in JASS to properly represent the "\" character because the "\" character has other uses that I will not go into. Also, noticed how I set the effect to a variable. A very common mistake is creating the effect, not setting it to a variable, and then trying to use the GetLastCreatedEffectBJ function to refer to the effect. This function only works with the function AddSpecialEffectLocBJ which I do not ever recommend using as it has no point other than for allowing a "Get Last Created Effect" action in GUI. Since we are using JASS, we can ignore this function and use the native.

    Challenge

    Okay, so now we know how to add a special effect, but now we need to take advantage of this newly learned function and add it into our spell. First, we'll need to decide when and where we want the effect to be placed. I think now will be an appropriate time for a challenge. Your challenge will be to add special effects to the spell as you find appropriate. Feel free to experiment with various models and where you place them in the code. Now, I thought I'd give you one last tip before sending you on your way. Effects, like all other handles, leak. Even though the model of the effect may disappear after a few seconds, you'll still need to remove the effect. There are various ways to do so and I'll go over them now.
    First, and most obvious, you create the effect and set it to a variable. Later in the function, you call the DestroyEffect function on the effect to destroy the model and get rid of the memory the model was using. Here's an example of that:

    Code (vJASS):
    local effect specialEffect = AddSpecialEffectLoc("model\\path", someLocation)
    // Clean up
    call DestroyEffect(specialEffect)
    set specialEffect = null



    This creates an effect and sets it to the local variable specialEffect. Later in the function, it is destroyed with the DestroyEffect function and set to null. Another thing that should be noted about special effects is that until it's destroyed, an effect will play its "stand" animation if it has one. When you destroy an effect, it plays its "death" animation if it has one. Here's where the second method comes into play. Some functions only have a single animation, or perhaps you only want to play an effect's death animation. You can both create and destroy an effect on the same line. Most effects will play either their death animation or sometimes their regular animation the whole way through before being removed. However, this may not work on all effects so be sure to test it out. Here's basically how the code would look to demonstrate this:

    Code (vJASS):
    call DestroyEffect( AddSpecialEffectLoc("model\\path", someLocation) )



    Once again, some models may respond differently than expected with this function so make sure to look things over when using this method. This method is nice due to squeezing many things onto a single line. No other variable for the effect is needed and no memory leak is created from the effect. However, remember that you need to remove the location used in this function as it is not cleaned like the effect is.

    Now, I think this is sufficient information for you to add special effects to the spell. Go ahead and give it a shot, the next tutorial will contain how I added the effects. If you have trouble with adding the effects, make sure to ask as questions help you learn.

    Good Luck - wyrmlord



    This tutorial is still in progress and I would greatly appreciate suggestions.
     
    Last edited: Oct 5, 2007
  3. Wolverabid

    Wolverabid

    Joined:
    Oct 23, 2006
    Messages:
    8,303
    Resources:
    5
    Tutorials:
    5
    Resources:
    5
    IMPORTANT:

    • Posts in this thread should relate only to the tutorials themselves.

     
    Last edited: Apr 30, 2007
  4. Deep Sea Kraken

    Deep Sea Kraken

    Joined:
    Dec 29, 2006
    Messages:
    1,009
    Resources:
    6
    Models:
    6
    Resources:
    6
    Hmm, I have a suggestion: I completely SUCK at reading tutorials, so maybe you could put the tutorial into a downloadable map and create comments on what each function does; for me this would help alot, and im probably not the only person out there (looking at everything like they do in tutorials rly confuses me) i got JASS craft, but i have to have something (or someone) explaining what it does and how it work, and these tutorials just dont do that for me. Sorry if I'm bugging you or being over pretentious (whatever that means ^.^), but you did ask for suggestions, so this is mine.

    Although i do probably have a slight edge over other people; i write codes in a program called: Ready to Program, which uses Java language, and its pretty close to this, but far less complex
     
  5. wyrmlord

    wyrmlord

    Joined:
    Oct 13, 2005
    Messages:
    252
    Resources:
    5
    Tools:
    1
    Maps:
    1
    Tutorials:
    3
    Resources:
    5
    For some reason, I am unable to upload files to this topic. The tutorials should pretty much be self-explanatory, but not everyone learns everything the same way. You'll probably have to stick with copying and pasting the code into a map (there's instructions for running JASS code) and later in the tutorial it goes into triggers in JASS so you'll lose the need for GUI. You should easily be able to put code into a map and just run it. As for commenting, I pretty heavily commented the source code for anything above self-explanatory things (and even some simple things as well).

    EDIT: It seems the site allows me to upload files now, but creating a map showing this stuff off wouldn't really take much, so you should be able to do it as I said before.
     
  6. Deep Sea Kraken

    Deep Sea Kraken

    Joined:
    Dec 29, 2006
    Messages:
    1,009
    Resources:
    6
    Models:
    6
    Resources:
    6
    I still cant figure out how to make it create a specific unit.

    How do you find out what the JASS term for each unit is (footman is: 'hf00') how would you find that for custom units? or would you just have to create it in GuI then convert the trigger?
     
  7. wyrmlord

    wyrmlord

    Joined:
    Oct 13, 2005
    Messages:
    252
    Resources:
    5
    Tools:
    1
    Maps:
    1
    Tutorials:
    3
    Resources:
    5
    While the object editor is open, press ctrl+d. That will show the rawcodes for all objects.
     
  8. Deep Sea Kraken

    Deep Sea Kraken

    Joined:
    Dec 29, 2006
    Messages:
    1,009
    Resources:
    6
    Models:
    6
    Resources:
    6
    Ah, thank you, also you used this code: local location start_position = GetUnitLoc(caster) to get the postiton of the casting unit whould you do:
    local location start_position = GetUnitLoc(attacker) if you want it to be the position of an attacking unit?
     
  9. wyrmlord

    wyrmlord

    Joined:
    Oct 13, 2005
    Messages:
    252
    Resources:
    5
    Tools:
    1
    Maps:
    1
    Tutorials:
    3
    Resources:
    5
    Find the function that returns the attacking unit. Get a program such as JassCraft or open up common.j and search for it. I'm not going to do all the work for you.:wink: By the way, I'd like this thread to only be about the tutorials; if you have trouble go ask in the Jass Forum.
     
  10. PurgeandFire

    PurgeandFire

    Code Moderator

    Joined:
    Nov 11, 2006
    Messages:
    7,420
    Resources:
    18
    Icons:
    1
    Spells:
    4
    Tutorials:
    9
    JASS:
    4
    Resources:
    18
    This is a great and descriptive tutorial. I hope more is to be added, or is it finished? Either way, it is an outstanding tutorial (IMO), +rep... Thanx :emote_grin:
     
  11. wyrmlord

    wyrmlord

    Joined:
    Oct 13, 2005
    Messages:
    252
    Resources:
    5
    Tools:
    1
    Maps:
    1
    Tutorials:
    3
    Resources:
    5
    More will be added, as I'm currently working on the next tutorial. I would probably have it finished by now, but I've had a lot of homework this week.
     
  12. Armentia

    Armentia

    Joined:
    May 21, 2007
    Messages:
    14
    Resources:
    0
    Resources:
    0
    One suggestion, which may or may not be avoidable. Fix the scrolling requirement. -.- When 'powerreading' tutorials as I do, I lose concentration when having to horizontally scroll for every line of text. I'm only guessing that this is do to the long comments in your code boxes. Maybe edit these and turn some of the longer ones into multiple lines. Thanks -Arm
     
  13. HermanTheGibbon

    HermanTheGibbon

    Joined:
    May 27, 2007
    Messages:
    174
    Resources:
    1
    Tutorials:
    1
    Resources:
    1
    This a "most outstounding" tutorial Rufus! It's awesome for people like me who know precisely nil about technical computery witchcraft, it's thorough and in layman's terms, which is what a tutorial should be. All the other JASS tutorials I tried to read were obviously made by computer boffins/nerds (lol) who usually just outline a bit of code and expect all the 'begginers' who the tutorial is aimed at to know how to fill it in and what everything means. This is not the case here however, all the jazzy jassy terms explained nicely, most excellent tutorial dudes! +rep WHOOT!
     
  14. PurgeandFire

    PurgeandFire

    Code Moderator

    Joined:
    Nov 11, 2006
    Messages:
    7,420
    Resources:
    18
    Icons:
    1
    Spells:
    4
    Tutorials:
    9
    JASS:
    4
    Resources:
    18
    >wyrmlord:
    Code (vJASS):
    local unit caster = GetSpellAbilityUnit()


    It is good to say that GetTriggerUnit() proves to be more efficient:
    Code (vJASS):
    local unit caster = GetSpellTargetUnit()


    > When a function has the text 'takes nothing', that means you don't need anything in the parenthesis when calling it.

    I think you could put something like this:

    --=======--------------------------=======--

    When a function has the text 'takes nothing', that means that there is no variables to substitute parameters of a call.

    The format is like so:
    Code (vJASS):
    function JASS takes var Vname returns nothing


    To have multiple parameters to what the function takes, you seperate them with commas:
    Code (vJASS):
    function JASS takes var1 Vname1, var 2 Vname2 returns nothing


    An example of a function with parameters would be this:
    Code (vJASS):
    function Killunit takes unit whichUnit returns nothing
        call KillUnit(whichUnit)
    endfunction


    Parameters from functions can also be used to create your own functions:
    Code (vJASS):
    function Killunit takes unit whichUnit returns nothing
        call KillUnit(whichUnit)
    endfunction

    function test takes nothing returns nothing
        call Killunit(GetTriggerUnit)
    endfunction


    --=======--------------------------=======--

    I may reply more, but that's it for now. :smile:
     
  15. wyrmlord

    wyrmlord

    Joined:
    Oct 13, 2005
    Messages:
    252
    Resources:
    5
    Tools:
    1
    Maps:
    1
    Tutorials:
    3
    Resources:
    5
    The use of GetSpellAbilityUnit() is just for clarity. Thanks for your second suggestion, though unless I'm mistaken the tutorial already covers that.
     
  16. hot lips

    hot lips

    Joined:
    Apr 28, 2007
    Messages:
    25
    Resources:
    0
    Resources:
    0
    WOW to hard way to hard i like the trigger editer better.
     
  17. cosmicat

    cosmicat

    Joined:
    Nov 26, 2006
    Messages:
    60
    Resources:
    0
    Resources:
    0
    Well you did say we could ask... What's so special about Channel?
     
  18. PurgeandFire

    PurgeandFire

    Code Moderator

    Joined:
    Nov 11, 2006
    Messages:
    7,420
    Resources:
    18
    Icons:
    1
    Spells:
    4
    Tutorials:
    9
    JASS:
    4
    Resources:
    18
    Yea, it does, but I was just saying that it may be better to explain it a bit better, and I provided an example.

    Well, it takes a while to learn JASS and it will benefit you in map making. Though many people do prefer GUI...

    Channel is a "special" ability because channel has more fields than what a regular spell has.

    Channel is one of the only few abilities that allow you to change the Base Order ID which is extremely useful if you want to quickly change an ability's ID. Channel also allows you to set whether or not it is visible, it's target types, and more. It is like the perfect ability to create a spell on due to it's features. Just simply remove the fields and add some, then trigger the rest. :thumbs_up:
     
  19. Mr.Jamaka2

    Mr.Jamaka2

    Joined:
    Mar 21, 2007
    Messages:
    90
    Resources:
    0
    Resources:
    0
    now what about attaching stuff to models how do i do that in JASS?:confused:
     
  20. Fulla

    Fulla

    Joined:
    Aug 3, 2005
    Messages:
    757
    Resources:
    2
    Tutorials:
    2
    Resources:
    2
    Code (vJASS):

    call AddSpecialEffectTarget()
     


    example:
    Code (vJASS):

    call AddSpecialEffectTarget(effect,GetTriggerUnit(),"chest")