How to write rotation from scratch

Information about addon, how it works, how to install, etc.
1 post Page 1 of 1
Kaminaris
Site Admin
Posts: 322
Joined: 25 Jun 2017, 03:45


First let me say this. As long as you have non-zero knowledge of programming, writing rotation is easy. Even if you never tried lua before. Don't be lazy ass and try it yourself.

There are few classes (ex. rogue assassination) that are exception to this but that is another part of story.

Here is the list of steps to take to write your own rotation to whatever you like.

1. List all of the spells/talents/auras you are going to use.
That is easy part because all you need to do is to either write down spell ids by hand (which is time consuming) in the following manner:
local _SpellName = SpellId;
ex.
local _SoulCarver = 207407;
local _FelDevastation = 212084;
local _SoulCleave = 228477;
local _ImmolationAura = 178740;
OR you can use my magic function that extracts spells automatically
You need to use browser with developer tools like chrome, firefox. I will write it using chrome as example.

a) Navigate to icy-veins.com
b) Navigate to class guide you are interested, to "Rotation, Cooldowns, and Abilities" page. ex Fire Mage
c) Open developer tools in browser (F12 in chrome)
d) Open console in developer tools (button Console in chrome)
e) Paste this little script in console:
  1. var slist = {};
  2. jQuery('div.page_content').find('a.spell').each(function() {
  3.     var name = jQuery(this).text().replace(/ /g, '').replace(/'/g, '').replace(/:/g, '');
  4.     if (name && name.length) {
  5.         slist[name] = jQuery(this).attr('href').match(/[\d]+$/)[0];
  6.     }
  7. });
  8. var sout = '';
  9. for (var i in slist) {
  10.     if (slist.hasOwnProperty(i)) {
  11.         sout += 'local _' + i + ' = ' + slist[i] + ";\n";
  12.     }
  13. }
  14. console.log(sout);
f) Execute it and voilà! You have a list of spells for specific Class/Specialization.
Image

Save it somewhere, you will need it later.

2. Write down rotation in simple priority list
There are 2 things you need to know and keep in mind while working on rotation:
  • Rotation is a priority list that is executed in 0.15s intervals (by default). This means if guide says something like: Use spell X then use spell Y; lua ain't gonna understand that shit.
  • Rotation function should return spell what needs to be casted after current spell. This is the biggest difference between MaxDps rotation functions and Simcraft action priority lists. And this is why variable timeShift exists (it's a fucking important variable).
Most (but not all) of icy veins rotations are compatible with MaxDps. Lets take a look at Frost Mage (I have simplified it a bit, since you don't care about cooldowns and generally at spells with longer than 60s cooldown):

1.  Ice Lance
Conditions:
a) Player aura  Fingers of Frost has reached 3 stacks
2.  Frost Bomb
Conditions:
a) It is talented (always present for spells from talents)
b) You are currently not casting frost bomb (this is always present in spells that are not instant.)
c) Player aura  Fingers of Frost has at least 1 stack
3.  Freeze from water elemental
Conditions:
a) if it will hit at least 2 adds that can be rooted (bosses are immune to Freeze). <- You skip shit spells with conditions like this because it can't be detected.
4. This is a part where it gets fun, icy-veins says something like this:
Cast Frostbolt and immediately Flurry if Brain Freeze is active. You can't do shit like this. But you can't forget about it. Solution is pretty fucking simple. You just need to watch for Brain Freeze aura and cast Flurry BEFORE Frostbolt. So in the end it looks like this:
4 (again).  Flurry
Conditions:
a) Player Aura  Brain Freeze is active
Simple isn't it?
5.  Ice Lance immediately after  Flurry.
Again, not possible to do, what you CAN do is to simply watch for target debuff  Winter's Chill
5 (again).  Ice Lance
Conditions:
a) Target has  Winter's Chill debuff
OR
b) Your current cast is  Flurry (It really doesn't work for instant casts, BUT if someone wants to cast it without  Brain Freeze then it will not be instant cast)

There are other conditions and spells here but i'm gonna skip them since it does not really matter for guide purpose.

6. FILLER SPELL, you always want to return some spell id in case of rotations that DOES have filler spell. In case of fire mage it is  Frostbolt
And it has NO conditions.

3. Convert it to rotation function
I will write this as if you would make a Custom Rotation (its not much different from class module rotations, the only difference is that spell variables are not inside functions but at the top of the file):

So you start with empty function like this:
  1. function(_, timeShift, currentSpell, gcd)
  2.    
  3. end
First, you add spell list at the begining so you don't need to put spell ids by hand (you might want to clean them up a bit and remove spells that you are not gonna use ex. Blink, but I'm not gonna do that in guide):
  1. function(_, timeShift, currentSpell, gcd)
  2.     local _RuneofPower = 116011;
  3.     local _IcyVeins = 12472;
  4.     local _RayofFrost = 205021;
  5.     local _IceLance = 30455;
  6.     local _FingersofFrost = 112965;
  7.     local _FrostBomb = 112948;
  8.     local _FrozenOrb = 84714;
  9.     local _Freeze = 33395;
  10.     local _Ebonbolt = 214634;
  11.     local _BrainFreeze = 190447;
  12.     local _Flurry = 44614;
  13.     local _Frostbolt = 116;
  14.     local _WaterJet = 135029;
  15.     local _IceNova = 157997;
  16.     local _CometStorm = 153595;
  17.     local _Blizzard = 190356;
  18.     local _ArcticGale = 205038;
  19.     local _GlacialSpike = 199786;
  20.     local _MirrorImage = 55342;
  21.     local _IncantersFlow = 1463;
  22.     local _ThermalVoid = 155149;
  23.     local _SplittingIce = 56377;
  24.     local _IceFloes = 108839;
  25.     local _Blink = 1953;
  26.     local _IceBarrier = 11426;
  27.     local _Shimmer = 212653;
  28.  
  29.     -- Your cooldowns goes here
  30.  
  31.     -- Your rotation goes here
  32. end
