Register

Leafkiller's 4.1 Feral Ovale Script

Face-rippin fun.

Moderator: Forum Administrators

Exalted
User avatar
Posts: 1145
Joined: Fri Jun 04, 2010 4:28 am

Leafkiller's 4.1 Feral Ovale Script

Postby Leafkiller » Wed Oct 20, 2010 5:35 pm

EDIT: Welcome to 4.2! To find Leaf's awesome 4.2 Ovale script please go to
http://fluiddruid.net/forum/viewtopic.php?f=3&t=381
There is no reason to run the old script or a reason to ask Leaf to discuss it:)


The following script is a continuation of the script that Alaron had created with some contributions I had made to the extra script boxes. The bear portion of the script is from tbot.

The script that has been optimized based on Mew modeling (see the Mew thread for more details on the modeling that Alaron did along with my subsequent testing).

To use this script, make sure you have the most current version of Ovale, and replace the default script in the Ovale configuration with the one below. Under the "Apparence" tab, make sure to select "Numeric display" and also "Hide empty buttons"

======================
Version 1.3.2 - put the ripshred spellinfo back in.
Version 1.3.1 - Fixes to Berserk and removal of spellinfo stuff that apparently is not needed and causes problems.
Version 1.2.6.2 - Add flag that allows disabling the t11 autochecking. Turn the flag on for the t11 code to work. Added two additional configurable cooldown boxes to the right side of the display.
Version 1.2.6 - Check for 2 points in BiTW for refreshing Rip with FB below 25%
Version 1.2.5.1 - Changed the Berserk logic to account for TF vs. non-TF casting (lower energy levels outside of TF)
Version 1.2.4 - Add in support for cooldown tracking of unheeded warning - also add in tracking of heroic Essence of the Cyclone. Put the demo roar checkbox back in - on aoe mobs it is annoying to not be able to turn it off.
Version 1.2.2 - Remove the switch to track T11 and use the built-in Ovale ArmorSetParts function to automatically detect the 4 piece bonus. Add in the first attempt to track a non-proc trinket - Unheeded Warning.
Version 1.2.1 - Change the Berserk rotation box to use the polar bear white texture when it should not be cast or is on cooldown (TF and energy are the constraints). Added drop downs to the 2 cooldown boxes on the right so you can select what spell or trinket slot to monitor. Default is none.
Version 1.2 - Removed all of the bear options - bear is single target only and demo roar/thrash are core to the rotation. Move the FC code to the top left button. It shows FC only when you can cast it - in range and off of cooldown. If you are in a "wait" state it shows the stampeding roar texture (which also shows the FC cooldown) and when it is time to run out the dash texture. There are a set of conditions that bound when to show the dash texture and these can be improved. There are only two cooldown boxes on the right side now - one for Rip and one for TF. The others are not as important to see. For bear, the right side boxes show SI and FR which complement the Barkskin shown for bears in the upper left hand box.
Version 1.1.5c - Make the FC cooldown part of the "Show Right Cooldown Boxes" switch. Change the texture displayed when it is time to run out for Feral Charge to "Spell_druid_stampedingroar_cat" so it is different than the
one displayed when you are out of range: "Ability_druid_dash."
Version 1.1.5b - This release has significantly enhanced code for Feral Charge. It will only show FC if it is selected (of course), off of cooldown, and in range to be cast (I have not tested this on a Drake with zero range). If you are in melee range and it is not castable, the normal rotation shows. If you are out of melee range the main rotation box ow shows a "dash" texture to tell you to move. There is a drop down to select the amount of FC travel time (as in running out). If this is set to a nonzero number and FC is selected (and some other spell constraints are met) it will flash the 'dash" texture to tell you to run out. As soon as you are in FC range and FC is off of cooldown, the icon changes to FC. I also added a cooldown tracking box for FC - so there are now 5 small boxes to the right side.
Version 1.1.5 - for use in 4.06. Removed FB from the rotation prior to 25% and also remove the SR desync code. Both simplify the rotation and end up as a net dps up.
Version 1.1.4 - Consider this the first version for 4.06, although the change is applicable to both 4.03 and 4.06. In this version I have added an option to call for Feral Charge whenever it is off of cooldown. This is prioritized ahead of everything else in the rotation. There are fights (such as Valiona/Theralion) where you can Feral Charge while in melee range. Doing so is a huge dps up.
Version 1.1.3a - removed swipe from level 80 rotation on the "adds" option. Fixed bug with Pulverize using wrong spellid for the buff.
Version 1.1.3 - Revamped bear code (level 85 ready) from tbot with feedback from Timbermaw and Astrylian on the rotation. Bear code includes Thrash and also an AOE option. Use level check for FB in place of checkbox. Slight adjustment to limits on when to FB.
Version 1.1.2 - Added code to Clip Rake if it has less than 9 seconds left and TF is up. Also, do not pool energy if
TF is up. Both of thse changes are based on sim work from Mihir. Also removed the option to disable clips on Rip - it should always be attempted.

Version 1.1.1 - Added code to FB more often during Berserk - small dps up - mostly it feels right to not just keep spamming shred. As a side note - this script does work for both level 80 and 85. Just make sure to adjust the FB setting to low if you are 85.

New version 1.1 - for use at level 85 - Add tier 11 4 piece set bonus code in two places - just before Shred code to stack it up and near the top of the script with a 4 second clip to keep it from falling off. Also put the refresh part into the second box as it is not a filler to refresh (while it is to stack). Also changed the "mangle" buff tracking box to use Panther for tracking with t11. Make sure to use "Few Ferocious Bites" at level 85.

