parent
daaf678513
commit
7939b9fe03
@ -0,0 +1,351 @@ |
|||||||
|
local Tinkr, Bastion = ... |
||||||
|
|
||||||
|
local RestoShamanModule = Bastion.Module:New('RestoShaman') |
||||||
|
local Player = Bastion.UnitManager:Get('player') |
||||||
|
local Target = Bastion.UnitManager:Get('target') |
||||||
|
|
||||||
|
-- Initialize SpellBook |
||||||
|
local SpellBook = Bastion.SpellBook:New() |
||||||
|
|
||||||
|
-- Spells |
||||||
|
local WaterShield = SpellBook:GetSpell(52127) |
||||||
|
local EarthShield = SpellBook:GetSpell(974) |
||||||
|
local HealingRain = SpellBook:GetSpell(73920) |
||||||
|
local Riptide = SpellBook:GetSpell(61295) |
||||||
|
local CloudburstTotem = SpellBook:GetSpell(157153) |
||||||
|
local HealingStreamTotem = SpellBook:GetSpell(5394) |
||||||
|
local PrimordialWave = SpellBook:GetSpell(375982) |
||||||
|
local UnleashLife = SpellBook:GetSpell(73685) |
||||||
|
local Downpour = SpellBook:GetSpell(207778) |
||||||
|
local ChainHeal = SpellBook:GetSpell(1064) |
||||||
|
local HealingWave = SpellBook:GetSpell(77472) |
||||||
|
local HealingSurge = SpellBook:GetSpell(8004) |
||||||
|
local Wellspring = SpellBook:GetSpell(197995) |
||||||
|
local SpiritLinkTotem = SpellBook:GetSpell(98008) |
||||||
|
local HealingTideTotem = SpellBook:GetSpell(108280) |
||||||
|
local AncestralGuidance = SpellBook:GetSpell(108281) |
||||||
|
local ManaTideTotem = SpellBook:GetSpell(16191) |
||||||
|
local Ascendance = SpellBook:GetSpell(114052) |
||||||
|
local NaturesSwiftness = SpellBook:GetSpell(378081) |
||||||
|
local EarthenWallTotem = SpellBook:GetSpell(198838) |
||||||
|
local PurifySpirit = SpellBook:GetSpell(77130) |
||||||
|
local LightningBolt = SpellBook:GetSpell(403) |
||||||
|
local ChainLightning = SpellBook:GetSpell(421) |
||||||
|
local FlameShock = SpellBook:GetSpell(188389) |
||||||
|
local LavaBurst = SpellBook:GetSpell(51505) |
||||||
|
|
||||||
|
-- Buffs |
||||||
|
local TidalWaves = SpellBook:GetSpell(53390) |
||||||
|
local HighTide = SpellBook:GetSpell(288675) |
||||||
|
|
||||||
|
-- Totem timers |
||||||
|
local cloudburstTotemEnd = 0 |
||||||
|
local healingStreamTotemEnd = 0 |
||||||
|
local earthenWallTotemEnd = 0 |
||||||
|
local spiritLinkTotemEnd = 0 |
||||||
|
local healingTideTotemEnd = 0 |
||||||
|
|
||||||
|
-- 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) |
||||||
|
|
||||||
|
-- APLs |
||||||
|
local PrePullAPL = Bastion.APL:New('prepull') |
||||||
|
local DefaultAPL = Bastion.APL:New('default') |
||||||
|
local CooldownAPL = Bastion.APL:New('cooldown') |
||||||
|
local DamageAPL = Bastion.APL:New('damage') |
||||||
|
|
||||||
|
-- Debug function |
||||||
|
local function Debug(message) |
||||||
|
-- print("[RestoShaman Debug]: " .. message) |
||||||
|
end |
||||||
|
|
||||||
|
-- Helper Functions |
||||||
|
local function IsTotemActive(totemEnd) |
||||||
|
return GetTime() < totemEnd |
||||||
|
end |
||||||
|
|
||||||
|
local function UpdateTotemTimer(totemEnd, duration) |
||||||
|
return GetTime() + duration |
||||||
|
end |
||||||
|
|
||||||
|
local function ShouldUseCloudburstTotem() |
||||||
|
return not IsTotemActive(cloudburstTotemEnd) and (Player:GetEnemies(10) >= 3 or Player:GetPartyHPAround(30, 80) >= 3) |
||||||
|
end |
||||||
|
|
||||||
|
local function ShouldUseHealingStreamTotem() |
||||||
|
return not IsTotemActive(healingStreamTotemEnd) and not CloudburstTotem:IsKnownAndUsable() |
||||||
|
end |
||||||
|
|
||||||
|
local function ShouldUseEarthenWallTotem() |
||||||
|
return not IsTotemActive(earthenWallTotemEnd) and Player:GetPartyHPAround(40, 80) >= 3 |
||||||
|
end |
||||||
|
|
||||||
|
local function ShouldUseSpiritLinkTotem() |
||||||
|
return not IsTotemActive(spiritLinkTotemEnd) and Player:GetPartyHPAround(40, 60) >= 3 |
||||||
|
end |
||||||
|
|
||||||
|
local function ShouldUseHealingTideTotem() |
||||||
|
return not IsTotemActive(healingTideTotemEnd) and Player:GetPartyHPAround(40, 70) >= 3 |
||||||
|
end |
||||||
|
|
||||||
|
local function GetRiptideCount() |
||||||
|
local count = 0 |
||||||
|
Bastion.UnitManager:EnumFriends(function(unit) |
||||||
|
if unit:GetAuras():FindMy(Riptide):IsUp() then |
||||||
|
count = count + 1 |
||||||
|
end |
||||||
|
end) |
||||||
|
return count |
||||||
|
end |
||||||
|
|
||||||
|
local function ShouldUseAscendance() |
||||||
|
return Player:GetPartyHPAround(40, 70) >= 3 and CloudburstTotem:GetTimeSinceLastCast() < 3 |
||||||
|
end |
||||||
|
|
||||||
|
local function GetTanks() |
||||||
|
local tanks = {} |
||||||
|
Bastion.UnitManager:EnumFriends(function(unit) |
||||||
|
if unit:IsTank() and not unit:IsDead() and Player:CanSee(unit) and Player:GetDistance(unit) <= 40 then |
||||||
|
table.insert(tanks, unit) |
||||||
|
end |
||||||
|
end) |
||||||
|
Debug("Found " .. #tanks .. " tanks") |
||||||
|
return tanks |
||||||
|
end |
||||||
|
|
||||||
|
local function ApplyEarthShield() |
||||||
|
local tanks = GetTanks() |
||||||
|
for _, tank in ipairs(tanks) do |
||||||
|
if not tank:GetAuras():FindMy(EarthShield):IsUp() then |
||||||
|
Debug("Applying Earth Shield to " .. tank:GetName()) |
||||||
|
return EarthShield:Cast(tank) |
||||||
|
end |
||||||
|
end |
||||||
|
Debug("No tanks need Earth Shield") |
||||||
|
end |
||||||
|
|
||||||
|
local function NeedsHealing(unit, threshold) |
||||||
|
return unit:GetHP() < threshold |
||||||
|
end |
||||||
|
|
||||||
|
-- Pre-Pull APL |
||||||
|
PrePullAPL:AddSpell( |
||||||
|
WaterShield:CastableIf(function(self) |
||||||
|
return Player:Exists() and self:IsKnownAndUsable() and not Player:GetAuras():FindMy(WaterShield):IsUp() |
||||||
|
end):SetTarget(Player) |
||||||
|
) |
||||||
|
|
||||||
|
-- Default APL |
||||||
|
DefaultAPL:AddSpell( |
||||||
|
CloudburstTotem:CastableIf(function(self) |
||||||
|
return Player:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() and ShouldUseCloudburstTotem() |
||||||
|
end):SetTarget(Player):OnCast(function() |
||||||
|
cloudburstTotemEnd = UpdateTotemTimer(cloudburstTotemEnd, 15) |
||||||
|
end) |
||||||
|
) |
||||||
|
|
||||||
|
DefaultAPL:AddSpell( |
||||||
|
HealingStreamTotem:CastableIf(function(self) |
||||||
|
return Player:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() and ShouldUseHealingStreamTotem() |
||||||
|
end):SetTarget(Player):OnCast(function() |
||||||
|
healingStreamTotemEnd = UpdateTotemTimer(healingStreamTotemEnd, 15) |
||||||
|
end) |
||||||
|
) |
||||||
|
|
||||||
|
DefaultAPL:AddSpell( |
||||||
|
Riptide:CastableIf(function(self) |
||||||
|
return Lowest:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() |
||||||
|
and NeedsHealing(Lowest, 90) |
||||||
|
end):SetTarget(Lowest) |
||||||
|
) |
||||||
|
|
||||||
|
DefaultAPL:AddSpell( |
||||||
|
PrimordialWave:CastableIf(function(self) |
||||||
|
return Lowest:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() |
||||||
|
and NeedsHealing(Lowest, 85) |
||||||
|
end):SetTarget(Lowest) |
||||||
|
) |
||||||
|
|
||||||
|
DefaultAPL:AddSpell( |
||||||
|
UnleashLife:CastableIf(function(self) |
||||||
|
return Lowest:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() |
||||||
|
and NeedsHealing(Lowest, 80) |
||||||
|
end):SetTarget(Lowest) |
||||||
|
) |
||||||
|
|
||||||
|
DefaultAPL:AddSpell( |
||||||
|
HealingRain:CastableIf(function(self) |
||||||
|
return Player:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() |
||||||
|
and Player:GetPartyHPAround(30, 85) >= 6 and not Player:IsMoving() |
||||||
|
end):SetTarget(Player) |
||||||
|
) |
||||||
|
|
||||||
|
DefaultAPL:AddSpell( |
||||||
|
Downpour:CastableIf(function(self) |
||||||
|
return Player:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() |
||||||
|
and Player:GetPartyHPAround(30, 80) >= 3 |
||||||
|
end):SetTarget(Player) |
||||||
|
) |
||||||
|
|
||||||
|
DefaultAPL:AddSpell( |
||||||
|
ChainHeal:CastableIf(function(self) |
||||||
|
return Lowest:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() |
||||||
|
and (Player:GetAuras():FindMy(HighTide):IsUp() or Player:GetAuras():FindMy(NaturesSwiftness):IsUp()) |
||||||
|
and not Player:IsMoving() and NeedsHealing(Lowest, 75) |
||||||
|
end):SetTarget(Lowest) |
||||||
|
) |
||||||
|
|
||||||
|
DefaultAPL:AddSpell( |
||||||
|
HealingWave:CastableIf(function(self) |
||||||
|
return Lowest:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() |
||||||
|
and Player:GetAuras():FindMy(TidalWaves):IsUp() and not Player:IsMoving() |
||||||
|
and NeedsHealing(Lowest, 85) |
||||||
|
end):SetTarget(Lowest) |
||||||
|
) |
||||||
|
|
||||||
|
DefaultAPL:AddSpell( |
||||||
|
HealingSurge:CastableIf(function(self) |
||||||
|
return Lowest:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() |
||||||
|
and NeedsHealing(Lowest, 70) |
||||||
|
end):SetTarget(Lowest) |
||||||
|
) |
||||||
|
|
||||||
|
DefaultAPL:AddSpell( |
||||||
|
PurifySpirit:CastableIf(function(self) |
||||||
|
return Lowest:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() |
||||||
|
and Lowest:GetAuras():HasAnyDispelableAura(PurifySpirit) |
||||||
|
end):SetTarget(Lowest) |
||||||
|
) |
||||||
|
|
||||||
|
-- Cooldown APL |
||||||
|
CooldownAPL:AddSpell( |
||||||
|
SpiritLinkTotem:CastableIf(function(self) |
||||||
|
return Player:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() and ShouldUseSpiritLinkTotem() |
||||||
|
end):SetTarget(Player):OnCast(function() |
||||||
|
spiritLinkTotemEnd = UpdateTotemTimer(spiritLinkTotemEnd, 6) |
||||||
|
end) |
||||||
|
) |
||||||
|
|
||||||
|
CooldownAPL:AddSpell( |
||||||
|
HealingTideTotem:CastableIf(function(self) |
||||||
|
return Player:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() and ShouldUseHealingTideTotem() |
||||||
|
end):SetTarget(Player):OnCast(function() |
||||||
|
healingTideTotemEnd = UpdateTotemTimer(healingTideTotemEnd, 10) |
||||||
|
end) |
||||||
|
) |
||||||
|
|
||||||
|
CooldownAPL:AddSpell( |
||||||
|
AncestralGuidance:CastableIf(function(self) |
||||||
|
return Player:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() |
||||||
|
and Player:GetPartyHPAround(40, 75) >= 3 |
||||||
|
end):SetTarget(Player) |
||||||
|
) |
||||||
|
|
||||||
|
CooldownAPL:AddSpell( |
||||||
|
ManaTideTotem:CastableIf(function(self) |
||||||
|
return Player:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() |
||||||
|
and Player:GetPP() <= 80 |
||||||
|
end):SetTarget(Player) |
||||||
|
) |
||||||
|
|
||||||
|
CooldownAPL:AddSpell( |
||||||
|
Ascendance:CastableIf(function(self) |
||||||
|
return Player:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() |
||||||
|
and ShouldUseAscendance() |
||||||
|
end):SetTarget(Player) |
||||||
|
) |
||||||
|
|
||||||
|
CooldownAPL:AddSpell( |
||||||
|
NaturesSwiftness:CastableIf(function(self) |
||||||
|
return Lowest:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() |
||||||
|
and NeedsHealing(Lowest, 50) |
||||||
|
end):SetTarget(Lowest) |
||||||
|
) |
||||||
|
|
||||||
|
CooldownAPL:AddSpell( |
||||||
|
EarthenWallTotem:CastableIf(function(self) |
||||||
|
return Player:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() and ShouldUseEarthenWallTotem() |
||||||
|
end):SetTarget(Player):OnCast(function() |
||||||
|
earthenWallTotemEnd = UpdateTotemTimer(earthenWallTotemEnd, 15) |
||||||
|
end) |
||||||
|
) |
||||||
|
|
||||||
|
CooldownAPL:AddSpell( |
||||||
|
Wellspring:CastableIf(function(self) |
||||||
|
return Player:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() |
||||||
|
and Player:GetPartyHPAround(30, 85) >= 3 |
||||||
|
end):SetTarget(Player) |
||||||
|
) |
||||||
|
|
||||||
|
-- Damage APL |
||||||
|
DamageAPL:AddSpell( |
||||||
|
FlameShock:CastableIf(function(self) |
||||||
|
return Target:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() |
||||||
|
and not Target:GetAuras():FindMy(FlameShock):IsUp() |
||||||
|
end):SetTarget(Target) |
||||||
|
) |
||||||
|
|
||||||
|
DamageAPL:AddSpell( |
||||||
|
LavaBurst:CastableIf(function(self) |
||||||
|
return Target:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() |
||||||
|
and Target:GetAuras():FindMy(FlameShock):IsUp() |
||||||
|
end):SetTarget(Target) |
||||||
|
) |
||||||
|
|
||||||
|
DamageAPL:AddSpell( |
||||||
|
ChainLightning:CastableIf(function(self) |
||||||
|
return Target:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() |
||||||
|
and Player:GetEnemies(10) > 2 |
||||||
|
end):SetTarget(Target) |
||||||
|
) |
||||||
|
|
||||||
|
DamageAPL:AddSpell( |
||||||
|
LightningBolt:CastableIf(function(self) |
||||||
|
return Target:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() |
||||||
|
end):SetTarget(Target) |
||||||
|
) |
||||||
|
|
||||||
|
-- Module Sync |
||||||
|
RestoShamanModule:Sync(function() |
||||||
|
if not Player:IsAffectingCombat() then |
||||||
|
-- Reset totem timers when leaving combat |
||||||
|
cloudburstTotemEnd = 0 |
||||||
|
healingStreamTotemEnd = 0 |
||||||
|
earthenWallTotemEnd = 0 |
||||||
|
spiritLinkTotemEnd = 0 |
||||||
|
healingTideTotemEnd = 0 |
||||||
|
|
||||||
|
if not Player:GetAuras():FindMy(WaterShield):IsUp() then |
||||||
|
WaterShield:Cast(Player) |
||||||
|
end |
||||||
|
ApplyEarthShield() |
||||||
|
elseif Player:IsAffectingCombat() then |
||||||
|
ApplyEarthShield() |
||||||
|
CooldownAPL:Execute() |
||||||
|
DefaultAPL:Execute() |
||||||
|
|
||||||
|
-- Use damage abilities when healing isn't needed |
||||||
|
if Player:GetPP() > 80 and Player:GetPartyHPAround(40, 95) == 0 then |
||||||
|
DamageAPL:Execute() |
||||||
|
end |
||||||
|
end |
||||||
|
end) |
||||||
|
|
||||||
|
Bastion:Register(RestoShamanModule) |
Loading…
Reference in new issue