Spells - Making a DotA like Omnislash

Tutorial By Tinki3

Making a DotA like Omnislash

What is Omnislash?

Omnislash is defined as "All-slash", an ability/move/special attack based on the original from Final Fantasy VII on Playstation One.
All-slash is defined as blinking around multiple enemy targets, dealing damage to each.
During each blink, the caster will have a special effect created somewhere on their body to make the spell look more convincing, or to make it look like they are moving extremely quickly. They will have their 'attack' animation played also to look convincing.
The Omnislasher becomes invulnerable during the ordeal, and is then made vulnerable after they finish slashing.

Introduction

I have made this tutorial for people who wanted an ability like Omnislash in their maps because it's one of the coolest spells in DotA. So, have you ever wondered how the heck DotA's Omnislash works? Well, here you can read how to make your own that is similar to DotA's to put in your map, or to use just for fun. Please note that if you want to succeed in making this spell, you need to have some skill with using GUI and knowing how to use variables (A good variable tutorial is located here). Without a decent amount of knowledge, you will waste your time reading this Tutorial. The Omnislash we are going to learn to make is going to be very similar to DotA's one. It will be easy, if you follow the steps one by one, and read most things that need to be read.

Contents:

1. Starting off
2. The first part of the trigger
3. The spell's basic mechanics
4. Creating an advanced loop for Omnislash - Part 1
5. Creating an advanced loop for Omnislash - Part 2
6. The final trigger

------------------------------------------------------------

1: Starting off

First of all, to get going, we need to base our spell of some ability.
I am going to use Storm Bolt in this case, as its a good, easy-to-modify, targetable spell, which is what we need.

Open the Object Editor, create a new spell, basing it off Storm Bolt, then rename it to 'Omnislash' and make it stun for 0.01 seconds at all levels (0.00 seconds will result in a permanent stun), as no stun is needed for Omnislash. Also, make it deal no damage at all at any level and delete the missile art.

After you have done all of that, add the ability to the Orc Blademaster, or some unit with a large sword.

------------------------------------------------------------

2: The first part of the trigger

Our next step is to start the triggering for the spell:

Create a new trigger and call it Omnislash. Then, add in the classic event - 'A unit Starts the effect of an ability' and the Ability comparison condition as shown below:
Omnislash Events Unit - A unit Starts the effect of an ability Conditions (Ability being cast) Equal to Omnislash Actions
We use the function 'A unit Starts the effect of an ability' simply because it is the best option to use when making a triggered spell like we are. This is because it can't be abused like 'Begins casting an ability'. And why, you ask? Well, with 'Begins', you can quickly order your caster to stop casting the spell, leaving mana and cooldown unaffected, but you'll still get the effect from the trigger! 'Starts the effect' runs the trigger after mana and cooldown have started. The condition we used lets the trigger know that we only want it to fire if the casted ability is equal to Omnislash, otherwise it could fire off Animate Dead or War Stomp, which isn't obviously neccessary.

We now need to set a number of variables.
'o' stands for Omnislasher,
't' stands for target,
'tl' stands for target location:
Actions Set o = (Triggering unit) Set t = (Target unit of ability being cast) Set tl = (Position of t)
You might be wondering why I havn't used "Casting unit" as to "Triggering unit".
Well, to be honest with you, casting unit returns triggering unit, leaving triggering unit the faster, more efficient option.
Casting unit is just a general reference in this case, and should be avoided.

Next, we need to set the amount of loops/times the caster will be blinking, which we will be needing later on in the trigger, which is very important, using the 'If/then/else' function. I will explain what we will be using the loops for later on, but for now, you need to create an integer variable. Name it 'loops', or something that'll make it easy to reference. After you've done that, set loops into a few variables as shown:
(Notice that we are using values 1 less per lvl than DotA's Omnislash's loop times.
This is because 1 loop is deducted due to the caster blinking to the targeted target initally)
If ((Level of Omnislash for o) Equal to 1) then do (Set loops = 2) else do (Do nothing) If ((Level of Omnislash for o) Equal to 2) then do (Set loops = 4) else do (Do nothing) If ((Level of Omnislash for o) Equal to 3) then do (Set loops = 7) else do (Do nothing)

