forked from vibe/Bastion
- Abunai Interface added - Jeffs Config added Simple shaman script added for testing purposemain
parent
5cad5d3ea0
commit
1e5289abaf
@ -1,24 +0,0 @@ |
|||||||
local Tinkr, Bastion = ... |
|
||||||
local ExampleModule = Bastion.Module:New('ExampleModule') |
|
||||||
local Player = Bastion.UnitManager:Get('player') |
|
||||||
|
|
||||||
-- Create a local spellbook |
|
||||||
local SpellBook = Bastion.SpellBook:New() |
|
||||||
|
|
||||||
local FlashHeal = SpellBook:GetSpell(2061) |
|
||||||
|
|
||||||
-- Get a global spell (this can collide with other modules, so be careful) |
|
||||||
-- This is useful for caching common spells that you might not actually cast, and to avoid needless spell creation inline |
|
||||||
local FlashHeal = Bastion.Globals.SpellBook:GetSpell(2061) |
|
||||||
|
|
||||||
local AdvancedMath = Bastion:Import('AdvancedMath') |
|
||||||
|
|
||||||
print(AdvancedMath:Add(1, 2)) |
|
||||||
|
|
||||||
ExampleModule:Sync(function() |
|
||||||
if Player:GetHP() <= 50 then |
|
||||||
FlashHeal:Cast(Player) |
|
||||||
end |
|
||||||
end) |
|
||||||
|
|
||||||
Bastion:Register(ExampleModule) |
|
@ -1,21 +0,0 @@ |
|||||||
local Tinkr, Bastion = ... |
|
||||||
|
|
||||||
local Player = Bastion.UnitManager:Get('player') |
|
||||||
|
|
||||||
Bastion:RegisterLibrary(Bastion.Library:New({ |
|
||||||
name = 'Dependable', |
|
||||||
exports = { |
|
||||||
default = function() |
|
||||||
local Dependable = {} |
|
||||||
|
|
||||||
Dependable.__index = Dependable |
|
||||||
|
|
||||||
function Dependable:Test(a) |
|
||||||
print(a) |
|
||||||
end |
|
||||||
|
|
||||||
return Dependable |
|
||||||
end, |
|
||||||
Test = 5 |
|
||||||
} |
|
||||||
})) |
|
@ -1,15 +0,0 @@ |
|||||||
local Tinkr, Bastion = ... |
|
||||||
|
|
||||||
Bastion:RegisterLibrary(Bastion.Library:New({ |
|
||||||
name = 'Circular', |
|
||||||
exports = { |
|
||||||
default = function(self) |
|
||||||
-- Return default first, and then the remaining exports |
|
||||||
local Math, OtherExports = self:Import('AdvancedMath') |
|
||||||
|
|
||||||
print(Math:Add(1, 2)) |
|
||||||
|
|
||||||
return 'Circular' |
|
||||||
end |
|
||||||
} |
|
||||||
})) |
|
@ -1,25 +0,0 @@ |
|||||||
local Tinkr, Bastion = ... |
|
||||||
|
|
||||||
Bastion:RegisterLibrary(Bastion.Library:New({ |
|
||||||
name = 'AdvancedMath', |
|
||||||
exports = { |
|
||||||
default = function(self) -- Function exports are called when the library is loaded |
|
||||||
-- Return default first, and then the remaining exports |
|
||||||
local Dependable, OtherExports = self:Import('Dependable') |
|
||||||
|
|
||||||
local CircularDependency = self:Import('Circular') -- Causes a circular dependency error |
|
||||||
|
|
||||||
Dependable:Test(OtherExports.Test) |
|
||||||
|
|
||||||
local AdvancedMath = {} |
|
||||||
|
|
||||||
AdvancedMath.__index = AdvancedMath |
|
||||||
|
|
||||||
function AdvancedMath:Add(a, b) |
|
||||||
return a + b |
|
||||||
end |
|
||||||
|
|
||||||
return AdvancedMath |
|
||||||
end |
|
||||||
} |
|
||||||
})) |
|
@ -0,0 +1,337 @@ |
|||||||
|
local Tinkr, Bastion = ... |
||||||
|
|
||||||
|
local Util = Tinkr.Util |
||||||
|
if UnitClass('player') ~= 'Shaman' then return end |
||||||
|
|
||||||
|
Bastion.Rotation = {} |
||||||
|
local BR = Bastion.Rotation |
||||||
|
BR.Units = { |
||||||
|
Player = Bastion.UnitManager:Get('player'), |
||||||
|
Target = Bastion.UnitManager:Get('target'), |
||||||
|
None = Bastion.UnitManager:Get('none') |
||||||
|
} |
||||||
|
|
||||||
|
local ShamanModule = Bastion.Module:New('Shaman') |
||||||
|
local SpellBook = Bastion.Globals.SpellBook |
||||||
|
|
||||||
|
local Player = BR.Units.Player |
||||||
|
local None = BR.Units.None |
||||||
|
local Target = BR.Units.Target |
||||||
|
|
||||||
|
Tinkr:require("scripts/bastion/scripts/ShamanSettings", Bastion) |
||||||
|
BR.myconf = Tinkr.Util.Config:New('shaman') -- for saving variables |
||||||
|
|
||||||
|
local function _highestrank(spell) |
||||||
|
local name = GetSpellInfo(spell) |
||||||
|
local highrankid = (select(7, GetSpellInfo(name))) |
||||||
|
if not highrankid then |
||||||
|
highrankid = 1 |
||||||
|
end |
||||||
|
return highrankid |
||||||
|
end |
||||||
|
|
||||||
|
local s = { |
||||||
|
-- Basic Attack |
||||||
|
AutoAttack = SpellBook:GetSpell(6603), |
||||||
|
|
||||||
|
-- Shocks |
||||||
|
EarthShock = SpellBook:GetSpell(_highestrank(8042)), |
||||||
|
FrostShock = SpellBook:GetSpell(_highestrank(8056)), |
||||||
|
FlameShock = SpellBook:GetSpell(_highestrank(8050)), |
||||||
|
|
||||||
|
-- Specific Ranks for Utility |
||||||
|
EarthShockRank1 = SpellBook:GetSpell(8042), -- Rank 1 (Interrupt) |
||||||
|
FrostShockRank1 = SpellBook:GetSpell(8056), -- Rank 1 (Slow), |
||||||
|
|
||||||
|
-- Healing Spells |
||||||
|
HealingWave = SpellBook:GetSpell(_highestrank(331)), |
||||||
|
LesserHealingWave = SpellBook:GetSpell(_highestrank(8004)), |
||||||
|
ChainHeal = SpellBook:GetSpell(_highestrank(1064)), |
||||||
|
|
||||||
|
-- Healing Sub Ranks (Healing Wave) |
||||||
|
HealingWaveRank1 = SpellBook:GetSpell(331), -- Rank 1 |
||||||
|
HealingWaveRank2 = SpellBook:GetSpell(332), -- Rank 2 |
||||||
|
HealingWaveRank3 = SpellBook:GetSpell(547), -- Rank 3 |
||||||
|
HealingWaveRank4 = SpellBook:GetSpell(913), -- Rank 4 |
||||||
|
HealingWaveRank5 = SpellBook:GetSpell(939), -- Rank 5 |
||||||
|
HealingWaveRank6 = SpellBook:GetSpell(959), -- Rank 6 |
||||||
|
HealingWaveRank7 = SpellBook:GetSpell(8005), -- Rank 7 |
||||||
|
HealingWaveRank8 = SpellBook:GetSpell(10395), -- Rank 8 |
||||||
|
HealingWaveRank9 = SpellBook:GetSpell(10396), -- Rank 9 (Max Rank) |
||||||
|
|
||||||
|
-- Healing Sub Ranks (Lesser Healing Wave) |
||||||
|
LesserHealingWaveRank1 = SpellBook:GetSpell(8004), -- Rank 1 |
||||||
|
LesserHealingWaveRank2 = SpellBook:GetSpell(8008), -- Rank 2 |
||||||
|
LesserHealingWaveRank3 = SpellBook:GetSpell(8010), -- Rank 3 |
||||||
|
LesserHealingWaveRank4 = SpellBook:GetSpell(10466), -- Rank 4 |
||||||
|
LesserHealingWaveRank5 = SpellBook:GetSpell(10467), -- Rank 5 |
||||||
|
LesserHealingWaveRank6 = SpellBook:GetSpell(10468), -- Rank 6 (Max Rank) |
||||||
|
|
||||||
|
-- Healing Sub Ranks (Chain Heal) |
||||||
|
ChainHealRank1 = SpellBook:GetSpell(1064), -- Rank 1 |
||||||
|
ChainHealRank2 = SpellBook:GetSpell(10622), -- Rank 2 |
||||||
|
ChainHealRank3 = SpellBook:GetSpell(10623), -- Rank 3 |
||||||
|
ChainHealRank4 = SpellBook:GetSpell(25422), -- Rank 4 (Max Rank) |
||||||
|
|
||||||
|
-- Totems |
||||||
|
EarthbindTotem = SpellBook:GetSpell(2484), |
||||||
|
StoneclawTotem = SpellBook:GetSpell(_highestrank(5730)), |
||||||
|
StrengthOfEarthTotem = SpellBook:GetSpell(_highestrank(8075)), |
||||||
|
TremorTotem = SpellBook:GetSpell(_highestrank(8143)), |
||||||
|
SearingTotem = SpellBook:GetSpell(_highestrank(3599)), |
||||||
|
FireNovaTotem = SpellBook:GetSpell(_highestrank(1535)), |
||||||
|
HealingStreamTotem = SpellBook:GetSpell(_highestrank(5394)), |
||||||
|
ManaSpringTotem = SpellBook:GetSpell(_highestrank(5675)), |
||||||
|
WindfuryTotem = SpellBook:GetSpell(_highestrank(8512)), |
||||||
|
GraceOfAirTotem = SpellBook:GetSpell(_highestrank(8835)), |
||||||
|
|
||||||
|
-- Buffs |
||||||
|
LightningShield = SpellBook:GetSpell(_highestrank(324)), |
||||||
|
|
||||||
|
-- Offensive Spells |
||||||
|
LightningBolt = SpellBook:GetSpell(_highestrank(403)), |
||||||
|
ChainLightning = SpellBook:GetSpell(_highestrank(421)), |
||||||
|
|
||||||
|
-- Utility |
||||||
|
Purge = SpellBook:GetSpell(_highestrank(370)), |
||||||
|
CurePoison = SpellBook:GetSpell(526), |
||||||
|
CureDisease = SpellBook:GetSpell(2870), |
||||||
|
GhostWolf = SpellBook:GetSpell(2645), |
||||||
|
WaterWalking = SpellBook:GetSpell(_highestrank(546)), |
||||||
|
WaterBreathing = SpellBook:GetSpell(_highestrank(131)), |
||||||
|
|
||||||
|
-- Weapon Buffs |
||||||
|
FlametongueWeapon = SpellBook:GetSpell(_highestrank(8024)), |
||||||
|
FrostbrandWeapon = SpellBook:GetSpell(_highestrank(8033)), |
||||||
|
WindfuryWeapon = SpellBook:GetSpell(_highestrank(8232)), |
||||||
|
RockbiterWeapon = SpellBook:GetSpell(_highestrank(8017)), |
||||||
|
|
||||||
|
-- Talents |
||||||
|
ElementalMastery = SpellBook:GetSpell(16166), |
||||||
|
NaturesSwiftness = SpellBook:GetSpell(16188), |
||||||
|
ManaTideTotem = SpellBook:GetSpell(_highestrank(16190)), |
||||||
|
|
||||||
|
--Buffs |
||||||
|
refreshment = SpellBook:GetList(430, 431, 432, 1133, 1135, 1137, 10250, 22734, 27089, 433, 434, 435, 1127, 1129, 1131, 5004, 11199, 11200, 22731, 25696) |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
-- Create APLs |
||||||
|
local DefaultAPL = Bastion.APL:New('default') |
||||||
|
local HealingAPL = Bastion.APL:New('healing') |
||||||
|
local DamageAPL = Bastion.APL:New('damage') |
||||||
|
local CooldownAPL = Bastion.APL:New('cooldown') |
||||||
|
local DefensiveAPL = Bastion.APL:New('defensive') |
||||||
|
|
||||||
|
-- Default APL |
||||||
|
--DefaultAPL:AddAPL(DefensiveAPL, function() return true end) |
||||||
|
--DefaultAPL:AddAPL(CooldownAPL, function() return true end) |
||||||
|
DefaultAPL:AddAPL(HealingAPL, function() return true end) |
||||||
|
--DefaultAPL:AddAPL(ExecuteAPL, function() return true end) |
||||||
|
--DefaultAPL:AddAPL(DamagePriorityAPL, function() return not HealingNeeded() and AggressiveDamagePhase() end) |
||||||
|
--DefaultAPL:AddAPL(DamageAPL, function() return not HealingNeeded() 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(s.CurePoison) or unit:GetAuras():HasAnyDispelableAura(s.CureDisease)) 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 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 |
||||||
|
if not lowest then |
||||||
|
lowest = Player |
||||||
|
end |
||||||
|
end) |
||||||
|
if lowest == nil then |
||||||
|
lowest = None |
||||||
|
end |
||||||
|
return lowest |
||||||
|
end) |
||||||
|
|
||||||
|
local InterruptTarget = Bastion.UnitManager:CreateCustomUnit('interrupttarget', 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) > 20 then return false end |
||||||
|
if unit:IsInterruptibleAt(40) and Player:IsFacing(unit) then |
||||||
|
interrupt = unit |
||||||
|
--print(unit) |
||||||
|
return true |
||||||
|
end |
||||||
|
end) |
||||||
|
if interrupt == nil then |
||||||
|
interrupt = None |
||||||
|
end |
||||||
|
return interrupt |
||||||
|
end) |
||||||
|
|
||||||
|
local PurgeTarget = Bastion.UnitManager:CreateCustomUnit('purgetarget', function(unit) |
||||||
|
local purgeTarget = nil |
||||||
|
local highestPriority = 0 |
||||||
|
|
||||||
|
-- List of high-priority buffs to purge |
||||||
|
local highPriorityBuffs = { |
||||||
|
642, -- Divine Shield |
||||||
|
1022, -- Blessing of Protection |
||||||
|
19752, -- Divine Intervention |
||||||
|
1044, -- Blessing of Freedom |
||||||
|
6940, -- Blessing of Sacrifice |
||||||
|
1461, -- Arcane Intellect |
||||||
|
23028, -- Arcane Brilliance |
||||||
|
10157, -- Arcane Intellect (Rank 6) |
||||||
|
27126, -- Arcane Brilliance (Rank 2) |
||||||
|
} |
||||||
|
|
||||||
|
Bastion.UnitManager:EnumEnemies(function(unit) |
||||||
|
-- Basic checks |
||||||
|
if unit:IsDead() then return false end |
||||||
|
if not Player:CanSee(unit) then return false end |
||||||
|
if Player:GetDistance(unit) > 30 then return false end |
||||||
|
if not Player:IsFacing(unit) then return false end |
||||||
|
if not unit:IsAffectingCombat() then return false end |
||||||
|
|
||||||
|
-- Check if unit has purgeable buffs |
||||||
|
if unit:GetAuras():HasPurgeableBuff() then |
||||||
|
local currentPriority = 0 |
||||||
|
|
||||||
|
-- Check if unit has any high priority buffs |
||||||
|
for _, buffId in ipairs(highPriorityBuffs) do |
||||||
|
if unit:GetAuras():Find(buffId):IsUp() then |
||||||
|
currentPriority = 2 |
||||||
|
break |
||||||
|
end |
||||||
|
end |
||||||
|
|
||||||
|
-- If no high priority buffs found, but unit has other purgeable buffs |
||||||
|
if currentPriority == 0 then |
||||||
|
currentPriority = 1 |
||||||
|
end |
||||||
|
|
||||||
|
-- Update target if this unit has higher priority |
||||||
|
if currentPriority > highestPriority then |
||||||
|
purgeTarget = unit |
||||||
|
highestPriority = currentPriority |
||||||
|
end |
||||||
|
end |
||||||
|
end) |
||||||
|
|
||||||
|
if purgeTarget == nil then |
||||||
|
purgeTarget = None |
||||||
|
end |
||||||
|
|
||||||
|
return purgeTarget |
||||||
|
end) |
||||||
|
|
||||||
|
-- Utility function to check if healing is needed |
||||||
|
local function HealingNeeded() |
||||||
|
return Lowest:Exists() and Lowest:GetHP() < 90 |
||||||
|
end |
||||||
|
|
||||||
|
-- Utility function to check if emergency healing is needed |
||||||
|
local function EmergencyHealingNeeded() |
||||||
|
return Lowest:Exists() and Lowest:GetHP() < 50 |
||||||
|
end |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
local function out_of_combat_function() |
||||||
|
if Player:GetAuras():FindAnyOf(s.refreshment):IsUp() then return end |
||||||
|
|
||||||
|
end |
||||||
|
|
||||||
|
HealingAPL:AddSpell( |
||||||
|
s.LesserHealingWave:CastableIf(function(self) |
||||||
|
if not Lowest:Exists() then return false end |
||||||
|
if Lowest:GetHP() > 20 then return false end |
||||||
|
return self:IsKnownAndUsable() and HealingNeeded() |
||||||
|
end):SetTarget(Lowest) |
||||||
|
) |
||||||
|
|
||||||
|
HealingAPL:AddSpell( |
||||||
|
s.HealingWave:CastableIf(function(self) |
||||||
|
if not Lowest:Exists() then return false end |
||||||
|
if Lowest:GetHP() > 50 or Lowest:GetHP() < 20 then return false end |
||||||
|
return self:IsKnownAndUsable() and HealingNeeded() |
||||||
|
end):SetTarget(Lowest) |
||||||
|
) |
||||||
|
|
||||||
|
HealingAPL:AddSpell( |
||||||
|
s.CurePoison:CastableIf(function(self) |
||||||
|
if not DispelTarget:Exists() then return false end |
||||||
|
return (DispelTarget:GetAuras():HasAnyDispelableAura(s.CurePoison)) and self:IsKnownAndUsable() |
||||||
|
end):SetTarget(DispelTarget) |
||||||
|
) |
||||||
|
|
||||||
|
HealingAPL:AddSpell( |
||||||
|
s.CureDisease:CastableIf(function(self) |
||||||
|
if not DispelTarget:Exists() then return false end |
||||||
|
return (DispelTarget:GetAuras():HasAnyDispelableAura(s.CureDisease)) and self:IsKnownAndUsable() |
||||||
|
end):SetTarget(DispelTarget) |
||||||
|
) |
||||||
|
|
||||||
|
DamageAPL:AddSpell( |
||||||
|
s.Purge:CastableIf(function(self) |
||||||
|
if not PurgeTarget:Exists() then return false end |
||||||
|
return self:IsKnownAndUsable() and PurgeTarget:GetAuras():HasPurgeableBuff() |
||||||
|
end):SetTarget(PurgeTarget) |
||||||
|
) |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
ShamanModule:Sync(function() |
||||||
|
if Player:GetAuras():FindAnyOf(s.refreshment):IsUp() then return end |
||||||
|
if Player:IsDead() then return end |
||||||
|
if Player:IsCastingOrChanneling() then return end |
||||||
|
if IsMounted() then return end |
||||||
|
if InterruptTarget:Exists() and s.EarthShockRank1:IsKnownAndUsable() then |
||||||
|
s.EarthShockRank1:Cast(InterruptTarget) |
||||||
|
end |
||||||
|
|
||||||
|
if Player:IsAffectingCombat() then |
||||||
|
|
||||||
|
DefaultAPL:Execute() |
||||||
|
else |
||||||
|
if Player:GetPP() > 5 then |
||||||
|
HealingAPL:Execute() |
||||||
|
end |
||||||
|
out_of_combat_function() |
||||||
|
end |
||||||
|
end) |
||||||
|
|
||||||
|
|
||||||
|
Bastion:Register(ShamanModule) |
||||||
|
ShamanModule:Toggle() |
@ -0,0 +1,124 @@ |
|||||||
|
local Unlocker, Bastion = ... |
||||||
|
--! Creating the initial GUI !-- |
||||||
|
|
||||||
|
Bastion.Settings = Bastion.Interface.Category:New("Shaman") |
||||||
|
|
||||||
|
|
||||||
|
Bastion.Settings:AddSubsection("General") |
||||||
|
|
||||||
|
Bastion.Settings:Slider({ |
||||||
|
category = "bastion", |
||||||
|
var = "tickrate", |
||||||
|
name = "Engine Tickrate (milliseconds)", |
||||||
|
tooltip = "How often the Bastion Engine runs. The lower this number, the more resources Bastion will use.\n\nYou must reload for changes to take effect.", |
||||||
|
default = 100, |
||||||
|
min = 50, |
||||||
|
max = 500, |
||||||
|
step = 50, |
||||||
|
}) |
||||||
|
|
||||||
|
|
||||||
|
Bastion.Settings:Dropdown({ |
||||||
|
category = "bastion", |
||||||
|
var = "pause_key", |
||||||
|
name = "Hold-to-Pause", |
||||||
|
tooltip = "Bastion will not run while this button is held down.", |
||||||
|
default = false, |
||||||
|
options = { |
||||||
|
{ "None", false }, |
||||||
|
{ "Shift", "SHIFT" }, |
||||||
|
{ "Control", "CTRL" }, |
||||||
|
{ "Alt", "ALT" }, |
||||||
|
} |
||||||
|
}) |
||||||
|
|
||||||
|
Bastion.Settings:AddSubsection("Engine Options") |
||||||
|
|
||||||
|
Bastion.Settings:Checkbox({ |
||||||
|
category = "bastion", |
||||||
|
var = "debug", |
||||||
|
name = "Debug Mode", |
||||||
|
tooltip = "Toggles Debug Mode for the Bastion Engine.", |
||||||
|
default = false, |
||||||
|
onClick = function() |
||||||
|
Bastion.DebugMode = not Bastion.DebugMode |
||||||
|
if Bastion.DebugMode then |
||||||
|
Bastion:Debug("Debug Enabled") |
||||||
|
else |
||||||
|
Bastion:Print("Debug Disabled") |
||||||
|
end |
||||||
|
end, |
||||||
|
}) |
||||||
|
|
||||||
|
Bastion.MainBar = Bastion.Interface.Hotbar:New({ |
||||||
|
buttonCount = 3, |
||||||
|
name = "Bastion", |
||||||
|
options = Bastion.Settings |
||||||
|
}) |
||||||
|
|
||||||
|
if Bastion:IsClassic() then |
||||||
|
Bastion.MainBar:AddButton({ |
||||||
|
name = "Toggle", |
||||||
|
texture = "Interface\\ICONS\\Inv_drink_15", |
||||||
|
tooltip = "This button toggle's Bastion on and off.", |
||||||
|
toggle = true, |
||||||
|
onClick = function() |
||||||
|
Bastion.Enabled = not Bastion.Enabled |
||||||
|
if Bastion.Enabled then |
||||||
|
Bastion:Print("Enabled") |
||||||
|
else |
||||||
|
Bastion:Print("Disabled") |
||||||
|
end |
||||||
|
end, |
||||||
|
}) |
||||||
|
Bastion.MainBar:AddButton({ |
||||||
|
name = "Options", |
||||||
|
tooltip = "This button opens the Bastion Options menu.", |
||||||
|
texture = "Interface\\ICONS\\Inv_misc_gear_01", |
||||||
|
toggle = false, |
||||||
|
onClick = function() |
||||||
|
if SettingsPanel and SettingsPanel:IsVisible() then |
||||||
|
HideUIPanel(SettingsPanel) |
||||||
|
HideUIPanel(GameMenuFrame) |
||||||
|
else |
||||||
|
Settings.OpenToCategory(Bastion.MainBar.options.settings:GetID()) |
||||||
|
end |
||||||
|
end, |
||||||
|
}) |
||||||
|
|
||||||
|
else |
||||||
|
Bastion.MainBar:AddButton({ |
||||||
|
name = "Toggle", |
||||||
|
texture = "Interface\\ICONS\\ACHIEVEMENT_GUILDPERK_MRPOPULARITY", |
||||||
|
tooltip = "This button toggle's Bastion on and off.", |
||||||
|
toggle = true, |
||||||
|
onClick = function() |
||||||
|
-- if Bastion.Settings.config:Read("bastion_stimulant", true) then |
||||||
|
-- Bastion.Stimulant:Toggle() |
||||||
|
-- end |
||||||
|
Bastion.Enabled = not Bastion.Enabled |
||||||
|
if Bastion.Enabled then |
||||||
|
Bastion:Print("Enabled") |
||||||
|
else |
||||||
|
Bastion:Print("Disabled") |
||||||
|
end |
||||||
|
end, |
||||||
|
}) |
||||||
|
Bastion.MainBar:AddButton({ |
||||||
|
name = "Options", |
||||||
|
tooltip = "This button opens the Bastion Options menu.", |
||||||
|
texture = "Interface\\ICONS\\INV_Engineering_90_Gizmo", |
||||||
|
toggle = false, |
||||||
|
onClick = function() |
||||||
|
if SettingsPanel and SettingsPanel:IsVisible() then |
||||||
|
HideUIPanel(SettingsPanel) |
||||||
|
HideUIPanel(GameMenuFrame) |
||||||
|
else |
||||||
|
Settings.OpenToCategory(Bastion.MainBar.options.settings:GetID()) |
||||||
|
end |
||||||
|
end, |
||||||
|
}) |
||||||
|
end |
||||||
|
|
||||||
|
|
||||||
|
Bastion.Settings:Register() |
@ -0,0 +1,85 @@ |
|||||||
|
---@type Tinkr |
||||||
|
local Tinkr, |
||||||
|
---@class Bastion |
||||||
|
Bastion = ... |
||||||
|
|
||||||
|
---@class Bastion.Config |
||||||
|
---@field instantiated boolean |
||||||
|
---@field config Tinkr.Util.Config.Instance |
||||||
|
---@field defaults nil | table |
||||||
|
local Config = { |
||||||
|
instantiated = false, |
||||||
|
} |
||||||
|
|
||||||
|
function Config:__index(k) |
||||||
|
local response = Config[k] |
||||||
|
|
||||||
|
if response == nil then |
||||||
|
response = rawget(self, k) |
||||||
|
end |
||||||
|
|
||||||
|
if response == nil and self.instantiated then |
||||||
|
response = self:Read(k) |
||||||
|
end |
||||||
|
|
||||||
|
return response |
||||||
|
end |
||||||
|
|
||||||
|
function Config:__newindex(key, value) |
||||||
|
if self.instantiated then |
||||||
|
self:Write(key, value) |
||||||
|
else |
||||||
|
rawset(self, key, value) |
||||||
|
end |
||||||
|
end |
||||||
|
|
||||||
|
---@generic D |
||||||
|
---@param name string |
||||||
|
---@param defaults? D |
||||||
|
function Config:New(name, defaults) |
||||||
|
---@type Bastion.Config |
||||||
|
local self = setmetatable({}, Config) |
||||||
|
self.config = Tinkr.Util.Config:New(name) |
||||||
|
self.defaults = type(defaults) == "table" and defaults or {} |
||||||
|
self.instantiated = true |
||||||
|
return self |
||||||
|
end |
||||||
|
|
||||||
|
---@generic D |
||||||
|
---@param key string |
||||||
|
---@param default? D |
||||||
|
---@return D |
||||||
|
function Config:Read(key, default) |
||||||
|
if type(default) == "nil" then |
||||||
|
default = self.defaults[key] |
||||||
|
end |
||||||
|
return self.config:Read(key, default) |
||||||
|
end |
||||||
|
|
||||||
|
function Config:Reset() |
||||||
|
if type(self.defaults) == "table" then |
||||||
|
-- Clear all values currently in the config. |
||||||
|
for key, _ in pairs(self.config.data) do |
||||||
|
self:Write(key, nil) |
||||||
|
end |
||||||
|
-- Use default table to write new defaults. |
||||||
|
for key, value in pairs(self.defaults) do |
||||||
|
self:Write(key, value) |
||||||
|
end |
||||||
|
return true |
||||||
|
end |
||||||
|
return false |
||||||
|
end |
||||||
|
|
||||||
|
---@param key string |
||||||
|
---@param value any |
||||||
|
function Config:Write(key, value) |
||||||
|
self.config:Write(key, value) |
||||||
|
end |
||||||
|
|
||||||
|
---@param key string |
||||||
|
function Config:Sync(key) |
||||||
|
self.config:Sync(key) |
||||||
|
end |
||||||
|
|
||||||
|
Bastion.Config = Config |
@ -0,0 +1,268 @@ |
|||||||
|
local Tinkr, Bastion = ... |
||||||
|
local Interface = {} |
||||||
|
|
||||||
|
--[[ |
||||||
|
The current settings is named "Vertical" as it uses the Dragonflight Vertical |
||||||
|
layout, rather than the Canvas layout. Vertical looks better, is easier to |
||||||
|
format and use. Canvas layout allows you to add multi-select dropdowns, text |
||||||
|
inputs, and more. I prefer vertical. Canvas support will be added in the future. |
||||||
|
]]-- |
||||||
|
|
||||||
|
local Hotbar = {} |
||||||
|
Hotbar.__index = Hotbar |
||||||
|
|
||||||
|
Bastion.Hotbars = {} |
||||||
|
|
||||||
|
-- Constructor |
||||||
|
---@return Hotbar |
||||||
|
function Hotbar:New(details) |
||||||
|
local self = setmetatable({}, Hotbar) |
||||||
|
self.button_size = 45 |
||||||
|
self.button_spacing = 5 |
||||||
|
self.button_count = details.buttonCount |
||||||
|
self.name = details.name |
||||||
|
self.options = details.options |
||||||
|
|
||||||
|
local position = self.options.config:Read("bar_location", { "CENTER", 0, -50 }) |
||||||
|
|
||||||
|
|
||||||
|
self.frame = CreateFrame("Frame", nil, UIParent, "SecureHandlerStateTemplate") |
||||||
|
self.frame:SetWidth(self.button_count * (32 + self.button_spacing) - self.button_spacing) -- width = total width of all buttons + total width of all spacings |
||||||
|
self.frame:SetHeight(32 + 20) |
||||||
|
|
||||||
|
|
||||||
|
self.frame:SetPoint(position[1], position[2], position[3]) |
||||||
|
|
||||||
|
self.title = self.frame:CreateFontString(nil, "OVERLAY", "Game15Font") |
||||||
|
|
||||||
|
self.title:SetPoint("BOTTOMLEFT", self.frame, "LEFT", 0, 10) -- adjust these values as necessary |
||||||
|
|
||||||
|
self.title:SetText(self.name) -- replace this with your desired title |
||||||
|
|
||||||
|
self.frame:EnableMouse(true) |
||||||
|
self.frame:SetMovable(true) |
||||||
|
self.frame:SetClampedToScreen(true) |
||||||
|
self.frame:RegisterForDrag("LeftButton") |
||||||
|
self.frame:SetScript("OnDragStart", self.frame.StartMoving) |
||||||
|
self.frame:SetScript("OnDragStop", function() |
||||||
|
self.frame:StopMovingOrSizing() |
||||||
|
local point, _, _, x, y = self.frame:GetPoint() |
||||||
|
self.options.config:Write("bar_location", { point, x, y }) |
||||||
|
end) |
||||||
|
|
||||||
|
if not self.options.config:Read("display_hotbar_" .. self.options.name, true) then |
||||||
|
self.frame:Hide() |
||||||
|
end |
||||||
|
|
||||||
|
self.options:Checkbox({ |
||||||
|
category = "display_hotbar", |
||||||
|
var = self.name, |
||||||
|
name = self.name .. " Hotbar", |
||||||
|
tooltip = "Display the hotbar for " .. self.name, |
||||||
|
default = true |
||||||
|
}) |
||||||
|
|
||||||
|
self.buttons = {} |
||||||
|
|
||||||
|
table.insert(Bastion.Hotbars, self) |
||||||
|
return self |
||||||
|
end |
||||||
|
|
||||||
|
-- Needed to ensure hotbars are positioned properly and hidden when a user hides them in settings |
||||||
|
function Hotbar:Refresh() |
||||||
|
if not self.options.config:Read("display_hotbar_" .. self.options.name, true) then |
||||||
|
if self.frame:IsVisible() then |
||||||
|
self.frame:Hide() |
||||||
|
end |
||||||
|
else |
||||||
|
if not self.frame:IsVisible() then |
||||||
|
self.frame:Show() |
||||||
|
end |
||||||
|
end |
||||||
|
|
||||||
|
return self |
||||||
|
end |
||||||
|
|
||||||
|
-- Adds a button to the hotbar. |
||||||
|
-- TODO: Make this not a hot mess for classic/retail |
||||||
|
function Hotbar:AddButton(details) |
||||||
|
local button = CreateFrame("CheckButton", nil, self.frame, "UIPanelButtonTemplate") |
||||||
|
button:SetNormalTexture(details.texture) |
||||||
|
button:SetPoint("CENTER") |
||||||
|
button:SetSize(32, 32) |
||||||
|
table.insert(self.buttons, button) |
||||||
|
if details.onClick then |
||||||
|
if details.toggle then |
||||||
|
local toggleAnim = false |
||||||
|
button:SetScript("OnClick", function() |
||||||
|
-- Toggle animation |
||||||
|
if toggleAnim then |
||||||
|
ActionButton_HideOverlayGlow(button) |
||||||
|
toggleAnim = false |
||||||
|
else |
||||||
|
ActionButton_ShowOverlayGlow(button) |
||||||
|
toggleAnim = true |
||||||
|
end |
||||||
|
details.onClick() |
||||||
|
end) |
||||||
|
else |
||||||
|
button:SetScript("OnClick", details.onClick) |
||||||
|
end |
||||||
|
end |
||||||
|
button:SetScript("OnEnter", function(self) |
||||||
|
GameTooltip:SetOwner(self, "ANCHOR_RIGHT") |
||||||
|
GameTooltip:AddLine(details.name, 1, 1, 1) -- sets the tooltip as the button's name |
||||||
|
GameTooltip:AddLine(details.tooltip) |
||||||
|
GameTooltip:Show() |
||||||
|
end) |
||||||
|
button:SetScript("OnLeave", function(self) |
||||||
|
GameTooltip:Hide() |
||||||
|
end) |
||||||
|
for i, btn in ipairs(self.buttons) do |
||||||
|
button:SetPoint("BOTTOMLEFT", (i - 1) * (32 + self.button_spacing), 0) -- Position each button |
||||||
|
end |
||||||
|
|
||||||
|
return self |
||||||
|
end |
||||||
|
|
||||||
|
local Category = {} |
||||||
|
Category.__index = Category |
||||||
|
|
||||||
|
-- Constructor |
||||||
|
---@param name String |
||||||
|
---@param config Config |
||||||
|
---@return Category |
||||||
|
function Category:New(name, parent) |
||||||
|
local self = setmetatable({}, Category) |
||||||
|
self.name = name |
||||||
|
self.parent = parent or nil |
||||||
|
|
||||||
|
if self.parent then |
||||||
|
self.settings, self.layout = Settings.RegisterVerticalLayoutSubcategory(parent.settings, self.name) |
||||||
|
self.config = self.parent.config |
||||||
|
else |
||||||
|
self.settings, self.layout = Settings.RegisterVerticalLayoutCategory(self.name) |
||||||
|
self.config = Bastion.Config:New(name) |
||||||
|
end |
||||||
|
|
||||||
|
return self |
||||||
|
end |
||||||
|
|
||||||
|
function Category:AddSubsection(section_title) |
||||||
|
local section = CreateSettingsListSectionHeaderInitializer(section_title) |
||||||
|
self.layout:AddInitializer(section) |
||||||
|
return self |
||||||
|
end |
||||||
|
|
||||||
|
-- Register the Category object with the Blizzard UI |
||||||
|
---@return nil |
||||||
|
function Category:Register() |
||||||
|
Settings.RegisterAddOnCategory(self.settings) |
||||||
|
end |
||||||
|
|
||||||
|
-- Adds a checkbox to the Category |
||||||
|
---@param details Table |
||||||
|
function Category:Checkbox(details) |
||||||
|
local default_value = details.default or false |
||||||
|
local variable_name = details.category .. "_" .. details.var |
||||||
|
|
||||||
|
local setting = Settings.RegisterAddOnSetting(self.settings, details.name, variable_name, type(default_value), self.config:Read(variable_name, default_value)) |
||||||
|
|
||||||
|
Settings.SetOnValueChangedCallback(variable_name, function(event) |
||||||
|
self.config:Write(variable_name, setting:GetValue()) |
||||||
|
end) |
||||||
|
|
||||||
|
local initializer = Settings.CreateCheckBox(self.settings, setting, details.tooltip and ("\n" .. details.tooltip) or "") |
||||||
|
|
||||||
|
if details.disabled then |
||||||
|
initializer:AddModifyPredicate(function() return false end) |
||||||
|
self.config:Write(variable_name, false) |
||||||
|
end |
||||||
|
|
||||||
|
return self |
||||||
|
end |
||||||
|
|
||||||
|
-- Adds a checkbox to the Category |
||||||
|
---@param details Table |
||||||
|
function Category:SubCheck(details) |
||||||
|
local default_value = details.default or false |
||||||
|
local variable_name = details.category .. "_" .. details.var |
||||||
|
|
||||||
|
local setting = Settings.RegisterAddOnSetting(self.settings, details.name, variable_name, type(default_value), self.config:Read(variable_name, default_value)) |
||||||
|
|
||||||
|
Settings.SetOnValueChangedCallback(variable_name, function(event) |
||||||
|
print(variable_name, setting:GetValue()) |
||||||
|
self.config:Write(variable_name, setting:GetValue()) |
||||||
|
details.sub:Toggle() |
||||||
|
end) |
||||||
|
|
||||||
|
local initializer = Settings.CreateCheckBox(self.settings, setting, details.tooltip and ("\n" .. details.tooltip) or "") |
||||||
|
|
||||||
|
return self |
||||||
|
end |
||||||
|
|
||||||
|
-- Adds a slider to the Category |
||||||
|
---@param details Table |
||||||
|
function Category:Slider(details) |
||||||
|
details = details or {} |
||||||
|
local default_value = details.default or 0 |
||||||
|
local min_value = details.min or 0 |
||||||
|
local max_value = details.max or 100 |
||||||
|
|
||||||
|
local step = details.step or 1 |
||||||
|
local variable_name = details.category .. "_" .. details.var |
||||||
|
|
||||||
|
local setting = Settings.RegisterAddOnSetting(self.settings, details.name, variable_name, type(default_value), tonumber(self.config:Read(variable_name, default_value))) |
||||||
|
|
||||||
|
Settings.SetOnValueChangedCallback(variable_name, function(event) |
||||||
|
self.config:Write(variable_name, setting:GetValue()) |
||||||
|
end) |
||||||
|
|
||||||
|
local options = Settings.CreateSliderOptions(min_value, max_value, step) |
||||||
|
|
||||||
|
options:SetLabelFormatter(MinimalSliderWithSteppersMixin.Label.Right) |
||||||
|
|
||||||
|
local initializer = Settings.CreateSlider(self.settings, setting, options, details.tooltip and ("\n" .. details.tooltip) or "") |
||||||
|
|
||||||
|
-- if details.disabled then |
||||||
|
-- initializer:AddModifyPredicate(function() return false end) |
||||||
|
-- self.config:Write(variable_name, false) |
||||||
|
-- end |
||||||
|
|
||||||
|
return self |
||||||
|
end |
||||||
|
|
||||||
|
-- Adds a dropdown to the category |
||||||
|
---@param details Table |
||||||
|
function Category:Dropdown(details) |
||||||
|
local default_value = details.default |
||||||
|
local variable_name = details.category .. "_" .. details.var |
||||||
|
|
||||||
|
local setting = Settings.RegisterAddOnSetting(self.settings, details.name, variable_name, type(default_value), self.config:Read(variable_name, default_value)) |
||||||
|
|
||||||
|
local function GetOptions() |
||||||
|
local container = Settings.CreateControlTextContainer() |
||||||
|
for k, v in ipairs(details.options) do |
||||||
|
container:Add(v[2], v[1]) |
||||||
|
end |
||||||
|
return container:GetData() |
||||||
|
end |
||||||
|
|
||||||
|
Settings.SetOnValueChangedCallback(variable_name, function(event) |
||||||
|
self.config:Write(variable_name, setting:GetValue()) |
||||||
|
end) |
||||||
|
|
||||||
|
local initializer = Settings.CreateDropDown(self.settings, setting, GetOptions, details.tooltip or "") |
||||||
|
|
||||||
|
if details.disabled then |
||||||
|
initializer:AddModifyPredicate(function() return false end) |
||||||
|
self.config:Write(variable_name, false) |
||||||
|
end |
||||||
|
|
||||||
|
return self |
||||||
|
end |
||||||
|
|
||||||
|
Interface.Hotbar = Hotbar |
||||||
|
Interface.Category = Category |
||||||
|
print("Interface Loaded") |
||||||
|
Bastion.Interface = Interface |
Loading…
Reference in new issue