Objectmanager update

To allow for healing tests in Proving Grounds
main
Ofrex 2 years ago
parent bd58c55102
commit 8c691161e4
  1. 726
      scripts/discpriest.lua
  2. 400
      scripts/feraldruid.lua
  3. 337
      scripts/guardiandruid.lua
  4. 476
      scripts/holypriest.lua
  5. 608
      scripts/outlawbak.lua
  6. 906
      scripts/restodruid.lua
  7. 1980
      scripts/subtlety.lua
  8. 39
      src/APL/APL.lua
  9. 40
      src/Aura/Aura.lua
  10. 37
      src/AuraTable/AuraTable.lua
  11. 10
      src/Cache/Cache.lua
  12. 13
      src/Cacheable/Cacheable.lua
  13. 8
      src/Class/Class.lua
  14. 4
      src/ClassMagic/ClassMagic.lua
  15. 13
      src/Command/Command.lua
  16. 12
      src/EventManager/EventManager.lua
  17. 59
      src/Item/Item.lua
  18. 4
      src/ItemBook/ItemBook.lua
  19. 35
      src/List/List.lua
  20. 13
      src/Module/Module.lua
  21. 6
      src/MythicPlusUtils/MythicPlusUtils.lua
  22. 45
      src/NotificationsList/NotificationsList.lua
  23. 13
      src/ObjectManager/ObjectManager.lua
  24. 10
      src/Refreshable/Refreshable.lua
  25. 65
      src/Spell/Spell.lua
  26. 22
      src/SpellBook/SpellBook.lua
  27. 7
      src/Timer/Timer.lua
  28. 253
      src/Unit/Unit.lua
  29. 25
      src/UnitManager/UnitManager.lua
  30. 51
      src/Vector3/Vector3.lua
  31. 45
      src/_bastion.lua

@ -0,0 +1,726 @@
local Tinkr, Bastion = ...
local DiscModule = Bastion.Module:New('disc')
local Evaluator = Tinkr.Util.Evaluator
local Player = Bastion.UnitManager:Get('player')
local None = Bastion.UnitManager:Get('none')
local Target = Bastion.UnitManager:Get('target')
local myconf = Tinkr.Util.Config:New('disc_priest')
local AngelicFeather = Bastion.SpellBook:GetSpell(121536)
local DesperatePrayer = Bastion.SpellBook:GetSpell(19236)
local DispelMagic = Bastion.SpellBook:GetSpell(528)
local Fade = Bastion.SpellBook:GetSpell(586)
local FlashHeal = Bastion.SpellBook:GetSpell(2061)
local LeapofFaith = Bastion.SpellBook:GetSpell(73325)
local Levitate = Bastion.SpellBook:GetSpell(1706)
local MassDispel = Bastion.SpellBook:GetSpell(32375)
local MindBlast = Bastion.SpellBook:GetSpell(8092)
local MindSoothe = Bastion.SpellBook:GetSpell(453)
local MindVision = Bastion.SpellBook:GetSpell(2096)
local PowerInfusion = Bastion.SpellBook:GetSpell(10060)
local PowerWordFortitude = Bastion.SpellBook:GetSpell(21562)
local PowerWordLife = Bastion.SpellBook:GetSpell(373481)
local PowerWordShield = Bastion.SpellBook:GetSpell(17)
local PsychicScream = Bastion.SpellBook:GetSpell(8122)
local Renew = Bastion.SpellBook:GetSpell(139)
local Resurrection = Bastion.SpellBook:GetSpell(2006)
local ShadowWordDeath = Bastion.SpellBook:GetSpell(32379)
local Shadowfiend = Bastion.SpellBook:GetSpell(34433)
local Smite = Bastion.SpellBook:GetSpell(585)
local VampiricEmbrace = Bastion.SpellBook:GetSpell(15286)
local VoidTendrils = Bastion.SpellBook:GetSpell(108920)
local FocusedWill = Bastion.SpellBook:GetSpell(45243)
local BoonoftheAscended = Bastion.SpellBook:GetSpell(325013)
local Apotheosis = Bastion.SpellBook:GetSpell(392941)
local DivineStar = Bastion.SpellBook:GetSpell(110744)
local MassResurrection = Bastion.SpellBook:GetSpell(212036)
local PainSuppression = Bastion.SpellBook:GetSpell(33206)
local Penance = Bastion.SpellBook:GetSpell(47540)
local PowerWordBarrier = Bastion.SpellBook:GetSpell(62618)
local PowerWordRadiance = Bastion.SpellBook:GetSpell(194509)
local PurgetheWicked = Bastion.SpellBook:GetSpell(204197)
local Purify = Bastion.SpellBook:GetSpell(527)
local Rapture = Bastion.SpellBook:GetSpell(47536)
local Schism = Bastion.SpellBook:GetSpell(214621)
local ShadowCovenant = Bastion.SpellBook:GetSpell(314867)
local Atonement = Bastion.SpellBook:GetSpell(81749)
local MasteryGrace = Bastion.SpellBook:GetSpell(271534)
local SinsoftheMany = Bastion.SpellBook:GetSpell(280391)
local Apotheosis = Bastion.SpellBook:GetSpell(392941)
local DivineStar = Bastion.SpellBook:GetSpell(110744)
local MassResurrection = Bastion.SpellBook:GetSpell(212036)
local Purify = Bastion.SpellBook:GetSpell(527)
local ShadowWordPain = Bastion.SpellBook:GetSpell(204197)
local DivineStar = Bastion.SpellBook:GetSpell(110744)
local ShadowWordPain = Bastion.SpellBook:GetSpell(204197)
local Lowest = Bastion.UnitManager:CreateCustomUnit('lowest', function(unit)
local lowest = nil
local lowestHP = math.huge
Bastion.UnitManager:EnumFriends(function(unit)
if unit:IsDead() then
return false
end
if Player:GetDistance(unit) > 40 then
return false
end
if not Player:CanSee(unit) then
return false
end
local hp = unit:GetHP()
if hp < lowestHP then
lowest = unit
lowestHP = hp
end
end)
if not lowest then
lowest = Player
end
return lowest
end)
local PurgeTarget = Bastion.UnitManager:CreateCustomUnit('purge', function(unit)
local purge = nil
Bastion.UnitManager:EnumEnemies(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 not unit:IsDead() and Player:CanSee(unit) and
unit:GetAuras():HasAnyStealableAura() then
purge = unit
return true
end
end)
if purge == nil then
purge = None
end
return purge
end)
local DispelTarget = Bastion.UnitManager:CreateCustomUnit('dispel', 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 not unit:IsDead() and Player:CanSee(unit) and
unit:GetAuras():HasAnyDispelableAura(Purify) 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 Tank = Bastion.UnitManager:CreateCustomUnit('tank', function(unit)
local tank = nil
Bastion.UnitManager:EnumFriends(function(unit)
if Player:GetDistance(unit) > 40 then return false end
if not Player:CanSee(unit) then return false end
if unit:IsDead() then return false end
if unit:IsTank() then
tank = unit
return true
end
return false
end)
if tank == nil then
tank = None
end
return tank
end)
local Explosive = Bastion.UnitManager:CreateCustomUnit('explosive', function(unit)
local explosive = nil
Bastion.UnitManager:EnumEnemies(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:InMelee(unit) and unit:GetID() == 120651 and Player:IsFacing(unit) then
explosive = unit
return true
end
end)
if explosive == nil then
explosive = None
end
return explosive
end)
local RenewUnit = Bastion.UnitManager:CreateCustomUnit('renew', 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 not unit:IsDead() and Player:CanSee(unit) and
(
not unit:GetAuras():FindMy(Renew):IsUp() or
unit:GetAuras():FindMy(Renew):GetRemainingTime() <= 1.6) then
local hp = unit:GetHP()
if hp < lowestHP then
lowest = unit
lowestHP = hp
end
end
end)
if lowest == nil then
lowest = Player
end
return lowest
end)
local PshieldUnit = Bastion.UnitManager:CreateCustomUnit('pshield', 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 not unit:IsDead() and Player:CanSee(unit) and
(
not unit:GetAuras():FindMy(PowerWordShield):IsUp()) then
local hp = unit:GetHP()
if hp < lowestHP then
lowest = unit
lowestHP = hp
end
end
end)
if lowest == nil then
lowest = Player
end
return lowest
end)
local DefaultAPL = Bastion.APL:New('default')
DefaultAPL:AddSpell(
PowerWordFortitude:CastableIf(function(self)
return usepwf and self:IsKnownAndUsable() and
not Player:IsCastingOrChanneling() and not Player:GetAuras():FindMy(PowerWordFortitude):IsUp() and not IsMounted()
end):SetTarget(Player)
)
DefaultAPL:AddSpell(
ShadowCovenant:CastableIf(function(self)
return self:IsKnownAndUsable() and not Player:IsCastingOrChanneling()
end):SetTarget(Player)
)
DefaultAPL:AddSpell(
ShadowWordPain:CastableIf(function(self)
return self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() and not Target:GetAuras():FindMy(ShadowWordPain):IsUp()
end):SetTarget(Target)
)
DefaultAPL:AddSpell(
PowerWordShield:CastableIf(function(self)
return self:IsKnownAndUsable() and
not Player:IsCastingOrChanneling() and not Player:GetAuras():FindMy(PowerWordShield):IsUp() and not IsMounted() and Player:GetHealth() < 80
end):SetTarget(Player)
)
DefaultAPL:AddSpell(
Shadowfiend:CastableIf(function(self)
return self:IsKnownAndUsable() and not Player:IsCastingOrChanneling()
end):SetTarget(Target)
)
DefaultAPL:AddSpell(
PowerInfusion:CastableIf(function(self)
return self:IsKnownAndUsable() and not Player:IsCastingOrChanneling()
end):SetTarget(Player)
)
DefaultAPL:AddSpell(
ShadowWordDeath:CastableIf(function(self)
return self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() and Target:GetHealthPercent() <= 20
end):SetTarget(Target)
)
DefaultAPL:AddSpell(
MindBlast:CastableIf(function(self)
return self:IsKnownAndUsable() and not Player:IsCastingOrChanneling()
end):SetTarget(Target)
)
DefaultAPL:AddSpell(
Smite:CastableIf(function(self)
return self:IsKnownAndUsable() and not Player:IsCastingOrChanneling()
end):SetTarget(Target)
)
DefaultAPL:AddSpell(
PurgeTheWicked:CastableIf(function(self)
return self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() and not Target:GetAuras():PurgeTheWicked()
end):SetTarget(Target)
)
DefaultAPL:AddSpell(
Schism:CastableIf(function(self)
return self:IsKnownAndUsable() and not Player:IsCastingOrChanneling()
end):SetTarget(Target)
)
DefaultAPL:AddSpell(
Penance:CastableIf(function(self)
return self:IsKnownAndUsable() and not Player:IsCastingOrChanneling()
end):SetTarget(Target)
)
DefaultAPL:AddSpell(
Penance:CastableIf(function(self)
return self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() and Lowest:GetHP() <= 70
end):SetTarget(Lowest)
)
DefaultAPL:AddSpell(
DispelMagic:CastableIf(function(self)
return PurgeTarget:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() and
self:IsInRange(PurgeTarget) and PurgeTarget:GetAuras():HasAnyStealableAura()
end):SetTarget(PurgeTarget)
)
DefaultAPL:AddSpell(
Purify:CastableIf(function(self)
return DispelTarget:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() and
self:IsInRange(DispelTarget) and DispelTarget:GetAuras():HasAnyDispelableAura(Purify)
end):SetTarget(DispelTarget)
)
DefaultAPL:AddSpell(
PainSuppression:CastableIf(function(self)
return Tank:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling()
and Player:CanSee(Tank) and Tank:GetHP() <= 30
end):SetTarget(Tank)
)
DefaultAPL:AddSpell(
FlashHeal:CastableIf(function(self)
return Lowest:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling()
and Player:CanSee(Lowest) and Lowest:GetHP() <= 65
end):SetTarget(Lowest)
)
DefaultAPL:AddSpell(
PowerWordLife:CastableIf(function(self)
return Lowest:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling()
and Player:CanSee(Lowest) and Lowest:GetHP() <= 35
end):SetTarget(Lowest)
)
DefaultAPL:AddSpell(
Renew:CastableIf(function(self)
return RenewUnit:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling()
and Player:CanSee(RenewUnit) and RenewUnit:GetHP() <= 95
end):SetTarget(RenewUnit)
)
DefaultAPL:AddSpell(
PowerWordShield:CastableIf(function(self)
return PshieldUnit:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling()
and Player:CanSee(PshieldUnit) and PshieldUnit:GetHP() <= 70
end):SetTarget(PshieldUnit)
)
DefaultAPL:AddSpell(
PowerWordRadiance:CastableIf(function(self)
return Player:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() and Player:IsInParty() and
self:IsInRange(Player) and Player:GetPartyHPAround(50) >= 3
end):SetTarget(Player)
)
DefaultAPL:AddSpell(
PowerWordBarrier:CastableIf(function(self)
return Player:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() and Player:IsInParty() and
self:IsInRange(Player) and Player:GetPartyHPAround(40) >= 3
end):SetTarget(Player)
)
OpenerAPL:AddSpell(
DivineStar:CastableIf(function(self)
return self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() and Player:IsFacing(target)
end):SetTarget(None):OnCast(function(self)
local loc = Target:GetPosition()
self:Click(loc)
end)
)
DiscModule:Sync(function()
if Player:IsAffectingCombat() then
DefaultAPL:Execute()
end
end)
Bastion:Register(DiscModule)
local tab1 =
{
layoutConfig = { padding = { top = 40 } },
rows = {
[1] = { resto = { type = 'header', label = 'DPS Options' } },
[2] = { dps1 = { type = 'slider', label = 'DPS Health Threshold', column = 6, order = 2,
min = 1, max = 100, precision = 0,
initialValue = myconf:Read('dpshealth', 85),
onValueChanged = function(_, value) myconf:Write('dpshealth', value) end },
dps2 = { type = 'slider', label = 'Player Mana Threshold', column = 6, order = 2,
min = 1, max = 100, precision = 0,
initialValue = myconf:Read('playermana', 85),
onValueChanged = function(_, value) myconf:Write('playermana', value) end }, },
[3] = { autoform = { type = 'header', label = 'Natures Cure' } },
[4] = { pummel = { type = 'checkbox', label = 'Dispell', column = 6,
initialValue = myconf:Read('naturescure1', false),
onValueChanged = function(_, flag) myconf:Write('naturescure1', flag) end }, },
[5] = { resto = { type = 'header', label = 'Soothe' } },
[6] = { incombat = { type = 'checkbox', label = 'Shoote Target', column = 12, order = 1,
initialValue = myconf:Read('soothe', false),
onValueChanged = function(_, flag) myconf:Write('soothe', flag) end }, },
[7] = { resto = { type = 'header', label = 'Dispel Delay Time' } },
[8] = { delay = { type = 'slider', label = 'In seconds', column = 6, order = 1,
min = 0.5, max = 2, precision = 1,
initialValue = myconf:Read('dispeldelay', 1),
onValueChanged = function(_, value) myconf:Write('dispeldelay', value) end }, },
[9] = { innervate1 = { type = 'checkbox', label = 'Innervate', column = 6, order = 1,
initialValue = myconf:Read('innervate', false),
onValueChanged = function(_, flag) myconf:Write('innervate', flag) end },
innervate2 = { type = 'slider', label = 'Player Mana', column = 6, order = 2,
min = 1, max = 100, precision = 0,
initialValue = myconf:Read('innervatemana', 35),
onValueChanged = function(_, value) myconf:Write('innervatemana', value) end }, },
[10] = { frostmage = { type = 'header', label = 'Trinkets' } },
[11] = { pummel = { type = 'checkbox', label = 'Use Trinkets', column = 6,
initialValue = myconf:Read('trinkets', false),
onValueChanged = function(_, flag) myconf:Write('trinkets', flag) end }, },
[12] = { autoform = { type = 'header', label = 'Auto Form' } },
[13] = { pummel = { type = 'checkbox', label = 'Use Auto Form', column = 6,
initialValue = myconf:Read('autoform', false),
onValueChanged = function(_, flag) myconf:Write('autoform', flag) end }, },
},
}
local tab2 =
{
layoutConfig = { padding = { top = 40 } },
rows = {
[1] = { resto = { type = 'header', label = 'Player Healing' } },
[2] = { incombat = { type = 'checkbox', label = 'In Combat Healing', column = 6, order = 1,
initialValue = myconf:Read('playericheal', false),
onValueChanged = function(_, flag) myconf:Write('playericheal', flag) end },
outcombat = { type = 'checkbox', label = 'Out of Combat Healing', column = 6, order = 2,
initialValue = myconf:Read('playeroocheal', false),
onValueChanged = function(_, flag) myconf:Write('playeroocheal', flag) end }, },
[3] = { shadowmend1 = { type = 'checkbox', label = 'Regrowth', column = 6, order = 1,
initialValue = myconf:Read('shadowmend', false),
onValueChanged = function(_, flag) myconf:Write('shadowmend', flag) end },
shadowmend2 = { type = 'slider', label = 'Player Health', column = 6, order = 2,
min = 1, max = 100, precision = 0,
initialValue = myconf:Read('shadowmendpercent', 35),
onValueChanged = function(_, value) myconf:Write('shadowmendpercent', value) end }, },
[4] = { resto = { type = 'header', label = 'Defensives' } },
[5] = { bark1 = { type = 'checkbox', label = 'Barkskin', column = 6, order = 1,
initialValue = myconf:Read('barkskin', false),
onValueChanged = function(_, flag) myconf:Write('barkskin', flag) end },
bark2 = { type = 'slider', label = 'Player Health', column = 6, order = 2,
min = 1, max = 100, precision = 0,
initialValue = myconf:Read('barkskinpercent', 35),
onValueChanged = function(_, value) myconf:Write('barkskinpercent', value) end }, },
},
}
local tab3 =
{
layoutConfig = { padding = { top = 40 } },
rows = {
[1] = { incombat = { type = 'checkbox', label = 'In Combat Healing', column = 6, order = 1,
initialValue = myconf:Read('groupicheal', false),
onValueChanged = function(_, flag) myconf:Write('groupicheal', flag) end },
outcombat = { type = 'checkbox', label = 'Out of Combat Healing', column = 6, order = 2,
initialValue = myconf:Read('groupoocheal', false),
onValueChanged = function(_, flag) myconf:Write('groupoocheal', flag) end }, },
[2] = { lifebloom1 = { type = 'dropdown', label = 'Lifebloom on', column = 6, order = 1,
options = {
{ text = 'Tank Only', value = 'tank'},
{ text = 'All Party', value = 'party'},
{ text = 'Player', value = 'player'},
{ text = 'None', value = 'none'},
},
initialValue = myconf:Read('lifebloomtarget', 'tank'),
onValueChanged = function(_, value) myconf:Write('lifebloomtarget', value) end }, },
[3] = { resto = { type = 'header', label = 'AOE Heals' } },
[4] = { tranq1 = { type = 'checkbox', label = 'Tranquility', column = 6, order = 1,
initialValue = myconf:Read('grptranq', false),
onValueChanged = function(_, flag) myconf:Write('grptranq', flag) end }, },
[5] = { tranq2 = { type = 'slider', label = 'Number of Targets', column = 6, order = 2,
min = 1, max = 10, precision = 0,
initialValue = myconf:Read('tranqtargets', 3),
onValueChanged = function(_, value) myconf:Write('tranqtargets', value) end },
tranq3 = { type = 'slider', label = 'Target Health', column = 6, order = 1,
min = 1, max = 100, precision = 0,
initialValue = myconf:Read('tranqpercent', 50),
onValueChanged = function(_, value) myconf:Write('tranqpercent', value) end }, },
[6] = { flourish1 = { type = 'checkbox', label = 'Flourish', column = 6, order = 1,
initialValue = myconf:Read('flourish', false),
onValueChanged = function(_, flag) myconf:Write('flourish', flag) end }, },
[7] = { flourish2 = { type = 'slider', label = 'Number of Targets', column = 6, order = 2,
min = 1, max = 10, precision = 0,
initialValue = myconf:Read('flourishtargets', 3),
onValueChanged = function(_, value) myconf:Write('flourishtargets', value) end },
flourish3 = { type = 'slider', label = 'Target Health', column = 6, order = 1,
min = 1, max = 100, precision = 0,
initialValue = myconf:Read('flourishpercent', 50),
onValueChanged = function(_, value) myconf:Write('flourishpercent', value) end }, },
[8] = { convoke1 = { type = 'checkbox', label = 'Convoke The Spirits', column = 6, order = 1,
initialValue = myconf:Read('convoke', false),
onValueChanged = function(_, flag) myconf:Write('convoke', flag) end }, },
[9] = { convoke2 = { type = 'slider', label = 'Number of Targets', column = 6, order = 2,
min = 1, max = 10, precision = 0,
initialValue = myconf:Read('convoketargets', 3),
onValueChanged = function(_, value) myconf:Write('convoketargets', value) end },
convoke3 = { type = 'slider', label = 'Target Health', column = 6, order = 1,
min = 1, max = 100, precision = 0,
initialValue = myconf:Read('convokepercent', 50),
onValueChanged = function(_, value) myconf:Write('convokepercent', value) end }, },
[10] = { wild1 = { type = 'checkbox', label = 'Wild Growth', column = 6, order = 1,
initialValue = myconf:Read('grpwildgrowth', false),
onValueChanged = function(_, flag) myconf:Write('grpwildgrowth', flag) end }, },
[11] = { wild2 = { type = 'slider', label = 'Number of Targets', column = 6, order = 2,
min = 1, max = 10, precision = 0,
initialValue = myconf:Read('wildgrowthtargets', 3),
onValueChanged = function(_, value) myconf:Write('wildgrowthtargets', value) end },
wild3 = { type = 'slider', label = 'Target Health', column = 6, order = 1,
min = 1, max = 100, precision = 0,
initialValue = myconf:Read('wildgrowthpercent', 80),
onValueChanged = function(_, value) myconf:Write('wildgrowthpercent', value) end }, },
[12] = { incarnationtree1 = { type = 'checkbox', label = 'Incarnation: Tree of Life', column = 6, order = 1,
initialValue = myconf:Read('incarnationtree', false),
onValueChanged = function(_, flag) myconf:Write('incarnationtree', flag) end }, },
[13] = { convoke2 = { type = 'slider', label = 'Number of Targets', column = 6, order = 2,
min = 1, max = 10, precision = 0,
initialValue = myconf:Read('incarnationtreetargets', 3),
onValueChanged = function(_, value) myconf:Write('incarnationtreetargets', value) end },
convoke3 = { type = 'slider', label = 'Target Health', column = 6, order = 1,
min = 1, max = 100, precision = 0,
initialValue = myconf:Read('incarnationtreepercent', 50),
onValueChanged = function(_, value) myconf:Write('incarnationtreepercent', value) end }, }
},
}
local tab4 =
{
layoutConfig = { padding = { top = 40 } },
rows = {
[1] = { resto = { type = 'header', label = 'AOE Heals ' } },
[2] = { ironbark1 = { type = 'dropdown', label = 'Ironbark on', column = 6, order = 1,
options = {
{ text = 'Tank Only', value = 'tank'},
{ text = 'All Party', value = 'party'},
{ text = 'None', value = 'none'},
},
initialValue = myconf:Read('ironbarktarget', 'tank'),
onValueChanged = function(_, value) myconf:Write('ironbarktarget', value) end },
ironbark2 = { type = 'slider', label = 'Target Health', column = 6, order = 2,
min = 1, max = 100, precision = 0,
initialValue = myconf:Read('ironbarkpercent', 30),
onValueChanged = function(_, value) myconf:Write('ironbarkpercent', value) end }, },
[3] = { ward1 = { type = 'dropdown', label = 'Cenarion Ward on', column = 6, order = 1,
options = {
{ text = 'Tank Only', value = 'tank'},
{ text = 'All Party', value = 'party'},
{ text = 'None', value = 'none'},
},
initialValue = myconf:Read('wardtarget', 'tank'),
onValueChanged = function(_, value) myconf:Write('wardtarget', value) end },
ward2 = { type = 'slider', label = 'Target Health', column = 6, order = 2,
min = 1, max = 100, precision = 0,
initialValue = myconf:Read('wardpercent', 30),
onValueChanged = function(_, value) myconf:Write('wardpercent', value) end }, },
[4] = { natswift1 = { type = 'checkbox', label = 'Natures Swiftness', column = 6, order = 1,
initialValue = myconf:Read('grpnatswift', false),
onValueChanged = function(_, flag) myconf:Write('grpnatswift', flag) end },
natswift2 = { type = 'slider', label = 'Target Health', column = 6, order = 2,
min = 1, max = 100, precision = 0,
initialValue = myconf:Read('grpnatswiftpercent', 40),
onValueChanged = function(_, value) myconf:Write('grpnatswiftpercent', value) end }, },
[5] = { swift1 = { type = 'checkbox', label = 'Swiftmend', column = 6, order = 1,
initialValue = myconf:Read('grpswiftmend', false),
onValueChanged = function(_, flag) myconf:Write('grpswiftmend', flag) end },
swift2 = { type = 'slider', label = 'Target Health', column = 6, order = 2,
min = 1, max = 100, precision = 0,
initialValue = myconf:Read('grpswiftmendpercent', 60),
onValueChanged = function(_, value) myconf:Write('grpswiftmendpercent', value) end }, },
[6] = { regrowth1 = { type = 'checkbox', label = 'Regrowth', column = 6, order = 1,
initialValue = myconf:Read('grpregrowth', false),
onValueChanged = function(_, flag) myconf:Write('grpregrowth', flag) end },
regrowth2 = { type = 'slider', label = 'Target Health', column = 6, order = 2,
min = 1, max = 100, precision = 0,
initialValue = myconf:Read('grpregrowthpercent', 65),
onValueChanged = function(_, value) myconf:Write('grpregrowthpercent', value) end }, },
[7] = { rejuv1 = { type = 'checkbox', label = 'Rejuvenation', column = 6, order = 1,
initialValue = myconf:Read('grprejuv', false),
onValueChanged = function(_, flag) myconf:Write('grprejuv', flag) end },
rejuv2 = { type = 'slider', label = 'Target Health', column = 6, order = 2,
min = 1, max = 100, precision = 0,
initialValue = myconf:Read('grprejuvpercent', 85),
onValueChanged = function(_, value) myconf:Write('grprejuvpercent', value) end }, },
},
}
local discpriestconfig = {
layoutConfig = { padding = { top = 30 } },
rows = {
[1] = {
container = {
type = 'tab',
fullSize = true,
tabs = {
{
name = 'player',
title = 'Player Settings',
layout = tab1
},
{
name = 'playerhealing',
title = 'Player Healing',
layout = tab2
},
{
name = 'group',
title = 'Group Healing',
layout = tab3
},
{
name = 'group2',
title = 'AOE Healing ',
layout = tab4
}
},
}
},
},
}
Bastion.settingstemplate(discpriestconfig, 'Disc Priest', 460, 780, 1.00, 0.49, 0.04)

