GUI, Scripts, Commands

Embedded GUI, amended scripts, added bastion interface
main
Ofrex 2 years ago
parent 53679d748f
commit ac9d9740be
  1. 17
      README.md
  2. 954
      scripts/outlaw.lua
  3. 608
      scripts/outlawbak.lua
  4. 287
      scripts/restodruid.lua
  5. 64
      scripts/shadowpriest.lua
  6. 88
      scripts/subtlety.lua
  7. 4
      src/APL/APL.lua
  8. 14
      src/Aura/Aura.lua
  9. 4
      src/AuraTable/AuraTable.lua
  10. 1
      src/Cache/Cache.lua
  11. 6
      src/Cacheable/Cacheable.lua
  12. 1
      src/Class/Class.lua
  13. 2
      src/ClassMagic/ClassMagic.lua
  14. 2
      src/Command/Command.lua
  15. 2
      src/EventManager/EventManager.lua
  16. 113
      src/GUI/Gui.lua
  17. 11
      src/Item/Item.lua
  18. 2
      src/ItemBook/ItemBook.lua
  19. 1
      src/List/List.lua
  20. 1
      src/Module/Module.lua
  21. 159
      src/MythicPlusUtils/MythicPlusUtils.lua
  22. 30
      src/NotificationsList/NotificationsList.lua
  23. 1
      src/ObjectManager/ObjectManager.lua
  24. 6
      src/Refreshable/Refreshable.lua
  25. 10
      src/Spell/Spell.lua
  26. 4
      src/SpellBook/SpellBook.lua
  27. 1
      src/Timer/Timer.lua
  28. 18
      src/Unit/Unit.lua
  29. 6
      src/UnitManager/UnitManager.lua
  30. 1
      src/Vector3/Vector3.lua
  31. 57
      src/_bastion.lua