You should have all of the following so far:
Omnislash Events Unit - A unit Starts the effect of an ability Conditions (Ability being cast) Equal to Omnislash Actions Set o = (Triggering unit) Set t = (Target unit of ability being cast) Set tl = (Position of t) If ((Level of Omnislash for o) Equal to 1) then do (Set loops = 2) else do (Do nothing) If ((Level of Omnislash for o) Equal to 2) then do (Set loops = 4) else do (Do nothing) If ((Level of Omnislash for o) Equal to 3) then do (Set loops = 7) else do (Do nothing)
What we have done has basically initialized the Omnislash trigger. If there is anything you don't understand so far, I suggest reading the tutorial through to this point again.

------------------------------------------------------------

3: The spell's basic mechanics

After initializing our trigger for Omnislash, we need to know how Omnislash actually works, or, in other words, what mechanics it uses to do what it does.

First of all, DotA's Omnislash does NOT pause the caster (pausing basically makes a unit disabled). This is becuase it makes the entire spell run a whole lot better, as the caster is free to physically attack the target sometimes, thus if he has a critical strike ability, he has a chance to fire that which makes the spell actually look alot cooler, and improves it somewhat for us. So, instead of pausing the caster so he can't be controlled whilst he is Omnislashing, it uses a simple function called 'de-selecting' to remove the caster from selection for the owner of the caster so that he can't be moved AS easily. But, it still shouldn't be a problem, becuase, later on, we will be removing the caster, 'o' from selection every 0.3 seconds of game time, which will prove to be an interval too short to control a unit properly with.