@ -0,0 +1,400 @@
local Tinkr, Bastion = ...
local FeralModule = Bastion.Module:New('feral')
local Evaluator = Tinkr.Util.Evaluator
local Player = Bastion.UnitManager:Get('player')
local None = Bastion.UnitManager:Get('none')
local Target = Bastion.UnitManager:Get('target')
local myconf = Tinkr.Util.Config:New('feral_druid') -- for saving variables
-- Spellbook spells
local Shadowmeld = Bastion.SpellBook:GetSpell(58984)
local Barkskin = Bastion.SpellBook:GetSpell(22812)
local BearForm = Bastion.SpellBook:GetSpell(5487)
--local Berserk = Bastion.SpellBook:GetSpell(50334)
local CatForm = Bastion.SpellBook:GetSpell(768)
local Dash = Bastion.SpellBook:GetSpell(1850)
local EntanglingRoots = Bastion.SpellBook:GetSpell(339)
local FeralFrenzy = Bastion.SpellBook:GetSpell(274837)
local FerociousBite = Bastion.SpellBook:GetSpell(22568)
--local FrenziedRegeneration = Bastion.SpellBook:GetSpell(22842)
local Growl = Bastion.SpellBook:GetSpell(6795)
--local Ironfur = Bastion.SpellBook:GetSpell(192081)
local Mangle = Bastion.SpellBook:GetSpell(33917)
local MarkoftheWild = Bastion.SpellBook:GetSpell(1126)
local Moonfire = Bastion.SpellBook:GetSpell(8921)
local MoonfireDebuff = Bastion.SpellBook:GetSpell(164812)
local PredatorySwiftness = Bastion.SpellBook:GetSpell(69369)
local PrimalWrath = Bastion.SpellBook:GetSpell(285381)
local Prowl = Bastion.SpellBook:GetSpell(5215)
local Rake = Bastion.SpellBook:GetSpell(1822)
local RakeDebuff = Bastion.SpellBook:GetSpell(155722)
local Regrowth = Bastion.SpellBook:GetSpell(8936)
local Revive = Bastion.SpellBook:GetSpell(50769)
local Rip = Bastion.SpellBook:GetSpell(1079)
local Shred = Bastion.SpellBook:GetSpell(5221)
local SkullBash = Bastion.SpellBook:GetSpell(106839)
--local Thrash = Bastion.SpellBook:GetSpell(106830)
local Thrash = Bastion.SpellBook:GetSpell(106832)
local ThrashDebuff = Bastion.SpellBook:GetSpell(106830)
local TigersFury = Bastion.SpellBook:GetSpell(5217)
local TravelForm = Bastion.SpellBook:GetSpell(783)
local Wrath = Bastion.SpellBook:GetSpell(5176)
--local Maul = Bastion.SpellBook:GetSpell(6807)
--local SurvivalInstincts = Bastion.SpellBook:GetSpell(61336)
--local Swipe = Bastion.SpellBook:GetSpell(106785)
local Swipe = Bastion.SpellBook:GetSpell(213764)
local BrutalSlash = Bastion.SpellBook:GetSpell(202028)
local ApexPredator = Bastion.SpellBook:GetSpell(391882)
local Incarnation = Bastion.SpellBook:GetSpell(102543)
-- Define Units
local InterruptTarget = Bastion.UnitManager:CreateCustomUnit('skullbash', function(unit)
local interrupt = nil
Bastion.UnitManager:EnumEnemies(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:InMelee(unit) and unit:IsInterruptible(5) and Player:IsFacing(unit) then
interrupt = unit
return true
end
end)
if interrupt == nil then
interrupt = None
end
return interrupt
end)
local Tank = Bastion.UnitManager:CreateCustomUnit('tank', function(unit)
local tank = nil
Bastion.UnitManager:EnumFriends(function(unit)
if Player:GetDistance(unit) > 40 then return false end
if not Player:CanSee(unit) then return false end
if unit:IsDead() then return false end
if unit:IsTank() then
tank = unit
return true
end
return false
end)
if tank == nil then
tank = None
end
return tank
end)
local Explosive = Bastion.UnitManager:CreateCustomUnit('explosive', function(unit)
local explosive = nil
Bastion.UnitManager:EnumEnemies(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:InMelee(unit) and unit:GetID() == 120651 and Player:IsFacing(unit) then
explosive = unit
return true
end
end)
if explosive == nil then
explosive = None
end
return explosive
end)
-- Rotation code here
local function Buffs()
-- Mark of the Wild
local motw = myconf:Read('motw')
MarkoftheWild:Condition('Mark of the Wild', function()
return motw and MarkoftheWild:IsKnownAndUsable() and not Player:IsCastingOrChanneling() and not Player:GetAuras():FindMy(MarkoftheWild):IsUp()
and not Player:IsMounted()
end)
MarkoftheWild:Cast(Player, 'Mark of the Wild')
end
local function DruidProwl()
-- Prowl
Prowl:Condition('Prowl', function()
return Prowl:IsKnownAndUsable() and not Player:IsCastingOrChanneling() and not Player:GetAuras():FindMy(Prowl):IsUp()
and Player:GetDistance(Target) <= 25 and not Player:IsMounted() and Target:IsHostile() and not Target:IsDead()
end)
Prowl:Cast(Player, 'Prowl')
end
local function Opener()
-- Rake
Rake:Condition('Rake', function()
return Rake:IsKnownAndUsable() and not Player:IsCastingOrChanneling() and Player:InMelee(Target)
and not Target:GetAuras():FindMy(RakeDebuff):IsUp() and Target:Exists() and Target:IsHostile() and not Target:IsDead()
end)
Rake:Cast(Target, 'Rake')
end
local function Interrupt()
-- Skull Bash
SkullBash:Condition('SkullBash', function()
return SkullBash:IsKnownAndUsable() and InterruptTarget:Exists() and not Player:IsCastingOrChanneling()
end)
C_Timer.After(1.5, function()
SkullBash:Cast(Target, 'SkullBash')
end)
end
local function Damage()
-- Cat Form
CatForm:Condition('Cat Form', function()
return CatForm:IsKnownAndUsable() and not Player:GetAuras():FindMy(CatForm):IsUp()
end)
CatForm:Cast(Player, 'Cat Form')
-- Healing with Predatory Swiftness
Regrowth:Condition('Regrowth', function()
return Regrowth:IsKnownAndUsable() and Player:GetAuras():FindMy(PredatorySwiftness):IsUp()
end)
Regrowth:Cast(Player, 'Regrowth')
-- Cooldowns
-- Tiger's Fury
TigersFury:Condition('Tigers Fury', function()
return TigersFury:IsKnownAndUsable() and not Player:GetAuras():FindMy(TigersFury):IsUp()
end)
TigersFury:Cast(Player, 'Tigers Fury')
-- Feral Frenzy on cooldown and when combo points are zero
FeralFrenzy:Condition('Feral Frenzy', function()
return FeralFrenzy:IsKnownAndUsable() and Player:GetComboPoints(Target) == 0
end)
FeralFrenzy:Cast(Player, 'Feral Frenzy')
-- Incarnation: Avatar of Ashamane
Incarnation:Condition('Incarnation', function()
return Incarnation:IsKnownAndUsable()
end)
Incarnation:Cast(Player, 'Incarnation')
-- Multi Target Rotation
if Player:GetEnemies(8) >= 2 then
-- Primal Wrath at 5 combo points
PrimalWrath:Condition('Primal Wrath', function()
return PrimalWrath:IsKnownAndUsable() and Player:InMelee(Target) and Player:GetComboPoints(Target) >= 5
and (not Target:GetAuras():FindMy(Rip):IsUp() or Target:GetAuras():FindMy(Rip):GetRemainingTime() <= 7)
end)
PrimalWrath:Cast(Target, 'Primal Wrath')
-- Spend Apex Predator Procs on Ferocious Bite
FerociousBite:Condition('Ferocious Bite Apex Predator', function()
return FerociousBite:IsKnownAndUsable() and Player:InMelee(Target) and Player:GetAuras():FindMy(ApexPredator):IsUp()
end)
FerociousBite:Cast(Target, 'Ferocious Bite Apex Predator')
-- Maintain Rake
Rake:Condition('Maintain Rake', function()
return Rake:IsKnownAndUsable() and not Player:IsCastingOrChanneling() and Player:InMelee(Target)
and Target:GetAuras():FindMy(RakeDebuff):GetRemainingTime() <= 4
end)
Rake:Cast(Target, 'Maintain Rake')
-- Cast Thrash if its not up
Thrash:Condition('Thrash', function()
return Thrash:IsKnownAndUsable() and not Target:GetAuras():FindMy(ThrashDebuff):IsUp() and Player:InMelee(Target)
end)
Thrash:Cast(Target, 'Thrash')
-- Avoid capping Brutal Slash charges
BrutalSlash:Condition('Brutal Slash', function()
return BrutalSlash:IsKnownAndUsable() and Player:InMelee(Target)
end)
BrutalSlash:Cast(Target, 'Brutal Slash')
-- Shred to generate combo points
Shred:Condition('Shred', function()
return Shred:IsKnownAndUsable() and Player:InMelee(Target)
end)
Shred:Cast(Target, 'Shred')
end
-- Single Target Rotation
if Player:GetEnemies(8) == 1 then
-- Maintain Rip - you'll want to cast this at 5 combo points
Rip:Condition('Rip', function()
return Rip:IsKnownAndUsable() and Player:InMelee(Target) and Player:GetComboPoints(Target) >= 5
and (not Target:GetAuras():FindMy(Rip):IsUp() or Target:GetAuras():FindMy(Rip):GetRemainingTime() <= 7)
end)
Rip:Cast(Target, 'Rip')
-- Spend Apex Predator Procs on Ferocious Bite
FerociousBite:Condition('Ferocious Bite Apex Predator', function()
return FerociousBite:IsKnownAndUsable() and Player:InMelee(Target) and Player:GetAuras():FindMy(ApexPredator):IsUp()
end)
FerociousBite:Cast(Target, 'Ferocious Bite Apex Predator')
-- If you have 5 combo points and Rip is not in Pandemic then cast Ferocious Bite
FerociousBite:Condition('Ferocious Bite', function()
return FerociousBite:IsKnownAndUsable() and Player:InMelee(Target) and Player:GetComboPoints(Target) >= 5
end)
FerociousBite:Cast(Target, 'Ferocious Bite')
-- Maintain Rake
Rake:Condition('Maintain Rake', function()
return Rake:IsKnownAndUsable() and not Player:IsCastingOrChanneling() and Player:InMelee(Target)
and Target:GetAuras():FindMy(RakeDebuff):GetRemainingTime() <= 4
end)
Rake:Cast(Target, 'Maintain Rake')
-- Avoid capping Brutal Slash charges
BrutalSlash:Condition('Brutal Slash', function()
return BrutalSlash:IsKnownAndUsable() and Player:InMelee(Target)
end)
BrutalSlash:Cast(Target, 'Brutal Slash')
-- Cast Thrash if its not up
Thrash:Condition('Thrash', function()
return Thrash:IsKnownAndUsable() and not Target:GetAuras():FindMy(ThrashDebuff):IsUp() and Player:InMelee(Target)
end)
Thrash:Cast(Target, 'Thrash')
-- Shred to generate combo points
Shred:Condition('Shred', function()
return Shred:IsKnownAndUsable() and Player:InMelee(Target)
end)
Shred:Cast(Target, 'Shred')
end
end
-- Module that dictates workflow
FeralModule:Sync(function()
if not Player:IsAffectingCombat() then
if Buffs() then return end
if DruidProwl() then return end
if Opener() then return end
end
if Player:IsAffectingCombat() and Target:Exists() and Target:IsHostile() and not Target:IsDead() then
if Interrupt() then return end
if Damage() then return end
end
end)
Bastion:Register(FeralModule)
local tab1 =
{
layoutConfig = { padding = { top = 40 } },
rows = {
[1] = { shadpr = { type = 'label', label = 'Open Combat' } },
[2] = { opener = { type = 'dropdown', label = 'Opener', column = 6, order = 1,
options = {
{ text = 'Moonfire', value = 'moonfire'},
{ text = 'None', value = 'none'},
},
initialValue = myconf:Read('opener', 'moonfire'),
onValueChanged = function(_, value) myconf:Write('opener', value) end }, },
[3] = { shadpr = { type = 'label', label = 'Buffs' } },
[4] = { motw = { type = 'checkbox', label = 'Mark of the Wild', column = 12, order = 1,
initialValue = myconf:Read('motw', false),
onValueChanged = function(_, flag) myconf:Write('motw', flag) end }, },
[5] = { shadpr = { type = 'label', label = 'Defensives' } },
[6] = { shield1 = { type = 'checkbox', label = 'Ironfur', column = 6, order = 1,
initialValue = myconf:Read('ironfur', false),
onValueChanged = function(_, flag) myconf:Write('ironfur', flag) end },
shield2 = { type = 'slider', label = 'Player Health', column = 6, order = 2,
min = 1, max = 100, precision = 0,
initialValue = myconf:Read('ironfurpercent', 35),
onValueChanged = function(_, value) myconf:Write('ironfurpercent', value) end }, },
[7] = { dispersion1 = { type = 'checkbox', label = 'Frenzied Regeneration', column = 6, order = 1,
initialValue = myconf:Read('fregen', false),
onValueChanged = function(_, flag) myconf:Write('fregen', flag) end },
dispersion2 = { type = 'slider', label = 'Player Health', column = 6, order = 2,
min = 1, max = 100, precision = 0,
initialValue = myconf:Read('fregenpercent', 35),
onValueChanged = function(_, value) myconf:Write('fregenpercent', value) end }, },
[8] = { shadpr = { type = 'label', label = 'Interrupts' } },
[9] = { silence = { type = 'checkbox', label = 'Skull Bash on CD', column = 12, order = 1,
initialValue = myconf:Read('skullbash', false),
onValueChanged = function(_, flag) myconf:Write('skullbash', flag) end }, },
[10] = { shadpr = { type = 'header', label = 'Purify Disease' } },
[11] = { incombat = { type = 'checkbox', label = 'In Combat', column = 6, order = 1,
initialValue = myconf:Read('purifyic', false),
onValueChanged = function(_, flag) myconf:Write('purifyic', flag) end },
outcombat = { type = 'checkbox', label = 'Out of Combat', column = 6, order = 2,
initialValue = myconf:Read('purifyooc', false),
onValueChanged = function(_, flag) myconf:Write('purifyooc', flag) end }, },
[12] = { shadpr = { type = 'header', label = 'Dispel Magic' } },
[13] = { incombat = { type = 'checkbox', label = 'In Combat', column = 12, order = 1,
initialValue = myconf:Read('dispelic', false),
onValueChanged = function(_, flag) myconf:Write('dispelic', flag) end }, },
[14] = { shadpr = { type = 'header', label = 'Dispel Delay Time' } },
[15] = { delay = { type = 'slider', label = 'In seconds', column = 6, order = 1,
min = 0.5, max = 2, precision = 1,
initialValue = myconf:Read('dispeldelay', 1),
onValueChanged = function(_, value) myconf:Write('dispeldelay', value) end }, },
},
}
local tab2 =
{
layoutConfig = { padding = { top = 40 } },
rows = {
[1] = { shadpr = { type = 'header', label = 'Player Healing' } },
[2] = { incombat = { type = 'checkbox', label = 'In Combat Healing', column = 6, order = 1,
initialValue = myconf:Read('playericheal', false),
onValueChanged = function(_, flag) myconf:Write('playericheal', flag) end },
outcombat = { type = 'checkbox', label = 'Out of Combat Healing', column = 6, order = 2,
initialValue = myconf:Read('playeroocheal', false),
onValueChanged = function(_, flag) myconf:Write('playeroocheal', flag) end }, },
[3] = { shadowmend1 = { type = 'checkbox', label = 'Shadow Mend', column = 6, order = 1,
initialValue = myconf:Read('shadowmend', false),
onValueChanged = function(_, flag) myconf:Write('shadowmend', flag) end },
shadowmend2 = { type = 'slider', label = 'Player Health', column = 6, order = 2,
min = 1, max = 100, precision = 0,
initialValue = myconf:Read('shadowmendpercent', 35),
onValueChanged = function(_, value) myconf:Write('shadowmendpercent', value) end }, },
},
}
local feralconfig = {
layoutConfig = { padding = { top = 30 } },
rows = {
[1] = {
container = {
type = 'tab',
fullSize = true,
tabs = {
{
name = 'player',
title = 'Player Settings',
layout = tab1
},
{
name = 'group',
title = 'Placeholder',
layout = tab2
}
},
}
},
},
}
Bastion.settingstemplate(feralconfig, 'Feral Druid', 400, 600, 1.00, 0.49, 0.04) -- config, Title of Settings Frame, Width, Height, ClassRGB
-- Class colours
-- Death Knight 0.77 0.12 0.23 Red
-- Demon Hunter 0.64 0.19 0.79 Dark Magenta
-- Druid 1.00 0.49 0.04 Orange
-- Evoker 0.20 0.58 0.50 Dark Emerald
-- Hunter 0.67 0.83 0.45 Green
-- Mage 0.25 0.78 0.92 Light Blue
-- Monk 0.00 1.00 0.60 Spring Green
-- Paladin 0.96 0.55 0.73 Pink
-- Priest 1.00 1.00 1.00 White
-- Rogue 1.00 0.96 0.41 Yellow
-- Shaman 0.00 0.44 0.87 Blue
-- Warlock 0.53 0.53 0.93 Purple
-- Warrior 0.78 0.61 0.43 Tan

@ -0,0 +1,337 @@
local Tinkr, Bastion = ...
local GuardianModule = Bastion.Module:New('guardian')
local Evaluator = Tinkr.Util.Evaluator
local Player = Bastion.UnitManager:Get('player')
local None = Bastion.UnitManager:Get('none')
local Target = Bastion.UnitManager:Get('target')
local myconf = Tinkr.Util.Config:New('guardian_druid') -- for saving variables
local AutoAttack = Bastion.SpellBook:GetSpell(6603)
local WarStomp = Bastion.SpellBook:GetSpell(20549)
local Barkskin = Bastion.SpellBook:GetSpell(22812)
local BearForm = Bastion.SpellBook:GetSpell(5487)
local Berserk = Bastion.SpellBook:GetSpell(50334)
local CatForm = Bastion.SpellBook:GetSpell(768)
local Dash = Bastion.SpellBook:GetSpell(1850)
local EntanglingRoots = Bastion.SpellBook:GetSpell(339)
local FerociousBite = Bastion.SpellBook:GetSpell(22568)
local FrenziedRegeneration = Bastion.SpellBook:GetSpell(22842)
local Growl = Bastion.SpellBook:GetSpell(6795)
local Ironfur = Bastion.SpellBook:GetSpell(192081)
local Mangle = Bastion.SpellBook:GetSpell(33917)
local MarkoftheWild = Bastion.SpellBook:GetSpell(1126)
local Moonfire = Bastion.SpellBook:GetSpell(8921)
local MoonfireDebuff = Bastion.SpellBook:GetSpell(164812)
local Prowl = Bastion.SpellBook:GetSpell(5215)
local Regrowth = Bastion.SpellBook:GetSpell(8936)
local Revive = Bastion.SpellBook:GetSpell(50769)
local Shred = Bastion.SpellBook:GetSpell(5221)
local SkullBash = Bastion.SpellBook:GetSpell(106839)
local Thrash = Bastion.SpellBook:GetSpell(77758)
local ThrashDebuff = Bastion.SpellBook:GetSpell(192090)
local TravelForm = Bastion.SpellBook:GetSpell(783)
local Wrath = Bastion.SpellBook:GetSpell(5176)
local Maul = Bastion.SpellBook:GetSpell(6807)
local SurvivalInstincts = Bastion.SpellBook:GetSpell(61336)
local Swipe = Bastion.SpellBook:GetSpell(213771)
local InterruptTarget = Bastion.UnitManager:CreateCustomUnit('skullbash', function(unit)
local interrupt = nil
Bastion.UnitManager:EnumEnemies(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:InMelee(unit) and unit:IsInterruptible(5) and Player:IsFacing(unit) then
interrupt = unit
return true
end
end)
if interrupt == nil then
interrupt = None
end
return interrupt
end)
local Tank = Bastion.UnitManager:CreateCustomUnit('tank', function(unit)
local tank = nil
Bastion.UnitManager:EnumFriends(function(unit)
if Player:GetDistance(unit) > 40 then return false end
if not Player:CanSee(unit) then return false end
if unit:IsDead() then return false end
if unit:IsTank() then
tank = unit
return true
end
return false
end)
if tank == nil then
tank = None
end
return tank
end)
local Explosive = Bastion.UnitManager:CreateCustomUnit('explosive', function(unit)
local explosive = nil
Bastion.UnitManager:EnumEnemies(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:InMelee(unit) and unit:GetID() == 120651 and Player:IsFacing(unit) then
explosive = unit
return true
end
end)
if explosive == nil then
explosive = None
end
return explosive
end)
local RestingAPL = Bastion.APL:New('resting')
local OpenerAPL = Bastion.APL:New('opener')
local DefensivesAPL = Bastion.APL:New('defensives')
local STAPL = Bastion.APL:New('st')
local UtilityAPL = Bastion.APL:New('utility')
-- Resting - Out of Combat Actions
local motw = myconf:Read('motw')
RestingAPL:AddSpell(
MarkoftheWild:CastableIf(function(self)
return motw and self:IsKnownAndUsable() and
not Player:IsCastingOrChanneling() and not Player:GetAuras():FindMy(MarkoftheWild):IsUp() and not IsMounted()
end):SetTarget(Player)
)
-- Opener spells
local opener = myconf:Read('opener')
OpenerAPL:AddSpell(
Moonfire:CastableIf(function(self)
return opener == 'moonfire' and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling()
end):SetTarget(Target)
)
-- Defensive spells
local ironfur = myconf:Read('ironfur')
local ironfurpercent = myconf:Read('ironfurpercent')
DefensivesAPL:AddSpell(
Ironfur:CastableIf(function(self)
return ironfur and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() and not Player:GetAuras():FindMy(Ironfur):IsUp()
and Player:GetHP() <= ironfurpercent
end):SetTarget(Player)
)
-- Heal yourself with Frenzied Regeneration if your health ever dips low
local fregen = myconf:Read('fregen')
local fregenpercent = myconf:Read('fregenpercent')
DefensivesAPL:AddSpell(
FrenziedRegeneration:CastableIf(function(self)
return fregen and self:IsKnownAndUsable() and Player:GetHP() <= fregenpercent
end):SetTarget(Player)
)
-- Utility spells
local skullbash = myconf:Read('skullbash')
UtilityAPL:AddSpell(
SkullBash:CastableIf(function(self)
return skullbash and InterruptTarget:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling()
end):SetTarget(InterruptTarget)
)
-- Single Target Action Priority List
-- Bear Form
STAPL:AddSpell(
BearForm:CastableIf(function(self)
return self:IsKnownAndUsable() and not Player:GetAuras():FindMy(BearForm):IsUp()
end):SetTarget(Player)
)
-- Auto Attack
STAPL:AddSpell(
AutoAttack:CastableIf(function(self)
return self:IsKnownAndUsable() and not IsCurrentSpell(AutoAttack) and Player:InMelee(Target)
end):SetTarget(Target)
)
-- Opener spells
STAPL:AddSpell(
Moonfire:CastableIf(function(self)
return self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() and not Target:GetAuras():FindMy(MoonfireDebuff):IsUp()
end):SetTarget(Target)
)
-- Spend your rage on Maul as required
STAPL:AddSpell(
Maul:CastableIf(function(self)
return self:IsKnownAndUsable() and Player:InMelee(Target)
end):SetTarget(Target)
)
-- Maintain Moonfire on as many mobs as possible
-- Thrash on cooldown
STAPL:AddSpell(
Thrash:CastableIf(function(self)
return not Target:GetAuras():FindMy(ThrashDebuff):IsUp() and Player:InMelee(Target)
end):SetTarget(Target)
)
-- Mangle on cooldown
STAPL:AddSpell(
Mangle:CastableIf(function(self)
return self:IsKnownAndUsable() and Player:InMelee(Target)
end):SetTarget(Target)
)
-- Fill your empty GCDs with Swipe
STAPL:AddSpell(
Swipe:CastableIf(function(self)
return not self:IsOnCooldown() and Player:InMelee(Target)
end):SetTarget(Target)
)
-- Module that dictates APL flow
GuardianModule:Sync(function()
if not Player:IsAffectingCombat() then
RestingAPL:Execute()
end
if not Player:IsAffectingCombat() and Target:Exists() and Target:IsHostile() and not Target:IsDead() then
OpenerAPL:Execute()
end
if Player:IsAffectingCombat() and Target:Exists() and Target:IsHostile() and not Target:IsDead() then
DefensivesAPL:Execute()
STAPL:Execute()
end
end)
Bastion:Register(GuardianModule)
local tab1 =
{
layoutConfig = { padding = { top = 40 } },
rows = {
[1] = { shadpr = { type = 'label', label = 'Open Combat' } },
[2] = { opener = { type = 'dropdown', label = 'Opener', column = 6, order = 1,
options = {
{ text = 'Moonfire', value = 'moonfire'},
{ text = 'None', value = 'none'},
},
initialValue = myconf:Read('opener', 'moonfire'),
onValueChanged = function(_, value) myconf:Write('opener', value) end }, },
[3] = { shadpr = { type = 'label', label = 'Buffs' } },
[4] = { motw = { type = 'checkbox', label = 'Mark of the Wild', column = 12, order = 1,
initialValue = myconf:Read('motw', false),
onValueChanged = function(_, flag) myconf:Write('motw', flag) end }, },
[5] = { shadpr = { type = 'label', label = 'Defensives' } },
[6] = { shield1 = { type = 'checkbox', label = 'Ironfur', column = 6, order = 1,
initialValue = myconf:Read('ironfur', false),
onValueChanged = function(_, flag) myconf:Write('ironfur', flag) end },
shield2 = { type = 'slider', label = 'Player Health', column = 6, order = 2,
min = 1, max = 100, precision = 0,
initialValue = myconf:Read('ironfurpercent', 35),
onValueChanged = function(_, value) myconf:Write('ironfurpercent', value) end }, },
[7] = { dispersion1 = { type = 'checkbox', label = 'Frenzied Regeneration', column = 6, order = 1,
initialValue = myconf:Read('fregen', false),
onValueChanged = function(_, flag) myconf:Write('fregen', flag) end },
dispersion2 = { type = 'slider', label = 'Player Health', column = 6, order = 2,
min = 1, max = 100, precision = 0,
initialValue = myconf:Read('fregenpercent', 35),
onValueChanged = function(_, value) myconf:Write('fregenpercent', value) end }, },
[8] = { shadpr = { type = 'label', label = 'Interrupts' } },
[9] = { silence = { type = 'checkbox', label = 'Skull Bash on CD', column = 12, order = 1,
initialValue = myconf:Read('skullbash', false),
onValueChanged = function(_, flag) myconf:Write('skullbash', flag) end }, },
[10] = { shadpr = { type = 'header', label = 'Purify Disease' } },
[11] = { incombat = { type = 'checkbox', label = 'In Combat', column = 6, order = 1,
initialValue = myconf:Read('purifyic', false),
onValueChanged = function(_, flag) myconf:Write('purifyic', flag) end },
outcombat = { type = 'checkbox', label = 'Out of Combat', column = 6, order = 2,
initialValue = myconf:Read('purifyooc', false),
onValueChanged = function(_, flag) myconf:Write('purifyooc', flag) end }, },
[12] = { shadpr = { type = 'header', label = 'Dispel Magic' } },
[13] = { incombat = { type = 'checkbox', label = 'In Combat', column = 12, order = 1,
initialValue = myconf:Read('dispelic', false),
onValueChanged = function(_, flag) myconf:Write('dispelic', flag) end }, },
[14] = { shadpr = { type = 'header', label = 'Dispel Delay Time' } },
[15] = { delay = { type = 'slider', label = 'In seconds', column = 6, order = 1,
min = 0.5, max = 2, precision = 1,
initialValue = myconf:Read('dispeldelay', 1),
onValueChanged = function(_, value) myconf:Write('dispeldelay', value) end }, },
},
}
local tab2 =
{
layoutConfig = { padding = { top = 40 } },
rows = {
[1] = { shadpr = { type = 'header', label = 'Player Healing' } },
[2] = { incombat = { type = 'checkbox', label = 'In Combat Healing', column = 6, order = 1,
initialValue = myconf:Read('playericheal', false),
onValueChanged = function(_, flag) myconf:Write('playericheal', flag) end },
outcombat = { type = 'checkbox', label = 'Out of Combat Healing', column = 6, order = 2,
initialValue = myconf:Read('playeroocheal', false),
onValueChanged = function(_, flag) myconf:Write('playeroocheal', flag) end }, },
[3] = { shadowmend1 = { type = 'checkbox', label = 'Shadow Mend', column = 6, order = 1,
initialValue = myconf:Read('shadowmend', false),
onValueChanged = function(_, flag) myconf:Write('shadowmend', flag) end },
shadowmend2 = { type = 'slider', label = 'Player Health', column = 6, order = 2,
min = 1, max = 100, precision = 0,
initialValue = myconf:Read('shadowmendpercent', 35),
onValueChanged = function(_, value) myconf:Write('shadowmendpercent', value) end }, },
},
}
local guardianconfig = {
layoutConfig = { padding = { top = 30 } },
rows = {
[1] = {
container = {
type = 'tab',
fullSize = true,
tabs = {
{
name = 'player',
title = 'Player Settings',
layout = tab1
},
{
name = 'group',
title = 'Placeholder',
layout = tab2
}
},
}
},
},
}
Bastion.settingstemplate(guardianconfig, 'Guardian Druid', 400, 600, 1.00, 0.49, 0.04) -- config, Title of Settings Frame, Width, Height, ClassRGB
-- Class colours
-- Death Knight 0.77 0.12 0.23 Red
-- Demon Hunter 0.64 0.19 0.79 Dark Magenta
-- Druid 1.00 0.49 0.04 Orange
-- Evoker 0.20 0.58 0.50 Dark Emerald
-- Hunter 0.67 0.83 0.45 Green
-- Mage 0.25 0.78 0.92 Light Blue
-- Monk 0.00 1.00 0.60 Spring Green
-- Paladin 0.96 0.55 0.73 Pink
-- Priest 1.00 1.00 1.00 White
-- Rogue 1.00 0.96 0.41 Yellow
-- Shaman 0.00 0.44 0.87 Blue
-- Warlock 0.53 0.53 0.93 Purple
-- Warrior 0.78 0.61 0.43 Tan