New version 1.0.6 - Cleans up the interface - there is now a checkbox to toggle display for the cooldowns on the left side and a checkbox to toggle display for the cooldowns on the right. The trinket cooldowns (for bears) have been merged into the right cooldown boxes - and can be hidden. The emergency FB for Blood in the Water now looks for 2.1 seconds on Rip due to the bug where Rip drops off (2 dps loss in sim). Also, disabled the Savagee Roar desync code during Blood in the Water phase to preserve combo points (this is dps neutral). Added checkbox for two levels of ferocious bite (taken from Alaron's pre patch script) for later use (predicting at level 85 with lower crit rates we will want to FB less - still needs to be tested and optimized in a sim).

New version 1.0.5 - adds two additional cooldown checkboxes for cat - Savage roar and mangle. This is controlled on a separate checkbox. Also added clipping to Rip conntrolled by a checkbox.

New version 1.0.4 - changes text for swipe on cooldown checkbox, change max energy for berserk from 91 to 96, add optional small timer boxes (on checkbox) for rake/rip and mangle/swipe cooldowns.

New version 1.0.3 - fixed a bug I introduced when adding in the bear code. Also did some cleanup on the Ripshred code. Everyone using the script should also make sure to update Ovale - 4.09 was released on 10/17.

New version 1.0.2 folded in tbot's Bear code. I did move the option for Demo Roar higher in the script - otherwise it is never cast (it is on a toggle).

New version 1.0.1 with support for Ravage/Stampede and Berserk

The 4.06 scripts have been removed.
======================
Code: Select all
# Ovale Optimized Script Leafkiller 1.3.2
#       Bear code from tbot
# Started with the Ovale default druid script, this includes significant work from Alaron and goes back to the work of Fatalsaints
# Script source: http://fluiddruid.net/forum/viewtopic.php?f=3&t=33
# Ovale source: http://wow.curse.com/downloads/wow-addons/details/ovale.aspx
# Initial optimized version based on Sim work from Alaron with some modifications from Leafkiller
# Revision History (post 1.0)
# 1.3.2 04/26/2011
#   Put ripshreds code back in - but not other spellinfo params.
# 1.3.1 04/26/2011
#   Change the Berserk code for the 4.1 patch (no longer on the GCD). Had to comment out the spellinfo stuff - caused problems.
# 1.2.6.2 03/18/2011
#   Add in two extra cooldown boxes and a switch to ignore the t-11 code - did not change the FC code or the cooldown code for t-11 - just the rotations.
# 1.2.6 03/01/2011
#   Look for talent points in Blood in the Water for FB refresh code.
# 1.2.5 02/25/2011
#   Small optimization of the Berserk code (which wastes energy outside of TF)
# 1.2.4 02/21/2011
#   Put demo roar checkbox back in. It is a problem on short lived mobs and packs. Add in support for the heroic Essence of Cyclone.
# 1.2.3 02/13/2011
#   Enhance the Unheeded Heeded Warning code to show the internal cooldown after the buff expires.
# 1.2.2 02/12/2011
#   Remove the T11 config switch and use ArmorSetParts (built in Ovale function). Add item tracking for Unheeded Warning.
# 1.2.1 02/12/2011
#   Change the Berserk code to use a texture (polar bear white) to show its cooldown and when it is contrained by energy or
#   TF cooldown. Show the Berserk icon when it is a good time to cast it. Change the cooldown boxes to the right side to be
#   dropdowns so you can select which if any spells/trinkets to monitor there.
# 1.2 - 02/11/2011
#   Restructure some to better deal with "out of rotation" skills. Removed the bear options - the rotation is only for single
#   target now and Demo Roar is included if it is missing from the target. The FC code is now the top left box. It will
#   show the Stampedingroar_cat texture during cooldowns, will show the "dash" texture when it is time to run out and will show
#   the FC spell if it is off of cooldown and in range to be cast. The Dash texture is still in the rotation section to tell
#   when you are out of melee range - but this is separate. Cut down to two cooldown boxes - TF and Rip, SI and  FR for bear
# Removed older comments - to keep the file from growing too large.

Define(BARKSKIN 22812)
Define(BERSERK 50334) #cat+bear cd buff
Define(DEMOROAR 99) #bear
Define(ENRAGE 5229) #bear
Define(FAERIEFERAL 16857) #bear+cat
Define(FERALCHARGECAT 49376)
Define(FEROCIOUSBITE 22568) #cat finish 35-70 mana
Define(FRENZIEDREGENERATION 22842) #bear
Define(LACERATE 33745) #bear bleed*3
Define(MANGLECAT 33876) #cat bleed+debuff
Define(MANGLEBEAR 33878) #bear bleed+debuff
Define(MAUL 6807) #bear
Define (PANTHER 90166) #tier 11 4 piece cat
Define(PULVERIZE 80313) #bear after lacerate*3
Define (PULVERIZEBUFF 80951) #buff has a different spellid then the ability
Define(RAKE 1822) #cat bleed
Define(RAVAGE 6785) #cat behind+(prowling or stampede)
Define(RIP 1079) #cat bleed
   SpellInfo(RIP resetcounter=ripshreds)
Define(SAVAGEROAR 52610) #cat damage buff
Define(SHRED 5221) #cat behind
    SpellInfo(SHRED inccounter=ripshreds)
Define(SURVIVALINSTINCTS 61336) #cat+bear surv cd
Define(SWIPEBEAR 779) #bear aoe
Define(SWIPECAT 62078) #cat aoe
Define(THRASH 77758) #bear aoe bleed
Define(TIGERSFURY 5217) #cat buff
   
#Trinket Procs
Define(UNHEEDEDWARNING 59520)
Define(HEEDLESSCARNAGE 92108) #Unheeded Warning Proc
Define(ESSENCEOFCYCLONEH 65140) # heroic Esscence of Cyclone
Define(TWISTEDH 92351)

#Glyphs
Define(GLYPHOFSHRED 54815)
Define(GLYPHOFRIP 54818)
Define(GLYPHOFBERSERK 62969)

#Buff
Define(CLEARCASTING 16870)
Define(STAMPEDE 81022)

#Talents
Define(BLOODINTHEWATERTALENT 8341)

AddCheckBox(demo SpellName(DEMOROAR) default mastery=2)
AddCheckBox(berserk SpellName(BERSERK) default mastery=2)
AddCheckBox(cooldownsL "Show Left Rotation Boxes" default mastery=2)
AddCheckBox(cooldownsR "Show Right Cooldown Boxes" default mastery=2)
AddCheckBox(lucioles SpellName(FAERIEFERAL) default mastery=2)
AddCheckBox(mangle SpellName(MANGLECAT) default mastery=2)
AddCheckBox(t11 "Detect t11 set bonus" default mastery=2)
AddListItem(cd0 t0 "Top right - No Cooldown" default mastery=2)
AddListItem(cd0 t1 "Top right - Mangle" mastery=2)
AddListItem(cd0 t2 "Top right - Rake" mastery=2)
AddListItem(cd0 t3 "Top right - Rip" mastery=2)
AddListItem(cd0 t4 "Top right - Savage Roar" mastery=2)
AddListItem(cd0 t5 "Top right - Tiger's Fury" mastery=2)
AddListItem(cd0 t6 "Top right - Trinket 0" mastery=2)
AddListItem(cd0 t7 "Top right - Trinket 1" mastery=2)
AddListItem(cd0 t8 "Top right - Unheeded Warning" mastery=2)
AddListItem(cd0 t9 "Top right - Heroic Essence of Cyclone" mastery=2)
AddListItem(cd1 t0 "Bottom right - No Cooldown" default mastery=2)
AddListItem(cd1 t1 "Bottom right - Mangle" mastery=2)
AddListItem(cd1 t2 "Bottom right - Rake" mastery=2)
AddListItem(cd1 t3 "Bottom right - Rip" mastery=2)
AddListItem(cd1 t4 "Bottom right - Savage Roar" mastery=2)
AddListItem(cd1 t5 "Bottom right - Tiger's Fury" mastery=2)
AddListItem(cd1 t6 "Bottom right - Trinket 0" mastery=2)
AddListItem(cd1 t7 "Bottom right - Trinket 1" mastery=2)
AddListItem(cd1 t8 "Bottom right - Unheeded Warning" mastery=2)
AddListItem(cd1 t9 "Bottom right - Heroic Essence of Cyclone" mastery=2)
AddListItem(cd2 t0 "Top far right - No Cooldown" default mastery=2)
AddListItem(cd2 t1 "Top far right - Mangle" mastery=2)
AddListItem(cd2 t2 "Top far right - Rake" mastery=2)
AddListItem(cd2 t3 "Top far right - Rip" mastery=2)
AddListItem(cd2 t4 "Top far right - Savage Roar" mastery=2)
AddListItem(cd2 t5 "Top far right - Tiger's Fury" mastery=2)
AddListItem(cd2 t6 "Top far right - Trinket 0" mastery=2)
AddListItem(cd2 t7 "Top far right - Trinket 1" mastery=2)
AddListItem(cd2 t8 "Top far right - Unheeded Warning" mastery=2)
AddListItem(cd2 t9 "Top far right - Heroic Essence of Cyclone" mastery=2)
AddListItem(cd3 t0 "Bottom far right - No Cooldown" default mastery=2)
AddListItem(cd3 t1 "Bottom far right - Mangle" mastery=2)
AddListItem(cd3 t2 "Bottom far right - Rake" mastery=2)
AddListItem(cd3 t3 "Bottom far right - Rip" mastery=2)
AddListItem(cd3 t4 "Bottom far right - Savage Roar" mastery=2)
AddListItem(cd3 t5 "Bottom far right - Tiger's Fury" mastery=2)
AddListItem(cd3 t6 "Bottom far right - Trinket 0" mastery=2)
AddListItem(cd3 t7 "Bottom far right - Trinket 1" mastery=2)
AddListItem(cd3 t8 "Bottom far right - Unheeded Warning" mastery=2)
AddListItem(cd3 t9 "Bottom far right - Heroic Essence of Cyclone" mastery=2)

ScoreSpells(FAERIEFERAL DEMOROAR MANGLEBEAR LACERATE SAVAGEROAR RIP
        MANGLECAT RAKE SHRED FEROCIOUSBITE PULVERIZE MAUL)
 
AddIcon help=cd size=small mastery=2 { # TF Icon or Barkskin for Bear
    if CheckBoxOn(cooldownsL) {
        if Stance(3) {
            # off of cooldown and in range
            if TargetInRange(FERALCHARGECAT)
                Spell(FERALCHARGECAT)
            # FC Runaway code
            unless BuffPresent(TIGERSFURY) or BuffPresent(BERSERK) or Mana(more 69) or BuffPresent(CLEARCASTING) {
                unless ArmorSetParts(T11 more 3) and BuffExpires(PANTHER 4) {
                    if 2s before Spell(FERALCHARGECAT) {
                        unless TargetDebuffExpires(RAKE 5.9 mine=1) or TargetInRange(FERALCHARGECAT)
                            Texture(Ability_druid_dash)
                    }
                }   
            }
            # default - shows cooldown
            if 0s before Spell(FERALCHARGECAT)
                Texture(Spell_nature_timestop)  # default - FC is off of cooldown other conditons not met
        }
        if Stance(1) {Spell(BARKSKIN)}
    }
}
AddIcon help=cd size=small mastery=2 { # Berserk Icon
    if CheckBoxOn(cooldownsL) {
        if Stance(1) {
            Spell(BERSERK)
        }
        if Stance(3) {
         if BuffPresent(TIGERSFURY) Spell(BERSERK)
           unless BuffPresent(TIGERSFURY) {
              if Glyph(GLYPHOFBERSERK) {
                 if Mana(more 64) unless 20s before Spell(TIGERSFURY) Spell(BERSERK)
              }
              unless Glyph(GLYPHOFBERSERK) {
                 if Mana(more 64) unless 15s before Spell(TIGERSFURY) Spell(BERSERK)
              }
           }
            if 0s before Spell(BERSERK) Texture(Ability_mount_polarbear_white)
        }
    }
}
AddIcon help=main mastery=2 {
    if Stance(1) {  #bear
        if CheckBoxOn(lucioles) and CheckBoxOff(aoe) and TargetDebuffExpires(lowerarmor 2 stacks=3) {
            Spell(FAERIEFERAL)
        }
       
        if 1s before Spell(MANGLEBEAR) {
            Spell(MANGLEBEAR priority=4)
        }
       
        if CheckBoxOn(demo) and TargetDebuffExpires(lowerphysicaldamage 4) {
            Spell(DEMOROAR)
        }

        unless TargetDebuffPresent(LACERATE stacks=1 mine=1) {
            Spell(LACERATE)
        }
       
        if 0s before Spell(THRASH) {
            Spell(THRASH)
        }

        if TargetDebuffPresent(LACERATE stacks=3) and BuffExpires(PULVERIZEBUFF 1) {
            Spell(PULVERIZE)
        }
       
        unless TargetDebuffPresent(LACERATE stacks=3) {
            Spell(LACERATE)
        }
        if 0s before Spell(FAERIEFERAL) {
            Spell(FAERIEFERAL)
        }
        Spell(LACERATE)
    }

    if Stance(3) { # cat
        unless BuffPresent(BERSERK) or BuffPresent(CLEARCASTING) {
            if Mana(less 36) Spell(TIGERSFURY)
        }
       
        unless TargetInRange(MANGLECAT) {
            Texture(ability_druid_catformattack)
        }

        #refresh PANTHER (T11)
        if ArmorSetParts(T11 more 3) and BuffPresent(PANTHER) and CheckBoxOn(t11) {
            if BuffExpires(PANTHER 4) Spell(MANGLECAT)
        }
   
        if CheckBoxOn(lucioles) and TargetDebuffExpires(lowerarmor 1) and TargetDeadIn(more 15) {
            Spell(FAERIEFERAL)
        }
           
        if TargetDebuffExpires(bleed 1) and CheckBoxOn(mangle) {
            Spell(MANGLECAT)
        }
       
        # Ravage Code - this is the catch all
        if BuffPresent(STAMPEDE) and BuffExpires(STAMPEDE 3) {
            Spell(RAVAGE)
        }
       
        # Berserk Code
        if CheckBoxOn(berserk) {
           if BuffPresent(TIGERSFURY) Spell(BERSERK)
           unless BuffPresent(TIGERSFURY) {
              if Glyph(GLYPHOFBERSERK) {
                 if Mana(more 64) unless 20s before Spell(TIGERSFURY) Spell(BERSERK)
              }
              unless Glyph(GLYPHOFBERSERK) {
                 if Mana(more 64) unless 15s before Spell(TIGERSFURY) Spell(BERSERK)
              }
           }
        }
   
        # Two conditions for FB during Blood of the Water phase
        # Add in FB code for end of fight - only do this is Rip buff is present
        if TalentPoints(BLOODINTHEWATERTALENT more 1) and ComboPoints(more 0) and TargetDebuffExpires(RIP 2.1 mine=1) and TargetLifePercent(less 25) and TargetDebuffPresent(RIP mine=1) {
            Spell(FEROCIOUSBITE)
        }
        if TalentPoints(BLOODINTHEWATERTALENT more 1) and ComboPoints(more 4) and TargetLifePercent(less 25) and TargetDebuffPresent(RIP mine=1) {
            Spell(FEROCIOUSBITE)
        } 
       
        #Extends Rip with shred if glyph
        if Glyph(GLYPHOFSHRED) and TargetDebuffPresent(RIP mine=1) and TargetDebuffExpires(RIP 4 mine=1) and Counter(ripshreds less 3) {
            Spell(SHRED)
        }

        # Burn combo points on FB if the target is about to die - on a boss fight this is redundant with BotW phase
        if ComboPoints(more 4) and TargetDeadIn(less 7) {
            Spell(FEROCIOUSBITE)
        }
       
        # Time to recast Rip - clip if possible
        if ComboPoints(more 4) and TargetDeadIn(more 6) {
            if TargetDebuffExpires(RIP 1.9 mine=1) Spell(RIP)
        }
 
        # clip Rake early if TF is up and rake ramining is less than 9 seconds
        if TargetDebuffExpires(RAKE 8.9 mine=1) and TargetDeadIn(more 8) and BuffPresent(TIGERSFURY) {
          Spell(RAKE)
        }
       
        # intentionally clip Rake to maximize uptime
        if TargetDebuffExpires(RAKE 2.9 mine=1) and TargetDeadIn(more 8.4) {
            Spell(RAKE)
        }
       
        # Savage Roar code - both when it is down and the desync code for Rip and Roar
        if ComboPoints(more 0) and BuffExpires(SAVAGEROAR 1) and TargetDebuffPresent(RIP 6 mine=1) {
            Spell(SAVAGEROAR)
        }
       
        if BuffPresent(STAMPEDE) and BuffPresent(TIGERSFURY) {
            unless BuffPresent(CLEARCASTING) Spell(RAVAGE)
        }
       
        #stack up PANTHER (T11)
        if ArmorSetParts(T11 more 3) and CheckBoxOn(t11) {
            unless BuffPresent(PANTHER stacks=3) Spell(MANGLECAT)
        }
       
        # Conditions for Shreding now that everything else is taken into account
        if Mana(more 69) Spell(SHRED)
        if BuffPresent(CLEARCASTING) or TargetDeadIn(less 10) or BuffPresent(BERSERK) or BuffPresent(TIGERSFURY)
                Spell(SHRED)
        if ComboPoints(less 5) and TargetDebuffExpires(RIP 3 mine=1) Spell(SHRED)
        if ComboPoints(less 1) and BuffExpires(SAVAGEROAR 2) Spell(SHRED)
        if { 3s before Spell(TIGERSFURY) } Spell(SHRED)
    }
}

# Main Rotation (no filler shreds, otherwise copy of other rotation)
AddIcon help=main mastery=2
{
    if Stance(1) {
        if Mana(more 70) {
            Spell(MAUL)
        }
    }

    if Stance(3) { # cat
        unless BuffPresent(BERSERK) or BuffPresent(CLEARCASTING) {
            if Mana(less 36) Spell(TIGERSFURY)
        }

        #refresh PANTHER (T11)
        if ArmorSetParts(T11 more 3) and BuffPresent(PANTHER) and CheckBoxOn(t11) {
            if BuffExpires(PANTHER 4) Spell(MANGLECAT)
        }
   
        if CheckBoxOn(lucioles) and TargetDebuffExpires(lowerarmor 1) and TargetDeadIn(more 15) {
            Spell(FAERIEFERAL)
        }
           
        if TargetDebuffExpires(bleed 1) and CheckBoxOn(mangle) {
            Spell(MANGLECAT)
        }
       
        # Ravage Code - this is the catch all
        if BuffPresent(STAMPEDE) and BuffExpires(STAMPEDE 3) {
            Spell(RAVAGE)
        }
       
        # Berserk Code
        if CheckBoxOn(berserk) {
           if BuffPresent(TIGERSFURY) Spell(BERSERK)
           unless BuffPresent(TIGERSFURY) {
              if Glyph(GLYPHOFBERSERK) {
                 if Mana(more 64) unless 20s before Spell(TIGERSFURY) Spell(BERSERK)
              }
              unless Glyph(GLYPHOFBERSERK) {
                 if Mana(more 64) unless 15s before Spell(TIGERSFURY) Spell(BERSERK)
              }
           }
        }
   
        # Two conditions for FB during Blood of the Water phase
        # Add in FB code for end of fight - only do this is Rip buff is present
        if TalentPoints(BLOODINTHEWATERTALENT more 1) and ComboPoints(more 0) and TargetDebuffExpires(RIP 2.1 mine=1) and TargetLifePercent(less 25) and TargetDebuffPresent(RIP mine=1) {
            Spell(FEROCIOUSBITE)
        }
        if TalentPoints(BLOODINTHEWATERTALENT more 1) and ComboPoints(more 4) and TargetLifePercent(less 25) and TargetDebuffPresent(RIP mine=1) {
            Spell(FEROCIOUSBITE)
        }
       
        #Extends Rip with shred if glyph
        if Glyph(GLYPHOFSHRED) and TargetDebuffPresent(RIP mine=1) and TargetDebuffExpires(RIP 4 mine=1) and Counter(ripshreds less 3) {
            Spell(SHRED)
        }

        # Burn combo points on FB if the target is about to die - on a boss fight this is redundant with BotW phase
        if ComboPoints(more 4) and TargetDeadIn(less 7) {
            Spell(FEROCIOUSBITE)
        }
       
        # Time to recast Rip - clip if possible
        if ComboPoints(more 4) and TargetDeadIn(more 6) {
            if TargetDebuffExpires(RIP 1.9 mine=1) Spell(RIP)
        }
       
        # clip Rake early if TF is up and rake ramining is less than 9 seconds
        if TargetDebuffExpires(RAKE 8.9 mine=1) and TargetDeadIn(more 8.4) and BuffPresent(TIGERSFURY) {
            Spell(RAKE)
        }
       
        # intentionally clip Rake to maximize uptime
        if TargetDebuffExpires(RAKE 2.9 mine=1) and TargetDeadIn(more 8.4) {
            Spell(RAKE)
        }
       
        # Savage Roar code - both when it is down and the desync code for Rip and Roar
        if ComboPoints(more 0) and BuffExpires(SAVAGEROAR 1) and TargetDebuffPresent(RIP 6 mine=1) {
            Spell(SAVAGEROAR)
        }

        if BuffPresent(STAMPEDE) and BuffPresent(TIGERSFURY) {
            unless BuffPresent(CLEARCASTING) Spell(RAVAGE)
        }
       
        #stack up PANTHER (T11)
        if ArmorSetParts(T11 more 3) and CheckBoxOn(t11) {
            unless BuffPresent(PANTHER stacks=3) Spell(MANGLECAT)
        }
    }
}

AddIcon help=cd size=small mastery=2 { # Rake/Manglebear Icon
    if CheckBoxOn(cooldownsR) {
        if Stance(3) {
            if List(cd0 t1) {
                if ArmorSetParts(T11 more 3) {
                   if BuffExpires(PANTHER 0) Spell(MANGLECAT)
               }
               unless ArmorSetParts(T11 more 3) {
                   if TargetDebuffExpires(bleed 0) Spell(MANGLECAT)
               }
            }
            if List(cd0 t2) if TargetDebuffExpires(RAKE 0 mine=1) Spell(RAKE)
            if List(cd0 t3) if TargetDebuffExpires(RIP 0 mine=1) Spell(RIP)
            if List(cd0 t4) if BuffExpires(SAVAGEROAR 0) Spell(SAVAGEROAR)
            if List(cd0 t5) Spell(TIGERSFURY)
            if List(cd0 t6) Item(Trinket0Slot usable=1)
            if List(cd0 t7) Item(Trinket1Slot usable=1)
            if List(cd0 t8) {
               unless BuffPresent(HEEDLESSCARNAGE) {
                  if 0s before BuffGain(HEEDLESSCARNAGE 50) Item(UNHEEDEDWARNING)
               }
               if BuffPresent(HEEDLESSCARNAGE) {
                   if 0s before BuffExpires(HEEDLESSCARNAGE 0) Texture(Spell_deathknight_butcher)
               }
           }
            if List(cd0 t9) {
               unless BuffPresent(TWISTEDH) {
                  if 0s before BuffGain(TWISTEDH 50) Item(ESSENCEOFCYCLONEH)
               }
               if BuffPresent(TWISTEDH) {
                   if 0s before BuffExpires(TWISTEDH 0) Texture(Ability_rogue_dirtydeeds)
               }
           }
        }
        if Stance(1) {
           Spell(SURVIVALINSTINCTS)
        }
    }
}
AddIcon help=cd size=small mastery=2 { # Rip/Swipebear Icon
    if CheckBoxOn(cooldownsR) {
        if Stance(3) {
            if List(cd1 t1) {
                if ArmorSetParts(T11 more 3) {
                   if BuffExpires(PANTHER 0) Spell(MANGLECAT)
               }
               unless ArmorSetParts(T11 more 3) {
                   if TargetDebuffExpires(bleed 0) Spell(MANGLECAT)
               }
            }
            if List(cd1 t2) if TargetDebuffExpires(RAKE 0 mine=1) Spell(RAKE)
            if List(cd1 t3) if TargetDebuffExpires(RIP 0 mine=1) Spell(RIP)
            if List(cd1 t4) if BuffExpires(SAVAGEROAR 0) Spell(SAVAGEROAR)
            if List(cd1 t5) Spell(TIGERSFURY)
            if List(cd1 t6) Item(Trinket0Slot usable=1)
            if List(cd1 t7) Item(Trinket1Slot usable=1)
            if List(cd1 t8) {
               unless BuffPresent(HEEDLESSCARNAGE) {
                  if 0s before BuffGain(HEEDLESSCARNAGE 50) Item(UNHEEDEDWARNING)
               }
               if BuffPresent(HEEDLESSCARNAGE) {
                   if 0s before BuffExpires(HEEDLESSCARNAGE 0) Texture(Spell_deathknight_butcher)
               }
            }
            if List(cd1 t9) {
               unless BuffPresent(TWISTEDH) {
                  if 0s before BuffGain(TWISTEDH 50) Item(ESSENCEOFCYCLONEH)
               }
               if BuffPresent(TWISTEDH) {
                   if 0s before BuffExpires(TWISTEDH 0) Texture(Ability_rogue_dirtydeeds)
               }
           }
        }
        if Stance(1) {
            Spell(FRENZIEDREGENERATION)
        }
    }
}
AddIcon help=cd size=small mastery=2 { # Rake/Manglebear Icon
    if CheckBoxOn(cooldownsR) {
        if Stance(3) {
            if List(cd2 t1) {
                if ArmorSetParts(T11 more 3) {
                   if BuffExpires(PANTHER 0) Spell(MANGLECAT)
               }
               unless ArmorSetParts(T11 more 3) {
                   if TargetDebuffExpires(bleed 0) Spell(MANGLECAT)
               }
            }
            if List(cd2 t2) if TargetDebuffExpires(RAKE 0 mine=1) Spell(RAKE)
            if List(cd2 t3) if TargetDebuffExpires(RIP 0 mine=1) Spell(RIP)
            if List(cd2 t4) if BuffExpires(SAVAGEROAR 0) Spell(SAVAGEROAR)
            if List(cd2 t5) Spell(TIGERSFURY)
            if List(cd2 t6) Item(Trinket0Slot usable=1)
            if List(cd2 t7) Item(Trinket1Slot usable=1)
            if List(cd2 t8) {
               unless BuffPresent(HEEDLESSCARNAGE) {
                  if 0s before BuffGain(HEEDLESSCARNAGE 50) Item(UNHEEDEDWARNING)
               }
               if BuffPresent(HEEDLESSCARNAGE) {
                   if 0s before BuffExpires(HEEDLESSCARNAGE 0) Texture(Spell_deathknight_butcher)
               }
           }
            if List(cd2 t9) {
               unless BuffPresent(TWISTEDH) {
                  if 0s before BuffGain(TWISTEDH 50) Item(ESSENCEOFCYCLONEH)
               }
               if BuffPresent(TWISTEDH) {
                   if 0s before BuffExpires(TWISTEDH 0) Texture(Ability_rogue_dirtydeeds)
               }
           }
        }
    }
}
AddIcon help=cd size=small mastery=2 { # Rip/Swipebear Icon
    if CheckBoxOn(cooldownsR) {
        if Stance(3) {
            if List(cd3 t1) {
                if ArmorSetParts(T11 more 3) {
                   if BuffExpires(PANTHER 0) Spell(MANGLECAT)
               }
               unless ArmorSetParts(T11 more 3) {
                   if TargetDebuffExpires(bleed 0) Spell(MANGLECAT)
               }
            }
            if List(cd3 t2) if TargetDebuffExpires(RAKE 0 mine=1) Spell(RAKE)
            if List(cd3 t3) if TargetDebuffExpires(RIP 0 mine=1) Spell(RIP)
            if List(cd3 t4) if BuffExpires(SAVAGEROAR 0) Spell(SAVAGEROAR)
            if List(cd3 t5) Spell(TIGERSFURY)
            if List(cd3 t6) Item(Trinket0Slot usable=1)
            if List(cd3 t7) Item(Trinket1Slot usable=1)
            if List(cd3 t8) {
               unless BuffPresent(HEEDLESSCARNAGE) {
                  if 0s before BuffGain(HEEDLESSCARNAGE 50) Item(UNHEEDEDWARNING)
               }
               if BuffPresent(HEEDLESSCARNAGE) {
                   if 0s before BuffExpires(HEEDLESSCARNAGE 0) Texture(Spell_deathknight_butcher)
               }
            }
            if List(cd3 t9) {
               unless BuffPresent(TWISTEDH) {
                  if 0s before BuffGain(TWISTEDH 50) Item(ESSENCEOFCYCLONEH)
               }
               if BuffPresent(TWISTEDH) {
                   if 0s before BuffExpires(TWISTEDH 0) Texture(Ability_rogue_dirtydeeds)
               }
           }
        }
    }
}
Last edited by Leafkiller on Tue Mar 01, 2011 8:03 pm, edited 18 times in total.

Exalted
User avatar
Posts: 1145
Joined: Fri Jun 04, 2010 4:28 am

Re: Leafkiller's 4.01 Feral Ovale Script

Postby Leafkiller » Wed Oct 20, 2010 5:37 pm

Below is the most current Mew script I use to help tune the Ovale script.

I just refactored the code. I am no longer breaking it into separate sections since the introduction of interrupt and feral charge modeling has added dependencies between the sections of the script and made it annoying to maintain - especially when merging new versions of the default script into it. This script contains a full copy of the 2/15 version of the default mew sim script along with 2 copies of my sim script - one that I use for experimenting on before merging the changes into the other copy.

I have put all three copies into a single script file because the I/O for Mew is slow and it is significantly faster to change a variable at the top of my script file to point to the different scripts than it is to load different scripts into Mew.

Make sure you get the latest version of Mew to test this with - it requires the version released on 4/12/2011 (or later)

Version 20 is based on an unreleased version of Mew that has the Berserk GCD change included. To properly test this you will need to create a build environment for Mew - or you can wait for the next release to be posted.

Version 19 reflects the 4/12/2011 release of Mew. The experimental rotation is currently set to emulate the Atremedes fight with the timings taken from DBM.

Version 18 has Berserk code that explicitly differentiates the energy levels with and without TF up (both min and max energy levels)

Version 17 supports interrupts and Feral Charge modeling - code is copied/merged over from the default Mew script. This allows comparisons of both rotations while modeling FC/interrupts.

==========================

The version below has been tested and optimized for the Tier 11 4 piece set bonus (it also works if you do not have 4 piece T11 per your Mew profile setup).

I have tested many different options including things such as pooling energy for FB and trying to sync Rip/Rake to the next TF when they are close in time - and so far have only found these to be dps losses. The interactions of the various abilities (especially OOC) are very complex and sometimes what we think might be a dps increase based on some napkin math, is actually a dps loss (in the simulator). There is a leap of faith that the simulator is modeling everything properly.

Code: Select all
//
// Sample Simulator Script
//
// Yawning <yawninglol at gmail.com>
// (Leaf v20 16 apr 2011)
//    Changed the Berserk code to optimize for Berserk being removed from the GCD. In my script, I have included three versions of the
//    Berserk code, with two commented out. These are the decault script's 4.06 code, my 4.06 code and the new 4.1 code. This is to
//    make it easier to compare the different schemes and see how dps is affected.
// (Leaf v19 13 apr 2011)
//    Merge in the latest version of the default script. Update the code in my scripts to match the code at the start of the default
//    script up to the TF code (which looks identical now anyways). This is the external abilities/events code, the feral charge code
//    and the interrupt code. The code for taking the potion of Tol'vir needed to be after the code that turns on auto_attack...
//    Also changed the Atremedes code in the experimental rotation to use the new options for combat length, time in combat and disabling
//    auto-attack. The timings in the Atremedes code have been changed to match the fight rather than being approximations. This data
//    is based on the values used in DBM. Also merged the Berserk length and time to die into my berserk code.
// (Leaf v18 24 feb 2011)
//    Tune the Berserk energy levels some. Specifically account for when Berserk is happening during TF. Used actual energy numbers
//    rather than taking into account energy regen - because I use this to tune my Ovale script and I don't trust the energy
//    regen code in Ovale. The dps difference between this approach and energy regen is minimal.
// (Leaf v17 21 Feb 2011)
//    Restructure into complete scripts rather than the separate sections. Due to the addition of interrupts and mid-encounter FC,
//    the sections now have dependencies which is making maintenance more annoying. FC and interrupt code has been merged into
//    my scripts - most of it is directly from Yawning's code.
// (Leaf v16, 18 Feb 2011)
//    Update the default script to the 2/15 version Yawning released. Need to reconcile the scripts to see what improvements
//    Yawning made on this version (his last?). Move in-combat FC code into my main script (from experimental script - Yawning's code).
//    Added isInGCD() check to TF in my code. The question is how to add this to Ovale as it is about 100dps.
// (Leaf v15, 7 Feb 2011)
//    Update the default script to the one released for patch 4.06. Remove Fb before 25% and also SR desync code from the rotation.
//    The FB change measures as a 32dps increase on my test profile. The SR change was a 0.1 dps decrease (noise).
// (Leaf v14, 30 Jan 2011)
//    Update the default script to the one Yawning created for 4.06 on 1/30/2011. Also add the Ravage code to the experimental section.
// (Leaf v13, 11 Jan 2011)
//    Experimental work on SR limiting - not resyncing during Berserk is a 1dps up. All other SR attempts seemed to fail.
//    With default script and 4.06 parms, Glyph of FB is a dps loss, while for my script it is a DPS gain.
// (Leaf v12, 24 Nov 2010)
//    Update the default script to the one Yawning created 11/23.
// (Leaf v11, 20 Nov 2010)
//    Change prelude to use defualt TF handling for level 80 toons. Change Rake code to include Mihir's Rake cliping for TF. Also
//    add in the code to not pool energy on Shred during TF (also from Mihir).
// (Leaf v10, 19 Nov 2010)
//    The experimental main section includes code to better test waiting on Rip/Rake for TF. It shows as a very small dps up
//    which is unlikely to carry over into actual play. If I can find a way to make it mroe substantial I will modify the
//    Ovale script. Just set "int mainRotation = 2;" to use it.
// (Leaf v9, 18 Nov 2010)
//    Add a fifth section called Debuffs (not the best name) that has mangle, FFF, blood in the water, Ravage. This is
//    just before the main rotation. The reason is to separate out the portion of the rotation that is very sensitive to
//    stat changes such as crit and haste to better isolate script differences and ultiately focus on areas to optimize.
// (Leaf v8, 17 Nov 2010)
//    Use the getLevel function to toggle FB limits on SR/Rip so the script works for level 80 and 85.
//    Also removed the extra FB during berserk from the default script code - with hte latest Mew this is now shows as dps
//    loss (using the High Resolution Timer).
// (Leaf v7, 17 Nov 2010)
//    Refactor the code into a series of sections so that I can toggle back and forth between
//    different versions of the script. Merge the default script into this one - both
//    scripts are now included (this is the modified default script for level 85 t11)
// (Leaf v6, 15 Nov 2010 - added code to FB more often during Berserk - small dps up)
// (Leaf v5, 14 Nov 2010 - refined level 85 sim)
//    Clip mangle with 4 seconds to spare for refreshing t11 Panther buff and also move the refresh code
//    above everything but TF - it is the first GCD. This is a 50dps increase - apparently the cost of letting
//    the buff drop is much higher than the loss from clipping it. May change the RSV for hit/exp.
// (leaf v4, 7 Nov 2010 - level 85 sim)
//    Put in code to support tier 11 4 piece set bonus. Change FB to 12 second windows from 8.
// (Leaf v3, 22 Oct 2010)
//    Modeled refresh of Blood in the Water at 2.1 seconds in case Rip falls off. Tiny dps loss - so left in for safety.
//    Put in code to not desync SR/RIp in Blood in the Water phase to preserve combo points. Dps neutral - left in.
// (Leaf v2, 20 Oct 2010)
//    Move FB after Rake - yields 30dps increase with Yawning.mew
// (Alaron v2 (After Buffs Edition), 15 Oct 2010)
// (Alaron v1, 8 Oct 2010)
// (Leaf v1, 17 Oct 2010)
//    Note - this script incorporates a lot Alaron's most recent modifications to Yawning's model - which is now the default model.
//    Most of the testing was done using Yawning.mew.
//    This was developed in conjunction with an Ovale script and they are very close to one another in functionality.
//          The Ovale script can be found at: http://fluiddruid.net/forum/viewtopic.php?p=427#p427
//    Since it is not always possible to clip Rip in game,
//          this script has no Rip clipping in it. The default script clips Rip with 2 seconds left.
//    Some differences: SR handling is different - it is prioritized below Rip. There is no special OOC handling -
//          OOC procs are just used in the normal rotation. This makes the rotation easier to use in game as it does
//          not swap to Shred on a proc. The code to desync Rip and SR is different as it incorporates the prioritization of Rip over SR.
//    DPS is 7 below the default script, although it is 28 above if 2 second Rip clipping is added to this script.
//          In other words, the two scripts are very close in total DPS.
//          If the simulator is not taking into account "A more powerful spell is already active,"
//          then the results for the default script are not accurate. I am guessing this is not being modeled right now.
//
// Default CatModelSimulatorScript
//
// Yawning <yawninglol at gmail.com>
// Elements from:
//  Alaron v2 (After Buffs Edition), 15 Oct 2010
//  Leafkiller's testing/scripts
//  Mihir's testing
//  SimulationCraft (r4522, level 80 profile)
//  Toskk's testing/scripts
//
// WARNING: This routine is invoked every time the Simulator thinks it's a good idea
// to query the user for input.  While the temptation may be there to pop open a window
// and render fractals, doing so is strongly advised against.
//

//
// Determine what action to take if any.
//
// Valid return values:
//  Off GCD:
//   Action.TIGERSFURY
//   Action.FERALCHARGE
//   Action.SKULLBASH
//   Action.POTION
//   Action.HEROISM
//   Action.UNHOLYFRENZY
//   Action.SHATTERINGTHROW
//   Action.RUNAWAY (Gain distance to allow Feral Charge use)
//   Action.AUTOATTACK_START
//   Action.AUTOATTACK_STOP
//
//  On GCD:
//   Action.RAVAGE
//   Action.MANGLE
//   Action.RAKE
//   Action.SHRED
//   Action.RIP
//   Action.BITE
//   Action.ROAR
//   Action.FERALFF
//   Action.BERSERK
//

//
// Base logic stolen from SimulationCraft (r4522)
// http://code.google.com/p/simulationcraft/source/browse/trunk/profiles/Druid_T10_00_55_16_M.simc
//    

public IAction getAction(IStatus stat) {
   
   CatModelSimState status = (CatModelSimState)stat;
   
   IAction sectionResult;
   // switch values to select which rotation to use - 0 is the default, 1 is my rotation, 2 is the experimental rotation.
   int rotation = 1;   

   // Global bufs (and potions) - make it a switch statement to support future mods
   switch (rotation) {
      case 1:
         sectionResult = leafRotation(status);
         break;
      case 2:
         sectionResult = expRotation(status);
         break;
      default:
         sectionResult = defaultRotation(status);
   }
   return(sectionResult);
}

// Default script
private IAction defaultRotation(CatModelSimState status) {

   double timeToDie = status.getTimeRemaining();
   int energy = status.getEnergy();
   int energyPerSec = (int) Math.floor(1.0 / status.getEnergyTickInterval());
   int cps = status.getComboPoints();

   boolean canTF = (!status.isBerserkUp() && status.getTigersFuryCD() == 0.0);
   boolean canBerserk = (status.getBerserkCD() == 0.0);

   double ripRemaining = status.getRipRemaining();
   double srRemaining = status.getSavageRoarRemaining();
   double rakeRemaining = status.getRakeRemaining();
   double ripSRSyncTimer = (double) Math.abs(ripRemaining - srRemaining);
   double berserkBaseDuration = status.getBerserkBaseDuration();
   double nextUtilityCastIn = status.nextUtilityCastIn();

   //
   // External Abilities/events.
   //

   // Heroism
   //
   // Note: This doesn't handle "encounters that would result in non-integer uses of heroism"
   // at all.  Defining default behavior for that case is more a matter of personal taste.
   if (status.getHeroismCD() == 0.0) {
      // If the mob will die as heroism is falling off if we use it now, use it.
      if (timeToDie <= 40)
         return Action.HEROISM;

      // If we will get a full heroism in at the end of the fight if we use it now, use it.
      if (timeToDie >= 600 + 40)
         return Action.HEROISM;
   }

   // Shattering throw
   if (status.getShatteringThrowCD() == 0.0) {
      // If heroism is up, use it.
      if (status.isHeroismUp())
         return Action.SHATTERINGTHROW;

      // If the mob will die as Shattering Throw is falling off if we use it now, use it.
      if (timeToDie < 10)
         return Action.SHATTERINGTHROW;

      // If we will get the full Shattering Throw in at the end of the fight if we use it now, use it.
      if (timeToDie >= 300 + 10)
         return Action.SHATTERINGTHROW;
   }

   // Unholy Frenzy
   //
   // Just simulate the DK using this on cooldown for now.  More sophisticated things
   // like stacking it with Berserk or Heroism could be done.
   if (status.getUnholyFrenzyCD() == 0.0)
      return Action.UNHOLYFRENZY;

   // EXAMPLE - Simulate forced DPS stop.
//   if (status.getElapsedTime() > 30 && status.getElapsedTime() < 60) {
//      // Stop the swing timer.
//      if (status.isAutoAttackEnabled()) return Action.AUTOATTACK_STOP;
//
//      return null;
//   }

   //
   // Druid abilities that are off the GCD.
   //

   // Feral Charge to get Stampede up if we are not in combat.
   if (!status.isInCombat() && status.getFeralChargeCD() == 0.0)
      return Action.FERALCHARGE;

   // Feral Charge to get Stampede up if we can.
   if (status.shouldAggressiveFeralCharge() && status.canFeralCharge())
      return Action.FERALCHARGE;

   // Don't bother trying to do anything else if we are out of melee range.
   if (!status.isInMeleeRange()) return null;

   // Start the swing timer if needed.
   if (!status.isAutoAttackEnabled())
      return Action.AUTOATTACK_START;

   // Potion of Tol'vir
   if (status.canPotion()) {
      // Pre-potion.
      if (!status.isInCombat())
         return Action.POTION;

      if (status.isHeroismUp() || timeToDie < 40)
         return Action.POTION;
   }

   // If the target is casting, interrupt it if we can.
   if (status.isTargetCasting() && status.getSkullBashCD() == 0.0) {
      // Use Tiger's Fury to get energy to interrupt if needed.
      if (energy < status.getSkullBashCost() && canTF == true)
         return Action.TIGERSFURY;

      return Action.SKULLBASH;
   }

   // Start pooling energy for interrupts.
   boolean interruptSoon = false;
   if (status.shouldSkullBash()) {
      double timeToNextCast = status.nextCastIn();

      // Only bother pooling assuming we can manage to interrupt.
      if (status.getSkullBashCD() <= timeToNextCast + status.getTargetCastTime()) {
         // Use base energy regen instead of energyPerSec to be somewhat conservative.
         double poolReqTime = status.getSkullBashCost() / 10;
         double expectedEnergyRegen = timeToNextCast * 10;

         // Pool assuming we do not have OoC up, and next cast is soon.
         if (timeToNextCast <= poolReqTime) {
            if (!status.isOoCUp() && energy + expectedEnergyRegen < status.getShredCost() + status.getSkullBashCost()) {
               return null;
            }

            // Determine if it's "safe" to allow Ferocious Bite (Assume no Glyph)
            int biteCost = (status.isOoCUp()) ? 0 : status.getFerociousBiteCost();
            int extraEnergy = Math.min(35, energy - biteCost);

            if (energy - (biteCost + extraEnergy) + expectedEnergyRegen < status.getSkullBashCost())
               interruptSoon = true;
         }
      }
   }

   // Note: Ensuring that we are off the GCD will allow for one more ability while the buff is up.
   if (status.getLevel() == 80) {
      if (energy <= 26 && canTF == true && !status.isInGCD())
         return Action.TIGERSFURY;
   } else {
      if (energy <= 35 && canTF == true && !status.isInGCD() && !status.isOoCUp())
         return Action.TIGERSFURY;
   }

   //
   // Druid abilities that are on the GCD.
   //

   // Raid debuffs:

   // Mangle if the 4T11 bonus is about to fall off.
   if (status.hasTier_11_4pc() && status.getTier_11_4pcRemaining() <= 4)
      return Action.MANGLE;

   // Faerie Fire if it's not up.
   if (status.getFeralFFCD() == 0.0 && status.shouldFF() && (status.getFeralFFStacks() < 3 || status.getFeralFFRemaining() <= 1))
      return Action.FERALFF;

   // Mangle to get debuff up.
   if ((status.getMangleRemaining() <= 2 | !status.isMangleUp()) && status.shouldMangle())
      return Action.MANGLE;

   // Ravage/Blood in the Water:

   // Ravage if Stampede will drop during the next global...we don't want to lose the free Ravage.
   if (status.isStampedeUp() && status.getStampedeRemaining() <= 2.0)
      return Action.RAVAGE;

   // Since Berserk does not clip Tiger's Fury anymore, stacking is ideal but makes this encounter sensitive.
   // For now Berserk whenever we are at the correct energy level, and when it won't push back the next TF.
   // The difference between the two appears to be < 10 DPS.
   if (energy <= (status.getEnergyCap() - (energyPerSec*2)) && canBerserk && (status.getTigersFuryCD() > berserkBaseDuration || timeToDie < status.getTigersFuryCD() + berserkBaseDuration))
      return Action.BERSERK;

   if (!interruptSoon) {
      // Ferocious Bite to extend Rip if we are at > 0 cps, are in BitW range, and Rip is about to fall.
      if (cps >= 1 && status.isRipUp() && ripRemaining <= 1 && status.isInBloodInTheWaterRange())
         return Action.BITE;

      // Ferocious Bite if we are at 5 cps, Rip is up, and we are in BitW range.
      if (cps == 5 && status.isRipUp() && status.isInBloodInTheWaterRange())
         return Action.BITE;
   }

   // Regular Rotation:

   // Shred if you can utilize Glyph of Shred to extend Rip.
   if (status.getRipShredExtRemaining() > 0 && ripRemaining <= 4 && status.isRipUp() && !status.isInBloodInTheWaterRange())
      return Action.SHRED;

   // Rip at 5 CP if enemy will live for 3 ticks and Rip has 2sec or less.
   if (cps >= 5 && timeToDie >= 6 && (!status.isRipUp() || ripRemaining < 2.0) && (status.isBerserkUp() || ripRemaining <= status.getTigersFuryCD()))
      return Action.RIP;

   // Clip Rake if the existing Rake has < 9 sec left, and we have TF up.
   // Per Mihir/Leafkiller - Substantial gain.  At 85, across a vast array of gear points 9.0 sec appears optimal.
   if (timeToDie >= 8.5 && status.isTigersFuryUp() && !status.isRakeTFed() && rakeRemaining < 9.0)
      return Action.RAKE;

   // Rake if the enemy will live for the full duration of Rake and Rake has 3sec or less.
   // Allow for slight pushback on Rake refresh depending on the TF CD since it's a marginal gain.
   if (timeToDie >= 8.5 && (!status.isRakeUp() || rakeRemaining < 3.0) && (status.isBerserkUp() || rakeRemaining - 0.8 <= status.getTigersFuryCD() || energy >= 71))
      return Action.RAKE;

   // Shred on OOC.
   if (status.isOoCUp())
      return Action.SHRED;

   // Savage Roar if it's down or about to drop.
   if (cps > 0 && (!status.isSavageRoarUp() || srRemaining <= 1) && ripRemaining >= 6)
      return Action.ROAR;

   // Rip/SR Desync; If Rip has 12s or less left, you have 5 CPs, and SR will expire within 3s of Rip expiring, go ahead and SR now.
   // Note: Per Toskk removing this entirely can produce higher DPS though it's CP generation(?) dependent.
   if (cps >= 5 && timeToDie >= 9 && (ripRemaining <= 12 && ripSRSyncTimer <= 3))
      return Action.ROAR;

   if (!interruptSoon) {
      // Ferocious Bite if they'll die soon.
      if (cps == 5 && timeToDie <= 7)
         return Action.BITE;

      // Ferocious Bite if you have 5 cp's and FB/SR have more than <Number here> sec left on their timers.
      // (Messed with this extensively; not much of an effect on DPS. Relook at 85.)
      // (Leafkiller says 12 sec for 85.  Toskk says 14 sec for 85.)
      //
      // Technically speaking I can remove this for 4.0.6.  Simming a 372 geared Feral Druid,
      // the difference between having it and not is not statistically significant (DPS difference <
      // error of the sim).
      if (!status.isBerserkUp() || energy < 25) {
         if (status.getLevel() == 80) {
            if (cps == 5 && ripRemaining >= 8 && srRemaining >= 4)
               return Action.BITE;
         } else {
            // As of 4.0.6, there is no point in using Ferocious Bite at all.
            //if (cps == 5 && ripRemaining >= 14 && srRemaining >= 10)
            //   return Action.BITE;
         }
      }
   }

   // Ravage If Stampede/TF is up and OoC is not.
   if (status.isStampedeUp() && !status.isOoCUp() && status.isTigersFuryUp())
      return Action.RAVAGE;

   // Mangle if the 4T11 bonus is not at 3 stacks.
   if (status.hasTier_11_4pc() && status.getTier_11_4pcStacks() < 3)
      return Action.MANGLE;

   // Shred aggressively if Tiger's Fury is up.
   if (status.isTigersFuryUp())
      return Action.SHRED;

   // Shred to build CP's if we have 4 CP's or less, Rip/Rake isn't about to drop, and we have "enough" energy.
   // Note: Using "80" instead of "100 - energyPerSec" produces comparable DPS.
   if (cps <= 4 && rakeRemaining > 3 && ripRemaining > 3)
      if (energy >= (100 - energyPerSec) || (status.isBerserkUp() && energy >= 20))
         return Action.SHRED;

   // Shred if we need to burn energy off so we can TF without capping.
   if (status.getTigersFuryCD() <= 3)
      return Action.SHRED;

   // Shred if they're going to die within one Rake.
   if (timeToDie <= 8.5)
      return Action.SHRED;

   // Shred if you have 0 CP's and SR is about to drop, and Rake has "enough" time left.
   if (cps == 0 && (srRemaining <= 2 || rakeRemaining >= 5))
      return Action.SHRED;

   // Fallback Shred to prevent energy capping or doing nothing with rip down.
   if (!status.isRipUp() || energy >= (status.getEnergyCap() - energyPerSec) || status.isBerserkUp())
      return Action.SHRED;

   // Allow Stampede + Ravage! when out of opener.
   if (status.shouldAggressiveFeralCharge() && !interruptSoon) {
      double travelTime = status.getFeralChargeTotalTime();

      // Running away right as you are about to cast Tranquility or Rebirth is a DPS loss, avoid it.
      //
      // Note: The engine will force the "player" to hold the GCD for Rebirth/Tranquility so include
      // some padding when figuring out if we can do this or not.
      if (nextUtilityCastIn > travelTime + 2) {
         // Some bosses allow us to Feral Charge at point blank range.
         if (travelTime > 0) {
            // WARNING - This is still relatively unoptimized.  There's clearly a point where it's not worth
            // attempting to do this at all (too much DPS time lost, ~3 sec).
            //
            // Note: The script will time it so that you run out right when Feral Charge is going to come off
            // CD when you are done.
            //
            // Per Leafkiller, ensuring that Rake won't fall off is a minimal gain.  Micro managing this
            // around both Rake/Rip is fairly minimal due to Rake/Rip having massively higher priority.
            if (!(status.shouldSkullBash() && status.nextCastIn() < travelTime) && !(status.isBerserkUp() || status.isTigersFuryUp()) && status.getFeralChargeCD() < travelTime)
               if (rakeRemaining > travelTime + 2.9)
                  return Action.RUNAWAY;
         }
      }
   }

   // Commented snippets:

   // Rip if the the existing one does not have TF.  (Appears to be a DPS loss, retest later)
//   if (cps == 5 && timeToDie >= 6 && status.isTigersFuryUp() && !status.isRipTFed())
//      return Action.RIP;

   // Shred if Stampede is up, and Tiger's Fury is not if that lets us TF. (Opener)
//   if (status.isStampedeUp() && !status.isTigersFuryUp() && energy + energyPerSec - status.getShredCost() <= 30)
//      return Action.SHRED;

   return null;
}


//=======================================================================================================

// My rotation
private IAction leafRotation(CatModelSimState status) {

   double timeToDie = status.getTimeRemaining();
   int energy = status.getEnergy();
   int energyPerSec = (int) Math.floor(1.0 / status.getEnergyTickInterval());
   int cps = status.getComboPoints();
   
   double tfRemaining = status.getTigersFuryCD();
   boolean canTF = (!status.isBerserkUp() && tfRemaining == 0.0);
   boolean canBerserk = (status.getBerserkCD() == 0.0);

   double ripRemaining = status.getRipRemaining();
   double srRemaining = status.getSavageRoarRemaining();
   double rakeRemaining = status.getRakeRemaining();
   double brRemaining = status.getBerserkRemaining();
   double ripSRSyncTimer = (double) Math.abs(ripRemaining - srRemaining);
   double berserkBaseDuration = status.getBerserkBaseDuration();
   double nextUtilityCastIn = status.nextUtilityCastIn();
   

   //
   // External Abilities/events.
   //

   // Heroism
   //
   // Note: This doesn't handle "encounters that would result in non-integer uses of heroism"
   // at all.  Defining default behavior for that case is more a matter of personal taste.
   if (status.getHeroismCD() == 0.0) {
      // If the mob will die as heroism is falling off if we use it now, use it.
      if (timeToDie <= 40)
         return Action.HEROISM;

      // If we will get a full heroism in at the end of the fight if we use it now, use it.
      if (timeToDie >= 600 + 40)
         return Action.HEROISM;
   }

   // Shattering throw
   if (status.getShatteringThrowCD() == 0.0) {
      // If heroism is up, use it.
      if (status.isHeroismUp())
         return Action.SHATTERINGTHROW;

      // If the mob will die as Shattering Throw is falling off if we use it now, use it.
      if (timeToDie < 10)
         return Action.SHATTERINGTHROW;

      // If we will get the full Shattering Throw in at the end of the fight if we use it now, use it.
      if (timeToDie >= 300 + 10)
         return Action.SHATTERINGTHROW;
   }

   // Unholy Frenzy
   //
   // Just simulate the DK using this on cooldown for now.  More sophisticated things
   // like stacking it with Berserk or Heroism could be done.
   if (status.getUnholyFrenzyCD() == 0.0)
      return Action.UNHOLYFRENZY;

   // EXAMPLE - Simulate forced DPS stop.
//   if (status.getElapsedTime() > 30 && status.getElapsedTime() < 60) {
//      // Stop the swing timer.
//      if (status.isAutoAttackEnabled()) return Action.AUTOATTACK_STOP;
//
//      return null;
//   }

   //
   // Druid abilities that are off the GCD.
   //

   // Feral Charge to get Stampede up if we are not in combat.
   if (!status.isInCombat() && status.getFeralChargeCD() == 0.0)
      return Action.FERALCHARGE;

   // Feral Charge to get Stampede up if we can.
   if (status.shouldAggressiveFeralCharge() && status.canFeralCharge())
      return Action.FERALCHARGE;

   // Don't bother trying to do anything else if we are out of melee range.
   if (!status.isInMeleeRange()) return null;

   // Start the swing timer if needed.
   if (!status.isAutoAttackEnabled())
      return Action.AUTOATTACK_START;

   // Potion of Tol'vir
   if (status.canPotion()) {
      // Pre-potion.
      if (!status.isInCombat())
         return Action.POTION;

      if (status.isHeroismUp() || timeToDie < 40)
         return Action.POTION;
   }

   // If the target is casting, interrupt it if we can.
   if (status.isTargetCasting() && status.getSkullBashCD() == 0.0) {
      // Use Tiger's Fury to get energy to interrupt if needed.
      if (energy < status.getSkullBashCost() && canTF == true)
         return Action.TIGERSFURY;

      return Action.SKULLBASH;
   }

   // Start pooling energy for interrupts.
   boolean interruptSoon = false;
   if (status.shouldSkullBash()) {
      double timeToNextCast = status.nextCastIn();

      // Only bother pooling assuming we can manage to interrupt.
      if (status.getSkullBashCD() <= timeToNextCast + status.getTargetCastTime()) {
         // Use base energy regen instead of energyPerSec to be somewhat conservative.
         double poolReqTime = status.getSkullBashCost() / 10;
         double expectedEnergyRegen = timeToNextCast * 10;

         // Pool assuming we do not have OoC up, and next cast is soon.
         if (timeToNextCast <= poolReqTime) {
            if (!status.isOoCUp() && energy + expectedEnergyRegen < status.getShredCost() + status.getSkullBashCost()) {
               return null;
            }

            // Determine if it's "safe" to allow Ferocious Bite (Assume no Glyph)
            int biteCost = (status.isOoCUp()) ? 0 : status.getFerociousBiteCost();
            int extraEnergy = Math.min(35, energy - biteCost);

            if (energy - (biteCost + extraEnergy) + expectedEnergyRegen < status.getSkullBashCost())
               interruptSoon = true;
         }
      }
   }

   // actions+=/tigers_fury,if=energy<=30&!buff.berserk.up
   if (status.getLevel() == 80) {
      if (energy <= 26 && canTF == true && !status.isInGCD() )
         return Action.TIGERSFURY;;
   } else {
      if (energy <= 35 && canTF == true && !status.isInGCD() && !status.isOoCUp())
         return Action.TIGERSFURY;
   }
   
   //
   // Druid abilities that are on the GCD.
   //

   // Raid debuffs:
   
   // Mangle if the 4T11 bonus is about to fall off.
   if (status.hasTier_11_4pc() && status.getTier_11_4pcRemaining() <= 4)
      return Action.MANGLE;

   // actions+=/faerie_fire_feral,debuff_only=1
   if (status.getFeralFFCD() == 0.0 && status.shouldFF() && (status.getFeralFFStacks() < 3 || status.getFeralFFRemaining() <= 1))
      return Action.FERALFF;
     
   // actions+=/mangle_cat,mangle<=1 (Alaron: Same logic as FF...rDPS increases go first.)
   if (status.getMangleRemaining() <= 1 && status.shouldMangle())
      return Action.MANGLE;   

   // Ravage if Stampede will drop during the next global.
   if (status.isStampedeUp() && status.getStampedeRemaining() <= 2.0)
      return Action.RAVAGE;

   // actions+=/berserk_cat,if=energy>=80&energy<=90&!buff.tigers_fury.up
   // Since Berserk does not clip Tiger's Fury anymore, stacking is ideal but makes this encounter sensitive.
   // For now Berserk whenever we are at the correct energy level, and when it won't push back the next TF.
   // The difference between the two appears to be < 10 DPS.
   // Note - with Glyph of Berserk you want a minimum energy level - but with Glyph of TF it does not seem to matter much.
   if (status.isTigersFuryUp() && !status.isInGCD()) {
      if (energy > 0 && canBerserk)
         return Action.BERSERK;
   } else {
      if (energy > 64 && canBerserk && !status.isInGCD() && (tfRemaining > berserkBaseDuration || timeToDie < tfRemaining + berserkBaseDuration))
         return Action.BERSERK;
   }
   /*if (status.isTigersFuryUp()) {
      if (energy > 84 && energy <= 100 && canBerserk)
         return Action.BERSERK;
   } else {
      if (energy > 64 && energy <= 80 && canBerserk && (tfRemaining > berserkBaseDuration || timeToDie < tfRemaining + berserkBaseDuration))
         return Action.BERSERK;
   }*/
   /*if (energy <= (status.getEnergyCap() - (energyPerSec*2)) && canBerserk && (status.getTigersFuryCD() > berserkBaseDuration || timeToDie < status.getTigersFuryCD() + berserkBaseDuration))
      return Action.BERSERK;*/

   if (!interruptSoon) {
      // Ferocious Bite if we are at > 0 cps, are in Feast Of Flesh range, and Rip is about to fall.
      // (Alaron: Shouldn't these conditionals come first? Else you're never refreshing Rip via FB.)
      if (cps > 0 && status.isRipUp() && ripRemaining <= 2.1 && status.isInBloodInTheWaterRange())
         return Action.BITE;

      // Ferocious Bite if we are at 5 cps, Rip is up, and we are in Feast Of Flesh range.
      if (cps == 5 && status.isRipUp() && status.isInBloodInTheWaterRange())
         return Action.BITE;
   }
   
   // Regular Rotation:
   
   // actions+=/shred,extend_rip=1,if=dot.rip.remains<=4
   if (status.getRipShredExtRemaining() > 0 && ripRemaining <= 4 && status.isRipUp())
      return Action.SHRED;

   if (cps == 5 && timeToDie < 7 && !interruptSoon)
      return Action.BITE;

   // actions+=/rip,if=buff.combo_points.stack>=5&target.time_to_die>=6
   if (cps >= 5 && timeToDie >= 6 && (!status.isRipUp() || ripRemaining < 2.0)) {
      return Action.RIP;
   }
   
   // Mihir Rake improvements
   if (timeToDie >= 8.5 && status.isTigersFuryUp() && !status.isRakeTFed() && rakeRemaining < 9.0)
      return Action.RAKE;

   // actions+=/rake,if=target.time_to_die>=9 - waiting for TF to come off of cooldown is a dps loss clip Rake
   if (timeToDie >= 8.5 && (!status.isRakeUp() || rakeRemaining < 3.0)) {
      return Action.RAKE;
   }

   // actions+=/savage_roar,if=buff.combo_points.stack>=1&buff.savage_roar.remains<=1
   if (cps > 0 && (!status.isSavageRoarUp() || srRemaining <= 1) && ripRemaining >= 6)
      return Action.ROAR;

   // Ravage If Stampede, Feral FF, Mangle, Rake are all up and OoC is not, and TF is up.
   if (status.isStampedeUp() && !status.isOoCUp() && status.isTigersFuryUp())
      return Action.RAVAGE;
         
   // Mangle if the 4T11 bonus is not at 3 stacks.
   if (status.hasTier_11_4pc() && status.getTier_11_4pcStacks() < 3)
      return Action.MANGLE;
      
   // Fillers

   // Just going to use the logic from the script here
   if (energy >= 70 || status.isTigersFuryUp())
      return Action.SHRED;
   if (status.isOoCUp() || timeToDie < 10 || status.isBerserkUp())
      return Action.SHRED;
   if (cps < 5 && ripRemaining <= 3)
      return Action.SHRED;
   if (cps == 0 && srRemaining <= 2)
      return Action.SHRED;
   if (tfRemaining <= 3)
      return Action.SHRED;
      
   // Allow Stampede + Ravage! when out of opener.
   if (status.shouldAggressiveFeralCharge() && !interruptSoon) {
      double travelTime = status.getFeralChargeTotalTime();

      // Running away right as you are about to cast Tranquility or Rebirth is a DPS loss, avoid it.
      //
      // Note: The engine will force the "player" to hold the GCD for Rebirth/Tranquility so include
      // some padding when figuring out if we can do this or not.
      if (nextUtilityCastIn > travelTime + 2) {
         // Some bosses allow us to Feral Charge at point blank range.
         if (travelTime > 0) {
            // WARNING - This is still relatively unoptimized.  There's clearly a point where it's not worth
            // attempting to do this at all (too much DPS time lost, ~3 sec).
            //
            // Note: The script will time it so that you run out right when Feral Charge is going to come off
            // CD when you are done.
            //
            // Per Leafkiller, ensuring that Rake won't fall off is a minimal gain.  Micro managing this
            // around both Rake/Rip is fairly minimal due to Rake/Rip having massively higher priority.
            if (!(status.shouldSkullBash() && status.nextCastIn() < travelTime) && !(status.isBerserkUp() || status.isTigersFuryUp()) && status.getFeralChargeCD() < travelTime)
               if (rakeRemaining > travelTime + 2.9)
                  return Action.RUNAWAY;
         }
      }
   }
   
   return null;
}


//=======================================================================================================
// variables for emulating Atramedes ground/air phases. Times were taken from DBM.
private double combatLength = -1;
private double initialGround = 90;
private double airPhase = 31.5;
private double groundPhase= 85;

// Experimental rotation

private IAction expRotation(CatModelSimState status) {

   double timeToDie = status.getTimeRemaining();
   int energy = status.getEnergy();
   int energyPerSec = (int) Math.floor(1.0 / status.getEnergyTickInterval());
   int cps = status.getComboPoints();
   
   double tfRemaining = status.getTigersFuryCD();
   boolean canTF = (!status.isBerserkUp() && tfRemaining == 0.0);
   boolean canBerserk = (status.getBerserkCD() == 0.0);

   double ripRemaining = status.getRipRemaining();
   double srRemaining = status.getSavageRoarRemaining();
   double rakeRemaining = status.getRakeRemaining();
   double brRemaining = status.getBerserkRemaining();
   double ripSRSyncTimer = (double) Math.abs(ripRemaining - srRemaining);
   double berserkBaseDuration = status.getBerserkBaseDuration();
   double nextUtilityCastIn = status.nextUtilityCastIn();
   

   if (combatLength == -1) combatLength = status.getEncounterDuration();
   double timeInCombat = status.getElapsedTime();
   double timeToAirPhase = 0;  // for berserk later on - initial testing shows it is a dps loss to try to not clip Berserk - too time dependant.
   
   // special case the first ground/air phases
   if (timeInCombat < (initialGround + airPhase)) {
      if (timeInCombat >= initialGround) {
         if (status.isAutoAttackEnabled()) return Action.AUTOATTACK_STOP;
         return null;
      }
      timeToAirPhase = initialGround - timeInCombat;
   } else {
      double deadTime = (timeInCombat - (initialGround + airPhase)) % (groundPhase + airPhase);
      if (deadTime >= groundPhase) {
         if (status.isAutoAttackEnabled()) return Action.AUTOATTACK_STOP;
         return null;
      }
      timeToAirPhase = groundPhase - deadTime;
   }
   
   //
   // External Abilities/events.
   //

   // Heroism
   //
   // Note: This doesn't handle "encounters that would result in non-integer uses of heroism"
   // at all.  Defining default behavior for that case is more a matter of personal taste.
   if (status.getHeroismCD() == 0.0) {
      // If the mob will die as heroism is falling off if we use it now, use it.
      if (timeToDie <= 40)
         return Action.HEROISM;

      // If we will get a full heroism in at the end of the fight if we use it now, use it.
      if (timeToDie >= 600 + 40)
         return Action.HEROISM;
   }

   // Shattering throw
   if (status.getShatteringThrowCD() == 0.0) {
      // If heroism is up, use it.
      if (status.isHeroismUp())
         return Action.SHATTERINGTHROW;

      // If the mob will die as Shattering Throw is falling off if we use it now, use it.
      if (timeToDie < 10)
         return Action.SHATTERINGTHROW;

      // If we will get the full Shattering Throw in at the end of the fight if we use it now, use it.
      if (timeToDie >= 300 + 10)
         return Action.SHATTERINGTHROW;
   }

   // Unholy Frenzy
   //
   // Just simulate the DK using this on cooldown for now.  More sophisticated things
   // like stacking it with Berserk or Heroism could be done.
   if (status.getUnholyFrenzyCD() == 0.0)
      return Action.UNHOLYFRENZY;

   // EXAMPLE - Simulate forced DPS stop.
//   if (status.getElapsedTime() > 30 && status.getElapsedTime() < 60) {
//      // Stop the swing timer.
//      if (status.isAutoAttackEnabled()) return Action.AUTOATTACK_STOP;
//
//      return null;
//   }

   //
   // Druid abilities that are off the GCD.
   //

   // Feral Charge to get Stampede up if we are not in combat.
   if (!status.isInCombat() && status.getFeralChargeCD() == 0.0)
      return Action.FERALCHARGE;

   // Feral Charge to get Stampede up if we can.
   if (status.shouldAggressiveFeralCharge() && status.canFeralCharge())
      return Action.FERALCHARGE;

   // Don't bother trying to do anything else if we are out of melee range.
   if (!status.isInMeleeRange()) return null;

   // Start the swing timer if needed.
   if (!status.isAutoAttackEnabled())
      return Action.AUTOATTACK_START;

   // Potion of Tol'vir
   if (status.canPotion()) {
      // Pre-potion.
      if (!status.isInCombat())
         return Action.POTION;

      if (status.isHeroismUp() || timeToDie < 40)
         return Action.POTION;
   }

   // If the target is casting, interrupt it if we can.
   if (status.isTargetCasting() && status.getSkullBashCD() == 0.0) {
      // Use Tiger's Fury to get energy to interrupt if needed.
      if (energy < status.getSkullBashCost() && canTF == true)
         return Action.TIGERSFURY;

      return Action.SKULLBASH;
   }

   // Start pooling energy for interrupts.
   boolean interruptSoon = false;
   if (status.shouldSkullBash()) {
      double timeToNextCast = status.nextCastIn();

      // Only bother pooling assuming we can manage to interrupt.
      if (status.getSkullBashCD() <= timeToNextCast + status.getTargetCastTime()) {
         // Use base energy regen instead of energyPerSec to be somewhat conservative.
         double poolReqTime = status.getSkullBashCost() / 10;
         double expectedEnergyRegen = timeToNextCast * 10;

         // Pool assuming we do not have OoC up, and next cast is soon.
         if (timeToNextCast <= poolReqTime) {
            if (!status.isOoCUp() && energy + expectedEnergyRegen < status.getShredCost() + status.getSkullBashCost()) {
               return null;
            }

            // Determine if it's "safe" to allow Ferocious Bite (Assume no Glyph)
            int biteCost = (status.isOoCUp()) ? 0 : status.getFerociousBiteCost();
            int extraEnergy = Math.min(35, energy - biteCost);

            if (energy - (biteCost + extraEnergy) + expectedEnergyRegen < status.getSkullBashCost())
               interruptSoon = true;
         }
      }
   }

   // actions+=/tigers_fury,if=energy<=30&!buff.berserk.up
   if (status.getLevel() == 80) {
      if (energy <= 26 && canTF == true && !status.isInGCD() )
         return Action.TIGERSFURY;;
   } else {
      if (energy <= 35 && canTF == true && !status.isInGCD() && !status.isOoCUp())
         return Action.TIGERSFURY;
   }
   
   //
   // Druid abilities that are on the GCD.
   //

   // Raid debuffs:
   
   // Mangle if the 4T11 bonus is about to fall off.
   if (status.hasTier_11_4pc() && status.getTier_11_4pcRemaining() <= 4)
      return Action.MANGLE;

   // actions+=/faerie_fire_feral,debuff_only=1
   if (status.getFeralFFCD() == 0.0 && status.shouldFF() && (status.getFeralFFStacks() < 3 || status.getFeralFFRemaining() <= 1))
      return Action.FERALFF;
     
   // actions+=/mangle_cat,mangle<=1 (Alaron: Same logic as FF...rDPS increases go first.)
   if (status.getMangleRemaining() <= 1 && status.shouldMangle())
      return Action.MANGLE;   

   // Ravage if Stampede will drop during the next global.
   if (status.isStampedeUp() && status.getStampedeRemaining() <= 2.0)
      return Action.RAVAGE;

   // actions+=/berserk_cat,if=energy>=80&energy<=90&!buff.tigers_fury.up
   // Since Berserk does not clip Tiger's Fury anymore, stacking is ideal but makes this encounter sensitive.
   // For now Berserk whenever we are at the correct energy level, and when it won't push back the next TF.
   // The difference between the two appears to be < 10 DPS.
   // Note - with Glyph of Berserk you want a minimum energy level - but with Glyph of TF it does not seem to matter much.
    if (status.isTigersFuryUp() && !status.isInGCD()) {
      if (energy > 0 && canBerserk)
         return Action.BERSERK;
   } else {
      if (energy > 64 && canBerserk && !status.isInGCD() && (tfRemaining > berserkBaseDuration || timeToDie < tfRemaining + berserkBaseDuration))
         return Action.BERSERK;
   }
   /*if (status.isTigersFuryUp()) {
      if (energy > 84 && energy <= 100 && canBerserk)
         return Action.BERSERK;
   } else {
      if (energy > 64 && energy <= 80 && canBerserk && (tfRemaining > berserkBaseDuration || timeToDie < tfRemaining + berserkBaseDuration))
         return Action.BERSERK;
   }*/
   /*if (energy <= (status.getEnergyCap() - (energyPerSec*2)) && canBerserk && (status.getTigersFuryCD() > berserkBaseDuration || timeToDie < status.getTigersFuryCD() + berserkBaseDuration))
      return Action.BERSERK;
   */

   if (!interruptSoon) {
      // Ferocious Bite if we are at > 0 cps, are in Feast Of Flesh range, and Rip is about to fall.
      // (Alaron: Shouldn't these conditionals come first? Else you're never refreshing Rip via FB.)
      if (cps > 0 && status.isRipUp() && ripRemaining <= 2.1 && status.isInBloodInTheWaterRange())
         return Action.BITE;

      // Ferocious Bite if we are at 5 cps, Rip is up, and we are in Feast Of Flesh range.
      if (cps == 5 && status.isRipUp() && status.isInBloodInTheWaterRange())
         return Action.BITE;
   }
   
   // Regular Rotation:
   
   // actions+=/shred,extend_rip=1,if=dot.rip.remains<=4
   if (status.getRipShredExtRemaining() > 0 && ripRemaining <= 4 && status.isRipUp())
      return Action.SHRED;

   if (cps == 5 && timeToDie < 7 && !interruptSoon)
      return Action.BITE;

   // actions+=/rip,if=buff.combo_points.stack>=5&target.time_to_die>=6
   if (cps >= 5 && timeToDie >= 6 && (!status.isRipUp() || ripRemaining < 2.0)) {
      return Action.RIP;
   }
   
   // Mihir Rake improvements
   if (timeToDie >= 8.5 && status.isTigersFuryUp() && !status.isRakeTFed() && rakeRemaining < 9.0)
      return Action.RAKE;

   // actions+=/rake,if=target.time_to_die>=9 - waiting for TF to come off of cooldown is a dps loss clip Rake
   if (timeToDie >= 8.5 && (!status.isRakeUp() || rakeRemaining < 3.0)) {
      return Action.RAKE;
   }

   // actions+=/savage_roar,if=buff.combo_points.stack>=1&buff.savage_roar.remains<=1
   if (cps > 0 && (!status.isSavageRoarUp() || srRemaining <= 1) && ripRemaining >= 6)
      return Action.ROAR;

   // Ravage If Stampede, Feral FF, Mangle, Rake are all up and OoC is not, and TF is up.
   if (status.isStampedeUp() && !status.isOoCUp() && status.isTigersFuryUp())
      return Action.RAVAGE;
         
   // Mangle if the 4T11 bonus is not at 3 stacks.
   if (status.hasTier_11_4pc() && status.getTier_11_4pcStacks() < 3)
      return Action.MANGLE;
      
   // Fillers

   // Just going to use the logic from the script here
   if (energy >= 70 || status.isTigersFuryUp())
      return Action.SHRED;
   if (status.isOoCUp() || timeToDie < 10 || status.isBerserkUp())
      return Action.SHRED;
   if (cps < 5 && ripRemaining <= 3)
      return Action.SHRED;
   if (cps == 0 && srRemaining <= 2)
      return Action.SHRED;
   if (tfRemaining <= 3)
      return Action.SHRED;
      
   // Allow Stampede + Ravage! when out of opener.
   if (status.shouldAggressiveFeralCharge() && !interruptSoon) {
      double travelTime = status.getFeralChargeTotalTime();

      // Running away right as you are about to cast Tranquility or Rebirth is a DPS loss, avoid it.
      //
      // Note: The engine will force the "player" to hold the GCD for Rebirth/Tranquility so include
      // some padding when figuring out if we can do this or not.
      if (nextUtilityCastIn > travelTime + 2) {
         // Some bosses allow us to Feral Charge at point blank range.
         if (travelTime > 0) {
            // WARNING - This is still relatively unoptimized.  There's clearly a point where it's not worth
            // attempting to do this at all (too much DPS time lost, ~3 sec).
            //
            // Note: The script will time it so that you run out right when Feral Charge is going to come off
            // CD when you are done.
            //
            // Per Leafkiller, ensuring that Rake won't fall off is a minimal gain.  Micro managing this
            // around both Rake/Rip is fairly minimal due to Rake/Rip having massively higher priority.
            if (!(status.shouldSkullBash() && status.nextCastIn() < travelTime) && !(status.isBerserkUp() || status.isTigersFuryUp()) && status.getFeralChargeCD() < travelTime)
               if (rakeRemaining > travelTime + 2.9)
                  return Action.RUNAWAY;
         }
      }
   }
   
   return null;
}
Last edited by Leafkiller on Fri Feb 25, 2011 9:04 pm, edited 12 times in total.

Exalted
User avatar
Posts: 1145
Joined: Fri Jun 04, 2010 4:28 am

Re: Leafkiller's 4.01 Feral Ovale Script

Postby Leafkiller » Fri Oct 22, 2010 4:25 pm

New version 1.0.6 -

Cleans up the interface - there is now a checkbox to toggle display for the cooldowns on the left side and a checkbox to toggle display for the cooldowns on the right.

The trinket cooldowns (for bears) have been merged into the right cooldown boxes - and can be hidden.

The emergency FB for Blood in the Water now looks for 2.1 seconds on Rip due to the bug where Rip drops off (2 dps loss in sim).

Also, disabled the Savagee Roar desync code during Blood in the Water phase to preserve combo points (this is dps neutral).

Added checkbox for two levels of ferocious bite (taken from Alaron's pre patch script) for later use (predicting at level 85 with lower crit rates we will want to FB less - still needs to be tested and optimized in a sim).

Posts: 43
Joined: Thu Oct 14, 2010 1:48 am

Re: Leafkiller's 4.01 Feral Ovale Script

Postby Evil » Sat Oct 23, 2010 8:58 am

Hi Leafkiller,

tested it and it's great stuff. Really appreciate your work!! Keep it up dude. Thanks!

Greets,

Evil

Posts: 6
Joined: Wed Oct 20, 2010 1:35 pm

Re: Leafkiller's 4.01 Feral Ovale Script

Postby Achnom » Sun Oct 24, 2010 7:08 pm

I've been testing adding more conditions in the Mew script on when to refresh Roar (or Bite) based on the TF cooldown. There are certainly times when Roar/Bite are the right things to do even with Rip about to fall off (< 6 seconds). Just need to figure them out.

if (cps >= 5 && timeToDie >= 9 && srRemaining <= 9.0 && (ripRemaining >= 9.0 | (ripRemaining >= 6.0 && status.getTigersFuryCD() <= 6.0)))
return Action.ROAR;

Exalted
User avatar
Posts: 1145
Joined: Fri Jun 04, 2010 4:28 am

Re: Leafkiller's 4.01 Feral Ovale Script

Postby Leafkiller » Sun Oct 24, 2010 9:35 pm

Achnom wrote:I've been testing adding more conditions in the Mew script on when to refresh Roar (or Bite) based on the TF cooldown. There are certainly times when Roar/Bite are the right things to do even with Rip about to fall off (< 6 seconds). Just need to figure them out.

if (cps >= 5 && timeToDie >= 9 && srRemaining <= 9.0 && (ripRemaining >= 9.0 | (ripRemaining >= 6.0 && status.getTigersFuryCD() <= 6.0)))
return Action.ROAR;


What sort of dps difference are you seeing?

* I have tested a lot of different things lately and it is hard to make much of a dent in the dps of the sims now...

Posts: 6
Joined: Wed Oct 20, 2010 1:35 pm

Re: Leafkiller's 4.01 Feral Ovale Script

Postby Achnom » Sun Oct 24, 2010 10:45 pm

Not much, about 20 dps, but it's a gain. I really just wanted to give you an idea, in case you haven't already thought of everything.

Exalted
User avatar
Posts: 1145
Joined: Fri Jun 04, 2010 4:28 am

Re: Leafkiller's 4.01 Feral Ovale Script

Postby Leafkiller » Mon Oct 25, 2010 12:19 pm

I certainly have not thought of everything - and many of the things I have thought of along the way turned out to be dps losses.

BTW - the default script has different constraints on when to refresh SR/FB and the dps between the two sims is very close. The main difference between the two is the priority of SR vs. Rip but from what I have seen this is pretty dps neutral (weaker gear seems to favor the Rip over SR approach though).

Posts: 13
Joined: Thu Apr 08, 2010 7:39 am

Re: Leafkiller's 4.01 Feral Ovale Script

Postby Willféral » Tue Oct 26, 2010 8:02 am

Leafkiller wrote:I certainly have not thought of everything - and many of the things I have thought of along the way turned out to be dps losses.

BTW - the default script has different constraints on when to refresh SR/FB and the dps between the two sims is very close. The main difference between the two is the priority of SR vs. Rip but from what I have seen this is pretty dps neutral (weaker gear seems to favor the Rip over SR approach though).


Whats the time set in the script to stop saying to FB with time left on RIP is it around 8 secs? Or more of a 6-7 sec ?

hope my question makes sense :)

Posts: 6
Joined: Wed Oct 20, 2010 1:35 pm

Re: Leafkiller's 4.01 Feral Ovale Script

Postby Achnom » Tue Oct 26, 2010 1:26 pm

If you have the Hi FB selected, it's 8 seconds. If you have the Lo FB selected, it's 12 seconds.

if ComboPoints(more 4) and List(FBOption HiFB) and TargetDebuffPresent(RIP 8 mine=1) and BuffPresent(SAVAGEROAR 8) {
Spell(FEROCIOUSBITE)
}
if ComboPoints(more 4) and List(FBOption LoFB) and TargetDebuffPresent(RIP 12 mine=1) and BuffPresent(SAVAGEROAR 12) {
Spell(FEROCIOUSBITE)
}

User avatar
Posts: 48
Joined: Wed Oct 20, 2010 2:56 pm

Re: Leafkiller's 4.01 Feral Ovale Script

Postby Lax » Wed Oct 27, 2010 9:11 am

Testing the script in the beta (4.0.3) at lvl 85, I found that you definitely need to check Low FB and use the FB glyph. Our crit % is so low compared to live, that you often end up low on combo points. Other than that, the script seems to work really well for me at least.

Posts: 28
Joined: Wed Oct 27, 2010 12:44 pm

Re: Leafkiller's 4.01 Feral Ovale Script

Postby Beatrix » Wed Oct 27, 2010 12:52 pm

First of all I wanted to say thanks to all of your theorycrafters : Alaron, Leafkiller, Mihir and all the unsung and unrecognized ones as well. Thanks to all your great work on Ovale, Mew and the great guides that you have produced for feral kitties.

With the use of the new Ovale script my dps has gone from 13.5ish K dps on Saurfang to a whopping 16.5k DPS as of last night on Saurfang. I was in shock because I have not upgraded a single piece of gear between pre and post patch. and I was already using the Ovale script pre-patch. The only difference is the new Ovale script, regemming to agility and reforging to Mastery. I have even gone back to my Herkulm token instead of my Whispering fang skull and I do not have more the full Sanctified 4 piece set (only 2 of each actually) .

So you have made me a very happy and purring kitty. :D

Cheers!

Exalted
User avatar
Posts: 1145
Joined: Fri Jun 04, 2010 4:28 am

Re: Leafkiller's 4.01 Feral Ovale Script

Postby Leafkiller » Wed Oct 27, 2010 5:47 pm

@Beatrix - I am glad to hear it is working for you. As a side note, I am pretty sure Whispering Fanged Skull is better than Herkumi. You should check that in Mew - you will just need to enter your stats with each trinket equipped and then set the appropriate trinket in the procs section.

@Lax - I was hoping that the low FB setting + FB glyph would work for level 85. That was the main reason I grabbed that code from Alaron's older script. For most of us, the high FB setting is fine for level 80.

Posts: 5
Joined: Fri Oct 15, 2010 2:32 am

Re: Leafkiller's 4.01 Feral Ovale Script

Postby Cav » Fri Oct 29, 2010 12:58 pm

Any idea why I would periodically get FF to pop up randomly through out a fight? I would FF at the start and sometimes a minute later or so it would be in the move suggester and other times worked as I would expected.

This was while I was a cat, version 1.0.6

Honored
Posts: 87
Joined: Mon Jun 14, 2010 2:04 pm

Re: Leafkiller's 4.01 Feral Ovale Script

Postby Goodmongo » Fri Oct 29, 2010 4:47 pm

My guess is that you didn't apply three layers of it. Forget if it's a glyph or trait but it allows you to apply FFF three times for one cast. So if you don't have that you still have two more casts to do.

Posts: 5
Joined: Fri Oct 15, 2010 2:32 am

Re: Leafkiller's 4.01 Feral Ovale Script

Postby Cav » Sun Oct 31, 2010 1:20 pm

I should have mentioned that, but yes I have it talented to apply 3 stacks with application.

Exalted
User avatar
Posts: 1145
Joined: Fri Jun 04, 2010 4:28 am

Re: Leafkiller's 4.01 Feral Ovale Script

Postby Leafkiller » Sun Oct 31, 2010 5:06 pm

I have not seen it suggest FF other than when it was needed. Perhaps something removed the debuff from the mob you were fighting. I am using a built in Ovale test to check for that as multiple classes can put up the same debuff. One possibility is some other class overwrote the FF and then let it fall off.

Posts: 2
Joined: Sat Nov 06, 2010 2:35 pm

Re: Leafkiller's 4.01 Feral Ovale Script

Postby Timbermaw » Sat Nov 06, 2010 3:00 pm

Just some additions it may be worth mentioning to the bear portion of your code (and infact may be useful in cat somewhere too)

Code: Select all
if 2s before Spell(MANGLEBEAR)
{
   Spell(MANGLEBEAR)
}

if CheckBoxOn(adds) and 0s before Spell(SWIPEBEAR)
{   
   Spell(SWIPEBEAR)
}


In the code above, the "Xs before Spell(Y)" are completely useless and do nothing.

I'll show the example primarily in MANGLEBEAR.

You're attempting to get it to suggest MANGLEBEAR 2.0s before it is ready to be used.

So when MANGLEBEAR has 2.0s left on the cooldown, the conditional is true and it goes to the next line.

Spell(MANGLEBEAR) - But because MANGLEBEAR is on cooldown is continues to the next spell.

In order to force it to actually show MANGLEBEAR and not continue on to the next line of code, you need to alter the priority. All spells can have a priority specified.

Default priority for all spells is 3. An increase in priority (As in make this spell show over other spells) is done by increasing the priority above 3.

As such, the below code should replace all occurences of "if Xs before Spell(Y)" conditionals as required.

Code: Select all
if 2s before Spell(MANGLEBEAR)
{
   Spell(MANGLEBEAR priority=4)
}

if CheckBoxOn(adds) and 0s before Spell(SWIPEBEAR)
{   
   Spell(SWIPEBEAR priority=4)
}


When MANGLEBEAR has more than 2s left on the cooldown, the conditional is false and the Spell() is never processed.

When MANGLEBEAR has only 2s or less left on the cooldown, the conditional is now true and goes to the next line. The Spell() is processed and because this instance of MANGLEBEAR has a priority=4 while all other abilities have a priority=3, so regardless of anything else that Spell(MANGLEBEAR priority=4) will be the next suggested abilitity until the conditional before it is no longer true (and thus the Spell() is no longer processed)

Also it still won't fix your SWIPEBEAR option because you need to change the (Xs until Spell(Y)), but you get the idea. Hopefully you can improve the bear part of the script with it!

I set it for a 1.0s before Spell(MANGLEBEAR) incase I'm needing to use Feral FF in my rotation which only triggers a 1s global.

Exalted
User avatar
Posts: 1145
Joined: Fri Jun 04, 2010 4:28 am

Re: Leafkiller's 4.01 Feral Ovale Script

Postby Leafkiller » Sat Nov 06, 2010 11:32 pm

In the code above, the "Xs before Spell(Y)" are completely useless and do nothing.

I'll show the example primarily in MANGLEBEAR.

You're attempting to get it to suggest MANGLEBEAR 2.0s before it is ready to be used.

So when MANGLEBEAR has 2.0s left on the cooldown, the conditional is true and it goes to the next line.

Spell(MANGLEBEAR) - But because MANGLEBEAR is on cooldown is continues to the next spell.

In order to force it to actually show MANGLEBEAR and not continue on to the next line of code, you need to alter the priority. All spells can have a priority specified.


Disclaimer - Tbot wrote the bear code.

In general for the cat script, I have avoided setting the spell priorities explicitly, as the order in the script defines priorities - and the cat script is attempting to mirror the sim script as close as possible so the dps is more or less "provably optimized."

On the bear script I think there is a lot of refinement that can be made. I have not studied the bear rotation that carefully outside of reading the threads on EJB - although it has been sufficient for the single target tanking I have done. Before going in a making a few small changes, let's discuss what the optimal rotation should be. i.e. do we not want to cast anything else if Mangle comes off of cooldown in 2 seconds and just wait? Right now most of the time with 2 seconds left it will end up casting a swipe or lacerate - and I do notice that the Mangle is sometimes delayed. Another question I have is around the pulverize logic. For example, right now it is very restrictive and does not guarantee to keep the crit buf up.

If we focus on what the rotation should be, making the script is the easy part.

Posts: 26
Joined: Fri Oct 15, 2010 11:10 pm

Re: Leafkiller's 4.01 Feral Ovale Script

Postby tbot » Sun Nov 07, 2010 9:00 am

Hey timber. You don't know how much I love you.

I knew the code wasn't working, but didn't know how to get it to do what I wanted. I left the things in there so someone (like yourself) would recognize the intent.

The priority listed(with the changes to 1s before w/ priority) is pretty close to optimal. You are welcome to think it out yourself if you like :)

