Paloro wrote:Mangle is actually the better cp generator outside of Berserk and TF.

Ah ok thanks, noxxic wasnt saying anything about that.

Since these types of questions seem to get asked a lot, it would be cool if someone could maintain a generic PvE Feral thread here at the FluidDruid, that outlines all of the best practices, similar to: http://us.battle.net/wow/en/forum/topic/6471617676 but more focused on the action list and mechanics.

Things like: when to use various cooldowns, how to open, how to AoE, when to AoE, when to tab-Rake, casting during HotW, how snapshotting works, how clipping works, various buff strengths (see Ovale/DroodFocus + Catus Rake/Rip tables), symbiosis overview, critical macros (shiftless-HT, TF+Berserk), etc...

It would be cool to have a breakdown of the Simc/Ovale script with approximate English descriptions, so non-technical Cats can understand what's going on.

I think having a comprehensive and up-to-date Feral Cheat-sheet would be very valuable, as a lot of this information is currently spread across various threads.

I have been wanting to do this, but my life has pretty much been, Work, Raid, Work some more, Sleep. Now that Lei Shen is down and work is starting to quite down I might have the time to pull lots of stuff together. If someone beats me to it that's fine. I think we need to readjust the stickies anyway. They are starting to get out of control.

}AddFunction TotalRipMultiplier{ RuneExpiresRipMultiplier()*TigersFuryExpiresRipMultiplier()}AddFunction TotalRipAttackPower{ DancingSteelExpiresRipAttackPower() + SoulCharmExpiresRipAttackPower() + BadJujuExpiresRipAttackPower() + ViciousTalismanExpiresRipAttackPower()}AddFunction FutureRipTickDamage{ {RipBaseDamage() + {{RipDamagePerComboPoint() + {RipDamagePerComboPointAttackPower() * {AttackPower() - TotalRipAttackPower()}}} * ComboPoints()}} * DamageMultiplier(RIP) * {1 + {MeleeCritChance() - TotalRipAttackPower()/CritPerAP()/{1+0.1*BuffStacks(attack_power_multiplier any=1)}}/100} * {1 + Mastery()/100} / TotalRipMultiplier()}AddFunction RipDamageTillDead{ # The damage from Rip that is cast under the current conditions and lasting till target is dead. # Multiply the damage per tick with the number of ticks that can fit into the time to die. FutureRipTickDamage() * {target.TimeToDie() / 2}}AddFunction ExistingRipDamageTillDead{ # The damage from Rip that is already on the target and lasting till target is dead. if target.DebuffPresent(RIP) { # Multiply the damage per tick with the number of ticks that can fit into the time to die. LastRipTickDamage() * {target.TimeToDie() / 2} } 0}

AddFunction IncarnationBerserkLogic{ #incarnation,if=energy<=35&!buff.omen_of_clarity.react&cooldown.tigers_fury.remains=0&cooldown.berserk.remains=0 #use_item,name=eternal_blossom_grips,sync=tigers_fury #tigers_fury,if=(energy<=35&!buff.omen_of_clarity.react)|buff.king_of_the_jungle.up #berserk,if=buff.tigers_fury.up|(target.time_to_die<15&cooldown.tigers_fury.remains>6) if {{Energy() <=35 and BuffExpires(CLEARCASTING)} or BuffPresent(INCARNATION_CAT)} and Spell(TIGERS_FURY) { if CheckBoxOn(berserk) and Spell(BERSERK_CAT) { if TalentPoints(INCARNATION_TALENT) Spell(INCARNATION) if not TalentPoints(INCARNATION_TALENT) or BuffPresent(INCARNATION_CAT) Spell(BERSERK_CAT) } unless BuffPresent(BERSERK_CAT) Spell(TIGERS_FURY) } if CheckBoxOn(berserk) and TalentPoints(INCARNATION_TALENT) and BuffPresent(BERSERK_CAT) Spell(INCARNATION_CAT)}

AddFunction ExecuteRangeRipFerociousBiteLogic # Left one Doc line in here and added a talent check, normally tried to take them out but this one was annoyingly in a bad place so left here for simplicities sake{ #ferocious_bite,if=combo_points>=1&dot.rip.ticking&dot.rip.remains<=3&target.health.pct<=25 if target.HealthPercent() <=25 and ComboPoints() >=1 and target.DebuffPresent(RIP) and target.DebuffRemains(RIP) <=4 Spell(FEROCIOUS_BITE)

#thrash_cat,if=target.time_to_die>=6&buff.omen_of_clarity.react&dot.thrash_cat.remains<3 if target.TimeToDie() >=9 and BuffPresent(CLEARCASTING) and target.DebuffRemains(THRASH_CAT) <3 Spell(THRASH_CAT)

if ComboPoints() >=5 { #natures_swiftness,if=buff.dream_of_cenarius_damage.down&buff.predatory_swiftness.down&combo_points>=5&target.health.pct<=25 if TalentPoints(DREAM_OF_CENARIUS_TALENT) and TalentPoints(NATURES_SWIFTNESS_TALENT) and BuffExpires(DREAM_OF_CENARIUS_DAMAGE) and BuffExpires(PREDATORY_SWIFTNESS) and BuffRemains(SAVAGE_ROAR) >5 Spell(NATURES_SWIFTNESS)

#virmens_bite_potion,if=combo_points>=5&$(time_til_bitw)<15&$(rip_ratio)>=1.15&buff.dream_of_cenarius_damage.up # if not HasTrinket(ROR_ITEM) and ComboPoints() >=5 and BuffPresent(DREAM_OF_CENARIUS_DAMAGE) and RipRatio() >=115 UsePotion()

#virmens_bite_potion,if=combo_points>=5&$(time_til_bitw)<15&buff.rune_of_reorigination.up&buff.dream_of_cenarius_damage.up # if HasTrinket(ROR_ITEM) and ComboPoints() >=5 and BuffPresent(DREAM_OF_CENARIUS_DAMAGE) and BuffPresent(ROR_MASTERY) UsePotion()

AddFunction DocRipLogic # If any changes are applicable to NonDoc logic, also make changes there!!!{ if target.HealthPercent() >25 and ComboPoints() >=5 and target.TimeToDie() >30 and RipRatio() >=92 { #natures_swiftness,if=enabled&buff.dream_of_cenarius_damage.down&buff.predatory_swiftness.down&combo_points>=5&$(rip_ratio)>=0.92&target.time_to_die>30 if TalentPoints(NATURES_SWIFTNESS_TALENT) and BuffExpires(DREAM_OF_CENARIUS_DAMAGE) and BuffExpires(PREDATORY_SWIFTNESS) Spell(NATURES_SWIFTNESS)

AddFunction NonDocRipLogic # If any changes are applicable to Doc logic, also make changes there!!!{ #rip,if=combo_points>=5&$(rip_ratio)>=1.15&target.time_to_die>30 #rip,if=combo_points>=5&target.time_to_die>=6&dot.rip.remains<2&(buff.berserk.up|dot.rip.remains+1.9<=cooldown.tigers_fury.remains) if {target.HealthPercent() >25 and ComboPoints() >=5 and target.TimeToDie() >30 and RipRatio() >= 115} or {target.TimeToDie() >=6 and ComboPoints() >=5 and target.DebuffRemains(RIP) <2} Spell(RIP)}

#healing_touch,if=buff.predatory_swiftness.up&combo_points>=4&buff.dream_of_cenarius_damage.down if BuffPresent(PREDATORY_SWIFTNESS) and BuffExpires(DREAM_OF_CENARIUS_DAMAGE) and ComboPoints() >=4 Spell(HEALING_TOUCH)

Huge decrease in CPU utilization from some tweaks Jeshu made to ovale. My script still uses about twice what the current official script does but that's more like 2.5% vs 5% instead of the 20-30% it could use before (or 10-20% if you hacked the throttling back into 5.3.6 like I did). My calculation heavy script should perform about equal to what the official script did in 5.3.6.

Not seeing any obvious bugs (not for ferals anyhow, weapon damage doesn't work for non-ferals) and anyone that had to revert back to 5.3.2 should be able to update to 5.3.7 with no problems.

Spanja wrote:I see that sometimes you suggest to cast Savage Roar on 5 cp with a proc of Predatory Swiftness, which will results in a refresh of Predator Swiftness and you'll lose the bonus of a DoC.

I see in the script that everytime you suggest a HT it's because PS is about to expire. Isn't it better to check if there isn't already any PS proc ?

BTW, 3.5.7 seems a lot better, thanks for your work

Hrm, is savage roar completely gone at that point? Because that should be the only case of it suggesting savage roar before healing touch.

The top of the DoC action list is:Healing Touch if Predatory Swiftness is about to expire and DoCd is downSavage roar if it is expiredHealing touch at >=4 combo points if PS is up and DoCd is downHealing touch if Nature's swiftness is up

Your case should only be occurring if either Savage Roar is completely expired or for some reason you still have a DoC buff up (I don't see how barring using Nature's Swiftness as a heal)

This happens so rarely in simcraft (like 25% of attempts) that its pretty much impossible to measure the DPS impact of such a change.

ShmooDude wrote:Huge decrease in CPU utilization from some tweaks Jeshu made to ovale. My script still uses about twice what the current official script does but that's more like 2.5% vs 5% instead of the 20-30% it could use before (or 10-20% if you hacked the throttling back into 5.3.6 like I did). My calculation heavy script should perform about equal to what the official script did in 5.3.6.

In Ovale 5.3.7, if you factor out common code into a function, then that function is basically only evaluated once and the results saved for the current run of the script. There are some more caveats in the details, but that's the best way to understand it. The time savings can be quite significant.

I also fixed some code that I broke a while back that throttled the number of times that a script was run. The refresh interval is currently exposed in the new, reorganized configuration panel under "Icon", and can be changed to vary from 0ms to 500ms. The default value is 100ms, which seems about right for catching consecutive game events and factoring in typical latency.

I certainly welcome all the testing and suggested improvements to Ovale to drive development. Ovale started out as a rather simple scripting engine with rather simple scripts, and it has grown quite a lot since Wrath of the Lich King. Leafkiller's original scripts drove a lot of development in the previous patch, and the feral scripts in this thread have continued the trend. I'm looking forward to more feedback.

Well I suppose I should say thanks and congratulations on the huge efficiency changes. While it's definitely no excuse to forsake efficiency it does definitely allow for a lot more breathing room in terms of what's possible (or reasonable) to do in the script.

Jeshu wrote:Leafkiller's original scripts drove a lot of development in the previous patch, and the feral scripts in this thread have continued the trend. I'm looking forward to more feedback.

That is because Feral's are crazy...and optimize/theorycraft as much or more than any other class. I think it started in BC when we became viable tanks for most of the encounters but our kitty dps was 30+% lower than anyone else's. Anyone else remember the power-shifting addon?

The complexity (and efficacy) of the script has made huge leaps forward in MoP, and none of that would have been possible without your support and enhancements to Ovale, Jeshu. Thanks for making it possible

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

Jeshu wrote:In Ovale 5.3.7, if you factor out common code into a function, then that function is basically only evaluated once and the results saved for the current run of the script.

Sounds good - and provides extra incentive to write the scripts in a structured way. The three most common methods of scaling software are introducing parallelism (i.e. multiple instances which is not viable for this use case), cutting down on I/O (including system calls), and fixing expensive algorithms/cutting down on processing. Your changes are attacking a combination of the I/O and processing. Hopefully you can continue to find opportunities in Ovale to further optimize processing time and to cut down on system I/O.

}AddFunction TotalRipMultiplier{ RuneExpiresRipMultiplier()*TigersFuryExpiresRipMultiplier()}AddFunction TotalRipAttackPower{ DancingSteelExpiresRipAttackPower() + SoulCharmExpiresRipAttackPower() + BadJujuExpiresRipAttackPower() + ViciousTalismanExpiresRipAttackPower()}AddFunction FutureRipTickDamage{ {RipBaseDamage() + {{RipDamagePerComboPoint() + {RipDamagePerComboPointAttackPower() * {AttackPower() - TotalRipAttackPower()}}} * ComboPoints()}} * DamageMultiplier(RIP) * {1 + {MeleeCritChance() - TotalRipAttackPower()/CritPerAP()/{1+0.1*BuffStacks(attack_power_multiplier any=1)}}/100} * {1 + Mastery()/100} / TotalRipMultiplier()}AddFunction RipDamageTillDead{ # The damage from Rip that is cast under the current conditions and lasting till target is dead. # Multiply the damage per tick with the number of ticks that can fit into the time to die. FutureRipTickDamage() * {target.TimeToDie() / 2}}AddFunction ExistingRipDamageTillDead{ # The damage from Rip that is already on the target and lasting till target is dead. if target.DebuffPresent(RIP) { # Multiply the damage per tick with the number of ticks that can fit into the time to die. LastRipTickDamage() * {target.TimeToDie() / 2} } 0}

AddFunction IncarnationBerserkLogic{ #incarnation,if=energy<=35&!buff.omen_of_clarity.react&cooldown.tigers_fury.remains=0&cooldown.berserk.remains=0 #use_item,name=eternal_blossom_grips,sync=tigers_fury #tigers_fury,if=(energy<=35&!buff.omen_of_clarity.react)|buff.king_of_the_jungle.up #berserk,if=buff.tigers_fury.up|(target.time_to_die<15&cooldown.tigers_fury.remains>6) if {{Energy() <=35 and BuffExpires(CLEARCASTING)} or BuffPresent(INCARNATION_CAT)} and Spell(TIGERS_FURY) { if CheckBoxOn(berserk) and Spell(BERSERK_CAT) { if TalentPoints(INCARNATION_TALENT) Spell(INCARNATION) if not TalentPoints(INCARNATION_TALENT) or BuffPresent(INCARNATION_CAT) Spell(BERSERK_CAT) } unless BuffPresent(BERSERK_CAT) Spell(TIGERS_FURY) } if CheckBoxOn(berserk) and TalentPoints(INCARNATION_TALENT) and BuffPresent(BERSERK_CAT) Spell(INCARNATION_CAT)}

AddFunction ExecuteRangeRipFerociousBiteLogic # Left one Doc line in here and added a talent check, normally tried to take them out but this one was annoyingly in a bad place so left here for simplicities sake{ #ferocious_bite,if=combo_points>=1&dot.rip.ticking&dot.rip.remains<=3&target.health.pct<=25 if target.HealthPercent() <=25 and ComboPoints() >=1 and target.DebuffPresent(RIP) and target.DebuffRemains(RIP) <=4 Spell(FEROCIOUS_BITE)

#thrash_cat,if=target.time_to_die>=6&buff.omen_of_clarity.react&dot.thrash_cat.remains<3 if target.TimeToDie() >=9 and BuffPresent(CLEARCASTING) and target.DebuffRemains(THRASH_CAT) <3 Spell(THRASH_CAT)

if ComboPoints() >=5 { #natures_swiftness,if=buff.dream_of_cenarius_damage.down&buff.predatory_swiftness.down&combo_points>=5&target.health.pct<=25 if TalentPoints(DREAM_OF_CENARIUS_TALENT) and TalentPoints(NATURES_SWIFTNESS_TALENT) and BuffExpires(DREAM_OF_CENARIUS_DAMAGE) and BuffExpires(PREDATORY_SWIFTNESS) and BuffRemains(SAVAGE_ROAR) >5 Spell(NATURES_SWIFTNESS)

#virmens_bite_potion,if=combo_points>=5&$(time_til_bitw)<15&$(rip_ratio)>=1.15&buff.dream_of_cenarius_damage.up # if not HasTrinket(ROR_ITEM) and ComboPoints() >=5 and BuffPresent(DREAM_OF_CENARIUS_DAMAGE) and RipRatio() >=115 UsePotion()

#virmens_bite_potion,if=combo_points>=5&$(time_til_bitw)<15&buff.rune_of_reorigination.up&buff.dream_of_cenarius_damage.up # if HasTrinket(ROR_ITEM) and ComboPoints() >=5 and BuffPresent(DREAM_OF_CENARIUS_DAMAGE) and BuffPresent(ROR_MASTERY) UsePotion()

AddFunction DocRipLogic # If any changes are applicable to NonDoc logic, also make changes there!!!{ if target.HealthPercent() >25 and ComboPoints() >=5 and RipRatio() >=92 { #natures_swiftness,if=enabled&buff.dream_of_cenarius_damage.down&buff.predatory_swiftness.down&combo_points>=5&$(rip_ratio)>=0.92&target.time_to_die>30 if TalentPoints(NATURES_SWIFTNESS_TALENT) and BuffExpires(DREAM_OF_CENARIUS_DAMAGE) and BuffExpires(PREDATORY_SWIFTNESS) Spell(NATURES_SWIFTNESS)

AddFunction NonDocRipLogic # If any changes are applicable to Doc logic, also make changes there!!!{ #rip,if=combo_points>=5&$(rip_ratio)>=1.15 #rip,if=combo_points>=5&target.time_to_die>=6&dot.rip.remains<2 if {target.HealthPercent() >25 and ComboPoints() >=5 and RipRatio() >= 115} or {ComboPoints() >=5 and target.DebuffRemains(RIP) <2} Spell(RIP)}

#healing_touch,if=buff.predatory_swiftness.up&combo_points>=4&buff.dream_of_cenarius_damage.down if BuffPresent(PREDATORY_SWIFTNESS) and BuffExpires(DREAM_OF_CENARIUS_DAMAGE) and ComboPoints() >=4 Spell(HEALING_TOUCH)

A few more optimizations based on the new efficiency of functionsRemoved the timetodie operators from Rip since the execute range stuff will catch anything <25%. Helps on megera where the heads are usually ~60-70 seconds for my guild. Let me know if this has issues with ultra low hp mobs but I don't think it should.Removed wait from thrash as it wasn't actually doing anything (wait in ovale only seems to do anything if you want the energy used for an ability to be higher than its energy cost as in pooling to 50 for ferocious bite since it doesn't let you fall down when the buff conditions are true like simcraft does)A couple of bug fixes related to energy comparisons bug. See Ticket 275A couple of bug fixes related to clearcasting and low energy situations

Ovale keeps telling me to mangle instead of shred. It randomly throw in FF and rake, despite them being on the mob already and keeps telling me to use Thrash(Which I thought was only for OOC procs). Other times it just seems to spaz out like it's trying to pick something but can't. It just shows a dark box with the gcd constantly trying to go off, but gets stuck. A few seconds later it fixes itself. I haven't touched any settings besides the placement.

Any help with this?

Last edited by Allarius on Fri Jul 19, 2013 3:43 pm, edited 1 time in total.

Hey Shmoodude, I had one other strange behavior that I'm not sure is correct. I am using the 5.3.6 script.

I use 543 Rune and 543 Renataki. One behavior I was seeing that seemed wrong to me (but may not be, hence me posting), is that if the two trinkets had overlapping procs with Rune's proc finishing first, the script would suggest that I keep Raking right after Rune expired. I find it hard to believe that this is correct, since it didn't seem like a Renataki Rake would surpass the Rune-buffed Rake, at least not immediately.

I also had a couple of situations in my last raid where I had a DoC and Rune-buffed Rip on the target and below sub-25% the script was suggesting that I re-apply Rip instead of using Ferocious Bite when the Rip was unquestionably weaker than the one I had up, e.g., not backed by Rune or DoC.

Other than those glitches I find the current script to be really good at both Rune and Renataki handling, so yay!

Allarius wrote:Ovale keeps telling me to mangle instead of shred. It randomly throw in FF and rake, despite them being on the mob already and keeps telling me to use Thrash(Which I thought was only for OOC procs). Other times it just seems to spaz out like it's trying to pick something but can't. It just shows a dark box with the gcd constantly trying to go off, but gets stuck. A few seconds later it fixes itself. I haven't touched any settings besides the placement.

Any help with this?

Mangle has been the new CP generator over Shred most of this teir. Shred is only used during OoC procs or berserk/bloodlust.

The FF thing you can avoid by clicking on Ovale and unchecking the FF box. The Rake reasoning is Ovale will tell you to overwrite a bleed with a stronger one at anytime. This happens a lot with Renataki's.

Thrash needs to be up on a target all the time. It is now part of our single target rotation regardless of OoC procs.

The reason behind it bugging out like that is at times it is trying to figure out what to suggest next. My suggestion is don't listen to it all the time. Grab some WA Bleed Ratios and that will help a lot.

}AddFunction TotalRipMultiplier{ RuneExpiresRipMultiplier()*TigersFuryExpiresRipMultiplier()}AddFunction TotalRipAttackPower{ DancingSteelExpiresRipAttackPower() + SoulCharmExpiresRipAttackPower() + BadJujuExpiresRipAttackPower() + ViciousTalismanExpiresRipAttackPower()}AddFunction FutureRipTickDamage{ {RipBaseDamage() + {{RipDamagePerComboPoint() + {RipDamagePerComboPointAttackPower() * {AttackPower() - TotalRipAttackPower()}}} * ComboPoints()}} * DamageMultiplier(RIP) * {1 + {MeleeCritChance() - TotalRipAttackPower()/CritPerAP()/{1+0.1*BuffStacks(attack_power_multiplier any=1)}}/100} * {1 + Mastery()/100} / TotalRipMultiplier()}AddFunction RipDamageTillDead{ # The damage from Rip that is cast under the current conditions and lasting till target is dead. # Multiply the damage per tick with the number of ticks that can fit into the time to die. FutureRipTickDamage() * {target.TimeToDie() / 2}}AddFunction ExistingRipDamageTillDead{ # The damage from Rip that is already on the target and lasting till target is dead. if target.DebuffPresent(RIP) { # Multiply the damage per tick with the number of ticks that can fit into the time to die. LastRipTickDamage() * {target.TimeToDie() / 2} } 0}

AddFunction IncarnationBerserkTigersFuryLogic{ #incarnation,if=energy<=35&!buff.omen_of_clarity.react&cooldown.tigers_fury.remains=0&cooldown.berserk.remains=0 #use_item,name=eternal_blossom_grips,sync=tigers_fury #tigers_fury,if=(energy<=35&!buff.omen_of_clarity.react)|buff.king_of_the_jungle.up #berserk,if=buff.tigers_fury.up|(target.time_to_die<15&cooldown.tigers_fury.remains>6) if {{Energy() <=35 and BuffExpires(CLEARCASTING)} or BuffPresent(INCARNATION_CAT)} and Spell(TIGERS_FURY) { if CheckBoxOn(berserk) and Spell(BERSERK_CAT) { if TalentPoints(INCARNATION_TALENT) Spell(INCARNATION) if not TalentPoints(INCARNATION_TALENT) or BuffPresent(INCARNATION_CAT) Spell(BERSERK_CAT) } unless BuffPresent(BERSERK_CAT) Spell(TIGERS_FURY) } if CheckBoxOn(berserk) and TalentPoints(INCARNATION_TALENT) and BuffPresent(BERSERK_CAT) Spell(INCARNATION_CAT)}

AddFunction ExecuteRangeRipFerociousBiteLogic # Left one Doc line in here and added a talent check, normally tried to take them out but this one was annoyingly in a bad place so left here for simplicities sake{ #ferocious_bite,if=combo_points>=1&dot.rip.ticking&dot.rip.remains<=3&target.health.pct<=25 if target.HealthPercent() <=25 and ComboPoints() >=1 and target.DebuffPresent(RIP) and target.DebuffRemains(RIP) <=4 { Spell(FEROCIOUS_BITE) }

if ComboPoints() >=5 { #natures_swiftness,if=buff.dream_of_cenarius_damage.down&buff.predatory_swiftness.down&combo_points>=5&target.health.pct<=25 if TalentPoints(DREAM_OF_CENARIUS_TALENT) and TalentPoints(NATURES_SWIFTNESS_TALENT) and BuffExpires(DREAM_OF_CENARIUS_DAMAGE) and BuffExpires(PREDATORY_SWIFTNESS) and BuffRemains(SAVAGE_ROAR) >5 { Spell(NATURES_SWIFTNESS) }

#virmens_bite_potion,if=combo_points>=5&$(time_til_bitw)<15&$(rip_ratio)>=1.15&buff.dream_of_cenarius_damage.up # if not HasTrinket(ROR_ITEM) and ComboPoints() >=5 and BuffPresent(DREAM_OF_CENARIUS_DAMAGE) and RipRatio() >=115 UsePotion()

#virmens_bite_potion,if=combo_points>=5&$(time_til_bitw)<15&buff.rune_of_reorigination.up&buff.dream_of_cenarius_damage.up # if HasTrinket(ROR_ITEM) and ComboPoints() >=5 and BuffPresent(DREAM_OF_CENARIUS_DAMAGE) and BuffPresent(ROR_MASTERY) UsePotion()

AddFunction DocRipLogic # If any changes are applicable to NonDoc logic, also make changes there!!!{ if target.HealthPercent() >25 and ComboPoints() >=5 and RipRatio() >=92 { #natures_swiftness,if=enabled&buff.dream_of_cenarius_damage.down&buff.predatory_swiftness.down&combo_points>=5&$(rip_ratio)>=0.92 if TalentPoints(NATURES_SWIFTNESS_TALENT) and BuffExpires(DREAM_OF_CENARIUS_DAMAGE) and BuffExpires(PREDATORY_SWIFTNESS) { Spell(NATURES_SWIFTNESS) }

#healing_touch,if=buff.predatory_swiftness.up&combo_points>=4&buff.dream_of_cenarius_damage.down if BuffPresent(PREDATORY_SWIFTNESS) and BuffExpires(DREAM_OF_CENARIUS_DAMAGE) and ComboPoints() >=4 Spell(HEALING_TOUCH)

Kihrawr wrote:Hey Shmoodude, I had one other strange behavior that I'm not sure is correct. I am using the 5.3.6 script.

I use 543 Rune and 543 Renataki. One behavior I was seeing that seemed wrong to me (but may not be, hence me posting), is that if the two trinkets had overlapping procs with Rune's proc finishing first, the script would suggest that I keep Raking right after Rune expired. I find it hard to believe that this is correct, since it didn't seem like a Renataki Rake would surpass the Rune-buffed Rake, at least not immediately.

I also had a couple of situations in my last raid where I had a DoC and Rune-buffed Rip on the target and below sub-25% the script was suggesting that I re-apply Rip instead of using Ferocious Bite when the Rip was unquestionably weaker than the one I had up, e.g., not backed by Rune or DoC.

Other than those glitches I find the current script to be really good at both Rune and Renataki handling, so yay!

Are you using 5.3.6 with it? There's a pretty serious bug in 5.3.6 where Ovale will "forget" the values for Rip on a target (only seems to happen in raids for me, i can do target dummies all day long and not run into the bug) and thus anytime that happens it will always think a new rip is better. Jeshu thinks he has this fixed for 5.3.7 but I haven't had an opportunity to test it yet.

Rune logic I got messed up and it wasn't actually fixing the recommendations close to expiring so in newer versions I simply made it match the rest of them (with an "assumed" ratio of 2.0, which while not mathematically perfect, should still generate the correct recommendations)

Spanja wrote:I see that sometimes you suggest to cast Savage Roar on 5 cp with a proc of Predatory Swiftness, which will results in a refresh of Predator Swiftness and you'll lose the bonus of a DoC.

I see in the script that everytime you suggest a HT it's because PS is about to expire. Isn't it better to check if there isn't already any PS proc ?

BTW, 3.5.7 seems a lot better, thanks for your work

I think leafkiller found the problem with this. It was me not understanding the intricacies of how ovale evaluates all valid nodes and then picks the one it thinks is best (based on soonest occuring I believe). DoC was evaluating both the DoC and Non-Doc code and so was probably getting a valid Savage Roar call from the non-doc code. Should be fixed in 5.3.7 version above.

ShmooDude wrote:Removed wait from thrash as it wasn't actually doing anything (wait in ovale only seems to do anything if you want the energy used for an ability to be higher than its energy cost as in pooling to 50 for ferocious bite since it doesn't let you fall down when the buff conditions are true like simcraft does)

Could you elaborate on this? The way I implemented wait in Ovale was based on the documentation for SimC's pool_resource. What were you trying to do with Thrash and wait?

ShmooDude wrote:Are you using 5.3.6 with it? There's a pretty serious bug in 5.3.6 where Ovale will "forget" the values for Rip on a target (only seems to happen in raids for me, i can do target dummies all day long and not run into the bug) and thus anytime that happens it will always think a new rip is better. Jeshu thinks he has this fixed for 5.3.7 but I haven't had an opportunity to test it yet.

If the changes in 5.3.7 don't fix it, then I have another solution in mind that I was trying to avoid but will likely fix it definitively. The problem is that it can make Ovale's memory usage grow and it would rely on the Lua garbage collector instead of the pool code I had implemented into various modules to bound memory usage. However, if it's needed for correctness, then there's not much choice -- DoT snapshotting is too important of a feature to roll back as it's needed for many class's optimal action lists (pretty much every DoT class).

ShmooDude wrote:Removed wait from thrash as it wasn't actually doing anything (wait in ovale only seems to do anything if you want the energy used for an ability to be higher than its energy cost as in pooling to 50 for ferocious bite since it doesn't let you fall down when the buff conditions are true like simcraft does)

Could you elaborate on this? The way I implemented wait in Ovale was based on the documentation for SimC's pool_resource. What were you trying to do with Thrash and wait?

Basically, the way it was coded (this is from the official script) there was no need for the "wait"

Since as soon as all the conditions become true, the icon will change from Mangle to Thrash regardless of energy level (assuming there wasn't something higher up in the list needed to be done). However, in Simcraft, if you don't use wait, it will fall past Thrash and actually use mangle, thus never having enough energy to use Thrash (50 energy for thrash vs 35 energy for Mangle).I don't think its a problem. I think its just a case of the wait being put in to match simcraft when its simply not necessary in ovale unless the amount of energy you want to use it at is greater than the energy cost of the ability (as with Ferocious Bite where we use it at 50 energy when it costs 25), and so I went ahead and removed it (it functions exactly the same both with and without the wait).

Jeshu wrote:

ShmooDude wrote:Huge decrease in CPU utilization from some tweaks Jeshu made to ovale. My script still uses about twice what the current official script does but that's more like 2.5% vs 5% instead of the 20-30% it could use before (or 10-20% if you hacked the throttling back into 5.3.6 like I did). My calculation heavy script should perform about equal to what the official script did in 5.3.6.

In Ovale 5.3.7, if you factor out common code into a function, then that function is basically only evaluated once and the results saved for the current run of the script. There are some more caveats in the details, but that's the best way to understand it. The time savings can be quite significant.

I also fixed some code that I broke a while back that throttled the number of times that a script was run. The refresh interval is currently exposed in the new, reorganized configuration panel under "Icon", and can be changed to vary from 0ms to 500ms. The default value is 100ms, which seems about right for catching consecutive game events and factoring in typical latency.

I certainly welcome all the testing and suggested improvements to Ovale to drive development. Ovale started out as a rather simple scripting engine with rather simple scripts, and it has grown quite a lot since Wrath of the Lich King. Leafkiller's original scripts drove a lot of development in the previous patch, and the feral scripts in this thread have continued the trend. I'm looking forward to more feedback.

I had a thought on another optimization, though I don't know how easy/difficult it would be to implement.

Would it be possible to extend the current logic of only evaluating a function once to any matching nodes/node comparison?

AddIcon{ if Energy() >= 50 if Energy() >= 50 # repeated * 3000 to get an idea of the difference in CPU usage if Energy() >= 50 if Energy() >= 50 Spell(1822)}

The first runs at about half the CPU utilization of the second showing that its more efficient if you have any sections that repeat to throw them into a function. What I was thinking was if ovale could recognize that the code sections are identical, to just run the comparison once and save the value.

Not sure how well this would work (if the extra overhead in looking for like comparisons would nullify the savings from saving it for example) or how easy it would be to implement, but I figured it couldn't hurt throwing the idea out there.

}AddFunction TotalRipMultiplier{ RuneExpiresRipMultiplier()*TigersFuryExpiresRipMultiplier()}AddFunction TotalRipAttackPower{ DancingSteelExpiresRipAttackPower() + SoulCharmExpiresRipAttackPower() + BadJujuExpiresRipAttackPower() + ViciousTalismanExpiresRipAttackPower()}AddFunction FutureRipTickDamage{ {RipBaseDamage() + {{RipDamagePerComboPoint() + {RipDamagePerComboPointAttackPower() * {AttackPower() - TotalRipAttackPower()}}} * ComboPoints()}} * DamageMultiplier(RIP) * {1 + {MeleeCritChance() - TotalRipAttackPower()/CritPerAP()/{1+0.1*BuffStacks(attack_power_multiplier any=1)}}/100} * {1 + Mastery()/100} / TotalRipMultiplier()}AddFunction RipDamageTillDead{ # The damage from Rip that is cast under the current conditions and lasting till target is dead. # Multiply the damage per tick with the number of ticks that can fit into the time to die. FutureRipTickDamage() * {target.TimeToDie() / 2}}AddFunction ExistingRipDamageTillDead{ # The damage from Rip that is already on the target and lasting till target is dead. if target.DebuffPresent(RIP) { # Multiply the damage per tick with the number of ticks that can fit into the time to die. LastRipTickDamage() * {target.TimeToDie() / 2} } 0}

AddFunction IncarnationBerserkTigersFuryLogic{ #incarnation,if=energy<=35&!buff.omen_of_clarity.react&cooldown.tigers_fury.remains=0&cooldown.berserk.remains=0 #use_item,name=eternal_blossom_grips,sync=tigers_fury #tigers_fury,if=(energy<=35&!buff.omen_of_clarity.react)|buff.king_of_the_jungle.up #berserk,if=buff.tigers_fury.up|(target.time_to_die<15&cooldown.tigers_fury.remains>6) if {{Energy() <=35 and BuffExpires(CLEARCASTING)} or BuffPresent(INCARNATION_CAT)} and Spell(TIGERS_FURY) { if CheckBoxOn(berserk) and Spell(BERSERK_CAT) { if TalentPoints(INCARNATION_TALENT) Spell(INCARNATION) if not TalentPoints(INCARNATION_TALENT) or BuffPresent(INCARNATION_CAT) Spell(BERSERK_CAT) } unless BuffPresent(BERSERK_CAT) Spell(TIGERS_FURY) } if CheckBoxOn(berserk) and TalentPoints(INCARNATION_TALENT) and BuffPresent(BERSERK_CAT) Spell(INCARNATION_CAT)}

AddFunction ExecuteRangeRipFerociousBiteLogic # Left one Doc line in here and added a talent check, normally tried to take them out but this one was annoyingly in a bad place so left here for simplicities sake{ #ferocious_bite,if=combo_points>=1&dot.rip.ticking&dot.rip.remains<=3&target.health.pct<=25 if target.HealthPercent() <=25 and ComboPoints() >=1 and target.DebuffPresent(RIP) and target.DebuffRemains(RIP) <=4 { Spell(FEROCIOUS_BITE) }

if ComboPoints() >=5 { #natures_swiftness,if=buff.dream_of_cenarius_damage.down&buff.predatory_swiftness.down&combo_points>=5&target.health.pct<=25 if TalentPoints(DREAM_OF_CENARIUS_TALENT) and TalentPoints(NATURES_SWIFTNESS_TALENT) and BuffExpires(DREAM_OF_CENARIUS_DAMAGE) and BuffExpires(PREDATORY_SWIFTNESS) and BuffRemains(SAVAGE_ROAR) >5 { Spell(NATURES_SWIFTNESS) }

#virmens_bite_potion,if=combo_points>=5&$(time_til_bitw)<15&$(rip_ratio)>=1.15&buff.dream_of_cenarius_damage.up # if not HasTrinket(ROR_ITEM) and ComboPoints() >=5 and BuffPresent(DREAM_OF_CENARIUS_DAMAGE) and RipRatio() >=115 UsePotion()

#virmens_bite_potion,if=combo_points>=5&$(time_til_bitw)<15&buff.rune_of_reorigination.up&buff.dream_of_cenarius_damage.up # if HasTrinket(ROR_ITEM) and ComboPoints() >=5 and BuffPresent(DREAM_OF_CENARIUS_DAMAGE) and BuffPresent(ROR_MASTERY) UsePotion()

AddFunction DocRipLogic # If any changes are applicable to NonDoc logic, also make changes there!!!{ if target.HealthPercent() >25 and ComboPoints() >=5 and RipRatio() >=92 { #natures_swiftness,if=enabled&buff.dream_of_cenarius_damage.down&buff.predatory_swiftness.down&combo_points>=5&$(rip_ratio)>=0.92 if TalentPoints(NATURES_SWIFTNESS_TALENT) and BuffExpires(DREAM_OF_CENARIUS_DAMAGE) and BuffExpires(PREDATORY_SWIFTNESS) { Spell(NATURES_SWIFTNESS) }

#healing_touch,if=buff.predatory_swiftness.up&combo_points>=4&buff.dream_of_cenarius_damage.down if BuffPresent(PREDATORY_SWIFTNESS) and BuffExpires(DREAM_OF_CENARIUS_DAMAGE) and ComboPoints() >=4 Spell(HEALING_TOUCH)

ShmooDude wrote:The first runs at about half the CPU utilization of the second showing that its more efficient if you have any sections that repeat to throw them into a function. What I was thinking was if ovale could recognize that the code sections are identical, to just run the comparison once and save the value.

I looked at implementing this originally, but the problem with this approach is that the standard conditions can have parameters, which changes the total function signature. For example, target.Casting() is different from player.Casting() but it's the same base Casting() call, just with different target parameters. It's possible to create a hash of the function name and the entire parameter list and use that hash as a key to a table of cached values and then to use that to auto-optimize the script evaluation. I did take a stab at quickly implementing that; however, the implementation is tricky and rather than spending time on getting that working, I just went with the simpler change for now just so I could release at least this improvement for complex scripts.

In the spirit of looking for ways to do less processing here is an idea for you to consider:

Currently, (as I understand it) for each icon, Ovale will do a complete walkthrough of the script calculating the time when every node will be ready. If any nodes have time zero, then the highest priority node that is earliest in the script is displayed to the user. If no nodes have a zero time, then the one that will be ready the soonest will be shown with a cooldown.

Because it is possible to specify different priorities for spells, even when the script comes across a node that has a time of zero, it needs to continue to evaluate the rest of the nodes in the script.

So - if Ovale knew that there are no nodes later in a script with a higher priority (something that is characteristic of the simc scripts) it could stop building the node list anytime it found a node with a time of zero since no future nodes would ever replace that node as the one to be displayed.

This could be determined programmatically, or via a setting by the script writer.

Is my understanding correct, or are there other reasons that require a full scan of the script even when a node with time zero has been found?

# ShmooDude's modified Leafkiller's Feral/Guardian druid script.# Support/Discussion thread: http://fluiddruid.net/forum/viewtopic.php?f=3&t=857# 7/20/13 version 5.3.8.1 # Switched from berserk testing to the new built in EnergyCost(ability) function for determining the energy for abilities.# Switched from (EnergyCost - CurrentEnergy) / EnergyRegen to the new built in function TimeToEnergyFor(ability).# Slight code reorganization to make it easier to browse.# More things in functions for better efficiency.# Allowed the user to customize the safety margin around expiring buffs via a list item.# Removed the "Use Healing CDs for damage" checkbox as its not currently used.# Rake will now compare with ravage instead of mangle if incarnation is up (modified by the difference in energy cost).# Added bug catching code for target based rip damage.# Added a "Debug Mode" checkbox for testing the target.Debuff data vs the LastSpell data.# 7/19/13 Version 5.3.7.3

AddFunction IncarnationBerserkTigersFuryLogic{ #incarnation,if=energy<=35&!buff.omen_of_clarity.react&cooldown.tigers_fury.remains=0&cooldown.berserk.remains=0 #use_item,name=eternal_blossom_grips,sync=tigers_fury #tigers_fury,if=(energy<=35&!buff.omen_of_clarity.react)|buff.king_of_the_jungle.up #berserk,if=buff.tigers_fury.up|(target.time_to_die<15&cooldown.tigers_fury.remains>6) if {{Energy() <=35 and BuffExpires(CLEARCASTING)} or BuffPresent(INCARNATION_CAT)} and Spell(TIGERS_FURY) { if CheckBoxOn(berserk) and Spell(BERSERK_CAT) { if TalentPoints(INCARNATION_TALENT) Spell(INCARNATION) if not TalentPoints(INCARNATION_TALENT) or BuffPresent(INCARNATION_CAT) Spell(BERSERK_CAT) } unless BuffPresent(BERSERK_CAT) Spell(TIGERS_FURY) } if CheckBoxOn(berserk) and TalentPoints(INCARNATION_TALENT) and BuffPresent(BERSERK_CAT) Spell(INCARNATION_CAT)}

AddFunction ExecuteRangeRipFerociousBiteLogic # Left one Doc line in here and added a talent check, normally tried to take them out but this one was annoyingly in a bad place so left here for simplicities sake{ #ferocious_bite,if=combo_points>=1&dot.rip.ticking&dot.rip.remains<=3&target.health.pct<=25 if target.HealthPercent() <=25 and HasAnyComboPoints() and target.DebuffPresent(RIP) and target.DebuffRemains(RIP) <=4 # is 4 instead of 3 because the remaining time on rip can be inaccurate upto 2 seconds { Spell(FEROCIOUS_BITE) }

if MaxComboPoints() { #natures_swiftness,if=buff.dream_of_cenarius_damage.down&buff.predatory_swiftness.down&combo_points>=5&target.health.pct<=25 if TalentPoints(DREAM_OF_CENARIUS_TALENT) and TalentPoints(NATURES_SWIFTNESS_TALENT) and BuffExpires(DREAM_OF_CENARIUS_DAMAGE) and BuffExpires(PREDATORY_SWIFTNESS) and BuffRemains(SAVAGE_ROAR) >5 { Spell(NATURES_SWIFTNESS) }

#virmens_bite_potion,if=combo_points>=5&$(time_til_bitw)<15&$(rip_ratio)>=1.15&buff.dream_of_cenarius_damage.up # if not HasTrinket(ROR_ITEM) and MaxComboPoints() and BuffPresent(DREAM_OF_CENARIUS_DAMAGE) and RipRatio() >=115 UsePotion()

#virmens_bite_potion,if=combo_points>=5&$(time_til_bitw)<15&buff.rune_of_reorigination.up&buff.dream_of_cenarius_damage.up # if HasTrinket(ROR_ITEM) and MaxComboPoints() and BuffPresent(DREAM_OF_CENARIUS_DAMAGE) and BuffPresent(ROR_MASTERY) UsePotion()

AddFunction DocRipLogic ##### If any changes are applicable to NonDoc logic, also make changes there!!!{ if target.HealthPercent() >25 and MaxComboPoints() and RipRatio() >=92 { #natures_swiftness,if=enabled&buff.dream_of_cenarius_damage.down&buff.predatory_swiftness.down&combo_points>=5&$(rip_ratio)>=0.92 if TalentPoints(NATURES_SWIFTNESS_TALENT) and BuffExpires(DREAM_OF_CENARIUS_DAMAGE) and BuffExpires(PREDATORY_SWIFTNESS) { Spell(NATURES_SWIFTNESS) }

#natures_swiftness,if=buff.dream_of_cenarius_damage.down&buff.predatory_swiftness.down&combo_points>=5&dot.rip.remains<3 if TalentPoints(NATURES_SWIFTNESS_TALENT) and BuffExpires(DREAM_OF_CENARIUS_DAMAGE) and BuffExpires(PREDATORY_SWIFTNESS) and MaxComboPoints() and target.DebuffRemains(RIP) <3 { Spell(NATURES_SWIFTNESS) }

#rip,if=combo_points>=5&dot.rip.remains<2 if MaxComboPoints() and target.DebuffRemains(RIP) <2 { Spell(RIP) }} ##### If any changes are applicable to NonDoc logic, also make changes there!!!

AddFunction NonDocRipLogic ##### If any changes are applicable to Doc logic, also make changes there!!!{ #rip,if=combo_points>=5&$(rip_ratio)>=1.15 #rip,if=combo_points>=5&target.time_to_die>=6&dot.rip.remains<2 if {target.HealthPercent() >25 and MaxComboPoints() and RipRatio() >= 115} or {MaxComboPoints() and target.DebuffRemains(RIP) <2} { Spell(RIP) }} ##### If any changes are applicable to Doc logic, also make changes there!!!

AddFunction NonExcuteRangeFerociousBiteLogic{ #actions.doc+=/pool_resource,wait=0.1,if=combo_points>=5&((energy<50&buff.berserk.down)|(energy<25&buff.berserk.remains>1))&dot.rip.ticking&!(dot.rip.remains-2<=energy.time_to_max-1)&!(buff.savage_roar.remains-3<=energy.time_to_max-1) #actions.doc+=/ferocious_bite,if=combo_points>=5&dot.rip.ticking&!(dot.rip.remains-2<=energy.time_to_max-1)&!(buff.savage_roar.remains-3<=energy.time_to_max-1)&!((buff.savage_roar.remains-6<=energy.time_to_max-1)&buff.savage_roar.remains+2<=$(rip_remains)) if MaxComboPoints() and target.DebuffPresent(RIP) and BuffPresent(SAVAGE_ROAR) and not target.DebuffRemains(RIP)-2 <= TimeToMaxEnergy()-1 and not BuffRemains(SAVAGE_ROAR)-3 <= TimeToMaxEnergy()-1 and not {BuffRemains(SAVAGE_ROAR)-6 <= TimeToMaxEnergy()-1 and BuffRemains(SAVAGE_ROAR)+2 <= target.DebuffRemains(RIP)} and target.DebuffRemains(RIP) >=5 { if not HasEnergyForFerociousBite() SpareGcdCooldowns() wait if HasEnergyForFerociousBite() Spell(FEROCIOUS_BITE) }}

#healing_touch,if=buff.predatory_swiftness.up&combo_points>=4&buff.dream_of_cenarius_damage.down if BuffPresent(PREDATORY_SWIFTNESS) and BuffExpires(DREAM_OF_CENARIUS_DAMAGE) and ComboPoints() >=4 Spell(HEALING_TOUCH)

- Switched from berserk testing to the now built in EnergyCost(ability) function for determining the energy for abilities.- Switched from (EnergyCost - CurrentEnergy) / EnergyRegen to the new built in function TimeToEnergyFor(ability)- Slight code reorganization to make it easier to browse.- More things in functions for better efficiency (though realistically its pretty close to as efficient as it can get without changing the logic).- Allowed the user to customize the safety margin around expiring buffs via a list item.- Removed the "Use Healing CDs for damage" checkbox as its not currently used.- Rake will now compare with ravage instead of mangle if incarnation is up (modified by the difference in energy cost). Small DPS up for incarnation builds.- Added bug catching code for target based rip damage. It will try to use target based data but if that data is invalid it will revert back to the old last spell functions (which are working fine). This ensures accuracy on single target fights, might be slightly inaccurate if you're multi-ripping on something like council but still no worse than the old method which always used your last cast's data.- Added a "Debug Mode" checkbox for testing the target.Debuff data vs the LastSpell data when Jeshu makes another update to see if its working (should always match on a single target fight). Wouldn't bother with this unless you wanna help with the testing next version.- Fully reconsiled with simcraft to be DPS neutral or DPS gain.

Next (and probably last till next patch) I think I want to add an aoe rotation. I recently found that you can set a keybind to manipulate checkboxes in ovale so I figured an aoe rotation could be implemented pretty easily with the checkbox/keybind to allow you to swap mid fight.

@JeshuWould it be possible to have access to sliders? If its something that's easy to add, that'd be a better option than the list box for what I'm using it for, if not that's fine too. Alternatively, is there a way to add a label/description to a list box? Right now my list box just says "0.X seconds" which doesn't particularly tell the user what its for but I haven't found a way to label it aside from maybe putting something short as the top list item. Access to a tooltip style description would be the best as if possible I'd like to give a detailed explanation of what its for (so there's no confusion, though probably most people reading this thread know what its for).

Also, how would I go about adding it as a separate script to the Nernian's addon?

ShmooDude wrote:- Added bug catching code for target based rip damage. It will try to use target based data but if that data is invalid it will revert back to the old last spell functions (which are working fine). This ensures accuracy on single target fights, might be slightly inaccurate if you're multi-ripping on something like council but still no worse than the old method which always used your last cast's data.

I should have something to fix this issue in the next few days. Just needs a lot of testing on my end to check for memory leaks.

ShmooDude wrote:@JeshuWould it be possible to have access to sliders? If its something that's easy to add, that'd be a better option than the list box for what I'm using it for, if not that's fine too. Alternatively, is there a way to add a label/description to a list box? Right now my list box just says "0.X seconds" which doesn't particularly tell the user what its for but I haven't found a way to label it aside from maybe putting something short as the top list item. Access to a tooltip style description would be the best as if possible I'd like to give a detailed explanation of what its for (so there's no confusion, though probably most people reading this thread know what its for).

A list box just uses the text you put there, so you can put a short description there for now. I can add a tooltip description, which shouldn't be too difficult. Just submit an enhancement ticket for it so I don't forget. I'm old so I'm forgetful

ShmooDude wrote:Also, how would I go about adding it as a separate script to the Nernian's addon?

If you'd like to add it, it's as simple as just letting me know. If you're familiar with using GitHub, that's the simplest way for you to maintain it and letting me easily pull in changes (this is how @aggixx does it). If not, then just submit a ticket for that addon with a script update and I'll update it manually. For now, I can put this latest version of your script verbatim into the addon so it'll show up on GitHub if you want to play around with maintaining it there.

Leafkiller wrote:Currently, (as I understand it) for each icon, Ovale will do a complete walkthrough of the script calculating the time when every node will be ready. If any nodes have time zero, then the highest priority node that is earliest in the script is displayed to the user. If no nodes have a zero time, then the one that will be ready the soonest will be shown with a cooldown.

Because it is possible to specify different priorities for spells, even when the script comes across a node that has a time of zero, it needs to continue to evaluate the rest of the nodes in the script.

So - if Ovale knew that there are no nodes later in a script with a higher priority (something that is characteristic of the simc scripts) it could stop building the node list anytime it found a node with a time of zero since no future nodes would ever replace that node as the one to be displayed.

This is basically right. All nodes are represent by time intervals. Think of them as mathematical sets {t: start < t < end}. Every node evaluates to a time interval, and once the entire script is seen, then Ovale picks the highest priority node whose time interval overlaps "now", or else picks the node with the lowest start time. There's some fudge factor there with priorities where if a node is available now, but there's a higher priority node that's available a short time in the future, then Ovale will pick the higher priority node.

Your idea has merit, and it's easy to check programatically -- I could keep track of the maximum priority found in a script when compiling the script and later during the execution while keeping track of the best node found so far, if the priority is the same as the maximum priority, then we don't need to keep looking.

As an aside, I don't think priorities work well for classes using cast-time spells, but it might be something worth looking into classes for instant-cast spells such as for melee classes. The way the engine works, it'll pick a higher priority node if it occurs less than 0.75 of a GCD ahead of a node that's available now. This might be another way to express "use these CPs to refresh Rip", although the way it's currently done meshes better with cross-translation to a SimC action list.

ShmooDude wrote:Also, how would I go about adding it as a separate script to the Nernian's addon?

If you'd like to add it, it's as simple as just letting me know. If you're familiar with using GitHub, that's the simplest way for you to maintain it and letting me easily pull in changes (this is how @aggixx does it). If not, then just submit a ticket for that addon with a script update and I'll update it manually. For now, I can put this latest version of your script verbatim into the addon so it'll show up on GitHub if you want to play around with maintaining it there.

I just went ahead and released a new version of Nerien's Ovale Scripts with your script in it.

Although it seems Rake is being overwritten fairly often. I use WA Bleed Ratios and my ratio will show 103-109 and Rake will be suggested by the 5.3.8.1 script. I was in the understanding that it would not suggest an overwrite unless it's 115+.