Start by converting your priority list into lua conditions. They should look like this:
  1. if CONDITIONS then
  2.     return _Spell;
  3. end
So in our case first one is  Ice Lance
Order of conditions is important and should be the same as your priority list.
Look at big point 2 for reference.

1.
  1. -- timeShift is provided as function argument
  2. local fof, fofCharges = MaxDps:Aura(_FingersofFrost, timeShift); -- This is important because we need to get STACKS from Fingers of frost aura.
  3. if fofCharges >= 3 then -- 3 or more charges of fingers of frost
  4.     return _IceLance;
  5. end
2.
  1. --currentSpell is provided as function argument
  2. --Enters (new line chars) does not matter, you can actually write it in one line but I formatted it for readability
  3. if
  4.     talents[_FrostBomb] --Thats how you check for talents, talent variable is provided as function argument
  5.     and fofCharges >= 1 --fofCharges were declared in first spell so we can use it here
  6.     and not MaxDps:SameSpell(currentSpell, _FrostBomb) --Player is not casting FrostBomb already
  7.     and not MaxDps:TargetAura(_FrostBomb, timeShift) --Target does not already have Frost Bomb debuff
  8. then
  9.     return _FrostBomb;
  10. end
3. Skipped

4.
  1. if MaxDps:Aura(_BrainFreeze, timeShift) then
  2.     return _Flurry;
  3. end
5.
  1. if
  2.     MaxDps:SameSpell(currentSpell, _Flurry) -- Player is casting Flurry
  3.     or -- OR
  4.     MaxDps:TargetAura(_WintersChill, timeShift) -- Target has Winter's Chill Debuff
  5. then
  6.     return _IceLance;
  7. end
6.
  1. return _Frostbolt;
Putting it all together:
  1. function(_, timeShift, currentSpell, gcd)
  2.     local _RuneofPower = 116011;
  3.     local _IcyVeins = 12472;
  4.     local _RayofFrost = 205021;
  5.     local _IceLance = 30455;
  6.     local _FingersofFrost = 112965;
  7.     local _FrostBomb = 112948;
  8.     local _FrozenOrb = 84714;
  9.     local _Freeze = 33395;
  10.     local _Ebonbolt = 214634;
  11.     local _BrainFreeze = 190447;
  12.     local _Flurry = 44614;
  13.     local _Frostbolt = 116;
  14.     local _WaterJet = 135029;
  15.     local _IceNova = 157997;
  16.     local _CometStorm = 153595;
  17.     local _Blizzard = 190356;
  18.     local _ArcticGale = 205038;
  19.     local _GlacialSpike = 199786;
  20.     local _MirrorImage = 55342;
  21.     local _IncantersFlow = 1463;
  22.     local _ThermalVoid = 155149;
  23.     local _SplittingIce = 56377;
  24.     local _IceFloes = 108839;
  25.     local _Blink = 1953;
  26.     local _IceBarrier = 11426;
  27.     local _Shimmer = 212653;
  28.  
  29.     -- Your cooldowns goes here
  30.  
  31.     -- Your rotation goes here
  32.     -- timeShift is provided as function argument
  33.     local fof, fofCharges = MaxDps:Aura(_FingersofFrost, timeShift); -- This is important because we need to get STACKS from Fingers of             frost aura.
  34.     if fofCharges >= 3 then -- 3 or more charges of fingers of frost
  35.         return _IceLance;
  36.     end
  37.  
  38.     --currentSpell is provided as function argument
  39.     --Enters (new line chars) does not matter, you can actually write it in one line but I formatted it for readability
  40.     if
  41.         talents[_FrostBomb] --Thats how you check for talents, talent variable is provided as function argument
  42.         and fofCharges >= 1 --fofCharges were declared in first spell so we can use it here
  43.         and not MaxDps:SameSpell(currentSpell, _FrostBomb) --Player is not casting FrostBomb already
  44.         and not MaxDps:TargetAura(_FrostBomb, timeShift) --Target does not already have Frost Bomb debuff
  45.     then
  46.         return _FrostBomb;
  47.     end
  48.  
  49.     if MaxDps:Aura(_BrainFreeze, timeShift) then
  50.         return _Flurry;
  51.     end
  52.  
  53.     if
  54.         MaxDps:SameSpell(currentSpell, _Flurry) -- Player is casting Flurry
  55.         or -- OR
  56.         MaxDps:TargetAura(_WintersChill, timeShift) -- Target has Winter's Chill Debuff
  57.     then
  58.         return _IceLance;
  59.     end
  60.  
  61.     return _Frostbolt;
  62. end
4. Add cooldowns
Below line
-- Your cooldowns goes here
Add your cooldowns, (spells that you skipped but are still a part of your rotation)
General idea is like this:
  1. MaxDps:GlowCooldown(_Spell, Condition);
for example Mirror Image:
  1. MaxDps:GlowCooldown(_MirrorImage, talents[_MirrorImage] and MaxDps:SpellAvailable(_MirrorImage, timeShift));
It will highlight green when Mirror Image is talented and off cooldown.

And thats it. Then you go to training dummy and test your rotation (need to close Custom Rotations window before getting into combat).

For experienced developers it takes around 1h to write rotation from scratch, you can always use one of the Original rotations and modify it to suit your needs.
1 post Page 1 of 1
drogie łóżka stolik kawowy stół dębowy rozkładany