--Talents: C4QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzCzsMmxMmxM2w2sMbjHAz2yyMzyCImZgZYmFDsMzMDzGzMMLzEAAAAAEgFLz22sNzMBAA2A local Tinkr, Bastion = ... local RestoMonkModule = Bastion.Module:New('MistweaverMonk') local Player = Bastion.UnitManager:Get('player') local Target = Bastion.UnitManager:Get('target') -- Initialize SpellBook local SpellBook = Bastion.SpellBook:New() -- Spells local RenewingMist = SpellBook:GetSpell(115151) local EnvelopingMist = SpellBook:GetSpell(124682) local Vivify = SpellBook:GetSpell(116670) local RisingSunKick = SpellBook:GetSpell(107428) local ThunderFocusTea = SpellBook:GetSpell(116680) local TigerPalm = SpellBook:GetSpell(100780) local BlackoutKick = SpellBook:GetSpell(100784) local SpinningCraneKick = SpellBook:GetSpell(101546) local Revival = SpellBook:GetSpell(115310) local Restoral = SpellBook:GetSpell(388615) local InvokeYulon = SpellBook:GetSpell(322118) local InvokeChiJi = SpellBook:GetSpell(325197) local SoothingMist = SpellBook:GetSpell(115175) local ManaTea = SpellBook:GetSpell(115294) local CelestialConduit = SpellBook:GetSpell(443028) local UnityWithin = SpellBook:GetSpell(443591) local FortifyingBrew = SpellBook:GetSpell(243435) local DiffuseMagic = SpellBook:GetSpell(122783) local LifeCocoon = SpellBook:GetSpell(116849) local JadefireStomp = SpellBook:GetSpell(388193) local SheilunsGift = SpellBook:GetSpell(399491) local TouchOfDeath = SpellBook:GetSpell(322109) local SpearHandStrike = SpellBook:GetSpell(116705) local LegSweep = SpellBook:GetSpell(119381) -- Add Rising Mist spell local RisingMist = SpellBook:GetSpell(274909) -- Buffs local TeachingsOfTheMonastery = SpellBook:GetSpell(202090) local StrengthOfTheBlackOx = SpellBook:GetSpell(392883) -- Custom Units local Lowest = Bastion.UnitManager:CreateCustomUnit('lowest', function(unit) local lowest = nil local lowestHP = math.huge Bastion.UnitManager:EnumFriends(function(unit) if unit:IsDead() or Player:GetDistance(unit) > 40 or not Player:CanSee(unit) then return false end local hp = unit:GetHP() if hp < lowestHP then lowest = unit lowestHP = hp end end) return lowest or Player end) -- Create a custom unit for finding a Touch of Death target local TouchOfDeathTarget = Bastion.UnitManager:CreateCustomUnit('touchofdeath', function(unit) local todTarget = nil Bastion.UnitManager:EnumEnemies(function(unit) if unit:IsDead() or Player:GetDistance(unit) > 5 or not Player:CanSee(unit) then return false end -- Check if unit is eligible for Touch of Death if unit:GetHP() <= Player:GetMaxHealth() * 0.15 or Player:GetHP() > unit:GetMaxHealth() then todTarget = unit return true end end) return todTarget or Bastion.UnitManager:Get('none') end) -- APLs local DefaultAPL = Bastion.APL:New('default') local CooldownAPL = Bastion.APL:New('cooldown') local DefensiveAPL = Bastion.APL:New('defensive') local DpsAPL = Bastion.APL:New('dps') local InterruptAPL = Bastion.APL:New('interrupt') -- Helper Functions local function ShouldUseRenewingMist() return RenewingMist:GetCharges() >= 2 end local function ShouldUseEnvelopingMist() return Player:GetAuras():FindMy(StrengthOfTheBlackOx):IsUp() end local function NeedsUrgentHealing() return Lowest:GetHP() < 70 or Player:GetPartyHPAround(30, 80) >= 3 end -- Add this helper function near the top of the file, after the SpellBook initialization local function GetPlayerManaPercent() return (UnitPower("player", Enum.PowerType.Mana) / UnitPowerMax("player", Enum.PowerType.Mana)) * 100 end -- Add a variable to track Mana Tea stacks local manaTea = SpellBook:GetSpell(115294) local manaTeaStacks = 0 -- Add a function to update Mana Tea stacks local function UpdateManaTeaStacks() manaTeaStacks = Player:GetAuras():FindMy(manaTea):GetCount() end -- Add this helper function near the top of the file local function GetRandomInterruptDelay() return math.random(50, 90) end -- Add this near the top of the file, after the SpellBook initialization local interruptThresholds = {} -- Modify the Interrupt APL InterruptAPL:AddSpell( SpearHandStrike:CastableIf(function(self) if not self:IsKnownAndUsable() or not Target:IsCasting() or not Target:IsInterruptible() or not Player:IsWithinCombatDistance(Target, 5) then return false end local spellName, _, _, startTimeMS, endTimeMS = UnitCastingInfo(Target:GetOMToken()) if not spellName then return false end local castDuration = (endTimeMS - startTimeMS) / 1000 local currentCastTime = (GetTime() * 1000 - startTimeMS) / 1000 local castPercentage = (currentCastTime / castDuration) * 100 -- Generate a random interrupt threshold if it doesn't exist if not interruptThresholds[self:GetID()] then interruptThresholds[self:GetID()] = GetRandomInterruptDelay() end -- Check if the cast percentage is at or above the threshold if castPercentage >= interruptThresholds[self:GetID()] then return true end return false end):SetTarget(Target):OnCast(function(self) -- Reset the interrupt threshold after successful interrupt interruptThresholds[self:GetID()] = nil end) ) -- Default APL DefaultAPL:AddSpell( SheilunsGift:CastableIf(function(self) return self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() and Player:GetPartyHPAround(40, 80) >= 3 end):SetTarget(Player) ) DefaultAPL:AddSpell( Vivify:CastableIf(function(self) return Lowest:Exists() and Lowest:GetHP() < 70 and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() end):SetTarget(Lowest) ) DefaultAPL:AddSpell( RenewingMist:CastableIf(function(self) return ShouldUseRenewingMist() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() end):SetTarget(Lowest) ) DefaultAPL:AddSpell( RisingSunKick:CastableIf(function(self) return Target:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() end):SetTarget(Target):OnCast(function() -- Trigger Rising Mist effect if RisingMist:IsKnown() then Bastion.UnitManager:EnumFriends(function(unit) local renewingMist = unit:GetAuras():FindMy(RenewingMist) if renewingMist:IsUp() then renewingMist:Refresh() end end) end end) ) DefaultAPL:AddSpell( ThunderFocusTea:CastableIf(function(self) return self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() end):SetTarget(Player) ) DefaultAPL:AddSpell( EnvelopingMist:CastableIf(function(self) return Lowest:Exists() and ShouldUseEnvelopingMist() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() and (Player:GetAuras():FindMy(ManaTea):IsUp() or GetPlayerManaPercent() > 30) end):SetTarget(Lowest) ) DefaultAPL:AddSpell( TigerPalm:CastableIf(function(self) return Target:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() end):SetTarget(Target) ) -- Cooldown APL CooldownAPL:AddSpell( CelestialConduit:CastableIf(function(self) return self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() and Player:GetPartyHPAround(40, 70) >= 3 end):SetTarget(Player) ) CooldownAPL:AddSpell( InvokeChiJi:CastableIf(function(self) return self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() and Player:GetPartyHPAround(40, 85) >= 2 end):SetTarget(Player) ) CooldownAPL:AddSpell( InvokeYulon:CastableIf(function(self) return self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() and Player:GetPartyHPAround(40, 75) >= 3 end):SetTarget(Player) ) CooldownAPL:AddSpell( ManaTea:CastableIf(function(self) UpdateManaTeaStacks() return self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() and (GetPlayerManaPercent() < 50 or manaTeaStacks >= 18 or Player:GetEnemies(8) >= 3) end):SetTarget(Player):OnCast(function() -- Cast an Enveloping Mist immediately after Mana Tea if EnvelopingMist:IsKnownAndUsable() and Lowest:Exists() then EnvelopingMist:Cast(Lowest) end end) ) -- Add Unity Within to the CooldownAPL CooldownAPL:AddSpell( UnityWithin:CastableIf(function(self) return self:IsKnownAndUsable() end):SetTarget(Player) ) -- Defensive APL DefensiveAPL:AddSpell( FortifyingBrew:CastableIf(function(self) return self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() and Player:GetHP() < 50 end):SetTarget(Player) ) DefensiveAPL:AddSpell( DiffuseMagic:CastableIf(function(self) return self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() and Player:GetHP() < 70 end):SetTarget(Player) ) DefensiveAPL:AddSpell( LifeCocoon:CastableIf(function(self) return Lowest:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() and Lowest:GetHP() < 40 end):SetTarget(Lowest) ) -- DPS APL DpsAPL:AddSpell( JadefireStomp:CastableIf(function(self) return self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() end):SetTarget(Player) ) DpsAPL:AddSpell( RisingSunKick:CastableIf(function(self) return self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() and Player:IsWithinCombatDistance(Target, 5) -- Assuming 5 is melee range end):SetTarget(Target) ) DpsAPL:AddSpell( SpinningCraneKick:CastableIf(function(self) return self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() and Player:GetEnemies(8) >= 2 end):SetTarget(Player) ) DpsAPL:AddSpell( BlackoutKick:CastableIf(function(self) return self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() and Player:IsWithinCombatDistance(Target, 5) end):SetTarget(Target) ) DpsAPL:AddSpell( TigerPalm:CastableIf(function(self) return self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() and Player:IsWithinCombatDistance(Target, 5) and Player:GetAuras():FindMy(TeachingsOfTheMonastery):GetCount() < 3 end):SetTarget(Target) ) DpsAPL:AddSpell( SpinningCraneKick:CastableIf(function(self) return self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() and Player:GetEnemies(8) >= 3 end):SetTarget(Player) ) DpsAPL:AddSpell( TouchOfDeath:CastableIf(function(self) return self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() and TouchOfDeathTarget:Exists() end):SetTarget(TouchOfDeathTarget) ) -- Add Celestial Conduit to the CooldownAPL CooldownAPL:AddSpell( CelestialConduit:CastableIf(function(self) return self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() and Player:GetPartyHPAround(20, 80) >= 3 -- Use when 3 or more party members within 20 yards are below 80% HP and Player:GetEnemies(20) >= 2 -- Ensure there are at least 2 enemies within 20 yards for increased effectiveness end):SetTarget(Player):OnCast(function() -- Logic to handle the channeling of Celestial Conduit C_Timer.NewTicker(0.5, function() if not Player:IsCastingOrChanneling() then return end -- Continue DPS rotation while channeling if RisingSunKick:IsKnownAndUsable() and Player:IsWithinCombatDistance(Target, 5) then RisingSunKick:Cast(Target) elseif BlackoutKick:IsKnownAndUsable() and Player:IsWithinCombatDistance(Target, 5) then BlackoutKick:Cast(Target) end end, 8) -- 8 ticks over 4 seconds end) ) -- Module Sync RestoMonkModule:Sync(function() if Player:IsMounted() then return end if Player:IsAffectingCombat() then UpdateManaTeaStacks() if manaTeaStacks >= 19 then ManaTea:Cast(Player) end InterruptAPL:Execute() DefensiveAPL:Execute() -- Prioritize Unity Within if UnityWithin:IsKnownAndUsable() then UnityWithin:Cast(Player) elseif TouchOfDeath:IsKnownAndUsable() and TouchOfDeathTarget:Exists() then TouchOfDeath:Cast(TouchOfDeathTarget) elseif CelestialConduit:IsKnownAndUsable() and Player:GetPartyHPAround(20, 80) >= 3 and Player:GetEnemies(20) >= 2 then CelestialConduit:Cast(Player) elseif RisingMist:IsKnown() and RisingSunKick:IsKnownAndUsable() then RisingSunKick:Cast(Target) elseif NeedsUrgentHealing() then CooldownAPL:Execute() DefaultAPL:Execute() else DpsAPL:Execute() if RenewingMist:GetCharges() >= 2 then RenewingMist:Cast(Lowest) end if Vivify:IsKnownAndUsable() and Lowest:GetHP() < 80 then Vivify:Cast(Lowest) end end else if not Player:IsMounted() and Lowest:GetHP() < 90 then DefaultAPL:Execute() end end end) Bastion:Register(RestoMonkModule)