local Tinkr, Bastion = ... local ShadowModule = Bastion.Module:New('shadow') local Evaluator = Tinkr.Util.Evaluator local Player = Bastion.UnitManager:Get('player') local None = Bastion.UnitManager:Get('none') local Target = Bastion.UnitManager:Get('target') local myconf = Tinkr.Util.Config:New('shadow_priest') -- for saving variables local ArcaneTorrent = Bastion.SpellBook:GetSpell(232633) local AutoAttack = Bastion.SpellBook:GetSpell(6603) local AngelicFeather = Bastion.SpellBook:GetSpell(121536) local DesperatePrayer = Bastion.SpellBook:GetSpell(19236) local DispelMagic = Bastion.SpellBook:GetSpell(528) local DominateMind = Bastion.SpellBook:GetSpell(205364) local Fade = Bastion.SpellBook:GetSpell(586) local FlashHeal = Bastion.SpellBook:GetSpell(2061) local LeapofFaith = Bastion.SpellBook:GetSpell(73325) local Levitate = Bastion.SpellBook:GetSpell(1706) local MassDispel = Bastion.SpellBook:GetSpell(32375) local MindBlast = Bastion.SpellBook:GetSpell(8092) local MindSoothe = Bastion.SpellBook:GetSpell(453) local MindVision = Bastion.SpellBook:GetSpell(2096) local Mindgames = Bastion.SpellBook:GetSpell(375901) local PowerInfusion = Bastion.SpellBook:GetSpell(10060) local PowerWordFortitude = Bastion.SpellBook:GetSpell(21562) local PowerWordShield = Bastion.SpellBook:GetSpell(17) local PsychicScream = Bastion.SpellBook:GetSpell(8122) local Resurrection = Bastion.SpellBook:GetSpell(2006) local ShadowWordDeath = Bastion.SpellBook:GetSpell(32379) local ShadowWordPain = Bastion.SpellBook:GetSpell(589) local VampiricEmbrace = Bastion.SpellBook:GetSpell(15286) local DarkAscension = Bastion.SpellBook:GetSpell(391109) local DevouringPlague = Bastion.SpellBook:GetSpell(335467) local Dispersion = Bastion.SpellBook:GetSpell(47585) local Halo = Bastion.SpellBook:GetSpell(120644) local MindFlay = Bastion.SpellBook:GetSpell(15407) local MindFlayInsanity = Bastion.SpellBook:GetSpell(391399) local MindSpike = Bastion.SpellBook:GetSpell(73510) local Mindbender = Bastion.SpellBook:GetSpell(200174) local ShadowCrash = Bastion.SpellBook:GetSpell(205385) local Shadowform = Bastion.SpellBook:GetSpell(232698) local Silence = Bastion.SpellBook:GetSpell(15487) local SurgeofDarkness = Bastion.SpellBook:GetSpell(87160) local VampiricTouch = Bastion.SpellBook:GetSpell(34914) local VoidTorrent = Bastion.SpellBook:GetSpell(263165) local function checktotem(totemname) for index = 1, MAX_TOTEMS do local haveTotem, totemName, startTime, duration, icon = GetTotemInfo(index) if not totemName then return false end if string.find(totemName, totemname) then return true end end return false end local InterruptTarget = Bastion.UnitManager:CreateCustomUnit('silence', function(unit) local interrupt = 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 interrupt = unit return true end end) if interrupt == nil then interrupt = None end return interrupt 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 RestingAPL = Bastion.APL:New('resting') local OpenerAPL = Bastion.APL:New('opener') local STAPL = Bastion.APL:New('st') local AOEAPL = Bastion.APL:New('aoe') local UtilityAPL = Bastion.APL:New('utility') -- Resting - Out of Combat Actions local usepwf = myconf:Read('pwf') local useshadowform = myconf:Read('shadowform') RestingAPL:AddSpell( PowerWordFortitude:CastableIf(function(self) 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 and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() and not Player:GetAuras():FindMy(Shadowform):IsUp() and not IsMounted() end):SetTarget(Player) ) -- Opener spells local opener = myconf:Read('opener') OpenerAPL:AddSpell( ShadowCrash:CastableIf(function(self) return opener == 'crash' and Target:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() end):SetTarget(None):OnCast(function(self) local loc = Target:GetPosition() self:Click(loc) end) ) OpenerAPL:AddSpell( ShadowWordPain:CastableIf(function(self) return opener == 'swp' and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() and not Target:GetAuras():FindMy(ShadowWordPain):IsUp() end):SetTarget(Target) ) -- Utility spells UtilityAPL:AddSpell( Silence:CastableIf(function(self) return InterruptTarget:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() end):SetTarget(InterruptTarget) ) -- Single Target Action Priority List -- Make sure your target has both Shadow Word: Pain and Vampiric Touch active. Prioritise Shadow Crash over Vampiric Touch for this. STAPL:AddSpell( ShadowWordPain:CastableIf(function(self) return self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() and not Target:GetAuras():FindMy(ShadowWordPain):IsUp() end):SetTarget(Target) ) -- Cast Mindbender on cooldown STAPL:AddSpell( Mindbender:CastableIf(function(self) return Target:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() end):SetTarget(Target) ) -- Cast Dark Ascension on cooldown STAPL:AddSpell( DarkAscension:CastableIf(function(self) return Target:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() end):SetTarget(Player) ) -- Cast Power Infusion if Dark Ascension is active STAPL:AddSpell( PowerInfusion:CastableIf(function(self) return Target:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() and Player:GetAuras():FindMy(DarkAscension):IsUp() end):SetTarget(Player) ) -- Use offensive trinkets and potions. -- Cast Mind Blast if you have two charges STAPL:AddSpell( MindBlast:CastableIf(function(self) return Target:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() and MindBlast:GetCharges() == 2 end):SetTarget(Target) ) -- Cast Shadow Word: Death if Mindbender is active STAPL:AddSpell( ShadowWordDeath:CastableIf(function(self) return Target:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() and checktotem("Mindbender") end):SetTarget(Target) ) -- Cast Devouring Plague if you're close to capping Insanity or the debuff will expire STAPL:AddSpell( DevouringPlague:CastableIf(function(self) return Target:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() and Player:GetPower(Enum.PowerType.Insanity) >= 80 end):SetTarget(Target) ) -- Cast Vampiric Touch if you are within pandemic range to maintain uptime STAPL:AddSpell( VampiricTouch:CastableIf(function(self) return self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() and (not Target:GetAuras():FindMy(VampiricTouch):IsUp() or Target:GetAuras():FindMy(VampiricTouch):GetRemainingTime() <= 6.3) end):SetTarget(Target) ) -- Cast Shadow Word: Death if the target is below 20% hp STAPL:AddSpell( ShadowWordDeath:CastableIf(function(self) return Target:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() and Target:GetHealthPercent() <= 20 end):SetTarget(Target) ) -- Cast Mind Blast STAPL:AddSpell( MindBlast:CastableIf(function(self) return Target:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() end):SetTarget(Target) ) -- Cast Mindgames STAPL:AddSpell( Mindgames:CastableIf(function(self) return Target:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() end):SetTarget(Target) ) -- Cast Shadow Crash, even if your DoTs are not close to expiring STAPL:AddSpell( ShadowCrash:CastableIf(function(self) return Target:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() end):SetTarget(None):OnCast(function(self) local loc = Target:GetPosition() self:Click(loc) end) ) -- Cast Void Torrent STAPL:AddSpell( VoidTorrent:CastableIf(function(self) return Target:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() end):SetTarget(Target) ) -- Cast Mind Spike if you have a Surge of Darkness proc STAPL:AddSpell( MindSpike:CastableIf(function(self) return Target:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() and Player:GetAuras():FindMy(SurgeofDarkness):IsUp() end):SetTarget(Target) ) -- Cast Mind Flay: Insanity STAPL:AddSpell( MindFlayInsanity:CastableIf(function(self) return Target:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() end):SetTarget(Target) ) -- Cast Mind Spike STAPL:AddSpell( MindSpike:CastableIf(function(self) return Target:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() end):SetTarget(Target) ) -- Cast Mind Flay STAPL:AddSpell( MindFlay:CastableIf(function(self) return Target:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() end):SetTarget(Target) ) -- Cast Shadow Word: Pain if you're moving and nothing else is available STAPL:AddSpell( ShadowWordPain:CastableIf(function(self) return self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() and not Player:IsMoving() end):SetTarget(Target) ) -- Module that dictates APL flow ShadowModule:Sync(function() if not Player:IsAffectingCombat() then RestingAPL:Execute() end if not Player:IsAffectingCombat() and Target:Exists() then OpenerAPL:Execute() end if Player:IsAffectingCombat() and Target:Exists() then STAPL:Execute() end end) Bastion:Register(ShadowModule) local tab1 = { layoutConfig = { padding = { top = 40 } }, rows = { [1] = { shadpr = { type = 'label', label = 'Open Combat' } }, [2] = { opener = { type = 'dropdown', label = 'Opener', column = 6, order = 1, options = { { text = 'Shadow Word: Pain', value = 'swp'}, { text = 'Shadow Crash', value = 'crash'}, { text = 'None', value = 'none'}, }, initialValue = myconf:Read('opener', 'shield'), onValueChanged = function(_, value) myconf:Write('opener', value) 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 }, shadform = { type = 'checkbox', label = 'Shadowform', column = 6, order = 2, initialValue = myconf:Read('shadowform', false), onValueChanged = function(_, flag) myconf:Write('shadowform', flag) end }, }, [5] = { shadpr = { type = 'header', label = 'Defensives' } }, [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 }, 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 }, }, [7] = { 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 }, }, [8] = { shadpr = { type = 'header', label = 'Interrupts' } }, [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 }, 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 }, }, [10] = { shadpr = { type = 'header', label = 'Purify Disease' } }, [11] = { 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 }, }, [12] = { shadpr = { type = 'header', label = 'Dispel Magic' } }, [13] = { incombat = { type = 'checkbox', label = 'In Combat', column = 12, order = 1, initialValue = myconf:Read('dispelic', false), onValueChanged = function(_, flag) myconf:Write('dispelic', flag) end }, }, [14] = { shadpr = { type = 'header', label = 'Dispel Delay Time' } }, [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 }, }, }, } 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 shadpriestconfig = { layoutConfig = { padding = { top = 30 } }, rows = { [1] = { container = { type = 'tab', fullSize = true, tabs = { { name = 'player', title = 'Player Settings', layout = tab1 }, { name = 'group', title = 'Placeholder', layout = tab2 } }, } }, }, } 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