When the caster 'attacks' his targets, he is instantly moved to their current location (as all DotA players would've seen), he then has his 'attack' animation played with SFX (Special effects) created on his chest for a bit of eye candy (note that he is also made 50% transparent when the spell is first casted). He is also made invulnerable so he can't be interupted by an enemy unit attacking him, either with physical damage, or a spell.

As for the damage that Omnislash does, the caster actually deals a random real number between 150 & 250 damage to the target. This makes the damage more random, and is what's used in DotA's Omnislash's trigger's damage, so since we're making a DotA-like Omnislash, why not do the same?

Let's start creating the part of Omnislash where the caster is made invulerable, is moved instantly to the target location (tl), plays his attack animation, creates SFX, and deals damage (note that he is also removed from selection when he first moves to the 'tl').

Let's add all of this into our trigger:
Unit - Make o Invulnerable
(Makes 'o' invulnerable for reasons I mentioned above)
Animation - Change o's vertex coloring to (100.00%, 100.00%, 100.00%) with 50.00% transparency (Changes o's transparency for the eye candy)
Selection - Remove o from selection
(Removes o from selection so it's harder to control him)
Unit - Move o instantly to tl (Moves o instantly to tl for the attacking part)
Custom script: call RemoveLocation(udg_tl)(Removes the location 'tl' to avoid a memory leak)
Animation - Play o's attack animation
(Play's o's attack animation to make it look like he's doing physical damage)
Unit - Cause o to damage t, dealing (Random real number between 150.00 and 250.00) damage of attack type Hero and damage type Normal
(Deals the random damage to t)
Special Effect - Create a special effect attached to the chest of o using Abilities\Spells\NightElf\Blink\BlinkCaster.mdl
(Creates eye candy on o's chest)
Special Effect - Destroy (Last created special effect)(Destroys our eye candy, avoiding another memory leak)

All of this should've been completed so far:
Omnislash Events Unit - A unit Starts the effect of an ability Conditions (Ability being cast) Equal to Omnislash Actions Set o = (Triggering unit) Set t = (Target unit of ability being cast) Set tl = (Position of t) If ((Level of Omnislash for o) Equal to 1) then do (Set loops = 2) else do (Do nothing) If ((Level of Omnislash for o) Equal to 2) then do (Set loops = 4) else do (Do nothing) If ((Level of Omnislash for o) Equal to 3) then do (Set loops = 7) else do (Do nothing) Unit - Make o Invulnerable Animation - Change o's vertex coloring to (100.00%, 100.00%, 100.00%) with 50.00% transparency Selection - Remove o from selection Unit - Move o instantly to tl Custom script: call RemoveLocation(udg_tl) Animation - Play o's attack animation Unit - Cause o to damage t, dealing (Random real number between 150.00 and 250.00) damage of attack type Hero and damage type Normal Special Effect - Create a special effect attached to the chest of o using Abilities\Spells\NightElf\Blink\BlinkCaster.mdl Special Effect - Destroy (Last created special effect)
Please read over this chapter again (3) to fully understand the mechanics of Omnislash.

------------------------------------------------------------

4: Creating an advanced loop for Omnislash - Part 1

In order to make the caster blink around random targets over & over, we need to make a long and advanced loop that will make sure our caster actually does blink around to random targets, and to tell the trigger to stop temporarially Omnislashing or not. It will take a fair amount of time to complete this loop, but, once its done, our Omnislash trigger will be more or less 99% complete.

To create a loop, we will be using the function, For Each Integer A, Do Multiple Actions.

Select this function from the actions list (located near the top), and add it to the very bottom of your trigger. Then you need to change it around by doing this (note that loops is the variable we set earlier):
For each (Integer A) from 1 to loops, do (Actions) Loop - Actions
Note that 'loops' was originally 10; just click on 10 when you are creating the function, and select the variable loops from the list.

Next, we need to add in a wait of 0.30 game-time seconds. This will give us a good delay between each attack made to targets.
Note that 0.27 seconds is the minimal amount of delay a wait can have, so 0.3 seems to be the nicest value to use here.
Add that into the Loop-Actions:
For each (Integer A) from 1 to loops, do (Actions) Loop - Actions Wait 0.30 game-time seconds
After you've done that, we need to calculate the caster's (o's) current location (I will explain why soon). Create a new point variable and call it o_current_loc. Set the variable into the trigger, directly below our 0.3 second wait, using "Position of unit" to
select 'o' from the variable list.

You should have done all of the following so far:
Omnislash Events Unit - A unit Starts the effect of an ability Conditions (Ability being cast) Equal to Omnislash Actions Set o = (Triggering unit) Set t = (Target unit of ability being cast) Set tl = (Position of t) If ((Level of Omnislash for o) Equal to 1) then do (Set loops = 2) else do (Do nothing) If ((Level of Omnislash for o) Equal to 2) then do (Set loops = 4) else do (Do nothing) If ((Level of Omnislash for o) Equal to 3) then do (Set loops = 7) else do (Do nothing) Unit - Make o Invulnerable Animation - Change o's vertex coloring to (100.00%, 100.00%, 100.00%) with 50.00% transparency Selection - Remove o from selection Unit - Move o instantly to tl Custom script: call RemoveLocation(udg_tl) Animation - Play o's attack animation Unit - Cause o to damage t, dealing (Random real number between 150.00 and 250.00) damage of attack type Hero and damage type Normal Special Effect - Create a special effect attached to the chest of o using Abilities\Spells\NightElf\Blink\BlinkCaster.mdl Special Effect - Destroy (Last created special effect) For each (Integer A) from 1 to loops, do (Actions) Loop - Actions Wait 0.30 game-time seconds Set o_current_loc = (Position of o)

After setting our point variable, o_current_loc, we are going to need to use it to calculate how many units are within 600 (the AoE of the spell) of that point. Yes, that's right, we are going to need to create a new Unit Group variable to make it so 'o' can blink to the picked units of that group, and do the usual Omnislash mechanics we discussed in chapter 3.

Open up the variable editor and create a new 'Unit Group' variable, with an array size of 1, and change it's name to 'EG' (Enemy Group, for short).

Set the first EG variable (EG[1]) into your trigger below the 'o_current_loc', like so:
Set EG[1] = (Units within 600.00 of o_current_loc matching ((((Matching unit) is A structure) Not equal to True) and ((((Matching unit) is alive) Equal to True) and ((((Matching unit) belongs to an enemy of (Owner of o)) Equal to True) and ((((Matching unit) is A flying unit) Not equal to True) and ((((Matching unit) is sleeping) Not equal to True) and (((Matching unit) is Magic Immune) Not equal to True) and (((Matching unit) is hidden) Note equal to True)
The above Unit Group variable is set to filter units that are:
-Not structures/buildings
-Not dead
-Enemies of 'o'
-Not flying units
-Not sleeping
-Not magic immune
-Not hidden

All of that seems more than logical to me, as it should to you.

After you have set EG[1], its time to set EG[2]. EG[2] will pick a random unit from EG[1] to ensure us that 'o' only attacks 1 of them, not the whole group, as that would look very strange indeed:
Set EG[2] = (Random 1 units from EG[1])
To find the above function when searching, it is called Random N Units From Unit Group.

Notice that 'o_current_loc' is still sitting there, doing nothing, so we may as well remove it with a custom script, to avoid yet another memory leak, as have no use for it again: Custom script: call RemoveLocation(udg_o_current_loc)

You should now have all of the following:
Omnislash Events Unit - A unit Starts the effect of an ability Conditions (Ability being cast) Equal to Omnislash Actions Set o = (Triggering unit) Set t = (Target unit of ability being cast) Set tl = (Position of t) If ((Level of Omnislash for o) Equal to 1) then do (Set loops = 2) else do (Do nothing) If ((Level of Omnislash for o) Equal to 2) then do (Set loops = 4) else do (Do nothing) If ((Level of Omnislash for o) Equal to 3) then do (Set loops = 7) else do (Do nothing) Unit - Make o Invulnerable Animation - Change o's vertex coloring to (100.00%, 100.00%, 100.00%) with 50.00% transparency Selection - Remove o from selection Unit - Move o instantly to tl Custom script: call RemoveLocation(udg_tl) Animation - Play o's attack animation Unit - Cause o to damage t, dealing (Random real number between 150.00 and 250.00) damage of attack type Hero and damage type Normal Special Effect - Create a special effect attached to the chest of o using Abilities\Spells\NightElf\Blink\BlinkCaster.mdl Special Effect - Destroy (Last created special effect) For each (Integer A) from 1 to loops, do (Actions) Loop - Actions Wait 0.30 game-time seconds Set o_current_loc = (Position of o) Set EG[1] = (Units within 600.00 of o_current_loc matching ((((Matching unit) is A structure) Not equal to True) and ((((Matching unit) is alive) Equal to True) and ((((Matching unit) belongs to an enemy of (Owner of o)) Equal to True) and ((((Matching unit) is A flying Set EG[2] = (Random 1 units from EG[1]) Custom script: call RemoveLocation(udg_o_current_loc)

------------------------------------------------------------

5: Creating an advanced loop for Omnislash - Part 2

After creating our massively piled up Unit Group, EG[1] and [2], we now need to make 'o' attack units from EG[2].

We will be needing to use the function If/Then/Else, Multiple Functions in our loop for a number of reasons:
It will ensure us that if the amount of units that are in the EG[1] is greater than 0, in other words, not equal to 0, it will pick every unit in EG[2] and do our usual mechanics. And if the number of units in EG[1] are not greater than 0, it will make 'o', the caster, non-transparent and turned back to being vulnerable again.

Add the following into your Omnislash trigger:
If (All Conditions are True) then do (Then Actions) else do (Else Actions) If - Conditions (Number of units in EG[1]) Greater than 0 Then - Actions Unit Group - Pick every unit in EG[2] and do (Actions) Loop - Actions Else - Actions
The above function needs to be placed under the custom script function we used to remove o_current_loc. The above function's condition is an integer comparison, and is initially called Unit- Count Units In Unit Group.

After doing all of that, you need to create 2 more variables. Create a new unit variable called p and another point variable called pl, and set them into the Loop-Actions of the Unit Group as shown:
Unit Group - Pick every unit in EG[2] and do (Actions) Loop - Actions Set p = (Picked unit) Set pl = (Position of p)

Next, we need to add in our usual mechanics to the trigger, into the Loop-Actions of the Unit Group.

You should end up with this:
Unit Group - Pick every unit in EG[2] and do (Actions) Loop - Actions Set p = (Picked unit) Set pl = (Position of p) Selection - Remove o from selection Unit - Move o instantly to pl Custom script: call RemoveLocation(udg_pl) Animation - Play o's attack animation Unit - Cause o to damage p, dealing (Random real number between 150.00 and 250.00) damage of attack type Hero and damage type Normal Special Effect - Create a special effect attached to the chest of o using Abilities\Spells\NightElf\Blink\BlinkCaster.mdl Special Effect - Destroy (Last created special effect)

We also need to destroy our Unit Groups after they have been used by using custom script, otherwise they will cause memory leaks as they are updated every 0.3 seconds:
Unit Group - Pick every unit in EG[2] and do (Actions) Loop - Actions Set p = (Picked unit) Set pl = (Position of p) Selection - Remove o from selection Unit - Move o instantly to pl Custom script: call RemoveLocation(udg_pl) Animation - Play o's attack animation Unit - Cause o to damage p, dealing (Random real number between 150.00 and 250.00) damage of attack type Hero and damage type Normal Special Effect - Create a special effect attached to the chest of o using Abilities\Spells\NightElf\Blink\BlinkCaster.mdl Special Effect - Destroy (Last created special effect) Custom script: call DestroyGroup(udg_EG[1]) Custom script: call DestroyGroup(udg_EG[2])

You should now have an empty Else-Actions sitting at the bottom of your trigger. We need to fill this in with the following:
Else - Actions Custom script: call DestroyGroup(udg_EG[1]) Custom script: call DestroyGroup(udg_EG[2]) Selection - Add o to selection for (Owner of o) Animation - Change o's vertex coloring to (100.00%, 100.00%, 100.00%) with 0.00% transparency Unit - Make o Vulnerable
The reason why we need to fill in the Else-Actions is becuase if the Condtions from before, which are - ((Number of units in EG[1]) Greater than 0), are not Greater than 0, we need to turn the Invulnerability for 'o' off, change his transparency back to normal and select him . Selecting is not really required, but it makes things easier at the end of the slashing. We also needed to destroy our EG groups becuase otherwise they will cause memory leaks which are not wanted.

Omnislash 99% complete:
(see how we use our set 'loops' to determine how many times the loop is looped).
Omnislash Events Unit - A unit Starts the effect of an ability Conditions (Ability being cast) Equal to Omnislash Actions Set o = (Triggering unit) Set t = (Target unit of ability being cast) Set tl = (Position of t) If ((Level of Omnislash for o) Equal to 1) then do (Set loops = 2) else do (Do nothing) If ((Level of Omnislash for o) Equal to 2) then do (Set loops = 4) else do (Do nothing) If ((Level of Omnislash for o) Equal to 3) then do (Set loops = 7) else do (Do nothing) Unit - Make o Invulnerable Animation - Change o's vertex coloring to (100.00%, 100.00%, 100.00%) with 50.00% transparency Selection - Remove o from selection Unit - Move o instantly to tl Custom script: call RemoveLocation(udg_tl) Animation - Play o's attack animation Unit - Cause o to damage t, dealing (Random real number between 150.00 and 250.00) damage of attack type Hero and damage type Normal Special Effect - Create a special effect attached to the chest of o using Abilities\Spells\NightElf\Blink\BlinkCaster.mdl Special Effect - Destroy (Last created special effect) For each (Integer A) from 1 to loops, do (Actions) Loop - Actions Wait 0.30 game-time seconds Set o_current_loc = (Position of o) Set EG[1] = (Units within 600.00 of o_current_loc matching ((((Matching unit) is A structure) Not equal to True) and ((((Matching unit) is alive) Equal to True) and ((((Matching unit) belongs to an enemy of (Owner of o)) Equal to True) and ((((Matching unit) is A flying Set EG[2] = (Random 1 units from EG[1]) Custom script: call RemoveLocation(udg_o_current_loc) If (All Conditions are True) then do (Then Actions) else do (Else Actions) If - Conditions (Number of units in EG[1]) Greater than 0 Then - Actions Unit Group - Pick every unit in EG[2] and do (Actions) Loop - Actions Set p = (Picked unit) Set pl = (Position of p) Selection - Remove o from selection Unit - Move o instantly to pl Custom script: call RemoveLocation(udg_pl) Animation - Play o's attack animation Unit - Cause o to damage p, dealing (Random real number between 150.00 and 250.00) damage of attack type Hero and damage type Normal Special Effect - Create a special effect attached to the chest of o using Abilities\Spells\NightElf\Blink\BlinkCaster.mdl Special Effect - Destroy (Last created special effect) Custom script: call DestroyGroup(udg_EG[1]) Custom script: call DestroyGroup(udg_EG[2]) Else - Actions Custom script: call DestroyGroup(udg_EG[1]) Custom script: call DestroyGroup(udg_EG[2]) Selection - Add o to selection for (Owner of o) Animation - Change o's vertex coloring to (100.00%, 100.00%, 100.00%) with 0.00% transparency Unit - Make o Vulnerable

------------------------------------------------------------

6: The final trigger

A few final tweeks need to be added to the trigger to make sure it resets o's stats. Add the following to your trigger to ensure this:
Selection - Add o to selection for (Owner of o) Animation - Change o's vertex coloring to (100.00%, 100.00%, 100.00%) with 0.00% transparency Unit - Make o Vulnerable

After you have done that, move it so its underneath the 'For Each (Integer A) from 1 to loops, do (Actions)'.

Here is the final result for the trigger for Omnislash:
Omnislash Events Unit - A unit Starts the effect of an ability Conditions (Ability being cast) Equal to Omnislash Actions Set o = (Triggering unit) Set t = (Target unit of ability being cast) Set tl = (Position of t) If ((Level of Omnislash for o) Equal to 1) then do (Set loops = 2) else do (Do nothing) If ((Level of Omnislash for o) Equal to 2) then do (Set loops = 4) else do (Do nothing) If ((Level of Omnislash for o) Equal to 3) then do (Set loops = 7) else do (Do nothing) Unit - Make o Invulnerable Animation - Change o's vertex coloring to (100.00%, 100.00%, 100.00%) with 50.00% transparency Selection - Remove o from selection Unit - Move o instantly to tl Custom script: call RemoveLocation(udg_tl) Animation - Play o's attack animation Unit - Cause o to damage t, dealing (Random real number between 150.00 and 250.00) damage of attack type Hero and damage type Normal Special Effect - Create a special effect attached to the chest of o using Abilities\Spells\NightElf\Blink\BlinkCaster.mdl Special Effect - Destroy (Last created special effect) For each (Integer A) from 1 to loops, do (Actions) Loop - Actions Wait 0.30 game-time seconds Set o_current_loc = (Position of o) Set EG[1] = (Units within 600.00 of o_current_loc matching ((((Matching unit) is A structure) Not equal to True) and ((((Matching unit) is alive) Equal to True) and ((((Matching unit) belongs to an enemy of (Owner of o)) Equal to True) and ((((Matching unit) is A flying Set EG[2] = (Random 1 units from EG[1]) Custom script: call RemoveLocation(udg_o_current_loc) If (All Conditions are True) then do (Then Actions) else do (Else Actions) If - Conditions (Number of units in EG[1]) Greater than 0 Then - Actions Unit Group - Pick every unit in EG[2] and do (Actions) Loop - Actions Set p = (Picked unit) Set pl = (Position of p) Selection - Remove o from selection Unit - Move o instantly to pl Custom script: call RemoveLocation(udg_pl) Animation - Play o's attack animation Unit - Cause o to damage p, dealing (Random real number between 150.00 and 250.00) damage of attack type Hero and damage type Normal Special Effect - Create a special effect attached to the chest of o using Abilities\Spells\NightElf\Blink\BlinkCaster.mdl Special Effect - Destroy (Last created special effect) Custom script: call DestroyGroup(udg_EG[1]) Custom script: call DestroyGroup(udg_EG[2]) Else - Actions Custom script: call DestroyGroup(udg_EG[1]) Custom script: call DestroyGroup(udg_EG[2]) Selection - Add o to selection for (Owner of o) Animation - Change o's vertex coloring to (100.00%, 100.00%, 100.00%) with 0.00% transparency Unit - Make o Vulnerable Selection - Add o to selection for (Owner of o) Animation - Change o's vertex coloring to (100.00%, 100.00%, 100.00%) with 0.00% transparency Unit - Make o Vulnerable
Demo map can be downloaded [thread=45751]here[/thread].

Have fun Omnislashing!

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.