I give up, this is good enough

main
Emlembow 4 months ago
parent 70adba914f
commit 70d691eb67
  1. 376
      RestoShaman.lua

@ -3,52 +3,40 @@ local Tinkr, Bastion = ...
local RestoShamanModule = Bastion.Module:New('RestoShaman') local RestoShamanModule = Bastion.Module:New('RestoShaman')
local Player = Bastion.UnitManager:Get('player') local Player = Bastion.UnitManager:Get('player')
local Target = Bastion.UnitManager:Get('target') local Target = Bastion.UnitManager:Get('target')
-- Initialize SpellBook
local SpellBook = Bastion.SpellBook:New() local SpellBook = Bastion.SpellBook:New()
-- Spells -- Spells
local WaterShield = SpellBook:GetSpell(52127) local WaterShield = SpellBook:GetSpell(52127)
local EarthShield = SpellBook:GetSpell(974) local EarthShield = SpellBook:GetSpell(974)
local HealingRain = SpellBook:GetSpell(73920)
local Riptide = SpellBook:GetSpell(61295) 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 HealingSurge = SpellBook:GetSpell(8004)
local Wellspring = SpellBook:GetSpell(197995) local HealingWave = SpellBook:GetSpell(77472)
local ChainHeal = SpellBook:GetSpell(1064)
local HealingRain = SpellBook:GetSpell(73920)
local Downpour = SpellBook:GetSpell(207778)
local HealingStreamTotem = SpellBook:GetSpell(5394)
local CloudburstTotem = SpellBook:GetSpell(157153)
local SpiritLinkTotem = SpellBook:GetSpell(98008) local SpiritLinkTotem = SpellBook:GetSpell(98008)
local HealingTideTotem = SpellBook:GetSpell(108280)
local AncestralGuidance = SpellBook:GetSpell(108281) local AncestralGuidance = SpellBook:GetSpell(108281)
local ManaTideTotem = SpellBook:GetSpell(16191)
local Ascendance = SpellBook:GetSpell(114052) local Ascendance = SpellBook:GetSpell(114052)
local NaturesSwiftness = SpellBook:GetSpell(378081) local Wellspring = SpellBook:GetSpell(197995)
local EarthenWallTotem = SpellBook:GetSpell(198838) local UnleashLife = SpellBook:GetSpell(73685)
local PurifySpirit = SpellBook:GetSpell(77130) local PrimordialWave = SpellBook:GetSpell(375982)
local LightningBolt = SpellBook:GetSpell(403)
local ChainLightning = SpellBook:GetSpell(421)
local FlameShock = SpellBook:GetSpell(188389)
local LavaBurst = SpellBook:GetSpell(51505) local LavaBurst = SpellBook:GetSpell(51505)
local FlameShock = SpellBook:GetSpell(188389)
local WindShear = SpellBook:GetSpell(57994)
local LightningBolt = SpellBook:GetSpell(403)
-- Buffs -- Buffs
local TidalWaves = SpellBook:GetSpell(53390) local TidalWaves = SpellBook:GetSpell(53390)
local HighTide = SpellBook:GetSpell(288675) local WaterShieldBuff = SpellBook:GetSpell(52127)
local EarthShieldBuff = SpellBook:GetSpell(383648)
-- Totem timers local UnleashLifeBuff = SpellBook:GetSpell(73685)
local cloudburstTotemEnd = 0
local healingStreamTotemEnd = 0
local earthenWallTotemEnd = 0
local spiritLinkTotemEnd = 0
local healingTideTotemEnd = 0
-- Custom Units -- Custom Units
local Lowest = Bastion.UnitManager:CreateCustomUnit('lowest', function(unit) local Lowest = Bastion.UnitManager:CreateCustomUnit('lowest', function()
local lowest = nil local lowest = nil
local lowestHP = math.huge local lowestHP = 100
Bastion.UnitManager:EnumFriends(function(unit) Bastion.UnitManager:EnumFriends(function(unit)
if unit:IsDead() or Player:GetDistance(unit) > 40 or not Player:CanSee(unit) then if unit:IsDead() or Player:GetDistance(unit) > 40 or not Player:CanSee(unit) then
@ -65,285 +53,211 @@ local Lowest = Bastion.UnitManager:CreateCustomUnit('lowest', function(unit)
return lowest or Player return lowest or Player
end) end)
-- APLs local BestTarget = Bastion.UnitManager:CreateCustomUnit('besttarget', function()
local PrePullAPL = Bastion.APL:New('prepull') local bestTarget = nil
local DefaultAPL = Bastion.APL:New('default') local highestHP = 0
local CooldownAPL = Bastion.APL:New('cooldown')
local DamageAPL = Bastion.APL:New('damage') Bastion.UnitManager:EnumEnemies(function(unit)
if unit:IsAffectingCombat() and Player:IsWithinCombatDistance(unit, 40) and Player:CanSee(unit) and Player:IsFacing(unit) then
-- Debug function local hp = unit:GetHP()
local function Debug(message) if hp > highestHP then
-- print("[RestoShaman Debug]: " .. message) bestTarget = unit
end highestHP = hp
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
end) end)
return count
end
local function ShouldUseAscendance() return bestTarget or Target
return Player:GetPartyHPAround(40, 70) >= 3 and CloudburstTotem:GetTimeSinceLastCast() < 3 end)
end
local function GetTanks() -- APLs
local tanks = {} local DefaultAPL = Bastion.APL:New('default')
Bastion.UnitManager:EnumFriends(function(unit) local CooldownAPL = Bastion.APL:New('cooldown')
if unit:IsTank() and not unit:IsDead() and Player:CanSee(unit) and Player:GetDistance(unit) <= 40 then local DefensiveAPL = Bastion.APL:New('defensive')
table.insert(tanks, unit) local DpsAPL = Bastion.APL:New('dps')
end local InterruptAPL = Bastion.APL:New('interrupt')
end)
Debug("Found " .. #tanks .. " tanks")
return tanks
end
local function ApplyEarthShield() -- Helper Functions
local tanks = GetTanks() local function GetPlayerManaPercent()
for _, tank in ipairs(tanks) do return (UnitPower("player", Enum.PowerType.Mana) / UnitPowerMax("player", Enum.PowerType.Mana)) * 100
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 end
local function NeedsHealing(unit, threshold) local function NeedsUrgentHealing()
return unit:GetHP() < threshold return Lowest:GetHP() < 70 or Player:GetPartyHPAround(30, 80) >= 3
end end
-- Pre-Pull APL -- Modify the EarthShield spell in the DefaultAPL
PrePullAPL:AddSpell( DefaultAPL:AddSpell(
WaterShield:CastableIf(function(self) EarthShield:CastableIf(function(self)
return Player:Exists() and self:IsKnownAndUsable() and not Player:GetAuras():FindMy(WaterShield):IsUp() local playerShield = Player:GetAuras():FindMy(EarthShieldBuff)
return self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() and
(not playerShield:IsUp() or playerShield:GetRemainingTime() < 30)
end):SetTarget(Player) end):SetTarget(Player)
) )
-- Default APL -- 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( DefaultAPL:AddSpell(
Riptide:CastableIf(function(self) Riptide:CastableIf(function(self)
return Lowest:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() return Lowest:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling()
and NeedsHealing(Lowest, 90) and Lowest:GetHP() < 95 and not Lowest:GetAuras():FindMy(TidalWaves):IsUp()
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) end):SetTarget(Lowest)
) )
DefaultAPL:AddSpell( DefaultAPL:AddSpell(
UnleashLife:CastableIf(function(self) UnleashLife:CastableIf(function(self)
return Lowest:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() return Lowest:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling()
and NeedsHealing(Lowest, 80) and Lowest:GetHP() < 80
end):SetTarget(Lowest) end):SetTarget(Lowest)
) )
DefaultAPL:AddSpell( DefaultAPL:AddSpell(
HealingRain:CastableIf(function(self) HealingSurge: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() return Lowest:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling()
and (Player:GetAuras():FindMy(HighTide):IsUp() or Player:GetAuras():FindMy(NaturesSwiftness):IsUp()) and Lowest:GetHP() < 70 and Player:GetAuras():FindMy(TidalWaves):IsUp()
and not Player:IsMoving() and NeedsHealing(Lowest, 75)
end):SetTarget(Lowest) end):SetTarget(Lowest)
) )
DefaultAPL:AddSpell( DefaultAPL:AddSpell(
HealingWave:CastableIf(function(self) HealingWave: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:GetAuras():FindMy(TidalWaves):IsUp() and not Player:IsMoving() and Lowest:GetHP() < 85
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) end):SetTarget(Lowest)
) )
DefaultAPL:AddSpell( DefaultAPL:AddSpell(
PurifySpirit:CastableIf(function(self) ChainHeal:CastableIf(function(self)
return Lowest:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() return self:IsKnownAndUsable() and not Player:IsCastingOrChanneling()
and Lowest:GetAuras():HasAnyDispelableAura(PurifySpirit) and Player:GetPartyHPAround(40, 85) >= 3
end):SetTarget(Lowest) end):SetTarget(Lowest)
) )
-- Cooldown APL -- Cooldown APL
CooldownAPL:AddSpell( CooldownAPL:AddSpell(
SpiritLinkTotem:CastableIf(function(self) CloudburstTotem:CastableIf(function(self)
return Player:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() and ShouldUseSpiritLinkTotem() return self:IsKnownAndUsable() and not Player:IsCastingOrChanneling()
end):SetTarget(Player):OnCast(function() and Player:GetPartyHPAround(40, 80) >= 3
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) end):SetTarget(Player)
) )
CooldownAPL:AddSpell( CooldownAPL:AddSpell(
ManaTideTotem:CastableIf(function(self) HealingStreamTotem:CastableIf(function(self)
return Player:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() return self:IsKnownAndUsable() and not Player:IsCastingOrChanneling()
and Player:GetPP() <= 80 and not CloudburstTotem:IsKnownAndUsable() and Player:GetPartyHPAround(40, 90) >= 2
end):SetTarget(Player) end):SetTarget(Player)
) )
CooldownAPL:AddSpell( CooldownAPL:AddSpell(
Ascendance:CastableIf(function(self) SpiritLinkTotem:CastableIf(function(self)
return Player:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() return self:IsKnownAndUsable() and not Player:IsCastingOrChanneling()
and ShouldUseAscendance() and Player:GetPartyHPAround(30, 70) >= 3
end):SetTarget(Player) end):SetTarget(Player)
) )
CooldownAPL:AddSpell( CooldownAPL:AddSpell(
NaturesSwiftness:CastableIf(function(self) AncestralGuidance:CastableIf(function(self)
return Lowest:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() return self:IsKnownAndUsable() and not Player:IsCastingOrChanneling()
and NeedsHealing(Lowest, 50) and Player:GetPartyHPAround(40, 75) >= 3
end):SetTarget(Lowest) end):SetTarget(Player)
)
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( CooldownAPL:AddSpell(
Wellspring:CastableIf(function(self) Ascendance:CastableIf(function(self)
return Player:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() return self:IsKnownAndUsable() and not Player:IsCastingOrChanneling()
and Player:GetPartyHPAround(30, 85) >= 3 and Player:GetPartyHPAround(40, 60) >= 3
end):SetTarget(Player) end):SetTarget(Player)
) )
-- Damage APL -- DPS APL
DamageAPL:AddSpell( DpsAPL:AddSpell(
FlameShock:CastableIf(function(self) FlameShock:CastableIf(function(self)
return Target:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() return BestTarget:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling()
and not Target:GetAuras():FindMy(FlameShock):IsUp() and not BestTarget:GetAuras():FindMy(FlameShock):IsUp()
end):SetTarget(Target) end):SetTarget(BestTarget)
) )
DamageAPL:AddSpell( DpsAPL:AddSpell(
LavaBurst:CastableIf(function(self) LavaBurst:CastableIf(function(self)
return Target:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() return BestTarget:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling()
and Target:GetAuras():FindMy(FlameShock):IsUp() and BestTarget:GetAuras():FindMy(FlameShock):IsUp()
end):SetTarget(Target) end):SetTarget(BestTarget)
) )
DamageAPL:AddSpell( DpsAPL:AddSpell(
ChainLightning:CastableIf(function(self) LightningBolt:CastableIf(function(self)
return Target:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() return BestTarget:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling()
and Player:GetEnemies(10) > 2 end):SetTarget(BestTarget)
end):SetTarget(Target)
) )
DamageAPL:AddSpell( -- Interrupt APL
LightningBolt:CastableIf(function(self) InterruptAPL:AddSpell(
return Target:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() WindShear:CastableIf(function(self)
end):SetTarget(Target) return BestTarget:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling()
and BestTarget:IsCasting() and BestTarget:IsInterruptible()
and BestTarget:GetChannelOrCastPercentComplete() >= 50
end):SetTarget(BestTarget)
) )
-- Module Sync -- Modify the out of combat Earth Shield logic in the Module Sync function
RestoShamanModule:Sync(function() RestoShamanModule:Sync(function()
if Player:IsMounted() then
return
end
-- Out of combat healing and buffs
if not Player:IsAffectingCombat() then if not Player:IsAffectingCombat() then
-- Reset totem timers when leaving combat if not Player:GetAuras():FindMy(WaterShieldBuff):IsUp() then
cloudburstTotemEnd = 0
healingStreamTotemEnd = 0
earthenWallTotemEnd = 0
spiritLinkTotemEnd = 0
healingTideTotemEnd = 0
if not Player:GetAuras():FindMy(WaterShield):IsUp() then
WaterShield:Cast(Player) WaterShield:Cast(Player)
elseif not Player:GetAuras():FindMy(EarthShieldBuff):IsUp() then
EarthShield:Cast(Player)
elseif Lowest:GetHP() < 90 then
DefaultAPL:Execute()
end end
ApplyEarthShield() return
elseif Player:IsAffectingCombat() then end
ApplyEarthShield()
-- In combat
InterruptAPL:Execute()
if NeedsUrgentHealing() then
CooldownAPL:Execute() CooldownAPL:Execute()
DefaultAPL:Execute() DefaultAPL:Execute()
else
if GetPlayerManaPercent() > 80 and BestTarget:Exists() then
DpsAPL:Execute()
end
if Riptide:GetCharges() >= 2 then
Bastion.UnitManager:EnumFriends(function(unit)
if unit:GetHP() < 95 and not unit:GetAuras():FindMy(TidalWaves):IsUp() then
Riptide:Cast(unit)
return true -- Stop enumerating after casting
end
end)
end
if HealingWave:IsKnownAndUsable() and Lowest:GetHP() < 90 then
HealingWave:Cast(Lowest)
end
end
-- Use damage abilities when healing isn't needed -- AoE Healing
if Player:GetPP() > 80 and Player:GetPartyHPAround(40, 95) == 0 then if Player:GetPartyHPAround(30, 85) >= 4 then
DamageAPL:Execute() if HealingRain:IsKnownAndUsable() then
local loc = Bastion.UnitManager:FindFriendsCentroid(10, 40)
if loc then
HealingRain:Cast(Player):OnCast(function(self)
self:Click(loc)
end)
end
elseif Downpour:IsKnownAndUsable() then
local loc = Bastion.UnitManager:FindFriendsCentroid(10, 40)
if loc then
Downpour:Cast(Player):OnCast(function(self)
self:Click(loc)
end)
end
elseif Wellspring:IsKnownAndUsable() then
Wellspring:Cast(Player)
end end
end end
end) end)

Loading…
Cancel
Save