But reesi and kalon both came to the same conclusions I did. On a further note, I actually don't use the script anymore as it was mostly just for learning (I hate having my eyes glued to something) so I probably won't change the code myself.

Something to consider adding - disable FFF on aoe pulls as you'll be tab targeting and you'll get nothing but FFF all the time.

Edit: Another thing that bugs me with the code though doesn't actually impact performance is pulverise. Because of how ovale seems to work the instant you use it, the icon flips making you feel like you shouldn't have used it (because lacerate is no longer on the target)

Exalted
User avatar
Posts: 1145
Joined: Fri Jun 04, 2010 4:28 am

Re: Leafkiller's 4.01 Feral Ovale Script

Postby Leafkiller » Sun Nov 14, 2010 5:36 pm

I just posted version 1.1 of my Ovale script - this time with support for level 85 - specifically the Tier 11 4 piece set bonus. I also posted an updated version of the matching Mew script.

The bear code has not been updated for level 85 yet, and in light of the discussion between tbot and Timbermaw, it sounds like it could use a fair amount of work. Can you two expand on what you feel the rotation should be? I would like to get that code cleaned up some and ready for testing on Beta.

Posts: 2
Joined: Sat Nov 06, 2010 2:35 pm

Re: Leafkiller's 4.01 Feral Ovale Script

