Basic rotations that work
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
OkRotations/ElementalShaman.lua

306 lines
10 KiB

-- Talents: CYQAAAAAAAAAAAAAAAAAAAAAAAAAAAAMbzy2MjxwMbMmZMmZGAAAAAAGzYYgFYb0QjNAwsNNDYbhZmGmZmxMWmxMYWGmFzMzMMjZYA
local Tinkr, Bastion = ...
local ElementalShamanModule = Bastion.Module:New('ElementalShaman')
local Player = Bastion.UnitManager:Get('player')
local Target = Bastion.UnitManager:Get('target')
local Pet = Bastion.UnitManager:Get('pet')
-- Initialize SpellBook
local SpellBook = Bastion.SpellBook:New()
-- Spells
local LightningBolt = SpellBook:GetSpell(188196)
local LavaBurst = SpellBook:GetSpell(51505)
local EarthShock = SpellBook:GetSpell(8042)
local FlameShock = SpellBook:GetSpell(188389)
local Stormkeeper = SpellBook:GetSpell(191634)
local ElementalBlast = SpellBook:GetSpell(117014)
local ChainLightning = SpellBook:GetSpell(188443)
local Earthquake = SpellBook:GetSpell(61882)
local FireElemental = SpellBook:GetSpell(198067)
local StormElemental = SpellBook:GetSpell(192249)
local LiquidMagmaTotem = SpellBook:GetSpell(192222)
local Icefury = SpellBook:GetSpell(210714)
local FrostShock = SpellBook:GetSpell(196840)
local Ascendance = SpellBook:GetSpell(114050)
local PrimordialWave = SpellBook:GetSpell(375982)
local AstralShift = SpellBook:GetSpell(108271)
local WindShear = SpellBook:GetSpell(57994)
local Skyfury = SpellBook:GetSpell(462854)
5 months ago
local LightningShield = SpellBook:GetSpell(192106)
local EarthShield = SpellBook:GetSpell(974)
local Tempest = SpellBook:GetSpell(454009)
local NaturesSwiftness = SpellBook:GetSpell(378081)
local HealingSurge = SpellBook:GetSpell(8004)
local AncestralGuidance = SpellBook:GetSpell(108281)
-- Buffs and Debuffs
local MasterOfTheElements = SpellBook:GetSpell(260734)
local SurgeOfPower = SpellBook:GetSpell(285514)
local LavaSurge = SpellBook:GetSpell(77762)
local Icefury_Buff = SpellBook:GetSpell(210714)
local FlameShock_Debuff = SpellBook:GetSpell(188389)
local MagmaChamber_Buff = SpellBook:GetSpell(381933)
local SplinteredElements_Buff = SpellBook:GetSpell(382043)
local WindGust_Buff = SpellBook:GetSpell(263806)
local EarthShield_Buff = SpellBook:GetSpell(383648)
local LightningShield_Buff = SpellBook:GetSpell(192106)
local PrimordialWave_Buff = SpellBook:GetSpell(375986)
-- Custom Units
local BestTarget = Bastion.UnitManager:CreateCustomUnit('besttarget', function()
local bestTarget = nil
local highestHP = 0
Bastion.UnitManager:EnumEnemies(function(unit)
if unit:IsAffectingCombat() and Player:IsWithinCombatDistance(unit, 40) and Player:CanSee(unit) and Player:IsFacing(unit) then
local hp = unit:GetHP()
if hp > highestHP then
bestTarget = unit
highestHP = hp
end
end
end)
return bestTarget or Target
end)
5 months ago
local InterruptTarget = Bastion.UnitManager:CreateCustomUnit('interrupttarget', function()
local target = nil
Bastion.UnitManager:EnumEnemies(function(unit)
if unit:IsAffectingCombat() and unit:GetDistance(Player) <= 30 and Player:CanSee(unit)
and unit:IsCasting() and unit:IsInterruptible() then
local castPercentage = unit:GetChannelOrCastPercentComplete()
if castPercentage >= 30 and castPercentage <= 80 then
target = unit
return true
end
end
end)
return target or Bastion.UnitManager:Get('none')
end)
-- APLs
local DefaultAPL = Bastion.APL:New('default')
local AoEAPL = Bastion.APL:New('aoe')
local CooldownAPL = Bastion.APL:New('cooldown')
local DefensiveAPL = Bastion.APL:New('defensive')
local OutOfCombatAPL = Bastion.APL:New('outofcombat')
5 months ago
local InterruptAPL = Bastion.APL:New('interrupt')
-- Helper Functions
local function ShouldAoE()
local _, enemies = Bastion.UnitManager:GetEnemiesWithMostEnemies(10)
return #enemies >= 2
end
5 months ago
local function NeedSkyfury()
-- Check if any party member (including the player) needs Skyfury
local needsBuff = false
Bastion.UnitManager:EnumFriends(function(unit)
if unit:IsAlive() and not unit:GetAuras():FindAny(Skyfury):IsUp() then
needsBuff = true
return true -- This will break the enumeration loop
end
end)
return needsBuff
end
-- Default APL
DefaultAPL:AddSpell(
PrimordialWave:CastableIf(function(self)
return BestTarget:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling()
end):SetTarget(BestTarget)
)
DefaultAPL:AddSpell(
LavaBurst:CastableIf(function(self)
return BestTarget:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling()
and (Player:GetAuras():FindAny(PrimordialWave_Buff):IsUp() or (Player:GetAuras():FindAny(LavaSurge):IsUp() and Player:IsMoving()))
end):SetTarget(BestTarget)
)
DefaultAPL:AddSpell(
Tempest:CastableIf(function(self)
return BestTarget:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling()
and Player:GetAuras():FindAny(MasterOfTheElements):IsUp()
end):SetTarget(BestTarget)
)
DefaultAPL:AddSpell(
EarthShock:CastableIf(function(self)
return BestTarget:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling()
and Player:GetPower() >= 60 and (Player:GetAuras():FindAny(MasterOfTheElements):IsUp() or (Player:GetPower() + self:GetCost()) > Player:GetMaxPower())
end):SetTarget(BestTarget)
)
DefaultAPL:AddSpell(
ElementalBlast:CastableIf(function(self)
return BestTarget:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling()
and Player:GetAuras():FindAny(MasterOfTheElements):IsUp()
end):SetTarget(BestTarget)
)
DefaultAPL:AddSpell(
FlameShock:CastableIf(function(self)
return BestTarget:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling()
and not BestTarget:GetAuras():FindAny(FlameShock_Debuff):IsUp()
end):SetTarget(BestTarget)
)
DefaultAPL:AddSpell(
LightningBolt:CastableIf(function(self)
return BestTarget:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling()
end):SetTarget(BestTarget)
)
DefaultAPL:AddSpell(
FrostShock:CastableIf(function(self)
return BestTarget:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() and Player:IsMoving()
end):SetTarget(BestTarget)
)
5 months ago
-- OutOfCombat APL
OutOfCombatAPL:AddSpell(
Skyfury:CastableIf(function(self)
return self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() and NeedSkyfury()
end):SetTarget(Player)
)
OutOfCombatAPL:AddSpell(
EarthShield:CastableIf(function(self)
return self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() and not Player:GetAuras():FindAny(EarthShield_Buff):IsUp()
end):SetTarget(Player)
)
OutOfCombatAPL:AddSpell(
LightningShield:CastableIf(function(self)
return self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() and not Player:GetAuras():FindAny(LightningShield_Buff):IsUp()
end):SetTarget(Player)
)
-- AoE APL
AoEAPL:AddSpell(
Tempest:CastableIf(function(self)
return BestTarget:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling()
and ShouldAoE()
end):SetTarget(BestTarget)
)
AoEAPL:AddSpell(
ChainLightning:CastableIf(function(self)
return BestTarget:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling()
and ShouldAoE()
end):SetTarget(BestTarget)
)
AoEAPL:AddSpell(
Earthquake:CastableIf(function(self)
return self:IsKnownAndUsable() and not Player:IsCastingOrChanneling()
and Player:GetPower() >= 60 and ShouldAoE()
end):SetTarget(Bastion.UnitManager:Get('none')):OnCast(function(self)
5 months ago
local loc = Bastion.UnitManager:FindEnemiesCentroid(10, 39)
if loc then
self:Click(loc)
end
end)
)
-- Cooldown APL
CooldownAPL:AddSpell(
AncestralGuidance:CastableIf(function(self)
return self:IsKnownAndUsable() and not Player:IsCastingOrChanneling()
and Player:GetPartyHPAround(40, 90) >= 3
end):SetTarget(Player)
)
CooldownAPL:AddSpell(
StormElemental:CastableIf(function(self)
return self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() and not Pet:Exists()
end):SetTarget(Player)
)
CooldownAPL:AddSpell(
FireElemental:CastableIf(function(self)
return self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() and not StormElemental:IsKnownAndUsable()
end):SetTarget(Player)
)
CooldownAPL:AddSpell(
Stormkeeper:CastableIf(function(self)
return self:IsKnownAndUsable() and not Player:IsCastingOrChanneling()
end):SetTarget(Player)
)
CooldownAPL:AddSpell(
LiquidMagmaTotem:CastableIf(function(self)
return self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() and ShouldAoE()
end):SetTarget(Bastion.UnitManager:Get('none')):OnCast(function(self)
local loc = Bastion.UnitManager:FindEnemiesCentroid(10, 40)
if loc then
self:Click(loc)
end
end)
)
CooldownAPL:AddSpell(
Ascendance:CastableIf(function(self)
return self:IsKnownAndUsable() and not Player:IsCastingOrChanneling()
end):SetTarget(Player)
)
-- Defensive APL
DefensiveAPL:AddSpell(
AstralShift:CastableIf(function(self)
return self:IsKnownAndUsable() and not Player:IsCastingOrChanneling()
and Player:GetHP() < 70
end):SetTarget(Player)
)
DefensiveAPL:AddSpell(
NaturesSwiftness:CastableIf(function(self)
return self:IsKnownAndUsable() and not Player:IsCastingOrChanneling()
and Player:GetHP() < 80 and HealingSurge:IsKnownAndUsable()
end):SetTarget(Player):OnCast(function()
HealingSurge:Cast(Player)
end)
)
-- Interrupt APL
InterruptAPL:AddSpell(
WindShear:CastableIf(function(self)
5 months ago
local target = InterruptTarget
local randomInterruptPercent = math.random(50, 90)
return target:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling()
and target:IsCasting() and target:IsInterruptible()
and target:GetChannelOrCastPercentComplete() >= randomInterruptPercent
end):SetTarget(InterruptTarget)
)
-- Module Sync
ElementalShamanModule:Sync(function()
if Player:IsMounted() then
return
end
if Player:IsAffectingCombat() then
5 months ago
DefensiveAPL:Execute()
InterruptAPL:Execute()
CooldownAPL:Execute()
if ShouldAoE() then
AoEAPL:Execute()
else
DefaultAPL:Execute()
end
else
5 months ago
OutOfCombatAPL:Execute()
end
end)
-- Register the ElementalShaman module with Bastion
Bastion:Register(ElementalShamanModule)