JASS - Creating a Passive Ability in Jass

Tutorial By Romek

Creating a Passive Ability in Jass
By Romek

Welcome to my second tutorial. Today, you'll be learning how to make a simple passive spell in vJass. Specifically, we'll be making a spell which gives a chance to possess (Give the attacker permanent control over the target) the target.

As well as this, you'll learn how to make spells easily configurable, use scopes, and other Jass skills.

When creating passive spells with triggers, the actual spell will have to do nothing, and the chances will have to be triggered.

Creating the Spell:
Well, you obviously need a map and a spell. So open NewGen, make a new map, and go to the object editor.
Now you should note that when making passive abilities with triggers, the actual ability should have no effects whatsoever. It should just be a dummy spell which is used to check if the attacker has the spell.

I'll base my ability off of "Bash" (Human, Hero Ability)
I set the spell so that it has no chance to do no damage. And I removed the buffs. I also changed the tooltips and the icons :)

My spells Raw Code is 'Pwnt'. Yours will probably be different.
To check the raw code, go to the object editor and press CTRL + D. Everything will then be displayed in the Raw Codes.

Creating the Trigger:
Right. We have the spell, now all we need to do is make the triggers, the Hero, and the weaklings which will be possessed.

Open up the trigger editor (F4) and Create a new Trigger (CTRL + T).
Name the trigger whatever you want. It really doesn't matter.
Then go to Edit > Convert to Custom Text so that we can use Jass instead of GUI :).
Now delete everything that appears in the text box. It's rubbish.

Creating the Initializer and the Condition:
Now that we have a blank Jass trigger, we need to start the actual triggering.
We'll begin with creating a scope by using the syntax:

Scopes allow the use of Public and Private functions (Which prevent the functions being accessed from any other trigger). The Initializer is the name of the function which will be ran at Map Initialization.
Now, if our initializer is called "Init" we'll obviously need a function called Init. So lets create that now. We'll also create a local trigger to detect when a unit is attacked.

For this tutorial, my scope will be called "Possession"

Next, we'll register the events using Player Events. To do this, create a local integer and loop through it until you stop at 16 (All Players, including Neutral). Then register the event for the Player you're currently looping for.

There! We now have a trigger with the events registered... But wait. We have a problem. When using "null" as an argument for a boolexpr, we get a leak. (For some weird reason). So we'll have to create a boolexpr to take care of that leak.
Make a new, private function called "True" that takes nothing, and returns true.

Now, use the function as an argument instead of null
Your complete trigger should now look like this:

We're nearly finished with the preparations. We just need a condition and an action for our new trigger.

We'll start off with the condition. Create a new function called "Con" which takes nothing and returns a boolean. In this function, we'll be checking if the attacked unit is an ally of the attacker, as well as making the spell random.

We'll start off with checking if the owners of the attacker and the target are enemies. To do this, we'll use a function called "IsPlayerEnemy". This function takes 2 arguments, both of which are players, and returns true if they are enemies. Another function we will use is "GetUnitOwner" which returns the owner of the unit given to the function.
So to check if the Owner of the Target and the Owner of the Attacker are enemies, we need to do:

Now we need to make sure that the spell is random. At the moment, we'll add a 2% chance of the spell happening.
To do this, we'll get a random integer between 0 and 100, and check if it is less than or equal to 2.
For this, we will use the function call:

Now we will return the value of both of these functions. As we will need both of these to be true (Enemy, and Random), we will use the and keyword so that it will return true only if both of the conditions are true.

Our condition should now look like this:

After that, we'll need to check if the target is a Hero or not. We don't want to possess heroes do we? :P
To do this, we use:

Finally, we'll need to make sure the attacking unit has the ability, or every unit would be possessing units with no end :p

To do this we use:

Your final conditions should look like this:

Now, we need to add the conditions to the trigger. To do this, we use the function

Making the Actions:
Time for the actions. This is where all the effects of the spell will happen.
In this function, we'll change the owner of the target, and create a special effect on it.

Create a new, private function called Possession which takes and returns nothing. In this function, create 2 local unit variables: t and u (For Target, and Attacker)

These will make it easier to use these units later on in the trigger without having to keep calling the same functions.

Next, we'll create an effect on the target to show the players that it's been possessed. I'll use the model "Abilities\Spells\Items\AIvi\AIviTarget.mdl" because it looks cool for something like this :p

As we won't be needing the effect except for showing it once, we'll have to destroy it instantly. We can do this in 1 line by using

So I'll add my effect to the "chest" of the target.

Next, we're going to change the owner of the target.
To achieve this, we'll use the function called "SetUnitOwner"
We'll need to change the owner of t (target unit) to the Owner of u (Attacker) and change the colour of the unit.
For this, we'll use:

Now we'll need to null the 2 unit variables to prevent them from leaking.

Finally, we'll need to add the actions to the trigger.
For this, we use the function:

Your code should now look like this:

Creating the Configurables:
Now, although you have a fully working spell, it still isn't up to a good standard. It has a 2% chance of happening no matter what happens, and it'll be very difficult for newbies to change the effect created when the conditions are met.

We'll start off by creating another global block above everything except the first scope keyword. This global block will be used for the configurables.
In this block, create 2 private, constant strings. One for the effect, and one for the place it's attached to.

As these are constants, they have to be initialized (Have a value assigned to them immediately) So we'll assign them to what they are in the code, and replace the strings in the code with the variable names.

Your entire code should now look like this:

Secondly, we'll create a private, constant function which returns the chances of the unit being possessed based on the level of the ability.
This will also go at the top of the script for the user to change as they like :)
I'll make it so that for every level of the spell, a 1% chance is added.

We'll also have to change the Con function so that it checks the chance based on this function.

Thirdly, what if the person using the spell made the Raw Code 'A000'. Then it could become difficult for them to configure the spell. So we create another constant integer called ID, which is the Raw Code of the spell. We'll also change the code so that it uses the constant.
Your code should now look like this:

Finishing Off:
Finally, we'll just need to add some comments to the code, and make a neat test map.

So, make a nice map header and place it above Everything (Or below the scope keyword if you want) and give a brief description of the spell, say who made it, and write how to import it.

And then add some short, simple comments around the constants to explain what should be changed.

Your final code should look something like this:

Congratulations! You have just created a passive spell in vJass :D

Note: The DeathKnight in the Demo Map has superfast attack speed and low damage, so it's easier to notice the spells effect :)

Click here to comment on this tutorial.
Blizzard Entertainment, Inc.
Silkroad Online Forums
Team Griffonrawl Trains Muay Thai and MMA fighters in Ohio.
Apex Steel Pipe - Buys and sells Steel Pipe.