Postby Timbermaw » Wed Nov 17, 2010 3:53 am

Ahh damnit, I completely forgot about my post here.

On the topic of the rotation...
I believe the current priority list is about the most optimised TPS rotation you are going to get. Every GCD the highest TPS ability available is used.

I'd only be pedantic and enhance it with a "TPR" model to: That is, a threat-per-rage model for if you are rage starved - This would then prioritise the highest threat per rage abilities instead of threat per second to get the most threat out of limited resources (For example Swipe is wildly rage ineffecient on a single target I believe, doing only slightly more threat than a Lacerate for double the rage cost)

This wouldn't be tough to implement. Just a tick box or a drop down box and then encase the entire bear code in
Code: Select all
If CheckBoxOff(ThreatPerRage) { Previous bear code here }
If CheckBoxOn(ThreatPerRage) { Rage efficient bear code here }


It's not necessarily needed, but it would be a nice option in my opinion for ticking on and off mid-fight on bosses like Saurfang or Lich King where you may be sitting around with your claw up your ass and the last thing you want is Ovale saying "Hey, I think you should swipe!" when rage is at a precious, precious premium and you want to make the most of vengance stacks for damage before they all vanish.

As for extensive code changes just to get the base script working...

This entire problem stems from the fact that bear GCDs are 1.5s and mangle is on a 6s cooldown. Ovale doesn't view mangle as the next ability if it predicts there'd be even a 0.01s gap after the GCD ends in which mangle would still be on cooldown. Because the bear GCD is 1.5s and we have "Perfect" 6s cooldowns such as Swipe and Mangle, both of these abilities will actually be delayed by a GCD because Lacerate, for example, has no cooldown.

