diff --git a/scripts/outlaw.lua b/scripts/outlaw.lua deleted file mode 100644 index 73d2829..0000000 --- a/scripts/outlaw.lua +++ /dev/null @@ -1,954 +0,0 @@ --- local Tinkr, Bastion = ... - --- local OutlawModule = Bastion.Module:New('outlaw') --- local Evaluator = Tinkr.Util.Evaluator --- local Player = Bastion.UnitManager:Get('player') --- local None = Bastion.UnitManager:Get('none') --- local Target = Bastion.UnitManager:Get('target') - --- 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 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 - --- Bastion.UnitManager:EnumEnemies(function(unit) --- if unit:IsDead() then --- return false --- end - --- if not Player:CanSee(unit) then --- return false --- end - --- if Player:GetDistance(unit) > 40 then --- return false --- end - --- if unit:GetAuras():HasAnyStealableAura() then --- purge = unit --- return true --- end --- end) - --- if purge == nil then --- purge = None --- end - --- return purge --- end) - --- local KickTarget = Bastion.UnitManager:CreateCustomUnit('kick', function(unit) --- local purge = nil - --- Bastion.UnitManager:EnumEnemies(function(unit) --- if unit:IsDead() then --- return false --- end - --- if not Player:CanSee(unit) then --- return false --- end - --- if Player:GetDistance(unit) > 40 then --- return false --- end - --- if Player:InMelee(unit) and unit:IsInterruptible(5) and Player:IsFacing(unit) then --- purge = unit --- return true --- end --- end) - --- if purge == nil then --- purge = None --- end - --- return purge --- end) - --- local Tank = Bastion.UnitManager:CreateCustomUnit('tank', function(unit) --- local tank = nil - --- Bastion.UnitManager:EnumFriends(function(unit) --- if Player:GetDistance(unit) > 40 then --- return false --- end - --- if not Player:CanSee(unit) then --- return false --- end - --- if unit:IsDead() then --- return false --- end - --- if unit:IsTank() then --- tank = unit --- return true --- end - --- return false --- end) - --- if tank == nil then --- tank = None --- end - --- return tank --- end) - --- local Explosive = Bastion.UnitManager:CreateCustomUnit('explosive', function(unit) --- local explosive = nil - --- Bastion.UnitManager:EnumEnemies(function(unit) --- if unit:IsDead() then --- return false --- end - --- if not Player:CanSee(unit) then --- return false --- end - --- if Player:GetDistance(unit) > 40 then --- return false --- end - --- if Player:InMelee(unit) and unit:GetID() == 120651 and Player:IsFacing(unit) then - --- explosive = unit --- return true --- end --- end) - --- if explosive == nil then --- explosive = None --- end - --- return explosive --- end) - --- local DefaultAPL = Bastion.APL:New('default') --- 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') - --- -- # 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 self:IsKnownAndUsable() and KickTarget:Exists() and self:IsInRange(KickTarget) and --- self:IsKnownAndUsable() and --- not Player:IsCastingOrChanneling() and Player:IsFacing(Target) --- end):SetTarget(KickTarget) --- ) --- -- # 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 --- ) - --- local function GetRTBCount() --- local count = 0 - --- 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 --- ) - --- -- # 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 --- ) - --- -- # 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 --- ) - --- -- # 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 --- ) - --- -- # 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 --- ) - --- -- # 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 --- ) - --- -- # 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 --- ) - --- -- # 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 --- ) - --- -- actions+=/call_action_list,name=cds --- DefaultAPL:AddAPL( --- CDsAPL, --- function() --- return true --- end --- ) - --- -- # 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 --- ) - --- -- actions+=/run_action_list,name=finish,if=variable.finish_condition --- DefaultAPL:AddAPL( --- FinishAPL, --- function() --- return DefaultAPL:GetVariable('finish_condition') --- end --- ) - --- -- actions+=/call_action_list,name=build --- DefaultAPL:AddAPL( --- BuildAPL, --- function() --- return true --- end --- ) - --- -- 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) - --- ) - --- -- actions+=/arcane_pulse --- DefaultAPL:AddSpell( --- ArcanePulse:CastableIf( --- function(self) --- return self:IsKnownAndUsable() and true --- end --- ):SetTarget(Target) --- ) - --- -- actions+=/lights_judgment --- DefaultAPL:AddSpell( --- LightsJudgment:CastableIf( --- function(self) --- return self:IsKnownAndUsable() and true --- end --- ):SetTarget(Target) --- ) - --- -- actions+=/bag_of_tricks --- DefaultAPL:AddSpell( --- BagOfTricks:CastableIf( --- function(self) --- return self:IsKnownAndUsable() and true --- end --- ):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 --- ):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 --- ):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 --- ):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 --- ):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) --- ) - --- -- 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: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) --- ) - --- -- 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) --- ) - - --- -- actions.build+=/sinister_strike --- BuildAPL:AddSpell( --- SinisterStrike:CastableIf( --- function(self) --- return self:IsKnownAndUsable() and true --- end --- ):SetTarget(Target) --- ) - --- -- # 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) --- ) - --- -- actions.cds+=/blade_flurry,if=spell_targets>=2&buff.blade_flurry.remains= 2 and --- Player:GetAuras():FindMy(BladeFlurry):GetRemainingTime() < Player:GetGCD() --- 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) --- ) - --- -- 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) --- ) - --- -- 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 --- ) - --- -- 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) --- ) - --- -- # 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) --- ) - --- -- actions.cds+=/fireblood --- CDsAPL:AddSpell( --- Fireblood:CastableIf( --- function(self) --- return self:IsKnownAndUsable() and true --- end --- ):SetTarget(Target) --- ) - --- -- actions.cds+=/ancestral_call --- CDsAPL:AddSpell( --- AncestralCall:CastableIf( --- function(self) --- return self:IsKnownAndUsable() and true --- end --- ):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 --- ):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 --- ):SetTarget(Target) --- ) - --- -- actions.finish+=/cold_blood --- FinishAPL:AddSpell( --- ColdBlood:CastableIf( --- function(self) --- return self:IsKnownAndUsable() and true --- end --- ):SetTarget(Target) --- ) - --- -- actions.finish+=/dispatch --- FinishAPL:AddSpell( --- Dispatch:CastableIf( --- function(self) --- return self:IsKnownAndUsable() and true --- end --- ):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 --- ):SetTarget(Target) --- ) - --- -- 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) --- ) - --- -- actions.stealth+=/dispatch,if=variable.finish_condition --- StealthAPL:AddSpell( --- Dispatch:CastableIf( --- function(self) --- return self:IsKnownAndUsable() and DefaultAPL:GetVariable('finish_condition') --- end --- ):SetTarget(Target) --- ) - --- -- 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) --- ) - --- -- # 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 --- ) - --- -- actions.stealth_cds+=/variable,name=vanish_opportunity_condition,value=!talent.shadow_dance&talent.fan_the_hammer.rank+talent.quick_draw+talent.audacity120&(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 deleted file mode 100644 index 272b585..0000000 --- a/scripts/restodruid.lua +++ /dev/null @@ -1,758 +0,0 @@ -local Tinkr, Bastion = ... - -local RestoModule = Bastion.Module:New('resto_druid') -local Evaluator = Tinkr.Util.Evaluator -local Player = Bastion.UnitManager:Get('player') -local None = Bastion.UnitManager:Get('none') -local Target = Bastion.UnitManager:Get('target') - -local AnomalyDetectionMarkI = Bastion.SpellBook:GetSpell(382499) -local AutoAttack = Bastion.SpellBook:GetSpell(6603) -local MechanismBypass = Bastion.SpellBook:GetSpell(382501) -local OverloadElementalDeposit = Bastion.SpellBook:GetSpell(388213) -local ReviveBattlePets = Bastion.SpellBook:GetSpell(125439) -local WarStomp = Bastion.SpellBook:GetSpell(20549) -local ArmorSkills = Bastion.SpellBook:GetSpell(76275) -local Brawn = Bastion.SpellBook:GetSpell(154743) -local Cultivation = Bastion.SpellBook:GetSpell(20552) -local Endurance = Bastion.SpellBook:GetSpell(20550) -local Languages = Bastion.SpellBook:GetSpell(79746) -local MasterRiding = Bastion.SpellBook:GetSpell(90265) -local NatureResistance = Bastion.SpellBook:GetSpell(20551) -local WeaponSkills = Bastion.SpellBook:GetSpell(76300) -local ActivateEmpowerment = Bastion.SpellBook:GetSpell(357857) -local BlessingofOhnara = Bastion.SpellBook:GetSpell(384522) -local BronzeTimelock = Bastion.SpellBook:GetSpell(374990) -local ChampionAbility = Bastion.SpellBook:GetSpell(356550) -local CenarionWard = Bastion.SpellBook:GetSpell(102351) -local CombatAlly = Bastion.SpellBook:GetSpell(211390) -local ConstructAbility = Bastion.SpellBook:GetSpell(347013) -local CovenantAbility = Bastion.SpellBook:GetSpell(313347) -local GarrisonAbility = Bastion.SpellBook:GetSpell(161691) -local HeartEssence = Bastion.SpellBook:GetSpell(296208) -local HuntingCompanion = Bastion.SpellBook:GetSpell(376280) -local SanityRestorationOrb = Bastion.SpellBook:GetSpell(314955) -local SignatureAbility = Bastion.SpellBook:GetSpell(326526) -local SkywardAscent = Bastion.SpellBook:GetSpell(372610) -local SummonPocopoc = Bastion.SpellBook:GetSpell(360078) -local SurgeForward = Bastion.SpellBook:GetSpell(372608) -local Throw = Bastion.SpellBook:GetSpell(385265) -local VenthyrAbility = Bastion.SpellBook:GetSpell(315594) -local WartimeAbility = Bastion.SpellBook:GetSpell(264739) -local WhirlingSurge = Bastion.SpellBook:GetSpell(361584) -local PocopocZoneAbilitySkill = Bastion.SpellBook:GetSpell(363942) -local DragonridingBasics = Bastion.SpellBook:GetSpell(376777) -local LiftOff = Bastion.SpellBook:GetSpell(383363) -local ThrilloftheSkies = Bastion.SpellBook:GetSpell(383366) -local Vigor = Bastion.SpellBook:GetSpell(383359) -local WindsoftheIsles = Bastion.SpellBook:GetSpell(373586) -local Barkskin = Bastion.SpellBook:GetSpell(22812) -local BearForm = Bastion.SpellBook:GetSpell(5487) -local CatForm = Bastion.SpellBook:GetSpell(768) -local Cyclone = Bastion.SpellBook:GetSpell(33786) -local EntanglingRoots = Bastion.SpellBook:GetSpell(339) -local FerociousBite = Bastion.SpellBook:GetSpell(22568) -local FrenziedRegeneration = Bastion.SpellBook:GetSpell(22842) -local Growl = Bastion.SpellBook:GetSpell(6795) -local Innervate = Bastion.SpellBook:GetSpell(29166) -local Mangle = Bastion.SpellBook:GetSpell(33917) -local MarkoftheWild = Bastion.SpellBook:GetSpell(1126) -local Moonfire = Bastion.SpellBook:GetSpell(8921) -local MoonfireAura = Bastion.SpellBook:GetSpell(164812) -local Prowl = Bastion.SpellBook:GetSpell(5215) -local Rebirth = Bastion.SpellBook:GetSpell(20484) -local Regrowth = Bastion.SpellBook:GetSpell(8936) -local Rejuvenation = Bastion.SpellBook:GetSpell(774) -local RejuvenationAura = Bastion.SpellBook:GetSpell(25299) -local Revive = Bastion.SpellBook:GetSpell(50769) -local Rip = Bastion.SpellBook:GetSpell(1079) -local Shred = Bastion.SpellBook:GetSpell(5221) -local Soothe = Bastion.SpellBook:GetSpell(2908) -local StampedingRoar = Bastion.SpellBook:GetSpell(106898) -local Sunfire = Bastion.SpellBook:GetSpell(93402) -local SunfireAura = Bastion.SpellBook:GetSpell(164815) -local Swiftmend = Bastion.SpellBook:GetSpell(18562) -local TeleportMoonglade = Bastion.SpellBook:GetSpell(18960) -local Thrash = Bastion.SpellBook:GetSpell(106832) -local TigerDash = Bastion.SpellBook:GetSpell(252216) -local TravelForm = Bastion.SpellBook:GetSpell(783) -local UrsolsVortex = Bastion.SpellBook:GetSpell(102793) -local WildGrowth = Bastion.SpellBook:GetSpell(48438) -local Wrath = Bastion.SpellBook:GetSpell(5176) -local AquaticForm = Bastion.SpellBook:GetSpell(276012) -local FlightForm = Bastion.SpellBook:GetSpell(276029) -local TigerDash = Bastion.SpellBook:GetSpell(252216) -local Efflorescence = Bastion.SpellBook:GetSpell(145205) -local IncarnationTreeofLife = Bastion.SpellBook:GetSpell(33891) -local Ironbark = Bastion.SpellBook:GetSpell(102342) -local Lifebloom = Bastion.SpellBook:GetSpell(33763) -local LifebloomAura = Bastion.SpellBook:GetSpell(188550) -local NaturesCure = Bastion.SpellBook:GetSpell(88423) -local NaturesSwiftness = Bastion.SpellBook:GetSpell(132158) -local Revitalize = Bastion.SpellBook:GetSpell(212040) -local Tranquility = Bastion.SpellBook:GetSpell(740) -local MasteryHarmony = Bastion.SpellBook:GetSpell(77495) -local Moonfire = Bastion.SpellBook:GetSpell(8921) -local Wrath = Bastion.SpellBook:GetSpell(5176) -local BearForm = Bastion.SpellBook:GetSpell(5487) -local AdaptiveSwarm = Bastion.SpellBook:GetSpell(391888) -local AdaptiveSwarmBuff = Bastion.SpellBook:GetSpell(391891) -local ClearCasting = Bastion.SpellBook:GetSpell(16870) -local ConvokeTheSpirits = Bastion.SpellBook:GetSpell(391528) -local Flourish = Bastion.SpellBook:GetSpell(197721) -local SoulOfTheForest = Bastion.SpellBook:GetSpell(114108) -local Bursting = Bastion.SpellBook:GetSpell(240443) -local Rake = Bastion.SpellBook:GetSpell(1822) -local RakeAura = Bastion.SpellBook:GetSpell(155722) -local Starsurge = Bastion.SpellBook:GetSpell(197626) -local NaturesVigil = Bastion.SpellBook:GetSpell(124974) -local SpringBlossoms = Bastion.SpellBook:GetSpell(207386) -local RakeDebuff = Bastion.SpellBook:GetSpell(155722) - - -local Lowest = Bastion.UnitManager:CreateCustomUnit('lowest', function(unit) - local lowest = nil - local lowestHP = math.huge - - Bastion.UnitManager:EnumFriends(function(unit) - if unit:IsDead() then - return false - end - - if Player:GetDistance(unit) > 40 then - return false - end - - if not Player:CanSee(unit) then - return false - end - - local hp = unit:GetHP() - if hp < lowestHP then - lowest = unit - lowestHP = hp - end - end) - - if not lowest then - lowest = Player - end - - return lowest - end) - -local DispelTarget = Bastion.UnitManager:CreateCustomUnit('dispel', function(unit) - local lowest = nil - local lowestHP = math.huge - - Bastion.UnitManager:EnumFriends(function(unit) - if unit:IsDead() then - return false - end - - if not Player:CanSee(unit) then - return false - end - - if Player:GetDistance(unit) > 40 then - return false - end - - if not unit:IsDead() and Player:CanSee(unit) and - unit:GetAuras():HasAnyDispelableAura(NaturesCure) then - local hp = unit:GetHP() - if hp < lowestHP then - lowest = unit - lowestHP = hp - end - end - end) - - if lowest == nil then - lowest = None - end - - return lowest - end) - -local PurgeTarget = Bastion.UnitManager:CreateCustomUnit('purge', function(unit) - local purge = nil - - Bastion.UnitManager:EnumEnemies(function(unit) - if unit:IsDead() then - return false - end - - if not Player:CanSee(unit) then - return false - end - - if Player:GetDistance(unit) > 40 then - return false - end - - if not unit:IsDead() and Player:CanSee(unit) and - unit:GetAuras():HasAnyStealableAura() then - purge = unit - return true - end - end) - - if purge == nil then - purge = None - end - - return purge - end) - -local Tank = Bastion.UnitManager:CreateCustomUnit('tank', function(unit) - local tank = nil - - Bastion.UnitManager:EnumFriends(function(unit) - if Player:GetDistance(unit) > 40 then - return false - end - - if not Player:CanSee(unit) then - return false - end - - if unit:IsDead() then - return false - end - - if unit:IsTank() then - tank = unit - return true - end - - return false - end) - - if tank == nil then - tank = Player - end - - return tank - end) - -local RejuvUnit = Bastion.UnitManager:CreateCustomUnit('rejuv', function(unit) - local lowest = nil - local lowestHP = math.huge - - Bastion.UnitManager:EnumFriends(function(unit) - if unit:IsDead() then - return false - end - - if not Player:CanSee(unit) then - return false - end - - if Player:GetDistance(unit) > 40 then - return false - end - - if not unit:IsDead() and Player:CanSee(unit) and - ( - not unit:GetAuras():FindMy(Rejuvenation):IsUp() or - unit:GetAuras():FindMy(Rejuvenation):GetRemainingTime() <= 3.6) then - local hp = unit:GetHP() - if hp < lowestHP then - lowest = unit - lowestHP = hp - end - end - end) - - - if lowest == nil then - lowest = Player - end - - return lowest - end) - -local SwiftmendUnit = Bastion.UnitManager:CreateCustomUnit('swiftmend', function(unit) - local lowest = nil - local lowestHP = math.huge - - Bastion.UnitManager:EnumFriends(function(unit) - if unit:IsDead() then - return false - end - - if not Player:CanSee(unit) then - return false - end - - if Player:GetDistance(unit) > 40 then - return false - end - - if ( - Player:CanSee(unit) and ( - (unit:GetAuras():FindMy(Regrowth):IsUp()) - or - ( - unit:GetAuras():FindMy(Rejuvenation):IsUp() and - not unit:GetAuras():FindMy(WildGrowth):IsUp()) - ) - ) then - local hp = unit:GetHP() - if hp < lowestHP then - lowest = unit - lowestHP = hp - end - end - end) - - - if lowest == nil then - lowest = None - end - - return lowest - end) - -local WildGrowthUnit = Bastion.UnitManager:CreateCustomUnit('wildgrowth', function(unit) - local lowest = nil - local lowestHP = math.huge - - Bastion.UnitManager:EnumFriends(function(unit) - if unit:IsDead() then - return false - end - - if not Player:CanSee(unit) then - return false - end - - if Player:GetDistance(unit) > 40 then - return false - end - - if Player:CanSee(unit) and ( - ( - Player:GetAuras():FindMy(SoulOfTheForest):IsUp() and - ( - Player:GetAuras():FindMy(SoulOfTheForest):GetRemainingTime() <= 5 or - unit:GetPartyHPAround(30, 90) >= 2)) or - (unit:GetPartyHPAround(30, 90) >= 3 or unit:GetPartyHPAround(30, 85) >= 2)) - then - local hp = unit:GetHP() - if hp < lowestHP then - lowest = unit - lowestHP = hp - end - end - end) - - - if lowest == nil then - lowest = None - end - - return lowest - end) - -local Explosive = Bastion.UnitManager:CreateCustomUnit('explosive', function(unit) - local explosive = nil - - Bastion.ObjectManager.explosives:each(function(unit) - if unit:IsDead() then - return false - end - - if not Player:CanSee(unit) then - return false - end - - if Player:GetDistance(unit) <= 40 then - explosive = unit - return true - end - end) - - if explosive == nil then - explosive = None - end - - return explosive - end) - -local RakeTarget = Bastion.UnitManager:CreateCustomUnit('rake', function(unit) - local rakeTarget = nil - - Bastion.UnitManager:EnumEnemies(function(unit) - if unit:IsDead() then - return false - end - - if not Player:CanSee(unit) then - return false - end - - if Player:GetDistance(unit) > 40 then - return false - end - - if not unit:IsDead() and Player:CanSee(unit) and unit:InCombatOdds() > 80 and unit:InMelee(Player) and - Player:IsFacing(unit) and - ( - not unit:GetAuras():FindMy(RakeDebuff):IsUp() or - unit:GetAuras():FindMy(RakeDebuff):GetRemainingTime() <= 3.6) then - rakeTarget = unit - end - end) - - - if rakeTarget == nil then - rakeTarget = None - end - - return rakeTarget - end) - -local MoonfireTarget = Bastion.UnitManager:CreateCustomUnit('moonfire', function(unit) - local moonfireTarget = nil - - Bastion.UnitManager:EnumEnemies(function(unit) - if unit:IsDead() then - return false - end - - if not Player:CanSee(unit) then - return false - end - - if Player:GetDistance(unit) > 40 then - return false - end - - if not unit:IsDead() and Player:CanSee(unit) and unit:InCombatOdds() > 80 and - ( - not unit:GetAuras():FindMy(MoonfireAura):IsUp() or - unit:GetAuras():FindMy(MoonfireAura):GetRemainingTime() <= 3.6) then - moonfireTarget = unit - end - end) - - if moonfireTarget == nil then - moonfireTarget = None - end - - return moonfireTarget - end) - -local SunfireTarget = Bastion.UnitManager:CreateCustomUnit('sunfire', function(unit) - local sunfireTarget = nil - - Bastion.UnitManager:EnumEnemies(function(unit) - if unit:IsDead() then - return false - end - - if not Player:CanSee(unit) then - return false - end - - if Player:GetDistance(unit) > 40 then - return false - end - - if not unit:IsDead() and Player:CanSee(unit) and unit:InCombatOdds() > 80 and - ( - not unit:GetAuras():FindMy(SunfireAura):IsUp() or - unit:GetAuras():FindMy(SunfireAura):GetRemainingTime() <= 3.6) then - sunfireTarget = unit - end - end) - - if sunfireTarget == nil then - sunfireTarget = None - end - - return sunfireTarget - end) - -local RestoCommands = Bastion.Command:New('resto') - -local PLACE_EFFLO = false - -RestoCommands:Register('efflo', 'Request the engine to place an Efflorescence', function() - PLACE_EFFLO = true - Bastion.Notifications:AddNotification(Efflorescence:GetIcon(), "Efflorescence requested") -end) - -local DefaultAPL = Bastion.APL:New('default') -local DamageAPL = Bastion.APL:New('damage') - -DamageAPL:AddSpell( - Rake:CastableIf(function(self) - return RakeTarget:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() and - ( - not RakeTarget:GetAuras():FindMy(RakeDebuff):IsUp() or - RakeTarget:GetAuras():FindMy(RakeDebuff):GetRemainingTime() <= 3.6) - end):SetTarget(RakeTarget) -) - -DamageAPL:AddSpell( - FerociousBite:CastableIf(function(self) - return Target:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() and - Player:GetComboPoints() >= 5 - end):SetTarget(Target) -) - -DamageAPL:AddSpell( - Shred:CastableIf(function(self) - return Target:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() and - Player:GetComboPoints() < 5 - end):SetTarget(Target) -) - - -DefaultAPL:AddSpell( - Efflorescence:CastableIf(function(self) - return PLACE_EFFLO and Player:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() - end):SetTarget(None):OnCast(function(self) - local loc = Bastion.UnitManager:FindFriendsCentroid(10, 40) - PLACE_EFFLO = false - self:Click(loc) - end) -) - -CatForm:OnCast(function(self) - if not Player:GetAuras():FindMy(Prowl):IsUp() and not Player:IsAffectingCombat() then - Prowl:Cast(Player) - end -end) - -DefaultAPL:AddAction( - 'cat_form_shift', - function() - if (IsShiftKeyDown()) and not Player:IsMounted() and - not Player:GetAuras():FindMy(CatForm):IsUp() and - not Player:IsCastingOrChanneling() then - CatForm:Cast(Player) - elseif (not IsShiftKeyDown() and Player:IsAffectingCombat()) and Player:GetAuras():FindMy(CatForm):IsUp() then - CancelShapeshiftForm() - end - end -) - -DefaultAPL:AddSpell( - NaturesCure:CastableIf(function(self) - return DispelTarget:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() and - self:IsInRange(DispelTarget) and DispelTarget:GetAuras():HasAnyDispelableAura(NaturesCure) - end):SetTarget(DispelTarget) -) - -DefaultAPL:AddSpell( - Soothe:CastableIf(function(self) - return PurgeTarget:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() and - self:IsInRange(PurgeTarget) and PurgeTarget:GetAuras():HasAnyStealableAura() - end):SetTarget(PurgeTarget) -) - -DefaultAPL:AddSpell( - NaturesSwiftness:CastableIf(function(self) - return Lowest:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() - 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, 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, 70) >= 2 or Player:GetPartyHPAround(40, 75) >= 3) and - (not ConvokeTheSpirits:IsKnownAndUsable() and ConvokeTheSpirits:GetTimeSinceLastCast() > 10) and - WildGrowth:GetTimeSinceLastCast() <= 6 - end):SetTarget(Player) -) - -DefaultAPL:AddSpell( - NaturesVigil:CastableIf(function(self) - return Player:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() and - self:IsInRange(Player) and Flourish:GetTimeSinceLastCast() <= 5 - end):SetTarget(Player) -) - -DefaultAPL:AddSpell( - AdaptiveSwarm:CastableIf(function(self) - return Lowest:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() - and Player:CanSee(Lowest) - end):SetTarget(Lowest) -) - -DefaultAPL:AddSpell( - Swiftmend:CastableIf(function(self) - return SwiftmendUnit:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() - and Player:CanSee(SwiftmendUnit) and - ( - SwiftmendUnit:GetHP() <= 60 or - ( - Lowest:GetPartyHPAround(30, 90) >= 3 or Lowest:GetPartyHPAround(30, 85) >= 2 - ) - ) - end):SetTarget(SwiftmendUnit) -) - -DefaultAPL:AddSpell( - WildGrowth:CastableIf(function(self) - return WildGrowthUnit:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() - and Player:CanSee(WildGrowthUnit) 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) -) - -DefaultAPL:AddSpell( - Regrowth:CastableIf(function(self) - return Lowest:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() - and Player:CanSee(Lowest) and Lowest:GetHP() < 65 and - Player:GetAuras():FindMy(SoulOfTheForest):IsUp() and not Player:IsMoving() - end):SetTarget(Lowest) -) - -DefaultAPL:AddSpell( - Regrowth:CastableIf(function(self) - return Lowest:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() - and Player:CanSee(Lowest) and Lowest:GetHP() < 70 and - ( - NaturesSwiftness:GetTimeSinceLastCast() < 2 or Player:GetAuras():FindMy(NaturesSwiftness):IsUp() or - NaturesSwiftness:IsKnownAndUsable()) and not Player:IsMoving() and - not Player:GetAuras():FindMy(SoulOfTheForest):IsUp() - end):SetTarget(Lowest) -) - -DefaultAPL:AddSpell( - CenarionWard:CastableIf(function(self) - return Lowest:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() - and Player:CanSee(Lowest) and Lowest:GetHP() <= 90 - end):SetTarget(Lowest) -) - -DefaultAPL:AddSpell( - Ironbark:CastableIf(function(self) - return Lowest:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() - and Player:CanSee(Lowest) and Lowest:GetHP() <= 70 and not Lowest:GetAuras():FindMy(CenarionWard):IsUp() - 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) and - not Player:GetAuras():FindMy(SoulOfTheForest):IsUp() - end):SetTarget(RejuvUnit) -) - -DefaultAPL:AddSpell( - Lifebloom:CastableIf(function(self) - return Player:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() - and - ( - not Player:GetAuras():FindMy(LifebloomAura):IsUp() or - Player:GetAuras():FindMy(LifebloomAura):GetRemainingTime() <= 4.5) and Player:IsAffectingCombat() - end):SetTarget(Player) -) - -DefaultAPL:AddSpell( - Lifebloom:CastableIf(function(self) - return Tank:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() - and - ( - not Tank:GetAuras():FindMy(LifebloomAura):IsUp() or - Tank:GetAuras():FindMy(LifebloomAura):GetRemainingTime() <= 4.5) and Tank:IsAffectingCombat() - end):SetTarget(Tank) -) - -DefaultAPL:AddSpell( - Regrowth:CastableIf(function(self) - return Lowest:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() - and Player:CanSee(Lowest) and - ( - not Player:GetAuras():FindMy(Regrowth):IsUp() and Lowest:GetHP() < 70 or - (Lowest:GetHP() <= 85 and Player:GetAuras():FindMy(ClearCasting):IsUp())) and - not Player:GetAuras():FindMy(SoulOfTheForest):IsUp() and - not Player:IsMoving() - 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( - Moonfire:CastableIf(function(self) - return Explosive:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() - end):SetTarget(Explosive) -) - -DefaultAPL:AddSpell( - Sunfire:CastableIf(function(self) - return SunfireTarget:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() - and Player:CanSee(SunfireTarget) and - ( - not SunfireTarget:GetAuras():FindMy(SunfireAura):IsUp() or - SunfireTarget:GetAuras():FindMy(SunfireAura):GetRemainingTime() <= 5.4) and - SunfireTarget:IsHostile() and - SunfireTarget:IsAffectingCombat() and Player:GetPP() >= 25 - end):SetTarget(SunfireTarget) -) - -DefaultAPL:AddSpell( - Moonfire:CastableIf(function(self) - return MoonfireTarget:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() - and Player:CanSee(MoonfireTarget) and - ( - not MoonfireTarget:GetAuras():FindMy(MoonfireAura):IsUp() or - MoonfireTarget:GetAuras():FindMy(MoonfireAura):GetRemainingTime() <= 5.4) and - MoonfireTarget:IsHostile() and - MoonfireTarget:IsAffectingCombat() and Player:GetPP() >= 25 - end):SetTarget(MoonfireTarget) -) - -DefaultAPL:AddSpell( - Starsurge:CastableIf(function(self) - 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 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() - if IsShiftKeyDown() and Player:GetAuras():FindMy(CatForm):IsUp() then - return DamageAPL:Execute() - end - DefaultAPL:Execute() -end) - -Bastion:Register(RestoModule) diff --git a/scripts/subtlety.lua b/scripts/subtlety.lua deleted file mode 100644 index d1432f6..0000000 --- a/scripts/subtlety.lua +++ /dev/null @@ -1,1379 +0,0 @@ -local Tinkr, Bastion = ... - -local SubModulue = Bastion.Module:New('sub') -local Evaluator = Tinkr.Util.Evaluator -local Player = Bastion.UnitManager:Get('player') -local None = Bastion.UnitManager:Get('none') -local Target = Bastion.UnitManager:Get('target') - -Player:WatchForSwings() - -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 FlagellationPersist = Bastion.SpellBook:GetSpell(345569) -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 Blind = Bastion.SpellBook:GetSpell(2094) -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 Gouge = Bastion.SpellBook:GetSpell(1776) -local DeviousStratagem = Bastion.SpellBook:GetSpell(193531) -local SkullAndCrossbones = Bastion.SpellBook:GetSpell(199603) -local ShadowFocus = Bastion.SpellBook:GetSpell(108209) -local BuriedTreasure = Bastion.SpellBook:GetSpell(199600) -local AdrenalineRush = Bastion.SpellBook:GetSpell(13750) -local ShadowDance = Bastion.SpellBook:GetSpell(185313) -local ShadowDanceAura = Bastion.SpellBook:GetSpell(185422) -local Shadowmeld = Bastion.SpellBook:GetSpell(58984) -local Audacity = Bastion.SpellBook:GetSpell(381845) -local SealFate = Bastion.SpellBook:GetSpell(14190) -local GlobalCooldown = Bastion.SpellBook:GetSpell(61304) -local Flagellation = Bastion.SpellBook:GetSpell(323654) -local Dreadblades = Bastion.SpellBook:GetSpell(343142) -local MasterOfShadows = Bastion.SpellBook:GetSpell(196976) -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 TheRotten = Bastion.SpellBook:GetSpell(394203) -local Shiv = Bastion.SpellBook:GetSpell(5938) -local KidneyShot = Bastion.SpellBook:GetSpell(408) -local InstantPoison = Bastion.SpellBook:GetSpell(315584) -local Sanguine = Bastion.SpellBook:GetSpell(226512) -local AtrophicPosion = Bastion.SpellBook:GetSpell(381637) -local Evasion = Bastion.SpellBook:GetSpell(5277) -local TricksOfTheTrade = Bastion.SpellBook:GetSpell(57934) -local Backstab = Bastion.SpellBook:GetSpell(53) -local CheapShot = Bastion.SpellBook:GetSpell(1833) -local BagOfTricks = Bastion.SpellBook:GetSpell(312411) -local Alacrity = Bastion.SpellBook:GetSpell(193539) -local PerforatedVeins = Bastion.SpellBook:GetSpell(394254) -local AutoAttack = Bastion.SpellBook:GetSpell(6603) -local DeeperStratagem = Bastion.SpellBook:GetSpell(193531) -local SecretStratagem = Bastion.SpellBook:GetSpell(394320) -local SymbolsOfDeath = Bastion.SpellBook:GetSpell(212283) -local ShadowBlades = Bastion.SpellBook:GetSpell(121471) -local Vigor = Bastion.SpellBook:GetSpell(14983) -local ColdBlood = Bastion.SpellBook:GetSpell(382245) -local ShurikenTornado = Bastion.SpellBook:GetSpell(277925) -local ThistleTea = Bastion.SpellBook:GetSpell(381623) -local Gloomblade = Bastion.SpellBook:GetSpell(200758) -local Shadowstrike = Bastion.SpellBook:GetSpell(185438) -local Rupture = Bastion.SpellBook:GetSpell(1943) -local Eviscerate = Bastion.SpellBook:GetSpell(196819) -local ResoundingClarity = Bastion.SpellBook:GetSpell(381622) -local ArcanePulse = Bastion.SpellBook:GetSpell(260364) -local NumbingPoison = Bastion.SpellBook:GetSpell(5761) -local ShurikenStorm = Bastion.SpellBook:GetSpell(197835) -local BlackPowder = Bastion.SpellBook:GetSpell(319175) -local Sepsis = Bastion.SpellBook:GetSpell(385408) -local SecretTechnique = Bastion.SpellBook:GetSpell(280719) -local DarkBrew = Bastion.SpellBook:GetSpell(310454) -local Premeditation = Bastion.SpellBook:GetSpell(343173) -local ArcaneTorrent = Bastion.SpellBook:GetSpell(50613) -local DanseMacabre = Bastion.SpellBook:GetSpell(393969) -local LingeringShadow = Bastion.SpellBook:GetSpell(385960) -local EchoingReprimand = Bastion.SpellBook:GetSpell(385616) -local LightsJudgment = Bastion.SpellBook:GetSpell(255647) -local Subterfuge = Bastion.SpellBook:GetSpell(108208) -local EchoingReprimand2 = Bastion.SpellBook:GetSpell(323558) -local EchoingReprimand3 = Bastion.SpellBook:GetSpell(323559) -local EchoingReprimand4 = Bastion.SpellBook:GetSpell(323560) -local EchoingReprimand5 = Bastion.SpellBook:GetSpell(354838) -local SilentStorm = Bastion.SpellBook:GetSpell(385727) -local FindWeakness = Bastion.SpellBook:GetSpell(91023) -local ImprovedShurikenStorm = Bastion.SpellBook:GetSpell(319951) -local Feint = Bastion.SpellBook:GetSpell(1966) -local FinalityRupture = Bastion.SpellBook:GetSpell(385951) - -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) -local AlgetharsPuzzleBox = Bastion.ItemBook:GetItem(193701) - -local DeadgeHealth = 120000 * 12 - -local function IsDeadge(unit) return false end - -local PurgeTarget = Bastion.UnitManager:CreateCustomUnit('purge', function(unit) - local purge = nil - - Bastion.UnitManager:EnumEnemies(function(unit) - if unit:IsDead() then - return false - end - - if not Player:CanSee(unit) then - return false - end - - if Player:GetDistance(unit) > 40 then - return false - end - - if unit:GetAuras():HasAnyStealableAura() and Shiv:IsInRange(unit) then - purge = unit - return true - end - end) - - if purge == nil then - purge = None - end - - return purge - end) - -local KickTarget = Bastion.UnitManager:CreateCustomUnit('kick', function(unit) - local kick = nil - - Bastion.UnitManager:EnumEnemies(function(unit) - if unit:IsDead() then - return false - end - - if not Player:CanSee(unit) then - return false - end - - if Player:GetDistance(unit) > 40 then - return false - end - - if Player:InMelee(unit) and Player:IsFacing(unit) and Bastion.MythicPlusUtils:CastingCriticalKick(unit, 5) then - kick = unit - return true - end - end) - - if kick == nil then - kick = None - end - - return kick - end) - -local StunTarget = Bastion.UnitManager:CreateCustomUnit('stun', function(unit) - local stun = nil - - Bastion.UnitManager:EnumEnemies(function(unit) - if unit:IsDead() then - return false - end - - if not Player:CanSee(unit) then - return false - end - - if Player:GetDistance(unit) > 40 then - return false - end - - if Player:InMelee(unit) and Player:IsFacing(unit) and Bastion.MythicPlusUtils:CastingCriticalStun(unit, 5) then - stun = unit - return true - end - end) - - if stun == nil then - stun = None - end - - return stun - end) - -local Tank = Bastion.UnitManager:CreateCustomUnit('tank', function(unit) - local tank = nil - - Bastion.UnitManager:EnumFriends(function(unit) - if Player:GetDistance(unit) > 40 then - return false - end - - if not Player:CanSee(unit) then - return false - end - - if unit:IsDead() then - return false - end - - if unit:IsTank() then - tank = unit - return true - end - - return false - end) - - if tank == nil then - tank = None - end - - return tank - end) - -local RuptureTarget = Bastion.UnitManager:CreateCustomUnit('rupture', function() - local target = nil - - Bastion.UnitManager:EnumEnemies(function(unit) - if unit:IsDead() then - return false - end - - if not Player:CanSee(unit) then - return false - end - - if not Player:InMelee(unit) then - return false - end - - if not Player:IsFacing(unit) then - return false - end - - if ( - not unit:GetAuras():FindMy(Rupture):IsUp() or - unit:GetAuras():FindMy(Rupture):GetRemainingTime() < 6 - ) - and unit:GetHealth() > DeadgeHealth - then - target = unit - return true - end - end) - - if target == nil then - target = None - end - - return target - end) - - - -local DefaultAPL = Bastion.APL:New('default') -local ItemsAPL = Bastion.APL:New('items') -local DefensivesAPL = Bastion.APL:New('defensives') -local InterruptAPL = Bastion.APL:New('interrupt') -local BuildersAPL = Bastion.APL:New('builders') -local FinishersAPL = Bastion.APL:New('finishers') -local CDsAPL = Bastion.APL:New('cds') -local OpenersAPL = Bastion.APL:New('openers') -local TrinketsAPL = Bastion.APL:New('trinkets') - -function WasSelfHealUsedWithin(time) - local timeSinceHealthstone = Healthstone:GetTimeSinceLastUseAttempt() - local timeSincePotion = RefreshingHealingPotion:GetTimeSinceLastUseAttempt() - - return timeSinceHealthstone < time or timeSincePotion < time -end - -function WasInterruptUsedWithin(time) - local timeSinceKick = Kick:GetTimeSinceLastCastAttempt() - local timeSinceKidney = KidneyShot:GetTimeSinceLastCastAttempt() - local timeSinceGouge = Gouge:GetTimeSinceLastCastAttempt() - local timeSinceBlind = Blind:GetTimeSinceLastCastAttempt() - - return timeSinceKick < time or timeSinceKidney < time or timeSinceGouge < time or timeSinceBlind < time -end - -local FeintOn = { - [397878] = true, - [152964] = true, - [153094] = true, - [191284] = true, - [200901] = true, - [196512] = true, - [198058] = true, - [212784] = true, - [214692] = true, - [397892] = true, - [209741] = true, - [377004] = true, - [388923] = true, - [388537] = true, - [396991] = true, - [3747312] = true, - [384132] = true, - [388804] = true, - [388817] = true, - [384620] = true, - [375943] = true, - [376894] = true, - [372735] = true, - [373692] = true, - [392486] = true, - [392641] = true, - [384823] = true, - [381516] = true, -} - -local lastFeintTime = 0 - -Bastion.EventManager:RegisterWoWEvent('COMBAT_LOG_EVENT_UNFILTERED', function() - -- Check if the spell cast/channel is started is in a list - local _, event, _, sourceGUID, _, _, _, destGUID, _, _, _, spellID = CombatLogGetCurrentEventInfo() - - if event == 'SPELL_CAST_START' and FeintOn[spellID] then - lastFeintTime = GetTime() - end -end) - --- We should feint if we are about to take aoe damage -DefensivesAPL:AddSpell( - Feint:CastableIf(function(self) - return self:IsKnownAndUsable() and - not Player:IsCastingOrChanneling() and - GetTime() - lastFeintTime < 4 - end):SetTarget(Player) -) - -DefensivesAPL:AddSpell( - CrimsonVial:CastableIf(function(self) - return self:IsKnownAndUsable() and - not Player:IsCastingOrChanneling() and - Player:GetHealthPercent() < 70 and - not WasSelfHealUsedWithin(5) - end):SetTarget(Player) -) - -DefensivesAPL:AddItem( - Healthstone:UsableIf(function(self) - return self:IsEquippedAndUsable() and - not Player:IsCastingOrChanneling() and - Player:GetHealthPercent() < 40 and - not WasSelfHealUsedWithin(5) - end):SetTarget(Player) -) - -DefensivesAPL:AddItem( - RefreshingHealingPotion:UsableIf(function(self) - return self:IsEquippedAndUsable() and - not Player:IsCastingOrChanneling() and - Player:GetHealthPercent() < 40 and - not WasSelfHealUsedWithin(5) - end):SetTarget(Player) -) - -DefensivesAPL:AddSpell( - TricksOfTheTrade:CastableIf(function(self) - return Tank:Exists() and Target:Exists() and self:IsKnownAndUsable() and - not Player:IsCastingOrChanneling() and - Player:IsTanking(Target) - end):SetTarget(Tank) -) - --- DefensivesAPL:AddSpell( --- Evasion:CastableIf(function(self) --- return self:IsKnownAndUsable() and --- not Player:IsCastingOrChanneling() and --- Player:GetHealthPercent() < 40 --- end):SetTarget(Player) --- ) - -TrinketsAPL:AddItem( - IrideusFragment:UsableIf(function(self) - return self:IsEquippedAndUsable() and - not Player:IsCastingOrChanneling() and (Player:GetMeleeAttackers() > 2 or Target:IsBoss()) - end):SetTarget(Player) -) - -TrinketsAPL:AddItem( - ElementalPotionOfPower:UsableIf(function(self) - return self:IsEquippedAndUsable() and - not Player:IsCastingOrChanneling() and (Player:GetMeleeAttackers() > 2 or Target:IsBoss()) - end):SetTarget(Player) -) - -TrinketsAPL:AddItem( - WindscarWhetstone:UsableIf(function(self) - return Target:Exists() and Player:InMelee(Target) and self:IsEquippedAndUsable() and - not Player:IsCastingOrChanneling() and Target:GetHealth() and (Player:GetEnemies(10) > 2 or Target:IsBoss()) - end):SetTarget(Player) -) - -TrinketsAPL:AddItem( - AlgetharsPuzzleBox:UsableIf(function(self) - return Target:Exists() and Player:InMelee(Target) and self:IsEquippedAndUsable() and - not Player:IsCastingOrChanneling() and (Player:GetMeleeAttackers() > 3 or Target:IsBoss()) and - not Player:IsMoving() - end):SetTarget(Player) -) - -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) -) - -DefaultAPL:AddSpell( - Kick:CastableIf(function(self) - return KickTarget:Exists() and self:IsInRange(KickTarget) and - self:IsKnownAndUsable() and - not Player:IsCastingOrChanneling() and Player:IsFacing(Target) and not WasInterruptUsedWithin(2) and - not IsDeadge(Target) - end):SetTarget(KickTarget) -) - -DefaultAPL:AddSpell( - Gouge:CastableIf(function(self) - return StunTarget:Exists() and self:IsInRange(StunTarget) and - self:IsKnownAndUsable() and - not Player:IsCastingOrChanneling() and Player:IsFacing(Target) and - (Player:GetDistance(Target) < 1.5 or not Player:IsBehind(Target)) - and not Player:GetAuras():FindMy(SymbolsOfDeath):IsUp() and - not Player:GetAuras():FindMy(ShadowDanceAura):IsUp() and not WasInterruptUsedWithin(2) and - not IsDeadge(Target) - end):SetTarget(StunTarget) -) - -DefaultAPL:AddSpell( - KidneyShot:CastableIf(function(self) - return StunTarget:Exists() and self:IsInRange(StunTarget) and - self:IsKnownAndUsable() and - not Player:IsCastingOrChanneling() and Player:IsFacing(Target) - and not Player:GetAuras():FindMy(SymbolsOfDeath):IsUp() and - not Player:GetAuras():FindMy(ShadowDanceAura):IsUp() and not WasInterruptUsedWithin(2) and - not IsDeadge(Target) - end):SetTarget(StunTarget) -) - -DefaultAPL:AddSpell( - Blind:CastableIf(function(self) - return StunTarget:Exists() and self:IsInRange(StunTarget) and - self:IsKnownAndUsable() and - not Player:IsCastingOrChanneling() and Player:IsFacing(Target) - and not Player:GetAuras():FindMy(SymbolsOfDeath):IsUp() and - not Player:GetAuras():FindMy(ShadowDanceAura):IsUp() and not WasInterruptUsedWithin(2) and - not IsDeadge(Target) - end):SetTarget(StunTarget) -) - --- DefaultAPL:AddSpell( --- CheapShot:CastableIf(function(self) --- return StunTarget:Exists() and self:IsInRange(StunTarget) and --- self:IsKnownAndUsable() and --- not Player:IsCastingOrChanneling() and Player:IsFacing(Target) and not Player:IsBehind(Target) and --- Player:IsStealthed() and Player:GetPower() > 80 -- Cheap shot costs a lot so lets only use it with a surplus --- and Player:GetComboPoints() < 3 and not Player:GetAuras():FindMy(SymbolsOfDeath):IsUp() and --- not Player:GetAuras():FindMy(ShadowDanceAura):IsUp() --- end):SetTarget(StunTarget) --- ) - --- Purge -DefaultAPL:AddSpell( - Shiv:CastableIf(function(self) - return PurgeTarget:Exists() and - self:IsKnownAndUsable() and - not Player:IsCastingOrChanneling() and Player:IsFacing(Target) and not IsDeadge(Target) and - not Player:GetAuras():FindMy(ShadowDanceAura):IsUp() and not Player:GetAuras():FindMy(SymbolsOfDeath):IsUp() - end):SetTarget(PurgeTarget) -) - ---[[ - Subtlety Rogue Opener Sequence (Single Target) - - 1. Ensure you are in Stealth. - 2. Use Shadowstrike. - 3. Use Symbols of Death. | With Symbols of Death, use your offensive potion. - 4. Use Shadow Blades. - 5. Use Gloomblade. - 6. Use Rupture. - 7. Use Shadow Dance. - 7.5 Use Thistle Tea - 8. Use Gloomblade. | Use shadow strike if we don't have `The First Dance` - 9. Use Eviscerate - 10. Use Shadowstrike - 11. Use Secret Technique | With Secret Technique use Cold Blood - 12. Vanish - 13. Use Shadowstrike - - -- Continue with normal rotation -]] -local function CanPerformSTOpener() - return ShadowDance:IsKnownAndUsable() and - ShadowBlades:IsKnownAndUsable() and - SymbolsOfDeath:IsKnownAndUsable() and - Vanish:GetCharges() > 0 and - ThistleTea:GetCharges() > 0 and - ColdBlood:IsKnownAndUsable() -end - -local function ShouldPerformSTOpener() - -- If the target will survive the opener we should perform it - return Target:TimeToDie() > - Player:GetMaxGCD() * 13 + 5 and Player:GetEnemies(10) <= 2 -end - -local function ShouldResetSTOpener() - -- If we are no longer in combat and we can perform the opener we should reset it so we can perform it again in the future - return not Player:IsAffectingCombat() and CanPerformSTOpener() -end - -local function OpenerAbortCondition(spell) - -- If the cooldown is over 2 seconds we should abort the opener - return spell:GetCooldownRemaining() > 2 -end - -local OpenerSequenceST = Bastion.Sequencer:New({ - function(self) - if OpenerAbortCondition(Shadowstrike) then - self:Abort() - print("Aborting on Shadowstrike") - return true - end - - if Shadowstrike:IsKnownAndUsable() then - Shadowstrike:ForceCast(Target) - return true - end - return false - end, - function(self) - if OpenerAbortCondition(SymbolsOfDeath) then - self:Abort() - print("Aborting on SymbolsOfDeath") - return true - end - - if SymbolsOfDeath:IsKnownAndUsable() then - SymbolsOfDeath:ForceCast(Player) - ElementalPotionOfPower:Use(Player) - return true - end - return false - end, - function(self) - if OpenerAbortCondition(ShadowBlades) then - self:Abort() - print("Aborting on ShadowBlades") - return true - end - - if ShadowBlades:IsKnownAndUsable() then - ShadowBlades:ForceCast(Player) - return true - end - return false - end, - function(self) - if OpenerAbortCondition(Gloomblade) then - self:Abort() - print("Aborting on Gloomblade") - return true - end - - if Gloomblade:IsKnownAndUsable() then - Gloomblade:ForceCast(Target) - return true - end - return false - end, - function(self) - if OpenerAbortCondition(Rupture) then - self:Abort() - print("Aborting on Rupture") - return true - end - - if Rupture:IsKnownAndUsable() then - Rupture:ForceCast(Target) - return true - end - return false - end, - function(self) - if OpenerAbortCondition(ShadowDance) then - self:Abort() - print("Aborting on ShadowDance", ShadowDance:GetCooldownRemaining()) - return true - end - - if ShadowDance:IsKnownAndUsable() then - ShadowDance:ForceCast(Player) - return true - end - return false - end, - function(self) - if OpenerAbortCondition(ThistleTea) then - self:Abort() - print("Aborting on ThistleTea") - return true - end - - if ThistleTea:IsKnownAndUsable() then - ThistleTea:ForceCast(Player) - return true - end - return false - end, - function(self) - if OpenerAbortCondition(Gloomblade) then - self:Abort() - print("Aborting on Gloomblade") - return true - end - - if Gloomblade:IsKnownAndUsable() then - Gloomblade:ForceCast(Target) - return true - end - return false - end, - function(self) - if OpenerAbortCondition(Eviscerate) then - self:Abort() - print("Aborting on Eviscerate") - return true - end - - if Eviscerate:IsKnownAndUsable() then - Eviscerate:ForceCast(Target) - return true - end - return false - end, - function(self) - if OpenerAbortCondition(Shadowstrike) then - self:Abort() - print("Aborting on Shadowstrike") - return true - end - - if Shadowstrike:IsKnownAndUsable() then - Shadowstrike:ForceCast(Target) - return true - end - return false - end, - function(self) - if OpenerAbortCondition(SecretTechnique) then - self:Abort() - print("Aborting on SecretTechnique") - print("Aborting on ColdBlood") - return true - end - - if SecretTechnique:IsKnownAndUsable() then - SecretTechnique:ForceCast(Target) - ColdBlood:ForceCast(Target) - return true - end - return false - end, - function(self) - -- Somehow we lost our vanish charges, abort the opener - if Vanish:GetCharges() < 1 then - self:Abort() - print("Aborting on Vanish") - return true - end - - if Vanish:IsKnownAndUsable() then - Vanish:ForceCast(Player) - return true - end - return false - end, - function(self) - if OpenerAbortCondition(Shadowstrike) then - self:Abort() - print("Aborting on Shadowstrike") - return true - end - - if Shadowstrike:IsKnownAndUsable() then - Shadowstrike:ForceCast(Target) - return true - end - return false - end, - }, ShouldResetSTOpener) - ---[[ - Subtlety Opener Sequence for AoE - - 1. Ensure you are in Stealth. - 2. Shadowstrike - 3. Symbols of Death - 4. Shadow Blades - 5. Shuriken Tornado - 6. Shadow Dance | Use our offensive potion here - 7. Thistle Tea - 8. Rupture - 9. Black Powder - 10. Cold Blood and Secret Technique - 11. Black Powder - 12. Shadowstrike - 13. Black Powder - 14. Shuriken Storm - - ss, sd, sb, st, sd, tt, ru, bp, stcb, bp, ss, bp, sstor - - -- Continue with the normal rotation -]] -local function CanPerformAOEOpener() - return ShadowDance:IsKnownAndUsable() and - ShadowBlades:IsKnownAndUsable() and - SymbolsOfDeath:IsKnownAndUsable() and - ThistleTea:GetCharges() > 0 and - ColdBlood:IsKnownAndUsable() and ShurikenTornado:IsKnownAndUsable() -end - -local function ShouldPerformAOEOpener() - -- If the target will survive the opener we should perform it - return Target:TimeToDie() > - Player:GetMaxGCD() * 13 + 5 and Player:GetEnemies(10) > 2 -end - -local function ShouldResetAOEOpener() - -- If we are no longer in combat and we can perform the opener we should reset it so we can perform it again in the future - return not Player:IsAffectingCombat() and CanPerformAOEOpener() -end - -local OpenerSequenceAOE = Bastion.Sequencer:New({ - function(self) - if OpenerAbortCondition(Shadowstrike) then - self:Abort() - print("Aborting on Shadowstrike") - return true - end - - if Shadowstrike:IsKnownAndUsable() then - Shadowstrike:ForceCast(Target) - return true - end - return false - end, - function(self) - if OpenerAbortCondition(SymbolsOfDeath) then - self:Abort() - print("Aborting on SymbolsOfDeath") - return true - end - - if SymbolsOfDeath:IsKnownAndUsable() then - SymbolsOfDeath:ForceCast(Player) - return true - end - return false - end, - function(self) - if OpenerAbortCondition(ShadowBlades) then - self:Abort() - print("Aborting on ShadowBlades") - return true - end - - if ShadowBlades:IsKnownAndUsable() then - ShadowBlades:ForceCast(Player) - return true - end - return false - end, - function(self) - if OpenerAbortCondition(ShurikenTornado) then - self:Abort() - print("Aborting on ShurikenTornado") - return true - end - - if ShurikenTornado:IsKnownAndUsable() then - ShurikenTornado:ForceCast(Target) - return true - end - return false - end, - function(self) - if OpenerAbortCondition(ShadowDance) then - self:Abort() - print("Aborting on ShadowDance") - return true - end - - if ShadowDance:IsKnownAndUsable() then - ShadowDance:ForceCast(Player) - return true - end - return false - end, - function(self) - if OpenerAbortCondition(ThistleTea) then - self:Abort() - print("Aborting on ThistleTea") - return true - end - - if ThistleTea:IsKnownAndUsable() then - ThistleTea:ForceCast(Player) - return true - end - return false - end, - function(self) - if OpenerAbortCondition(Rupture) then - self:Abort() - print("Aborting on Rupture") - return true - end - - if Rupture:IsKnownAndUsable() then - Rupture:ForceCast(Target) - return true - end - return false - end, - function(self) - if OpenerAbortCondition(BlackPowder) then - self:Abort() - print("Aborting on BlackPowder") - return true - end - - if BlackPowder:IsKnownAndUsable() then - BlackPowder:ForceCast(Target) - return true - end - return false - end, - function(self) - if OpenerAbortCondition(SecretTechnique) then - self:Abort() - print("Aborting on SecretTechnique") - print("Aborting on ColdBlood") - return true - end - - if SecretTechnique:IsKnownAndUsable() then - SecretTechnique:ForceCast(Target) - ColdBlood:ForceCast(Target) - return true - end - return false - end, - function(self) - if OpenerAbortCondition(BlackPowder) then - self:Abort() - print("Aborting on BlackPowder") - return true - end - - if BlackPowder:IsKnownAndUsable() then - BlackPowder:ForceCast(Target) - return true - end - return false - end, - function(self) - if OpenerAbortCondition(Shadowstrike) then - self:Abort() - print("Aborting on Shadowstrike") - return true - end - - if Shadowstrike:IsKnownAndUsable() then - Shadowstrike:ForceCast(Target) - return true - end - return false - end, - function(self) - if OpenerAbortCondition(BlackPowder) then - self:Abort() - print("Aborting on BlackPowder") - return true - end - - if BlackPowder:IsKnownAndUsable() then - BlackPowder:ForceCast(Target) - return true - end - return false - end, - function(self) - if OpenerAbortCondition(ShurikenStorm) then - self:Abort() - print("Aborting on ShurikenStorm") - return true - end - - if ShurikenStorm:IsKnownAndUsable() then - ShurikenStorm:ForceCast(Target) - return true - end - return false - end, - }, ShouldResetAOEOpener) - ---[[ - == Subtlety Rogue Concepts == - - Keep Rupture and Slice and Dice up and stack cooldowns if reasonable. - Combo point Generators(Builders) are used when on low combo point value - Finishing moves are used to consume combo points when reaching six or more (five or more duringShadow Dance). -]] --- Builders - --- Should we pool for a Shadow Dance or Symbols of Death? -local function ShouldPoolForCD() - local SD = ShadowDance:GetCooldownRemaining() - local power = Player:GetPower() - local cp = Player:GetComboPoints() - local es = Player:GetEnemies(10) - - if es > 3 then return false end - - if power > 80 then return false end - - if SD < 3 and power < 80 then - return true - end - - return false -end - --- Gloomblade/Backstab: outside of Shadow Dance. -BuildersAPL:AddSpell( - Gloomblade:CastableIf(function(self) - return self:IsKnownAndUsable() and - not Player:IsCastingOrChanneling() and not Player:GetAuras():FindMy(ShadowDanceAura):IsUp() and - (Player:GetEnemies(10) <= 1 or (Player:GetEnemies(10) <= 2 and Player:GetAuras():FindMy(LingeringShadow):GetRemainingTime() > 6)) and - self:IsInRange(Target) - and not ShouldPoolForCD() - end):SetTarget(Target) -) - --- BuildersAPL:AddSpell( --- Backstab:CastableIf(function(self) --- return self:IsKnownAndUsable() and --- not Player:IsCastingOrChanneling() and not Player:GetAuras():FindMy(ShadowDanceAura):IsUp() --- end):SetTarget(Target) --- ) - --- Shadowstrike: during Shadow Dance. -BuildersAPL:AddSpell( - Shadowstrike:CastableIf(function(self) - return self:IsKnownAndUsable() and - not Player:IsCastingOrChanneling() and Player:GetAuras():FindMy(ShadowDanceAura):IsUp() and - (Player:GetEnemies(10) <= 2 or (Player:GetEnemies(10) <= 2 and Player:GetAuras():FindMy(ShadowDanceAura):IsUp())) and - self:IsInRange(Target) and Player:GetEnemies(10) < 6 and - not ShouldPoolForCD() - end):SetTarget(Target) -) - --- Shuriken Storm: on 2 or more targets (3 or more during Shadow Dance). -BuildersAPL:AddSpell( - ShurikenStorm:CastableIf(function(self) - return self:IsKnownAndUsable() and - not Player:IsCastingOrChanneling() and - ((Player:GetAuras():FindMy(ShadowDanceAura):IsUp() and Player:GetEnemies(10) >= 3) or - (not Player:GetAuras():FindMy(ShadowDanceAura):IsUp() and Player:GetEnemies(10) >= 2)) and - self:IsInRange(Target) and - not ShouldPoolForCD() - end):SetTarget(Target) -) - ---[[ - Optimizing around finality is mainly about consuming the buff in time, the optimal way to do so is to - prepare Rupture for Shadow Dance. This means to use Rupture if the remaining cooldown of Shadow Dance is - lower than 10 seconds and you have the Finality: Rupture buff. - -]] --- Rupture: any target that survives at least 12 seconds. -FinishersAPL:AddSpell( - Rupture:CastableIf(function(self) - return self:IsKnownAndUsable() and - not Player:IsCastingOrChanneling() and - Target:Exists() and - (Target:GetAuras():FindMy(Rupture):GetRemainingTime() < 8.4 or ((Player:GetAuras():FindMy(FinalityRupture):IsUp() and Player:GetAuras():FindMy(FinalityRupture):GetRemainingTime() < 10) and ShadowDance:GetCooldownRemaining() < 10) or (ShadowDance:GetCooldownRemaining() < 3 and (Target:GetAuras():FindMy(Rupture):GetRemainingTime() - 8 < 4))) and - self:IsInRange(Target) and not Player:GetAuras():FindMy(ShadowDanceAura):IsUp() and - not IsDeadge(Target) and not Player:GetAuras():FindMy(ShurikenTornado):IsUp() and - not ShadowDance:IsKnownAndUsable() and not Player:GetAuras():FindMy(SymbolsOfDeath):IsUp() and - Target:GetHealth() > DeadgeHealth - end):SetTarget(Target) -) - --- Slice and Dice: 1 - 5 targets. -FinishersAPL:AddSpell( - SliceAndDice:CastableIf(function(self) - return self:IsKnownAndUsable() and - not Player:IsCastingOrChanneling() and - (Player:GetAuras():FindMy(SliceAndDice):GetRemainingTime() < 12 or (ShadowDance:GetCooldownRemaining() < 3 and (Player:GetAuras():FindMy(SliceAndDice):GetRemainingTime() - 12 < 4))) and - Player:GetEnemies(10) <= 5 and - not Player:GetAuras():FindMy(ShadowDanceAura):IsUp() and not Player:GetAuras():FindMy(ShurikenTornado):IsUp() and - not ShadowDance:IsKnownAndUsable() and not Player:GetAuras():FindMy(SymbolsOfDeath):IsUp() - end):SetTarget(Player) -) - -FinishersAPL:AddSpell( - Rupture:CastableIf(function(self) - return self:IsKnownAndUsable() and - not Player:IsCastingOrChanneling() and - RuptureTarget:Exists() and - (RuptureTarget:GetAuras():FindMy(Rupture):GetRemainingTime() < 8.4 or ((Player:GetAuras():FindMy(FinalityRupture):IsUp() and Player:GetAuras():FindMy(FinalityRupture):GetRemainingTime() < 10) and ShadowDance:GetCooldownRemaining() < 10) or (ShadowDance:GetCooldownRemaining() < 3 and (RuptureTarget:GetAuras():FindMy(Rupture):GetRemainingTime() - 8 < 4))) and - self:IsInRange(RuptureTarget) and not Player:GetAuras():FindMy(ShadowDanceAura):IsUp() and - not IsDeadge(RuptureTarget) and not Player:GetAuras():FindMy(ShurikenTornado):IsUp() and - not ShadowDance:IsKnownAndUsable() and not Player:GetAuras():FindMy(SymbolsOfDeath):IsUp() and - RuptureTarget:GetHealth() > DeadgeHealth - end):SetTarget(RuptureTarget) -) - --- Secret Technique: During Shadow Dance, as 2nd finisher with Danse Macabre. --- FinishersAPL:AddSpell( --- SecretTechnique:CastableIf(function(self) --- return self:IsKnownAndUsable() and --- not Player:IsCastingOrChanneling() and --- Player:GetAuras():FindMy(ShadowDanceAura):IsUp() and self:IsInRange(Target) --- end):SetTarget(Target) --- ) - --- Black Powder: 3 or more targets. -FinishersAPL:AddSpell( - BlackPowder:CastableIf(function(self) - return self:IsKnownAndUsable() and - not Player:IsCastingOrChanneling() and - Player:GetEnemies(10) >= 3 and self:IsInRange(Target) and not ShadowDance:IsKnownAndUsable() - end):SetTarget(Target) -) - --- Eviscerate: 1 and 2 targets or for priority damage. -FinishersAPL:AddSpell( - Eviscerate:CastableIf(function(self) - return self:IsKnownAndUsable() and - not Player:IsCastingOrChanneling() and - (Player:GetEnemies(10) <= 2) and self:IsInRange(Target) and not ShadowDance:IsKnownAndUsable() - end):SetTarget(Target) -) - - --- Symbols of Death: on cooldown. -CDsAPL:AddSpell( - SymbolsOfDeath:CastableIf(function(self) - return self:IsKnownAndUsable() and - not Player:IsCastingOrChanneling() and - not Player:GetAuras():FindMy(SymbolsOfDeath):IsUp() and not IsDeadge(Target) and - GlobalCooldown:GetCooldownRemaining() <= 0 - end):SetTarget(Player):OnCast(function() - ShurikenTornado:ForceCast(Player) - end) -) - -CDsAPL:AddSpell( - ShurikenTornado:CastableIf(function(self) - return self:IsKnownAndUsable() and - not Player:IsCastingOrChanneling() and - (Player:GetAuras():FindMy(SymbolsOfDeath):IsUp() or SymbolsOfDeath:GetCooldownRemaining() > 10) and - Player:GetAuras():FindMy(SymbolsOfDeath):GetRemainingTime() > 3.5 and not IsDeadge(Target) and - not Player:GetAuras():FindMy(ShadowDanceAura):IsUp() - end):SetTarget(Player) -) - --- Shadow Dance: on cooldown -CDsAPL:AddSpell( - ShadowDance:CastableIf(function(self) - return self:IsKnownAndUsable() and - not Player:IsCastingOrChanneling() and - not Player:GetAuras():FindMy(ShadowDanceAura):IsUp() and - (Player:GetPower() >= 80 or Player:GetEnemies(10) > 2) and - not IsDeadge(Target) and - SymbolsOfDeath:GetCooldownRemaining() > 2 and GlobalCooldown:GetCooldownRemaining() <= 0 - end):SetTarget(Player):OnCast(function() - if Player:GetEnemies(10) > 3 then - ThistleTea:ForceCast(Player) - end - if Player:GetAuras():FindMy(SilentStorm):IsUp() then - ShurikenStorm:ForceCast(Target) - else - Gloomblade:ForceCast(Target) - end - end) -) - --- Shadow Blades: on cooldown. -CDsAPL:AddSpell( - ShadowBlades:CastableIf(function(self) - return self:IsKnownAndUsable() and - not Player:IsCastingOrChanneling() and not IsDeadge(Target) - end):SetTarget(Player) -) - --- Vanish: After Secret Technique during Shadow Dance -CDsAPL:AddSpell( - Vanish:CastableIf(function(self) - return self:IsKnownAndUsable() and - not Player:IsCastingOrChanneling() and - Player:GetAuras():FindMy(ShadowDanceAura):IsUp() and - SecretTechnique:GetTimeSinceLastCast() <= 3 and Vanish:GetCharges() > 1 and Player:GetEnemies(10) < 7 and - GlobalCooldown:GetCooldownRemaining() <= 0 - end):SetTarget(Player):OnCast(function() - Shadowstrike:ForceCast(Target) - end) -) - -local function HasRampedInDance() - if ShadowDance:GetTimeSinceLastCast() > 8 then - return false - end - - local ramped = false - local lastSD = ShadowDance:GetTimeSinceLastCast() - local lastEviscerate = Eviscerate:GetTimeSinceLastCast() - local lastBP = BlackPowder:GetTimeSinceLastCast() - local lastST = SecretTechnique:GetTimeSinceLastCast() - - -- if bp or ev happened before sd we are not ramped - return lastBP < lastSD or lastEviscerate < lastSD -end - --- Consider this a cooldown since it's tied to shadow dance ig and it has to be happening before cb/st. -CDsAPL:AddSpell( - Eviscerate:CastableIf(function(self) - return self:IsKnownAndUsable() and - not Player:IsCastingOrChanneling() and - self:IsInRange(Target) and Player:GetAuras():FindMy(ShadowDanceAura):IsUp() and - not HasRampedInDance() -- not sure yet - and Player:GetComboPoints() >= 5 and Player:GetEnemies(10) < 3 - end):SetTarget(Target) -) - -FinishersAPL:AddSpell( - BlackPowder:CastableIf(function(self) - return self:IsKnownAndUsable() and - not Player:IsCastingOrChanneling() and - self:IsInRange(Target) and Player:GetAuras():FindMy(ShadowDanceAura):IsUp() and - not HasRampedInDance() -- not sure yet - and Player:GetComboPoints() >= 5 and Player:GetEnemies(10) >= 3 - end):SetTarget(Target) -) - --- Cold Blood: before using a finishing move / before Secret Technique (if talented). -CDsAPL:AddSpell( - ColdBlood:CastableIf(function(self) - return (self:IsKnownAndUsable() or (SecretTechnique:IsKnownAndUsable() and ColdBlood:GetCooldownRemaining() > 2)) and - not Player:IsCastingOrChanneling() and SecretTechnique:IsKnownAndUsable() and - SecretTechnique:IsInRange(Target) and Player:GetAuras():FindMy(ShadowDanceAura):IsUp() - and Player:GetComboPoints() >= 5 and not IsDeadge(Target) and HasRampedInDance() - end):SetTarget(Player):OnCast(function() - SecretTechnique:ForceCast(Target) - end) -) - --- Thistle Tea: when on low energy (Single Target) / with Shadow Dance (Multi Target or on max charges). -CDsAPL:AddSpell( - ThistleTea:CastableIf(function(self) - return self:IsKnownAndUsable() and - not Player:IsCastingOrChanneling() and - ((Player:GetEnemies(10) <= 1 and Player:GetPower() <= 20)) and - not IsDeadge(Target) and not Player:GetAuras():FindMy(ThistleTea):IsUp() - end):SetTarget(Player) -) - --- DefaultAPL:AddSequence( --- OpenerSequenceST, --- ShouldPerformSTOpener --- ) - --- DefaultAPL:AddSequence( --- OpenerSequenceAOE, --- ShouldPerformAOEOpener --- ) - --- DefaultAPL:AddAPL( --- OpenersAPL, --- function() --- return ShouldPerformSTOpener() or ShouldPerformAOEOpener() --- end --- ) - -DefaultAPL:AddSpell( - Shadowstrike:CastableIf(function(self) - return self:IsKnownAndUsable() and - not Player:IsCastingOrChanneling() and - self:IsInRange(Target) and Player:GetAuras():FindMy(Premeditation):IsUp() and Player:GetEnemies(10) <= 6 - end):SetTarget(Target) -) - -DefaultAPL:AddAPL( - DefensivesAPL, - function() - return true - end -) - -DefaultAPL:AddAPL( - ItemsAPL, - function() - return true - end -) - -DefaultAPL:AddAPL( - TrinketsAPL, - function() - return Player:GetAuras():FindMy(SymbolsOfDeath):IsUp() and not IsDeadge(Target) - end -) - -DefaultAPL:AddAPL( - CDsAPL, - function() -- trying out a way to hold CDs, maybe it's dog - return Player:IsAffectingCombat() and not IsShiftKeyDown() - end -) - --- Use Finishing moves with 6 or more combo points (5 or more during Shadow Dance) with the following priority: -DefaultAPL:AddAPL( - FinishersAPL, - function() - return Player:GetComboPoints() >= 6 or - (Player:GetComboPoints() >= 5 and Player:GetAuras():FindMy(ShadowDanceAura):IsUp()) or - (Player:GetEnemies(10) > 3 and Player:GetComboPoints() >= 4) - end -) - -DefaultAPL:AddSpell( - BagOfTricks:CastableIf(function(self) - return self:IsKnownAndUsable() and - not Player:IsCastingOrChanneling() and - self:IsInRange(Target) and not Player:GetAuras():FindMy(ShadowDanceAura):IsUp() and - not Player:GetAuras():FindMy(SymbolsOfDeath):IsUp() and Player:GetEnemies(10) <= 2 - end):SetTarget(Target) -) - --- Builders APL -DefaultAPL:AddAPL( - BuildersAPL, - function() - return Player:GetComboPoints() < 6 or - (Player:GetComboPoints() < 5 and Player:GetAuras():FindMy(ShadowDanceAura):IsUp()) and - (not Player:GetAuras():FindMy(ShurikenTornado):IsUp() or Player:GetEnemies(10) <= 2) - end -) - -SubModulue:Sync(function() - if Player:IsAffectingCombat() and not IsCurrentSpell(6603) then - StartAttack() - end - -- DefensivesAPL:Execute() - -- InterruptAPL:Execute() - - DefaultAPL:Execute() -end) - -Bastion:Register(SubModulue) - -local Command = Bastion.Command:New('hero') -local hrEnabled = false - -Command:Register('toggle', 'Toggle hero rotations hook', function() - hrEnabled = not hrEnabled - Bastion:Print('HeroRotation ' .. (hrEnabled and 'enabled' or 'disabled')) -end) - -local HeroHooked = false -C_Timer.NewTicker(1, function() - if HeroRotation and not HeroHooked then - hooksecurefunc(HeroRotation, "Cast", (function(Object, OffGCD, DisplayStyle, OutofRange, CustomTime) - if DisplayStyle == "Pooling" and CustomTime ~= nil then - return - end - - if not hrEnabled then - return - end - DefensivesAPL:Execute() - InterruptAPL:Execute() - - if Object.ItemUseSpell then - UseItemByName(Object.ItemName) - elseif Object.SpellName then - CastSpellByName(Object.SpellName) - end - - if IsSpellPending() == 64 then - local x, y, z = ObjectPosition("target") - Click(x, y, z) - end - - -- DevTools_Dump(Object) - -- print("HeroRotation cast " .. Object.SpellID) - - HeroHooked = true - end)) - - hooksecurefunc(HeroRotation, "CastQueue", (function(...) - if not hrEnabled then - return - end - DefensivesAPL:Execute() - InterruptAPL:Execute() - - local spellsAndItems = { ... } - - for i = 1, #spellsAndItems do - local Object = spellsAndItems[i] - - if Object.ItemUseSpell then - UseItemByName(Object.ItemName) - SpellCancelQueuedSpell() - elseif Object.SpellName then - CastSpellByName(Object.SpellName) - SpellCancelQueuedSpell() - end - - if IsSpellPending() == 64 then - local x, y, z = ObjectPosition("target") - Click(x, y, z) - end - end - - -- DevTools_Dump(Object) - -- print("HeroRotation cast " .. Object.SpellID) - end)) - - hooksecurefunc(HeroRotation, "CastQueuePooling", function(customTime, Object) - if not hrEnabled then - return - end - - DefensivesAPL:Execute() - InterruptAPL:Execute() - - if Object.ItemUseSpell then - UseItemByName(Object.ItemName) - elseif Object.SpellName then - CastSpellByName(Object.SpellName) - end - - if IsSpellPending() == 64 then - local x, y, z = ObjectPosition("target") - Click(x, y, z) - end - - -- DevTools_Dump(Object) - -- print("HeroRotation cast " .. Object.SpellID) - - HeroHooked = true - end) - HeroHooked = true - print('HeroRotation hooked') - end -end) diff --git a/src/APL/APL.lua b/src/APL/APL.lua index fad2bf7..d5f4fd2 100644 --- a/src/APL/APL.lua +++ b/src/APL/APL.lua @@ -110,12 +110,14 @@ function APLActor:Execute() if self:GetActor().spell then if self:GetActor().condition then -- print("Bastion: APL:Execute: Condition for spell " .. self:GetActor().spell:GetName()) - self:GetActor().spell:CastableIf(self:GetActor().castableFunc):Cast(self:GetActor().target, + self:GetActor().spell:CastableIf(self:GetActor().castableFunc):OnCast(self:GetActor().onCastFunc):Cast( + self:GetActor().target, self:GetActor().condition) end -- print("Bastion: APL:Execute: No condition for spell " .. self:GetActor().spell:GetName()) - self:GetActor().spell:CastableIf(self:GetActor().castableFunc):Cast(self:GetActor().target) + self:GetActor().spell:CastableIf(self:GetActor().castableFunc):OnCast(self:GetActor().onCastFunc):Cast(self + :GetActor().target) end if self:GetActor().item then if self:GetActor().condition then @@ -208,9 +210,16 @@ end ---@return APLActor function APL:AddSpell(spell, condition) local castableFunc = spell.CastableIfFunc + local onCastFunc = spell.OnCastFunc local target = spell:GetTarget() - local actor = APLActor:New({ spell = spell, condition = condition, castableFunc = castableFunc, target = target }) + local actor = APLActor:New({ + spell = spell, + condition = condition, + castableFunc = castableFunc, + target = target, + onCastFunc = onCastFunc + }) table.insert(self.apl, actor) diff --git a/src/MythicPlusUtils/MythicPlusUtils.lua b/src/MythicPlusUtils/MythicPlusUtils.lua index e517e00..f131c74 100644 --- a/src/MythicPlusUtils/MythicPlusUtils.lua +++ b/src/MythicPlusUtils/MythicPlusUtils.lua @@ -8,6 +8,7 @@ local MythicPlusUtils = { loggedCasts = {}, loggedDebuffs = {}, kickList = {}, + aoeBosses = {} } MythicPlusUtils.__index = MythicPlusUtils @@ -17,9 +18,53 @@ function MythicPlusUtils:New() local self = setmetatable({}, MythicPlusUtils) self.random = math.random(1000000, 9999999) + + self.aoeBosses = { + [196482] = true, + [188252] = true, + [186644] = true, + [104217] = true, + } + + self.tankBusters = { + [397931] = true, -- https://www.wowhead.com/spell=397931/dark-claw + [396019] = true, -- https://www.wowhead.com/spell=396019/staggering-blow + [372730] = true, -- https://www.wowhead.com/spell=372730/crushing-smash + [395303] = true, -- https://www.wowhead.com/spell=395303/thunder-jaw + [392395] = true, -- https://www.wowhead.com/spell=392395/thunder-jaw + [372858] = true, -- https://www.wowhead.com/spell=372858/searing-blows + [372859] = true, -- https://www.wowhead.com/spell=372859/searing-blows + [387135] = true, -- https://www.wowhead.com/spell=387135/arcing-strike + [388801] = true, -- https://www.wowhead.com/spell=388801/mortal-strike + [387826] = true, -- https://www.wowhead.com/spell=387826/heavy-slash + [370764] = true, -- https://www.wowhead.com/spell=370764/piercing-shards + [377105] = true, -- https://www.wowhead.com/spell=377105/ice-cutter + [388911] = true, -- https://www.wowhead.com/spell=388911/severing-slash + [388912] = true, -- https://www.wowhead.com/spell=388912/severing-slash + [199050] = true, -- https://www.wowhead.com/spell=199050/mortal-hew + [164907] = true, -- https://www.wowhead.com/spell=164907/void-slash + [377991] = true, -- https://www.wowhead.com/spell=377991/storm-slash + [376997] = true, -- https://www.wowhead.com/spell=376997/savage-peck + [192018] = true, -- https://www.wowhead.com/spell=192018/shield-of-light + [106823] = true, -- https://www.wowhead.com/spell=106823/serpent-strike + [106841] = true, -- https://www.wowhead.com/spell=106841/jade-serpent-strike + [381512] = true, -- https://www.wowhead.com/spell=381512/stormslam + [381514] = true, -- https://www.wowhead.com/spell=381514/stormslam + [381513] = true, -- https://www.wowhead.com/spell=381513/stormslam + [381515] = true, -- https://www.wowhead.com/spell=381515/stormslam + [372222] = true, -- https://www.wowhead.com/spell=372222/arcane-cleave + [385958] = true, -- https://www.wowhead.com/spell=385958/arcane-expulsion + [382836] = true, -- https://www.wowhead.com/spell=382836/brutalize + [376827] = true, -- https://www.wowhead.com/spell=376827/conductive-strike not sure if we defensive on these or the other strike NO final boss + [375937] = true, -- https://www.wowhead.com/spell=375937/rending-strike not sure if we defensive on these or the other strike NO final boss + [198888] = true, -- https://www.wowhead.com/spell=198888/lightning-breath + [384978] = true, -- https://www.wowhead.com/spell=384978/dragon-strike + [388923] = true, -- https://www.wowhead.com/spell=388923/burst-forth + } + self.kickList = { -- Ruby life pools - [372735] = { -- Techtonic Slam + [372735] = { -- Techtonic Slam [187969] = { false, true, true -- Kick, Stun, Disorient } @@ -377,6 +422,11 @@ function MythicPlusUtils:New() false, true, false } }, + [195696] = { + [387125] = { + true, false, false + } + } } Bastion.EventManager:RegisterWoWEvent('UNIT_AURA', function(unit, auras) @@ -511,4 +561,14 @@ function MythicPlusUtils:CastingCriticalStun(unit, percent) return false end +---@param unit Unit +---@return boolean +function MythicPlusUtils:IsAOEBoss(unit) + return self.aoeBosses[unit:GetID()] +end + +function MythicPlusUtils:IsTankBuster(spell) + return self.tankBusters[spell:GetID()] +end + return MythicPlusUtils diff --git a/src/Spell/Spell.lua b/src/Spell/Spell.lua index c33d7c6..f96493d 100644 --- a/src/Spell/Spell.lua +++ b/src/Spell/Spell.lua @@ -12,6 +12,7 @@ local Spell = { lastCastAt = false, conditions = {}, target = false, + release_at = false, } local usableExcludes = { @@ -88,6 +89,26 @@ function Spell:GetCooldown() return select(2, GetSpellCooldown(self:GetID())) end +-- Get the full cooldown (time until all charges are available) +---@return number +function Spell:GetFullRechargeTime() + local start, duration, enabled = GetSpellCooldown(self:GetID()) + if enabled == 0 then + return 0 + end + + local charges, maxCharges, chargeStart, chargeDuration = GetSpellCharges(self:GetID()) + if charges == maxCharges then + return 0 + end + + if charges == 0 then + return start + duration - GetTime() + end + + return chargeStart + chargeDuration - GetTime() +end + -- Return the castable function ---@return fun(self:Spell):boolean function Spell:GetCastableFunction() @@ -113,6 +134,12 @@ function Spell:GetCooldownRemaining() return start + duration - GetTime() end +-- Get the spell count +---@return number +function Spell:GetCount() + return GetSpellCount(self:GetID()) +end + -- On cooldown ---@return boolean function Spell:OnCooldown() @@ -368,6 +395,10 @@ function Spell:GetMaxCharges() return select(2, GetSpellCharges(self:GetID())) end +function Spell:GetCastLength() + return select(4, GetSpellInfo(self:GetID())) +end + -- Get the spells charges ---@return number function Spell:GetChargesFractional() @@ -461,24 +492,24 @@ end ---@return boolean function Spell:IsMagicDispel() return ({ - [88423] = true - })[self:GetID()] + [88423] = true + })[self:GetID()] end -- IsCurseDispel ---@return boolean function Spell:IsCurseDispel() return ({ - [88423] = true - })[self:GetID()] + [88423] = true + })[self:GetID()] end -- IsPoisonDispel ---@return boolean function Spell:IsPoisonDispel() return ({ - [88423] = true - })[self:GetID()] + [88423] = true + })[self:GetID()] end -- IsDiseaseDispel @@ -486,7 +517,7 @@ end function Spell:IsDiseaseDispel() return ({ - })[self:GetID()] + })[self:GetID()] end -- IsSpell @@ -496,4 +527,17 @@ function Spell:IsSpell(spell) return self:GetID() == spell:GetID() end +-- GetCost +---@return number +function Spell:GetCost() + local cost = GetSpellPowerCost(self:GetID()) + return cost and cost.cost or 0 +end + +-- IsFree +---@return boolean +function Spell:IsFree() + return self:GetCost() == 0 +end + return Spell diff --git a/src/Unit/Unit.lua b/src/Unit/Unit.lua index 81155cf..0c34681 100644 --- a/src/Unit/Unit.lua +++ b/src/Unit/Unit.lua @@ -372,16 +372,35 @@ function Unit:IsCasting() return UnitCastingInfo(self:GetOMToken()) ~= nil end +function Unit:GetTimeCastIsAt(percent) + local name, text, texture, startTimeMS, endTimeMS, isTradeSkill, castID, notInterruptible, spellId = UnitCastingInfo( + self:GetOMToken()) + + if not name then + name, text, texture, startTimeMS, endTimeMS, isTradeSkill, notInterruptible, spellId = UnitChannelInfo(self + :GetOMToken()) + end + + if name and startTimeMS and endTimeMS then + local castLength = endTimeMS - startTimeMS + local startTime = startTimeMS / 1000 + local timeUntil = (castLength / 1000) * (percent / 100) + + return startTime + timeUntil + end + + return 0 +end + -- Get Casting or channeling spell ---@return Spell | nil function Unit:GetCastingOrChannelingSpell() local name, text, texture, startTimeMS, endTimeMS, isTradeSkill, castID, notInterruptible, spellId = UnitCastingInfo( - self - .unit) + self:GetOMToken()) if not name then - name, text, texture, startTimeMS, endTimeMS, isTradeSkill, notInterruptible, spellId = UnitChannelInfo(self.unit - :unit()) + name, text, texture, startTimeMS, endTimeMS, isTradeSkill, notInterruptible, spellId = UnitChannelInfo(self + :GetOMToken()) end if name then @@ -391,6 +410,24 @@ function Unit:GetCastingOrChannelingSpell() return nil end +-- Get the end time of the cast or channel +---@return number +function Unit:GetCastingOrChannelingEndTime() + local name, text, texture, startTimeMS, endTimeMS, isTradeSkill, castID, notInterruptible, spellId = UnitCastingInfo( + self:GetOMToken()) + + if not name then + name, text, texture, startTimeMS, endTimeMS, isTradeSkill, notInterruptible, spellId = UnitChannelInfo(self + :GetOMToken()) + end + + if name then + return endTimeMS / 1000 + end + + return 0 +end + -- Check if the unit is channeling a spell ---@return boolean function Unit:IsChanneling() @@ -413,12 +450,11 @@ end ---@return number function Unit:GetChannelOrCastPercentComplete() local name, text, texture, startTimeMS, endTimeMS, isTradeSkill, castID, notInterruptible, spellId = UnitCastingInfo( - self - .unit) + self:GetOMToken()) if not name then - name, text, texture, startTimeMS, endTimeMS, isTradeSkill, notInterruptible, spellId = UnitChannelInfo(self.unit - :unit()) + name, text, texture, startTimeMS, endTimeMS, isTradeSkill, notInterruptible, spellId = UnitChannelInfo(self + :GetOMToken()) end if name and startTimeMS and endTimeMS then @@ -435,12 +471,11 @@ end ---@return boolean function Unit:IsInterruptible() local name, text, texture, startTimeMS, endTimeMS, isTradeSkill, castID, notInterruptible, spellId = UnitCastingInfo( - self - .unit) + self:GetOMToken()) if not name then - name, text, texture, startTimeMS, endTimeMS, isTradeSkill, notInterruptible, spellId = UnitChannelInfo(self.unit - :unit()) + name, text, texture, startTimeMS, endTimeMS, isTradeSkill, notInterruptible, spellId = UnitChannelInfo(self + :GetOMToken()) end if name then @@ -481,7 +516,7 @@ function Unit:GetEnemies(range) local count = 0 Bastion.UnitManager:EnumEnemies(function(unit) - if not self:IsUnit(unit) and unit:GetDistance(self) <= range and unit:IsAlive() and self:CanSee(unit) and + if not self:IsUnit(unit) and self:IsWithinCombatDistance(unit, range) and unit:IsAlive() and self:CanSee(unit) and unit:IsEnemy() then count = count + 1 end @@ -503,7 +538,7 @@ function Unit:GetMeleeAttackers() Bastion.UnitManager:EnumEnemies(function(unit) if not self:IsUnit(unit) and unit:IsAlive() and self:CanSee(unit) and - self:InMelee(unit) and unit:IsEnemy() and unit:InCombatOdds() > 80 then + self:InMelee(unit) and unit:IsEnemy() then count = count + 1 end end) @@ -582,7 +617,7 @@ end ---@return boolean function Unit:IsTanking(unit) local isTanking, status, threatpct, rawthreatpct, threatvalue = UnitDetailedThreatSituation(self:GetOMToken(), - unit:GetOMToken()) + unit:GetOMToken()) return isTanking end @@ -773,9 +808,9 @@ function Unit:StartTTDTicker() end self.ttd_ticker = C_Timer.NewTicker(0.5, function() - local timeto = self:PredictTime(0) - GetTime() - self.ttd = timeto - end) + local timeto = self:PredictTime(0) - GetTime() + self.ttd = timeto + end) end -- Time until death @@ -968,4 +1003,166 @@ function Unit:IsDry() return not ObjectIsSubmerged(self.unit) end +-- The unit stagger amount +---@return number +function Unit:GetStagger() + return UnitStagger(self:GetOMToken()) +end + +-- The percent of health the unit is currently staggering +---@return number +function Unit:GetStaggerPercent() + local stagger = self:GetStagger() + local max_health = self:GetMaxHealth() + + return (stagger / max_health) * 100 +end + +-- Get the units power regen rate +---@return number +function Unit:GetPowerRegen() + return GetPowerRegen(self:GetOMToken()) +end + +-- Get the units staggered health relation +---@return number +function Unit:GetStaggeredHealth() + local stagger = self:GetStagger() + local max_health = self:GetMaxHealth() + + return (stagger / max_health) * 100 +end + +-- get the units combat reach +---@return number +function Unit:GetCombatReach() + return ObjectCombatReach(self:GetOMToken()) +end + +-- Get the units combat distance (distance - combat reach (realized distance)) +---@return number +function Unit:GetCombatDistance(Target) + return self:GetDistance(Target) - Target:GetCombatReach() +end + +-- Is the unit within distance of the target (combat reach + distance) +--- If the target is within 8 combat yards (8 + combat reach) of the unit +---@param Target Unit +---@param Distance number +---@return boolean +function Unit:IsWithinCombatDistance(Target, Distance) + if not Target:Exists() then + return false + end + return self:GetDistance(Target) <= Distance + Target:GetCombatReach() +end + +-- Check if the unit is within X yards (consider combat reach) +---@param Target Unit +---@param Distance number +---@return boolean +function Unit:IsWithinDistance(Target, Distance) + return self:GetDistance(Target) <= Distance +end + +-- Get the angle between the unit and the target in raidans +---@param Target Unit +---@return number +function Unit:GetAngle(Target) + if not Target:Exists() then + return 0 + end + + local sp = self:GetPosition() + local tp = Target:GetPosition() + + local an = Tinkr.Common.GetAnglesBetweenPositions(sp.x, sp.y, sp.z, tp.x, tp.y, tp.z) + + return an +end + +function Unit:GetFacing() + return ObjectRotation(self:GetOMToken()) or 0 +end + +-- Check if target is within a arc around the unit (angle, distance) accounting for a rotation of self +---@param Target Unit +---@param Angle number +---@param Distance number +---@return boolean +function Unit:IsWithinCone(Target, Angle, Distance, rotation) + if not Target:Exists() then + return false + end + + local angle = self:GetAngle(Target) + local rotation = rotation or self:GetFacing() + + local diff = math.abs(angle - rotation) + + if diff > math.pi then + diff = math.abs(diff - math.pi * 2) + end + + return diff <= Angle and self:GetDistance(Target) <= Distance +end + +-- local empowering = {} + +-- Bastion.EventManager:RegisterWoWEvent("UNIT_SPELLCAST_EMPOWER_START", function(...) +-- local unit, unk, id = ... +-- if not unit then return end +-- local guid = ObjectGUID(unit) +-- if not guid then return end +-- empowering[guid] = -1 +-- end) + +-- Bastion.EventManager:RegisterWoWEvent("UNIT_SPELLCAST_EMPOWER_STOP", function(...) +-- local unit, unk, id = ... +-- if not unit then return end +-- local guid = ObjectGUID(unit) +-- if not guid then return end +-- empowering[guid] = -1 +-- end) + +-- function Unit:GetUnitEmpowerStage() +-- local name, text, texture, startTime, endTime, isTradeSkill, notInterruptible, spellID, _, numStages = +-- UnitChannelInfo(self:GetOMToken()); + +-- if name and empowering[self:GetGUID()] == -1 then +-- empowering[self:GetGUID()] = numStages +-- end + +-- if not name and empowering[self:GetGUID()] then +-- return empowering[self:GetGUID()] +-- end + +-- if not name then +-- return empowering[self:GetGUID()] +-- end + +-- local getStageDuration = function(stage) +-- if stage == numStages then +-- return GetUnitEmpowerHoldAtMaxTime(self:GetOMToken()); +-- else +-- return GetUnitEmpowerStageDuration(self:GetOMToken(), stage - 1); +-- end +-- end + +-- local time = GetTime() - (startTime / 1000); + +-- local higheststage = 0 +-- local sumdur = 0 +-- for i = 1, numStages - 1, 1 do +-- local duration = getStageDuration(i) / 1000; +-- sumdur = sumdur + duration + +-- if time > sumdur then +-- higheststage = i +-- end +-- end + +-- return higheststage +-- end + return Unit diff --git a/src/_bastion.lua b/src/_bastion.lua index 7e52165..5e84909 100644 --- a/src/_bastion.lua +++ b/src/_bastion.lua @@ -135,19 +135,19 @@ Bastion.EventManager:RegisterWoWEvent("COMBAT_LOG_EVENT_UNFILTERED", function() end) Bastion.Ticker = C_Timer.NewTicker(0.1, function() - if not Bastion.CombatTimer:IsRunning() and UnitAffectingCombat("player") then - Bastion.CombatTimer:Start() - elseif Bastion.CombatTimer:IsRunning() and not UnitAffectingCombat("player") then - Bastion.CombatTimer:Reset() - end + if not Bastion.CombatTimer:IsRunning() and UnitAffectingCombat("player") then + Bastion.CombatTimer:Start() + elseif Bastion.CombatTimer:IsRunning() and not UnitAffectingCombat("player") then + Bastion.CombatTimer:Reset() + end - if Bastion.Enabled then - Bastion.ObjectManager:Refresh() - for i = 1, #Bastion.modules do - Bastion.modules[i]:Tick() - end + if Bastion.Enabled then + Bastion.ObjectManager:Refresh() + for i = 1, #Bastion.modules do + Bastion.modules[i]:Tick() end - end) + end +end) function Bastion:Register(module) table.insert(Bastion.modules, module) @@ -270,7 +270,7 @@ local files = ListFiles("scripts/bastion/scripts") for i = 1, #files do local file = files[i] - if file:sub( -4) == ".lua" or file:sub( -5) == '.luac' then + if file:sub(-4) == ".lua" or file:sub(-5) == '.luac' then Tinkr:require("scripts/bastion/scripts/" .. file:sub(1, -5), Bastion) end end