diff --git a/scripts/outlaw.lua b/scripts/outlaw.lua index 959ecb5..dd8b41a 100644 --- a/scripts/outlaw.lua +++ b/scripts/outlaw.lua @@ -6,46 +6,64 @@ local Player = Bastion.UnitManager:Get('player') local None = Bastion.UnitManager:Get('none') local Target = Bastion.UnitManager:Get('target') -local RollTheBones = Bastion.SpellBook:GetSpell(315508) -local SliceAndDice = Bastion.SpellBook:GetSpell(315496) -local BetweenTheEyes = Bastion.SpellBook:GetSpell(315341) -local BladeRush = Bastion.SpellBook:GetSpell(271877) -local Vanish = Bastion.SpellBook:GetSpell(1856) -local Dispatch = Bastion.SpellBook:GetSpell(2098) -local Ambush = Bastion.SpellBook:GetSpell(8676) -local Stealth = Bastion.SpellBook:GetSpell(1784) -local PistolShot = Bastion.SpellBook:GetSpell(185763) -local Opportunity = Bastion.SpellBook:GetSpell(195627) -local SinisterStrike = Bastion.SpellBook:GetSpell(193315) -local GrandMelee = Bastion.SpellBook:GetSpell(193358) -local Broadside = Bastion.SpellBook:GetSpell(193356) -local TrueBearing = Bastion.SpellBook:GetSpell(193359) -local RuthlessPrecision = Bastion.SpellBook:GetSpell(193357) +local Stealth = Bastion.SpellBook:GetSpell(115191) +local Kick = Bastion.SpellBook:GetSpell(1766) +local CountTheOdds = Bastion.SpellBook:GetSpell(381982) +local Shadowmeld = Bastion.SpellBook:GetSpell(58984) +local ShadowDance = Bastion.SpellBook:GetSpell(185313) +local ShadowDanceAura = Bastion.SpellBook:GetSpell(185422) +local HiddenOpportunity = Bastion.SpellBook:GetSpell(383281) +local RollTheBones = Bastion.SpellBook:GetSpell(315508) +local FanTheHammer = Bastion.SpellBook:GetSpell(381846) +local ImprovedAmbush = Bastion.SpellBook:GetSpell(381620) +local SummarilyDispatched = Bastion.SpellBook:GetSpell(381990) +local BladeFlurry = Bastion.SpellBook:GetSpell(13877) +local KillingSpree = Bastion.SpellBook:GetSpell(51690) +local ArcaneTorrent = Bastion.SpellBook:GetSpell(25046) +local ArcanePulse = Bastion.SpellBook:GetSpell(260364) +local LightsJudgment = Bastion.SpellBook:GetSpell(255647) +local BagOfTricks = Bastion.SpellBook:GetSpell(312411) +local Sepsis = Bastion.SpellBook:GetSpell(385408) +local BetweenTheEyes = Bastion.SpellBook:GetSpell(315341) +local GhostlyStrike = Bastion.SpellBook:GetSpell(196937) +local Dreadblades = Bastion.SpellBook:GetSpell(343142) +local Subterfuge = Bastion.SpellBook:GetSpell(108208) +local EchoingReprimand = Bastion.SpellBook:GetSpell(385616) +local Ambush = Bastion.SpellBook:GetSpell(8676) +local KeepItRolling = Bastion.SpellBook:GetSpell(381989) +local Audacity = Bastion.SpellBook:GetSpell(381845) +local FindWeakness = Bastion.SpellBook:GetSpell(91023) +local PistolShot = Bastion.SpellBook:GetSpell(185763) +local Opportunity = Bastion.SpellBook:GetSpell(279876) +local OpportunityAura = Bastion.SpellBook:GetSpell(195627) +local GreenskinsWickers = Bastion.SpellBook:GetSpell(386823) +local QuickDraw = Bastion.SpellBook:GetSpell(196938) +local Weaponmaster = Bastion.SpellBook:GetSpell(200733) +local SinisterStrike = Bastion.SpellBook:GetSpell(193315) +local AdrenalineRush = Bastion.SpellBook:GetSpell(13750) +local ImprovedAdrenalineRush = Bastion.SpellBook:GetSpell(395422) +local BladeRush = Bastion.SpellBook:GetSpell(271877) +local MarkedForDeath = Bastion.SpellBook:GetSpell(137619) +local ThistleTea = Bastion.SpellBook:GetSpell(381623) +local PotionOfUnbridledFury = Bastion.SpellBook:GetSpell(169299) +local Bloodlust = Bastion.SpellBook:GetSpell(2825) +local BloodFury = Bastion.SpellBook:GetSpell(20572) +local Berserking = Bastion.SpellBook:GetSpell(26297) +local Fireblood = Bastion.SpellBook:GetSpell(265221) +local AncestralCall = Bastion.SpellBook:GetSpell(274738) +local SliceAndDice = Bastion.SpellBook:GetSpell(315496) +local SwiftSlasher = Bastion.SpellBook:GetSpell(381988) +local ColdBlood = Bastion.SpellBook:GetSpell(382245) +local Dispatch = Bastion.SpellBook:GetSpell(2098) +local Vanish = Bastion.SpellBook:GetSpell(1856) + +local Broadside = Bastion.SpellBook:GetSpell(193356) +local GrandMelee = Bastion.SpellBook:GetSpell(193358) local SkullAndCrossbones = Bastion.SpellBook:GetSpell(199603) -local BuriedTreasure = Bastion.SpellBook:GetSpell(199600) -local AdrenalineRush = Bastion.SpellBook:GetSpell(13750) -local ShadowDance = Bastion.SpellBook:GetSpell(185313) -local Audacity = Bastion.SpellBook:GetSpell(381845) -local Flagellation = Bastion.SpellBook:GetSpell(323654) -local Dreadblades = Bastion.SpellBook:GetSpell(343142) -local JollyRoger = Bastion.SpellBook:GetSpell(199603) -local BladeFlurry = Bastion.SpellBook:GetSpell(13877) -local Kick = Bastion.SpellBook:GetSpell(1766) -local MarkedForDeath = Bastion.SpellBook:GetSpell(137619) -local CrimsonVial = Bastion.SpellBook:GetSpell(185311) -local Shiv = Bastion.SpellBook:GetSpell(5938) -local KidneyShot = Bastion.SpellBook:GetSpell(408) -local InstantPoison = Bastion.SpellBook:GetSpell(315584) -local AtrophicPosion = Bastion.SpellBook:GetSpell(381637) -local Evasion = Bastion.SpellBook:GetSpell(5277) -local TricksOfTheTrade = Bastion.SpellBook:GetSpell(57934) -local CheapShot = Bastion.SpellBook:GetSpell(1833) -local BagOfTricks = Bastion.SpellBook:GetSpell(312411) -local AutoAttack = Bastion.SpellBook:GetSpell(6603) - -local IrideusFragment = Bastion.ItemBook:GetItem(193743) -local Healthstone = Bastion.ItemBook:GetItem(5512) -local WindscarWhetstone = Bastion.ItemBook:GetItem(137486) +local TrueBearing = Bastion.SpellBook:GetSpell(193359) +local LoadedDice = Bastion.SpellBook:GetSpell(256171) +local BuriedTreasure = Bastion.SpellBook:GetSpell(199600) +local RuthlessPrecision = Bastion.SpellBook:GetSpell(193357) local PurgeTarget = Bastion.UnitManager:CreateCustomUnit('purge', function(unit) local purge = nil @@ -167,442 +185,770 @@ local Explosive = Bastion.UnitManager:CreateCustomUnit('explosive', function(uni end) local DefaultAPL = Bastion.APL:New('default') -local AOEAPL = Bastion.APL:New('aoe') -local SpecialAPL = Bastion.APL:New('special') +local StealthAPL = Bastion.APL:New('stealth') +local CDsAPL = Bastion.APL:New('cds') +local FinishAPL = Bastion.APL:New('finish') +local BuildAPL = Bastion.APL:New('build') +local StealthCDsAPL = Bastion.APL:New('stealthcds') -SpecialAPL:AddSpell( +-- # Executed every time the actor is available. +-- # Restealth if possible (no vulnerable enemies in combat) +-- actions=stealth + +DefaultAPL:AddSpell( + Stealth:CastableIf( + function(self) + return self:IsKnownAndUsable() and not Player:GetAuras():FindMy(Stealth):IsUp() and + not Player:IsAffectingCombat() and not IsMounted() + end + ):SetTarget(Player) +) + +-- # Interrupt on cooldown to allow simming interactions with that +-- actions+=/kick +DefaultAPL:AddSpell( Kick:CastableIf(function(self) - return KickTarget:Exists() and Player:InMelee(KickTarget) and + return self:IsKnownAndUsable() and KickTarget:Exists() and self:IsInRange(KickTarget) and self:IsKnownAndUsable() and - not Player:IsCastingOrChanneling() + not Player:IsCastingOrChanneling() and Player:IsFacing(Target) end):SetTarget(KickTarget) ) - -SpecialAPL:AddSpell( - SinisterStrike:CastableIf(function(self) - return Explosive:Exists() and not Player:IsCastingOrChanneling() - end):SetTarget(Explosive) +-- # Checks if we are in an appropriate Stealth state for triggering the Count the Odds bonus +-- actions+=/variable,name=stealthed_cto,value=talent.count_the_odds&(stealthed.basic|buff.shadowmeld.up|buff.shadow_dance.up) +DefaultAPL:AddVariable( + 'stealthed_cto', + function() + return CountTheOdds:IsKnown() and (Player:GetAuras():FindMy(Stealth):IsUp() or + Player:GetAuras():FindMy(Shadowmeld):IsUp() or + Player:GetAuras():FindMy(ShadowDanceAura):IsUp()) + end ) -SpecialAPL:AddSpell( - KidneyShot:CastableIf(function(self) - return KickTarget:Exists() and Player:InMelee(KickTarget) and - self:IsKnownAndUsable() and - not Player:IsCastingOrChanneling() and - (Player:GetComboPoints(Target) >= 5 or - ( - Player:GetComboPoints(Target) >= 4 and - (Player:GetAuras():FindMy(Broadside):IsUp() or Player:GetAuras():FindMy(Opportunity):IsUp()))) +local function GetRTBCount() + local count = 0 - end):SetTarget(KickTarget) + if Player:GetAuras():FindMy(Broadside):IsUp() then + count = count + 1 + end + + if Player:GetAuras():FindMy(GrandMelee):IsUp() then + count = count + 1 + end + + if Player:GetAuras():FindMy(SkullAndCrossbones):IsUp() then + count = count + 1 + end + + if Player:GetAuras():FindMy(TrueBearing):IsUp() then + count = count + 1 + end + + if Player:GetAuras():FindMy(LoadedDice):IsUp() then + count = count + 1 + end + + if Player:GetAuras():FindMy(BuriedTreasure):IsUp() then + count = count + 1 + end + + if Player:GetAuras():FindMy(RuthlessPrecision):IsUp() then + count = count + 1 + end + + return count +end + +-- # Roll the Bones Reroll Conditions +-- actions+=/variable,name=rtb_reroll,if=!talent.hidden_opportunity,value=rtb_buffs<2&(!buff.broadside.up&(!talent.fan_the_hammer|!buff.skull_and_crossbones.up)&!buff.true_bearing.up|buff.loaded_dice.up)|rtb_buffs=2&(buff.buried_treasure.up&buff.grand_melee.up|!buff.broadside.up&!buff.true_bearing.up&buff.loaded_dice.up) +DefaultAPL:AddVariable( + 'rtb_reroll', + function() + if not HiddenOpportunity:IsKnown() then + return GetRTBCount() < 2 and + (not Player:GetAuras():FindMy(Broadside):IsUp() and + (not FanTheHammer:IsKnown() or + not Player:GetAuras():FindMy(SkullAndCrossbones):IsUp()) and + not Player:GetAuras():FindMy(TrueBearing):IsUp() or + Player:GetAuras():FindMy(LoadedDice):IsUp()) or + GetRTBCount() == 2 and + (Player:GetAuras():FindMy(BuriedTreasure):IsUp() and + Player:GetAuras():FindMy(GrandMelee):IsUp() or + not Player:GetAuras():FindMy(Broadside):IsUp() and + not Player:GetAuras():FindMy(TrueBearing):IsUp() and + Player:GetAuras():FindMy(LoadedDice):IsUp()) + end + end ) -SpecialAPL:AddSpell( - CheapShot:CastableIf(function(self) - return KickTarget:Exists() and Player:InMelee(KickTarget) and - self:IsKnownAndUsable() and - not Player:IsCastingOrChanneling() and Player:GetAuras():FindMy(Stealth):IsUp() - end):SetTarget(KickTarget) +-- # Additional Reroll Conditions for Keep it Rolling or Count the Odds +-- actions+=/variable,name=rtb_reroll,if=!talent.hidden_opportunity&(talent.keep_it_rolling|talent.count_the_odds),value=variable.rtb_reroll|((rtb_buffs.normal=0&rtb_buffs.longer>=1)&!(buff.broadside.up&buff.true_bearing.up&buff.skull_and_crossbones.up)&!(buff.broadside.remains>39|buff.true_bearing.remains>39|buff.ruthless_precision.remains>39|buff.skull_and_crossbones.remains>39)) +DefaultAPL:AddVariable( + 'rtb_reroll', + function() + if not HiddenOpportunity:IsKnown() then + return GetRTBCount() < 2 and + (not Player:GetAuras():FindMy(Broadside):IsUp() and + (not FanTheHammer:IsKnown() or + not Player:GetAuras():FindMy(SkullAndCrossbones):IsUp()) and + not Player:GetAuras():FindMy(TrueBearing):IsUp() or + Player:GetAuras():FindMy(LoadedDice):IsUp()) or + GetRTBCount() == 2 and + (Player:GetAuras():FindMy(BuriedTreasure):IsUp() and + Player:GetAuras():FindMy(GrandMelee):IsUp() or + not Player:GetAuras():FindMy(Broadside):IsUp() and + not Player:GetAuras():FindMy(TrueBearing):IsUp() and + Player:GetAuras():FindMy(LoadedDice):IsUp()) + end + end ) -SpecialAPL:AddSpell( - Stealth:CastableIf(function(self) - return self:IsKnownAndUsable() and - not Player:IsCastingOrChanneling() and not Player:IsAffectingCombat() and - not Player:GetAuras():FindMy(Stealth):IsUp() and not IsMounted() - end):SetTarget(Player) +-- # With Hidden Opportunity, prioritize rerolling for Skull and Crossbones over everything else +-- actions+=/variable,name=rtb_reroll,if=talent.hidden_opportunity,value=!rtb_buffs.will_lose.skull_and_crossbones&(rtb_buffs.will_lose-rtb_buffs.will_lose.grand_melee)<2+buff.loaded_dice.up +DefaultAPL:AddVariable( + 'rtb_reroll', + function() + if HiddenOpportunity:IsKnown() then + return not Player:GetAuras():FindMy(SkullAndCrossbones):IsUp() and + ((Player:GetAuras():FindMy(SkullAndCrossbones):IsUp() and 1 or 0) - + (Player:GetAuras():FindMy(GrandMelee):IsUp() and 1 or 0)) < + 2 + (Player:GetAuras():FindMy(LoadedDice):IsUp() and 1 or 0) + end + end ) -SpecialAPL:AddSpell( - CrimsonVial:CastableIf(function(self) - return self:IsKnownAndUsable() and - not Player:IsCastingOrChanneling() and - Player:GetHealthPercent() < 70 - end):SetTarget(Player) +-- # Avoid rerolls when we will not have time remaining on the fight or add wave to recoup the opportunity cost of the global +-- actions+=/variable,name=rtb_reroll,op=reset,if=!(raid_event.adds.remains>12|raid_event.adds.up&(raid_event.adds.in-raid_event.adds.remains)<6|target.time_to_die>12)|fight_remains<12 +DefaultAPL:AddVariable( + 'rtb_reroll', + function() + if not HiddenOpportunity:IsKnown() then + return GetRTBCount() < 2 and + (not Player:GetAuras():FindMy(Broadside):IsUp() and + (not FanTheHammer:IsKnown() or + not Player:GetAuras():FindMy(SkullAndCrossbones):IsUp()) and + not Player:GetAuras():FindMy(TrueBearing):IsUp() or + Player:GetAuras():FindMy(LoadedDice):IsUp()) or + GetRTBCount() == 2 and + (Player:GetAuras():FindMy(BuriedTreasure):IsUp() and + Player:GetAuras():FindMy(GrandMelee):IsUp() or + not Player:GetAuras():FindMy(Broadside):IsUp() and + not Player:GetAuras():FindMy(TrueBearing):IsUp() and + Player:GetAuras():FindMy(LoadedDice):IsUp()) + end + end ) -SpecialAPL:AddSpell( - Shiv:CastableIf(function(self) - return PurgeTarget:Exists() and Player:InMelee(PurgeTarget) and - self:IsKnownAndUsable() and - not Player:IsCastingOrChanneling() and PurgeTarget:GetAuras():HasAnyStealableAura() - end):SetTarget(PurgeTarget) +-- # Ensure we get full Ambush CP gains and aren't rerolling Count the Odds buffs away +-- actions+=/variable,name=ambush_condition,value=combo_points.deficit>=2+talent.improved_ambush+buff.broadside.up&energy>=50&(!talent.count_the_odds|buff.roll_the_bones.remains>=10) +DefaultAPL:AddVariable( + 'ambush_condition', + function() + return Player:GetComboPointsDeficit() >= 2 + (ImprovedAmbush:IsKnown() and 1 or 0) + + (Player:GetAuras():FindMy(Broadside):IsUp() and 1 or 0) and + Player:GetPower() >= 50 and + (not CountTheOdds:IsKnown() or + Player:GetAuras():FindMy(RollTheBones):GetRemainingTime() >= 10) + end ) -SpecialAPL:AddSpell( - InstantPoison:CastableIf(function(self) - return self:IsKnownAndUsable() and - not Player:IsCastingOrChanneling() and - not Player:GetAuras():FindMy(InstantPoison):IsUp() and not Player:IsMoving() - end):SetTarget(Player) +-- # Finish at 6 (5 with Summarily Dispatched talented) CP or CP Max-1, whichever is greater of the two +-- actions+=/variable,name=finish_condition,value=combo_points>=((cp_max_spend-1)=cp_max_spend +DefaultAPL:AddVariable( + 'finish_condition', + function() + return Player:GetComboPoints() >= + math.min(Player:GetComboPointsMax() - 1, 6 - (SummarilyDispatched:IsKnown() and 1 or 0)) or + Player:GetComboPoints() >= Player:GetComboPointsMax() + end ) -SpecialAPL:AddSpell( - AtrophicPosion:CastableIf(function(self) - return self:IsKnownAndUsable() and - not Player:IsCastingOrChanneling() and - not Player:GetAuras():FindMy(AtrophicPosion):IsUp() and not Player:IsMoving() - end):SetTarget(Player) +-- # With multiple targets, this variable is checked to decide whether some CDs should be synced with Blade Flurry +-- actions+=/variable,name=blade_flurry_sync,value=spell_targets.blade_flurry<2&raid_event.adds.in>20|buff.blade_flurry.remains>1+talent.killing_spree.enabled +DefaultAPL:AddVariable( + 'blade_flurry_sync', + function() + return Player:GetMeleeAttackers() < 2 and + (not Player:GetAuras():FindMy(BladeFlurry):IsUp() or + Player:GetAuras():FindMy(BladeFlurry):GetRemainingTime() > 1 + + (KillingSpree:IsKnown() and 1 or 0)) + end ) -SpecialAPL:AddItem( - Healthstone:UsableIf(function(self) - return self:IsEquippedAndUsable() and - not Player:IsCastingOrChanneling() and - Player:GetHealthPercent() < 40 - end):SetTarget(Player) +-- # Higher priority Stealth list for Count the Odds or true Stealth/Vanish that will break in a single global +-- actions+=/call_action_list,name=stealth,if=stealthed.basic|buff.shadowmeld.up +DefaultAPL:AddAPL( + StealthAPL, + function() + return Player:IsStealthed() or Player:GetAuras():FindMy(Shadowmeld):IsUp() + end ) -SpecialAPL:AddSpell( - TricksOfTheTrade:CastableIf(function(self) - return Tank:Exists() and self:IsKnownAndUsable() and - not Player:IsCastingOrChanneling() and - Player:IsTanking(Target) - end):SetTarget(Tank) +-- actions+=/call_action_list,name=cds +DefaultAPL:AddAPL( + CDsAPL, + function() + return true + end ) -SpecialAPL:AddSpell( - Evasion:CastableIf(function(self) - return self:IsKnownAndUsable() and - not Player:IsCastingOrChanneling() and - Player:GetHealthPercent() < 40 - end):SetTarget(Player) +-- # Lower priority Stealth list for Shadow Dance +-- actions+=/call_action_list,name=stealth,if=variable.stealthed_cto +DefaultAPL:AddAPL( + StealthAPL, + function() + return DefaultAPL:GetVariable('stealthed_cto') + end ) -SpecialAPL:AddItem( - IrideusFragment:UsableIf(function(self) - return self:IsEquippedAndUsable() and - not Player:IsCastingOrChanneling() and (Player:GetMeleeAttackers() > 2 or Target:IsBoss()) - end):SetTarget(Player) +-- actions+=/run_action_list,name=finish,if=variable.finish_condition +DefaultAPL:AddAPL( + FinishAPL, + function() + return DefaultAPL:GetVariable('finish_condition') + end ) -SpecialAPL:AddItem( - WindscarWhetstone:UsableIf(function(self) - return self:IsEquippedAndUsable() and - not Player:IsCastingOrChanneling() and (Player:GetMeleeAttackers() > 2 or Target:IsBoss()) - end):SetTarget(Player) +-- actions+=/call_action_list,name=build +DefaultAPL:AddAPL( + BuildAPL, + function() + return true + end ) -SpecialAPL:AddSpell( - BagOfTricks:CastableIf(function(self) - return Target:Exists() and Player:InMelee(Target) and - self:IsKnownAndUsable() and - not Player:IsCastingOrChanneling() - end):SetTarget(Target) +-- actions+=/arcane_torrent,if=energy.base_deficit>=15+energy.regen +DefaultAPL:AddSpell( + ArcaneTorrent:CastableIf( + function(self) + return self:IsKnownAndUsable() and Player:GetPowerDeficit() >= 15 + Player:GetPowerRegen() + end + ):SetTarget(Target) + ) --- Adrenaline Rush on cooldown. +-- actions+=/arcane_pulse DefaultAPL:AddSpell( - AdrenalineRush:CastableIf(function(self) - return Target:Exists() and Player:InMelee(Target) and - self:IsKnownAndUsable() and - not Player:IsCastingOrChanneling() - end):SetTarget(Player) + ArcanePulse:CastableIf( + function(self) + return self:IsKnownAndUsable() and true + end + ):SetTarget(Target) ) --- Roll the Bones if you have no combat enhancements active. +-- actions+=/lights_judgment DefaultAPL:AddSpell( - RollTheBones:CastableIf(function(self) - local numBuffs = 0 - if Player:GetAuras():FindMy(Broadside):IsUp() then - numBuffs = numBuffs + 1 + LightsJudgment:CastableIf( + function(self) + return self:IsKnownAndUsable() and true end - if Player:GetAuras():FindMy(BuriedTreasure):IsUp() then - numBuffs = numBuffs + 1 + ):SetTarget(Target) +) + +-- actions+=/bag_of_tricks +DefaultAPL:AddSpell( + BagOfTricks:CastableIf( + function(self) + return self:IsKnownAndUsable() and true end - if Player:GetAuras():FindMy(GrandMelee):IsUp() then - numBuffs = numBuffs + 1 + ):SetTarget(Target) +) + +-- # Builders +-- actions.build=sepsis,target_if=max:target.time_to_die*debuff.between_the_eyes.up,if=target.time_to_die>11&debuff.between_the_eyes.up|fight_remains<11 +BuildAPL:AddSpell( + Sepsis:CastableIf( + function(self) + return self:IsKnownAndUsable() and ((Target:TimeToDie() > 11 and + Target:GetAuras():FindMy(BetweenTheEyes):IsUp()) or + Player:TimeToDie() < 11) end - if Player:GetAuras():FindMy(RuthlessPrecision):IsUp() then - numBuffs = numBuffs + 1 + ):SetTarget(Target) +) + +-- actions.build+=/ghostly_strike,if=debuff.ghostly_strike.remains<=3&(spell_targets.blade_flurry<=2|buff.dreadblades.up)&!buff.subterfuge.up&target.time_to_die>=5 +BuildAPL:AddSpell( + GhostlyStrike:CastableIf( + function(self) + return self:IsKnownAndUsable() and Target:GetAuras():FindMy(GhostlyStrike):GetRemainingTime() <= 3 and + (Player:GetMeleeAttackers() <= 2 or Player:GetAuras():FindMy(Dreadblades):IsUp()) and + not Player:GetAuras():FindMy(Subterfuge):IsUp() and Target:TimeToDie() >= 5 + end + ):SetTarget(Target) +) + +-- actions.build+=/echoing_reprimand,if=!buff.dreadblades.up +BuildAPL:AddSpell( + EchoingReprimand:CastableIf( + function(self) + return self:IsKnownAndUsable() and not Player:GetAuras():FindMy(Dreadblades):IsUp() end - if Player:GetAuras():FindMy(SkullAndCrossbones):IsUp() then - numBuffs = numBuffs + 1 + ):SetTarget(Target) +) + +-- # High priority Ambush line to apply Find Weakness or consume Audacity/Sepsis buff before Pistol Shot +-- actions.build+=/ambush,if=(talent.hidden_opportunity|talent.keep_it_rolling)&(buff.audacity.up|buff.sepsis_buff.up|buff.subterfuge.up&cooldown.keep_it_rolling.ready)|talent.find_weakness&debuff.find_weakness.down +BuildAPL:AddSpell( + Ambush:CastableIf( + function(self) + return self:IsKnownAndUsable() and ((HiddenOpportunity:IsKnown() or KeepItRolling:IsKnown()) and + (Player:GetAuras():FindMy(Audacity):IsUp() or Player:GetAuras():FindMy(Sepsis):IsUp() or + (Player:GetAuras():FindMy(Subterfuge):IsUp() and KeepItRolling:OnCooldown())) or + (FindWeakness:IsKnown() and Target:GetAuras():FindMy(FindWeakness):IsDown())) end - if Player:GetAuras():FindMy(TrueBearing):IsUp() then - numBuffs = numBuffs + 1 + ):SetTarget(Target) +) + +-- # With Audacity + Hidden Opportunity + Fan the Hammer, use Pistol Shot to proc Audacity any time Ambush is not available +-- actions.build+=/pistol_shot,if=talent.fan_the_hammer&talent.audacity&talent.hidden_opportunity&buff.opportunity.up&!buff.audacity.up&!buff.subterfuge.up&!buff.shadow_dance.up +BuildAPL:AddSpell( + PistolShot:CastableIf( + function(self) + return self:IsKnownAndUsable() and FanTheHammer:IsKnown() and Audacity:IsKnown() and + HiddenOpportunity:IsKnown() and + Player:GetAuras():FindMy(OpportunityAura):IsUp() and not Player:GetAuras():FindMy(Audacity):IsUp() and + not Player:GetAuras():FindMy(Subterfuge):IsUp() and not Player:GetAuras():FindMy(ShadowDance):IsUp() end - return self:IsKnownAndUsable() and - not Player:IsCastingOrChanneling() and - ((not Player:GetAuras():FindMy(Broadside):IsUp() and - not Player:GetAuras():FindMy(TrueBearing):IsUp()) or numBuffs < 2) - end):SetTarget(Player) + ):SetTarget(Target) ) --- Slice and Dice if at max, or -1 from maximum combo points with Broadside or Opportunity active, if missing or has has 12 or less seconds remaining. -DefaultAPL:AddSpell( - SliceAndDice:CastableIf(function(self) - return Target:Exists() and Player:InMelee(Target) and - self:IsKnownAndUsable() and - not Player:IsCastingOrChanneling() and - (Player:GetComboPoints(Target) >= 5 or - ( - Player:GetComboPoints(Target) >= 4 and - (Player:GetAuras():FindMy(Broadside):IsUp() or Player:GetAuras():FindMy(Opportunity):IsUp()))) and - ( - not Player:GetAuras():FindMy(SliceAndDice):IsUp() or - Player:GetAuras():FindMy(SliceAndDice):GetRemainingTime() <= 12 - ) - end):SetTarget(Target) + +-- # Use Greenskins Wickers buff immediately with Opportunity unless running Fan the Hammer +-- actions.build+=/pistol_shot,if=buff.greenskins_wickers.up&(!talent.fan_the_hammer&buff.opportunity.up|buff.greenskins_wickers.remains<1.5) +BuildAPL:AddSpell( + PistolShot:CastableIf( + function(self) + return self:IsKnownAndUsable() and Player:GetAuras():FindMy(GreenskinsWickers):IsUp() and + (not FanTheHammer:IsKnown() and Player:GetAuras():FindMy(OpportunityAura):IsUp() or + Player:GetAuras():FindMy(GreenskinsWickers):GetRemainingTime() < 1.5) + end + ):SetTarget(Target) ) --- Between the Eyes on cooldown if at max, or -1 from maximum combo points with Broadside or Opportunity active. -DefaultAPL:AddSpell( - BetweenTheEyes:CastableIf(function(self) - return Target:Exists() and Player:InMelee(Target) and - self:IsKnownAndUsable() and - not Player:IsCastingOrChanneling() and - (Player:GetComboPoints(Target) >= 5 or +-- const int stacks = 1 + as( p()->talent.outlaw.fan_the_hammer->effectN( 1 ).base_value() ); +local function MaxOpportunity() + return 1 + (FanTheHammer:IsKnown() and 1 or 0) +end + +-- # With Fan the Hammer, consume Opportunity at max stacks or if we will get max 4+ CP and Dreadblades is not up +-- actions.build+=/pistol_shot,if=talent.fan_the_hammer&buff.opportunity.up&(buff.opportunity.stack>=buff.opportunity.max_stack|buff.opportunity.remains<2) +BuildAPL:AddSpell( + PistolShot:CastableIf( + function(self) + return self:IsKnownAndUsable() and FanTheHammer:IsKnown() and + Player:GetAuras():FindMy(OpportunityAura):IsUp() and ( - Player:GetComboPoints(Target) >= 4 and - (Player:GetAuras():FindMy(Broadside):IsUp() or Player:GetAuras():FindMy(Opportunity):IsUp()))) - end):SetTarget(Target) + Player:GetAuras():FindMy(OpportunityAura):GetCount() >= + MaxOpportunity() + or + Player:GetAuras():FindMy(OpportunityAura):GetRemainingTime() < 2) + end + ):SetTarget(Target) +) + +-- actions.build+=/pistol_shot,if=talent.fan_the_hammer&buff.opportunity.up&combo_points.deficit>((1+talent.quick_draw)*talent.fan_the_hammer.rank)&!buff.dreadblades.up&(!talent.hidden_opportunity|!buff.subterfuge.up&!buff.shadow_dance.up) +BuildAPL:AddSpell( + PistolShot:CastableIf( + function(self) + return self:IsKnownAndUsable() and FanTheHammer:IsKnown() and + Player:GetAuras():FindMy(OpportunityAura):IsUp() and + Player:GetComboPointsDeficit() > ((1 + (QuickDraw:IsKnown() and 1 or 0)) * 1) and + not Player:GetAuras():FindMy(Dreadblades):IsUp() and + (not HiddenOpportunity:IsKnown() or not Player:GetAuras():FindMy(Subterfuge):IsUp() and + not Player:GetAuras():FindMy(ShadowDance):IsUp()) + end + ):SetTarget(Target) ) --- Dispatch if at max, or -1 from maximum combo points with Broadside or Opportunity active. -DefaultAPL:AddSpell( - Dispatch:CastableIf(function(self) - return Target:Exists() and Player:InMelee(Target) and - self:IsKnownAndUsable() and - not Player:IsCastingOrChanneling() and - (Player:GetComboPoints(Target) >= 5 or - ( - Player:GetComboPoints(Target) >= 4 and - (Player:GetAuras():FindMy(Broadside):IsUp() or Player:GetAuras():FindMy(Opportunity):IsUp()))) - end):SetTarget(Target) +-- actions.build+=/pool_resource,for_next=1 +-- actions.build+=/ambush,if=talent.hidden_opportunity|talent.find_weakness&debuff.find_weakness.down +BuildAPL:AddSpell( + Ambush:CastableIf( + function(self) + return self:IsKnownAndUsable() and (HiddenOpportunity:IsKnown() or + (FindWeakness:IsKnown() and Target:GetAuras():FindMy(FindWeakness):IsDown())) + end + ):SetTarget(Target) +) + +-- # Use Pistol Shot with Opportunity if Combat Potency won't overcap energy, when it will exactly cap CP, or when using Quick Draw +-- actions.build+=/pistol_shot,if=!talent.fan_the_hammer&buff.opportunity.up&(energy.base_deficit>energy.regen*1.5|!talent.weaponmaster&combo_points.deficit<=1+buff.broadside.up|talent.quick_draw.enabled|talent.audacity.enabled&!buff.audacity.up) +BuildAPL:AddSpell( + PistolShot:CastableIf( + function(self) + return self:IsKnownAndUsable() and not FanTheHammer:IsKnown() and + Player:GetAuras():FindMy(OpportunityAura):IsUp() and + (Player:GetPowerDeficit() > Player:GetPowerRegen() * 1.5 or + (not Weaponmaster:IsKnown() and + Player:GetComboPointsDeficit() <= 1 + (Player:GetAuras():FindMy(Broadside):IsUp() and 1 or 0)) or + QuickDraw:IsKnown() or + (Audacity:IsKnown() and not Player:GetAuras():FindMy(Audacity):IsUp())) + end + ):SetTarget(Target) ) --- Shadow Dance at or below 3 combo points, and do not have Audacity or Opportunity active and wait until you have at least 80 energy. While active Ambush becomes your highest priority builder. -DefaultAPL:AddSpell( - ShadowDance:CastableIf(function(self) - return Target:Exists() and Player:InMelee(Target) and - self:IsKnownAndUsable() and - not Player:IsCastingOrChanneling() and - Player:GetComboPoints(Target) <= 3 and - not Player:GetAuras():FindMy(Audacity):IsUp() and - not Player:GetAuras():FindMy(Opportunity):IsUp() and - Player:GetPower() >= 80 - end):SetTarget(Player) + +-- actions.build+=/sinister_strike +BuildAPL:AddSpell( + SinisterStrike:CastableIf( + function(self) + return self:IsKnownAndUsable() and true + end + ):SetTarget(Target) ) --- Blade Rush if missing 50 or more energy and do not have Flagellation, Dreadblades or Shadow Dance active. -DefaultAPL:AddSpell( - BladeRush:CastableIf(function(self) - return Target:Exists() and Player:InMelee(Target) and - self:IsKnownAndUsable() and - not Player:IsCastingOrChanneling() and - Player:GetPower() <= 50 and - not Player:GetAuras():FindMy(Flagellation):IsUp() and - not Player:GetAuras():FindMy(Dreadblades):IsUp() and - not Player:GetAuras():FindMy(ShadowDance):IsUp() - end):SetTarget(Player) +-- # Cooldowns +-- actions.cds=adrenaline_rush,if=!buff.adrenaline_rush.up&(!talent.improved_adrenaline_rush|combo_points<=2) +CDsAPL:AddSpell( + AdrenalineRush:CastableIf( + function(self) + return self:IsKnownAndUsable() and not Player:GetAuras():FindMy(AdrenalineRush):IsUp() and + (not ImprovedAdrenalineRush:IsKnown() or Player:GetComboPoints() <= 2) + end + ):SetTarget(Target) ) --- Vanish followed by Ambush if you won't overcap combo points and wait until you have at least 50 energy. -DefaultAPL:AddSpell( - Vanish:CastableIf(function(self) - return Tank:Exists() and Target:Exists() and Player:InMelee(Target) and - self:IsKnownAndUsable() and - not Player:IsCastingOrChanneling() and - Player:GetComboPoints(Target) <= 4 and - Player:GetPower() >= 50 and not Player:GetAuras():FindMy(Stealth):IsUp() - end):SetTarget(Player) +-- actions.cds+=/blade_flurry,if=spell_targets>=2&buff.blade_flurry.remains= 2 and + Player:GetAuras():FindMy(BladeFlurry):GetRemainingTime() < Player:GetGCD() + end + ):SetTarget(Target) ) --- Pistol Shot if you have an Opportunity proc and won't overcap combo points. -DefaultAPL:AddSpell( - PistolShot:CastableIf(function(self) - return Target:Exists() and Player:InMelee(Target) and - self:IsKnownAndUsable() and - not Player:IsCastingOrChanneling() and - Player:GetAuras():FindMy(Opportunity):IsUp() and - Player:GetComboPoints(Target) <= 4 - end):SetTarget(Target) +-- actions.cds+=/roll_the_bones,if=buff.dreadblades.down&(rtb_buffs.total=0|variable.rtb_reroll) +CDsAPL:AddSpell( + RollTheBones:CastableIf( + function(self) + return self:IsKnownAndUsable() and Player:GetAuras():FindMy(Dreadblades):IsDown() and + (GetRTBCount() == 0 or + DefaultAPL:GetVariable("rtb_reroll")) + end + ):SetTarget(Target) +) + +-- actions.cds+=/keep_it_rolling,if=!variable.rtb_reroll&(buff.broadside.up+buff.true_bearing.up+buff.skull_and_crossbones.up+buff.ruthless_precision.up)>2&(buff.shadow_dance.down|rtb_buffs>=6) +CDsAPL:AddSpell( + RollTheBones:CastableIf( + function(self) + return self:IsKnownAndUsable() and not DefaultAPL:GetVariable("rtb_reroll") and + ((Player:GetAuras():FindMy(Broadside):IsUp() and 1 or 0) + + (Player:GetAuras():FindMy(TrueBearing):IsUp() and 1 or 0) + + (Player:GetAuras():FindMy(SkullAndCrossbones):IsUp() and 1 or 0) + + (Player:GetAuras():FindMy(RuthlessPrecision):IsUp() and 1 or 0)) > 2 and + (Player:GetAuras():FindMy(ShadowDance):IsDown() or + GetRTBCount() >= 6) + end + ):SetTarget(Target) ) --- Use Ambush Icon Ambush instead of Sinister Strike Icon Sinister Strike whenever it is available to cast from any of the procs or cooldowns. -DefaultAPL:AddSpell( - Ambush:CastableIf(function(self) - return Target:Exists() and Player:InMelee(Target) and - self:IsKnownAndUsable() and - not Player:IsCastingOrChanneling() - end):SetTarget(Target) +-- actions.cds+=/blade_rush,if=variable.blade_flurry_sync&!buff.dreadblades.up&(energy.base_time_to_max>4+stealthed.rogue-spell_targets%3) +CDsAPL:AddSpell( + BladeRush:CastableIf( + function(self) + return self:IsKnownAndUsable() and DefaultAPL:GetVariable("blade_flurry_sync") and + not Player:GetAuras():FindMy(Dreadblades):IsUp() and + (Player:GetTimeToPowerPercent() > 4 + (Player:GetAuras():FindMy(Subterfuge):IsUp() and 1 or 0) + + (Player:GetAuras():FindMy(ShadowDance):IsUp() and 1 or 0) - Target:GetMeleeAttackers() % 3) + end + ):SetTarget(Target) ) --- Sinister Strike if you won't overcap combo points. -DefaultAPL:AddSpell( - SinisterStrike:CastableIf(function(self) - return Target:Exists() and Player:InMelee(Target) and - self:IsKnownAndUsable() and - not Player:IsCastingOrChanneling() and - Player:GetComboPoints(Target) < 5 - end):SetTarget(Target) +-- actions.cds+=/call_action_list,name=stealth_cds,if=!stealthed.all|talent.count_the_odds&!variable.stealthed_cto +CDsAPL:AddAPL( + StealthCDsAPL, + function() + return not Player:GetAuras():FindMy(Stealth):IsUp() or + (CountTheOdds:IsKnown() and not DefaultAPL:GetVariable("stealthed_cto")) + end ) --- AOE APL +-- actions.cds+=/dreadblades,if=!(variable.stealthed_cto|stealthed.basic|talent.hidden_opportunity&stealthed.rogue)&combo_points<=2&(!talent.marked_for_death|!cooldown.marked_for_death.ready)&target.time_to_die>=10 +CDsAPL:AddSpell( + Dreadblades:CastableIf( + function(self) + return self:IsKnownAndUsable() and + not (DefaultAPL:GetVariable("stealthed_cto") or Player:GetAuras():FindMy(Stealth):IsUp() or + (HiddenOpportunity:IsKnown() and Player:GetAuras():FindMy(Subterfuge):IsUp())) and + Player:GetComboPoints() <= 2 and + (not MarkedForDeath:IsKnown() or not MarkedForDeath:CooldownUp()) and + Target:TimeToDie() >= 10 + end + ):SetTarget(Target) +) --- Adrenaline Rush on cooldown. -AOEAPL:AddSpell( - AdrenalineRush:CastableIf(function(self) - return Target:Exists() and Player:InMelee(Target) and - self:IsKnownAndUsable() and - not Player:IsCastingOrChanneling() - end):SetTarget(Player) +-- # If adds are up, snipe the one with lowest TTD. Use when dying faster than CP deficit or without any CP. +-- actions.cds+=/marked_for_death,line_cd=1.5,target_if=min:target.time_to_die,if=raid_event.adds.up&(target.time_to_die=cp_max_spend-1)&!buff.dreadblades.up + +-- # If no adds will die within the next 30s, use MfD on boss without any CP. +-- actions.cds+=/marked_for_death,if=raid_event.adds.in>30-raid_event.adds.duration&combo_points.deficit>=cp_max_spend-1&!buff.dreadblades.up + +-- actions.cds+=/thistle_tea,if=!buff.thistle_tea.up&(energy.base_deficit>=100|fight_remains= 100 or Target:TimeToDie() < ThistleTea:Charges() * 6) + end + ):SetTarget(Target) +) + +-- actions.cds+=/killing_spree,if=variable.blade_flurry_sync&!stealthed.rogue&debuff.between_the_eyes.up&energy.base_time_to_max>4 +CDsAPL:AddSpell( + KillingSpree:CastableIf( + function(self) + return self:IsKnownAndUsable() and DefaultAPL:GetVariable("blade_flurry_sync") and + not Player:GetAuras():FindMy(Subterfuge):IsUp() and + Target:GetAuras():FindMy(BetweenTheEyes):IsUp() and + Player:GetTimeToPowerPercent() > 4 + end + ):SetTarget(Target) +) + +-- actions.cds+=/shadowmeld,if=!stealthed.all&(talent.count_the_odds&variable.finish_condition|!talent.weaponmaster.enabled&variable.ambush_condition) +CDsAPL:AddSpell( + Shadowmeld:CastableIf( + function(self) + return self:IsKnownAndUsable() and not Player:GetAuras():FindMy(Stealth):IsUp() and + (CountTheOdds:IsKnown() and DefaultAPL:GetVariable("finish_condition") or + not Weaponmaster:IsKnown() and DefaultAPL:GetVariable("ambush_condition")) + end + ):SetTarget(Target) +) + +-- actions.cds+=/potion,if=buff.bloodlust.react|fight_remains<30|buff.adrenaline_rush.up +-- CDsAPL:AddItem( +-- PotionOfUnbridledFury:CastableIf( +-- function(self) +-- return self:IsKnownAndUsable() and Player:GetAuras():FindMy(Bloodlust):IsUp() or Target:TimeToDie() < 30 or +-- Player:GetAuras():FindMy(AdrenalineRush):IsUp() +-- end +-- ):SetTarget(Target) +-- ) + +-- actions.cds+=/blood_fury +CDsAPL:AddSpell( + BloodFury:CastableIf( + function(self) + return self:IsKnownAndUsable() and true + end + ):SetTarget(Target) +) + +-- actions.cds+=/berserking +CDsAPL:AddSpell( + Berserking:CastableIf( + function(self) + return self:IsKnownAndUsable() and true + end + ):SetTarget(Target) ) --- Roll the Bones if you have no combat enhancements active. --- Roll the Bones has a large outcome of buffs which include; Broadside, Buried Treasure, Grand Melee, Ruthless Precision, Skull and Crossbones, and True Bearing. The buffs you want to keep this tier are going to be Broadside and True Bearing as single buffs or any combination of 2 or more buffs. Any of the other 4 buffs as a single means it's worth recasting Roll the Bones as soon as you are able to. +-- actions.cds+=/fireblood +CDsAPL:AddSpell( + Fireblood:CastableIf( + function(self) + return self:IsKnownAndUsable() and true + end + ):SetTarget(Target) +) -AOEAPL:AddSpell( - RollTheBones:CastableIf(function(self) - local numBuffs = 0 - if Player:GetAuras():FindMy(Broadside):IsUp() then - numBuffs = numBuffs + 1 +-- actions.cds+=/ancestral_call +CDsAPL:AddSpell( + AncestralCall:CastableIf( + function(self) + return self:IsKnownAndUsable() and true end - if Player:GetAuras():FindMy(BuriedTreasure):IsUp() then - numBuffs = numBuffs + 1 + ):SetTarget(Target) +) + +-- # Default conditions for usable items. +-- actions.cds+=/use_item,name=manic_grieftorch,if=!stealthed.all&!buff.adrenaline_rush.up|fight_remains<5 +-- actions.cds+=/use_item,name=stormeaters_boon,if=spell_targets.blade_flurry>desired_targets|raid_event.adds.in>60|fight_remains<10 +-- actions.cds+=/use_item,name=windscar_whetstone,if=spell_targets.blade_flurry>desired_targets|raid_event.adds.in>60|fight_remains<7 +-- actions.cds+=/use_items,slots=trinket1,if=debuff.between_the_eyes.up|trinket.1.has_stat.any_dps|fight_remains<=20 +-- actions.cds+=/use_items,slots=trinket2,if=debuff.between_the_eyes.up|trinket.2.has_stat.any_dps|fight_remains<=20 + +-- # Finishers BtE to keep the Crit debuff up, if RP is up, or for Greenskins, unless the target is about to die. +-- actions.finish=between_the_eyes,if=target.time_to_die>3&(debuff.between_the_eyes.remains<4|talent.greenskins_wickers&!buff.greenskins_wickers.up|!talent.greenskins_wickers&buff.ruthless_precision.up) +FinishAPL:AddSpell( + BetweenTheEyes:CastableIf( + function(self) + return self:IsKnownAndUsable() and Target:TimeToDie() > 3 and + (Target:GetAuras():FindMy(BetweenTheEyes):GetRemainingTime() < 4 or + GreenskinsWickers:IsKnown() and Player:GetAuras():FindMy(GreenskinsWickers):IsDown() or + not GreenskinsWickers:IsKnown() and Player:GetAuras():FindMy(RuthlessPrecision):IsUp()) end - if Player:GetAuras():FindMy(GrandMelee):IsUp() then - numBuffs = numBuffs + 1 + ):SetTarget(Target) +) + +-- actions.finish+=/slice_and_dice,if=buff.slice_and_dice.remains=cp_max_spend) +FinishAPL:AddSpell( + SliceAndDice:CastableIf( + function(self) + return self:IsKnownAndUsable() and + Player:GetAuras():FindMy(SliceAndDice):GetRemainingTime() < Target:TimeToDie() and + Player:GetAuras():FindMy(SliceAndDice):GetRemainingTime() < 6 and + (not SwiftSlasher:IsKnown() or Player:GetComboPoints() >= Player:GetComboPointsMax()) end - if Player:GetAuras():FindMy(RuthlessPrecision):IsUp() then - numBuffs = numBuffs + 1 + ):SetTarget(Target) +) + +-- actions.finish+=/cold_blood +FinishAPL:AddSpell( + ColdBlood:CastableIf( + function(self) + return self:IsKnownAndUsable() and true end - if Player:GetAuras():FindMy(SkullAndCrossbones):IsUp() then - numBuffs = numBuffs + 1 + ):SetTarget(Target) +) + +-- actions.finish+=/dispatch +FinishAPL:AddSpell( + Dispatch:CastableIf( + function(self) + return self:IsKnownAndUsable() and true end - if Player:GetAuras():FindMy(TrueBearing):IsUp() then - numBuffs = numBuffs + 1 + ):SetTarget(Target) +) + +-- # Stealth +-- actions.stealth=blade_flurry,if=talent.subterfuge&talent.hidden_opportunity&spell_targets>=2&!buff.blade_flurry.up +StealthAPL:AddSpell( + BladeFlurry:CastableIf( + function(self) + return self:IsKnownAndUsable() and Subterfuge:IsKnown() and HiddenOpportunity:IsKnown() and + Target:GetMeleeAttackers() >= 2 and + not Player:GetAuras():FindMy(BladeFlurry):IsUp() end - return self:IsKnownAndUsable() and - not Player:IsCastingOrChanneling() and - ((not Player:GetAuras():FindMy(Broadside):IsUp() and - not Player:GetAuras():FindMy(TrueBearing):IsUp()) or numBuffs < 2) - end):SetTarget(Player) + ):SetTarget(Target) ) --- Blade Flurry when missing. -AOEAPL:AddSpell( - BladeFlurry:CastableIf(function(self) - return self:IsKnownAndUsable() and - not Player:IsCastingOrChanneling() and - (not Player:GetAuras():FindMy(self):IsUp() or Player:GetAuras():FindMy(self):GetRemainingTime() <= 2) - end):SetTarget(Player) +-- actions.stealth+=/cold_blood,if=variable.finish_condition +StealthAPL:AddSpell( + ColdBlood:CastableIf( + function(self) + return self:IsKnownAndUsable() and DefaultAPL:GetVariable('finish_condition') + end + ):SetTarget(Target) ) --- Slice and Dice if at max, or -1 from maximum combo points with Broadside or Opportunity active, if missing or has has 12 or less seconds remaining. -AOEAPL:AddSpell( - SliceAndDice:CastableIf(function(self) - return Target:Exists() and Player:InMelee(Target) and - self:IsKnownAndUsable() and - not Player:IsCastingOrChanneling() and - (Player:GetComboPoints(Target) >= 5 or - (Player:GetComboPoints(Target) >= 4 and - (Player:GetAuras():FindMy(Broadside):IsUp() or - Player:GetAuras():FindMy(Opportunity):IsUp()))) and - (not Player:GetAuras():FindMy(self):IsUp() or - Player:GetAuras():FindMy(self):GetRemainingTime() <= 12) - end):SetTarget(Player) -) - --- Between the Eyes on cooldown if at max, or -1 from maximum combo points with Broadside or Opportunity active. -AOEAPL:AddSpell( - BetweenTheEyes:CastableIf(function(self) - return Target:Exists() and Player:InMelee(Target) and - self:IsKnownAndUsable() and - not Player:IsCastingOrChanneling() and - (Player:GetComboPoints(Target) >= 5 or - (Player:GetComboPoints(Target) >= 4 and - (Player:GetAuras():FindMy(Broadside):IsUp() or - Player:GetAuras():FindMy(Opportunity):IsUp()))) - end):SetTarget(Target) -) - --- Dispatch if at max, or -1 from maximum combo points with Broadside or Opportunity active. -AOEAPL:AddSpell( - Dispatch:CastableIf(function(self) - return Target:Exists() and Player:InMelee(Target) and - self:IsKnownAndUsable() and - not Player:IsCastingOrChanneling() and - (Player:GetComboPoints(Target) >= 5 or - (Player:GetComboPoints(Target) >= 4 and - (Player:GetAuras():FindMy(Broadside):IsUp() or - Player:GetAuras():FindMy(Opportunity):IsUp()))) - end):SetTarget(Target) -) - --- Shadow Dance at or below 3 combo points, and do not have Audacity or Opportunity active and wait until you have at least 80 energy. While active Ambush becomes your highest priority builder. -AOEAPL:AddSpell( - ShadowDance:CastableIf(function(self) - return Target:Exists() and Player:InMelee(Target) and - self:IsKnownAndUsable() and - not Player:IsCastingOrChanneling() and - Player:GetComboPoints(Target) <= 3 and - not Player:GetAuras():FindMy(Audacity):IsUp() and - not Player:GetAuras():FindMy(Opportunity):IsUp() and - Player:GetPower() >= 80 - end):SetTarget(Player) -) - --- Blade Rush if missing 50 or more energy and do not have Flagellation, Dreadblades or Shadow Dance active. -AOEAPL:AddSpell( - BladeRush:CastableIf(function(self) - return Target:Exists() and Player:InMelee(Target) and - self:IsKnownAndUsable() and - not Player:IsCastingOrChanneling() and - Player:GetPower() >= 50 and - not Player:GetAuras():FindMy(Flagellation):IsUp() and - not Player:GetAuras():FindMy(Dreadblades):IsUp() and - not Player:GetAuras():FindMy(ShadowDance):IsUp() - end):SetTarget(Player) +-- actions.stealth+=/dispatch,if=variable.finish_condition +StealthAPL:AddSpell( + Dispatch:CastableIf( + function(self) + return self:IsKnownAndUsable() and DefaultAPL:GetVariable('finish_condition') + end + ):SetTarget(Target) ) --- Vanish followed by Ambush if you won't overcap combo points and wait until you have at least 50 energy. -AOEAPL:AddSpell( - Vanish:CastableIf(function(self) - return Tank:Exists() and Target:Exists() and Player:InMelee(Target) and - self:IsKnownAndUsable() and - not Player:IsCastingOrChanneling() and - Player:GetComboPoints(Target) < 5 and - Player:GetPower() >= 50 and not Player:GetAuras():FindMy(Stealth):IsUp() - end):SetTarget(Player) +-- actions.stealth+=/ambush,if=variable.stealthed_cto|stealthed.basic&talent.find_weakness&!debuff.find_weakness.up|talent.hidden_opportunity +StealthAPL:AddSpell( + Ambush:CastableIf( + function(self) + return self:IsKnownAndUsable() and (DefaultAPL:GetVariable('stealthed_cto') or + Player:IsStealthed() and FindWeakness:IsKnown() and not Target:GetAuras():FindMy(FindWeakness):IsUp() or + HiddenOpportunity:IsKnown()) + end + ):SetTarget(Target) ) --- Pistol Shot if you have an Opportunity proc and won't overcap combo points. -AOEAPL:AddSpell( - PistolShot:CastableIf(function(self) - return Target:Exists() and Player:InMelee(Target) and - self:IsKnownAndUsable() and - not Player:IsCastingOrChanneling() and - Player:GetAuras():FindMy(Opportunity):IsUp() and - Player:GetComboPoints(Target) < 5 - end):SetTarget(Target) +-- # Stealth Cooldowns +-- actions.stealth_cds=variable,name=vanish_condition,value=talent.hidden_opportunity|!talent.shadow_dance|!cooldown.shadow_dance.ready +StealthAPL:AddVariable( + 'vanish_condition', + function() + return HiddenOpportunity:IsKnown() or not ShadowDance:IsKnown() or not ShadowDance:CooldownUp() + end ) -AOEAPL:AddSpell( - Ambush:CastableIf(function(self) - return Target:Exists() and Player:InMelee(Target) and - self:IsKnownAndUsable() and - not Player:IsCastingOrChanneling() - end):SetTarget(Target) +-- actions.stealth_cds+=/variable,name=vanish_opportunity_condition,value=!talent.shadow_dance&talent.fan_the_hammer.rank+talent.quick_draw+talent.audacity 1 then - AOEAPL:Execute() - else - DefaultAPL:Execute() +-- actions.stealth_cds+=/vanish,if=(!talent.find_weakness|talent.audacity)&!talent.hidden_opportunity&variable.finish_condition&variable.vanish_condition +StealthAPL:AddSpell( + Vanish:CastableIf( + function(self) + return self:IsKnownAndUsable() and (not FindWeakness:IsKnown() or Audacity:IsKnown()) and + not HiddenOpportunity:IsKnown() and + DefaultAPL:GetVariable('finish_condition') and StealthAPL:GetVariable('vanish_condition') + end + ):SetTarget(Target) +) + +-- actions.stealth_cds+=/variable,name=shadow_dance_condition,value=talent.shadow_dance&debuff.between_the_eyes.up&(!talent.ghostly_strike|debuff.ghostly_strike.up)&(!talent.dreadblades|!cooldown.dreadblades.ready)&(!talent.hidden_opportunity|!buff.audacity.up&(talent.fan_the_hammer.rank<2|!buff.opportunity.up)) +StealthAPL:AddVariable( + 'shadow_dance_condition', + function() + return ShadowDance:IsKnown() and Target:GetAuras():FindMy(BetweenTheEyes):IsUp() and + (not GhostlyStrike:IsKnown() or Target:GetAuras():FindMy(GhostlyStrike):IsUp()) and + (not Dreadblades:IsKnown() or not Dreadblades:CooldownUp()) and + (not HiddenOpportunity:IsKnown() or not Player:GetAuras():FindMy(Audacity):IsUp() and + (1 < 2 or not Player:GetAuras():FindMy(OpportunityAura):IsUp())) end +) + +-- actions.stealth_cds+=/shadow_dance,if=!talent.keep_it_rolling&variable.shadow_dance_condition&buff.slice_and_dice.up&(variable.finish_condition|talent.hidden_opportunity)&(!talent.hidden_opportunity|!cooldown.vanish.ready) +StealthAPL:AddSpell( + ShadowDance:CastableIf( + function(self) + return self:IsKnownAndUsable() and not KeepItRolling:IsKnown() and + StealthAPL:GetVariable('shadow_dance_condition') and + Player:GetAuras():FindMy(SliceAndDice):IsUp() and + (DefaultAPL:GetVariable('finish_condition') or HiddenOpportunity:IsKnown()) and + (not HiddenOpportunity:IsKnown() or not Vanish:CooldownUp()) + end + ):SetTarget(Target) +) + +-- actions.stealth_cds+=/shadow_dance,if=talent.keep_it_rolling&variable.shadow_dance_condition&(cooldown.keep_it_rolling.remains<=30|cooldown.keep_it_rolling.remains>120&(variable.finish_condition|talent.hidden_opportunity)) +StealthAPL:AddSpell( + ShadowDance:CastableIf( + function(self) + return self:IsKnownAndUsable() and KeepItRolling:IsKnown() and + StealthAPL:GetVariable('shadow_dance_condition') and + (KeepItRolling:GetCooldownRemaining() <= 30 or + KeepItRolling:GetCooldownRemaining() > 120 and + (DefaultAPL:GetVariable('finish_condition') or HiddenOpportunity:IsKnown())) + end + ):SetTarget(Target) +) + +OutlawModule:Sync(function() + print(BetweenTheEyes:IsKnownAndUsable()) + DefaultAPL:Execute() end) Bastion:Register(OutlawModule) diff --git a/scripts/restodruid.lua b/scripts/restodruid.lua index 1b6ebb6..58fcc15 100644 --- a/scripts/restodruid.lua +++ b/scripts/restodruid.lua @@ -441,24 +441,23 @@ DefaultAPL:AddSpell( DefaultAPL:AddSpell( NaturesSwiftness:CastableIf(function(self) return Lowest:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() - and Player:CanSee(Lowest) and - (Lowest:GetHP() < 70 or (Player:GetPartyHPAround(40, 65) >= 2 or Player:GetPartyHPAround(40, 70)) - ) + and Player:CanSee(Lowest) and Lowest:GetHP() < 70 end):SetTarget(Lowest) ) DefaultAPL:AddSpell( ConvokeTheSpirits:CastableIf(function(self) return Player:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() and - self:IsInRange(Player) and (Player:GetPartyHPAround(40, 65) >= 2 or Player:GetPartyHPAround(40, 70) >= 3) + self:IsInRange(Player) and (Player:GetPartyHPAround(40, 70) >= 2 or Player:GetPartyHPAround(40, 75) >= 3) + and (Flourish:IsKnownAndUsable() or Flourish:GetTimeSinceLastCast() > 10) end):SetTarget(Player) ) DefaultAPL:AddSpell( Flourish:CastableIf(function(self) return Player:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() and - self:IsInRange(Player) and (Player:GetPartyHPAround(40, 65) >= 2 or Player:GetPartyHPAround(40, 70) >= 3) and - (not ConvokeTheSpirits:IsKnownAndUsable() and ConvokeTheSpirits:GetTimeSinceLastCast() > 7) and + self:IsInRange(Player) and (Player:GetPartyHPAround(40, 70) >= 2 or Player:GetPartyHPAround(40, 75) >= 3) and + (not ConvokeTheSpirits:IsKnownAndUsable() and ConvokeTheSpirits:GetTimeSinceLastCast() > 10) and WildGrowth:GetTimeSinceLastCast() <= 6 end):SetTarget(Player) ) @@ -482,7 +481,7 @@ DefaultAPL:AddSpell( return SwiftmendUnit:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() and Player:CanSee(SwiftmendUnit) and ( - SwiftmendUnit:GetHP() <= 80 or + SwiftmendUnit:GetHP() <= 60 or ( Lowest:GetPartyHPAround(30, 90) >= 3 or Lowest:GetPartyHPAround(30, 85) >= 2 ) @@ -495,12 +494,10 @@ DefaultAPL:AddSpell( return WildGrowthUnit:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() and Player:CanSee(WildGrowthUnit) and ( - ( - Player:GetAuras():FindMy(SoulOfTheForest):IsUp() and - ( - Player:GetAuras():FindMy(SoulOfTheForest):GetRemainingTime() <= 5 or - WildGrowthUnit:GetPartyHPAround(30, 90) >= 2)) or - (WildGrowthUnit:GetPartyHPAround(30, 90) >= 3 or WildGrowthUnit:GetPartyHPAround(30, 85) >= 2)) and + Player:GetAuras():FindMy(SoulOfTheForest):IsUp() + or + (WildGrowthUnit:GetPartyHPAround(30, 90) >= 3 or WildGrowthUnit:GetPartyHPAround(30, 85) >= 2) + ) and not Player:IsMoving() end):SetTarget(WildGrowthUnit) ) @@ -541,7 +538,7 @@ DefaultAPL:AddSpell( DefaultAPL:AddSpell( Rejuvenation:CastableIf(function(self) return RejuvUnit:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() - and Player:CanSee(RejuvUnit) and RejuvUnit:GetHP() <= 94 and + and Player:CanSee(RejuvUnit) and (RejuvUnit:GetHP() <= 94) and not Player:GetAuras():FindMy(SoulOfTheForest):IsUp() end):SetTarget(RejuvUnit) ) @@ -578,45 +575,53 @@ DefaultAPL:AddSpell( end):SetTarget(Lowest) ) +DefaultAPL:AddSpell( + Rejuvenation:CastableIf(function(self) + return RejuvUnit:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() + and Player:CanSee(RejuvUnit) and (RejuvUnit:GetHP() <= 94 or Player:GetPartyHPAround(40, 90) >= 2) and + not Player:GetAuras():FindMy(SoulOfTheForest):IsUp() + end):SetTarget(RejuvUnit) +) + DefaultAPL:AddSpell( Sunfire:CastableIf(function(self) - return Bastion.UnitManager['target']:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() - and Player:CanSee(Bastion.UnitManager['target']) and + return Target:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() + and Player:CanSee(Target) and ( - not Bastion.UnitManager['target']:GetAuras():FindMy(SunfireAura):IsUp() or - Bastion.UnitManager['target']:GetAuras():FindMy(SunfireAura):GetRemainingTime() <= 5.4) and - Bastion.UnitManager['target']:IsHostile() and - Bastion.UnitManager['target']:IsAffectingCombat() and Player:GetPP() >= 25 - end):SetTarget(Bastion.UnitManager['target']) + not Target:GetAuras():FindMy(SunfireAura):IsUp() or + Target:GetAuras():FindMy(SunfireAura):GetRemainingTime() <= 5.4) and + Target:IsHostile() and + Target:IsAffectingCombat() and Player:GetPP() >= 25 + end):SetTarget(Target) ) DefaultAPL:AddSpell( Moonfire:CastableIf(function(self) - return Bastion.UnitManager['target']:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() - and Player:CanSee(Bastion.UnitManager['target']) and + return Target:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() + and Player:CanSee(Target) and ( - not Bastion.UnitManager['target']:GetAuras():FindMy(MoonfireAura):IsUp() or - Bastion.UnitManager['target']:GetAuras():FindMy(MoonfireAura):GetRemainingTime() <= 5.4) and - Bastion.UnitManager['target']:IsHostile() and - Bastion.UnitManager['target']:IsAffectingCombat() and Player:GetPP() >= 25 - end):SetTarget(Bastion.UnitManager['target']) + not Target:GetAuras():FindMy(MoonfireAura):IsUp() or + Target:GetAuras():FindMy(MoonfireAura):GetRemainingTime() <= 5.4) and + Target:IsHostile() and + Target:IsAffectingCombat() and Player:GetPP() >= 25 + end):SetTarget(Target) ) DefaultAPL:AddSpell( Starsurge:CastableIf(function(self) - return Bastion.UnitManager['target']:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() - and Player:CanSee(Bastion.UnitManager['target']) and Bastion.UnitManager['target']:IsHostile() and - Bastion.UnitManager['target']:IsAffectingCombat() and Player:GetPP() >= 25 - end):SetTarget(Bastion.UnitManager['target']) + return Target:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() + and Player:CanSee(Target) and Target:IsHostile() and + Target:IsAffectingCombat() and Player:GetPP() >= 25 + end):SetTarget(Target) ) DefaultAPL:AddSpell( Wrath:CastableIf(function(self) - return Bastion.UnitManager['target']:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() - and Player:CanSee(Bastion.UnitManager['target']) and not Player:IsMoving() and - Bastion.UnitManager['target']:IsHostile() and - Bastion.UnitManager['target']:IsAffectingCombat() and Player:GetPP() >= 25 - end):SetTarget(Bastion.UnitManager['target']) + return Target:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() + and Player:CanSee(Target) and not Player:IsMoving() and + Target:IsHostile() and + Target:IsAffectingCombat() and Player:GetPP() >= 25 + end):SetTarget(Target) ) RestoModule:Sync(function() diff --git a/scripts/subtlety.lua b/scripts/subtlety.lua index 55c0350..211aa04 100644 --- a/scripts/subtlety.lua +++ b/scripts/subtlety.lua @@ -843,7 +843,8 @@ local FindWeakness = Bastion.SpellBook:GetSpell(91023) local ImprovedShurikenStorm = Bastion.SpellBook:GetSpell(319951) - +local RefreshingHealingPotion = Bastion.ItemBook:GetItem(191380) +local ElementalPotionOfPower = Bastion.ItemBook:GetItem(191389) local IrideusFragment = Bastion.ItemBook:GetItem(193743) local Healthstone = Bastion.ItemBook:GetItem(5512) local WindscarWhetstone = Bastion.ItemBook:GetItem(137486) @@ -997,6 +998,38 @@ local FinishAPL = Bastion.APL:New('finish') local BuildAPL = Bastion.APL:New('build') local ItemsAPL = Bastion.APL:New('items') +ItemsAPL:AddItem( + Healthstone:UsableIf(function(self) + return self:IsEquippedAndUsable() and + not Player:IsCastingOrChanneling() and + Player:GetHealthPercent() < 40 + end):SetTarget(Player) +) + +ItemsAPL:AddItem( + RefreshingHealingPotion:UsableIf(function(self) + return self:IsEquippedAndUsable() and + not Player:IsCastingOrChanneling() and + Player:GetHealthPercent() < 40 + end):SetTarget(Player) +) + +ItemsAPL:AddSpell( + TricksOfTheTrade:CastableIf(function(self) + return Tank:Exists() and self:IsKnownAndUsable() and + not Player:IsCastingOrChanneling() and + Player:IsTanking(Target) + end):SetTarget(Tank) +) + +ItemsAPL:AddSpell( + Evasion:CastableIf(function(self) + return self:IsKnownAndUsable() and + not Player:IsCastingOrChanneling() and + Player:GetHealthPercent() < 40 + end):SetTarget(Player) +) + ItemsAPL:AddItem( IrideusFragment:UsableIf(function(self) return self:IsEquippedAndUsable() and @@ -1004,6 +1037,13 @@ ItemsAPL:AddItem( end):SetTarget(Player) ) +ItemsAPL:AddItem( + ElementalPotionOfPower:UsableIf(function(self) + return self:IsEquippedAndUsable() and + not Player:IsCastingOrChanneling() and (Player:GetMeleeAttackers() > 2 or Target:IsBoss()) + end):SetTarget(Player) +) + ItemsAPL:AddItem( WindscarWhetstone:UsableIf(function(self) return Target:Exists() and Player:InMelee(Target) and self:IsEquippedAndUsable() and