@ -1,13 +1,18 @@
All credit to 4n0n for creating the Bastion framework!
Bastion aims to be a highly performant and complete World of Warcraft data visualization layer, as such developers may
leverage it to create combat rotations, gathering bots, quest bots, and much more!
Pull requests are welcome and encouraged, however I do ask that scripts such as rotations live in their own repository,
for the moment the included restoration druid rotation is the exception as it serves as a learning resource for developers
to reference in creating their own scripts.
Feel free to browse around the [Wiki](https://git.tinkr.site/4n0n/bastion/wiki) or just start by reading the code!
## Quick Start
- [Download](https://git.tinkr.site/4n0n/bastion/archive/main.zip) or clone the repository.
- [Download](https://git.tinkr.site/RexUK/bastion/archive/main.zip) or clone the repository.
- Move the bastion folder to your `Tinkr/scripts` folder.
- Once in-game type `/bastion toggle` to enable the engine.
- Once in-game type `/bastion interface` to open the main menu.
## Latest changes
Added Unit:IsIndoors() to Unit.lua
Changed _bastion.lua to not automatically load all modules
Added class/spec checks to _bastion.lua to only load the class/spec you're in game with
Implemented GUI though Gui.lua based on Kaminaris StdUI - https://github.com/kaminaris/StdUi

@ -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)<?(6-talent.summarily_dispatched))|effective_combo_points>=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<int>( 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<gcd
CDsAPL:AddSpell(
BladeFlurry:CastableIf(
function(self)
return self:IsKnownAndUsable() and Target:GetMeleeAttackers() >= 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<combo_points.deficit|combo_points.deficit>=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<charges*6)
CDsAPL:AddSpell(
ThistleTea:CastableIf(
function(self)
return self:IsKnownAndUsable() and Player:GetAuras():FindMy(ThistleTea):IsDown() and
(Player:GetPowerDeficit() >= 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<fight_remains&refreshable&(!talent.swift_slasher|combo_points>=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.audacity<talent.count_the_odds+talent.keep_it_rolling
StealthAPL:AddVariable(
'vanish_opportunity_condition',
function()
return not ShadowDance:IsKnown() and
(FanTheHammer:IsKnown() and 1 or 0) + (QuickDraw:IsKnown() and 1 or 0) + (Audacity:IsKnown() and 1 or 0) <
(CountTheOdds:IsKnown() and 1 or 0) + (KeepItRolling:IsKnown() and 1 or 0)
end
)
-- actions.stealth_cds+=/vanish,if=talent.find_weakness&!talent.audacity&debuff.find_weakness.down&variable.ambush_condition&variable.vanish_condition
StealthAPL:AddSpell(
Vanish:CastableIf(
function(self)
return self:IsKnownAndUsable() and FindWeakness:IsKnown() and not Audacity:IsKnown() and
not Target:GetAuras():FindMy(FindWeakness):IsUp() and
DefaultAPL:GetVariable('ambush_condition') and StealthAPL:GetVariable('vanish_condition')
end
):SetTarget(Target)
)
-- actions.stealth_cds+=/vanish,if=talent.hidden_opportunity&!buff.audacity.up&(variable.vanish_opportunity_condition|buff.opportunity.stack<buff.opportunity.max_stack)&variable.ambush_condition&variable.vanish_condition
StealthAPL:AddSpell(
Vanish:CastableIf(
function(self)
return self:IsKnownAndUsable() and HiddenOpportunity:IsKnown() and
not Player:GetAuras():FindMy(Audacity):IsUp() and
(StealthAPL:GetVariable('vanish_opportunity_condition') or
Player:GetAuras():FindMy(OpportunityAura):GetCount() <
MaxOpportunity()) and
DefaultAPL:GetVariable('ambush_condition') and StealthAPL:GetVariable('vanish_condition')
end
):SetTarget(Target)
)
-- actions.stealth_cds+=/vanish,if=(!talent.find_weakness|talent.audacity)&!talent.hidden_opportunity&variable.finish_condition&variable.vanish_condition
StealthAPL:AddSpell(
Vanish:CastableIf(
function(self)
return self:IsKnownAndUsable() and (not FindWeakness:IsKnown() or Audacity:IsKnown()) and
not HiddenOpportunity:IsKnown() and
DefaultAPL:GetVariable('finish_condition') and StealthAPL:GetVariable('vanish_condition')
end
):SetTarget(Target)
)
-- actions.stealth_cds+=/variable,name=shadow_dance_condition,value=talent.shadow_dance&debuff.between_the_eyes.up&(!talent.ghostly_strike|debuff.ghostly_strike.up)&(!talent.dreadblades|!cooldown.dreadblades.ready)&(!talent.hidden_opportunity|!buff.audacity.up&(talent.fan_the_hammer.rank<2|!buff.opportunity.up))
StealthAPL:AddVariable(
'shadow_dance_condition',
function()
return ShadowDance:IsKnown() and Target:GetAuras():FindMy(BetweenTheEyes):IsUp() and
(not GhostlyStrike:IsKnown() or Target:GetAuras():FindMy(GhostlyStrike):IsUp()) and
(not Dreadblades:IsKnown() or not Dreadblades:CooldownUp()) and
(not HiddenOpportunity:IsKnown() or not Player:GetAuras():FindMy(Audacity):IsUp() and
(1 < 2 or not Player:GetAuras():FindMy(OpportunityAura):IsUp()))
end
)
-- actions.stealth_cds+=/shadow_dance,if=!talent.keep_it_rolling&variable.shadow_dance_condition&buff.slice_and_dice.up&(variable.finish_condition|talent.hidden_opportunity)&(!talent.hidden_opportunity|!cooldown.vanish.ready)
StealthAPL:AddSpell(
ShadowDance:CastableIf(
function(self)
return self:IsKnownAndUsable() and not KeepItRolling:IsKnown() and
StealthAPL:GetVariable('shadow_dance_condition') and
Player:GetAuras():FindMy(SliceAndDice):IsUp() and
(DefaultAPL:GetVariable('finish_condition') or HiddenOpportunity:IsKnown()) and
(not HiddenOpportunity:IsKnown() or not Vanish:CooldownUp())
end
):SetTarget(Target)
)
-- actions.stealth_cds+=/shadow_dance,if=talent.keep_it_rolling&variable.shadow_dance_condition&(cooldown.keep_it_rolling.remains<=30|cooldown.keep_it_rolling.remains>120&(variable.finish_condition|talent.hidden_opportunity))
StealthAPL:AddSpell(
ShadowDance:CastableIf(
function(self)
return self:IsKnownAndUsable() and KeepItRolling:IsKnown() and
StealthAPL:GetVariable('shadow_dance_condition') and
(KeepItRolling:GetCooldownRemaining() <= 30 or
KeepItRolling:GetCooldownRemaining() > 120 and
(DefaultAPL:GetVariable('finish_condition') or HiddenOpportunity:IsKnown()))
end
):SetTarget(Target)
)
OutlawModule:Sync(function()
print(BetweenTheEyes:IsKnownAndUsable())
DefaultAPL:Execute()
end)
Bastion:Register(OutlawModule)

@ -0,0 +1,608 @@
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 RollTheBones = Bastion.SpellBook:GetSpell(315508)
local SliceAndDice = Bastion.SpellBook:GetSpell(315496)
local BetweenTheEyes = Bastion.SpellBook:GetSpell(315341)
local BladeRush = Bastion.SpellBook:GetSpell(271877)
local Vanish = Bastion.SpellBook:GetSpell(1856)
local Dispatch = Bastion.SpellBook:GetSpell(2098)
local Ambush = Bastion.SpellBook:GetSpell(8676)
local Stealth = Bastion.SpellBook:GetSpell(1784)
local PistolShot = Bastion.SpellBook:GetSpell(185763)
local Opportunity = Bastion.SpellBook:GetSpell(195627)
local SinisterStrike = Bastion.SpellBook:GetSpell(193315)
local GrandMelee = Bastion.SpellBook:GetSpell(193358)
local Broadside = Bastion.SpellBook:GetSpell(193356)
local TrueBearing = Bastion.SpellBook:GetSpell(193359)
local RuthlessPrecision = Bastion.SpellBook:GetSpell(193357)
local SkullAndCrossbones = Bastion.SpellBook:GetSpell(199603)
local BuriedTreasure = Bastion.SpellBook:GetSpell(199600)
local AdrenalineRush = Bastion.SpellBook:GetSpell(13750)
local ShadowDance = Bastion.SpellBook:GetSpell(185313)
local Audacity = Bastion.SpellBook:GetSpell(381845)
local Flagellation = Bastion.SpellBook:GetSpell(323654)
local Dreadblades = Bastion.SpellBook:GetSpell(343142)
local JollyRoger = Bastion.SpellBook:GetSpell(199603)
local BladeFlurry = Bastion.SpellBook:GetSpell(13877)
local Kick = Bastion.SpellBook:GetSpell(1766)
local MarkedForDeath = Bastion.SpellBook:GetSpell(137619)
local CrimsonVial = Bastion.SpellBook:GetSpell(185311)
local Shiv = Bastion.SpellBook:GetSpell(5938)
local KidneyShot = Bastion.SpellBook:GetSpell(408)
local InstantPoison = Bastion.SpellBook:GetSpell(315584)
local AtrophicPosion = Bastion.SpellBook:GetSpell(381637)
local Evasion = Bastion.SpellBook:GetSpell(5277)
local TricksOfTheTrade = Bastion.SpellBook:GetSpell(57934)
local CheapShot = Bastion.SpellBook:GetSpell(1833)
local BagOfTricks = Bastion.SpellBook:GetSpell(312411)
local AutoAttack = Bastion.SpellBook:GetSpell(6603)
local IrideusFragment = Bastion.ItemBook:GetItem(193743)
local Healthstone = Bastion.ItemBook:GetItem(5512)
local WindscarWhetstone = Bastion.ItemBook:GetItem(137486)
local 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 AOEAPL = Bastion.APL:New('aoe')
local SpecialAPL = Bastion.APL:New('special')
SpecialAPL:AddSpell(
Kick:CastableIf(function(self)
return KickTarget:Exists() and Player:InMelee(KickTarget) and
self:IsKnownAndUsable() and
not Player:IsCastingOrChanneling()
end):SetTarget(KickTarget)
)
SpecialAPL:AddSpell(
SinisterStrike:CastableIf(function(self)
return Explosive:Exists() and not Player:IsCastingOrChanneling()
end):SetTarget(Explosive)
)
SpecialAPL:AddSpell(
KidneyShot:CastableIf(function(self)
return KickTarget:Exists() and Player:InMelee(KickTarget) and
self:IsKnownAndUsable() and
not Player:IsCastingOrChanneling() and
(Player:GetComboPoints(Target) >= 5 or
(
Player:GetComboPoints(Target) >= 4 and
(Player:GetAuras():FindMy(Broadside):IsUp() or Player:GetAuras():FindMy(Opportunity):IsUp())))
end):SetTarget(KickTarget)
)
SpecialAPL:AddSpell(
CheapShot:CastableIf(function(self)
return KickTarget:Exists() and Player:InMelee(KickTarget) and
self:IsKnownAndUsable() and
not Player:IsCastingOrChanneling() and Player:GetAuras():FindMy(Stealth):IsUp()
end):SetTarget(KickTarget)
)
SpecialAPL:AddSpell(
Stealth:CastableIf(function(self)
return self:IsKnownAndUsable() and
not Player:IsCastingOrChanneling() and not Player:IsAffectingCombat() and
not Player:GetAuras():FindMy(Stealth):IsUp() and not IsMounted()
end):SetTarget(Player)
)
SpecialAPL:AddSpell(
CrimsonVial:CastableIf(function(self)
return self:IsKnownAndUsable() and
not Player:IsCastingOrChanneling() and
Player:GetHealthPercent() < 70
end):SetTarget(Player)
)
SpecialAPL:AddSpell(
Shiv:CastableIf(function(self)
return PurgeTarget:Exists() and Player:InMelee(PurgeTarget) and
self:IsKnownAndUsable() and
not Player:IsCastingOrChanneling() and PurgeTarget:GetAuras():HasAnyStealableAura()
end):SetTarget(PurgeTarget)
)
SpecialAPL:AddSpell(
InstantPoison:CastableIf(function(self)
return self:IsKnownAndUsable() and
not Player:IsCastingOrChanneling() and
not Player:GetAuras():FindMy(InstantPoison):IsUp() and not Player:IsMoving()
end):SetTarget(Player)
)
SpecialAPL:AddSpell(
AtrophicPosion:CastableIf(function(self)
return self:IsKnownAndUsable() and
not Player:IsCastingOrChanneling() and
not Player:GetAuras():FindMy(AtrophicPosion):IsUp() and not Player:IsMoving()
end):SetTarget(Player)
)
SpecialAPL:AddItem(
Healthstone:UsableIf(function(self)
return self:IsEquippedAndUsable() and
not Player:IsCastingOrChanneling() and
Player:GetHealthPercent() < 40
end):SetTarget(Player)
)
SpecialAPL:AddSpell(
TricksOfTheTrade:CastableIf(function(self)
return Tank:Exists() and self:IsKnownAndUsable() and
not Player:IsCastingOrChanneling() and
Player:IsTanking(Target)
end):SetTarget(Tank)
)
SpecialAPL:AddSpell(
Evasion:CastableIf(function(self)
return self:IsKnownAndUsable() and
not Player:IsCastingOrChanneling() and
Player:GetHealthPercent() < 40
end):SetTarget(Player)
)
SpecialAPL:AddItem(
IrideusFragment:UsableIf(function(self)
return self:IsEquippedAndUsable() and
not Player:IsCastingOrChanneling() and (Player:GetMeleeAttackers() > 2 or Target:IsBoss())
end):SetTarget(Player)
)
SpecialAPL:AddItem(
WindscarWhetstone:UsableIf(function(self)
return self:IsEquippedAndUsable() and
not Player:IsCastingOrChanneling() and (Player:GetMeleeAttackers() > 2 or Target:IsBoss())
end):SetTarget(Player)
)
SpecialAPL:AddSpell(
BagOfTricks:CastableIf(function(self)
return Target:Exists() and Player:InMelee(Target) and
self:IsKnownAndUsable() and
not Player:IsCastingOrChanneling()
end):SetTarget(Target)
)
-- Adrenaline Rush on cooldown.
DefaultAPL:AddSpell(
AdrenalineRush:CastableIf(function(self)
return Target:Exists() and Player:InMelee(Target) and
self:IsKnownAndUsable() and
not Player:IsCastingOrChanneling()
end):SetTarget(Player)
)
-- Roll the Bones if you have no combat enhancements active.
DefaultAPL:AddSpell(
RollTheBones:CastableIf(function(self)
local numBuffs = 0
if Player:GetAuras():FindMy(Broadside):IsUp() then
numBuffs = numBuffs + 1
end
if Player:GetAuras():FindMy(BuriedTreasure):IsUp() then
numBuffs = numBuffs + 1
end
if Player:GetAuras():FindMy(GrandMelee):IsUp() then
numBuffs = numBuffs + 1
end
if Player:GetAuras():FindMy(RuthlessPrecision):IsUp() then
numBuffs = numBuffs + 1
end
if Player:GetAuras():FindMy(SkullAndCrossbones):IsUp() then
numBuffs = numBuffs + 1
end
if Player:GetAuras():FindMy(TrueBearing):IsUp() then
numBuffs = numBuffs + 1
end
return self:IsKnownAndUsable() and
not Player:IsCastingOrChanneling() and
((not Player:GetAuras():FindMy(Broadside):IsUp() and
not Player:GetAuras():FindMy(TrueBearing):IsUp()) or numBuffs < 2)
end):SetTarget(Player)
)
-- Slice and Dice if at max, or -1 from maximum combo points with Broadside or Opportunity active, if missing or has has 12 or less seconds remaining.
DefaultAPL:AddSpell(
SliceAndDice:CastableIf(function(self)
return Target:Exists() and Player:InMelee(Target) and
self:IsKnownAndUsable() and
not Player:IsCastingOrChanneling() and
(Player:GetComboPoints(Target) >= 5 or
(
Player:GetComboPoints(Target) >= 4 and
(Player:GetAuras():FindMy(Broadside):IsUp() or Player:GetAuras():FindMy(Opportunity):IsUp()))) and
(
not Player:GetAuras():FindMy(SliceAndDice):IsUp() or
Player:GetAuras():FindMy(SliceAndDice):GetRemainingTime() <= 12
)
end):SetTarget(Target)
)
-- Between the Eyes on cooldown if at max, or -1 from maximum combo points with Broadside or Opportunity active.
DefaultAPL:AddSpell(
BetweenTheEyes:CastableIf(function(self)
return Target:Exists() and Player:InMelee(Target) and
self:IsKnownAndUsable() and
not Player:IsCastingOrChanneling() and
(Player:GetComboPoints(Target) >= 5 or
(
Player:GetComboPoints(Target) >= 4 and
(Player:GetAuras():FindMy(Broadside):IsUp() or Player:GetAuras():FindMy(Opportunity):IsUp())))
end):SetTarget(Target)
)
-- Dispatch if at max, or -1 from maximum combo points with Broadside or Opportunity active.
DefaultAPL:AddSpell(
Dispatch:CastableIf(function(self)
return Target:Exists() and Player:InMelee(Target) and
self:IsKnownAndUsable() and
not Player:IsCastingOrChanneling() and
(Player:GetComboPoints(Target) >= 5 or
(
Player:GetComboPoints(Target) >= 4 and
(Player:GetAuras():FindMy(Broadside):IsUp() or Player:GetAuras():FindMy(Opportunity):IsUp())))
end):SetTarget(Target)
)
-- Shadow Dance at or below 3 combo points, and do not have Audacity or Opportunity active and wait until you have at least 80 energy. While active Ambush becomes your highest priority builder.
DefaultAPL:AddSpell(
ShadowDance:CastableIf(function(self)
return Target:Exists() and Player:InMelee(Target) and
self:IsKnownAndUsable() and
not Player:IsCastingOrChanneling() and
Player:GetComboPoints(Target) <= 3 and
not Player:GetAuras():FindMy(Audacity):IsUp() and
not Player:GetAuras():FindMy(Opportunity):IsUp() and
Player:GetPower() >= 80
end):SetTarget(Player)
)
-- Blade Rush if missing 50 or more energy and do not have Flagellation, Dreadblades or Shadow Dance active.
DefaultAPL:AddSpell(
BladeRush:CastableIf(function(self)
return Target:Exists() and Player:InMelee(Target) and
self:IsKnownAndUsable() and
not Player:IsCastingOrChanneling() and
Player:GetPower() <= 50 and
not Player:GetAuras():FindMy(Flagellation):IsUp() and
not Player:GetAuras():FindMy(Dreadblades):IsUp() and
not Player:GetAuras():FindMy(ShadowDance):IsUp()
end):SetTarget(Player)
)
-- Vanish followed by Ambush if you won't overcap combo points and wait until you have at least 50 energy.
DefaultAPL:AddSpell(
Vanish:CastableIf(function(self)
return Tank:Exists() and Target:Exists() and Player:InMelee(Target) and
self:IsKnownAndUsable() and
not Player:IsCastingOrChanneling() and
Player:GetComboPoints(Target) <= 4 and
Player:GetPower() >= 50 and not Player:GetAuras():FindMy(Stealth):IsUp()
end):SetTarget(Player)
)
-- Pistol Shot if you have an Opportunity proc and won't overcap combo points.
DefaultAPL:AddSpell(
PistolShot:CastableIf(function(self)
return Target:Exists() and Player:InMelee(Target) and
self:IsKnownAndUsable() and
not Player:IsCastingOrChanneling() and
Player:GetAuras():FindMy(Opportunity):IsUp() and
Player:GetComboPoints(Target) <= 4
end):SetTarget(Target)
)
-- Use Ambush Icon Ambush instead of Sinister Strike Icon Sinister Strike whenever it is available to cast from any of the procs or cooldowns.
DefaultAPL:AddSpell(
Ambush:CastableIf(function(self)
return Target:Exists() and Player:InMelee(Target) and
self:IsKnownAndUsable() and
not Player:IsCastingOrChanneling()
end):SetTarget(Target)
)
-- Sinister Strike if you won't overcap combo points.
DefaultAPL:AddSpell(
SinisterStrike:CastableIf(function(self)
return Target:Exists() and Player:InMelee(Target) and
self:IsKnownAndUsable() and
not Player:IsCastingOrChanneling() and
Player:GetComboPoints(Target) < 5
end):SetTarget(Target)
)
-- AOE APL
-- Adrenaline Rush on cooldown.
AOEAPL:AddSpell(
AdrenalineRush:CastableIf(function(self)
return Target:Exists() and Player:InMelee(Target) and
self:IsKnownAndUsable() and
not Player:IsCastingOrChanneling()
end):SetTarget(Player)
)
-- Roll the Bones if you have no combat enhancements active.
-- Roll the Bones has a large outcome of buffs which include; Broadside, Buried Treasure, Grand Melee, Ruthless Precision, Skull and Crossbones, and True Bearing. The buffs you want to keep this tier are going to be Broadside and True Bearing as single buffs or any combination of 2 or more buffs. Any of the other 4 buffs as a single means it's worth recasting Roll the Bones as soon as you are able to.
AOEAPL:AddSpell(
RollTheBones:CastableIf(function(self)
local numBuffs = 0
if Player:GetAuras():FindMy(Broadside):IsUp() then
numBuffs = numBuffs + 1
end
if Player:GetAuras():FindMy(BuriedTreasure):IsUp() then
numBuffs = numBuffs + 1
end
if Player:GetAuras():FindMy(GrandMelee):IsUp() then
numBuffs = numBuffs + 1
end
if Player:GetAuras():FindMy(RuthlessPrecision):IsUp() then
numBuffs = numBuffs + 1
end
if Player:GetAuras():FindMy(SkullAndCrossbones):IsUp() then
numBuffs = numBuffs + 1
end
if Player:GetAuras():FindMy(TrueBearing):IsUp() then
numBuffs = numBuffs + 1
end
return self:IsKnownAndUsable() and
not Player:IsCastingOrChanneling() and
((not Player:GetAuras():FindMy(Broadside):IsUp() and
not Player:GetAuras():FindMy(TrueBearing):IsUp()) or numBuffs < 2)
end):SetTarget(Player)
)
-- Blade Flurry when missing.
AOEAPL:AddSpell(
BladeFlurry:CastableIf(function(self)
return self:IsKnownAndUsable() and
not Player:IsCastingOrChanneling() and
(not Player:GetAuras():FindMy(self):IsUp() or Player:GetAuras():FindMy(self):GetRemainingTime() <= 2)
end):SetTarget(Player)
)
-- Slice and Dice if at max, or -1 from maximum combo points with Broadside or Opportunity active, if missing or has has 12 or less seconds remaining.
AOEAPL:AddSpell(
SliceAndDice:CastableIf(function(self)
return Target:Exists() and Player:InMelee(Target) and
self:IsKnownAndUsable() and
not Player:IsCastingOrChanneling() and
(Player:GetComboPoints(Target) >= 5 or
(Player:GetComboPoints(Target) >= 4 and
(Player:GetAuras():FindMy(Broadside):IsUp() or
Player:GetAuras():FindMy(Opportunity):IsUp()))) and
(not Player:GetAuras():FindMy(self):IsUp() or
Player:GetAuras():FindMy(self):GetRemainingTime() <= 12)
end):SetTarget(Player)
)
-- Between the Eyes on cooldown if at max, or -1 from maximum combo points with Broadside or Opportunity active.
AOEAPL:AddSpell(
BetweenTheEyes:CastableIf(function(self)
return Target:Exists() and Player:InMelee(Target) and
self:IsKnownAndUsable() and
not Player:IsCastingOrChanneling() and
(Player:GetComboPoints(Target) >= 5 or
(Player:GetComboPoints(Target) >= 4 and
(Player:GetAuras():FindMy(Broadside):IsUp() or
Player:GetAuras():FindMy(Opportunity):IsUp())))
end):SetTarget(Target)
)
-- Dispatch if at max, or -1 from maximum combo points with Broadside or Opportunity active.
AOEAPL:AddSpell(
Dispatch:CastableIf(function(self)
return Target:Exists() and Player:InMelee(Target) and
self:IsKnownAndUsable() and
not Player:IsCastingOrChanneling() and
(Player:GetComboPoints(Target) >= 5 or
(Player:GetComboPoints(Target) >= 4 and
(Player:GetAuras():FindMy(Broadside):IsUp() or
Player:GetAuras():FindMy(Opportunity):IsUp())))
end):SetTarget(Target)
)
-- Shadow Dance at or below 3 combo points, and do not have Audacity or Opportunity active and wait until you have at least 80 energy. While active Ambush becomes your highest priority builder.
AOEAPL:AddSpell(
ShadowDance:CastableIf(function(self)
return Target:Exists() and Player:InMelee(Target) and
self:IsKnownAndUsable() and
not Player:IsCastingOrChanneling() and
Player:GetComboPoints(Target) <= 3 and
not Player:GetAuras():FindMy(Audacity):IsUp() and
not Player:GetAuras():FindMy(Opportunity):IsUp() and
Player:GetPower() >= 80
end):SetTarget(Player)
)
-- Blade Rush if missing 50 or more energy and do not have Flagellation, Dreadblades or Shadow Dance active.
AOEAPL:AddSpell(
BladeRush:CastableIf(function(self)
return Target:Exists() and Player:InMelee(Target) and
self:IsKnownAndUsable() and
not Player:IsCastingOrChanneling() and
Player:GetPower() >= 50 and
not Player:GetAuras():FindMy(Flagellation):IsUp() and
not Player:GetAuras():FindMy(Dreadblades):IsUp() and
not Player:GetAuras():FindMy(ShadowDance):IsUp()
end):SetTarget(Player)
)
-- Vanish followed by Ambush if you won't overcap combo points and wait until you have at least 50 energy.
AOEAPL:AddSpell(
Vanish:CastableIf(function(self)
return Tank:Exists() and Target:Exists() and Player:InMelee(Target) and
self:IsKnownAndUsable() and
not Player:IsCastingOrChanneling() and
Player:GetComboPoints(Target) < 5 and
Player:GetPower() >= 50 and not Player:GetAuras():FindMy(Stealth):IsUp()
end):SetTarget(Player)
)
-- Pistol Shot if you have an Opportunity proc and won't overcap combo points.
AOEAPL:AddSpell(
PistolShot:CastableIf(function(self)
return Target:Exists() and Player:InMelee(Target) and
self:IsKnownAndUsable() and
not Player:IsCastingOrChanneling() and
Player:GetAuras():FindMy(Opportunity):IsUp() and
Player:GetComboPoints(Target) < 5
end):SetTarget(Target)
)
AOEAPL:AddSpell(
Ambush:CastableIf(function(self)
return Target:Exists() and Player:InMelee(Target) and
self:IsKnownAndUsable() and
not Player:IsCastingOrChanneling()
end):SetTarget(Target)
)
-- Sinister Strike if you won't overcap combo points.
AOEAPL:AddSpell(
SinisterStrike:CastableIf(function(self)
return Target:Exists() and Player:InMelee(Target) and
self:IsKnownAndUsable() and
not Player:IsCastingOrChanneling() and
Player:GetComboPoints(Target) < 5
end):SetTarget(Target)
)
OutlawModule:Sync(function()
SpecialAPL:Execute()
if Player:GetMeleeAttackers() > 1 then
AOEAPL:Execute()
else
DefaultAPL:Execute()
end
end)
Bastion:Register(OutlawModule)

@ -6,6 +6,8 @@ local Player = Bastion.UnitManager:Get('player')
local None = Bastion.UnitManager:Get('none')
local Target = Bastion.UnitManager:Get('target')
local myconf = Tinkr.Util.Config:New('resto_druid')
local AnomalyDetectionMarkI = Bastion.SpellBook:GetSpell(382499)
local AutoAttack = Bastion.SpellBook:GetSpell(6603)
local MechanismBypass = Bastion.SpellBook:GetSpell(382501)
@ -89,6 +91,7 @@ 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 MoonkinForm = Bastion.SpellBook:GetSpell(197625)
local Revitalize = Bastion.SpellBook:GetSpell(212040)
local Tranquility = Bastion.SpellBook:GetSpell(740)
local MasteryHarmony = Bastion.SpellBook:GetSpell(77495)
@ -385,14 +388,14 @@ local Explosive = Bastion.UnitManager:CreateCustomUnit('explosive', function(uni
return explosive
end)
local RestoCommands = Bastion.Command:New('resto')
-- local RestoCommands = Bastion.Command:New('rex')
local PLACE_EFFLO = false
-- 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)
-- 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')
@ -405,20 +408,21 @@ DefaultAPL:AddSpell(
DefaultAPL:AddSpell(
Efflorescence:CastableIf(function(self)
return PLACE_EFFLO and Player:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling()
return IsShiftKeyDown() 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
--local loc = Target:GetPosition()
self:Click(loc)
end)
)
DefaultAPL:AddAction(
'cat_form_shift',
function()
if IsShiftKeyDown() and not Player:GetAuras():FindMy(CatForm):IsUp() and not Player:IsCastingOrChanneling() then
CatForm:Cast(Player)
elseif not IsShiftKeyDown() and Player:GetAuras():FindMy(CatForm):IsUp() then
if IsAltKeyDown() and not Player:GetAuras():FindMy(MoonkinForm):IsUp() and not Player:IsCastingOrChanneling() then
MoonkinForm:Cast(Player)
elseif not IsAltKeyDown() and Player:GetAuras():FindMy(MoonkinForm):IsUp() then
CancelShapeshiftForm()
end
end
@ -441,23 +445,30 @@ DefaultAPL:AddSpell(
DefaultAPL:AddSpell(
NaturesSwiftness:CastableIf(function(self)
return Lowest:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling()
and Player:CanSee(Lowest) and Lowest:GetHP() < 70
and Player:CanSee(Lowest) and
(Lowest:GetHP() < 70 or (Player:GetPartyHPAround(40, 65) >= 2 or Player:GetPartyHPAround(40, 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)
self:IsInRange(Player) and (Player:GetPartyHPAround(40, 65) >= 2 or Player:GetPartyHPAround(40, 60) >= 3)
end):SetTarget(Player)
)
DefaultAPL:AddSpell(
MarkoftheWild:CastableIf(function(self)
return Player:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() and
not Player:GetAuras():FindMy(MarkoftheWild):IsUp()
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
self:IsInRange(Player) and (Player:GetPartyHPAround(40, 65) >= 2 or Player:GetPartyHPAround(40, 70) >= 3) and
(not ConvokeTheSpirits:IsKnownAndUsable() and ConvokeTheSpirits:GetTimeSinceLastCast() > 7) and
WildGrowth:GetTimeSinceLastCast() <= 6
end):SetTarget(Player)
)
@ -471,7 +482,7 @@ DefaultAPL:AddSpell(
DefaultAPL:AddSpell(
AdaptiveSwarm:CastableIf(function(self)
return Lowest:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling()
return Lowest:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() and Player:IsAffectingCombat()
and Player:CanSee(Lowest)
end):SetTarget(Lowest)
)
@ -481,7 +492,7 @@ DefaultAPL:AddSpell(
return SwiftmendUnit:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling()
and Player:CanSee(SwiftmendUnit) and
(
SwiftmendUnit:GetHP() <= 60 or
SwiftmendUnit:GetHP() <= 80 or
(
Lowest:GetPartyHPAround(30, 90) >= 3 or Lowest:GetPartyHPAround(30, 85) >= 2
)
@ -494,10 +505,12 @@ DefaultAPL:AddSpell(
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
(
Player:GetAuras():FindMy(SoulOfTheForest):IsUp() and
(
Player:GetAuras():FindMy(SoulOfTheForest):GetRemainingTime() <= 5 or
WildGrowthUnit:GetPartyHPAround(30, 90) >= 2)) or
(WildGrowthUnit:GetPartyHPAround(30, 90) >= 3 or WildGrowthUnit:GetPartyHPAround(30, 85) >= 2)) and
not Player:IsMoving()
end):SetTarget(WildGrowthUnit)
)
@ -538,7 +551,7 @@ DefaultAPL:AddSpell(
DefaultAPL:AddSpell(
Rejuvenation:CastableIf(function(self)
return RejuvUnit:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling()
and Player:CanSee(RejuvUnit) and (RejuvUnit:GetHP() <= 94) and
and Player:CanSee(RejuvUnit) and RejuvUnit:GetHP() <= 90 and
not Player:GetAuras():FindMy(SoulOfTheForest):IsUp()
end):SetTarget(RejuvUnit)
)
@ -575,60 +588,214 @@ DefaultAPL:AddSpell(
end):SetTarget(Lowest)
)
DamageAPL:AddSpell(
Sunfire:CastableIf(function(self)
return Bastion.UnitManager['target']:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling()
and Player:CanSee(Bastion.UnitManager['target']) and
(
not Bastion.UnitManager['target']:GetAuras():FindMy(SunfireAura):IsUp() or
Bastion.UnitManager['target']:GetAuras():FindMy(SunfireAura):GetRemainingTime() <= 5.4) and
Bastion.UnitManager['target']:IsHostile() and
Bastion.UnitManager['target']:IsAffectingCombat() and Player:GetPP() >= 25
end):SetTarget(Bastion.UnitManager['target'])
)
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)
Innervate:CastableIf(function(self)
return self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() and Player:IsAffectingCombat()
and Player:GetPP() <= 60
end):SetTarget(Player)
)
DefaultAPL:AddSpell(
Sunfire:CastableIf(function(self)
return Target:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling()
and Player:CanSee(Target) and
(
not Target:GetAuras():FindMy(SunfireAura):IsUp() or
Target:GetAuras():FindMy(SunfireAura):GetRemainingTime() <= 5.4) and
Target:IsHostile() and
Target:IsAffectingCombat() and Player:GetPP() >= 25
end):SetTarget(Target)
TravelForm:CastableIf(function(self)
return self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() and not Player:IsAffectingCombat() and not IsMounted()
and Player:IsMoving() and not Player:GetAuras():FindMy(TravelForm):IsUp() and not Player:IsIndoors()
end):SetTarget(Player)
)
DefaultAPL:AddSpell(
CatForm:CastableIf(function(self)
return self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() and not Player:IsAffectingCombat() and not IsMounted()
and Player:IsMoving() and not Player:GetAuras():FindMy(CatForm):IsUp() and Player:IsIndoors()
end):SetTarget(Player)
)
DamageAPL:AddSpell(
Moonfire:CastableIf(function(self)
return Target:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling()
and Player:CanSee(Target) and
return Bastion.UnitManager['target']:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling()
and Player:CanSee(Bastion.UnitManager['target']) and
(
not Target:GetAuras():FindMy(MoonfireAura):IsUp() or
Target:GetAuras():FindMy(MoonfireAura):GetRemainingTime() <= 5.4) and
Target:IsHostile() and
Target:IsAffectingCombat() and Player:GetPP() >= 25
end):SetTarget(Target)
not Bastion.UnitManager['target']:GetAuras():FindMy(MoonfireAura):IsUp() or
Bastion.UnitManager['target']:GetAuras():FindMy(MoonfireAura):GetRemainingTime() <= 5.4) and
Bastion.UnitManager['target']:IsHostile() and
Bastion.UnitManager['target']:IsAffectingCombat() and Player:GetPP() >= 25
end):SetTarget(Bastion.UnitManager['target'])
)
DefaultAPL:AddSpell(
DamageAPL: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)
return Bastion.UnitManager['target']:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling()
and Player:CanSee(Bastion.UnitManager['target']) and Bastion.UnitManager['target']:IsHostile() and
Bastion.UnitManager['target']:IsAffectingCombat() and Player:GetPP() >= 25
end):SetTarget(Bastion.UnitManager['target'])
)
DefaultAPL:AddSpell(
DamageAPL: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)
return Bastion.UnitManager['target']:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling()
and Player:CanSee(Bastion.UnitManager['target']) and not Player:IsMoving() and
Bastion.UnitManager['target']:IsHostile() and
Bastion.UnitManager['target']:IsAffectingCombat() and Player:GetPP() >= 25
end):SetTarget(Bastion.UnitManager['target'])
)
RestoModule:Sync(function()
if IsShiftKeyDown() and Player:GetAuras():FindMy(CatForm):IsUp() then
if IsAltKeyDown() and Player:GetAuras():FindMy(MoonkinForm):IsUp() then
return DamageAPL:Execute()
end
DefaultAPL:Execute()
end)
Bastion:Register(RestoModule)
local tab1 =
{
layoutConfig = { padding = { top = 40 } },
rows = {
[1] = { shadpr = { type = 'header', label = 'Open Combat' } },
[2] = { opener = { type = 'dropdown', label = 'Healing', column = 6, order = 1,
options = {
{ text = 'Healing 1', value = 'swp'},
{ text = 'Healing 2', value = 'crash'},
{ text = 'None', value = 'none'},
},
initialValue = myconf:Read('opener', 'shield'),
onValueChanged = function(_, value) myconf:Write('opener', value) end }, },
[3] = { swp1 = { type = 'checkbox', label = 'Spread SWP', column = 6, order = 1,
initialValue = myconf:Read('swpspread', false),
onValueChanged = function(_, flag) myconf:Write('swpspread', flag) end },
swp2 = { type = 'slider', label = 'Max Targets', column = 6, order = 2,
min = 1, max = 10, precision = 0,
initialValue = myconf:Read('swptargets', 3),
onValueChanged = function(_, value) myconf:Write('swptargets', value) end }, },
[4] = { shadpr = { type = 'header', label = 'Defensives' } },
[5] = { shield1 = { type = 'checkbox', label = 'Power Word: Shield', column = 6, order = 1,
initialValue = myconf:Read('pws', false),
onValueChanged = function(_, flag) myconf:Write('pws', flag) end },
shield2 = { type = 'slider', label = 'Player Health', column = 6, order = 2,
min = 1, max = 100, precision = 0,
initialValue = myconf:Read('pwspercent', 35),
onValueChanged = function(_, value) myconf:Write('pwspercent', value) end }, },
[6] = { dispersion1 = { type = 'checkbox', label = 'Dispersion', column = 6, order = 1,
initialValue = myconf:Read('dispersion', false),
onValueChanged = function(_, flag) myconf:Write('dispersion', flag) end },
dispersion2 = { type = 'slider', label = 'Player Health', column = 6, order = 2,
min = 1, max = 100, precision = 0,
initialValue = myconf:Read('dispersionpercent', 35),
onValueChanged = function(_, value) myconf:Write('dispersionpercent', value) end }, },
[7] = { shadpr = { type = 'header', label = 'Interrupts' } },
[8] = { silence = { type = 'checkbox', label = 'Silence on CD', column = 6, order = 1,
initialValue = myconf:Read('silence', false),
onValueChanged = function(_, flag) myconf:Write('silence', flag) end },
horror = { type = 'checkbox', label = 'Psychic Horror on CD', column = 6, order = 2,
initialValue = myconf:Read('horror', false),
onValueChanged = function(_, flag) myconf:Write('horror', flag) end }, },
[9] = { shadpr = { type = 'header', label = 'Purify Disease' } },
[10] = { incombat = { type = 'checkbox', label = 'In Combat', column = 6, order = 1,
initialValue = myconf:Read('purifyic', false),
onValueChanged = function(_, flag) myconf:Write('purifyic', flag) end },
outcombat = { type = 'checkbox', label = 'Out of Combat', column = 6, order = 2,
initialValue = myconf:Read('purifyooc', false),
onValueChanged = function(_, flag) myconf:Write('purifyooc', flag) end }, },
[11] = { shadpr = { type = 'header', label = 'Dispel Magic' } },
[12] = { incombat = { type = 'checkbox', label = 'In Combat', column = 12, order = 1,
initialValue = myconf:Read('dispelic', false),
onValueChanged = function(_, flag) myconf:Write('dispelic', flag) end }, },
[13] = { shadpr = { type = 'header', label = 'Dispel Delay Time' } },
[14] = { delay = { type = 'slider', label = 'In seconds', column = 6, order = 1,
min = 0.5, max = 2, precision = 1,
initialValue = myconf:Read('dispeldelay', 1),
onValueChanged = function(_, value) myconf:Write('dispeldelay', value) end }, },
},
}
local tab2 =
{
layoutConfig = { padding = { top = 40 } },
rows = {
[1] = { shadpr = { type = 'header', label = 'Player Healing' } },
[2] = { incombat = { type = 'checkbox', label = 'In Combat Healing', column = 6, order = 1,
initialValue = myconf:Read('playericheal', false),
onValueChanged = function(_, flag) myconf:Write('playericheal', flag) end },
outcombat = { type = 'checkbox', label = 'Out of Combat Healing', column = 6, order = 2,
initialValue = myconf:Read('playeroocheal', false),
onValueChanged = function(_, flag) myconf:Write('playeroocheal', flag) end }, },
[3] = { shadowmend1 = { type = 'checkbox', label = 'Shadow Mend', column = 6, order = 1,
initialValue = myconf:Read('shadowmend', false),
onValueChanged = function(_, flag) myconf:Write('shadowmend', flag) end },
shadowmend2 = { type = 'slider', label = 'Player Health', column = 6, order = 2,
min = 1, max = 100, precision = 0,
initialValue = myconf:Read('shadowmendpercent', 35),
onValueChanged = function(_, value) myconf:Write('shadowmendpercent', value) end }, },
},
}
local restodruidconfig = {
layoutConfig = { padding = { top = 30 } },
rows = {
[1] = {
container = {
type = 'tab',
fullSize = true,
tabs = {
{
name = 'player',
title = 'Player Settings',
layout = tab1
},
{
name = 'group',
title = 'Healing',
layout = tab2
}
},
}
},
},
}
Bastion.settingstemplate(restodruidconfig, 'Resto Druid', 400, 600, 1.00, 1.00, 1.00) --, 0.00, 0.44, 0.87, 'enhsha') --Title of Settings Frame, Width, Height, ClassRGB, Rotation Name
-- Class colours
-- Death Knight 0.77 0.12 0.23 Red
-- Demon Hunter 0.64 0.19 0.79 Dark Magenta
-- Druid 1.00 0.49 0.04 Orange
-- Evoker 0.20 0.58 0.50 Dark Emerald
-- Hunter 0.67 0.83 0.45 Green
-- Mage 0.25 0.78 0.92 Light Blue
-- Monk 0.00 1.00 0.60 Spring Green
-- Paladin 0.96 0.55 0.73 Pink
-- Priest 1.00 1.00 1.00 White
-- Rogue 1.00 0.96 0.41 Yellow
-- Shaman 0.00 0.44 0.87 Blue
-- Warlock 0.53 0.53 0.93 Purple
-- Warrior 0.78 0.61 0.43 Tan

@ -1,7 +1,5 @@
local Tinkr, Bastion = ...
Tinkr:require("scripts.bastion.ui", Bastion)
local ShadowModule = Bastion.Module:New('shadow')
local Evaluator = Tinkr.Util.Evaluator
local Player = Bastion.UnitManager:Get('player')
@ -122,13 +120,13 @@ local usepwf = myconf:Read('pwf')
local useshadowform = myconf:Read('shadowform')
RestingAPL:AddSpell(
PowerWordFortitude:CastableIf(function(self)
return usepwf == 'yes' and self:IsKnownAndUsable() and
return usepwf and self:IsKnownAndUsable() and
not Player:IsCastingOrChanneling() and not Player:GetAuras():FindMy(PowerWordFortitude):IsUp() and not IsMounted()
end):SetTarget(Player)
)
RestingAPL:AddSpell(
Shadowform:CastableIf(function(self)
return useshadowform == 'yes' and self:IsKnownAndUsable() and
return useshadowform and self:IsKnownAndUsable() and
not Player:IsCastingOrChanneling() and not Player:GetAuras():FindMy(Shadowform):IsUp() and not IsMounted()
end):SetTarget(Player)
)
@ -289,7 +287,7 @@ local tab1 =
{
layoutConfig = { padding = { top = 40 } },
rows = {
[1] = { shadpr = { type = 'header', label = 'Open Combat' } },
[1] = { shadpr = { type = 'label', label = 'Open Combat' } },
[2] = { opener = { type = 'dropdown', label = 'Opener', column = 6, order = 1,
options = {
@ -300,18 +298,19 @@ local tab1 =
initialValue = myconf:Read('opener', 'shield'),
onValueChanged = function(_, value) myconf:Write('opener', value) end }, },
[3] = { swp1 = { type = 'checkbox', label = 'Spread SWP', column = 6, order = 1,
initialValue = myconf:Read('swpspread', false),
onValueChanged = function(_, flag) myconf:Write('swpspread', flag) end },
[3] = { shadpr = { type = 'label', label = 'Buffs' } },
[4] = { pwf = { type = 'checkbox', label = 'Power Word: Fortitude', column = 6, order = 1,
initialValue = myconf:Read('pwf', false),
onValueChanged = function(_, flag) myconf:Write('pwf', flag) end },
swp2 = { type = 'slider', label = 'Max Targets', column = 6, order = 2,
min = 1, max = 10, precision = 0,
initialValue = myconf:Read('swptargets', 3),
onValueChanged = function(_, value) myconf:Write('swptargets', value) end }, },
shadform = { type = 'checkbox', label = 'Shadowform', column = 6, order = 2,
initialValue = myconf:Read('shadowform', false),
onValueChanged = function(_, flag) myconf:Write('shadowform', flag) end }, },
[4] = { shadpr = { type = 'header', label = 'Defensives' } },
[5] = { shadpr = { type = 'header', label = 'Defensives' } },
[5] = { shield1 = { type = 'checkbox', label = 'Power Word: Shield', column = 6, order = 1,
[6] = { shield1 = { type = 'checkbox', label = 'Power Word: Shield', column = 6, order = 1,
initialValue = myconf:Read('pws', false),
onValueChanged = function(_, flag) myconf:Write('pws', flag) end },
@ -320,7 +319,7 @@ local tab1 =
initialValue = myconf:Read('pwspercent', 35),
onValueChanged = function(_, value) myconf:Write('pwspercent', value) end }, },
[6] = { dispersion1 = { type = 'checkbox', label = 'Dispersion', column = 6, order = 1,
[7] = { dispersion1 = { type = 'checkbox', label = 'Dispersion', column = 6, order = 1,
initialValue = myconf:Read('dispersion', false),
onValueChanged = function(_, flag) myconf:Write('dispersion', flag) end },
@ -329,9 +328,9 @@ local tab1 =
initialValue = myconf:Read('dispersionpercent', 35),
onValueChanged = function(_, value) myconf:Write('dispersionpercent', value) end }, },
[7] = { shadpr = { type = 'header', label = 'Interrupts' } },
[8] = { shadpr = { type = 'header', label = 'Interrupts' } },
[8] = { silence = { type = 'checkbox', label = 'Silence on CD', column = 6, order = 1,
[9] = { silence = { type = 'checkbox', label = 'Silence on CD', column = 6, order = 1,
initialValue = myconf:Read('silence', false),
onValueChanged = function(_, flag) myconf:Write('silence', flag) end },
@ -339,9 +338,9 @@ local tab1 =
initialValue = myconf:Read('horror', false),
onValueChanged = function(_, flag) myconf:Write('horror', flag) end }, },
[9] = { shadpr = { type = 'header', label = 'Purify Disease' } },
[10] = { shadpr = { type = 'header', label = 'Purify Disease' } },
[10] = { incombat = { type = 'checkbox', label = 'In Combat', column = 6, order = 1,
[11] = { incombat = { type = 'checkbox', label = 'In Combat', column = 6, order = 1,
initialValue = myconf:Read('purifyic', false),
onValueChanged = function(_, flag) myconf:Write('purifyic', flag) end },
@ -349,15 +348,15 @@ local tab1 =
initialValue = myconf:Read('purifyooc', false),
onValueChanged = function(_, flag) myconf:Write('purifyooc', flag) end }, },
[11] = { shadpr = { type = 'header', label = 'Dispel Magic' } },
[12] = { shadpr = { type = 'header', label = 'Dispel Magic' } },
[12] = { incombat = { type = 'checkbox', label = 'In Combat', column = 12, order = 1,
[13] = { incombat = { type = 'checkbox', label = 'In Combat', column = 12, order = 1,
initialValue = myconf:Read('dispelic', false),
onValueChanged = function(_, flag) myconf:Write('dispelic', flag) end }, },
[13] = { shadpr = { type = 'header', label = 'Dispel Delay Time' } },
[14] = { shadpr = { type = 'header', label = 'Dispel Delay Time' } },
[14] = { delay = { type = 'slider', label = 'In seconds', column = 6, order = 1,
[15] = { delay = { type = 'slider', label = 'In seconds', column = 6, order = 1,
min = 0.5, max = 2, precision = 1,
initialValue = myconf:Read('dispeldelay', 1),
onValueChanged = function(_, value) myconf:Write('dispeldelay', value) end }, },
@ -406,7 +405,7 @@ local shadpriestconfig = {
},
{
name = 'group',
title = 'Healing',
title = 'Placeholder',
layout = tab2
}
},
@ -414,4 +413,19 @@ local shadpriestconfig = {
},
},
}
Bastion.setupsettingsframe(shadpriestconfig, 'Rex Shadow Priest', 400, 600, 1.00, 1.00, 1.00) --, 0.00, 0.44, 0.87, 'enhsha') --Title of Settings Frame, Width, Height, ClassRGB, Rotation Name
Bastion.settingstemplate(shadpriestconfig, 'Shadow Priest', 400, 600, 1.00, 1.00, 1.00) --, 0.00, 0.44, 0.87, 'enhsha') --Title of Settings Frame, Width, Height, ClassRGB, Rotation Name
-- Class colours
-- Death Knight 0.77 0.12 0.23 Red
-- Demon Hunter 0.64 0.19 0.79 Dark Magenta
-- Druid 1.00 0.49 0.04 Orange
-- Evoker 0.20 0.58 0.50 Dark Emerald
-- Hunter 0.67 0.83 0.45 Green
-- Mage 0.25 0.78 0.92 Light Blue
-- Monk 0.00 1.00 0.60 Spring Green
-- Paladin 0.96 0.55 0.73 Pink
-- Priest 1.00 1.00 1.00 White
-- Rogue 1.00 0.96 0.41 Yellow
-- Shaman 0.00 0.44 0.87 Blue
-- Warlock 0.53 0.53 0.93 Purple
-- Warrior 0.78 0.61 0.43 Tan

@ -775,7 +775,6 @@ 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 DeviousStratagem = Bastion.SpellBook:GetSpell(193531)
local SkullAndCrossbones = Bastion.SpellBook:GetSpell(199603)
local ShadowFocus = Bastion.SpellBook:GetSpell(108209)
local BuriedTreasure = Bastion.SpellBook:GetSpell(199600)
@ -844,8 +843,7 @@ local FindWeakness = Bastion.SpellBook:GetSpell(91023)
local ImprovedShurikenStorm = Bastion.SpellBook:GetSpell(319951)
local RefreshingHealingPotion = Bastion.ItemBook:GetItem(191380)
local ElementalPotionOfPower = Bastion.ItemBook:GetItem(191389)
local IrideusFragment = Bastion.ItemBook:GetItem(193743)
local Healthstone = Bastion.ItemBook:GetItem(5512)
local WindscarWhetstone = Bastion.ItemBook:GetItem(137486)
@ -999,38 +997,6 @@ local FinishAPL = Bastion.APL:New('finish')
local BuildAPL = Bastion.APL:New('build')
local ItemsAPL = Bastion.APL:New('items')
ItemsAPL:AddItem(
Healthstone:UsableIf(function(self)
return self:IsEquippedAndUsable() and
not Player:IsCastingOrChanneling() and
Player:GetHealthPercent() < 40
end):SetTarget(Player)
)
ItemsAPL:AddItem(
RefreshingHealingPotion:UsableIf(function(self)
return self:IsEquippedAndUsable() and
not Player:IsCastingOrChanneling() and
Player:GetHealthPercent() < 40
end):SetTarget(Player)
)
ItemsAPL:AddSpell(
TricksOfTheTrade:CastableIf(function(self)
return Tank:Exists() and self:IsKnownAndUsable() and
not Player:IsCastingOrChanneling() and
Player:IsTanking(Target)
end):SetTarget(Tank)
)
ItemsAPL:AddSpell(
Evasion:CastableIf(function(self)
return self:IsKnownAndUsable() and
not Player:IsCastingOrChanneling() and
Player:GetHealthPercent() < 40
end):SetTarget(Player)
)
ItemsAPL:AddItem(
IrideusFragment:UsableIf(function(self)
return self:IsEquippedAndUsable() and
@ -1038,13 +1004,6 @@ ItemsAPL:AddItem(
end):SetTarget(Player)
)
ItemsAPL:AddItem(
ElementalPotionOfPower:UsableIf(function(self)
return self:IsEquippedAndUsable() and
not Player:IsCastingOrChanneling() and (Player:GetMeleeAttackers() > 2 or Target:IsBoss())
end):SetTarget(Player)
)
ItemsAPL:AddItem(
WindscarWhetstone:UsableIf(function(self)
return Target:Exists() and Player:InMelee(Target) and self:IsEquippedAndUsable() and
@ -1110,7 +1069,7 @@ DefaultAPL:AddVariable(
'snd_condition',
function()
return Player:GetAuras():FindMy(SliceAndDice):IsUp() or
Player:GetEnemies(10) >= ConsumeCPMax()
Player:GetEnemies(10) >= Player:GetComboPointsMax()
end
)
@ -1207,7 +1166,7 @@ DefaultAPL:AddAPL(
DefaultAPL:AddSpell(
SliceAndDice:CastableIf(
function(self)
return self:IsKnownAndUsable() and Player:GetEnemies(10) < ConsumeCPMax() and
return self:IsKnownAndUsable() and Player:GetEnemies(10) < Player:GetComboPointsMax() and
Player:GetAuras():FindMy(SliceAndDice):GetRemainingTime() < Player:GetGCD() and
Player:GetAuras():FindMy(SliceAndDice):GetRemainingTime() > 6 and
Player:GetComboPoints() >= 4
@ -1258,7 +1217,7 @@ DefaultAPL:AddAPL(
DefaultAPL:AddAPL(
FinishAPL,
function()
return DefaultAPL:GetVariable('effective_combo_points') >= ConsumeCPMax()
return DefaultAPL:GetVariable('effective_combo_points') >= Player:GetComboPointsMax()
end
)
@ -1346,9 +1305,9 @@ BuildAPL:AddSpell(
BuildAPL:AddVariable(
'anima_helper',
function()
return not EchoingReprimand:IsKnown() or ((not (DefaultAPL:GetVariable('is_next_cp_animacharged') and
return not EchoingReprimand:IsKnown() or (not (DefaultAPL:GetVariable('is_next_cp_animacharged') and
(Player:GetTimeToShurikenTornado(3) < 0.5 or Player:GetTimeToShurikenTornado(4) < 1) and
Player:GetPower() < 60)))
Player:GetPower() < 60))
end
)
@ -1388,8 +1347,7 @@ CDsAPL:AddSpell(
CDsAPL:AddSpell(
SymbolsOfDeath:CastableIf(
function(self)
return Player:IsAffectingCombat() and self:IsKnownAndUsable() and
Player:GetAuras():FindMy(ShurikenTornado):IsUp() and
return self:IsKnownAndUsable() and Player:GetAuras():FindMy(ShurikenTornado):IsUp() and
Player:GetAuras():FindMy(ShurikenTornado):GetRemainingTime() <= 3.5
end
):SetTarget(Player)
@ -1592,16 +1550,6 @@ FinishAPL:AddVariable(
end
)
-- return ( cp + 1 ) * p()->buffs.slice_and_dice->data().duration();
function GetTriggeredDuration()
return (Player:GetComboPoints() + 1) * 6
end
-- return p()->buffs.slice_and_dice->remains() < get_triggered_duration( as<int>( p()->current_effective_cp( false ) ) ) * 0.3;
function Refreshable(aura, target)
return target:GetAuras():FindMy(aura):GetRemainingTime() < GetTriggeredDuration() * 0.3
end
-- actions.finish+=/slice_and_dice,if=!variable.premed_snd_condition&spell_targets.shuriken_storm<6&!buff.shadow_dance.up&buff.slice_and_dice.remains<fight_remains&refreshable
FinishAPL:AddSpell(
SliceAndDice:CastableIf(
@ -1610,7 +1558,7 @@ FinishAPL:AddSpell(
Player:GetEnemies(10) < 6 and
not Player:GetAuras():FindMy(ShadowDanceAura):IsUp() and
Player:GetAuras():FindMy(SliceAndDice):GetRemainingTime() < Target:TimeToDie() and
Refreshable(SliceAndDice, Player)
Player:GetAuras():FindMy(SliceAndDice):GetRemainingTime() < 6
end
):SetTarget(Player)
)
@ -1649,7 +1597,7 @@ FinishAPL:AddSpell(
(not DefaultAPL:GetVariable('skip_rupture') or
DefaultAPL:GetVariable('priority_rotation')) and
Target:TimeToDie() - Target:GetAuras():FindMy(Rupture):GetRemainingTime() > 6 and
Refreshable(Rupture, Target)
Target:GetAuras():FindMy(Rupture):GetRemainingTime() < 6
end
):SetTarget(Target)
)
@ -1706,7 +1654,7 @@ FinishAPL:AddSpell(
not DefaultAPL:GetVariable('priority_rotation') and
Player:GetEnemies(10) >= 2 and
RuptureTarget:TimeToDie() >= (2 * Player:GetComboPoints()) and
Refreshable(Rupture, RuptureTarget)
RuptureTarget:GetAuras():FindMy(Rupture):GetRemainingTime() < 6
end
):SetTarget(RuptureTarget)
)
@ -1913,25 +1861,11 @@ StealthedAPL:AddSpell(
):SetTarget(Target)
)
--[[
double consume_cp_max() const
{
return COMBO_POINT_MAX + as<double>( talent.rogue.deeper_stratagem->effectN( 2 ).base_value() +
talent.outlaw.devious_stratagem->effectN( 2 ).base_value() +
talent.subtlety.secret_stratagem->effectN( 2 ).base_value() );
}
]]
function ConsumeCPMax()
return 5 + (DeeperStratagem:IsKnownAndUsable() and 1 or 0) + (DeviousStratagem:IsKnownAndUsable() and 1 or 0) +
(SecretStratagem:IsKnownAndUsable() and 1 or 0)
end
-- actions.stealthed+=/call_action_list,name=finish,if=variable.effective_combo_points>=cp_max_spend
StealthedAPL:AddAPL(
FinishAPL,
function(self)
return DefaultAPL:GetVariable('effective_combo_points') >= ConsumeCPMax()
return DefaultAPL:GetVariable('effective_combo_points') >= Player:GetComboPointsMax()
end
)

@ -1,5 +1,4 @@
-- Create an APL trait for the APL class
---@class APLTrait
local APLTrait = {}
APLTrait.__index = APLTrait
@ -30,7 +29,6 @@ function APLTrait:__tostring()
end
-- Create an APL actor for the APL class
---@class APLActor
local APLActor = {}
APLActor.__index = APLActor
@ -118,7 +116,7 @@ function APLActor:__tostring()
end
-- APL (Attack priority list) class
---@class APL
local APL = {}
APL.__index = APL

@ -1,7 +1,6 @@
local Tinkr, Bastion = ...
-- Create a new Aura class
---@class Aura
local Aura = {}
function Aura:__index(k)
@ -18,19 +17,6 @@ function Aura:__index(k)
return response
end
-- Equals
function Aura:__eq(other)
if getmetatable(other) == Aura then
return self:GetSpell():GetID() == other:GetSpell():GetID()
end
if getmetatable(other) == Bastion.Spell then
return self:GetSpell():GetID() == other:GetID()
end
return false
end
function Aura:__tostring()
return "Bastion.__Aura(" .. self:GetSpell():GetID() .. ")" .. " - " .. (self:GetName() or "''")
end

@ -1,7 +1,6 @@
local Tinkr, Bastion = ...
-- Create a new AuraTable class
---@class AuraTable
local AuraTable = {}
AuraTable.__index = AuraTable
@ -197,7 +196,6 @@ function AuraTable:Clear()
end
-- Check if the unit has a specific aura
---@return Aura
function AuraTable:Find(spell)
local auras = self:GetUnitAuras()
local aurasub = auras[spell:GetID()]
@ -219,7 +217,6 @@ function AuraTable:Find(spell)
return Bastion.Aura:New()
end
---@return Aura
function AuraTable:FindMy(spell)
local aurasub = self.playerAuras[spell:GetID()]
@ -241,7 +238,6 @@ function AuraTable:FindMy(spell)
end
-- Find any
---@return Aura
function AuraTable:FindAny(spell)
local a = self:Find(spell)
if a:IsValid() then

@ -1,4 +1,3 @@
---@class Cache
local Cache = {}
Cache.__index = Cache

@ -1,14 +1,10 @@
local Tinkr, Bastion = ...
-- Define a Cacheable class
---@class Cacheable
local Cacheable = {
cache = nil,
callback = nil,
value = nil,
__eq = function(self, other)
return self.value.__eq(self.value, other)
end
value = nil
}
-- On index check the cache to be valid and return the value or reconstruct the value and return it

@ -1,7 +1,6 @@
local Tinkr, Bastion = ...
-- Create a new Class class
---@class Class
local Class = {}
function Class:__index(k)

@ -1,8 +1,6 @@
---@class ClassMagic
local ClassMagic = {}
ClassMagic.__index = ClassMagic
---@return any
function ClassMagic:Resolve(Class, key)
if Class[key] or Class[key] == false then
return Class[key]

@ -1,5 +1,5 @@
-- Create a wow command handler class
---@class Command
local Command = {}
Command.__index = Command

@ -1,5 +1,5 @@
-- Create an EventManager class
---@class EventManager
local EventManager = {
events = {},
eventHandlers = {},

@ -1,13 +1,10 @@
local Tinkr, Bastion = ...
--local Common = Tinkr.Common
--local Exports = Tinkr:require('Routine.Modules.Exports')
local Command = Tinkr.Util.Commands:New('rex')
--local OM = Tinkr.Util.ObjectManager
--local Command = Bastion.Command:New('bastion')
--UI Co-ordinates
local GUI = { points = {"CENTER"}, }
local SETTINGS = { points = {"CENTER"}, }
local ESP = { points = {"CENTER"}, }
local BUTTONS = { points = {"CENTER"}, }
Tinkr:require('scripts.bastion.libs.LibStub.LibStub', Bastion)
@ -38,28 +35,14 @@ Tinkr:require("scripts.bastion.libs.StdUi.widgets.Tab", Bastion)
Tinkr:require("scripts.bastion.libs.StdUi.widgets.Spell", Bastion)
Tinkr:require("scripts.bastion.libs.StdUi.widgets.ContextMenu", Bastion)
-- Class colours
-- Death Knight 0.77 0.12 0.23 Red
-- Demon Hunter 0.64 0.19 0.79 Dark Magenta
-- Druid 1.00 0.49 0.04 Orange
-- Hunter 0.67 0.83 0.45 Green
-- Mage 0.25 0.78 0.92 Light Blue
-- Monk 0.00 1.00 0.60 Spring Green
-- Paladin 0.96 0.55 0.73 Pink
-- Priest 1.00 1.00 1.00 White
-- Rogue 1.00 0.96 0.41 Yellow
-- Shaman 0.00 0.44 0.87 Blue
-- Warlock 0.53 0.53 0.93 Purple
-- Warrior 0.78 0.61 0.43 Tan
--Initial Frame Setup
function Bastion.setupsettingsframe(config, title, width, height, newr, newg, newb)
function Bastion.settingstemplate(config, title, width, height, newr, newg, newb)
local StdUi = LibStub('StdUi'):NewInstance()
StdUi.config = {
font = {
family = 'GameFontNormal',
size = 10,
titleSize = 12,
titleSize = 10,
effect = 'NONE',
strata = 'OVERLAY',
color = {
@ -100,7 +83,6 @@ function Bastion.setupsettingsframe(config, title, width, height, newr, newg, ne
local settingsframe = StdUi:Window(UIParent, width, height, title)
settingsframe:Hide()
settingsframe:SetPoint(SETTINGS.points[1], SETTINGS.points[2], SETTINGS.points[3], SETTINGS.points[4], SETTINGS.points[5])
--settingsframe:SetFont(StdUi.config.font.family,StdUi.config.font.titleSize)
StdUi:BuildWindow(settingsframe, config)
StdUi:EasyLayout(settingsframe, { padding = { top = 40 } })
settingsframe:SetScript("OnMouseUp", function(self)
@ -109,12 +91,9 @@ function Bastion.setupsettingsframe(config, title, width, height, newr, newg, ne
SETTINGS.points = {a, nil, c, d, e}
end)
--Main Menu (Settings, Enable Rotation, ESP, Buttons)
--Main Menu (Settings, Enable Rotation, etc)
_G.buttons = {}
local enabled = false
local espenabled = false
local espunitsenabled = false
local espobjectsenabled = false
buttons.aoeenabled = false
buttons.buffsenabled = false
buttons.cooldownsenabled = false
@ -122,10 +101,9 @@ function Bastion.setupsettingsframe(config, title, width, height, newr, newg, ne
buttons.dpsenabled = false
buttons.healenabled = false
buttons.rotationenabled = false
local mainmenu = StdUi:Window(nil, 150, 310, title)
_G.mainmenu = StdUi:Window(nil, 150, 280, title)
mainmenu:Hide()
mainmenu:SetPoint(GUI.points[1], GUI.points[2], GUI.points[3], GUI.points[4], GUI.points[5])
--mainmenu:SetFont(StdUi.config.font.family,StdUi.config.font.titleSize)
mainmenu:SetUserPlaced(true)
local aoebutton = StdUi:HighlightButton(mainmenu, 130, 20, 'AOE')
StdUi:GlueTop(aoebutton, mainmenu, 10, -40, 'LEFT')
@ -141,32 +119,13 @@ function Bastion.setupsettingsframe(config, title, width, height, newr, newg, ne
StdUi:GlueTop(healbutton, dpsbutton, 0, -30, 'LEFT')
local enablebutton = StdUi:HighlightButton(mainmenu, 130, 20, 'Rotation')
StdUi:GlueTop(enablebutton, healbutton, 0, -30, 'LEFT')
local espbutton = StdUi:Button(mainmenu, 130, 20, 'Open ESP')
StdUi:GlueTop(espbutton, enablebutton, 0, -30, 'LEFT')
local settingsbutton = StdUi:Button(mainmenu, 130, 20, 'Settings')
StdUi:GlueTop(settingsbutton, espbutton, 0, -30, 'LEFT')
StdUi:GlueTop(settingsbutton, enablebutton, 0, -30, 'LEFT')
mainmenu:SetScript("OnMouseUp", function(self)
self:StopMovingOrSizing()
local a,b,c,d,e = self:GetPoint()
GUI.points = {a, nil, c, d, e}
end)
--ESP Menu
local espmenu = StdUi:Window(nil, 200, 140, 'ESP Settings')
espmenu:Hide()
espmenu:SetPoint(ESP.points[1], ESP.points[2], ESP.points[3], ESP.points[4], ESP.points[5])
--espmenu:SetFont(StdUi.config.font.family,StdUi.config.font.titleSize)
espmenu:SetUserPlaced(true)
local enableespcheck = StdUi:Button(espmenu, 180, 20, 'Enable/Disable ESP');
StdUi:GlueTop(enableespcheck, espmenu, 10, -40, 'LEFT');
local espunitscheck = StdUi:Button(espmenu, 180, 20, 'Show Units');
StdUi:GlueTop(espunitscheck, enableespcheck, 0, -30, 'LEFT');
local espobjectscheck = StdUi:Button(espmenu, 180, 20, 'Show Objects');
StdUi:GlueTop(espobjectscheck, espunitscheck, 0, -30, 'LEFT');
espmenu:SetScript("OnMouseUp", function(self)
self:StopMovingOrSizing()
local a,b,c,d,e = self:GetPoint()
ESP.points = {a, nil, c, d, e}
end)
--Open/Hide Settings Window OnClick
settingsbutton:SetScript('OnClick', function ()
if settingsframe:IsShown() then
@ -175,48 +134,6 @@ function Bastion.setupsettingsframe(config, title, width, height, newr, newg, ne
settingsframe:Show()
end
end)
--Enable/Disable Rotation OnClick
enablebutton:SetScript('OnClick', function ()
if enabled == false then
Eval('RunMacroText("/bastion toggle")', 'bastion')
enabled = true
elseif enabled == true then
Eval('RunMacroText("/bastion toggle")', 'bastion')
enabled = false
end
end)
--Open/Hide ESP Window OnClick
espbutton:SetScript('OnClick', function ()
if espmenu:IsShown() then
espmenu:Hide()
else
espmenu:Show()
end
end)
--Enable/Disable ESP Draw OnClick
enableespcheck:SetScript('OnClick', function ()
if espenabled == false then
rexesp('enable', nil, nil)
espenabled = true
elseif espenabled == true then
rexesp('disable', nil, nil)
espenabled = false
end
end)
--Enable/Disable ESP Units OnClick
espunitscheck:SetScript('OnClick', function ()
if espunitsenabled == false then
rexesp(nil, 'unitenable', nil)
espunitsenabled = true
end
end)
--Enable/Disable ESP Objects OnClick
espobjectscheck:SetScript('OnClick', function ()
if espobjectsenabled == false then
rexesp(nil, nil, 'objectenable')
espobjectsenabled = true
end
end)
--Enable/Disable AOE Button OnClick
aoebutton:SetScript('OnClick', function()
if buttons.aoeenabled == false then
@ -289,13 +206,13 @@ function Bastion.setupsettingsframe(config, title, width, height, newr, newg, ne
buttons.rotationenabled = false
end
end)
--Toggle Main Menu
Command:Register({'open'}, function()
if mainmenu:IsShown() then
mainmenu:Hide()
else
mainmenu:Show()
end
end)
-- --Toggle Main Menu
-- Command:Register('interface', 'Opens interface menu', function()
-- if mainmenu:IsShown() then
-- mainmenu:Hide()
-- else
-- mainmenu:Show()
-- end
-- end)
end

@ -1,7 +1,6 @@
local Tinkr, Bastion = ...
-- Create a new Item class
---@class Item
local Item = {
UsableIfFunc = false,
PreUseFunc = false,
@ -30,11 +29,6 @@ function Item:__index(k)
return response
end
-- Equals
function Item:__eq(other)
return self:GetID() == other:GetID()
end
-- tostring
function Item:__tostring()
return "Bastion.__Item(" .. self:GetID() .. ")" .. " - " .. self:GetName()
@ -176,21 +170,18 @@ function Item:Usable()
end
-- Set a script to check if the Item is Usable
---@param func fun(self:Item):boolean
function Item:UsableIf(func)
self.UsableIfFunc = func
return self
end
-- Set a script to run before the Item has been Use
---@param func fun(self:Item)
function Item:PreUse(func)
self.PreUseFunc = func
return self
end
-- Set a script to run after the Item has been Use
---@param func fun(self:Item)
function Item:OnUse(func)
self.OnUseFunc = func
return self
@ -287,8 +278,6 @@ function Item:GetChargesRemaining()
end
-- Create a condition for the Item
---@param name string
---@param func fun(self:Item)
function Item:Condition(name, func)
self.conditions[name] = {
func = func

@ -1,7 +1,6 @@
local Tinkr, Bastion = ...
-- Create a new ItemBook class
---@class ItemBook
local ItemBook = {}
ItemBook.__index = ItemBook
@ -13,7 +12,6 @@ function ItemBook:New()
end
-- Get a spell from the ItemBook
---@return Item
function ItemBook:GetItem(id)
if self.items[id] == nil then
self.items[id] = Bastion.Item:New(id)

@ -1,6 +1,5 @@
local Tinkr, Bastion = ...
---@class List
local List = {}
List.__index = List

@ -1,6 +1,5 @@
-- Create a module class for a bastion module
---@class Module
local Module = {}
Module.__index = Module

@ -1,6 +1,5 @@
local Tinkr, Bastion = ...
---@class MythicPlusUtils
local MythicPlusUtils = {
debuffLogging = false,
random = ''
@ -13,71 +12,117 @@ function MythicPlusUtils:New()
self.random = math.random(1000000, 9999999)
self.kickList = {
-- Algeth'ar Academy
[396812] = true, -- https://www.wowhead.com/spell=396812/mystic-blast
[388392] = true, -- https://www.wowhead.com/spell=388392/monotonous-lecture
[388863] = true, -- https://www.wowhead.com/spell=388863/mana-void
[388862] = true, -- https://www.wowhead.com/spell=388862/surge
[377389] = true, -- https://www.wowhead.com/spell=377389/call-of-the-flock
[388623] = true, -- https://www.wowhead.com/spell=388623/branch-out
[396640] = true, -- https://www.wowhead.com/spell=396640/healing-touch
[387975] = true, -- https://www.wowhead.com/spell=387975/arcane-missiles
[387843] = true, -- https://www.wowhead.com/spell=387843/astral-bomb
[388392] = true, -- Monotonous Lecture
[396812] = true, -- Mystic Blast
[377389] = true, -- Call of the Flock
[396640] = true, -- Healing Touch
[387843] = true, -- Astral Bomb
[387955] = true, -- Celestial Shield
[387910] = true, -- Astral Whirlwind
-- Azure Vault
-- [375602] = true, -- Erratic Growth
[387564] = true, -- Mystic Vapors
-- [386546] = true, -- Waking Bane
[389804] = true, -- Heavy Tome
[377488] = true, -- Icy Bindings
-- Brackenhide
[382249] = true, -- Earth Bolt
[367500] = true, -- Hideous Cackle
[377950] = true, -- Greater Healing Rapids
[385029] = true, -- Screech
[373804] = true, -- Touch of Decay
[381770] = true, -- Gushing Ooze
[374544] = true, -- Burst of Decay
-- Halls of Infusion
[374066] = true, -- Earth Shield
[374339] = true, -- Demoralizing Shout
[374045] = true, -- Expulse
[374080] = true, -- Blasting Gust
[389443] = true, -- Purifying Blast
[395694] = true, -- Elemental Focus
[374563] = true, -- Dazzle
[385141] = true, -- Thunderstorm
[374706] = true, -- Pyretic Burst
[375384] = true, -- Rumbling Earth
[375950] = true, -- Ice Shards
[377348] = true, -- Tidal Divergence
[377402] = true, -- Aqueous Barrier
[387618] = true, -- Infuse
-- Neltharus
[378282] = true, -- Molten Core
[372615] = true, -- Ember Reach
[395427] = true, -- Burning Roar
[372538] = true, -- Melt
[384161] = true, -- Mote of Combustion
[382795] = true, -- Molten Barrier
-- Nokhud
[384365] = true, -- Disruptive Shout
[386024] = true, -- Tempest
[387411] = true, -- Death Bolt Volley
[387606] = true, -- Dominate
[376725] = true, -- Storm Bolt
[384808] = true, -- Guardian Wind
[383823] = true, -- Rally the Clan (CC to interrupt)
[387135] = true, -- Arcing Strike (CC to interrupt)
[373395] = true, -- Bloodcurdling Shout
-- Ruby Life Pools
[373017] = true, -- Roaring Blaze
[392398] = true, -- Crackling Detonation
[392451] = true, -- Flashfire
[385310] = true, -- Lightning Bolt
[375602] = true, -- Erratic Growth
-- [386546] = true, -- Waking Bane
-- [387564] = true, -- Mystic Vapors
[373932] = true, -- Illusionary Bolt
[386546] = true, -- Waking Bane
-- Uldaman
[369675] = true, -- Chain Lightning
[369674] = true, -- Stone Spike
[369823] = true, -- Spiked Carapace
[369603] = true, -- Defensive Bulwark
[369399] = true, -- Stone Bolt
[369400] = true, -- Earthen Ward
-- Court of Stars
[211401] = true, -- https://wowhead.com/spell=211401
[207980] = true, -- https://wowhead.com/spell=207980
[208165] = true, -- https://wowhead.com/spell=208165
[207881] = true, -- https://wowhead.com/spell=207881
[209413] = true, -- https://wowhead.com/spell=209413
[211401] = true, -- Drifting Embers
[211464] = true, -- Fel Detonation
[207980] = true, -- Disintegration Beam
[208165] = true, -- Withering Soul
[207881] = true, -- Infernal Eruption
-- Halls of Valor
[198595] = true, -- https://wowhead.com/spell=198595
[198959] = true, -- https://wowhead.com/spell=198959
[215433] = true, -- https://wowhead.com/spell=215433
[192288] = true, -- https://wowhead.com/spell=192288
[199726] = true, -- https://wowhead.com/spell=199726
[198750] = true, -- https://wowhead.com/spell=198750
-- Ruby Life Pools
[372749] = true, -- https://wowhead.com/spell=372749
[373803] = true, -- https://wowhead.com/spell=373803
[373017] = true, -- https://wowhead.com/spell=373017
[392398] = true, -- https://wowhead.com/spell=392398
[392451] = true, -- https://wowhead.com/spell=392451
[385310] = true, -- https://wowhead.com/spell=385310
[198595] = true, -- Thunderous Bolt
[198959] = true, -- Etch
[192288] = true, -- Searing Light
[199726] = true, -- Unruly Yell
[198750] = true, -- Surge
-- Shadowmoon Burial Grounds
[152818] = true, -- https://wowhead.com/spell=152818
[156776] = true, -- https://wowhead.com/spell=156776
[156722] = true, -- https://wowhead.com/spell=156722
[398206] = true, -- https://wowhead.com/spell=398206
[153524] = true, -- https://wowhead.com/spell=153524
[156718] = true, -- https://wowhead.com/spell=156718
[152818] = true, -- Shadow Mend
[153153] = true, -- Dark Communion (CC to interrupt)
[156776] = true, -- Rending Voidlash
[156722] = true, -- Void Bolt
[398206] = true, -- Death Blast
[156718] = true, -- Necrotic Burst
[153524] = true, -- Plague Spit
-- Temple of the Jade Serpent
[397888] = true, -- https://wowhead.com/spell=397888
[395859] = true, -- https://wowhead.com/spell=395859
[396073] = true, -- https://wowhead.com/spell=396073
[397914] = true, -- https://wowhead.com/spell=397914
-- The Azure Vault
[375602] = true, -- https://wowhead.com/spell=375602
[387564] = true, -- https://wowhead.com/spell=387564
[373932] = true, -- https://wowhead.com/spell=373932
[386546] = true, -- https://wowhead.com/spell=386546
[389804] = true, -- https://wowhead.com/spell=389804
[377488] = true, -- https://wowhead.com/spell=377488
[377503] = true, -- https://wowhead.com/spell=377503
-- NO
[384365] = true, -- https://wowhead.com/spell=384365
[386012] = true, -- https://wowhead.com/spell=386012
[386024] = true, -- https://wowhead.com/spell=386024
[387411] = true, -- https://wowhead.com/spell=387411
[387606] = true, -- https://wowhead.com/spell=387606
[373395] = true, -- https://wowhead.com/spell=373395
[376725] = true, -- https://wowhead.com/spell=376725
[397888] = true, -- Hydrolance
[114646] = true, -- Haunting Gaze
[395859] = true, -- Haunting Scream
[396073] = true, -- Cat Nap
[397914] = true, -- Defiling Mist
[315584] = true
}
Bastion.EventManager:RegisterWoWEvent('UNIT_AURA', function(unit, auras)

@ -1,6 +1,5 @@
-- Create a NotificationsList class
---@class NotificationsList
local NotificationsList = {
notifications = {}
}
@ -12,14 +11,14 @@ function NotificationsList:New()
-- Create a frame for the notifications
self.frame = CreateFrame("Frame", "BastionNotificationsList", UIParent)
self.frame:SetSize(600, 60)
self.frame:SetSize(300, 100)
self.frame:SetPoint("TOP", UIParent, "TOP", 0, -100)
self.frame:SetFrameStrata("HIGH")
-- Remove notifications after 5 seconds
C_Timer.NewTicker(0.1, function()
for i, notification in ipairs(self.notifications) do
if GetTime() - notification.addedAt > notification.duration then
if GetTime() - notification.addedAt > 2 then
notification:Remove()
table.remove(self.notifications, i)
end
@ -30,21 +29,18 @@ function NotificationsList:New()
end
-- Create a notification class for the notifications list (takes icon and text)
---@class Notification
local Notification = {
}
Notification.__index = Notification
-- Constructor
function Notification:New(list, icon, text, duration)
function Notification:New(list, icon, text)
local self = setmetatable({}, Notification)
if not duration then duration = 2 end
-- Create a frame for the notification
self.frame = CreateFrame("Frame", nil, list.frame)
self.frame:SetSize(5, 5)
self.frame:SetPoint("CENTER", list.frame, "CENTER", 0, 0)
self.frame:SetSize(300, 100)
self.frame:SetPoint("TOP", list.frame, "TOP", 0, 0)
self.frame:SetFrameStrata("HIGH")
-- Create a texture for the icon
@ -54,16 +50,12 @@ function Notification:New(list, icon, text, duration)
self.icon:SetTexture(icon)
-- Create a fontstring for the text
self.text = self.frame:CreateFontString(nil, "BACKGROUND", "NumberFontNormal")
self.text:SetPoint("LEFT", self.frame, "LEFT", 32 + 16, 0)
self.text = self.frame:CreateFontString(nil, "BACKGROUND", "GameFontNormal")
self.text:SetPoint("CENTER", self.frame, "CENTER", 10, 0)
self.text:SetText(text)
self.text:SetFont("Fonts\\OpenSans-Bold.ttf", 18)
-- set the frame size to the size of the text + icon
self.frame:SetSize(self.text:GetStringWidth() + 32 + 16, 32)
self.text:SetFont("Fonts\\FRIZQT__.TTF", 14)
self.addedAt = GetTime()
self.duration = duration
self.list = list
return self
@ -83,9 +75,9 @@ function Notification:Remove()
end
-- Add a notification to the list
function NotificationsList:AddNotification(icon, text, duration)
function NotificationsList:AddNotification(icon, text)
-- Create a new notification
local notification = Notification:New(self, icon, text, duration)
local notification = Notification:New(self, icon, text)
-- Add the notification to the list
table.insert(self.notifications, notification)
@ -100,7 +92,7 @@ function NotificationsList:Update()
-- Loop through the notifications
for i, notification in ipairs(self.notifications) do
-- Set the position of the notification
notification.frame:SetPoint("CENTER", self.frame, "CENTER", 0, -42 * (i - 1))
notification.frame:SetPoint("TOP", self.frame, "TOP", 0, -50 * (i - 1))
end
end

@ -1,6 +1,5 @@
local Tinkr, Bastion = ...
---@class ObjectManager
local ObjectManager = {}
ObjectManager.__index = ObjectManager

@ -1,14 +1,10 @@
local Tinkr, Bastion = ...
-- Define a Refreshable class
---@class Refreshable
local Refreshable = {
cache = nil,
callback = nil,
value = nil,
__eq = function(self, other)
return self.value.__eq(self.value, other)
end
value = nil
}
-- On index check the cache to be valid and return the value or reconstruct the value and return it

@ -1,7 +1,6 @@
local Tinkr, Bastion = ...
-- Create a new Spell class
---@class Spell
local Spell = {
CastableIfFunc = false,
PreCastFunc = false,
@ -31,11 +30,6 @@ function Spell:__index(k)
return response
end
-- Equals
function Spell:__eq(other)
return self:GetID() == other:GetID()
end
-- tostring
function Spell:__tostring()
return "Bastion.__Spell(" .. self:GetID() .. ")" .. " - " .. self:GetName()
@ -56,7 +50,6 @@ function Spell:GetID()
end
-- Add post cast func
---@param func fun(self:Spell)
function Spell:PostCast(func)
self.PostCastFunc = func
return self
@ -180,21 +173,18 @@ function Spell:Castable()
end
-- Set a script to check if the spell is castable
---@param func fun(spell:Spell):boolean
function Spell:CastableIf(func)
self.CastableIfFunc = func
return self
end
-- Set a script to run before the spell has been cast
---@param func fun(spell:Spell)
function Spell:PreCast(func)
self.PreCastFunc = func
return self
end
-- Set a script to run after the spell has been cast
---@param func fun(spell:Spell)
function Spell:OnCast(func)
self.OnCastFunc = func
return self

@ -1,12 +1,10 @@
local Tinkr, Bastion = ...
-- Create a new SpellBook class
---@class SpellBook
local SpellBook = {}
SpellBook.__index = SpellBook
-- Constructor
---@return SpellBook
function SpellBook:New()
local self = setmetatable({}, SpellBook)
self.spells = {}
@ -14,7 +12,6 @@ function SpellBook:New()
end
-- Get a spell from the spellbook
---@return Spell
function SpellBook:GetSpell(id)
if self.spells[id] == nil then
self.spells[id] = Bastion.Spell:New(id)
@ -23,7 +20,6 @@ function SpellBook:GetSpell(id)
return self.spells[id]
end
---@return Spell
function SpellBook:GetIfRegistered(id)
return self.spells[id]
end

@ -1,7 +1,6 @@
local Tinkr, Bastion = ...
-- Create a new Timer class
---@class Timer
local Timer = {
startTime = nil,
resetAfterCombat = false,

@ -1,12 +1,9 @@
local Tinkr, Bastion = ...
-- Create a new Unit class
---@class Unit
local Unit = {
cache = nil,
---@type AuraTable
aura_table = nil,
---@type Unit
unit = nil,
last_shadow_techniques = 0,
swings_since_sht = 0,
@ -28,11 +25,6 @@ function Unit:__index(k)
return response
end
-- Equals
function Unit:__eq(other)
return UnitIsUnit(self.unit, other.unit)
end
-- tostring
function Unit:__tostring()
return "Bastion.__Unit(" .. tostring(self.unit) .. ")" .. " - " .. (self:GetName() or '')
@ -224,7 +216,12 @@ end
-- Get if the unit is affecting combat
function Unit:IsAffectingCombat()
return UnitAffectingCombat(self.unit)
return UnitAffectingCombat('player', self.unit)
end
-- Is the unit indoors
function Unit:IsIndoors()
return IsIndoors()
end
-- Get the units class id
@ -234,7 +231,6 @@ function Unit:GetClass()
end
-- Get the units auras
---@return AuraTable
function Unit:GetAuras()
return self.aura_table
end
@ -678,7 +674,7 @@ function Unit:IsStealthed()
local Sepsis = Bastion.SpellBook:GetSpell(328305)
return self:GetAuras():FindAny(Stealth) or self:GetAuras():FindAny(ShadowDance)
return self:GetAuras():FindAny(Stealth) or self:GetAuras():FindAny(ShadowDance)
end
-- Get unit swing timers

@ -48,7 +48,6 @@ local function Validate(token)
end
-- Create a new UnitManager class
---@class UnitManager
local UnitManager = {
units = {},
customUnits = {},
@ -109,7 +108,6 @@ function UnitManager:Validate(token)
end
-- Get or create a unit
---@return Unit
function UnitManager:Get(token)
-- if not Validate(token) then
-- error("UnitManager:Get - Invalid token: " .. token)
@ -147,9 +145,6 @@ function UnitManager:SetObject(unit)
end
-- Create a custom unit and cache it for .5 seconds
---@param token string
---@param cb fun():Unit
---@return Unit
function UnitManager:CreateCustomUnit(token, cb)
local unit = cb()
local cachedUnit = Bastion.Cacheable:New(unit, cb)
@ -180,7 +175,6 @@ function UnitManager:EnumFriends(cb)
end
-- Enum Enemies (object manager)
---@param cb fun(unit: Unit):boolean
function UnitManager:EnumEnemies(cb)
Bastion.ObjectManager.activeEnemies:each(function(unit)
if cb(unit) then

@ -1,6 +1,5 @@
-- Create a Vector3 class
---@class Vector3
local Vector3 = {}
Vector3.__index = Vector3

@ -1,6 +1,5 @@
local Tinkr = ...
---@class Bastion
local Bastion = {
DebugMode = false
}
@ -10,54 +9,31 @@ function Bastion.require(class)
return Tinkr:require("scripts/bastion/src/" .. class .. "/" .. class, Bastion)
end
---@type ClassMagic
Bastion.ClassMagic = Bastion.require("ClassMagic")
---@type List
Bastion.List = Bastion.require("List")
---@type NotificationsList, Notification
Bastion.NotificationsList, Bastion.Notification = Bastion.require("NotificationsList")
---@type Vector3
Bastion.Vector3 = Bastion.require("Vector3")
---@type Command
Bastion.Command = Bastion.require("Command")
---@type Cache
Bastion.Cache = Bastion.require("Cache")
---@type Cacheable
Bastion.Cacheable = Bastion.require("Cacheable")
---@type Refreshable
Bastion.Refreshable = Bastion.require("Refreshable")
---@type Unit
Bastion.Unit = Bastion.require("Unit")
---@type Aura
Bastion.Aura = Bastion.require("Aura")
---@type APL, APLActor, APLTrait
Bastion.APL, Bastion.APLActor, Bastion.APLTrait = Bastion.require("APL")
Bastion.Module = Bastion.require("Module")
---@type UnitManager
Bastion.UnitManager = Bastion.require("UnitManager"):New()
---@type ObjectManager
Bastion.ObjectManager = Bastion.require("ObjectManager"):New()
---@type EventManager
Bastion.EventManager = Bastion.require("EventManager"):New()
---@type Spell
Bastion.Spell = Bastion.require("Spell")
---@type SpellBook
Bastion.SpellBook = Bastion.require("SpellBook"):New()
---@type Item
Bastion.Item = Bastion.require("Item")
---@type ItemBook
Bastion.ItemBook = Bastion.require("ItemBook"):New()
---@type AuraTable
Bastion.AuraTable = Bastion.require("AuraTable")
---@type Class
Bastion.Class = Bastion.require("Class")
---@type Timer
Bastion.Timer = Bastion.require("Timer")
---@type Timer
Bastion.Gui = Bastion.require("Gui")
Bastion.CombatTimer = Bastion.Timer:New('combat')
---@type MythicPlusUtils
Bastion.MythicPlusUtils = Bastion.require("MythicPlusUtils"):New()
---@type NotificationsList
Bastion.Notifications = Bastion.NotificationsList:New()
Bastion.modules = {}
@ -202,11 +178,28 @@ Command:Register('mplus', 'Toggle m+ module on/off', function(args)
Bastion:Print("debuffs")
end)
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
Tinkr:require("scripts/bastion/scripts/" .. file:sub(1, -5), Bastion)
--Toggle Main Menu
Command:Register('interface', 'Opens interface menu', function()
if mainmenu:IsShown() then
mainmenu:Hide()
else
mainmenu:Show()
end
end
end)
-- 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
-- Tinkr:require("scripts/bastion/scripts/" .. file:sub(1, -5), Bastion)
-- end
-- end
if UnitClass('player') == 'Priest' and GetSpecialization() == 3 then
Tinkr:require("scripts/bastion/scripts/shadowpriest", Bastion)
Eval('RunMacroText("/bastion module shadow")', 'bastion')
elseif UnitClass('player') == 'Druid' and GetSpecialization() == 4 then
Tinkr:require("scripts/bastion/scripts/restodruid", Bastion)
Eval('RunMacroText("/bastion module resto_druid")', 'bastion')
end
Loading…
Cancel
Save