@ -0,0 +1,476 @@
local Tinkr, Bastion = ...
local HolyModule = Bastion.Module:New('holypriest')
local Evaluator = Tinkr.Util.Evaluator
local Player = Bastion.UnitManager:Get('player')
local None = Bastion.UnitManager:Get('none')
local Target = Bastion.UnitManager:Get('target')
local myconf = Tinkr.Util.Config:New('holy_priest') -- for saving variables
local ArcaneTorrent = Bastion.SpellBook:GetSpell(232633)
local AutoAttack = Bastion.SpellBook:GetSpell(6603)
local AngelicFeather = Bastion.SpellBook:GetSpell(121536)
local DesperatePrayer = Bastion.SpellBook:GetSpell(19236)
local DispelMagic = Bastion.SpellBook:GetSpell(528)
local Fade = Bastion.SpellBook:GetSpell(586)
local FlashHeal = Bastion.SpellBook:GetSpell(2061)
local HolyNova = Bastion.SpellBook:GetSpell(132157)
local HolyWordSalvation = Bastion.SpellBook:GetSpell(265202)
local LeapofFaith = Bastion.SpellBook:GetSpell(73325)
local Levitate = Bastion.SpellBook:GetSpell(1706)
local MassDispel = Bastion.SpellBook:GetSpell(32375)
local MindSoothe = Bastion.SpellBook:GetSpell(453)
local MindVision = Bastion.SpellBook:GetSpell(2096)
local PowerInfusion = Bastion.SpellBook:GetSpell(10060)
local PowerWordFortitude = Bastion.SpellBook:GetSpell(21562)
local PowerWordLife = Bastion.SpellBook:GetSpell(373481)
local PowerWordShield = Bastion.SpellBook:GetSpell(17)
local PrayerofMending = Bastion.SpellBook:GetSpell(33076)
local PsychicScream = Bastion.SpellBook:GetSpell(8122)
local Renew = Bastion.SpellBook:GetSpell(139)
local Resurrection = Bastion.SpellBook:GetSpell(2006)
local ShadowWordPain = Bastion.SpellBook:GetSpell(589)
local Shadowfiend = Bastion.SpellBook:GetSpell(34433)
local Smite = Bastion.SpellBook:GetSpell(585)
local FocusedWill = Bastion.SpellBook:GetSpell(45243)
local CircleofHealing = Bastion.SpellBook:GetSpell(204883)
local DivineHymn = Bastion.SpellBook:GetSpell(64843)
local DivineWord = Bastion.SpellBook:GetSpell(372760)
local GuardianSpirit = Bastion.SpellBook:GetSpell(47788)
local Halo = Bastion.SpellBook:GetSpell(120517)
local Heal = Bastion.SpellBook:GetSpell(2060)
local HolyFire = Bastion.SpellBook:GetSpell(14914)
local HolyWordSanctify = Bastion.SpellBook:GetSpell(34861)
local HolyWordSerenity = Bastion.SpellBook:GetSpell(2050)
local Lightweaver = Bastion.SpellBook:GetSpell(390993)
local MassResurrection = Bastion.SpellBook:GetSpell(212036)
local PrayerofHealing = Bastion.SpellBook:GetSpell(596)
local Purify = Bastion.SpellBook:GetSpell(527)
local SurgeofLight = Bastion.SpellBook:GetSpell(114255)
local SymbolofHope = Bastion.SpellBook:GetSpell(64901)
local MindBlast = Bastion.SpellBook:GetSpell(14914)
local Lowest = Bastion.UnitManager:CreateCustomUnit('lowest', function(unit)
local lowest = nil
local lowestHP = math.huge
Bastion.UnitManager:EnumFriends(function(unit)
if unit:IsDead() then return false end
if Player:GetDistance(unit) > 40 then return false end
if not Player:CanSee(unit) then return false end
local hp = unit:GetHP()
if hp < lowestHP then
lowest = unit
lowestHP = hp
end
end)
if not lowest then
lowest = Player
end
return lowest
end)
local Tank = Bastion.UnitManager:CreateCustomUnit('tank', function(unit)
local tank = nil
Bastion.UnitManager:EnumFriends(function(unit)
if Player:GetDistance(unit) > 40 then return false end
if not Player:CanSee(unit) then return false end
if unit:IsDead() then return false end
if unit:IsTank() then
tank = unit
return true
end
return false
end)
if tank == nil then
tank = Player
end
return tank
end)
local Healer = Bastion.UnitManager:CreateCustomUnit('healer', function(unit)
local healer = nil
Bastion.UnitManager:EnumFriends(function(unit)
if Player:GetDistance(unit) > 40 then return false end
if not Player:CanSee(unit) then return false end
if unit:IsDead() then return false end
if unit:IsHealer() then
healer = unit
return true
end
return false
end)
if healer == nil then
healer = Player
end
return healer
end)
local PurifyUnit = Bastion.UnitManager:CreateCustomUnit('dispel', 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 not unit:IsDead() and Player:CanSee(unit) and
unit:GetAuras():HasAnyDispelableAura(Purify) 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 SanctifyUnit = Bastion.UnitManager:CreateCustomUnit('sanctify', 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 unit:GetPartyHPAround(10, 70) >= 5
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 CoHUnit = Bastion.UnitManager:CreateCustomUnit('coh', 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 unit:GetPartyHPAround(30, 80) >= 4
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 Explosive = Bastion.UnitManager:CreateCustomUnit('explosive', function(unit)
local explosive = nil
Bastion.UnitManager:EnumEnemies(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:InMelee(unit) and unit:GetID() == 120651 and Player:IsFacing(unit) then
explosive = unit
return true
end
end)
if explosive == nil then
explosive = None
end
return explosive
end)
local RestingAPL = Bastion.APL:New('resting')
local HealAPL = Bastion.APL:New('heal')
local DamageAPL = Bastion.APL:New('damage')
-- Resting - Out of Combat Actions
local usepwf = myconf:Read('pwf')
RestingAPL:AddSpell(
PowerWordFortitude:CastableIf(function(self)
return usepwf and self:IsKnownAndUsable() and
not Player:IsCastingOrChanneling() and not Player:GetAuras():FindMy(PowerWordFortitude):IsUp() and not IsMounted()
end):SetTarget(Player)
)
-- HealAPL - Healing here
-- Purify
HealAPL:AddSpell(
Purify:CastableIf(function(self)
return PurifyUnit:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() and
self:IsInRange(PurifyUnit) and PurifyUnit:GetAuras():HasAnyDispelableAura(Purify)
end):SetTarget(PurifyUnit)
)
-- Symbol of Hope
HealAPL:AddSpell(
SymbolofHope:CastableIf(function(self)
return Healer:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() and Healer:GetPP() <= 50
end):SetTarget(Player)
)
-- Guardian Spirit
HealAPL:AddSpell(
GuardianSpirit:CastableIf(function(self)
return self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() and Tank:GetHP() <= 40
end):SetTarget(Tank)
)
-- Flash Heal with Surge of Light
HealAPL:AddSpell(
FlashHeal:CastableIf(function(self)
return self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() and Player:GetAuras():FindMy(SurgeofLight):IsUp()
end):SetTarget(Lowest)
)
-- Holy Word: Salvation when the majority of the raid is heavily injured
HealAPL:AddSpell(
HolyWordSalvation:CastableIf(function(self)
return self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() and Player:GetPartyHPAround(40, 50) >= 5
and not Player:IsMoving()
end):SetTarget(Player)
)
-- Divine Hymn when the majority of the raid is heavily injured
HealAPL:AddSpell(
DivineHymn:CastableIf(function(self)
return self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() and Player:GetPartyHPAround(40, 40) >= 5
and not Player:IsMoving()
end):SetTarget(Player)
)
-- Divine Word followed by Holy Word: Sanctify (if available) on a cluster of injured allies
-- Divine Word followed by Holy Word: Serenity (if available) on an injured ally
HealAPL:AddSpell(
DivineWord:CastableIf(function(self)
return self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() and not Player:GetAuras():FindMy(DivineWord):IsUp()
and (Lowest:GetHP() <= 60 or SanctifyUnit:GetPartyHPAround(10, 60) >= 5)
end):SetTarget(Player)
)
-- Holy Word: Sanctify when a cluster of your raid is injured
HealAPL:AddSpell(
HolyWordSanctify:CastableIf(function(self)
return SanctifyUnit:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling()
and Player:CanSee(SanctifyUnit) and SanctifyUnit:GetPartyHPAround(10, 70) >= 5
end):SetTarget(None):OnCast(function(self)
local loc = SanctifyUnit:GetPosition()
self:Click(loc)
end)
)
-- Holy Word: Serenity on an injured ally
HealAPL:AddSpell(
HolyWordSerenity:CastableIf(function(self)
return self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() and Lowest:GetHP() <= 70
end):SetTarget(Lowest)
)
-- Circle of Healing on cooldown when at least 4 allies are injured
HealAPL:AddSpell(
CircleofHealing:CastableIf(function(self)
return CoHUnit:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling()
and Player:CanSee(CoHUnit) and CoHUnit:GetPartyHPAround(30, 80) >= 4
end):SetTarget(CoHUnit)
)
-- Prayer of Mending on cooldown, usually on the active tank
HealAPL:AddSpell(
PrayerofMending:CastableIf(function(self)
return self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() and Tank:GetHP() <= 95
end):SetTarget(Tank)
)
-- Halo when most of your raid is injured
HealAPL:AddSpell(
Halo:CastableIf(function(self)
return self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() and Player:GetPartyHPAround(30, 70) >= 5
end):SetTarget(Player)
)
-- Power Word: Life for emergency triage on an ally below 35% hitpoints
HealAPL:AddSpell(
PowerWordLife:CastableIf(function(self)
return self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() and Tank:GetHP() <= 35
end):SetTarget(Tank)
)
-- Alternate between Flash Heal and Heal and use Lightweaver buff
HealAPL:AddSpell(
Heal:CastableIf(function(self)
return self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() and Player:GetAuras():FindMy(Lightweaver):IsUp()
and Lowest:GetHP() <= 90
end):SetTarget(Lowest)
)
HealAPL:AddSpell(
FlashHeal:CastableIf(function(self)
return self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() and not Player:GetAuras():FindMy(Lightweaver):IsUp()
and Lowest:GetHP() <= 90
end):SetTarget(Lowest)
)
-- DamageAPL - DPS spells here
-- Cast Shadow Word: Pain if you're moving and nothing else is available
DamageAPL:AddSpell(
ShadowWordPain:CastableIf(function(self)
return self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() and not Target:GetAuras():FindMy(ShadowWordPain):IsUp()
end):SetTarget(Target)
)
-- Cast Smite
DamageAPL:AddSpell(
Smite:CastableIf(function(self)
return self:IsKnownAndUsable() and not Player:IsCastingOrChanneling()
end):SetTarget(Target)
)
-- Module that dictates APL flow
HolyModule:Sync(function()
-- Bastion:Print(Lowest)
-- if not Player:IsAffectingCombat() then
-- RestingAPL:Execute()
-- end
HealAPL:Execute()
-- if Player:IsAffectingCombat() and Target:Exists() and Target:IsHostile() then
-- DamageAPL:Execute()
-- end
end)
Bastion:Register(HolyModule)
local tab1 =
{
layoutConfig = { padding = { top = 40 } },
rows = {
[1] = { shadpr = { type = 'label', label = 'Open Combat' } },
[2] = { opener = { type = 'dropdown', label = 'Opener', column = 6, order = 1,
options = {
{ text = 'Shadow Word: Pain', value = 'swp'},
{ text = 'Shadow Crash', value = 'crash'},
{ text = 'None', value = 'none'},
},
initialValue = myconf:Read('opener', 'shield'),
onValueChanged = function(_, value) myconf:Write('opener', value) end }, },
[3] = { shadpr = { type = 'label', label = 'Buffs' } },
[4] = { pwf = { type = 'checkbox', label = 'Power Word: Fortitude', column = 12, order = 1,
initialValue = myconf:Read('pwf', false),
onValueChanged = function(_, flag) myconf:Write('pwf', flag) end }, },
[5] = { shadpr = { type = 'header', label = 'Defensives' } },
[6] = { shield1 = { type = 'checkbox', label = 'Power Word: Shield', column = 6, order = 1,
initialValue = myconf:Read('pws', false),
onValueChanged = function(_, flag) myconf:Write('pws', flag) end },
shield2 = { type = 'slider', label = 'Player Health', column = 6, order = 2,
min = 1, max = 100, precision = 0,
initialValue = myconf:Read('pwspercent', 35),
onValueChanged = function(_, value) myconf:Write('pwspercent', value) end }, },
[7] = { dispersion1 = { type = 'checkbox', label = 'Dispersion', column = 6, order = 1,
initialValue = myconf:Read('dispersion', false),
onValueChanged = function(_, flag) myconf:Write('dispersion', flag) end },
dispersion2 = { type = 'slider', label = 'Player Health', column = 6, order = 2,
min = 1, max = 100, precision = 0,
initialValue = myconf:Read('dispersionpercent', 35),
onValueChanged = function(_, value) myconf:Write('dispersionpercent', value) end }, },
[8] = { shadpr = { type = 'header', label = 'Interrupts' } },
[9] = { silence = { type = 'checkbox', label = 'Silence on CD', column = 6, order = 1,
initialValue = myconf:Read('silence', false),
onValueChanged = function(_, flag) myconf:Write('silence', flag) end },
horror = { type = 'checkbox', label = 'Psychic Horror on CD', column = 6, order = 2,
initialValue = myconf:Read('horror', false),
onValueChanged = function(_, flag) myconf:Write('horror', flag) end }, },
[10] = { shadpr = { type = 'header', label = 'Purify Disease' } },
[11] = { incombat = { type = 'checkbox', label = 'In Combat', column = 6, order = 1,
initialValue = myconf:Read('purifyic', false),
onValueChanged = function(_, flag) myconf:Write('purifyic', flag) end },
outcombat = { type = 'checkbox', label = 'Out of Combat', column = 6, order = 2,
initialValue = myconf:Read('purifyooc', false),
onValueChanged = function(_, flag) myconf:Write('purifyooc', flag) end }, },
[12] = { shadpr = { type = 'header', label = 'Dispel Magic' } },
[13] = { incombat = { type = 'checkbox', label = 'In Combat', column = 12, order = 1,
initialValue = myconf:Read('dispelic', false),
onValueChanged = function(_, flag) myconf:Write('dispelic', flag) end }, },
[14] = { shadpr = { type = 'header', label = 'Dispel Delay Time' } },
[15] = { delay = { type = 'slider', label = 'In seconds', column = 6, order = 1,
min = 0.5, max = 2, precision = 1,
initialValue = myconf:Read('dispeldelay', 1),
onValueChanged = function(_, value) myconf:Write('dispeldelay', value) end }, },
},
}
local tab2 =
{
layoutConfig = { padding = { top = 40 } },
rows = {
[1] = { shadpr = { type = 'header', label = 'Player Healing' } },
[2] = { incombat = { type = 'checkbox', label = 'In Combat Healing', column = 6, order = 1,
initialValue = myconf:Read('playericheal', false),
onValueChanged = function(_, flag) myconf:Write('playericheal', flag) end },
outcombat = { type = 'checkbox', label = 'Out of Combat Healing', column = 6, order = 2,
initialValue = myconf:Read('playeroocheal', false),
onValueChanged = function(_, flag) myconf:Write('playeroocheal', flag) end }, },
[3] = { shadowmend1 = { type = 'checkbox', label = 'Shadow Mend', column = 6, order = 1,
initialValue = myconf:Read('shadowmend', false),
onValueChanged = function(_, flag) myconf:Write('shadowmend', flag) end },
shadowmend2 = { type = 'slider', label = 'Player Health', column = 6, order = 2,
min = 1, max = 100, precision = 0,
initialValue = myconf:Read('shadowmendpercent', 35),
onValueChanged = function(_, value) myconf:Write('shadowmendpercent', value) end }, },
},
}
local holypriestconfig = {
layoutConfig = { padding = { top = 30 } },
rows = {
[1] = {
container = {
type = 'tab',
fullSize = true,
tabs = {
{
name = 'player',
title = 'Player Settings',
layout = tab1
},
{
name = 'group',
title = 'Placeholder',
layout = tab2
}
},
}
},
},
}
Bastion.settingstemplate(holypriestconfig, 'Holy Priest', 400, 600, 1.00, 1.00, 1.00) --, 0.00, 0.44, 0.87, 'enhsha') --Title of Settings Frame, Width, Height, ClassRGB, Rotation Name
-- Class colours
-- Death Knight 0.77 0.12 0.23 Red
-- Demon Hunter 0.64 0.19 0.79 Dark Magenta
-- Druid 1.00 0.49 0.04 Orange
-- Evoker 0.20 0.58 0.50 Dark Emerald
-- Hunter 0.67 0.83 0.45 Green
-- Mage 0.25 0.78 0.92 Light Blue
-- Monk 0.00 1.00 0.60 Spring Green
-- Paladin 0.96 0.55 0.73 Pink
-- Priest 1.00 1.00 1.00 White
-- Rogue 1.00 0.96 0.41 Yellow
-- Shaman 0.00 0.44 0.87 Blue
-- Warlock 0.53 0.53 0.93 Purple
-- Warrior 0.78 0.61 0.43 Tan

@ -1,608 +0,0 @@
local Tinkr, Bastion = ...
local OutlawModule = Bastion.Module:New('outlaw')
local Evaluator = Tinkr.Util.Evaluator
local Player = Bastion.UnitManager:Get('player')
local None = Bastion.UnitManager:Get('none')
local Target = Bastion.UnitManager:Get('target')
local RollTheBones = Bastion.SpellBook:GetSpell(315508)
local SliceAndDice = Bastion.SpellBook:GetSpell(315496)
local BetweenTheEyes = Bastion.SpellBook:GetSpell(315341)
local BladeRush = Bastion.SpellBook:GetSpell(271877)
local Vanish = Bastion.SpellBook:GetSpell(1856)
local Dispatch = Bastion.SpellBook:GetSpell(2098)
local Ambush = Bastion.SpellBook:GetSpell(8676)
local Stealth = Bastion.SpellBook:GetSpell(1784)
local PistolShot = Bastion.SpellBook:GetSpell(185763)
local Opportunity = Bastion.SpellBook:GetSpell(195627)
local SinisterStrike = Bastion.SpellBook:GetSpell(193315)
local GrandMelee = Bastion.SpellBook:GetSpell(193358)
local Broadside = Bastion.SpellBook:GetSpell(193356)
local TrueBearing = Bastion.SpellBook:GetSpell(193359)
local RuthlessPrecision = Bastion.SpellBook:GetSpell(193357)
local SkullAndCrossbones = Bastion.SpellBook:GetSpell(199603)
local BuriedTreasure = Bastion.SpellBook:GetSpell(199600)
local AdrenalineRush = Bastion.SpellBook:GetSpell(13750)
local ShadowDance = Bastion.SpellBook:GetSpell(185313)
local Audacity = Bastion.SpellBook:GetSpell(381845)
local Flagellation = Bastion.SpellBook:GetSpell(323654)
local Dreadblades = Bastion.SpellBook:GetSpell(343142)
local JollyRoger = Bastion.SpellBook:GetSpell(199603)
local BladeFlurry = Bastion.SpellBook:GetSpell(13877)
local Kick = Bastion.SpellBook:GetSpell(1766)
local MarkedForDeath = Bastion.SpellBook:GetSpell(137619)
local CrimsonVial = Bastion.SpellBook:GetSpell(185311)
local Shiv = Bastion.SpellBook:GetSpell(5938)
local KidneyShot = Bastion.SpellBook:GetSpell(408)
local InstantPoison = Bastion.SpellBook:GetSpell(315584)
local AtrophicPosion = Bastion.SpellBook:GetSpell(381637)
local Evasion = Bastion.SpellBook:GetSpell(5277)
local TricksOfTheTrade = Bastion.SpellBook:GetSpell(57934)
local CheapShot = Bastion.SpellBook:GetSpell(1833)
local BagOfTricks = Bastion.SpellBook:GetSpell(312411)
local AutoAttack = Bastion.SpellBook:GetSpell(6603)
local IrideusFragment = Bastion.ItemBook:GetItem(193743)
local Healthstone = Bastion.ItemBook:GetItem(5512)
local WindscarWhetstone = Bastion.ItemBook:GetItem(137486)
local PurgeTarget = Bastion.UnitManager:CreateCustomUnit('purge', function(unit)
local purge = nil
Bastion.UnitManager:EnumEnemies(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 unit:GetAuras():HasAnyStealableAura() then
purge = unit
return true
end
end)
if purge == nil then
purge = None
end
return purge
end)
local KickTarget = Bastion.UnitManager:CreateCustomUnit('kick', function(unit)
local purge = nil
Bastion.UnitManager:EnumEnemies(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:InMelee(unit) and unit:IsInterruptible(5) and Player:IsFacing(unit) then
purge = unit
return true
end
end)
if purge == nil then
purge = None
end
return purge
end)
local Tank = Bastion.UnitManager:CreateCustomUnit('tank', function(unit)
local tank = nil
Bastion.UnitManager:EnumFriends(function(unit)
if Player:GetDistance(unit) > 40 then
return false
end
if not Player:CanSee(unit) then
return false
end
if unit:IsDead() then
return false
end
if unit:IsTank() then
tank = unit
return true
end
return false
end)
if tank == nil then
tank = None
end
return tank
end)
local Explosive = Bastion.UnitManager:CreateCustomUnit('explosive', function(unit)
local explosive = nil
Bastion.UnitManager:EnumEnemies(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:InMelee(unit) and unit:GetID() == 120651 and Player:IsFacing(unit) then
explosive = unit
return true
end
end)
if explosive == nil then
explosive = None
end
return explosive
end)
local DefaultAPL = Bastion.APL:New('default')
local AOEAPL = Bastion.APL:New('aoe')
local SpecialAPL = Bastion.APL:New('special')
SpecialAPL:AddSpell(
Kick:CastableIf(function(self)
return KickTarget:Exists() and Player:InMelee(KickTarget) and
self:IsKnownAndUsable() and
not Player:IsCastingOrChanneling()
end):SetTarget(KickTarget)
)
SpecialAPL:AddSpell(
SinisterStrike:CastableIf(function(self)
return Explosive:Exists() and not Player:IsCastingOrChanneling()
end):SetTarget(Explosive)
)
SpecialAPL:AddSpell(
KidneyShot:CastableIf(function(self)
return KickTarget:Exists() and Player:InMelee(KickTarget) and
self:IsKnownAndUsable() and
not Player:IsCastingOrChanneling() and
(Player:GetComboPoints(Target) >= 5 or
(
Player:GetComboPoints(Target) >= 4 and
(Player:GetAuras():FindMy(Broadside):IsUp() or Player:GetAuras():FindMy(Opportunity):IsUp())))
end):SetTarget(KickTarget)
)
SpecialAPL:AddSpell(
CheapShot:CastableIf(function(self)
return KickTarget:Exists() and Player:InMelee(KickTarget) and
self:IsKnownAndUsable() and
not Player:IsCastingOrChanneling() and Player:GetAuras():FindMy(Stealth):IsUp()
end):SetTarget(KickTarget)
)
SpecialAPL:AddSpell(
Stealth:CastableIf(function(self)
return self:IsKnownAndUsable() and
not Player:IsCastingOrChanneling() and not Player:IsAffectingCombat() and
not Player:GetAuras():FindMy(Stealth):IsUp() and not IsMounted()
end):SetTarget(Player)
)
SpecialAPL:AddSpell(
CrimsonVial:CastableIf(function(self)
return self:IsKnownAndUsable() and
not Player:IsCastingOrChanneling() and
Player:GetHealthPercent() < 70
end):SetTarget(Player)
)
SpecialAPL:AddSpell(
Shiv:CastableIf(function(self)
return PurgeTarget:Exists() and Player:InMelee(PurgeTarget) and
self:IsKnownAndUsable() and
not Player:IsCastingOrChanneling() and PurgeTarget:GetAuras():HasAnyStealableAura()
end):SetTarget(PurgeTarget)
)
SpecialAPL:AddSpell(
InstantPoison:CastableIf(function(self)
return self:IsKnownAndUsable() and
not Player:IsCastingOrChanneling() and
not Player:GetAuras():FindMy(InstantPoison):IsUp() and not Player:IsMoving()
end):SetTarget(Player)
)
SpecialAPL:AddSpell(
AtrophicPosion:CastableIf(function(self)
return self:IsKnownAndUsable() and
not Player:IsCastingOrChanneling() and
not Player:GetAuras():FindMy(AtrophicPosion):IsUp() and not Player:IsMoving()
end):SetTarget(Player)
)
SpecialAPL:AddItem(
Healthstone:UsableIf(function(self)
return self:IsEquippedAndUsable() and
not Player:IsCastingOrChanneling() and
Player:GetHealthPercent() < 40
end):SetTarget(Player)
)
SpecialAPL:AddSpell(
TricksOfTheTrade:CastableIf(function(self)
return Tank:Exists() and self:IsKnownAndUsable() and
not Player:IsCastingOrChanneling() and
Player:IsTanking(Target)
end):SetTarget(Tank)
)
SpecialAPL:AddSpell(
Evasion:CastableIf(function(self)
return self:IsKnownAndUsable() and
not Player:IsCastingOrChanneling() and
Player:GetHealthPercent() < 40
end):SetTarget(Player)
)
SpecialAPL:AddItem(
IrideusFragment:UsableIf(function(self)
return self:IsEquippedAndUsable() and
not Player:IsCastingOrChanneling() and (Player:GetMeleeAttackers() > 2 or Target:IsBoss())
end):SetTarget(Player)
)
SpecialAPL:AddItem(
WindscarWhetstone:UsableIf(function(self)
return self:IsEquippedAndUsable() and
not Player:IsCastingOrChanneling() and (Player:GetMeleeAttackers() > 2 or Target:IsBoss())
end):SetTarget(Player)
)
SpecialAPL:AddSpell(
BagOfTricks:CastableIf(function(self)
return Target:Exists() and Player:InMelee(Target) and
self:IsKnownAndUsable() and
not Player:IsCastingOrChanneling()
end):SetTarget(Target)
)
-- Adrenaline Rush on cooldown.
DefaultAPL:AddSpell(
AdrenalineRush:CastableIf(function(self)
return Target:Exists() and Player:InMelee(Target) and
self:IsKnownAndUsable() and
not Player:IsCastingOrChanneling()
end):SetTarget(Player)
)
-- Roll the Bones if you have no combat enhancements active.
DefaultAPL:AddSpell(
RollTheBones:CastableIf(function(self)
local numBuffs = 0
if Player:GetAuras():FindMy(Broadside):IsUp() then
numBuffs = numBuffs + 1
end
if Player:GetAuras():FindMy(BuriedTreasure):IsUp() then
numBuffs = numBuffs + 1
end
if Player:GetAuras():FindMy(GrandMelee):IsUp() then
numBuffs = numBuffs + 1
end
if Player:GetAuras():FindMy(RuthlessPrecision):IsUp() then
numBuffs = numBuffs + 1
end
if Player:GetAuras():FindMy(SkullAndCrossbones):IsUp() then
numBuffs = numBuffs + 1
end
if Player:GetAuras():FindMy(TrueBearing):IsUp() then
numBuffs = numBuffs + 1
end
return self:IsKnownAndUsable() and
not Player:IsCastingOrChanneling() and
((not Player:GetAuras():FindMy(Broadside):IsUp() and
not Player:GetAuras():FindMy(TrueBearing):IsUp()) or numBuffs < 2)
end):SetTarget(Player)
)
-- Slice and Dice if at max, or -1 from maximum combo points with Broadside or Opportunity active, if missing or has has 12 or less seconds remaining.
DefaultAPL:AddSpell(
SliceAndDice:CastableIf(function(self)
return Target:Exists() and Player:InMelee(Target) and
self:IsKnownAndUsable() and
not Player:IsCastingOrChanneling() and
(Player:GetComboPoints(Target) >= 5 or
(
Player:GetComboPoints(Target) >= 4 and
(Player:GetAuras():FindMy(Broadside):IsUp() or Player:GetAuras():FindMy(Opportunity):IsUp()))) and
(
not Player:GetAuras():FindMy(SliceAndDice):IsUp() or
Player:GetAuras():FindMy(SliceAndDice):GetRemainingTime() <= 12
)
end):SetTarget(Target)
)
-- Between the Eyes on cooldown if at max, or -1 from maximum combo points with Broadside or Opportunity active.
DefaultAPL:AddSpell(
BetweenTheEyes:CastableIf(function(self)
return Target:Exists() and Player:InMelee(Target) and
self:IsKnownAndUsable() and
not Player:IsCastingOrChanneling() and
(Player:GetComboPoints(Target) >= 5 or
(
Player:GetComboPoints(Target) >= 4 and
(Player:GetAuras():FindMy(Broadside):IsUp() or Player:GetAuras():FindMy(Opportunity):IsUp())))
end):SetTarget(Target)
)
-- Dispatch if at max, or -1 from maximum combo points with Broadside or Opportunity active.
DefaultAPL:AddSpell(
Dispatch:CastableIf(function(self)
return Target:Exists() and Player:InMelee(Target) and
self:IsKnownAndUsable() and
not Player:IsCastingOrChanneling() and
(Player:GetComboPoints(Target) >= 5 or
(
Player:GetComboPoints(Target) >= 4 and
(Player:GetAuras():FindMy(Broadside):IsUp() or Player:GetAuras():FindMy(Opportunity):IsUp())))
end):SetTarget(Target)
)
-- Shadow Dance at or below 3 combo points, and do not have Audacity or Opportunity active and wait until you have at least 80 energy. While active Ambush becomes your highest priority builder.
DefaultAPL:AddSpell(
ShadowDance:CastableIf(function(self)
return Target:Exists() and Player:InMelee(Target) and
self:IsKnownAndUsable() and
not Player:IsCastingOrChanneling() and
Player:GetComboPoints(Target) <= 3 and
not Player:GetAuras():FindMy(Audacity):IsUp() and
not Player:GetAuras():FindMy(Opportunity):IsUp() and
Player:GetPower() >= 80
end):SetTarget(Player)
)
-- Blade Rush if missing 50 or more energy and do not have Flagellation, Dreadblades or Shadow Dance active.
DefaultAPL:AddSpell(
BladeRush:CastableIf(function(self)
return Target:Exists() and Player:InMelee(Target) and
self:IsKnownAndUsable() and
not Player:IsCastingOrChanneling() and
Player:GetPower() <= 50 and
not Player:GetAuras():FindMy(Flagellation):IsUp() and
not Player:GetAuras():FindMy(Dreadblades):IsUp() and
not Player:GetAuras():FindMy(ShadowDance):IsUp()
end):SetTarget(Player)
)
-- Vanish followed by Ambush if you won't overcap combo points and wait until you have at least 50 energy.
DefaultAPL:AddSpell(
Vanish:CastableIf(function(self)
return Tank:Exists() and Target:Exists() and Player:InMelee(Target) and
self:IsKnownAndUsable() and
not Player:IsCastingOrChanneling() and
Player:GetComboPoints(Target) <= 4 and
Player:GetPower() >= 50 and not Player:GetAuras():FindMy(Stealth):IsUp()
end):SetTarget(Player)
)
-- Pistol Shot if you have an Opportunity proc and won't overcap combo points.
DefaultAPL:AddSpell(
PistolShot:CastableIf(function(self)
return Target:Exists() and Player:InMelee(Target) and
self:IsKnownAndUsable() and
not Player:IsCastingOrChanneling() and
Player:GetAuras():FindMy(Opportunity):IsUp() and
Player:GetComboPoints(Target) <= 4
end):SetTarget(Target)
)
-- Use Ambush Icon Ambush instead of Sinister Strike Icon Sinister Strike whenever it is available to cast from any of the procs or cooldowns.
DefaultAPL:AddSpell(
Ambush:CastableIf(function(self)
return Target:Exists() and Player:InMelee(Target) and
self:IsKnownAndUsable() and
not Player:IsCastingOrChanneling()
end):SetTarget(Target)
)
-- Sinister Strike if you won't overcap combo points.
DefaultAPL:AddSpell(
SinisterStrike:CastableIf(function(self)
return Target:Exists() and Player:InMelee(Target) and
self:IsKnownAndUsable() and
not Player:IsCastingOrChanneling() and
Player:GetComboPoints(Target) < 5
end):SetTarget(Target)
)
-- AOE APL
-- Adrenaline Rush on cooldown.
AOEAPL:AddSpell(
AdrenalineRush:CastableIf(function(self)
return Target:Exists() and Player:InMelee(Target) and
self:IsKnownAndUsable() and
not Player:IsCastingOrChanneling()
end):SetTarget(Player)
)
-- Roll the Bones if you have no combat enhancements active.
-- Roll the Bones has a large outcome of buffs which include; Broadside, Buried Treasure, Grand Melee, Ruthless Precision, Skull and Crossbones, and True Bearing. The buffs you want to keep this tier are going to be Broadside and True Bearing as single buffs or any combination of 2 or more buffs. Any of the other 4 buffs as a single means it's worth recasting Roll the Bones as soon as you are able to.
AOEAPL:AddSpell(
RollTheBones:CastableIf(function(self)
local numBuffs = 0
if Player:GetAuras():FindMy(Broadside):IsUp() then
numBuffs = numBuffs + 1
end
if Player:GetAuras():FindMy(BuriedTreasure):IsUp() then
numBuffs = numBuffs + 1
end
if Player:GetAuras():FindMy(GrandMelee):IsUp() then
numBuffs = numBuffs + 1
end
if Player:GetAuras():FindMy(RuthlessPrecision):IsUp() then
numBuffs = numBuffs + 1
end
if Player:GetAuras():FindMy(SkullAndCrossbones):IsUp() then
numBuffs = numBuffs + 1
end
if Player:GetAuras():FindMy(TrueBearing):IsUp() then
numBuffs = numBuffs + 1
end
return self:IsKnownAndUsable() and
not Player:IsCastingOrChanneling() and
((not Player:GetAuras():FindMy(Broadside):IsUp() and
not Player:GetAuras():FindMy(TrueBearing):IsUp()) or numBuffs < 2)
end):SetTarget(Player)
)
-- Blade Flurry when missing.
AOEAPL:AddSpell(
BladeFlurry:CastableIf(function(self)
return self:IsKnownAndUsable() and
not Player:IsCastingOrChanneling() and
(not Player:GetAuras():FindMy(self):IsUp() or Player:GetAuras():FindMy(self):GetRemainingTime() <= 2)
end):SetTarget(Player)
)
-- Slice and Dice if at max, or -1 from maximum combo points with Broadside or Opportunity active, if missing or has has 12 or less seconds remaining.
AOEAPL:AddSpell(
SliceAndDice:CastableIf(function(self)
return Target:Exists() and Player:InMelee(Target) and
self:IsKnownAndUsable() and
not Player:IsCastingOrChanneling() and
(Player:GetComboPoints(Target) >= 5 or
(Player:GetComboPoints(Target) >= 4 and
(Player:GetAuras():FindMy(Broadside):IsUp() or
Player:GetAuras():FindMy(Opportunity):IsUp()))) and
(not Player:GetAuras():FindMy(self):IsUp() or
Player:GetAuras():FindMy(self):GetRemainingTime() <= 12)
end):SetTarget(Player)
)
-- Between the Eyes on cooldown if at max, or -1 from maximum combo points with Broadside or Opportunity active.
AOEAPL:AddSpell(
BetweenTheEyes:CastableIf(function(self)
return Target:Exists() and Player:InMelee(Target) and
self:IsKnownAndUsable() and
not Player:IsCastingOrChanneling() and
(Player:GetComboPoints(Target) >= 5 or
(Player:GetComboPoints(Target) >= 4 and
(Player:GetAuras():FindMy(Broadside):IsUp() or
Player:GetAuras():FindMy(Opportunity):IsUp())))
end):SetTarget(Target)
)
-- Dispatch if at max, or -1 from maximum combo points with Broadside or Opportunity active.
AOEAPL:AddSpell(
Dispatch:CastableIf(function(self)
return Target:Exists() and Player:InMelee(Target) and
self:IsKnownAndUsable() and
not Player:IsCastingOrChanneling() and
(Player:GetComboPoints(Target) >= 5 or
(Player:GetComboPoints(Target) >= 4 and
(Player:GetAuras():FindMy(Broadside):IsUp() or
Player:GetAuras():FindMy(Opportunity):IsUp())))
end):SetTarget(Target)
)
-- Shadow Dance at or below 3 combo points, and do not have Audacity or Opportunity active and wait until you have at least 80 energy. While active Ambush becomes your highest priority builder.
AOEAPL:AddSpell(
ShadowDance:CastableIf(function(self)
return Target:Exists() and Player:InMelee(Target) and
self:IsKnownAndUsable() and
not Player:IsCastingOrChanneling() and
Player:GetComboPoints(Target) <= 3 and
not Player:GetAuras():FindMy(Audacity):IsUp() and
not Player:GetAuras():FindMy(Opportunity):IsUp() and
Player:GetPower() >= 80
end):SetTarget(Player)
)
-- Blade Rush if missing 50 or more energy and do not have Flagellation, Dreadblades or Shadow Dance active.
AOEAPL:AddSpell(
BladeRush:CastableIf(function(self)
return Target:Exists() and Player:InMelee(Target) and
self:IsKnownAndUsable() and
not Player:IsCastingOrChanneling() and
Player:GetPower() >= 50 and
not Player:GetAuras():FindMy(Flagellation):IsUp() and
not Player:GetAuras():FindMy(Dreadblades):IsUp() and
not Player:GetAuras():FindMy(ShadowDance):IsUp()
end):SetTarget(Player)
)
-- Vanish followed by Ambush if you won't overcap combo points and wait until you have at least 50 energy.
AOEAPL:AddSpell(
Vanish:CastableIf(function(self)
return Tank:Exists() and Target:Exists() and Player:InMelee(Target) and
self:IsKnownAndUsable() and
not Player:IsCastingOrChanneling() and
Player:GetComboPoints(Target) < 5 and
Player:GetPower() >= 50 and not Player:GetAuras():FindMy(Stealth):IsUp()
end):SetTarget(Player)
)
-- Pistol Shot if you have an Opportunity proc and won't overcap combo points.
AOEAPL:AddSpell(
PistolShot:CastableIf(function(self)
return Target:Exists() and Player:InMelee(Target) and
self:IsKnownAndUsable() and
not Player:IsCastingOrChanneling() and
Player:GetAuras():FindMy(Opportunity):IsUp() and
Player:GetComboPoints(Target) < 5
end):SetTarget(Target)
)
AOEAPL:AddSpell(
Ambush:CastableIf(function(self)
return Target:Exists() and Player:InMelee(Target) and
self:IsKnownAndUsable() and
not Player:IsCastingOrChanneling()
end):SetTarget(Target)
)
-- Sinister Strike if you won't overcap combo points.
AOEAPL:AddSpell(
SinisterStrike:CastableIf(function(self)
return Target:Exists() and Player:InMelee(Target) and
self:IsKnownAndUsable() and
not Player:IsCastingOrChanneling() and
Player:GetComboPoints(Target) < 5
end):SetTarget(Target)
)
OutlawModule:Sync(function()
SpecialAPL:Execute()
if Player:GetMeleeAttackers() > 1 then
AOEAPL:Execute()
else
DefaultAPL:Execute()
end
end)
Bastion:Register(OutlawModule)

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -1,8 +1,13 @@
-- Document with emmy lua: https://emmylua.github.io/
-- Create an APL trait for the APL class -- Create an APL trait for the APL class
---@class APLTrait
local APLTrait = {} local APLTrait = {}
APLTrait.__index = APLTrait APLTrait.__index = APLTrait
-- Constructor -- Constructor
---@param cb fun():boolean
---@return APLTrait
function APLTrait:New(cb) function APLTrait:New(cb)
local self = setmetatable({}, APLTrait) local self = setmetatable({}, APLTrait)
@ -13,6 +18,7 @@ function APLTrait:New(cb)
end end
-- Evaulate the APL trait -- Evaulate the APL trait
---@return boolean
function APLTrait:Evaluate() function APLTrait:Evaluate()
if GetTime() - self.lastcall > 0.1 then if GetTime() - self.lastcall > 0.1 then
self.lastresult = self.cb() self.lastresult = self.cb()
@ -24,15 +30,18 @@ function APLTrait:Evaluate()
end end
-- tostring -- tostring
---@return string
function APLTrait:__tostring() function APLTrait:__tostring()
return "Bastion.__APLTrait" return "Bastion.__APLTrait"
end end
-- Create an APL actor for the APL class -- Create an APL actor for the APL class
---@class APLActor
local APLActor = {} local APLActor = {}
APLActor.__index = APLActor APLActor.__index = APLActor
-- Constructor -- Constructor
---@param actor table
function APLActor:New(actor) function APLActor:New(actor)
local self = setmetatable({}, APLActor) local self = setmetatable({}, APLActor)
@ -43,6 +52,8 @@ function APLActor:New(actor)
end end
-- Add a trait to the APL actor -- Add a trait to the APL actor
---@param ... APLTrait
---@return APLActor
function APLActor:AddTraits(...) function APLActor:AddTraits(...)
for _, trait in ipairs({ ... }) do for _, trait in ipairs({ ... }) do
table.insert(self.traits, trait) table.insert(self.traits, trait)
@ -52,11 +63,13 @@ function APLActor:AddTraits(...)
end end
-- Get the actor -- Get the actor
---@return table
function APLActor:GetActor() function APLActor:GetActor()
return self.actor return self.actor
end end
-- Evaulate the APL actor -- Evaulate the APL actor
---@return boolean
function APLActor:Evaluate() function APLActor:Evaluate()
for _, trait in ipairs(self.traits) do for _, trait in ipairs(self.traits) do
if not trait:Evaluate() then if not trait:Evaluate() then
@ -106,21 +119,25 @@ function APLActor:Execute()
end end
-- has traits -- has traits
---@return boolean
function APLActor:HasTraits() function APLActor:HasTraits()
return #self.traits > 0 return #self.traits > 0
end end
-- tostring -- tostring
---@return string
function APLActor:__tostring() function APLActor:__tostring()
return "Bastion.__APLActor" return "Bastion.__APLActor"
end end
-- APL (Attack priority list) class -- APL (Attack priority list) class
---@class APL
local APL = {} local APL = {}
APL.__index = APL APL.__index = APL
-- Constructor -- Constructor
---@param name string
---@return APL
function APL:New(name) function APL:New(name)
local self = setmetatable({}, APL) local self = setmetatable({}, APL)
@ -132,16 +149,23 @@ function APL:New(name)
end end
-- Add a variable to the APL -- Add a variable to the APL
---@param name string
---@param value any
function APL:SetVariable(name, value) function APL:SetVariable(name, value)
self.variables[name] = value self.variables[name] = value
end end
-- Get and evaluate a variable -- Get and evaluate a variable
---@param name string
---@return boolean
function APL:GetVariable(name) function APL:GetVariable(name)
return self.variables[name] return self.variables[name]
end end
-- Add variable -- Add variable
---@param name string
---@param cb fun(...):any
---@return APLActor
function APL:AddVariable(name, cb) function APL:AddVariable(name, cb)
local actor = APLActor:New({ variable = name, cb = cb, _apl = self }) local actor = APLActor:New({ variable = name, cb = cb, _apl = self })
table.insert(self.apl, actor) table.insert(self.apl, actor)
@ -149,6 +173,9 @@ function APL:AddVariable(name, cb)
end end
-- Add a manual action to the APL -- Add a manual action to the APL
---@param action string
---@param cb fun(...):any
---@return APLActor
function APL:AddAction(action, cb) function APL:AddAction(action, cb)
local actor = APLActor:New({ action = action, cb = cb }) local actor = APLActor:New({ action = action, cb = cb })
table.insert(self.apl, actor) table.insert(self.apl, actor)
@ -156,6 +183,9 @@ function APL:AddAction(action, cb)
end end
-- Add a spell to the APL -- Add a spell to the APL
---@param spell Spell
---@param condition fun(...):boolean
---@return APLActor
function APL:AddSpell(spell, condition) function APL:AddSpell(spell, condition)
local castableFunc = spell.CastableIfFunc local castableFunc = spell.CastableIfFunc
local target = spell:GetTarget() local target = spell:GetTarget()
@ -168,6 +198,9 @@ function APL:AddSpell(spell, condition)
end end
-- Add an item to the APL -- Add an item to the APL
---@param item Item
---@param condition fun(...):boolean
---@return APLActor
function APL:AddItem(item, condition) function APL:AddItem(item, condition)
local usableFunc = item.UsableIfFunc local usableFunc = item.UsableIfFunc
local target = item:GetTarget() local target = item:GetTarget()
@ -180,6 +213,9 @@ function APL:AddItem(item, condition)
end end
-- Add an APL to the APL (for sub APLs) -- Add an APL to the APL (for sub APLs)
---@param apl APL
---@param condition fun(...):boolean
---@return APLActor
function APL:AddAPL(apl, condition) function APL:AddAPL(apl, condition)
if not condition then if not condition then
error("Bastion: APL:AddAPL: No condition for APL " .. apl.name) error("Bastion: APL:AddAPL: No condition for APL " .. apl.name)
@ -201,6 +237,7 @@ function APL:Execute()
end end
-- tostring -- tostring
---@return string
function APL:__tostring() function APL:__tostring()
return "Bastion.__APL(" .. self.name .. ")" return "Bastion.__APL(" .. self.name .. ")"
end end

@ -1,3 +1,5 @@
-- Document with emmy lua: https://emmylua.github.io/
local Tinkr, Bastion = ... local Tinkr, Bastion = ...
-- Create a new Aura class -- Create a new Aura class
@ -19,6 +21,8 @@ function Aura:__index(k)
end end
-- Equals -- Equals
---@param other Aura|Spell
---@return boolean
function Aura:__eq(other) function Aura:__eq(other)
if getmetatable(other) == Aura then if getmetatable(other) == Aura then
return self:GetSpell():GetID() == other:GetSpell():GetID() return self:GetSpell():GetID() == other:GetSpell():GetID()
@ -31,11 +35,16 @@ function Aura:__eq(other)
return false return false
end end
-- tostring
---@return string
function Aura:__tostring() function Aura:__tostring()
return "Bastion.__Aura(" .. self:GetSpell():GetID() .. ")" .. " - " .. (self:GetName() or "''") return "Bastion.__Aura(" .. self:GetSpell():GetID() .. ")" .. " - " .. (self:GetName() or "''")
end end
-- Constructor -- Constructor
---@param unit Unit
---@param index number
---@param type string
function Aura:New(unit, index, type) function Aura:New(unit, index, type)
if unit == nil then if unit == nil then
local self = setmetatable({}, Aura) local self = setmetatable({}, Aura)
@ -68,7 +77,8 @@ function Aura:New(unit, index, type)
end end
local name, icon, count, dispelType, duration, expirationTime, source, isStealable, nameplateShowPersonal, local name, icon, count, dispelType, duration, expirationTime, source, isStealable, nameplateShowPersonal,
spellId, canApplyAura, isBossDebuff, castByPlayer, nameplateShowAll, timeMod = UnitAura(unit:GetOMToken(), index, type) spellId, canApplyAura, isBossDebuff, castByPlayer, nameplateShowAll, timeMod = UnitAura(unit:GetOMToken(), index,
type)
local self = setmetatable({}, Aura) local self = setmetatable({}, Aura)
self.aura = { self.aura = {
@ -98,6 +108,9 @@ function Aura:New(unit, index, type)
return self return self
end end
-- Constructor
---@param unitAuraInfo UnitAuraInfo
---@return Aura
function Aura:CreateFromUnitAuraInfo(unitAuraInfo) function Aura:CreateFromUnitAuraInfo(unitAuraInfo)
local self = setmetatable({}, Aura) local self = setmetatable({}, Aura)
self.aura = { self.aura = {
@ -128,56 +141,67 @@ function Aura:CreateFromUnitAuraInfo(unitAuraInfo)
end end
-- Check if the aura is valid -- Check if the aura is valid
---@return boolean
function Aura:IsValid() function Aura:IsValid()
return self.aura.name ~= nil return self.aura.name ~= nil
end end
-- Check if the aura is up -- Check if the aura is up
---@return boolean
function Aura:IsUp() function Aura:IsUp()
return self:IsValid() and (self:GetDuration() == 0 or self:GetRemainingTime() > 0) return self:IsValid() and (self:GetDuration() == 0 or self:GetRemainingTime() > 0)
end end
-- Check if the aura is down -- Check if the aura is down
---@return boolean
function Aura:IsDown() function Aura:IsDown()
return not self:IsUp() return not self:IsUp()
end end
-- Get the auras index -- Get the auras index
---@return number
function Aura:GetIndex() function Aura:GetIndex()
return self.aura.index return self.aura.index
end end
-- Get the auras type -- Get the auras type
---@return string
function Aura:GetType() function Aura:GetType()
return self.aura.type return self.aura.type
end end
-- Get the auras name -- Get the auras name
---@return string
function Aura:GetName() function Aura:GetName()
return self.aura.name return self.aura.name
end end
-- Get the auras icon -- Get the auras icon
---@return string
function Aura:GetIcon() function Aura:GetIcon()
return self.aura.icon return self.aura.icon
end end
-- Get the auras count -- Get the auras count
---@return number
function Aura:GetCount() function Aura:GetCount()
return self.aura.count return self.aura.count
end end
-- Get the auras dispel type -- Get the auras dispel type
---@return string
function Aura:GetDispelType() function Aura:GetDispelType()
return self.aura.dispelType return self.aura.dispelType
end end
-- Get the auras duration -- Get the auras duration
---@return number
function Aura:GetDuration() function Aura:GetDuration()
return self.aura.duration return self.aura.duration
end end
-- Get the auras remaining time -- Get the auras remaining time
---@return number
function Aura:GetRemainingTime() function Aura:GetRemainingTime()
local remainingTime = self.aura.expirationTime - GetTime() local remainingTime = self.aura.expirationTime - GetTime()
@ -189,71 +213,85 @@ function Aura:GetRemainingTime()
end end
-- Get the auras expiration time -- Get the auras expiration time
---@return number
function Aura:GetExpirationTime() function Aura:GetExpirationTime()
return self.aura.expirationTime return self.aura.expirationTime
end end
-- Get the auras source -- Get the auras source
---@return Unit
function Aura:GetSource() function Aura:GetSource()
return Bastion.UnitManager[self.aura.source] return Bastion.UnitManager[self.aura.source]
end end
-- Get the auras stealable status -- Get the auras stealable status
---@return boolean
function Aura:GetIsStealable() function Aura:GetIsStealable()
return self.aura.isStealable return self.aura.isStealable
end end
-- Get the auras nameplate show personal status -- Get the auras nameplate show personal status
---@return boolean
function Aura:GetNameplateShowPersonal() function Aura:GetNameplateShowPersonal()
return self.aura.nameplateShowPersonal return self.aura.nameplateShowPersonal
end end
-- Get the auras spell id -- Get the auras spell id
---@return Spell
function Aura:GetSpell() function Aura:GetSpell()
return Bastion.SpellBook:GetSpell(self.aura.spellId) return Bastion.SpellBook:GetSpell(self.aura.spellId)
end end
-- Get the auras can apply aura status -- Get the auras can apply aura status
---@return boolean
function Aura:GetCanApplyAura() function Aura:GetCanApplyAura()
return self.aura.canApplyAura return self.aura.canApplyAura
end end
-- Get the auras is boss debuff status -- Get the auras is boss debuff status
---@return boolean
function Aura:GetIsBossDebuff() function Aura:GetIsBossDebuff()
return self.aura.isBossDebuff return self.aura.isBossDebuff
end end
-- Get the auras cast by player status -- Get the auras cast by player status
---@return boolean
function Aura:GetCastByPlayer() function Aura:GetCastByPlayer()
return self.aura.castByPlayer return self.aura.castByPlayer
end end
-- Get the auras nameplate show all status -- Get the auras nameplate show all status
---@return boolean
function Aura:GetNameplateShowAll() function Aura:GetNameplateShowAll()
return self.aura.nameplateShowAll return self.aura.nameplateShowAll
end end
-- Get the auras time mod -- Get the auras time mod
---@return number
function Aura:GetTimeMod() function Aura:GetTimeMod()
return self.aura.timeMod return self.aura.timeMod
end end
-- Check if the aura is a buff -- Check if the aura is a buff
---@return boolean
function Aura:IsBuff() function Aura:IsBuff()
return self.aura.type == "HELPFUL" return self.aura.type == "HELPFUL"
end end
-- Check if the aura is a debuff -- Check if the aura is a debuff
---@return boolean
function Aura:IsDebuff() function Aura:IsDebuff()
return self.aura.type == "HARMFUL" return self.aura.type == "HARMFUL"
end end
-- Get aura instance id -- Get aura instance id
---@return number
function Aura:GetAuraInstanceID() function Aura:GetAuraInstanceID()
return self.aura.auraInstanceID return self.aura.auraInstanceID
end end
-- Check if the aura is dispelable by a spell -- Check if the aura is dispelable by a spell
---@param spell Spell
function Aura:IsDispelableBySpell(spell) function Aura:IsDispelableBySpell(spell)
if self:GetDispelType() == nil then if self:GetDispelType() == nil then
return false return false

@ -5,15 +5,9 @@ local Tinkr, Bastion = ...
local AuraTable = {} local AuraTable = {}
AuraTable.__index = 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 -- Constructor
---@param unit Unit
---@return AuraTable
function AuraTable:New(unit) function AuraTable:New(unit)
local self = setmetatable({}, AuraTable) local self = setmetatable({}, AuraTable)
@ -28,6 +22,8 @@ function AuraTable:New(unit)
return self return self
end end
---@param auras UnitAuraUpdateInfo
---@return nil
function AuraTable:OnUpdate(auras) function AuraTable:OnUpdate(auras)
if not auras then if not auras then
self:Update() self:Update()
@ -73,6 +69,8 @@ function AuraTable:OnUpdate(auras)
end end
end end
---@param instanceID number
---@return nil
function AuraTable:RemoveInstanceID(instanceID) function AuraTable:RemoveInstanceID(instanceID)
if not self.instanceIDLookup[instanceID] then if not self.instanceIDLookup[instanceID] then
return return
@ -93,6 +91,10 @@ function AuraTable:RemoveInstanceID(instanceID)
end end
end end
-- Update the aura table
---@param instanceID number
---@param aura Aura
---@return nil
function AuraTable:AddOrUpdateAuraInstanceID(instanceID, aura) function AuraTable:AddOrUpdateAuraInstanceID(instanceID, aura)
local spellId = aura:GetSpell():GetID() local spellId = aura:GetSpell():GetID()
@ -114,6 +116,7 @@ function AuraTable:AddOrUpdateAuraInstanceID(instanceID, aura)
end end
-- Get a units buffs -- Get a units buffs
---@return nil
function AuraTable:GetUnitBuffs() function AuraTable:GetUnitBuffs()
if Tinkr.classic then if Tinkr.classic then
for i = 1, 40 do for i = 1, 40 do
@ -152,6 +155,7 @@ function AuraTable:GetUnitBuffs()
end end
-- Get a units debuffs -- Get a units debuffs
---@return nil
function AuraTable:GetUnitDebuffs() function AuraTable:GetUnitDebuffs()
if Tinkr.classic then if Tinkr.classic then
for i = 1, 40 do for i = 1, 40 do
@ -190,6 +194,7 @@ function AuraTable:GetUnitDebuffs()
end end
-- Update auras -- Update auras
---@return nil
function AuraTable:Update() function AuraTable:Update()
-- print("Updating auras for " .. tostring(self.unit)) -- print("Updating auras for " .. tostring(self.unit))
self:Clear() self:Clear()
@ -203,6 +208,7 @@ function AuraTable:Update()
end end
-- Get a units auras -- Get a units auras
---@return table
function AuraTable:GetUnitAuras() function AuraTable:GetUnitAuras()
if not self.did then if not self.did then
self.did = true self.did = true
@ -226,6 +232,7 @@ function AuraTable:GetUnitAuras()
end end
-- Get a units auras -- Get a units auras
---@return table
function AuraTable:GetMyUnitAuras() function AuraTable:GetMyUnitAuras()
if not self.did then if not self.did then
self.did = true self.did = true
@ -249,6 +256,7 @@ function AuraTable:GetMyUnitAuras()
end end
-- Clear the aura table -- Clear the aura table
---@return nil
function AuraTable:Clear() function AuraTable:Clear()
self.auras = {} self.auras = {}
self.playerAuras = {} self.playerAuras = {}
@ -256,6 +264,7 @@ function AuraTable:Clear()
end end
-- Check if the unit has a specific aura -- Check if the unit has a specific aura
---@param spell Spell
---@return Aura ---@return Aura
function AuraTable:Find(spell) function AuraTable:Find(spell)
local auras = self:GetUnitAuras() local auras = self:GetUnitAuras()
@ -281,6 +290,8 @@ function AuraTable:Find(spell)
return Bastion.Aura:New() return Bastion.Aura:New()
end end
-- Check if the unit has a specific aura
---@param spell Spell
---@return Aura ---@return Aura
function AuraTable:FindMy(spell) function AuraTable:FindMy(spell)
local auras = self:GetMyUnitAuras() local auras = self:GetMyUnitAuras()
@ -305,6 +316,10 @@ function AuraTable:FindMy(spell)
return Bastion.Aura:New() return Bastion.Aura:New()
end end
-- Check if the unit has a specific aura
---@param spell Spell
---@param source Unit
---@return Aura
function AuraTable:FindFrom(spell, source) function AuraTable:FindFrom(spell, source)
local auras = self:GetUnitAuras() local auras = self:GetUnitAuras()
local aurasub = auras[spell:GetID()] local aurasub = auras[spell:GetID()]
@ -331,6 +346,8 @@ function AuraTable:FindFrom(spell, source)
end end
-- Find the aura from the current unit -- Find the aura from the current unit
---@param spell Spell
---@return Aura
function AuraTable:FindTheirs(spell) function AuraTable:FindTheirs(spell)
local auras = self:GetUnitAuras() local auras = self:GetUnitAuras()
local aurasub = auras[spell:GetID()] local aurasub = auras[spell:GetID()]
@ -357,6 +374,7 @@ function AuraTable:FindTheirs(spell)
end end
-- Find any -- Find any
---@param spell Spell
---@return Aura ---@return Aura
function AuraTable:FindAny(spell) function AuraTable:FindAny(spell)
local a = self:Find(spell) local a = self:Find(spell)
@ -368,6 +386,7 @@ function AuraTable:FindAny(spell)
end end
-- Has any stealable aura -- Has any stealable aura
---@return boolean
function AuraTable:HasAnyStealableAura() function AuraTable:HasAnyStealableAura()
for _, auras in pairs(self:GetUnitAuras()) do for _, auras in pairs(self:GetUnitAuras()) do
for _, aura in pairs(auras) do for _, aura in pairs(auras) do
@ -385,6 +404,8 @@ function AuraTable:HasAnyStealableAura()
end end
-- Has any dispelable aura -- Has any dispelable aura
---@param spell Spell
---@return boolean
function AuraTable:HasAnyDispelableAura(spell) function AuraTable:HasAnyDispelableAura(spell)
for _, auras in pairs(self:GetUnitAuras()) do for _, auras in pairs(self:GetUnitAuras()) do
for _, aura in pairs(auras) do for _, aura in pairs(auras) do

@ -1,13 +1,19 @@
---@class Cache
local Cache = {} local Cache = {}
Cache.__index = Cache Cache.__index = Cache
-- Constructor -- Constructor
---@return Cache
function Cache:New() function Cache:New()
local self = setmetatable({}, Cache) local self = setmetatable({}, Cache)
self.cache = {} self.cache = {}
return self return self
end end
---@param key any
---@param value any
---@param duration number
---@return nil
function Cache:Set(key, value, duration) function Cache:Set(key, value, duration)
self.cache = self.cache or {} self.cache = self.cache or {}
self.cache[key] = { self.cache[key] = {
@ -17,6 +23,8 @@ function Cache:Set(key, value, duration)
} }
end end
---@param key any
---@return any
function Cache:Get(key) function Cache:Get(key)
self.cache = self.cache or {} self.cache = self.cache or {}
local cache = self.cache[key] local cache = self.cache[key]
@ -30,6 +38,8 @@ function Cache:Get(key)
return nil return nil
end end
---@param key any
---@return boolean
function Cache:IsCached(key) function Cache:IsCached(key)
self.cache = self.cache or {} self.cache = self.cache or {}
local cache = self.cache[key] local cache = self.cache[key]

@ -1,10 +1,14 @@
local Tinkr, Bastion = ... local Tinkr, Bastion = ...
-- Define a Cacheable class -- Define a Cacheable class
---@class Cacheable
local Cacheable = { local Cacheable = {
cache = nil, cache = nil,
callback = nil, callback = nil,
value = nil value = nil,
-- __eq = function(self, other)
-- return self.value.__eq(self.value, other)
-- end
} }
-- On index check the cache to be valid and return the value or reconstruct the value and return it -- On index check the cache to be valid and return the value or reconstruct the value and return it
@ -26,11 +30,14 @@ function Cacheable:__index(k)
end end
-- When the object is accessed return the value -- When the object is accessed return the value
---@return string
function Cacheable:__tostring() function Cacheable:__tostring()
return "Bastion.__Cacheable(" .. tostring(self.value) .. ")" return "Bastion.__Cacheable(" .. tostring(self.value) .. ")"
end end
-- Create -- Create
---@param value any
---@param cb fun():any
function Cacheable:New(value, cb) function Cacheable:New(value, cb)
local self = setmetatable({}, Cacheable) local self = setmetatable({}, Cacheable)
@ -44,6 +51,7 @@ function Cacheable:New(value, cb)
end end
-- Try to update the value -- Try to update the value
---@return nil
function Cacheable:TryUpdate() function Cacheable:TryUpdate()
if self.cache:IsCached("value") then if self.cache:IsCached("value") then
self.value = self.callback() self.value = self.callback()
@ -51,16 +59,19 @@ function Cacheable:TryUpdate()
end end
-- Update the value -- Update the value
---@return nil
function Cacheable:Update() function Cacheable:Update()
self.value = self.callback() self.value = self.callback()
end end
-- Set a new value -- Set a new value
---@param value any
function Cacheable:Set(value) function Cacheable:Set(value)
self.value = value self.value = value
end end
-- Set a new callback -- Set a new callback
---@param cb fun():any
function Cacheable:SetCallback(cb) function Cacheable:SetCallback(cb)
self.callback = cb self.callback = cb
end end

@ -1,6 +1,7 @@
local Tinkr, Bastion = ... local Tinkr, Bastion = ...
-- Create a new Class class -- Create a new Class class
---@class Class
local Class = {} local Class = {}
function Class:__index(k) function Class:__index(k)
@ -18,6 +19,9 @@ function Class:__index(k)
end end
-- Constructor -- Constructor
---@param locale string
---@param name string
---@param id number
function Class:New(locale, name, id) function Class:New(locale, name, id)
local self = setmetatable({}, Class) local self = setmetatable({}, Class)
self.class = { self.class = {
@ -29,21 +33,25 @@ function Class:New(locale, name, id)
end end
-- Get the classes locale -- Get the classes locale
---@return string
function Class:GetLocale() function Class:GetLocale()
return self.class.locale return self.class.locale
end end
-- Get the classes name -- Get the classes name
---@return string
function Class:GetName() function Class:GetName()
return self.class.name return self.class.name
end end
-- Get the classes id -- Get the classes id
---@return number
function Class:GetID() function Class:GetID()
return self.class.id return self.class.id
end end
-- Return the classes color -- Return the classes color
---@return ColorMixin classColor
function Class:GetColor() function Class:GetColor()
return C_ClassColor.GetClassColor(self.class.name) return C_ClassColor.GetClassColor(self.class.name)
end end

@ -1,6 +1,10 @@
---@class ClassMagic
local ClassMagic = {} local ClassMagic = {}
ClassMagic.__index = ClassMagic ClassMagic.__index = ClassMagic
---@param Class table
---@param key string
---@return any
function ClassMagic:Resolve(Class, key) function ClassMagic:Resolve(Class, key)
if Class[key] or Class[key] == false then if Class[key] or Class[key] == false then
return Class[key] return Class[key]

@ -1,12 +1,14 @@
-- Create a wow command handler class -- Create a wow command handler class
---@class Command
local Command = {} local Command = {}
Command.__index = Command Command.__index = Command
---@return string
function Command:__tostring() function Command:__tostring()
return "Command(" .. self.command .. ")" return "Command(" .. self.command .. ")"
end end
---@param prefix string
function Command:New(prefix) function Command:New(prefix)
local self = setmetatable({}, Command) local self = setmetatable({}, Command)
@ -21,6 +23,10 @@ function Command:New(prefix)
return self return self
end end
---@param command string
---@param helpmsg string
---@param cb fun(args: table)
---@return nil
function Command:Register(command, helpmsg, cb) function Command:Register(command, helpmsg, cb)
self.commands[command] = { self.commands[command] = {
helpmsg = helpmsg, helpmsg = helpmsg,
@ -28,6 +34,8 @@ function Command:Register(command, helpmsg, cb)
} }
end end
---@param msg string
---@return table
function Command:Parse(msg) function Command:Parse(msg)
local args = {} local args = {}
for arg in msg:gmatch("%S+") do for arg in msg:gmatch("%S+") do
@ -37,6 +45,8 @@ function Command:Parse(msg)
return args return args
end end
---@param msg string
---@return nil
function Command:OnCommand(msg) function Command:OnCommand(msg)
local args = self:Parse(msg) local args = self:Parse(msg)
@ -51,6 +61,7 @@ function Command:OnCommand(msg)
end end
end end
---@return nil
function Command:PrintHelp() function Command:PrintHelp()
for k, v in pairs(self.commands) do for k, v in pairs(self.commands) do
print('/' .. self.prefix .. ' ' .. k .. " - " .. v.helpmsg) print('/' .. self.prefix .. ' ' .. k .. " - " .. v.helpmsg)

@ -1,5 +1,5 @@
-- Create an EventManager class -- Create an EventManager class
---@class EventManager
local EventManager = { local EventManager = {
events = {}, events = {},
eventHandlers = {}, eventHandlers = {},
@ -10,6 +10,7 @@ local EventManager = {
EventManager.__index = EventManager EventManager.__index = EventManager
-- Constructor -- Constructor
---@return EventManager
function EventManager:New() function EventManager:New()
local self = setmetatable({}, EventManager) local self = setmetatable({}, EventManager)
self.events = {} self.events = {}
@ -31,6 +32,9 @@ function EventManager:New()
end end
-- Register an event -- Register an event
---@param event string
---@param handler fun(...)
---@return nil
function EventManager:RegisterEvent(event, handler) function EventManager:RegisterEvent(event, handler)
if not self.events[event] then if not self.events[event] then
self.events[event] = {} self.events[event] = {}
@ -40,6 +44,9 @@ function EventManager:RegisterEvent(event, handler)
end end
-- Register a wow event -- Register a wow event
---@param event string
---@param handler fun(...)
---@return nil
function EventManager:RegisterWoWEvent(event, handler) function EventManager:RegisterWoWEvent(event, handler)
if not self.wowEventHandlers[event] then if not self.wowEventHandlers[event] then
self.wowEventHandlers[event] = {} self.wowEventHandlers[event] = {}
@ -50,6 +57,9 @@ function EventManager:RegisterWoWEvent(event, handler)
end end
-- Trigger an event -- Trigger an event
---@param event string
---@param ... any
---@return nil
function EventManager:TriggerEvent(event, ...) function EventManager:TriggerEvent(event, ...)
if self.events[event] then if self.events[event] then
for _, handler in pairs(self.events[event]) do for _, handler in pairs(self.events[event]) do

@ -31,16 +31,20 @@ function Item:__index(k)
end end
-- Equals -- Equals
---@param other Item
---@return boolean
function Item:__eq(other) function Item:__eq(other)
return self:GetID() == other:GetID() return self:GetID() == other:GetID()
end end
-- tostring -- tostring
---@return string
function Item:__tostring() function Item:__tostring()
return "Bastion.__Item(" .. self:GetID() .. ")" .. " - " .. self:GetName() return "Bastion.__Item(" .. self:GetID() .. ")" .. " - " .. self:GetName()
end end
-- Constructor -- Constructor
---@param id number
function Item:New(id) function Item:New(id)
local self = setmetatable({}, Item) local self = setmetatable({}, Item)
@ -57,47 +61,58 @@ function Item:New(id)
end end
-- Get the Items id -- Get the Items id
---@return number
function Item:GetID() function Item:GetID()
return self.ItemID return self.ItemID
end end
-- Get the Items name -- Get the Items name
---@return string
function Item:GetName() function Item:GetName()
return GetItemInfo(self:GetID()) return GetItemInfo(self:GetID())
end end
-- Get the Items icon -- Get the Items icon
---@return number
function Item:GetIcon() function Item:GetIcon()
return select(3, GetItemInfo(self:GetID())) return select(3, GetItemInfo(self:GetID()))
end end
-- Get the Items cooldown -- Get the Items cooldown
---@return number
function Item:GetCooldown() function Item:GetCooldown()
return select(2, C_Container.GetItemCooldown(self:GetID())) return select(2, C_Container.GetItemCooldown(self:GetID()))
end end
-- Return the Usable function -- Return the Usable function
---@return function | boolean
function Item:GetUsableFunction() function Item:GetUsableFunction()
return self.UsableIfFunc return self.UsableIfFunc
end end
-- Return the preUse function -- Return the preUse function
---@return function | boolean
function Item:GetPreUseFunction() function Item:GetPreUseFunction()
return self.PreUseFunc return self.PreUseFunc
end end
-- Get the on Use func -- Get the on Use func
---@return function | boolean
function Item:GetOnUseFunction() function Item:GetOnUseFunction()
return self.OnUseFunc return self.OnUseFunc
end end
-- Get the Items cooldown remaining -- Get the Items cooldown remaining
---@return number
function Item:GetCooldownRemaining() function Item:GetCooldownRemaining()
local start, duration = C_Container.GetItemCooldown(self:GetID()) local start, duration = C_Container.GetItemCooldown(self:GetID())
return start + duration - GetTime() return start + duration - GetTime()
end end
-- Use the Item -- Use the Item
---@param unit Unit
---@param condition string
---@return boolean
function Item:Use(unit, condition) function Item:Use(unit, condition)
if condition and not self:EvaluateCondition(condition) then if condition and not self:EvaluateCondition(condition) then
return false return false
@ -127,46 +142,56 @@ function Item:Use(unit, condition)
if self:GetOnUseFunction() then if self:GetOnUseFunction() then
self:GetOnUseFunction()(self) self:GetOnUseFunction()(self)
end end
return true
end end
-- Last use attempt -- Last use attempt
---@return number
function Item:GetLastUseAttempt() function Item:GetLastUseAttempt()
return self.lastUseAttempt return self.lastUseAttempt
end end
-- Time since last attepmt -- Time since last attepmt
---@return number
function Item:GetTimeSinceLastUseAttempt() function Item:GetTimeSinceLastUseAttempt()
return GetTime() - self:GetLastUseAttempt() return GetTime() - self:GetLastUseAttempt()
end end
-- Check if the Item is known -- Check if the Item is known
---@return boolean
function Item:IsEquipped() function Item:IsEquipped()
return IsEquippedItem(self:GetID()) return IsEquippedItem(self:GetID())
end end
-- Check if the Item is on cooldown -- Check if the Item is on cooldown
---@return boolean
function Item:IsOnCooldown() function Item:IsOnCooldown()
return select(2, C_Container.GetItemCooldown(self:GetID())) > 0 return select(2, C_Container.GetItemCooldown(self:GetID())) > 0
end end
-- Check if the Item is usable -- Check if the Item is usable
---@return boolean
function Item:IsUsable() function Item:IsUsable()
local usable, noMana = IsUsableItem(self:GetID()) local usable, noMana = IsUsableItem(self:GetID())
return usable or usableExcludes[self:GetID()] return usable or usableExcludes[self:GetID()]
end end
-- Check if the Item is Usable -- Check if the Item is Usable
---@return boolean
function Item:IsEquippedAndUsable() function Item:IsEquippedAndUsable()
return ((self:IsEquippable() and self:IsEquipped()) or return ((self:IsEquippable() and self:IsEquipped()) or
(not self:IsEquippable() and self:IsUsable())) and not self:IsOnCooldown() (not self:IsEquippable() and self:IsUsable())) and not self:IsOnCooldown()
end end
-- Is equippable -- Is equippable
---@return boolean
function Item:IsEquippable() function Item:IsEquippable()
return IsEquippableItem(self:GetID()) return IsEquippableItem(self:GetID())
end end
-- Check if the Item is Usable -- Check if the Item is Usable
---@return boolean
function Item:Usable() function Item:Usable()
if self:GetUsableFunction() then if self:GetUsableFunction() then
return self:GetUsableFunction()(self) return self:GetUsableFunction()(self)
@ -177,6 +202,7 @@ end
-- Set a script to check if the Item is Usable -- Set a script to check if the Item is Usable
---@param func fun(self:Item):boolean ---@param func fun(self:Item):boolean
---@return Item
function Item:UsableIf(func) function Item:UsableIf(func)
self.UsableIfFunc = func self.UsableIfFunc = func
return self return self
@ -184,6 +210,7 @@ end
-- Set a script to run before the Item has been Use -- Set a script to run before the Item has been Use
---@param func fun(self:Item) ---@param func fun(self:Item)
---@return Item
function Item:PreUse(func) function Item:PreUse(func)
self.PreUseFunc = func self.PreUseFunc = func
return self return self
@ -191,17 +218,23 @@ end
-- Set a script to run after the Item has been Use -- Set a script to run after the Item has been Use
---@param func fun(self:Item) ---@param func fun(self:Item)
---@return Item
function Item:OnUse(func) function Item:OnUse(func)
self.OnUseFunc = func self.OnUseFunc = func
return self return self
end end
-- Get was looking -- Get was looking
---@return boolean
function Item:GetWasLooking() function Item:GetWasLooking()
return self.wasLooking return self.wasLooking
end end
-- Click the Item -- Click the Item
---@param x number
---@param y number
---@param z number
---@return boolean
function Item:Click(x, y, z) function Item:Click(x, y, z)
if type(x) == 'table' then if type(x) == 'table' then
x, y, z = x.x, x.y, x.z x, y, z = x.x, x.y, x.z
@ -218,6 +251,8 @@ function Item:Click(x, y, z)
end end
-- Check if the Item is Usable and Use it -- Check if the Item is Usable and Use it
---@param unit Unit
---@return boolean
function Item:Call(unit) function Item:Call(unit)
if self:Usable() then if self:Usable() then
self:Use(unit) self:Use(unit)
@ -227,6 +262,8 @@ function Item:Call(unit)
end end
-- Check if the Item is in range of the unit -- Check if the Item is in range of the unit
---@param unit Unit
---@return boolean
function Item:IsInRange(unit) function Item:IsInRange(unit)
local name, rank, icon, UseTime, Itemmin, Itemmax, ItemID = GetItemInfo(self:GetID()) local name, rank, icon, UseTime, Itemmin, Itemmax, ItemID = GetItemInfo(self:GetID())
@ -263,11 +300,13 @@ function Item:IsInRange(unit)
end end
-- Get the last use time -- Get the last use time
---@return number
function Item:GetLastUseTime() function Item:GetLastUseTime()
return Bastion.SpellBook:GetSpell(self:GetID()):GetLastCastTime() return Bastion.SpellBook:GetSpell(self:GetID()):GetLastCastTime()
end end
-- Get time since last use -- Get time since last use
---@return number
function Item:GetTimeSinceLastUse() function Item:GetTimeSinceLastUse()
if not self:GetLastUseTime() then if not self:GetLastUseTime() then
return math.huge return math.huge
@ -276,11 +315,13 @@ function Item:GetTimeSinceLastUse()
end end
-- Get the Items charges -- Get the Items charges
---@return number
function Item:GetCharges() function Item:GetCharges()
return GetItemCharges(self:GetID()) return GetItemCharges(self:GetID())
end end
-- Get the Items charges remaining -- Get the Items charges remaining
---@return number
function Item:GetChargesRemaining() function Item:GetChargesRemaining()
local charges, maxCharges, start, duration = GetItemCharges(self:GetID()) local charges, maxCharges, start, duration = GetItemCharges(self:GetID())
return charges return charges
@ -289,6 +330,7 @@ end
-- Create a condition for the Item -- Create a condition for the Item
---@param name string ---@param name string
---@param func fun(self:Item) ---@param func fun(self:Item)
---@return Item
function Item:Condition(name, func) function Item:Condition(name, func)
self.conditions[name] = { self.conditions[name] = {
func = func func = func
@ -297,6 +339,8 @@ function Item:Condition(name, func)
end end
-- Get a condition for the Item -- Get a condition for the Item
---@param name string
---@return function | nil
function Item:GetCondition(name) function Item:GetCondition(name)
local condition = self.conditions[name] local condition = self.conditions[name]
if condition then if condition then
@ -307,6 +351,8 @@ function Item:GetCondition(name)
end end
-- Evaluate a condition for the Item -- Evaluate a condition for the Item
---@param name string
---@return boolean
function Item:EvaluateCondition(name) function Item:EvaluateCondition(name)
local condition = self:GetCondition(name) local condition = self:GetCondition(name)
if condition then if condition then
@ -317,6 +363,8 @@ function Item:EvaluateCondition(name)
end end
-- Check if the Item has a condition -- Check if the Item has a condition
---@param name string
---@return boolean
function Item:HasCondition(name) function Item:HasCondition(name)
local condition = self:GetCondition(name) local condition = self:GetCondition(name)
if condition then if condition then
@ -327,17 +375,21 @@ function Item:HasCondition(name)
end end
-- Set the Items target -- Set the Items target
---@param unit Unit
---@return Item
function Item:SetTarget(unit) function Item:SetTarget(unit)
self.target = unit self.target = unit
return self return self
end end
-- Get the Items target -- Get the Items target
---@return Unit | nil
function Item:GetTarget() function Item:GetTarget()
return self.target return self.target
end end
-- IsMagicDispel -- IsMagicDispel
---@return boolean
function Item:IsMagicDispel() function Item:IsMagicDispel()
return ({ return ({
[88423] = true [88423] = true
@ -345,6 +397,7 @@ function Item:IsMagicDispel()
end end
-- IsCurseDispel -- IsCurseDispel
---@return boolean
function Item:IsCurseDispel() function Item:IsCurseDispel()
return ({ return ({
[88423] = true [88423] = true
@ -352,6 +405,7 @@ function Item:IsCurseDispel()
end end
-- IsPoisonDispel -- IsPoisonDispel
---@return boolean
function Item:IsPoisonDispel() function Item:IsPoisonDispel()
return ({ return ({
[88423] = true [88423] = true
@ -359,16 +413,21 @@ function Item:IsPoisonDispel()
end end
-- IsDiseaseDispel -- IsDiseaseDispel
---@return boolean
function Item:IsDiseaseDispel() function Item:IsDiseaseDispel()
return ({ return ({
})[self:GetID()] })[self:GetID()]
end end
---@param item Item
---@return boolean
function Item:IsItem(item) function Item:IsItem(item)
return self:GetID() == item:GetID() return self:GetID() == item:GetID()
end end
-- Get the Items spell
---@return Spell | nil
function Item:GetSpell() function Item:GetSpell()
if self.spellID then if self.spellID then
return Bastion.SpellBook:GetSpell(self.spellID) return Bastion.SpellBook:GetSpell(self.spellID)

@ -1,10 +1,12 @@
local Tinkr, Bastion = ... local Tinkr, Bastion = ...
-- Create a new ItemBook class -- Create a new ItemBook class
---@class ItemBook
local ItemBook = {} local ItemBook = {}
ItemBook.__index = ItemBook ItemBook.__index = ItemBook
-- Constructor -- Constructor
---@return ItemBook
function ItemBook:New() function ItemBook:New()
local self = setmetatable({}, ItemBook) local self = setmetatable({}, ItemBook)
self.items = {} self.items = {}
@ -12,6 +14,8 @@ function ItemBook:New()
end end
-- Get a spell from the ItemBook -- Get a spell from the ItemBook
---@param id number
---@return Item
function ItemBook:GetItem(id) function ItemBook:GetItem(id)
if self.items[id] == nil then if self.items[id] == nil then
self.items[id] = Bastion.Item:New(id) self.items[id] = Bastion.Item:New(id)

@ -22,32 +22,42 @@ local List = {
} }
List.__index = List List.__index = List
---@param from table | nil
---@return List
function List:New(from) function List:New(from)
local self = setmetatable({}, List) local self = setmetatable({}, List)
self._list = from or {} self._list = from or {}
return self return self
end end
---@param value any
---@return nil
function List:push(value) function List:push(value)
table.insert(self._list, value) table.insert(self._list, value)
end end
---@return any
function List:pop() function List:pop()
return table.remove(self._list) return table.remove(self._list)
end end
---@return any
function List:peek() function List:peek()
return self._list[#self._list] return self._list[#self._list]
end end
---@return number
function List:count() function List:count()
return #self._list return #self._list
end end
---@return nil
function List:clear() function List:clear()
self._list = {} self._list = {}
end end
---@param value any
---@return boolean
function List:contains(value) function List:contains(value)
for _, v in ipairs(self._list) do for _, v in ipairs(self._list) do
if v == value then if v == value then
@ -57,6 +67,8 @@ function List:contains(value)
return false return false
end end
---@param value any
---@return boolean
function List:remove(value) function List:remove(value)
for i, v in ipairs(self._list) do for i, v in ipairs(self._list) do
if v == value then if v == value then
@ -67,6 +79,8 @@ function List:remove(value)
return false return false
end end
---@param callback fun(value: any): boolean
---@return nil
function List:each(callback) function List:each(callback)
for _, v in ipairs(self._list) do for _, v in ipairs(self._list) do
if callback(v) then if callback(v) then
@ -75,6 +89,8 @@ function List:each(callback)
end end
end end
---@param callback fun(value: any): boolean
---@return boolean
function List:map(callback) function List:map(callback)
local newList = List.new() local newList = List.new()
for _, v in ipairs(self._list) do for _, v in ipairs(self._list) do
@ -83,6 +99,8 @@ function List:map(callback)
return newList return newList
end end
---@param callback fun(value: any): boolean
---@return boolean
function List:filter(callback) function List:filter(callback)
local newList = List.new() local newList = List.new()
for _, v in ipairs(self._list) do for _, v in ipairs(self._list) do
@ -93,6 +111,9 @@ function List:filter(callback)
return newList return newList
end end
---@param callback fun(value: any): boolean
---@param initialValue any
---@return boolean
function List:reduce(callback, initialValue) function List:reduce(callback, initialValue)
local result = initialValue local result = initialValue
for _, v in ipairs(self._list) do for _, v in ipairs(self._list) do
@ -101,6 +122,8 @@ function List:reduce(callback, initialValue)
return result return result
end end
---@param callback fun(value: any): boolean
---@return boolean | nil
function List:find(callback) function List:find(callback)
for _, v in ipairs(self._list) do for _, v in ipairs(self._list) do
if callback(v) then if callback(v) then
@ -110,6 +133,8 @@ function List:find(callback)
return nil return nil
end end
---@param callback fun(value: any): boolean
---@return number | nil
function List:findIndex(callback) function List:findIndex(callback)
for i, v in ipairs(self._list) do for i, v in ipairs(self._list) do
if callback(v) then if callback(v) then
@ -119,10 +144,13 @@ function List:findIndex(callback)
return nil return nil
end end
---@param callback fun(value: any): boolean
---@return nil
function List:sort(callback) function List:sort(callback)
table.sort(self._list, callback) table.sort(self._list, callback)
end end
---@return List
function List:reverse() function List:reverse()
local newList = List.new() local newList = List.new()
for i = #self._list, 1, -1 do for i = #self._list, 1, -1 do
@ -131,6 +159,7 @@ function List:reverse()
return newList return newList
end end
---@return List
function List:clone() function List:clone()
local newList = List.new() local newList = List.new()
for _, v in ipairs(self._list) do for _, v in ipairs(self._list) do
@ -139,6 +168,8 @@ function List:clone()
return newList return newList
end end
---@param list List
---@return List
function List:concat(list) function List:concat(list)
local newList = List.new() local newList = List.new()
for _, v in ipairs(self._list) do for _, v in ipairs(self._list) do
@ -150,6 +181,8 @@ function List:concat(list)
return newList return newList
end end
---@param separator string
---@return string
function List:join(separator) function List:join(separator)
local result = "" local result = ""
for i, v in ipairs(self._list) do for i, v in ipairs(self._list) do
@ -161,10 +194,12 @@ function List:join(separator)
return result return result
end end
---@return string
function List:toString() function List:toString()
return self:join(", ") return self:join(", ")
end end
---@return string
function List:__tostring() function List:__tostring()
return self:toString() return self:toString()
end end

@ -1,13 +1,18 @@
-- Create a module class for a bastion module -- Create a module class for a bastion module
---@class Module
local Module = {} local Module = {}
Module.__index = Module Module.__index = Module
-- __tostring -- __tostring
---@return string
function Module:__tostring() function Module:__tostring()
return "Bastion.__Module(" .. self.name .. ")" return "Bastion.__Module(" .. self.name .. ")"
end end
-- Constructor
---@param name string
---@return Module
function Module:New(name) function Module:New(name)
local module = {} local module = {}
setmetatable(module, Module) setmetatable(module, Module)
@ -20,16 +25,19 @@ function Module:New(name)
end end
-- Enable the module -- Enable the module
---@return nil
function Module:Enable() function Module:Enable()
self.enabled = true self.enabled = true
end end
-- Disable the module -- Disable the module
---@return nil
function Module:Disable() function Module:Disable()
self.enabled = false self.enabled = false
end end
-- Toggle the module -- Toggle the module
---@return nil
function Module:Toggle() function Module:Toggle()
if self.enabled then if self.enabled then
self:Disable() self:Disable()
@ -39,11 +47,15 @@ function Module:Toggle()
end end
-- Add a function to the sync list -- Add a function to the sync list
---@param func function
---@return nil
function Module:Sync(func) function Module:Sync(func)
table.insert(self.synced, func) table.insert(self.synced, func)
end end
-- Remove a function from the sync list -- Remove a function from the sync list
---@param func function
---@return nil
function Module:Unsync(func) function Module:Unsync(func)
for i = 1, #self.synced do for i = 1, #self.synced do
if self.synced[i] == func then if self.synced[i] == func then
@ -54,6 +66,7 @@ function Module:Unsync(func)
end end
-- Sync -- Sync
---@return nil
function Module:Tick() function Module:Tick()
if self.enabled then if self.enabled then
for i = 1, #self.synced do for i = 1, #self.synced do

@ -12,6 +12,7 @@ local MythicPlusUtils = {
MythicPlusUtils.__index = MythicPlusUtils MythicPlusUtils.__index = MythicPlusUtils
---@return MythicPlusUtils
function MythicPlusUtils:New() function MythicPlusUtils:New()
local self = setmetatable({}, MythicPlusUtils) local self = setmetatable({}, MythicPlusUtils)
@ -148,14 +149,19 @@ function MythicPlusUtils:New()
return self return self
end end
---@return nil
function MythicPlusUtils:ToggleDebuffLogging() function MythicPlusUtils:ToggleDebuffLogging()
self.debuffLogging = not self.debuffLogging self.debuffLogging = not self.debuffLogging
end end
---@return nil
function MythicPlusUtils:ToggleCastLogging() function MythicPlusUtils:ToggleCastLogging()
self.castLogging = not self.castLogging self.castLogging = not self.castLogging
end end
---@param unit Unit
---@param percent number
---@return boolean
function MythicPlusUtils:CastingCriticalKick(unit, percent) function MythicPlusUtils:CastingCriticalKick(unit, percent)
local castingSpell = unit:GetCastingOrChannelingSpell() local castingSpell = unit:GetCastingOrChannelingSpell()

@ -1,24 +1,26 @@
-- Create a NotificationsList class -- Create a NotificationsList class
---@class NotificationsList
local NotificationsList = { local NotificationsList = {
notifications = {} notifications = {}
} }
NotificationsList.__index = NotificationsList NotificationsList.__index = NotificationsList
-- Constructor -- Constructor
---@return NotificationsList
function NotificationsList:New() function NotificationsList:New()
local self = setmetatable({}, NotificationsList) local self = setmetatable({}, NotificationsList)
-- Create a frame for the notifications -- Create a frame for the notifications
self.frame = CreateFrame("Frame", "BastionNotificationsList", UIParent) self.frame = CreateFrame("Frame", "BastionNotificationsList", UIParent)
self.frame:SetSize(300, 100) self.frame:SetSize(600, 60)
self.frame:SetPoint("TOP", UIParent, "TOP", 0, -100) self.frame:SetPoint("TOP", UIParent, "TOP", 0, -100)
self.frame:SetFrameStrata("HIGH") self.frame:SetFrameStrata("HIGH")
-- Remove notifications after 5 seconds -- Remove notifications after 5 seconds
C_Timer.NewTicker(0.1, function() C_Timer.NewTicker(0.1, function()
for i, notification in ipairs(self.notifications) do for i, notification in ipairs(self.notifications) do
if GetTime() - notification.addedAt > 2 then if GetTime() - notification.addedAt > notification.duration then
notification:Remove() notification:Remove()
table.remove(self.notifications, i) table.remove(self.notifications, i)
end end
@ -29,18 +31,26 @@ function NotificationsList:New()
end end
-- Create a notification class for the notifications list (takes icon and text) -- Create a notification class for the notifications list (takes icon and text)
---@class Notification
local Notification = { local Notification = {
} }
Notification.__index = Notification Notification.__index = Notification
-- Constructor -- Constructor
function Notification:New(list, icon, text) ---@param list NotificationsList
---@param icon string
---@param text string
---@param duration number
---@return Notification
function Notification:New(list, icon, text, duration)
local self = setmetatable({}, Notification) local self = setmetatable({}, Notification)
if not duration then duration = 2 end
-- Create a frame for the notification -- Create a frame for the notification
self.frame = CreateFrame("Frame", nil, list.frame) self.frame = CreateFrame("Frame", nil, list.frame)
self.frame:SetSize(300, 100) self.frame:SetSize(5, 5)
self.frame:SetPoint("TOP", list.frame, "TOP", 0, 0) self.frame:SetPoint("CENTER", list.frame, "CENTER", 0, 0)
self.frame:SetFrameStrata("HIGH") self.frame:SetFrameStrata("HIGH")
-- Create a texture for the icon -- Create a texture for the icon
@ -50,18 +60,23 @@ function Notification:New(list, icon, text)
self.icon:SetTexture(icon) self.icon:SetTexture(icon)
-- Create a fontstring for the text -- Create a fontstring for the text
self.text = self.frame:CreateFontString(nil, "BACKGROUND", "GameFontNormal") self.text = self.frame:CreateFontString(nil, "BACKGROUND", "NumberFontNormal")
self.text:SetPoint("CENTER", self.frame, "CENTER", 10, 0) self.text:SetPoint("LEFT", self.frame, "LEFT", 32 + 16, 0)
self.text:SetText(text) self.text:SetText(text)
self.text:SetFont("Fonts\\FRIZQT__.TTF", 14) self.text:SetFont("Fonts\\OpenSans-Bold.ttf", 18)
-- set the frame size to the size of the text + icon
self.frame:SetSize(self.text:GetStringWidth() + 32 + 16, 32)
self.addedAt = GetTime() self.addedAt = GetTime()
self.duration = duration
self.list = list self.list = list
return self return self
end end
-- Remove notification -- Remove notification
---@return nil
function Notification:Remove() function Notification:Remove()
-- Fade out the notification frame and remove it after the fade -- Fade out the notification frame and remove it after the fade
UIFrameFadeOut(self.frame, 0.2, 1, 0) UIFrameFadeOut(self.frame, 0.2, 1, 0)
@ -75,9 +90,13 @@ function Notification:Remove()
end end
-- Add a notification to the list -- Add a notification to the list
function NotificationsList:AddNotification(icon, text) ---@param icon string
---@param text string
---@param duration number
---@return nil
function NotificationsList:AddNotification(icon, text, duration)
-- Create a new notification -- Create a new notification
local notification = Notification:New(self, icon, text) local notification = Notification:New(self, icon, text, duration)
-- Add the notification to the list -- Add the notification to the list
table.insert(self.notifications, notification) table.insert(self.notifications, notification)
@ -88,15 +107,18 @@ function NotificationsList:AddNotification(icon, text)
end end
-- Update the notifications -- Update the notifications
---@return nil
function NotificationsList:Update() function NotificationsList:Update()
-- Loop through the notifications -- Loop through the notifications
for i, notification in ipairs(self.notifications) do for i, notification in ipairs(self.notifications) do
-- Set the position of the notification -- Set the position of the notification
notification.frame:SetPoint("TOP", self.frame, "TOP", 0, -50 * (i - 1)) notification.frame:SetPoint("CENTER", self.frame, "CENTER", 0, -42 * (i - 1))
end end
end end
-- Remove a notification from the list -- Remove a notification from the list
---@param notification Notification
---@return nil
function NotificationsList:RemoveNotification(notification) function NotificationsList:RemoveNotification(notification)
-- Loop through the notifications -- Loop through the notifications
for i, v in ipairs(self.notifications) do for i, v in ipairs(self.notifications) do
@ -111,6 +133,7 @@ function NotificationsList:RemoveNotification(notification)
end end
-- Remove all notifications from the list -- Remove all notifications from the list
---@return nil
function NotificationsList:RemoveAllNotifications() function NotificationsList:RemoveAllNotifications()
-- Loop through the notifications -- Loop through the notifications
for i, v in ipairs(self.notifications) do for i, v in ipairs(self.notifications) do

@ -18,6 +18,9 @@ function ObjectManager:New()
end end
-- Register a custom list with a callback -- Register a custom list with a callback
---@param name string
---@param cb function
---@return List
function ObjectManager:RegisterList(name, cb) function ObjectManager:RegisterList(name, cb)
if self._lists[name] then if self._lists[name] then
return false return false
@ -32,6 +35,7 @@ function ObjectManager:RegisterList(name, cb)
end end
-- reset custom lists -- reset custom lists
---@return nil
function ObjectManager:ResetLists() function ObjectManager:ResetLists()
for _, list in pairs(self._lists) do for _, list in pairs(self._lists) do
list.list:clear() list.list:clear()
@ -39,6 +43,8 @@ function ObjectManager:ResetLists()
end end
-- Refresh custom lists -- Refresh custom lists
---@param object table
---@return nil
function ObjectManager:EnumLists(object) function ObjectManager:EnumLists(object)
for _, list in pairs(self._lists) do for _, list in pairs(self._lists) do
local r = list.cb(object) local r = list.cb(object)
@ -49,10 +55,14 @@ function ObjectManager:EnumLists(object)
end end
-- Get a list -- Get a list
---@param name string
---@return List
function ObjectManager:GetList(name) function ObjectManager:GetList(name)
return self._lists[name].list return self._lists[name].list
end end
-- Refresh all lists
---@return nil
function ObjectManager:Refresh() function ObjectManager:Refresh()
self.enemies:clear() self.enemies:clear()
self.friends:clear() self.friends:clear()
@ -61,6 +71,7 @@ function ObjectManager:Refresh()
self:ResetLists() self:ResetLists()
local objects = Objects() local objects = Objects()
local _, _, _, _, _, _, _, instanceID = GetInstanceInfo()
for _, object in pairs(objects) do for _, object in pairs(objects) do
self:EnumLists(object) self:EnumLists(object)
@ -74,7 +85,7 @@ function ObjectManager:Refresh()
if unit:GetID() == 120651 then if unit:GetID() == 120651 then
self.explosives:push(unit) self.explosives:push(unit)
elseif unit:IsPlayer() and unit:IsInParty() then elseif (unit:IsPlayer() and unit:IsInParty()) or (instanceID == 1148 and unit:IsInParty()) then
self.friends:push(unit) self.friends:push(unit)
elseif unit:IsEnemy() then elseif unit:IsEnemy() then
self.enemies:push(unit) self.enemies:push(unit)

@ -22,11 +22,15 @@ function Refreshable:__index(k)
end end
-- When the object is accessed return the value -- When the object is accessed return the value
---@return string
function Refreshable:__tostring() function Refreshable:__tostring()
return "Bastion.__Refreshable(" .. tostring(rawget(self, 'value')) .. ")" return "Bastion.__Refreshable(" .. tostring(rawget(self, 'value')) .. ")"
end end
-- Create -- Create
---@param value any
---@param cb function
---@return Refreshable
function Refreshable:New(value, cb) function Refreshable:New(value, cb)
local self = setmetatable({}, Refreshable) local self = setmetatable({}, Refreshable)
@ -40,6 +44,7 @@ function Refreshable:New(value, cb)
end end
-- Try to update the value -- Try to update the value
---@return nil
function Refreshable:TryUpdate() function Refreshable:TryUpdate()
if self.cache:IsCached("value") then if self.cache:IsCached("value") then
self.value = self.callback() self.value = self.callback()
@ -47,16 +52,21 @@ function Refreshable:TryUpdate()
end end
-- Update the value -- Update the value
---@return nil
function Refreshable:Update() function Refreshable:Update()
self.value = self.callback() self.value = self.callback()
end end
-- Set a new value -- Set a new value
---@param value any
---@return nil
function Refreshable:Set(value) function Refreshable:Set(value)
self.value = value self.value = value
end end
-- Set a new callback -- Set a new callback
---@param cb function
---@return nil
function Refreshable:SetCallback(cb) function Refreshable:SetCallback(cb)
self.callback = cb self.callback = cb
end end

@ -32,16 +32,21 @@ function Spell:__index(k)
end end
-- Equals -- Equals
---@param other Spell
---@return boolean
function Spell:__eq(other) function Spell:__eq(other)
return self:GetID() == other:GetID() return self:GetID() == other:GetID()
end end
-- tostring -- tostring
---@return string
function Spell:__tostring() function Spell:__tostring()
return "Bastion.__Spell(" .. self:GetID() .. ")" .. " - " .. self:GetName() return "Bastion.__Spell(" .. self:GetID() .. ")" .. " - " .. self:GetName()
end end
-- Constructor -- Constructor
---@param id number
---@return Spell
function Spell:New(id) function Spell:New(id)
local self = setmetatable({}, Spell) local self = setmetatable({}, Spell)
@ -51,59 +56,72 @@ function Spell:New(id)
end end
-- Get the spells id -- Get the spells id
---@return number
function Spell:GetID() function Spell:GetID()
return self.spellID return self.spellID
end end
-- Add post cast func -- Add post cast func
---@param func fun(self:Spell) ---@param func fun(self:Spell)
---@return Spell
function Spell:PostCast(func) function Spell:PostCast(func)
self.PostCastFunc = func self.PostCastFunc = func
return self return self
end end
-- Get the spells name -- Get the spells name
---@return string
function Spell:GetName() function Spell:GetName()
return GetSpellInfo(self:GetID()) return GetSpellInfo(self:GetID())
end end
-- Get the spells icon -- Get the spells icon
---@return number
function Spell:GetIcon() function Spell:GetIcon()
return select(3, GetSpellInfo(self:GetID())) return select(3, GetSpellInfo(self:GetID()))
end end
-- Get the spells cooldown -- Get the spells cooldown
---@return number
function Spell:GetCooldown() function Spell:GetCooldown()
return select(2, GetSpellCooldown(self:GetID())) return select(2, GetSpellCooldown(self:GetID()))
end end
-- Return the castable function -- Return the castable function
---@return fun(self:Spell):boolean
function Spell:GetCastableFunction() function Spell:GetCastableFunction()
return self.CastableIfFunc return self.CastableIfFunc
end end
-- Return the precast function -- Return the precast function
---@return fun(self:Spell)
function Spell:GetPreCastFunction() function Spell:GetPreCastFunction()
return self.PreCastFunc return self.PreCastFunc
end end
-- Get the on cast func -- Get the on cast func
---@return fun(self:Spell)
function Spell:GetOnCastFunction() function Spell:GetOnCastFunction()
return self.OnCastFunc return self.OnCastFunc
end end
-- Get the spells cooldown remaining -- Get the spells cooldown remaining
---@return number
function Spell:GetCooldownRemaining() function Spell:GetCooldownRemaining()
local start, duration = GetSpellCooldown(self:GetID()) local start, duration = GetSpellCooldown(self:GetID())
return start + duration - GetTime() return start + duration - GetTime()
end end
-- On cooldown -- On cooldown
---@return boolean
function Spell:OnCooldown() function Spell:OnCooldown()
return self:GetCooldownRemaining() > 0 return self:GetCooldownRemaining() > 0
end end
-- Cast the spell -- Cast the spell
---@param unit Unit
---@param condition string
---@return boolean
function Spell:Cast(unit, condition) function Spell:Cast(unit, condition)
if condition and not self:EvaluateCondition(condition) then if condition and not self:EvaluateCondition(condition) then
return false return false
@ -140,14 +158,18 @@ function Spell:Cast(unit, condition)
if self:GetOnCastFunction() then if self:GetOnCastFunction() then
self:GetOnCastFunction()(self) self:GetOnCastFunction()(self)
end end
return true
end end
-- Get post cast func -- Get post cast func
---@return fun(self:Spell)
function Spell:GetPostCastFunction() function Spell:GetPostCastFunction()
return self.PostCastFunc return self.PostCastFunc
end end
-- Check if the spell is known -- Check if the spell is known
---@return boolean
function Spell:IsKnown() function Spell:IsKnown()
local isKnown = IsSpellKnown(self:GetID()) local isKnown = IsSpellKnown(self:GetID())
local isPlayerSpell = IsPlayerSpell(self:GetID()) local isPlayerSpell = IsPlayerSpell(self:GetID())
@ -155,22 +177,26 @@ function Spell:IsKnown()
end end
-- Check if the spell is on cooldown -- Check if the spell is on cooldown
---@return boolean
function Spell:IsOnCooldown() function Spell:IsOnCooldown()
return select(2, GetSpellCooldown(self:GetID())) > 0 return select(2, GetSpellCooldown(self:GetID())) > 0
end end
-- Check if the spell is usable -- Check if the spell is usable
---@return boolean
function Spell:IsUsable() function Spell:IsUsable()
local usable, noMana = IsUsableSpell(self:GetID()) local usable, noMana = IsUsableSpell(self:GetID())
return usable or usableExcludes[self:GetID()] return usable or usableExcludes[self:GetID()]
end end
-- Check if the spell is castable -- Check if the spell is castable
---@return boolean
function Spell:IsKnownAndUsable() function Spell:IsKnownAndUsable()
return self:IsKnown() and not self:IsOnCooldown() and self:IsUsable() return self:IsKnown() and not self:IsOnCooldown() and self:IsUsable()
end end
-- Check if the spell is castable -- Check if the spell is castable
---@return boolean
function Spell:Castable() function Spell:Castable()
if self:GetCastableFunction() then if self:GetCastableFunction() then
return self:GetCastableFunction()(self) return self:GetCastableFunction()(self)
@ -181,6 +207,7 @@ end
-- Set a script to check if the spell is castable -- Set a script to check if the spell is castable
---@param func fun(spell:Spell):boolean ---@param func fun(spell:Spell):boolean
---@return Spell
function Spell:CastableIf(func) function Spell:CastableIf(func)
self.CastableIfFunc = func self.CastableIfFunc = func
return self return self
@ -188,6 +215,7 @@ end
-- Set a script to run before the spell has been cast -- Set a script to run before the spell has been cast
---@param func fun(spell:Spell) ---@param func fun(spell:Spell)
---@return Spell
function Spell:PreCast(func) function Spell:PreCast(func)
self.PreCastFunc = func self.PreCastFunc = func
return self return self
@ -195,17 +223,23 @@ end
-- Set a script to run after the spell has been cast -- Set a script to run after the spell has been cast
---@param func fun(spell:Spell) ---@param func fun(spell:Spell)
---@return Spell
function Spell:OnCast(func) function Spell:OnCast(func)
self.OnCastFunc = func self.OnCastFunc = func
return self return self
end end
-- Get was looking -- Get was looking
---@return boolean
function Spell:GetWasLooking() function Spell:GetWasLooking()
return self.wasLooking return self.wasLooking
end end
-- Click the spell -- Click the spell
---@param x number
---@param y number
---@param z number
---@return boolean
function Spell:Click(x, y, z) function Spell:Click(x, y, z)
if type(x) == 'table' then if type(x) == 'table' then
x, y, z = x.x, x.y, x.z x, y, z = x.x, x.y, x.z
@ -222,6 +256,8 @@ function Spell:Click(x, y, z)
end end
-- Check if the spell is castable and cast it -- Check if the spell is castable and cast it
---@param unit Unit
---@return boolean
function Spell:Call(unit) function Spell:Call(unit)
if self:Castable() then if self:Castable() then
self:Cast(unit) self:Cast(unit)
@ -230,11 +266,15 @@ function Spell:Call(unit)
return false return false
end end
-- Check if the spell is castable and cast it
---@return boolean
function Spell:HasRange() function Spell:HasRange()
return SpellHasRange(self:GetName()) return SpellHasRange(self:GetName())
end end
-- Check if the spell is in range of the unit -- Check if the spell is in range of the unit
---@param unit Unit
---@return boolean
function Spell:IsInRange(unit) function Spell:IsInRange(unit)
local hasRange = self:HasRange() local hasRange = self:HasRange()
local inRange = IsSpellInRange(self:GetName(), unit:GetOMToken()) local inRange = IsSpellInRange(self:GetName(), unit:GetOMToken())
@ -251,11 +291,13 @@ function Spell:IsInRange(unit)
end end
-- Get the last cast time -- Get the last cast time
---@return number
function Spell:GetLastCastTime() function Spell:GetLastCastTime()
return self.lastCastAt return self.lastCastAt
end end
-- Get time since last cast -- Get time since last cast
---@return number
function Spell:GetTimeSinceLastCast() function Spell:GetTimeSinceLastCast()
if not self:GetLastCastTime() then if not self:GetLastCastTime() then
return math.huge return math.huge
@ -264,10 +306,13 @@ function Spell:GetTimeSinceLastCast()
end end
-- Get the spells charges -- Get the spells charges
---@return number
function Spell:GetCharges() function Spell:GetCharges()
return GetSpellCharges(self:GetID()) return GetSpellCharges(self:GetID())
end end
-- Get the spells charges
---@return number
function Spell:GetChargesFractional() function Spell:GetChargesFractional()
local charges, maxCharges, start, duration = GetSpellCharges(self:GetID()) local charges, maxCharges, start, duration = GetSpellCharges(self:GetID())
@ -288,12 +333,16 @@ function Spell:GetChargesFractional()
end end
-- Get the spells charges remaining -- Get the spells charges remaining
---@return number
function Spell:GetChargesRemaining() function Spell:GetChargesRemaining()
local charges, maxCharges, start, duration = GetSpellCharges(self:GetID()) local charges, maxCharges, start, duration = GetSpellCharges(self:GetID())
return charges return charges
end end
-- Create a condition for the spell -- Create a condition for the spell
---@param name string
---@param func fun(self:Spell):boolean
---@return Spell
function Spell:Condition(name, func) function Spell:Condition(name, func)
self.conditions[name] = { self.conditions[name] = {
func = func func = func
@ -302,6 +351,8 @@ function Spell:Condition(name, func)
end end
-- Get a condition for the spell -- Get a condition for the spell
---@param name string
---@return function | nil
function Spell:GetCondition(name) function Spell:GetCondition(name)
local condition = self.conditions[name] local condition = self.conditions[name]
if condition then if condition then
@ -312,6 +363,8 @@ function Spell:GetCondition(name)
end end
-- Evaluate a condition for the spell -- Evaluate a condition for the spell
---@param name string
---@return boolean
function Spell:EvaluateCondition(name) function Spell:EvaluateCondition(name)
local condition = self:GetCondition(name) local condition = self:GetCondition(name)
if condition then if condition then
@ -322,6 +375,8 @@ function Spell:EvaluateCondition(name)
end end
-- Check if the spell has a condition -- Check if the spell has a condition
---@param name string
---@return boolean
function Spell:HasCondition(name) function Spell:HasCondition(name)
local condition = self:GetCondition(name) local condition = self:GetCondition(name)
if condition then if condition then
@ -332,17 +387,21 @@ function Spell:HasCondition(name)
end end
-- Set the spells target -- Set the spells target
---@param unit Unit
---@return Spell
function Spell:SetTarget(unit) function Spell:SetTarget(unit)
self.target = unit self.target = unit
return self return self
end end
-- Get the spells target -- Get the spells target
---@return Unit
function Spell:GetTarget() function Spell:GetTarget()
return self.target return self.target
end end
-- IsMagicDispel -- IsMagicDispel
---@return boolean
function Spell:IsMagicDispel() function Spell:IsMagicDispel()
return ({ return ({
[88423] = true [88423] = true
@ -350,6 +409,7 @@ function Spell:IsMagicDispel()
end end
-- IsCurseDispel -- IsCurseDispel
---@return boolean
function Spell:IsCurseDispel() function Spell:IsCurseDispel()
return ({ return ({
[88423] = true [88423] = true
@ -357,6 +417,7 @@ function Spell:IsCurseDispel()
end end
-- IsPoisonDispel -- IsPoisonDispel
---@return boolean
function Spell:IsPoisonDispel() function Spell:IsPoisonDispel()
return ({ return ({
[88423] = true [88423] = true
@ -364,12 +425,16 @@ function Spell:IsPoisonDispel()
end end
-- IsDiseaseDispel -- IsDiseaseDispel
---@return boolean
function Spell:IsDiseaseDispel() function Spell:IsDiseaseDispel()
return ({ return ({
})[self:GetID()] })[self:GetID()]
end end
-- IsSpell
---@param spell Spell
---@return boolean
function Spell:IsSpell(spell) function Spell:IsSpell(spell)
return self:GetID() == spell:GetID() return self:GetID() == spell:GetID()
end end

@ -1,10 +1,12 @@
local Tinkr, Bastion = ... local Tinkr, Bastion = ...
-- Create a new SpellBook class -- Create a new SpellBook class
---@class SpellBook
local SpellBook = {} local SpellBook = {}
SpellBook.__index = SpellBook SpellBook.__index = SpellBook
-- Constructor -- Constructor
---@return SpellBook
function SpellBook:New() function SpellBook:New()
local self = setmetatable({}, SpellBook) local self = setmetatable({}, SpellBook)
self.spells = {} self.spells = {}
@ -12,6 +14,7 @@ function SpellBook:New()
end end
-- Get a spell from the spellbook -- Get a spell from the spellbook
---@return Spell
function SpellBook:GetSpell(id) function SpellBook:GetSpell(id)
if self.spells[id] == nil then if self.spells[id] == nil then
self.spells[id] = Bastion.Spell:New(id) self.spells[id] = Bastion.Spell:New(id)
@ -20,6 +23,25 @@ function SpellBook:GetSpell(id)
return self.spells[id] return self.spells[id]
end end
---@param ... number[]
---@return Spell, ... Spell
function SpellBook:GetSpells(...)
local spells = {}
for _, id in ipairs({ ... }) do
table.insert(spells, self:GetSpell(id))
end
return unpack(spells)
end
---@param name string
---@return Spell
function SpellBook:GetSpellByName(name)
local _, rank, icon, castTime, minRange, maxRange, spellID, originalIcon = GetSpellInfo(name)
return self:GetSpell(spellID)
end
---@return Spell
function SpellBook:GetIfRegistered(id) function SpellBook:GetIfRegistered(id)
return self.spells[id] return self.spells[id]
end end

@ -1,6 +1,7 @@
local Tinkr, Bastion = ... local Tinkr, Bastion = ...
-- Create a new Timer class -- Create a new Timer class
---@class Timer
local Timer = { local Timer = {
startTime = nil, startTime = nil,
resetAfterCombat = false, resetAfterCombat = false,
@ -8,6 +9,8 @@ local Timer = {
Timer.__index = Timer Timer.__index = Timer
-- Constructor -- Constructor
---@param type string
---@return Timer
function Timer:New(type) function Timer:New(type)
local self = setmetatable({}, Timer) local self = setmetatable({}, Timer)
self.startTime = nil self.startTime = nil
@ -16,11 +19,13 @@ function Timer:New(type)
end end
-- Start the timer -- Start the timer
---@return nil
function Timer:Start() function Timer:Start()
self.startTime = GetTime() self.startTime = GetTime()
end end
-- Get the time since the timer was started -- Get the time since the timer was started
---@return number
function Timer:GetTime() function Timer:GetTime()
if not self:IsRunning() then if not self:IsRunning() then
return 0 return 0
@ -29,11 +34,13 @@ function Timer:GetTime()
end end
-- Check if the timer is running -- Check if the timer is running
---@return boolean
function Timer:IsRunning() function Timer:IsRunning()
return self.startTime ~= nil return self.startTime ~= nil
end end
-- Reset the timer -- Reset the timer
---@return nil
function Timer:Reset() function Timer:Reset()
self.startTime = nil self.startTime = nil
end end

@ -34,16 +34,26 @@ function Unit:__index(k)
end end
-- Equals -- Equals
---@param other Unit
---@return boolean
function Unit:__eq(other) function Unit:__eq(other)
return UnitIsUnit(self:GetOMToken(), other.unit) return UnitIsUnit(self:GetOMToken(), other.unit)
end end
-- tostring -- tostring
---ToString
---
---```lua
---print(Unit:New('player'))
---```
---@return string
function Unit:__tostring() function Unit:__tostring()
return "Bastion.__Unit(" .. tostring(self:GetOMToken()) .. ")" .. " - " .. (self:GetName() or '') return "Bastion.__Unit(" .. tostring(self:GetOMToken()) .. ")" .. " - " .. (self:GetName() or '')
end end
-- Constructor -- Constructor
---@param unit string
---@return Unit
function Unit:New(unit) function Unit:New(unit)
local self = setmetatable({}, Unit) local self = setmetatable({}, Unit)
self.unit = unit self.unit = unit
@ -54,85 +64,107 @@ function Unit:New(unit)
end end
-- Check if the unit is valid -- Check if the unit is valid
---@return boolean
function Unit:IsValid() function Unit:IsValid()
return self:GetOMToken() ~= nil and self:Exists() return self:GetOMToken() ~= nil and self:Exists()
end end
-- Check if the unit exists -- Check if the unit exists
---@return boolean
function Unit:Exists() function Unit:Exists()
return Object(self:GetOMToken()) return Object(self:GetOMToken())
end end
-- Get the units token -- Get the units token
---@return string
function Unit:Token() function Unit:Token()
return self:GetOMToken() return self:GetOMToken()
end end
-- Get the units name -- Get the units name
---@return string
function Unit:GetName() function Unit:GetName()
return UnitName(self:GetOMToken()) return UnitName(self:GetOMToken())
end end
-- Get the units GUID -- Get the units GUID
---@return string
function Unit:GetGUID() function Unit:GetGUID()
return ObjectGUID(self:GetOMToken()) return ObjectGUID(self:GetOMToken())
end end
-- Get the units health -- Get the units health
---@return number
function Unit:GetHealth() function Unit:GetHealth()
return UnitHealth(self:GetOMToken()) return UnitHealth(self:GetOMToken())
end end
-- Get the units max health -- Get the units max health
---@return number
function Unit:GetMaxHealth() function Unit:GetMaxHealth()
return UnitHealthMax(self:GetOMToken()) return UnitHealthMax(self:GetOMToken())
end end
-- Get the units health percentage -- Get the units health percentage
---@return number
function Unit:GetHP() function Unit:GetHP()
return self:GetHealth() / self:GetMaxHealth() * 100 return self:GetHealth() / self:GetMaxHealth() * 100
end end
-- Get the units health deficit
---@return number
function Unit:GetHealthPercent() function Unit:GetHealthPercent()
return self:GetHP() return self:GetHP()
end end
-- Get the units power type -- Get the units power type
---@return number
function Unit:GetPowerType() function Unit:GetPowerType()
return UnitPowerType(self:GetOMToken()) return UnitPowerType(self:GetOMToken())
end end
-- Get the units power -- Get the units power
---@param powerType number | nil
---@return number
function Unit:GetPower(powerType) function Unit:GetPower(powerType)
local powerType = powerType or self:GetPowerType() local powerType = powerType or self:GetPowerType()
return UnitPower(self:GetOMToken(), powerType) return UnitPower(self:GetOMToken(), powerType)
end end
-- Get the units max power -- Get the units max power
---@param powerType number | nil
---@return number
function Unit:GetMaxPower(powerType) function Unit:GetMaxPower(powerType)
local powerType = powerType or self:GetPowerType() local powerType = powerType or self:GetPowerType()
return UnitPowerMax(self:GetOMToken(), powerType) return UnitPowerMax(self:GetOMToken(), powerType)
end end
-- Get the units power percentage -- Get the units power percentage
---@param powerType number | nil
---@return number
function Unit:GetPP(powerType) function Unit:GetPP(powerType)
local powerType = powerType or self:GetPowerType() local powerType = powerType or self:GetPowerType()
return self:GetPower(powerType) / self:GetMaxPower(powerType) * 100 return self:GetPower(powerType) / self:GetMaxPower(powerType) * 100
end end
-- Get the units power deficit -- Get the units power deficit
---@param powerType number | nil
---@return number
function Unit:GetPowerDeficit(powerType) function Unit:GetPowerDeficit(powerType)
local powerType = powerType or self:GetPowerType() local powerType = powerType or self:GetPowerType()
return self:GetMaxPower(powerType) - self:GetPower(powerType) return self:GetMaxPower(powerType) - self:GetPower(powerType)
end end
-- Get the units position -- Get the units position
---@return Vector3
function Unit:GetPosition() function Unit:GetPosition()
local x, y, z = ObjectPosition(self:GetOMToken()) local x, y, z = ObjectPosition(self:GetOMToken())
return Bastion.Vector3:New(x, y, z) return Bastion.Vector3:New(x, y, z)
end end
-- Get the units distance from another unit -- Get the units distance from another unit
---@param unit Unit
---@return number
function Unit:GetDistance(unit) function Unit:GetDistance(unit)
local pself = self:GetPosition() local pself = self:GetPosition()
local punit = unit:GetPosition() local punit = unit:GetPosition()
@ -141,36 +173,43 @@ function Unit:GetDistance(unit)
end end
-- Is the unit dead -- Is the unit dead
---@return boolean
function Unit:IsDead() function Unit:IsDead()
return UnitIsDeadOrGhost(self:GetOMToken()) return UnitIsDeadOrGhost(self:GetOMToken())
end end
-- Is the unit alive -- Is the unit alive
---@return boolean
function Unit:IsAlive() function Unit:IsAlive()
return not UnitIsDeadOrGhost(self:GetOMToken()) return not UnitIsDeadOrGhost(self:GetOMToken())
end end
-- Is the unit a pet -- Is the unit a pet
---@return boolean
function Unit:IsPet() function Unit:IsPet()
return UnitIsUnit(self:GetOMToken(), "pet") return UnitIsUnit(self:GetOMToken(), "pet")
end end
-- Is the unit a friendly unit -- Is the unit a friendly unit
---@return boolean
function Unit:IsFriendly() function Unit:IsFriendly()
return UnitIsFriend("player", self:GetOMToken()) return UnitIsFriend("player", self:GetOMToken())
end end
-- IsEnemy -- IsEnemy
---@return boolean
function Unit:IsEnemy() function Unit:IsEnemy()
return UnitCanAttack("player", self:GetOMToken()) return UnitCanAttack("player", self:GetOMToken())
end end
-- Is the unit a hostile unit -- Is the unit a hostile unit
---@return boolean
function Unit:IsHostile() function Unit:IsHostile()
return UnitCanAttack(self:GetOMToken(), 'player') return UnitCanAttack(self:GetOMToken(), 'player')
end end
-- Is the unit a boss -- Is the unit a boss
---@return boolean
function Unit:IsBoss() function Unit:IsBoss()
if UnitClassification(self:GetOMToken()) == "worldboss" then if UnitClassification(self:GetOMToken()) == "worldboss" then
return true return true
@ -187,6 +226,7 @@ function Unit:IsBoss()
return false return false
end end
---@return string
function Unit:GetOMToken() function Unit:GetOMToken()
if not self.unit then if not self.unit then
return "none" return "none"
@ -195,51 +235,61 @@ function Unit:GetOMToken()
end end
-- Is the unit a target -- Is the unit a target
---@return boolean
function Unit:IsTarget() function Unit:IsTarget()
return UnitIsUnit(self:GetOMToken(), "target") return UnitIsUnit(self:GetOMToken(), "target")
end end
-- Is the unit a focus -- Is the unit a focus
---@return boolean
function Unit:IsFocus() function Unit:IsFocus()
return UnitIsUnit(self:GetOMToken(), "focus") return UnitIsUnit(self:GetOMToken(), "focus")
end end
-- Is the unit a mouseover -- Is the unit a mouseover
---@return boolean
function Unit:IsMouseover() function Unit:IsMouseover()
return UnitIsUnit(self:GetOMToken(), "mouseover") return UnitIsUnit(self:GetOMToken(), "mouseover")
end end
-- Is the unit a tank -- Is the unit a tank
---@return boolean
function Unit:IsTank() function Unit:IsTank()
return UnitGroupRolesAssigned(self:GetOMToken()) == "TANK" return UnitGroupRolesAssigned(self:GetOMToken()) == "TANK"
end end
-- Is the unit a healer -- Is the unit a healer
---@return boolean
function Unit:IsHealer() function Unit:IsHealer()
return UnitGroupRolesAssigned(self:GetOMToken()) == "HEALER" return UnitGroupRolesAssigned(self:GetOMToken()) == "HEALER"
end end
-- Is the unit a damage dealer -- Is the unit a damage dealer
---@return boolean
function Unit:IsDamage() function Unit:IsDamage()
return UnitGroupRolesAssigned(self:GetOMToken()) == "DAMAGER" return UnitGroupRolesAssigned(self:GetOMToken()) == "DAMAGER"
end end
-- Is the unit a player -- Is the unit a player
---@return boolean
function Unit:IsPlayer() function Unit:IsPlayer()
return UnitIsPlayer(self:GetOMToken()) return UnitIsPlayer(self:GetOMToken())
end end
-- Is the unit a player controlled unit -- Is the unit a player controlled unit
---@return boolean
function Unit:IsPCU() function Unit:IsPCU()
return UnitPlayerControlled(self:GetOMToken()) return UnitPlayerControlled(self:GetOMToken())
end end
-- Get if the unit is affecting combat -- Get if the unit is affecting combat
---@return boolean
function Unit:IsAffectingCombat() function Unit:IsAffectingCombat()
return UnitAffectingCombat(self:GetOMToken()) return UnitAffectingCombat(self:GetOMToken())
end end
-- Get the units class id -- Get the units class id
---@return Class
function Unit:GetClass() function Unit:GetClass()
local locale, class, classID = UnitClass(self:GetOMToken()) local locale, class, classID = UnitClass(self:GetOMToken())
return Bastion.Class:New(locale, class, classID) return Bastion.Class:New(locale, class, classID)
@ -252,6 +302,7 @@ function Unit:GetAuras()
end end
-- Get the raw unit -- Get the raw unit
---@return string
function Unit:GetRawUnit() function Unit:GetRawUnit()
return self:GetOMToken() return self:GetOMToken()
end end
@ -266,6 +317,8 @@ local isClassicWow = select(4, GetBuildInfo()) < 40000
local losFlag = bit.bor(0x1, 0x10, 0x100000) local losFlag = bit.bor(0x1, 0x10, 0x100000)
-- Check if the unit can see another unit -- Check if the unit can see another unit
---@param unit Unit
---@return boolean
function Unit:CanSee(unit) function Unit:CanSee(unit)
-- mechagon smoke cloud -- mechagon smoke cloud
-- local mechagonID = 2097 -- local mechagonID = 2097
@ -311,11 +364,13 @@ function Unit:CanSee(unit)
end end
-- Check if the unit is casting a spell -- Check if the unit is casting a spell
---@return boolean
function Unit:IsCasting() function Unit:IsCasting()
return UnitCastingInfo(self:GetOMToken()) ~= nil return UnitCastingInfo(self:GetOMToken()) ~= nil
end end
-- Get Casting or channeling spell -- Get Casting or channeling spell
---@return Spell | nil
function Unit:GetCastingOrChannelingSpell() function Unit:GetCastingOrChannelingSpell()
local name, text, texture, startTimeMS, endTimeMS, isTradeSkill, castID, notInterruptible, spellId = UnitCastingInfo(self local name, text, texture, startTimeMS, endTimeMS, isTradeSkill, castID, notInterruptible, spellId = UnitCastingInfo(self
.unit) .unit)
@ -333,20 +388,25 @@ function Unit:GetCastingOrChannelingSpell()
end end
-- Check if the unit is channeling a spell -- Check if the unit is channeling a spell
---@return boolean
function Unit:IsChanneling() function Unit:IsChanneling()
return UnitChannelInfo(self:GetOMToken()) ~= nil return UnitChannelInfo(self:GetOMToken()) ~= nil
end end
-- Check if the unit is casting or channeling a spell -- Check if the unit is casting or channeling a spell
---@return boolean
function Unit:IsCastingOrChanneling() function Unit:IsCastingOrChanneling()
return self:IsCasting() or self:IsChanneling() return self:IsCasting() or self:IsChanneling()
end end
-- Check if the unit can attack the target -- Check if the unit can attack the target
---@param unit Unit
---@return boolean
function Unit:CanAttack(unit) function Unit:CanAttack(unit)
return UnitCanAttack(self:GetOMToken(), unit:GetOMToken()) return UnitCanAttack(self:GetOMToken(), unit:GetOMToken())
end end
---@return number
function Unit:GetChannelOrCastPercentComplete() function Unit:GetChannelOrCastPercentComplete()
local name, text, texture, startTimeMS, endTimeMS, isTradeSkill, castID, notInterruptible, spellId = UnitCastingInfo(self local name, text, texture, startTimeMS, endTimeMS, isTradeSkill, castID, notInterruptible, spellId = UnitCastingInfo(self
.unit) .unit)
@ -366,6 +426,8 @@ function Unit:GetChannelOrCastPercentComplete()
return 0 return 0
end end
-- Check if unit is interruptible
---@return boolean
function Unit:IsInterruptible() function Unit:IsInterruptible()
local name, text, texture, startTimeMS, endTimeMS, isTradeSkill, castID, notInterruptible, spellId = UnitCastingInfo(self local name, text, texture, startTimeMS, endTimeMS, isTradeSkill, castID, notInterruptible, spellId = UnitCastingInfo(self
.unit) .unit)
@ -383,6 +445,8 @@ function Unit:IsInterruptible()
end end
-- Check if unit is interruptible -- Check if unit is interruptible
---@param percent number
---@return boolean
function Unit:IsInterruptibleAt(percent) function Unit:IsInterruptibleAt(percent)
if not self:IsInterruptible() then if not self:IsInterruptible() then
return false return false
@ -399,6 +463,8 @@ function Unit:IsInterruptibleAt(percent)
end end
-- Get the number of enemies in a given range of the unit and cache the result for .5 seconds -- Get the number of enemies in a given range of the unit and cache the result for .5 seconds
---@param range number
---@return number
function Unit:GetEnemies(range) function Unit:GetEnemies(range)
local enemies = self.cache:Get("enemies_" .. range) local enemies = self.cache:Get("enemies_" .. range)
if enemies then if enemies then
@ -419,6 +485,7 @@ function Unit:GetEnemies(range)
end end
-- Get the number of melee attackers -- Get the number of melee attackers
---@return number
function Unit:GetMeleeAttackers() function Unit:GetMeleeAttackers()
local enemies = self.cache:Get("melee_attackers") local enemies = self.cache:Get("melee_attackers")
if enemies then if enemies then
@ -438,6 +505,9 @@ function Unit:GetMeleeAttackers()
return count return count
end end
---@param distance number
---@param percent number
---@return number
function Unit:GetPartyHPAround(distance, percent) function Unit:GetPartyHPAround(distance, percent)
local count = 0 local count = 0
@ -452,33 +522,57 @@ function Unit:GetPartyHPAround(distance, percent)
end end
-- Is moving -- Is moving
---@return boolean
function Unit:IsMoving() function Unit:IsMoving()
return GetUnitSpeed(self:GetOMToken()) > 0 return GetUnitSpeed(self:GetOMToken()) > 0
end end
-- Is moving at all
---@return boolean
function Unit:IsMovingAtAll() function Unit:IsMovingAtAll()
return ObjectMovementFlag(self:GetOMToken()) ~= 0 return ObjectMovementFlag(self:GetOMToken()) ~= 0
end end
function Unit:GetComboPoints() ---@param unit Unit | nil
---@return number
function Unit:GetComboPoints(unit)
if Tinkr.classic then
if not unit then
return 0
end
return GetComboPoints(self:GetOMToken(), unit:GetOMToken())
end
return UnitPower(self:GetOMToken(), 4) return UnitPower(self:GetOMToken(), 4)
end end
---@return number
function Unit:GetComboPointsMax() function Unit:GetComboPointsMax()
if Tinkr.classic then
return 5
end
return UnitPowerMax(self:GetOMToken(), 4) return UnitPowerMax(self:GetOMToken(), 4)
end end
-- Get combopoints deficit -- Get combopoints deficit
function Unit:GetComboPointsDeficit() ---@param unit Unit | nil
---@return number
function Unit:GetComboPointsDeficit(unit)
if Tinkr.classic then
return self:GetComboPointsMax() - self:GetComboPoints(unit)
end
return self:GetComboPointsMax() - self:GetComboPoints() return self:GetComboPointsMax() - self:GetComboPoints()
end end
-- IsUnit -- IsUnit
---@param unit Unit
---@return boolean
function Unit:IsUnit(unit) function Unit:IsUnit(unit)
return UnitIsUnit(self:GetOMToken(), unit and unit:GetOMToken() or 'none') return UnitIsUnit(self:GetOMToken(), unit and unit:GetOMToken() or 'none')
end end
-- IsTanking -- IsTanking
---@param unit Unit
---@return boolean
function Unit:IsTanking(unit) function Unit:IsTanking(unit)
local isTanking, status, threatpct, rawthreatpct, threatvalue = UnitDetailedThreatSituation(self:GetOMToken(), local isTanking, status, threatpct, rawthreatpct, threatvalue = UnitDetailedThreatSituation(self:GetOMToken(),
unit:GetOMToken()) unit:GetOMToken())
@ -486,6 +580,8 @@ function Unit:IsTanking(unit)
end end
-- IsFacing -- IsFacing
---@param unit Unit
---@return boolean
function Unit:IsFacing(unit) function Unit:IsFacing(unit)
local rot = ObjectRotation(self:GetOMToken()) local rot = ObjectRotation(self:GetOMToken())
local x, y, z = ObjectPosition(self:GetOMToken()) local x, y, z = ObjectPosition(self:GetOMToken())
@ -506,6 +602,8 @@ function Unit:IsFacing(unit)
end end
-- IsBehind -- IsBehind
---@param unit Unit
---@return boolean
function Unit:IsBehind(unit) function Unit:IsBehind(unit)
local rot = ObjectRotation(unit:GetOMToken()) local rot = ObjectRotation(unit:GetOMToken())
local x, y, z = ObjectPosition(unit:GetOMToken()) local x, y, z = ObjectPosition(unit:GetOMToken())
@ -525,6 +623,7 @@ function Unit:IsBehind(unit)
return math.abs(angle) > 90 return math.abs(angle) > 90
end end
---@return number
function Unit:GetMeleeBoost() function Unit:GetMeleeBoost()
if IsPlayerSpell(196924) then if IsPlayerSpell(196924) then
return 3 return 3
@ -540,6 +639,8 @@ end
-- return ((myPos.x - targetPos.x) * (myPos.x - targetPos.x)) + ((myPos.y - targetPos.y) * (myPos.y - targetPos.y)) + ((myPos.z - targetPos.z) * (myPos.z - targetPos.z)) <= (float)(fMaxDist * fMaxDist); -- return ((myPos.x - targetPos.x) * (myPos.x - targetPos.x)) + ((myPos.y - targetPos.y) * (myPos.y - targetPos.y)) + ((myPos.z - targetPos.z) * (myPos.z - targetPos.z)) <= (float)(fMaxDist * fMaxDist);
-- InMelee -- InMelee
---@param unit Unit
---@return boolean
function Unit:InMelee(unit) function Unit:InMelee(unit)
local x, y, z = ObjectPosition(self:GetOMToken()) local x, y, z = ObjectPosition(self:GetOMToken())
local x2, y2, z2 = ObjectPosition(unit:GetOMToken()) local x2, y2, z2 = ObjectPosition(unit:GetOMToken())
@ -556,16 +657,21 @@ function Unit:InMelee(unit)
end end
-- Get object id -- Get object id
---@return number
function Unit:GetID() function Unit:GetID()
return ObjectID(self:GetOMToken()) return ObjectID(self:GetOMToken())
end end
-- In party -- In party
---@return boolean
function Unit:IsInParty() function Unit:IsInParty()
return UnitInParty(self:GetOMToken()) return UnitInParty(self:GetOMToken())
end end
-- Linear regression between time and percent to something -- Linear regression between time and percent to something
---@param time table
---@param percent table
---@return number, number
function Unit:LinearRegression(time, percent) function Unit:LinearRegression(time, percent)
local x = time local x = time
local y = percent local y = percent
@ -592,6 +698,8 @@ function Unit:LinearRegression(time, percent)
end end
-- Use linear regression to get the health percent at a given time in the future -- Use linear regression to get the health percent at a given time in the future
---@param time number
---@return number
function Unit:PredictHealth(time) function Unit:PredictHealth(time)
local x = {} local x = {}
local y = {} local y = {}
@ -613,6 +721,8 @@ function Unit:PredictHealth(time)
end end
-- Use linear regression to guess the time until a given health percent -- Use linear regression to guess the time until a given health percent
---@param percent number
---@return number
function Unit:PredictTime(percent) function Unit:PredictTime(percent)
local x = {} local x = {}
local y = {} local y = {}
@ -634,6 +744,7 @@ function Unit:PredictTime(percent)
end end
-- Time until death -- Time until death
---@return number
function Unit:TimeToDie() function Unit:TimeToDie()
if self:IsDead() then if self:IsDead() then
self.regression_history = {} self.regression_history = {}
@ -650,16 +761,21 @@ function Unit:TimeToDie()
end end
-- Set combat time if affecting combat and return the difference between now and the last time -- Set combat time if affecting combat and return the difference between now and the last time
---@return number
function Unit:GetCombatTime() function Unit:GetCombatTime()
return GetTime() - self.last_combat_time return GetTime() - self.last_combat_time
end end
-- Set last combat time
---@param time number
---@return nil
function Unit:SetLastCombatTime(time) function Unit:SetLastCombatTime(time)
self.last_combat_time = time self.last_combat_time = time
end end
-- Get combat odds (if the last combat time is less than 1 minute ago return 1 / time, else return 0) -- Get combat odds (if the last combat time is less than 1 minute ago return 1 / time, else return 0)
-- the closer to 0 the more likely the unit is to be in combat (0 = 100%) 60 = 0% -- the closer to 0 the more likely the unit is to be in combat (0 = 100%) 60 = 0%
---@return number
function Unit:InCombatOdds() function Unit:InCombatOdds()
local time = self:GetCombatTime() local time = self:GetCombatTime()
local percent = 1 - (time / 60) local percent = 1 - (time / 60)
@ -668,6 +784,7 @@ function Unit:InCombatOdds()
end end
-- Get units gcd time -- Get units gcd time
---@return number
function Unit:GetGCD() function Unit:GetGCD()
local start, duration = GetSpellCooldown(61304) local start, duration = GetSpellCooldown(61304)
if start == 0 then if start == 0 then
@ -686,6 +803,7 @@ The GCD won't drop below 1 second
More than 50% Haste will drop a spell below 1 second More than 50% Haste will drop a spell below 1 second
]] ]]
---@return number
function Unit:GetMaxGCD() function Unit:GetMaxGCD()
local haste = UnitSpellHaste(self:GetOMToken()) local haste = UnitSpellHaste(self:GetOMToken())
if haste > 50 then if haste > 50 then
@ -696,6 +814,7 @@ function Unit:GetMaxGCD()
end end
-- IsStealthed -- IsStealthed
---@return boolean
function Unit:IsStealthed() function Unit:IsStealthed()
local Stealth = Bastion.SpellBook:GetSpell(1784) local Stealth = Bastion.SpellBook:GetSpell(1784)
local Vanish = Bastion.SpellBook:GetSpell(1856) local Vanish = Bastion.SpellBook:GetSpell(1856)
@ -709,6 +828,7 @@ function Unit:IsStealthed()
end end
-- Get unit swing timers -- Get unit swing timers
---@return number, number
function Unit:GetSwingTimers() function Unit:GetSwingTimers()
local main_speed, off_speed = UnitAttackSpeed(self:GetOMToken()) local main_speed, off_speed = UnitAttackSpeed(self:GetOMToken())
local main_speed = main_speed or 2 local main_speed = main_speed or 2
@ -728,6 +848,7 @@ function Unit:GetSwingTimers()
return main_speed_remains, off_speed_remains return main_speed_remains, off_speed_remains
end end
---@return nil
function Unit:WatchForSwings() function Unit:WatchForSwings()
Bastion.EventManager:RegisterWoWEvent("COMBAT_LOG_EVENT_UNFILTERED", function() Bastion.EventManager:RegisterWoWEvent("COMBAT_LOG_EVENT_UNFILTERED", function()
local _, subtype, _, sourceGUID, sourceName, _, _, destGUID, destName, destFlags, _, spellID, spellName, _, amount, interrupt, a, b, c, d, offhand, multistrike = CombatLogGetCurrentEventInfo() local _, subtype, _, sourceGUID, sourceName, _, _, destGUID, destName, destFlags, _, spellID, spellName, _, amount, interrupt, a, b, c, d, offhand, multistrike = CombatLogGetCurrentEventInfo()
@ -759,114 +880,34 @@ function Unit:WatchForSwings()
end) end)
end end
-- GetTimeToShurikenTornado -- ismounted
--[[ ---@return boolean
spec:RegisterStateTable( "time_to_sht", setmetatable( {}, { function Unit:IsMounted()
__index = function( t, k ) return UnitIsMounted(self.unit)
local n = tonumber( k ) end
n = n - ( n % 1 )
if not n or n > 5 then return 3600 end
if n <= swings_since_sht then return 0 end
local mh_speed = swings.mainhand_speed
local mh_next = ( swings.mainhand > now - 3 ) and ( swings.mainhand + mh_speed ) or now + ( mh_speed * 0.5 )
local oh_speed = swings.offhand_speed
local oh_next = ( swings.offhand > now - 3 ) and ( swings.offhand + oh_speed ) or now
table.wipe( sht )
if mh_speed and mh_speed > 0 then
for i = 1, 4 do
insert( sht, mh_next + ( i * mh_speed ) )
end
end
if oh_speed and oh_speed > 0 then
for i = 1, 4 do
insert( sht, oh_next + ( i * oh_speed ) )
end
end
local i = 1
while( sht[i] ) do
if sht[i] < last_shadow_techniques + 3 then
table.remove( sht, i )
else
i = i + 1
end
end
if #sht > 0 and n - swings_since_sht < #sht then
table.sort( sht )
return max( 0, sht[ n - swings_since_sht ] - query_time )
else
return 3600
end
end
} ) )
]]
function Unit:GetTimeToShurikenTornado(n)
local now = GetTime()
local sht = {}
local swings = self:GetSwingTimers()
if not self.swings_since_sht then
self.swings_since_sht = 0
end
if not self.last_shadow_techniques then
self.last_shadow_techniques = 0
end
if n <= self.swings_since_sht then
return 0
end
local mh_speed = swings[1]
local mh_next = (self.last_mh > now - 3) and (self.last_mh + mh_speed) or now + (mh_speed * 0.5)
local oh_speed = swings[2]
local oh_next = (self.last_oh > now - 3) and (self.last_oh + oh_speed) or now
table.wipe(sht)
if mh_speed and mh_speed > 0 then
for i = 1, 4 do
table.insert(sht, mh_next + (i * mh_speed))
end
end
if oh_speed and oh_speed > 0 then
for i = 1, 4 do
table.insert(sht, oh_next + (i * oh_speed))
end
end
local i = 1 -- isindoors
---@return boolean
function Unit:IsOutdoors()
return ObjectIsOutdoors(self.unit)
end
while (sht[i]) do -- IsIndoors
if sht[i] < self.last_shadow_techniques + 3 then ---@return boolean
table.remove(sht, i) function Unit:IsIndoors()
else return not ObjectIsOutdoors(self.unit)
i = i + 1 end
end
end
if #sht > 0 and n - self.swings_since_sht < #sht then -- IsSubmerged
table.sort(sht) ---@return boolean
return math.max(0, sht[n - self.swings_since_sht] - now) function Unit:IsSubmerged()
else return ObjectIsSubmerged(self.unit)
return 3600
end
end end
-- Is the unit indoors -- IsDry
function Unit:IsIndoors() ---@return boolean
return IsIndoors() function Unit:IsDry()
return not ObjectIsSubmerged(self.unit)
end end
return Unit return Unit

@ -99,6 +99,7 @@ function UnitManager:__index(k)
end end
-- Constructor -- Constructor
---@return UnitManager
function UnitManager:New() function UnitManager:New()
local self = setmetatable({}, UnitManager) local self = setmetatable({}, UnitManager)
self.units = {} self.units = {}
@ -112,6 +113,7 @@ function UnitManager:Validate(token)
end end
-- Get or create a unit -- Get or create a unit
---@param token string
---@return Unit ---@return Unit
function UnitManager:Get(token) function UnitManager:Get(token)
-- if not Validate(token) then -- if not Validate(token) then
@ -142,10 +144,16 @@ function UnitManager:Get(token)
end) end)
end end
-- Get a unit by guid
---@param guid string
---@return Unit
function UnitManager:GetObject(guid) function UnitManager:GetObject(guid)
return self.objects[guid] return self.objects[guid]
end end
-- Set a unit by guid
---@param unit Unit
---@return Unit
function UnitManager:SetObject(unit) function UnitManager:SetObject(unit)
self.objects[unit:GetGUID()] = unit self.objects[unit:GetGUID()] = unit
end end
@ -174,7 +182,9 @@ function UnitManager:CreateCustomUnit(token, cb)
return cachedUnit return cachedUnit
end end
-- Enum Friends (party/raid members) ---@description Enumerates all friendly units in the battlefield
---@param cb fun(unit: Unit):boolean
---@return nil
function UnitManager:EnumFriends(cb) function UnitManager:EnumFriends(cb)
Bastion.ObjectManager.friends:each(function(unit) Bastion.ObjectManager.friends:each(function(unit)
if cb(unit) then if cb(unit) then
@ -185,6 +195,7 @@ end
-- Enum Enemies (object manager) -- Enum Enemies (object manager)
---@param cb fun(unit: Unit):boolean ---@param cb fun(unit: Unit):boolean
---@return nil
function UnitManager:EnumEnemies(cb) function UnitManager:EnumEnemies(cb)
Bastion.ObjectManager.activeEnemies:each(function(unit) Bastion.ObjectManager.activeEnemies:each(function(unit)
if cb(unit) then if cb(unit) then
@ -194,6 +205,8 @@ function UnitManager:EnumEnemies(cb)
end end
-- Enum Units (object manager) -- Enum Units (object manager)
---@param cb fun(unit: Unit):boolean
---@return nil
function UnitManager:EnumUnits(cb) function UnitManager:EnumUnits(cb)
Bastion.ObjectManager.enemies:each(function(unit) Bastion.ObjectManager.enemies:each(function(unit)
if cb(unit) then if cb(unit) then
@ -203,6 +216,8 @@ function UnitManager:EnumUnits(cb)
end end
-- Get the number of friends with a buff (party/raid members) -- Get the number of friends with a buff (party/raid members)
---@param spell Spell
---@return number
function UnitManager:GetNumFriendsWithBuff(spell) function UnitManager:GetNumFriendsWithBuff(spell)
local count = 0 local count = 0
self:EnumFriends(function(unit) self:EnumFriends(function(unit)
@ -214,6 +229,7 @@ function UnitManager:GetNumFriendsWithBuff(spell)
end end
-- Get the number of friends alive (party/raid members) -- Get the number of friends alive (party/raid members)
---@return number
function UnitManager:GetNumFriendsAlive() function UnitManager:GetNumFriendsAlive()
local count = 0 local count = 0
self:EnumFriends(function(unit) self:EnumFriends(function(unit)
@ -225,7 +241,9 @@ function UnitManager:GetNumFriendsAlive()
end end
-- Get the friend with the most friends within a given radius (party/raid members) -- Get the friend with the most friends within a given radius (party/raid members)
-- Return unit, friends ---@param radius number
---@return Unit
---@return table
function UnitManager:GetFriendWithMostFriends(radius) function UnitManager:GetFriendWithMostFriends(radius)
local unit = nil local unit = nil
local count = 0 local count = 0
@ -254,6 +272,9 @@ function UnitManager:GetFriendWithMostFriends(radius)
end end
-- Find the centroid of the most dense area of friends (party/raid members) of a given radius within a given range -- Find the centroid of the most dense area of friends (party/raid members) of a given radius within a given range
---@param radius number
---@param range number
---@return Vector3 | nil
function UnitManager:FindFriendsCentroid(radius, range) function UnitManager:FindFriendsCentroid(radius, range)
local unit, friends = self:GetFriendWithMostFriends(radius) local unit, friends = self:GetFriendWithMostFriends(radius)
if unit == nil then if unit == nil then

@ -1,16 +1,22 @@
-- Create a Vector3 class -- Create a Vector3 class
---@class Vector3
local Vector3 = {} local Vector3 = {}
Vector3.__index = Vector3 Vector3.__index = Vector3
---@return string
function Vector3:__tostring() function Vector3:__tostring()
return "Vector3(" .. self.x .. ", " .. self.y .. ", " .. self.z .. ")" return "Vector3(" .. self.x .. ", " .. self.y .. ", " .. self.z .. ")"
end end
---@param other Vector3
---@return Vector3
function Vector3:__add(other) function Vector3:__add(other)
return Vector3:New(self.x + other.x, self.y + other.y, self.z + other.z) return Vector3:New(self.x + other.x, self.y + other.y, self.z + other.z)
end end
---@param other Vector3
---@return Vector3
function Vector3:__sub(other) function Vector3:__sub(other)
if type(other) == "number" then if type(other) == "number" then
return Vector3:New(self.x - other, self.y - other, self.z - other) return Vector3:New(self.x - other, self.y - other, self.z - other)
@ -18,30 +24,42 @@ function Vector3:__sub(other)
return Vector3:New(self.x - other.x, self.y - other.y, self.z - other.z) return Vector3:New(self.x - other.x, self.y - other.y, self.z - other.z)
end end
---@param other number
---@return Vector3
function Vector3:__mul(other) function Vector3:__mul(other)
return Vector3:New(self.x * other, self.y * other, self.z * other) return Vector3:New(self.x * other, self.y * other, self.z * other)
end end
---@param other number
---@return Vector3
function Vector3:__div(other) function Vector3:__div(other)
return Vector3:New(self.x / other, self.y / other, self.z / other) return Vector3:New(self.x / other, self.y / other, self.z / other)
end end
---@param other Vector3
---@return boolean
function Vector3:__eq(other) function Vector3:__eq(other)
return self.x == other.x and self.y == other.y and self.z == other.z return self.x == other.x and self.y == other.y and self.z == other.z
end end
---@param other Vector3
---@return boolean
function Vector3:__lt(other) function Vector3:__lt(other)
return self.x < other.x and self.y < other.y and self.z < other.z return self.x < other.x and self.y < other.y and self.z < other.z
end end
---@param other Vector3
---@return boolean
function Vector3:__le(other) function Vector3:__le(other)
return self.x <= other.x and self.y <= other.y and self.z <= other.z return self.x <= other.x and self.y <= other.y and self.z <= other.z
end end
---@return Vector3
function Vector3:__unm() function Vector3:__unm()
return Vector3:New(-self.x, -self.y, -self.z) return Vector3:New(-self.x, -self.y, -self.z)
end end
---@return number
function Vector3:__len() function Vector3:__len()
return math.sqrt(self.x * self.x + self.y * self.y + self.z * self.z) return math.sqrt(self.x * self.x + self.y * self.y + self.z * self.z)
end end
@ -151,6 +169,10 @@ function Vector3:__newindex(k, v)
end end
end end
---@param x number
---@param y number
---@param z number
---@return Vector3
function Vector3:New(x, y, z) function Vector3:New(x, y, z)
if x == false then if x == false then
return Vector3:New(0, 0, 0) return Vector3:New(0, 0, 0)
@ -160,18 +182,26 @@ function Vector3:New(x, y, z)
return self return self
end end
---@param rhs Vector3
---@return number
function Vector3:Dot(rhs) function Vector3:Dot(rhs)
return self.x * rhs.x + self.y * rhs.y + self.z * rhs.z return self.x * rhs.x + self.y * rhs.y + self.z * rhs.z
end end
---@param rhs Vector3
---@return Vector3
function Vector3:Cross(rhs) function Vector3:Cross(rhs)
return Vector3:New(self.y * rhs.z - self.z * rhs.y, self.z * rhs.x - self.x * rhs.z, self.x * rhs.y - self.y * rhs.x) return Vector3:New(self.y * rhs.z - self.z * rhs.y, self.z * rhs.x - self.x * rhs.z, self.x * rhs.y - self.y * rhs.x)
end end
---@param b Vector3
---@return number
function Vector3:Distance(b) function Vector3:Distance(b)
return FastDistance(self.x, self.y, self.z, b.x, b.y, b.z) return FastDistance(self.x, self.y, self.z, b.x, b.y, b.z)
end end
---@param to Vector3
---@return number
function Vector3:Angle(to) function Vector3:Angle(to)
return math.acos(self:Dot(to) / return math.acos(self:Dot(to) /
( (
@ -179,6 +209,8 @@ function Vector3:Angle(to)
math.sqrt(to.x * to.x + to.y * to.y + to.z * to.z))) math.sqrt(to.x * to.x + to.y * to.y + to.z * to.z)))
end end
---@param maxLength number
---@return Vector3
function Vector3:ClampMagnitude(maxLength) function Vector3:ClampMagnitude(maxLength)
if self:Dot(self) > maxLength * maxLength then if self:Dot(self) > maxLength * maxLength then
return self.normalized * maxLength return self.normalized * maxLength
@ -188,15 +220,25 @@ function Vector3:ClampMagnitude(maxLength)
end end
-- Implement a clamp function -- Implement a clamp function
---@param x number
---@param min number
---@param max number
---@return number
local function clamp(x, min, max) local function clamp(x, min, max)
return x < min and min or (x > max and max or x) return x < min and min or (x > max and max or x)
end end
---@param b Vector3
---@param t number
---@return Vector3
function Vector3:Lerp(b, t) function Vector3:Lerp(b, t)
t = clamp(t, 0, 1) t = clamp(t, 0, 1)
return Vector3:New(self.x + (b.x - self.x) * t, self.y + (b.y - self.y) * t, self.z + (b.z - self.z) * t) return Vector3:New(self.x + (b.x - self.x) * t, self.y + (b.y - self.y) * t, self.z + (b.z - self.z) * t)
end end
---@param target Vector3
---@param maxDistanceDelta number
---@return Vector3
function Vector3:MoveTowards(target, maxDistanceDelta) function Vector3:MoveTowards(target, maxDistanceDelta)
local toVector = target - self local toVector = target - self
local distance = toVector.magnitude local distance = toVector.magnitude
@ -207,10 +249,14 @@ function Vector3:MoveTowards(target, maxDistanceDelta)
return self + toVector / distance * maxDistanceDelta return self + toVector / distance * maxDistanceDelta
end end
---@param b Vector3
---@return Vector3
function Vector3:Scale(b) function Vector3:Scale(b)
return Vector3:New(self.x * b.x, self.y * b.y, self.z * b.z) return Vector3:New(self.x * b.x, self.y * b.y, self.z * b.z)
end end
---@param onNormal Vector3
---@return Vector3
function Vector3:Project(onNormal) function Vector3:Project(onNormal)
local num = onNormal:Dot(onNormal) local num = onNormal:Dot(onNormal)
if num < 1.401298E-45 then if num < 1.401298E-45 then
@ -220,14 +266,19 @@ function Vector3:Project(onNormal)
return onNormal * self:Dot(onNormal) / num return onNormal * self:Dot(onNormal) / num
end end
---@param planeNormal Vector3
---@return Vector3
function Vector3:ProjectOnPlane(planeNormal) function Vector3:ProjectOnPlane(planeNormal)
return self - self:Project(planeNormal) return self - self:Project(planeNormal)
end end
---@param inDirection Vector3
---@return Vector3
function Vector3:Reflect(inNormal) function Vector3:Reflect(inNormal)
return -2 * inNormal:Dot(self) * inNormal + self return -2 * inNormal:Dot(self) * inNormal + self
end end
---@return Vector3
function Vector3:Normalize() function Vector3:Normalize()
local num = self:Dot(self) local num = self:Dot(self)
if num > 1E-05 then if num > 1E-05 then

@ -1,5 +1,6 @@
local Tinkr = ... local Tinkr = ...
---@class Bastion
local Bastion = { local Bastion = {
DebugMode = false DebugMode = false
} }
@ -9,32 +10,56 @@ function Bastion.require(class)
return Tinkr:require("scripts/bastion/src/" .. class .. "/" .. class, Bastion) return Tinkr:require("scripts/bastion/src/" .. class .. "/" .. class, Bastion)
end end
---@type ClassMagic
Bastion.ClassMagic = Bastion.require("ClassMagic") Bastion.ClassMagic = Bastion.require("ClassMagic")
---@type List
Bastion.List = Bastion.require("List") Bastion.List = Bastion.require("List")
---@type NotificationsList, Notification
Bastion.NotificationsList, Bastion.Notification = Bastion.require("NotificationsList") Bastion.NotificationsList, Bastion.Notification = Bastion.require("NotificationsList")
---@type Vector3
Bastion.Vector3 = Bastion.require("Vector3") Bastion.Vector3 = Bastion.require("Vector3")
---@type Command
Bastion.Command = Bastion.require("Command") Bastion.Command = Bastion.require("Command")
---@type Cache
Bastion.Cache = Bastion.require("Cache") Bastion.Cache = Bastion.require("Cache")
---@type Cacheable
Bastion.Cacheable = Bastion.require("Cacheable") Bastion.Cacheable = Bastion.require("Cacheable")
---@type Refreshable
Bastion.Refreshable = Bastion.require("Refreshable") Bastion.Refreshable = Bastion.require("Refreshable")
---@type Unit
Bastion.Unit = Bastion.require("Unit") Bastion.Unit = Bastion.require("Unit")
---@type Aura
Bastion.Aura = Bastion.require("Aura") Bastion.Aura = Bastion.require("Aura")
---@type APL, APLActor, APLTrait
Bastion.APL, Bastion.APLActor, Bastion.APLTrait = Bastion.require("APL") Bastion.APL, Bastion.APLActor, Bastion.APLTrait = Bastion.require("APL")
Bastion.Module = Bastion.require("Module") Bastion.Module = Bastion.require("Module")
---@type UnitManager
Bastion.UnitManager = Bastion.require("UnitManager"):New() Bastion.UnitManager = Bastion.require("UnitManager"):New()
---@type ObjectManager
Bastion.ObjectManager = Bastion.require("ObjectManager"):New() Bastion.ObjectManager = Bastion.require("ObjectManager"):New()
---@type EventManager
Bastion.EventManager = Bastion.require("EventManager"):New() Bastion.EventManager = Bastion.require("EventManager"):New()
---@type Spell
Bastion.Spell = Bastion.require("Spell") Bastion.Spell = Bastion.require("Spell")
---@type SpellBook
Bastion.SpellBook = Bastion.require("SpellBook"):New() Bastion.SpellBook = Bastion.require("SpellBook"):New()
---@type Item
Bastion.Item = Bastion.require("Item") Bastion.Item = Bastion.require("Item")
---@type ItemBook
Bastion.ItemBook = Bastion.require("ItemBook"):New() Bastion.ItemBook = Bastion.require("ItemBook"):New()
---@type AuraTable
Bastion.AuraTable = Bastion.require("AuraTable") Bastion.AuraTable = Bastion.require("AuraTable")
---@type Class
Bastion.Class = Bastion.require("Class") Bastion.Class = Bastion.require("Class")
---@type Timer
Bastion.Timer = Bastion.require("Timer") Bastion.Timer = Bastion.require("Timer")
Bastion.Gui = Bastion.require("Gui") ---@type Timer
Bastion.CombatTimer = Bastion.Timer:New('combat') Bastion.CombatTimer = Bastion.Timer:New('combat')
---@type MythicPlusUtils
Bastion.MythicPlusUtils = Bastion.require("MythicPlusUtils"):New() Bastion.MythicPlusUtils = Bastion.require("MythicPlusUtils"):New()
---@type NotificationsList
Bastion.Notifications = Bastion.NotificationsList:New() Bastion.Notifications = Bastion.NotificationsList:New()
Bastion.Gui = Bastion.require("Gui")
Bastion.modules = {} Bastion.modules = {}
Bastion.Enabled = false Bastion.Enabled = false
@ -211,27 +236,21 @@ Command:Register('interface', 'Opens interface menu', function()
else else
mainmenu:Show() mainmenu:Show()
end end
end) end)
-- local files = ListFiles("scripts/bastion/scripts")
-- for i = 1, #files do
-- local file = files[i]
-- if file:sub(-4) == ".lua" or file:sub(-5) == '.luac' then
-- Tinkr:require("scripts/bastion/scripts/" .. file:sub(1, -5), Bastion)
-- end
-- end
if UnitClass('player') == 'Priest' and GetSpecialization() == 3 then if UnitClass('player') == 'Priest' and GetSpecialization() == 3 then
Tinkr:require("scripts/bastion/scripts/shadowpriest", Bastion) Tinkr:require("scripts/bastion/scripts/shadowpriest", Bastion)
Eval('RunMacroText("/bastion module shadow")', 'bastion') Eval('RunMacroText("/bastion module shadow")', 'bastion')
elseif UnitClass('player') == 'Priest' and GetSpecialization() == 2 then elseif UnitClass('player') == 'Priest' and GetSpecialization() == 2 then
Tinkr:require("scripts/bastion/scripts/holypriest", Bastion) Tinkr:require("scripts/bastion/scripts/holypriest", Bastion)
Eval('RunMacroText("/bastion module holypriest")', 'bastion') Eval('RunMacroText("/bastion module holypriest")', 'bastion')
elseif UnitClass('player') == 'Druid' and GetSpecialization() == 2 then
Tinkr:require("scripts/bastion/scripts/feraldruid", Bastion)
Eval('RunMacroText("/bastion module feral")', 'bastion')
elseif UnitClass('player') == 'Druid' and GetSpecialization() == 3 then elseif UnitClass('player') == 'Druid' and GetSpecialization() == 3 then
Tinkr:require("scripts/bastion/scripts/guardiandruid", Bastion) Tinkr:require("scripts/bastion/scripts/guardiandruid", Bastion)
Eval('RunMacroText("/bastion module guardian")', 'bastion') Eval('RunMacroText("/bastion module guardian")', 'bastion')
elseif UnitClass('player') == 'Druid' and GetSpecialization() == 4 then elseif UnitClass('player') == 'Druid' and GetSpecialization() == 4 then
Tinkr:require("scripts/bastion/scripts/restodruid", Bastion) Tinkr:require("scripts/bastion/scripts/restodruid", Bastion)
Eval('RunMacroText("/bastion module resto_druid")', 'bastion') Eval('RunMacroText("/bastion module resto")', 'bastion')
end end
Loading…
Cancel
Save