Updates to resto druid, and complete overhall of aura manager

notifications
4n0n 2 years ago
parent bd174b4b06
commit de09096a71
  1. 107
      scripts/restodruid.lua
  2. 12
      src/Aura/Aura.lua
  3. 218
      src/AuraTable/AuraTable.lua
  4. 3
      src/EventManager/EventManager.lua
  5. 8
      src/Spell/Spell.lua
  6. 3
      src/UnitManager/UnitManager.lua

@ -1,7 +1,7 @@
local Tinkr, Bastion = ...
local RestoModule = Bastion.Module:New('resto_druid')
local Evaluator = Tinkr.Util.Evaluator
local Player = Bastion.UnitManager:Get('player')
local None = Bastion.UnitManager:Get('none')
local Target = Bastion.UnitManager:Get('target')
@ -177,7 +177,7 @@ end)
local PurgeTarget = Bastion.UnitManager:CreateCustomUnit('purge', function(unit)
local purge = nil
Bastion.UnitManager:EnumEnemies(function(unit)
Bastion.UnitManager:EnumNameplates(function(unit)
if unit:IsDead() then
return false
end
@ -193,6 +193,7 @@ local PurgeTarget = Bastion.UnitManager:CreateCustomUnit('purge', function(unit)
if not unit:IsDead() and Player:CanSee(unit) and
unit:GetAuras():HasAnyStealableAura() then
purge = unit
return true
end
end)
@ -317,6 +318,48 @@ local SwiftmendUnit = Bastion.UnitManager:CreateCustomUnit('swiftmend', function
return lowest
end)
local WildGrowthUnit = Bastion.UnitManager:CreateCustomUnit('wildgrowth', function(unit)
local lowest = nil
local lowestHP = math.huge
Bastion.UnitManager:EnumFriends(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:CanSee(unit) and (
(
Player:GetAuras():FindMy(SoulOfTheForest):IsUp() and
(
Player:GetAuras():FindMy(SoulOfTheForest):GetRemainingTime() <= 5 or
unit:GetPartyHPAround(30, 90) >= 2)) or
(unit:GetPartyHPAround(30, 90) >= 3 or unit:GetPartyHPAround(30, 85) >= 2))
then
local hp = unit:GetHP()
if hp < lowestHP then
lowest = unit
lowestHP = hp
end
end
end)
if lowest == nil then
lowest = None
end
return lowest
end)
local RestoCommands = Bastion.Command:New('resto')
local PLACE_EFFLO = false
@ -385,7 +428,14 @@ DefaultAPL:AddSpell(
return Player:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() and
self:IsInRange(Player) and (Player:GetPartyHPAround(40, 65) >= 2 or Player:GetPartyHPAround(40, 70) >= 3) and
(not ConvokeTheSpirits:IsKnownAndUsable() and ConvokeTheSpirits:GetTimeSinceLastCast() > 7) and
WildGrowth:GetTimeSinceLastCast() <= 4
WildGrowth:GetTimeSinceLastCast() <= 6
end):SetTarget(Player)
)
DefaultAPL:AddSpell(
NaturesVigil:CastableIf(function(self)
return Player:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() and
self:IsInRange(Player) and Flourish:GetTimeSinceLastCast() <= 5
end):SetTarget(Player)
)
@ -411,22 +461,23 @@ DefaultAPL:AddSpell(
DefaultAPL:AddSpell(
WildGrowth:CastableIf(function(self)
return Lowest:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling()
and Player:CanSee(Lowest) and
return WildGrowthUnit:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling()
and Player:CanSee(WildGrowthUnit) and
(
(
Player:GetAuras():FindMy(SoulOfTheForest):IsUp() and
(
Player:GetAuras():FindMy(SoulOfTheForest):GetRemainingTime() <= 5 or
Lowest:GetPartyHPAround(30, 90) >= 2)) or
(Lowest:GetPartyHPAround(30, 90) >= 3 or Lowest:GetPartyHPAround(30, 85) >= 2)) and not Player:IsMoving()
end):SetTarget(Lowest)
WildGrowthUnit:GetPartyHPAround(30, 90) >= 2)) or
(WildGrowthUnit:GetPartyHPAround(30, 90) >= 3 or WildGrowthUnit:GetPartyHPAround(30, 85) >= 2)) and
not Player:IsMoving()
end):SetTarget(WildGrowthUnit)
)
DefaultAPL:AddSpell(
Regrowth:CastableIf(function(self)
return Lowest:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling()
and Player:CanSee(Lowest) and Lowest:GetHP() < 50 and
and Player:CanSee(Lowest) and Lowest:GetHP() < 65 and
Player:GetAuras():FindMy(SoulOfTheForest):IsUp() and not Player:IsMoving()
end):SetTarget(Lowest)
)
@ -456,6 +507,26 @@ DefaultAPL:AddSpell(
end):SetTarget(Lowest)
)
DefaultAPL:AddSpell(
Rejuvenation:CastableIf(function(self)
return RejuvUnit:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling()
and Player:CanSee(RejuvUnit) and RejuvUnit:GetHP() <= 94 and
not Player:GetAuras():FindMy(SoulOfTheForest):IsUp()
end):SetTarget(RejuvUnit)
)
DefaultAPL:AddSpell(
Regrowth:CastableIf(function(self)
return Lowest:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling()
and Player:CanSee(Lowest) and
(
not Player:GetAuras():FindMy(Regrowth):IsUp() and Lowest:GetHP() < 70 or
(Lowest:GetHP() <= 85 and Player:GetAuras():FindMy(ClearCasting):IsUp())) and
not Player:GetAuras():FindMy(SoulOfTheForest):IsUp() and
not Player:IsMoving()
end):SetTarget(Lowest)
)
DefaultAPL:AddSpell(
Lifebloom:CastableIf(function(self)
return Player:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling()
@ -476,24 +547,6 @@ DefaultAPL:AddSpell(
end):SetTarget(Tank)
)
DefaultAPL:AddSpell(
Rejuvenation:CastableIf(function(self)
return RejuvUnit:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling()
and Player:CanSee(RejuvUnit) and RejuvUnit:GetHP() <= 94 and
not Player:GetAuras():FindMy(SoulOfTheForest):IsUp()
end):SetTarget(RejuvUnit)
)
DefaultAPL:AddSpell(
Regrowth:CastableIf(function(self)
return Lowest:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling()
and Player:CanSee(Lowest) and
(Lowest:GetHP() < 70 or (Lowest:GetHP() <= 85 and Player:GetAuras():FindMy(ClearCasting):IsUp())) and
not Player:GetAuras():FindMy(Regrowth):IsUp() and not Player:GetAuras():FindMy(SoulOfTheForest):IsUp() and
not Player:IsMoving()
end):SetTarget(Lowest)
)
DefaultAPL:AddSpell(
Sunfire:CastableIf(function(self)
return Target:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling()

@ -69,6 +69,7 @@ function Aura:New(unit, index, type)
castByPlayer = castByPlayer,
nameplateShowAll = nameplateShowAll,
timeMod = timeMod,
auraInstanceID = nil,
index = index,
type = type,
@ -94,6 +95,7 @@ function Aura:CreateFromUnitAuraInfo(unitAuraInfo)
castByPlayer = unitAuraInfo.isFromPlayerOrPlayerPet,
nameplateShowAll = unitAuraInfo.nameplateShowAll,
timeMod = unitAuraInfo.timeMod,
auraInstanceID = unitAuraInfo.auraInstanceID,
index = nil,
type = unitAuraInfo.isHarmful and "HARMFUL" or "HELPFUL",
@ -111,6 +113,11 @@ function Aura:IsUp()
return self:IsValid() and (self:GetDuration() == 0 or self:GetRemainingTime() > 0)
end
-- Check if the aura is down
function Aura:IsDown()
return not self:IsUp()
end
-- Get the auras index
function Aura:GetIndex()
return self.aura.index
@ -217,6 +224,11 @@ function Aura:IsDebuff()
return self.aura.type == "HARMFUL"
end
-- Get aura instance id
function Aura:GetAuraInstanceID()
return self.aura.auraInstanceID
end
-- Check if the aura is dispelable by a spell
function Aura:IsDispelableBySpell(spell)
if self:GetDispelType() == nil then

@ -4,6 +4,14 @@ local Tinkr, Bastion = ...
local AuraTable = {}
AuraTable.__index = AuraTable
local function tsize(t)
local keys = {}
for k, v in pairs(t) do
table.insert(keys, k)
end
return keys[#keys]
end
-- Constructor
function AuraTable:New(unit)
local self = setmetatable({}, AuraTable)
@ -18,42 +26,84 @@ function AuraTable:New(unit)
self.playerAppliedDebuffs = {}
self.playerAuras = {}
self.guid = unit:GetGUID()
self.instanceIDLookup = {}
Bastion.EventManager:RegisterWoWEvent('UNIT_AURA', function(unit, auras)
local u = Bastion.UnitManager[unit]
if not self.unit:IsUnit(unit) then
if not self.unit:IsUnit(u) then
return
end
local isFullUpdate = auras.isFullUpdate
if isFullUpdate then
self:Update()
print("Full update requested for " .. unit)
return
end
local addedAuras = auras.addedAuras
local removedAuras = auras.removedAuraInstanceIDs
local updatedAuras = auras.updatedAuraInstanceIDs
-- DevTools_Dump(addedAuras)
if updatedAuras and #updatedAuras > 0 then
for i = 1, #updatedAuras do
local id = updatedAuras[i]
local newAura = C_UnitAuras.GetAuraDataByAuraInstanceID(unit, id);
if newAura then
local aura = Bastion.Aura:CreateFromUnitAuraInfo(newAura)
self:UpdateInstanceID(id, aura)
else
print("Instance ID " .. id .. " not found" .. " for unit " .. unit)
end
end
end
-- Remove auras
if removedAuras and #removedAuras > 0 then
for i = 1, #removedAuras do
self:RemoveInstanceID(removedAuras[i])
end
end
if #addedAuras > 0 then
-- Add auras
if addedAuras and #addedAuras > 0 then
for i = 1, #addedAuras do
local aura = Bastion.Aura:CreateFromUnitAuraInfo(addedAuras[i])
if aura:IsBuff() then
if aura:GetSource():Exists() and aura:GetSource():IsUnit(Bastion.UnitManager['player']) then
if not self.playerAppliedBuffs[aura:GetSpell():GetID()] then
self.playerAppliedBuffs[aura:GetSpell():GetID()] = {}
end
table.insert(self.playerAppliedBuffs[aura:GetSpell():GetID()], aura)
self.playerAppliedBuffs[aura:GetSpell():GetID()][aura:GetAuraInstanceID()] = aura
self.instanceIDLookup[aura:GetAuraInstanceID()] = { 'playerAppliedBuffs',
aura:GetSpell():GetID() }
else
if not self.buffs[aura:GetSpell():GetID()] then
self.buffs[aura:GetSpell():GetID()] = {}
end
table.insert(self.buffs[aura:GetSpell():GetID()], aura)
self.buffs[aura:GetSpell():GetID()][aura:GetAuraInstanceID()] = aura
self.instanceIDLookup[aura:GetAuraInstanceID()] = { 'buffs',
aura:GetSpell():GetID() }
end
else
if aura:GetSource():Exists() and aura:GetSource():IsUnit(Bastion.UnitManager['player']) then
if not self.playerAppliedDebuffs[aura:GetSpell():GetID()] then
self.playerAppliedDebuffs[aura:GetSpell():GetID()] = {}
end
table.insert(self.playerAppliedDebuffs[aura:GetSpell():GetID()], aura)
self.playerAppliedDebuffs[aura:GetSpell():GetID()][aura:GetAuraInstanceID()] = aura
self.instanceIDLookup[aura:GetAuraInstanceID()] = { 'playerAppliedDebuffs',
aura:GetSpell():GetID() }
else
if not self.debuffs[aura:GetSpell():GetID()] then
self.debuffs[aura:GetSpell():GetID()] = {}
end
table.insert(self.debuffs[aura:GetSpell():GetID()], aura)
self.debuffs[aura:GetSpell():GetID()][aura:GetAuraInstanceID()] = aura
self.instanceIDLookup[aura:GetAuraInstanceID()] = { 'debuffs', aura:GetSpell():GetID() }
end
end
end
@ -63,44 +113,84 @@ function AuraTable:New(unit)
return self
end
function AuraTable:RemoveInstanceID(instanceID)
if not self.instanceIDLookup[instanceID] then
return
end
local t, id = unpack(self.instanceIDLookup[instanceID])
-- print("Removing aura from table: " .. t .. " " .. id .. " " .. index .. "")
local a = self[t][id][instanceID]
if a:GetAuraInstanceID() ~= instanceID then
print("Instance ID mismatch: " .. a:GetAuraInstanceID() .. " " .. instanceID)
end
self[t][id][instanceID] = nil
self.instanceIDLookup[instanceID] = nil
end
function AuraTable:UpdateInstanceID(instanceID, newAura)
if not self.instanceIDLookup[instanceID] then
return
end
local t, id = unpack(self.instanceIDLookup[instanceID])
-- print("Updating aura in table: " .. t .. " " .. id .. " " .. index .. "")
self[t][id][instanceID] = newAura
end
-- Get a units buffs
function AuraTable:GetUnitBuffs()
for i = 1, 40 do
local aura = Bastion.Aura:New(self.unit, i, 'HELPFUL')
AuraUtil.ForEachAura(self.unit.unit, 'HELPFUL', nil, function(a)
local aura = Bastion.Aura:CreateFromUnitAuraInfo(a)
if aura:IsValid() then
if aura:GetSource():Exists() and aura:GetSource():IsUnit(Bastion.UnitManager['player']) then
if not self.playerAppliedBuffs[aura:GetSpell():GetID()] then
self.playerAppliedBuffs[aura:GetSpell():GetID()] = {}
end
table.insert(self.playerAppliedBuffs[aura:GetSpell():GetID()], aura)
self.playerAppliedBuffs[aura:GetSpell():GetID()][aura:GetAuraInstanceID()] = aura
self.instanceIDLookup[aura:GetAuraInstanceID()] = { 'playerAppliedBuffs',
aura:GetSpell():GetID() }
else
if not self.buffs[aura:GetSpell():GetID()] then
self.buffs[aura:GetSpell():GetID()] = {}
end
table.insert(self.buffs[aura:GetSpell():GetID()], aura)
self.buffs[aura:GetSpell():GetID()][aura:GetAuraInstanceID()] = aura
self.instanceIDLookup[aura:GetAuraInstanceID()] = { 'buffs',
aura:GetSpell():GetID() }
end
end
end
end, true)
end
-- Get a units debuffs
function AuraTable:GetUnitDebuffs()
for i = 1, 40 do
local aura = Bastion.Aura:New(self.unit, i, 'HARMFUL')
AuraUtil.ForEachAura(self.unit.unit, 'HARMFUL', nil, function(a)
local aura = Bastion.Aura:CreateFromUnitAuraInfo(a)
if aura:IsValid() then
if aura:GetSource():Exists() and aura:GetSource():IsUnit(Bastion.UnitManager['player']) then
if not self.playerAppliedDebuffs[aura:GetSpell():GetID()] then
self.playerAppliedDebuffs[aura:GetSpell():GetID()] = {}
end
table.insert(self.playerAppliedDebuffs[aura:GetSpell():GetID()], aura)
self.playerAppliedDebuffs[aura:GetSpell():GetID()][aura:GetAuraInstanceID()] = aura
self.instanceIDLookup[aura:GetAuraInstanceID()] = { 'playerAppliedDebuffs',
aura:GetSpell():GetID() }
else
if not self.debuffs[aura:GetSpell():GetID()] then
self.debuffs[aura:GetSpell():GetID()] = {}
end
table.insert(self.debuffs[aura:GetSpell():GetID()], aura)
self.debuffs[aura:GetSpell():GetID()][aura:GetAuraInstanceID()] = aura
self.instanceIDLookup[aura:GetAuraInstanceID()] = { 'debuffs',
aura:GetSpell():GetID() }
end
end
end
end, true)
end
local function merge(t1, t2)
@ -121,50 +211,59 @@ end
-- Update auras
function AuraTable:Update()
self:Clear()
self.lastUpdate = GetTime()
-- self.lastUpdate = GetTime()
self:GetUnitBuffs()
self:GetUnitDebuffs()
self.auras = merge(self.buffs, self.debuffs)
self.playerAuras = merge(self.playerAppliedBuffs, self.playerAppliedDebuffs)
-- self.auras = merge(self.buffs, self.debuffs)
-- self.playerAuras = merge(self.playerAppliedBuffs, self.playerAppliedDebuffs)
end
-- Get a units auras
function AuraTable:GetUnitAuras()
if not self.did then
self.did = true
self:Update()
end
-- For token units, we need to check if the GUID has changed
if self.unit:GetGUID() ~= self.guid then
self.guid = self.unit:GetGUID()
self:Update()
return self.auras
return merge(self.buffs, self.debuffs)
end
-- Cache the auras for the unit so we don't have to query the API every time we want to check if the unit has a specific aura or not
-- If it's less than .4 seconds since the last time we queried the API, return the cached auras
if self.lastUpdate and GetTime() - self.lastUpdate < 0.5 then
return self.auras
end
-- -- Cache the auras for the unit so we don't have to query the API every time we want to check if the unit has a specific aura or not
-- -- If it's less than .4 seconds since the last time we queried the API, return the cached auras
-- if self.lastUpdate and GetTime() - self.lastUpdate < 0.5 then
-- return merge(self.buffs, self.debuffs)
-- end
self:Update()
return self.auras
-- self:Update()
return merge(self.buffs, self.debuffs)
end
-- Get a units auras
function AuraTable:GetMyUnitAuras()
if not self.did then
self.did = true
self:Update()
end
-- For token units, we need to check if the GUID has changed
if self.unit:GetGUID() ~= self.guid then
self.guid = self.unit:GetGUID()
self:Update()
return self.playerAuras
return merge(self.playerAppliedBuffs, self.playerAppliedDebuffs)
end
-- Cache the auras for the unit so we don't have to query the API every time we want to check if the unit has a specific aura or not
-- If it's less than .4 seconds since the last time we queried the API, return the cached auras
if self.lastUpdate and GetTime() - self.lastUpdate < 0.5 then
return self.playerAuras
end
-- -- Cache the auras for the unit so we don't have to query the API every time we want to check if the unit has a specific aura or not
-- -- If it's less than .4 seconds since the last time we queried the API, return the cached auras
-- if self.lastUpdate and GetTime() - self.lastUpdate < 0.5 then
-- return merge(self.playerAppliedBuffs, self.playerAppliedDebuffs)
-- end
self:Update()
return self.playerAuras
-- self:Update()
return merge(self.playerAppliedBuffs, self.playerAppliedDebuffs)
end
-- Clear the aura table
@ -175,15 +274,26 @@ function AuraTable:Clear()
self.playerAppliedBuffs = {}
self.playerAppliedDebuffs = {}
self.playerAuras = {}
self.instanceIDLookup = {}
end
-- Check if the unit has a specific aura
function AuraTable:Find(spell)
local auras = self:GetUnitAuras()
local aura = auras[spell:GetID()]
local aurasub = auras[spell:GetID()]
if aura then
return aura[1]
if not aurasub then
return Bastion.Aura:New()
end
for k, a in pairs(aurasub) do
if a ~= nil then
if a:IsUp() then -- Handle expired and non refreshed dropoffs not coming in UNIT_AURA
return a
else
self:RemoveInstanceID(a:GetAuraInstanceID())
end
end
end
return Bastion.Aura:New()
@ -191,10 +301,20 @@ end
function AuraTable:FindMy(spell)
local auras = self:GetMyUnitAuras()
local aura = auras[spell:GetID()]
local aurasub = auras[spell:GetID()]
if aura then
return aura[1]
if not aurasub then
return Bastion.Aura:New()
end
for k, a in pairs(aurasub) do
if a ~= nil then
if a:IsUp() then -- Handle expired and non refreshed dropoffs not coming in UNIT_AURA
return a
else
self:RemoveInstanceID(a:GetAuraInstanceID())
end
end
end
return Bastion.Aura:New()
@ -204,8 +324,12 @@ end
function AuraTable:HasAnyStealableAura()
for _, auras in pairs(self:GetUnitAuras()) do
for _, aura in pairs(auras) do
if aura:GetIsStealable() then
return true
if aura:IsUp() then -- Handle expired and non refreshed dropoffs not coming in UNIT_AURA
if aura:GetIsStealable() then
return true
end
else
self:RemoveInstanceID(aura:GetAuraInstanceID())
end
end
end
@ -217,8 +341,12 @@ end
function AuraTable:HasAnyDispelableAura(spell)
for _, auras in pairs(self:GetUnitAuras()) do
for _, aura in pairs(auras) do
if aura:IsDebuff() and aura:IsDispelableBySpell(spell) then
return true
if aura:IsUp() then -- Handle expired and non refreshed dropoffs not coming in UNIT_AURA
if aura:IsDebuff() and aura:IsDispelableBySpell(spell) then
return true
end
else
self:RemoveInstanceID(aura:GetAuraInstanceID())
end
end
end

@ -27,7 +27,6 @@ function EventManager:New()
end
end)
return self
end
@ -36,6 +35,7 @@ function EventManager:RegisterEvent(event, handler)
if not self.events[event] then
self.events[event] = {}
end
table.insert(self.events[event], handler)
end
@ -45,6 +45,7 @@ function EventManager:RegisterWoWEvent(event, handler)
self.wowEventHandlers[event] = {}
self.frame:RegisterEvent(event)
end
table.insert(self.wowEventHandlers[event], handler)
end

@ -102,8 +102,14 @@ function Spell:Cast(unit, condition)
-- Check if the mouse was looking
self.wasLooking = IsMouselooking()
-- if unit.unit contains 'nameplate' then we need to use Object wrapper to cast
local u = unit.unit
if string.find(u, 'nameplate') then
u = Object(u)
end
-- Cast the spell
CastSpellByName(self:GetName(), unit.unit)
CastSpellByName(self:GetName(), u)
Bastion:Debug("Casting", self)

@ -214,7 +214,8 @@ end
-- Enum enemies (nameplates)
function UnitManager:EnumNameplates(cb)
for i = 1, 50 do
local n = GetNumNameplates()
for i = 1, n do
local unit = self:Get('nameplate' .. i)
if unit:IsValid() then
if cb(unit) then

Loading…
Cancel
Save