0s > Mangle
1.50s > Swipe
3.00s > Lacerate
4.50s > Lacerate
6.00s > Mangle or Lacerate, Lacerate is chosen because it's guaranteed to be off cooldown in time to use it - It's hard to explain but it effectively is off cooldown before Mangle is and Ovale isn't accurate enough to predict abilities within millisecond barriers like this. For all intents and purposes, mangle might as well have a 6.00000000001 cooldown attached.
7.50s > Mangle or Swipe, Mangle is chosen because it's guaranteed to be off cooldown in time to use it.
9.00s > Swipe
10.50s > Filler
12.00s > Filler
13.50s > Mangle or Filler, Filler is chosen
15.00s > Mangle or Swipe, Mangle is Chosen

etc.

Basically, mangle is being savagely delayed. In a 300s fight, mangle should be used 50 times and Swipe should be a similar but lesser number. This is then increased by lacerate ticks proccing mangle's cooldown to reset.

But with the code as it is now, mangle is used 40 times in a fight at base and is allowed regular 1.5s gaps where it's off cooldown and the lacerate tick can proc meaning a wasted proc.

With that wall of text out of the way...

I don't forsee an entire rewrite, we just need to use the tools given to use effectively.

There's my initial option, if 1.0s until Spell(MANGLEBEAR) { Spell(MANGLEBEAR priority=4) }

Setting priorities is extremely powerful, but also leads to problems.
In this scenario, other abilities are forcefully delayed if mangle comes off cooldown within 1.0 seconds of that ability being useable and mangle will overwrite Feral FF with the "lucioles" box on.

As soon as there is only 1s left on mangle's cooldown, it will outrank all other abilities in this script, even abilities with only 0.01s left before they are usable leading to a delay of up to 1 second while mangle is the only move suggested while other moves are availble.

Looking through the (finally bloody updated) documentation there's also another option that could be even more powerful than priority= for the task we wish to accomplish.

between "node1" and "node2"
Returns the absolute difference between the starting time of ''node1'' and ''node2'', whichever is the first.

While I havn't tested it (And the EU servers are still down so I can't test it for awhile anyway) there is a possiblility we can do a massive if statement just for mangle.

Code: Select all
if less than 0.1s between Spell(MANGLEBEAR) and Spell(LACERATE) or less than 0.1s between Spell(MANGLEBEAR) and Spell(SWIPEBEAR)...
    Spell(SWIPEBEAR)


If I have interpreted it correctly, we can make a spell cast if there's only 0.1s difference between any two spells coming off cooldown.

If this is actually true; this solves our entire problem because it effectively says "I want mangle to act as having a 0.1s faster cooldown than it really has when compared to Lacerate/Swipe/Pulverize etc."

With all that being said...
YES, IT'S CAPSLOCK TIME! I HAVN'T PERSONALLY TESTED THIS SCRIPT BECAUSE I DON'T ACTIVELY TANK. I WAS CALLED ON TO TWILIGHT REALM TANK MY GUILD'S FIRST HALION-25 HC KILL WHICH IS WHY I NEEDED TO MODIFY THE SCRIPT SLIGHTLY MYSELF BECAUSE I DID LITERALLY ZERO BEAR RESEARCH SINCE THE 4.0.1 PATCH WITH MY MAINSPEC AS CAT >.>

THIS VERSION I'M POSTING IS EVEN MORE MODIFIED AND REFINED THAN THE HACKED TOGETHER VERSION I USED MYSELF, BUT COMPLETELY UNTESTED.

THE CODE BELOW IS FOR DISCUSSION AND TESTING FIRST. THE WHOLE THING MAY NOT EVEN WORK IF THE MANGLE CHANGES AREN'T FORMATTED CORRECTLY.


Code: Select all
    if Stance(1) #BEAR! (Rawr!)
    {
        #OLD
        #if CheckBoxOn(lucioles) and TargetDebuffExpires(lowerarmor 2) {
        #       Spell(FAERIEFERAL)
        #   }

        #NEW
        #Issue: Feral FF wouldn't be cast up to 3 stacks.
        #Solution: Setting stacks=3 in the TargetDebuffExpires.
        #Issue 2: You probably don't want feral FF while AoEing.
        #Solution: So we don't suggest the cast with the AoE box on.
        #          It'll be cast naturally if we're rage starved by
        #          the FeralFF cast at the bottom of the script for
        #          when your rage is under 10.

        #If we're having to sunder ourselves, getting sunders up as fast as
        #possible is the highest priority. This suggests Feral FF as the
        #first move on any pull and it should be cast as you are approaching
        #the target so real GCDs are lost.

        if CheckBoxOn(lucioles) and CheckBoxOff(aoe) and TargetDebuffExpires(lowerarmor 2 stacks=3)
            Spell(FAERIEFERAL)

        #NEW
        #Issue: Swipe on CD was below mangle. Bad for AoE tanking.
        #Solution: Swipe on cooldown moved up! Oh yeah!
        #Issue 2: Swipe has the same problem as Mangle being delayed.
        #Solution: Copy paste mangle code, apply to swipe!

        if CheckBoxOn(adds)
            if {less than 0.1s between Spell(SWIPEBEAR) and Spell(DEMOROAR)} or {less than 0.1s between Spell(SWIPEBEAR) and Spell(LACERATE)} or {less than 0.1s between Spell(SWIPEBEAR) and Spell(MANGLEBEAR)} or {less than 0.1s between Spell(SWIPEBEAR) and Spell(PULVERIZE)} or {less than 0.1s between Spell(SWIPEBEAR) and Spell(FAERIEFERAL)}
            Spell(SWIPEBEAR priority=4)
                   
        #OLD
        #if 2s before Spell(MANGLEBEAR) {
        #    Spell(MANGLEBEAR)
        #}

        #NEW
        #Issue: If conditional did nothing. Even when True, for 0.5s
        #       of the conditional mangle was on cooldown anyway so
        #       it was bypassed.
        #Solution: Test the "between 'node1' and 'node2'" option.

        #This is just experimental. I havn't tested it myself.
        #I don't know how it works so I just encased the between
        #options in brackets incase the additional 'ands' sent
        #Ovale batshit crazy.

        if {less than 0.1s between Spell(MANGLEBEAR) and Spell(DEMOROAR)} or {less than 0.1s between Spell(MANGLEBEAR) and Spell(LACERATE)} or {less than 0.1s between Spell(MANGLEBEAR) and Spell(SWIPEBEAR)} or {less than 0.1s between Spell(MANGLEBEAR) and Spell(PULVERIZE)} or {less than 0.1s between Spell(MANGLEBEAR) and Spell(FAERIEFERAL)}
            Spell(MANGLEBEAR priority=4)

       

        #OLD
        #if CheckBoxOn(demo) and TargetDebuffExpires(lowerphysicaldamage 2)
        #    Spell(DEMOROAR)

        #NEW
        #Issue: Demoroar can fall off. If you're doing it yourself, it
        #       is a super important buff. Needs 100% uptime. Best to
        #       replace a filler with it, though. Threat and all that.
        #Solution: We'll just refresh it earlier.

        if CheckBoxOn(demo) and TargetDebuffExpires(lowerphysicaldamage 3)
                Spell(DEMOROAR)

        #MINOR
        #Issue: Excess bracketing makes code look unwieldy.

        unless TargetDebuffPresent(LACERATE stacks=1 mine=1)
            Spell(LACERATE)
       
        #NOTE
        #"Swipe on Cooldown" moved to higher priority.

        #MINOR
        #Issue: No longer need supporting mangle code.

        if TargetDebuffPresent(LACERATE stacks=3)
            Spell(PULVERIZE)

        #OLD
        #if Mana(more 10) and TargetDebuffExpires(LACERATE 4 stacks=3)
        #    Spell(LACERATE)

        #NEW
        #Issue: The code would never, ever be executed. Ever. Never.
        #       TargetDebuffPresent(LACERATE stacks=3) will ALWAYS
        #       be true at the same time as or before the
        #       (LACERATE 4 stacks=3) because it's the same only with
        #       one less condition to be true.
        #Solution: Deleted.

        #NEW
        #Issue: Swipe is higher Threat Per Global than Lacerate?
        #       May make effective rage dump?
        #Solution: Added swipe as a single target filler.
        #          May need Mana(more x) changed.

        if Mana(more 45)
            Spell(SWIPE)
   
        if Mana(more 15)
            Spell(LACERATE)

        if Mana(less 15)
            Spell(FAERIEFERAL)
    }


[b]Further edit:

The best way to test the "between" code is simple.

Clear the entire script (leaving all the #defines though, obviously).

You take an ability like Mangle that has a cooldown and the ability like Lacerate which doesn't, and do something like...
Code: Select all
if less than 3s between Spell(MANGLEBEAR) and Spell(LACERATE)
    Spell(MANGLEBEAR priority=4)


And observe the results. Try using a variety of methods as described in the Ovale Documentation to see if you can get it working as intended.

Exalted
User avatar
Posts: 1145
Joined: Fri Jun 04, 2010 4:28 am

Re: Leafkiller's 4.01 Feral Ovale Script

Postby Leafkiller » Wed Nov 17, 2010 3:08 pm

@Timbermaw

Thanks for you post. Below are some of my initial thoughts:

* The between code does work - you will see it in the cat rotation code when deciding whether or not to SR early when SR and Rip are going to expire close to each other.

* Since we can check for current rage, rather than have a separate set of code for rage efficient tanking, we can build that into one script with "Mana(more or less)" checks on high rage abilities.

* .1 seconds is much too small a number to check to decide which abilities to cast first. I really don't think you need that in this case - since the key criteria is more a question of not missing a GCD for critical abilities while making sure there is enough rage. Using priority to ensure an ability is cast first within certain time windows may be the way to go. I have tried that while doing cat simulations but to date have never found a case where it was a dps up - but that was always around TF which has a secondary issue that even if TF is off of cooldown you may still wait before casting it due to high energy or ooc - so the cascade effect of waiting is costly. The equivalent consideration in the bear code would be not having enough rage.

* I am inclined to remove the swipe code completely from the single target rotation and focus on a level 85 script. Swipe is changing to 15 rage in cata with half the damage and will no longer be part of a single target rotation (unless Blizz backtracks). We have at most 3 weeks of raiding until cata and my focus has shifted to being ready for that. Astrylian put up an interesting post on his EJB thread showing many different tanking rotations that are gear dependent - but there are patterns in it. The challenge is building a reasonable rotation that we can model in Ovale.

Posts: 26
Joined: Fri Oct 15, 2010 11:10 pm

Re: Leafkiller's 4.01 Feral Ovale Script

Postby tbot » Thu Nov 18, 2010 5:00 pm

Leaf, for level 81+ replace swipe with thrash and you are back to the highest tps rotation. The timing and positioning of the thrash is still correct.

Swipe would eventually be higher TPS at stacked values of vengeance then lacerate fillers, but it would cause too many issues in the rotation if you were to include it and thrash.

Edit: Your FFF code is unneeded Tinder. Any bear that isn't specing a wonky hybrid spec will have the talent to apply 3x stack with one press.

#MINOR
#Issue: No longer need supporting mangle code.

if TargetDebuffPresent(LACERATE stacks=3)
Spell(PULVERIZE)


Sorry tinder, your assumption and conclusions on this are incorrect. The conditional on pulverise is so that you only use pulverise on the 1st or 2nd gcd after a mangle. This gaurantees you will always have a gcd to reapply lacerate before mangle comes off cd.

Not doing so is a fairly substantial tps loss over the long haul due to loss in possible berzerk procs.

Exalted
User avatar
Posts: 1145
Joined: Fri Jun 04, 2010 4:28 am

Re: Leafkiller's 4.01 Feral Ovale Script

Postby Leafkiller » Sun Nov 21, 2010 6:52 pm

Version 1.1.2 of the script posted. It includes code to clip Rake if TF is up and Rake remaining is less than 9 seconds. It also no longer pools energy during TF. I also removed the option to not clip Rip. If you get the "More powerful spell active" message, just spam Rip.

Next

Return to Kitty DPS

Who is online

Users browsing this forum: aggixx, Robd, Roogz and 13 guests